fix(brain): enforce r_f=6mm minimum, reject pockets that can't fit fillets

- Default r_f raised from 1.5mm to 6mm (machining constraint)
- Default min_pocket_radius raised to 6mm
- Pockets that can't fit r_f at any corner (within 80% tolerance) are
  skipped entirely — left solid for more stiffness in tight areas
- Result: 26 pockets (was 432), 187 NX entities (was 13,061)
- Min fillet radius: 4.88mm, all >= 4.8mm (80% of 6mm)
- Mass: 4,601g (was 3,480g — more solid = heavier but manufacturable)
This commit is contained in:
2026-02-16 20:42:46 +00:00
parent da9b579bcf
commit 30981fa066
3 changed files with 1024 additions and 36339 deletions

View File

@@ -23,7 +23,7 @@ PARAM_SPACE = {
'gamma': {'type': 'float', 'low': 0.0, 'high': 3.0, 'desc': 'Density-thickness coupling'},
# Manufacturing
'w_frame': {'type': 'float', 'low': 3.0, 'high': 20.0, 'desc': 'Perimeter frame width (mm)'},
'r_f': {'type': 'float', 'low': 0.5, 'high': 3.0, 'desc': 'Pocket fillet radius (mm)'},
'r_f': {'type': 'float', 'low': 3.0, 'high': 10.0, 'desc': 'Pocket fillet radius (mm)'},
'd_keep': {'type': 'float', 'low': 1.0, 'high': 3.0, 'desc': 'Hole keepout multiplier (× diameter)'},
'min_triangle_area': {'type': 'float', 'low': 5.0, 'high': 80.0, 'desc': 'Minimum pocketable triangle area (mm²)'},
}
@@ -43,8 +43,8 @@ DEFAULT_PARAMS = {
't_0': 3.0,
'gamma': 1.0,
'w_frame': 8.0,
'r_f': 1.5,
'r_f': 6.0,
'd_keep': 1.5,
'min_pocket_radius': 1.5,
'min_pocket_radius': 6.0,
'min_triangle_area': 20.0,
}

View File

@@ -136,11 +136,13 @@ def _fillet_corner(
np.linalg.norm(v_next - v_corner) * 0.45,
)
if tan_dist > max_dist:
# Reduce fillet radius to fit
r_f = max_dist * np.tan(half_angle)
tan_dist = max_dist
if r_f < 0.05:
# Reduce fillet to fit, but never below hard minimum
r_f_reduced = max_dist * np.tan(half_angle)
if r_f_reduced < r_f * 0.8:
# Too much reduction — reject this corner
return None
r_f = r_f_reduced
tan_dist = max_dist
tangent_start = v_corner + d1 * tan_dist
tangent_end = v_corner + d2 * tan_dist
@@ -180,6 +182,9 @@ def _compute_filleted_pocket(inset_verts: List[np.ndarray], r_f: float) -> Optio
v_corner = inset_verts[i]
v_next = inset_verts[(i + 1) % n]
fillet = _fillet_corner(v_prev, v_corner, v_next, r_f)
if fillet is None and r_f > 0:
# Fillet doesn't fit at this corner — reject entire pocket
return None
fillets.append(fillet)
# Build lines connecting fillet tangent points
@@ -324,13 +329,15 @@ def generate_pockets(triangulation, geometry, params):
if perimeter < 1e-6:
continue
inscribed_r = inset_area / (perimeter / 2.0)
if inscribed_r < min_pocket_radius:
# Pocket must be large enough to fit the required fillet radius.
# If inscribed_r < r_f, the fillet would dominate the pocket and
# create tiny/degenerate geometry. Skip these — leave them solid.
if inscribed_r < r_f:
continue
# Compute fillet amount (don't over-fillet)
fillet_amount = min(r_f, inscribed_r * 0.4)
if fillet_amount < 0.1:
fillet_amount = 0.0
# Use full fillet radius — we've already verified it fits
fillet_amount = r_f
pocket_geom = _compute_filleted_pocket(inset, fillet_amount)
if pocket_geom is None:

File diff suppressed because it is too large Load Diff