"""Carve the servo mount-screw holes into Cameron's rough holder STL (already in the servo frame).
Holes run along the Y screw axis at the servo's real mount-hole positions that the holder covers."""
import sys
import numpy as np
import trimesh

SRC = "holder_approx.stl"
SERVO = "st3215.stl"
OUT = "holder_approx_drilled.stl"
BOLT_R = float(sys.argv[1]) if len(sys.argv) > 1 else 1.4   # M2.5 clearance ~2.8mm; tune per screw
CLEAR = float(sys.argv[2]) if len(sys.argv) > 2 else 0.5    # holder cavity print gap; loosened 0.3->0.5
                                                            # after print test (0.3 was a cracking tight fit)

# servo mount holes (x,z) the box covers, screws along +-Y:
TOP = [(3.5, 10.2), (3.5, -10.2)]    # +Y (horn-side) face
BOT = [(7.2, 10.2), (7.2, -10.2)]    # -Y (idler-side) face


def _cyl_Y(x, z, r, h=60.0):
    c = trimesh.creation.cylinder(radius=r, height=h)
    c.apply_transform(trimesh.transformations.rotation_matrix(np.pi / 2, [1, 0, 0]))  # Z->Y
    c.apply_translation([x, 0.0, z])
    return c


m = trimesh.load(SRC, force="mesh")

# subtract the servo body so the holder seats on it with a print gap. The raw st3215 mesh isn't
# watertight, so use its convex hull (clean, watertight, hugs the housing) dilated by CLEAR.
hull = trimesh.load(SERVO, force="mesh").convex_hull
hull.vertices += hull.vertex_normals * CLEAR
m = trimesh.boolean.difference([m, hull], engine="manifold")

for (x, z) in TOP + BOT:                                    # screw holes through the remaining walls
    m = trimesh.boolean.difference([m, _cyl_Y(x, z, BOLT_R)], engine="manifold")
m.export(OUT)
print(f"wrote {OUT}  holes={len(TOP+BOT)} r={BOLT_R} clear={CLEAR}  watertight={m.is_watertight}  vol={m.volume/1000:.1f}cm3")
