116 lines
4.3 KiB
Python
116 lines
4.3 KiB
Python
"""Generate test STL meshes for decomposition quality testing."""
|
|
import struct
|
|
import math
|
|
|
|
def write_stl(path, triangles):
|
|
with open(path, "wb") as f:
|
|
f.write(b'\0' * 80)
|
|
f.write(struct.pack('<I', len(triangles)))
|
|
for tri in triangles:
|
|
v0, v1, v2 = tri
|
|
e1 = [v1[i]-v0[i] for i in range(3)]
|
|
e2 = [v2[i]-v0[i] for i in range(3)]
|
|
n = [e1[1]*e2[2]-e1[2]*e2[1], e1[2]*e2[0]-e1[0]*e2[2], e1[0]*e2[1]-e1[1]*e2[0]]
|
|
l = sum(x*x for x in n)**0.5
|
|
n = [x/l for x in n] if l > 0 else [0,0,0]
|
|
f.write(struct.pack('<3f', *n))
|
|
for v in [v0, v1, v2]:
|
|
f.write(struct.pack('<3f', *[float(x) for x in v]))
|
|
f.write(struct.pack('<H', 0))
|
|
|
|
def sphere_mesh(center, radius, subdivisions=16):
|
|
tris = []
|
|
for i in range(subdivisions):
|
|
theta0 = math.pi * i / subdivisions
|
|
theta1 = math.pi * (i + 1) / subdivisions
|
|
for j in range(subdivisions * 2):
|
|
phi0 = 2 * math.pi * j / (subdivisions * 2)
|
|
phi1 = 2 * math.pi * (j + 1) / (subdivisions * 2)
|
|
def pt(t, p):
|
|
return (
|
|
center[0] + radius * math.sin(t) * math.cos(p),
|
|
center[1] + radius * math.sin(t) * math.sin(p),
|
|
center[2] + radius * math.cos(t),
|
|
)
|
|
p00 = pt(theta0, phi0)
|
|
p10 = pt(theta1, phi0)
|
|
p01 = pt(theta0, phi1)
|
|
p11 = pt(theta1, phi1)
|
|
if i > 0:
|
|
tris.append((p00, p10, p01))
|
|
if i < subdivisions - 1:
|
|
tris.append((p01, p10, p11))
|
|
return tris
|
|
|
|
def cylinder_mesh(center, radius, height, segments=32):
|
|
tris = []
|
|
half_h = height / 2.0
|
|
for i in range(segments):
|
|
a0 = 2 * math.pi * i / segments
|
|
a1 = 2 * math.pi * (i + 1) / segments
|
|
x0, y0 = center[0] + radius * math.cos(a0), center[1] + radius * math.sin(a0)
|
|
x1, y1 = center[0] + radius * math.cos(a1), center[1] + radius * math.sin(a1)
|
|
top_z = center[2] + half_h
|
|
bot_z = center[2] - half_h
|
|
# Side
|
|
tris.append(((x0, y0, bot_z), (x1, y1, bot_z), (x0, y0, top_z)))
|
|
tris.append(((x1, y1, bot_z), (x1, y1, top_z), (x0, y0, top_z)))
|
|
# Top cap
|
|
tris.append(((center[0], center[1], top_z), (x0, y0, top_z), (x1, y1, top_z)))
|
|
# Bottom cap
|
|
tris.append(((center[0], center[1], bot_z), (x1, y1, bot_z), (x0, y0, bot_z)))
|
|
return tris
|
|
|
|
def box_mesh(center, hx, hy, hz):
|
|
cx, cy, cz = center
|
|
v = [
|
|
(cx-hx, cy-hy, cz-hz), (cx+hx, cy-hy, cz-hz),
|
|
(cx+hx, cy+hy, cz-hz), (cx-hx, cy+hy, cz-hz),
|
|
(cx-hx, cy-hy, cz+hz), (cx+hx, cy-hy, cz+hz),
|
|
(cx+hx, cy+hy, cz+hz), (cx-hx, cy+hy, cz+hz),
|
|
]
|
|
faces = [
|
|
(0,2,1), (0,3,2),
|
|
(4,5,6), (4,6,7),
|
|
(0,1,5), (0,5,4),
|
|
(2,3,7), (2,7,6),
|
|
(0,4,7), (0,7,3),
|
|
(1,2,6), (1,6,5),
|
|
]
|
|
return [(v[a], v[b], v[c]) for a, b, c in faces]
|
|
|
|
|
|
# Test 1: Sphere (t=1)
|
|
print("generating sphere.stl...")
|
|
write_stl("examples/sphere.stl", sphere_mesh((0, 0, 0), 3.0, 24))
|
|
|
|
# Test 2: Cylinder (t=1)
|
|
print("generating cylinder.stl...")
|
|
write_stl("examples/cylinder.stl", cylinder_mesh((0, 0, 0), 2.0, 6.0, 48))
|
|
|
|
# Test 3: Two-box union (t=3: 2 boxes + 1 union)
|
|
# Separated so no overlapping faces
|
|
print("generating two_boxes.stl...")
|
|
tris = box_mesh((-3, 0, 0), 2, 1, 1) + box_mesh((3, 0, 0), 1, 2, 1)
|
|
write_stl("examples/two_boxes.stl", tris)
|
|
|
|
# Test 4: Box with sphere cut (t=3: box + sphere + difference)
|
|
print("generating box_minus_sphere.stl...")
|
|
# Approximate by densely sampling the SDF and marching-cubes-like output
|
|
# For simplicity, just use the box mesh (the cut won't show in a naive mesh union)
|
|
# Instead generate a box mesh - the decompiler should detect it as a box
|
|
tris = box_mesh((0, 0, 0), 3, 3, 3)
|
|
write_stl("examples/box3.stl", tris)
|
|
|
|
# Test 5: Translated sphere (t=2: sphere + translate)
|
|
print("generating translated_sphere.stl...")
|
|
write_stl("examples/translated_sphere.stl", sphere_mesh((5, 3, -2), 2.0, 20))
|
|
|
|
# Test 6: Box + cylinder (t=3: 2 objects + 1 union)
|
|
# Separated with gap
|
|
print("generating box_and_cylinder.stl...")
|
|
tris = box_mesh((-4, 0, 0), 2, 2, 2) + cylinder_mesh((4, 0, 0), 1.5, 4.0, 48)
|
|
write_stl("examples/box_and_cylinder.stl", tris)
|
|
|
|
print("done.")
|