整理文件夹及架构,加入打印机页面,octo反代有问题
This commit is contained in:
107
app/utils/stl_merger.py
Normal file
107
app/utils/stl_merger.py
Normal file
@@ -0,0 +1,107 @@
|
||||
import struct
|
||||
import math
|
||||
import os
|
||||
|
||||
def merge_stls(input_files, output_path):
|
||||
try:
|
||||
from stl import mesh
|
||||
import numpy as np
|
||||
|
||||
meshes = []
|
||||
for path, matrix in input_files:
|
||||
try:
|
||||
# 重新换回轻量级的 numpy-stl 以防内存溢出 (OOM)
|
||||
m = mesh.Mesh.from_file(path)
|
||||
|
||||
mat = np.array(matrix, dtype=np.float64).reshape((4, 4)).T
|
||||
|
||||
vectors = m.vectors.reshape(-1, 3)
|
||||
hom_vectors = np.hstack((vectors, np.ones((len(vectors), 1), dtype=np.float32)))
|
||||
transformed = (mat @ hom_vectors.T).T
|
||||
m.vectors = transformed[:, :3].reshape(-1, 3, 3)
|
||||
|
||||
# 检测缩放矩阵是否引发镜像翻转 (行列式为负数)
|
||||
det = np.linalg.det(mat[:3, :3])
|
||||
if det < 0:
|
||||
# 发生镜像反转,不仅法线会反向,三角形三个顶点的顺逆时针(Winding Order)也会错乱
|
||||
# 强行交换每个三角形的顶点2和顶点3以纠正渲染正反面
|
||||
m.vectors[:, [1, 2]] = m.vectors[:, [2, 1]]
|
||||
|
||||
m.update_normals()
|
||||
meshes.append(m)
|
||||
except Exception as e:
|
||||
print(f"Error processing path {path} with stl mesh: {e}")
|
||||
|
||||
if not meshes:
|
||||
return
|
||||
|
||||
if len(meshes) == 1:
|
||||
meshes[0].save(output_path)
|
||||
return
|
||||
|
||||
merged_data = np.concatenate([m.data for m in meshes])
|
||||
merged_mesh = mesh.Mesh(merged_data)
|
||||
merged_mesh.save(output_path)
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
print(f"Mesh fast-merge failed: {e}. Falling back to struct parsing.")
|
||||
|
||||
# Extreme fallback just in case no stl libraries work
|
||||
total_faces = 0
|
||||
meshes_data = []
|
||||
|
||||
for path, matrix in input_files:
|
||||
with open(path, 'rb') as f:
|
||||
f.read(80)
|
||||
faces = struct.unpack('<I', f.read(4))[0]
|
||||
data = f.read(faces * 50)
|
||||
|
||||
def apply_m(_x, _y, _z):
|
||||
w = _x * matrix[3] + _y * matrix[7] + _z * matrix[11] + matrix[15]
|
||||
nx = (_x * matrix[0] + _y * matrix[4] + _z * matrix[8] + matrix[12]) / w
|
||||
ny = (_x * matrix[1] + _y * matrix[5] + _z * matrix[9] + matrix[13]) / w
|
||||
nz = (_x * matrix[2] + _y * matrix[6] + _z * matrix[10] + matrix[14]) / w
|
||||
return nx, ny, nz
|
||||
|
||||
new_data = bytearray(faces * 50)
|
||||
src_offset = 0
|
||||
dst_offset = 0
|
||||
for _ in range(faces):
|
||||
n_x, n_y, n_z, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z, attr = struct.unpack_from('<12fH', data, src_offset)
|
||||
|
||||
nv1x, nv1y, nv1z = apply_m(v1x, v1y, v1z)
|
||||
nv2x, nv2y, nv2z = apply_m(v2x, v2y, v2z)
|
||||
nv3x, nv3y, nv3z = apply_m(v3x, v3y, v3z)
|
||||
|
||||
# Recalculate normal properly using cross product to fix flipped/sheared surfaces
|
||||
Ux = nv2x - nv1x
|
||||
Uy = nv2y - nv1y
|
||||
Uz = nv2z - nv1z
|
||||
Vx = nv3x - nv1x
|
||||
Vy = nv3y - nv1y
|
||||
Vz = nv3z - nv1z
|
||||
|
||||
nnx = Uy * Vz - Uz * Vy
|
||||
nny = Uz * Vx - Ux * Vz
|
||||
nnz = Ux * Vy - Uy * Vx
|
||||
|
||||
l = math.sqrt(nnx**2 + nny**2 + nnz**2)
|
||||
if l > 1e-8:
|
||||
nnx, nny, nnz = nnx/l, nny/l, nnz/l
|
||||
else:
|
||||
nnx, nny, nnz = 0.0, 0.0, 0.0
|
||||
|
||||
struct.pack_into('<12fH', new_data, dst_offset, nnx, nny, nnz, nv1x, nv1y, nv1z, nv2x, nv2y, nv2z, nv3x, nv3y, nv3z, attr)
|
||||
src_offset += 50
|
||||
dst_offset += 50
|
||||
|
||||
meshes_data.append(new_data)
|
||||
total_faces += faces
|
||||
|
||||
with open(output_path, 'wb') as f:
|
||||
f.write(b'\0' * 80)
|
||||
f.write(struct.pack('<I', total_faces))
|
||||
for d in meshes_data:
|
||||
f.write(d)
|
||||
|
||||
Reference in New Issue
Block a user