The Problem
You’ve just generated a parametric 3D enclosure in Python using build123d or CadQuery. It has screw holes through the walls, a cable slot, a barrel jack cutout, and internal standoffs. The STL exports fine. The STEP looks good in your CAD viewer.
But does the cable slot actually go all the way through the wall? Are the screw holes clipping through the top edge? Is there a paper-thin wall where your subtraction was tangent instead of overlapping?
You could slice the model and look at cross-sections. We tried that. The vision model confidently declared features “missing” that were present and “correct” that were broken. Cross-section images of 3D geometry are surprisingly hard to interpret — even for humans, let alone AI.
We needed something deterministic.
The Solution: Point-in-Mesh Probing
Trimesh can tell you whether a point is inside or outside a watertight mesh. That’s it. That’s the whole trick. But it turns out “is this point inside the solid?” is the only question you need to verify almost any 3D feature.
import trimesh
import numpy as np
mesh = trimesh.load("enclosure_box.stl")
# Is this point inside the mesh (solid material)?
point = np.array([[25.0, -29.25, 37.25]])
is_solid = mesh.contains(point)[0]
If the point is where a hole should be, is_solid should be False. If it’s where wall material should be, it should be True. No image interpretation. No ambiguity. Just geometry.
Verifying Wall Holes
Say you have screw holes through the Y± walls of a box. The walls run from Y=±28 (inner face) to Y=±30.5 (outer face). A hole at position X=-25 on the Y- wall should make the wall center hollow:
# Wall center point at the screw position
wall_center = np.array([[-25.0, -29.25, 37.25]])
is_solid = mesh.contains(wall_center)[0]
if is_solid:
print("BUG: wall is solid — hole didn't cut through!")
else:
print("Hole verified — wall is hollow at screw position")
This is how we caught a rotation bug where align=UP after rot=(90,0,0) in build123d always grows toward +Y. For Y+ wall holes that’s outward (correct). For Y- wall holes that’s inward (wrong — the cylinder subtracted from the interior, not the wall). The ray-cast verification caught it instantly:
# All four screw positions
BOSS_POSITIONS = [(-25, +1), (+15, +1), (-25, -1), (+15, -1)]
for bx, wall_sign in BOSS_POSITIONS:
wall_center_y = wall_sign * 29.25 # midpoint of wall
point = np.array([[bx, wall_center_y, 37.25]])
is_solid = mesh.contains(point)[0]
wall = "Y+" if wall_sign > 0 else "Y-"
status = "SOLID (BUG!)" if is_solid else "HOLLOW (OK)"
print(f"X={bx:+d} {wall}: {status}")
Verifying Slot Penetration
A cable slot should create a complete void through the wall. Probe multiple points along the wall thickness:
# Cable slot at X=33.2 on Y+ wall
# Wall runs from Y=28.0 (inner) to Y=30.5 (outer)
for y in [28.0, 28.5, 29.0, 29.5, 30.0, 30.5]:
inside = mesh.contains(np.array([[33.2, y, 13.6]]))[0]
print(f"Y={y}: {'SOLID' if inside else 'hollow'}")
This is how we found that a Box() subtract centered at the wall face with depth WALL + 2 left a 0.25mm skin on the inner face. The box was 4.5mm deep, centered at Y=30.5, so it spanned Y=28.25 to Y=32.75 — but the inner wall face was at Y=28.0. A quarter-millimeter gap. Invisible in a cross-section image. Obvious in the point probe:
Y=28.0: SOLID ← Bug! Should be hollow.
Y=28.5: hollow
Y=29.0: hollow
...
Fix: WALL * 3 instead of WALL + 2. Generous oversize on subtractions costs nothing and prevents tangent-face artifacts.
Why Not Ray Casting?
Trimesh also supports ray casting (mesh.ray.intersects_location), and we used that too. But it has a subtle failure mode: when a ray passes through two aligned holes (both walls of a box), the near-wall hits can disappear entirely. The ray enters the first hole, exits into the interior, enters the second hole, and exits — but trimesh sometimes reports only the far-wall hits, making it look like the near wall is solid.
Point-in-mesh probing doesn’t have this problem. You’re asking about a specific location, not tracing a path.
We still use ray casting for some checks (verifying hole size by probing the edge), but contains() is the workhorse for existence checks.
Checking Feature Dimensions
Binary search with contains() can measure features to arbitrary precision:
def find_edge(mesh, start, direction, lo, hi, tol=0.01):
"""Binary search for the boundary between solid and void."""
while hi - lo > tol:
mid = (lo + hi) / 2
point = np.array([start + direction * mid])
if mesh.contains(point)[0]:
lo = mid
else:
hi = mid
return (lo + hi) / 2
# Find exact wall thickness at a point
outer_y = find_edge(mesh,
start=np.array([0, 25, 20]), # start inside
direction=np.array([0, 1, 0]), # probe toward +Y
lo=0, hi=10)
print(f"Wall inner face at Y={25 + outer_y:.2f}")
The Watertight Prerequisite
All of this requires a watertight mesh. If your STL has non-manifold faces, contains() returns garbage. We check this first:
mesh = trimesh.load("part.stl")
assert mesh.is_watertight, "Mesh not watertight — contains() will be unreliable"
One gotcha we hit: OCP’s STL tessellation creates non-manifold meshes when you subtract horizontal cylinders from rounded-rectangle prisms. The STEP geometry is valid, but the triangulation fails at the curved intersection. Workaround: use Box() subtracts (square holes) instead of Cylinder() for features in complex geometry, or increase tessellation quality:
export_stl(part, "output.stl", tolerance=0.01, angular_tolerance=0.05)
Putting It Together: An Automated Verify Script
Here’s the pattern we use — a verify.py that runs after every enclosure.py build:
import trimesh
import numpy as np
import sys
def check(name, condition, detail=""):
status = "✓" if condition else "✗ FAIL:"
print(f" {status} {name}" + (f" — {detail}" if detail else ""))
return condition
mesh = trimesh.load("output/enclosure_box.stl")
passed = 0
total = 0
# 1. Mesh integrity
total += 1
passed += check("Watertight", mesh.is_watertight)
# 2. Feature existence (point probes)
for name, point, expect_hollow in [
("Barrel jack hole", [-29.25, 10.2, 20.5], True),
("Cable slot center", [33.2, 29.25, 13.6], True),
("Wall solid", [0, 29.25, 20.0], False),
]:
total += 1
is_solid = mesh.contains(np.array([point]))[0]
ok = (not is_solid) if expect_hollow else is_solid
passed += check(name, ok, f"solid={is_solid}")
print(f"\n{passed}/{total} passed")
sys.exit(0 if passed == total else 1)
Run it after every model generation. If any check fails, the build fails. No more “it looked fine in the slicer” surprises.
Lessons Learned
Vision models can’t reliably read CAD cross-sections. They hallucinate features, misidentify positions, and confidently declare broken geometry correct. Don’t trust them for verification.
Point probes are deterministic.
contains()returns True or False. No interpretation needed.Oversize your subtractions.
WALL * 3costs nothing. Tangent faces create paper-thin walls that break prints and confuse slicers.Process chamfers longest-first. OCC’s chamfer operation modifies topology. Once you chamfer edge A, nearby edge B might become unchamberable. Do the big visible arcs first.
build123d rotation + align is tricky.
align=UPafter rotation grows in the rotated +Z direction. For arot=(90,0,0), that’s world +Y — which is outward for Y+ walls but inward for Y- walls. Usewall_sign * 90for the rotation angle.STL watertight ≠ STEP valid. OCP can produce valid BREP geometry that tessellates into non-manifold triangles. If your verify script reports non-watertight and the STEP opens fine in a CAD viewer, the tessellation is the problem, not the geometry.
This post was written at 3:30 AM after a day of designing, printing, debugging, and reprinting a custom ESP32 enclosure. The techniques above caught four separate geometry bugs that would have wasted filament and time. Sleep is for people without parametric models to verify.