Add rib_web to Brain output + import_profile draws rib material
Brain: profile_assembly.py now exports 'rib_web' — the actual material geometry from Shapely boolean (exterior + interior rings). This is the rib shape, not the pocket cutouts. import_profile.py: prefers rib_web when available, drawing exterior + interior polyline rings directly. Falls back to pocket-based drawing for older rib JSONs without rib_web.
This commit is contained in:
@@ -106,10 +106,28 @@ def profile_to_json(ribbed_plate, pockets, geometry, params):
|
||||
'is_circular': True,
|
||||
})
|
||||
|
||||
# Rib web profile: the actual material geometry from Shapely boolean
|
||||
# This is what NX needs to draw — the ribs, not the pockets.
|
||||
rib_web_rings = []
|
||||
if ribbed_plate.geom_type == 'Polygon':
|
||||
polys = [ribbed_plate]
|
||||
elif ribbed_plate.geom_type == 'MultiPolygon':
|
||||
polys = list(ribbed_plate.geoms)
|
||||
else:
|
||||
polys = []
|
||||
|
||||
for poly in polys:
|
||||
ring = {
|
||||
'exterior': [list(c) for c in poly.exterior.coords],
|
||||
'interiors': [[list(c) for c in interior.coords] for interior in poly.interiors],
|
||||
}
|
||||
rib_web_rings.append(ring)
|
||||
|
||||
return {
|
||||
'valid': True,
|
||||
'outer_boundary': outer,
|
||||
'pockets': pocket_data,
|
||||
'holes': hole_data,
|
||||
'rib_web': rib_web_rings,
|
||||
'parameters_used': params,
|
||||
}
|
||||
|
||||
@@ -877,81 +877,93 @@ def main():
|
||||
continue
|
||||
|
||||
# --- Draw geometry ---
|
||||
pockets = profile.get("pockets", [])
|
||||
outer_2d = profile.get("outer_boundary", [])
|
||||
rib_web = profile.get("rib_web", [])
|
||||
|
||||
# Check if pockets are structured (lines+arcs) or legacy (point lists)
|
||||
is_structured = (len(pockets) > 0 and isinstance(pockets[0], dict)
|
||||
and 'lines' in pockets[0])
|
||||
|
||||
if is_structured:
|
||||
lister.WriteLine(f"[import] Structured format: {len(pockets)} pockets + outer boundary")
|
||||
|
||||
# Outer boundary (handles both v1.0 polyline and v2.0 typed segments)
|
||||
outer_lines, outer_arcs = _draw_outer_boundary(work_part, outer_2d, transform, lister)
|
||||
lister.WriteLine(f"[import] Outer boundary: {outer_lines} lines + {outer_arcs} arcs")
|
||||
|
||||
# Pockets
|
||||
total_lines = outer_lines
|
||||
total_arcs = outer_arcs
|
||||
for idx, pocket in enumerate(pockets):
|
||||
nl, na = _draw_structured_pocket(work_part, pocket, transform, lister)
|
||||
total_lines += nl
|
||||
total_arcs += na
|
||||
if (idx + 1) % 50 == 0:
|
||||
lister.WriteLine(f"[import] ... {idx+1}/{len(pockets)} pockets drawn")
|
||||
|
||||
lister.WriteLine(f"[import] Done: {total_lines} lines + {total_arcs} arcs in sketch")
|
||||
lister.WriteLine(f"[import] Expected: ~{len(pockets)*3} lines + ~{len(pockets)*3} arcs")
|
||||
|
||||
# Holes (bolt circles etc.)
|
||||
holes = profile.get("holes", [])
|
||||
if holes:
|
||||
holes_drawn = 0
|
||||
for hole in holes:
|
||||
try:
|
||||
cx, cy = hole["center"]
|
||||
r = hole["diameter"] / 2.0
|
||||
# Draw as circle: 3 points on circumference
|
||||
p1 = [cx + r, cy]
|
||||
p2 = [cx, cy + r]
|
||||
p3 = [cx - r, cy]
|
||||
p1_3d = unproject_point_to_3d(p1, transform)
|
||||
p2_3d = unproject_point_to_3d(p2, transform)
|
||||
p3_3d = unproject_point_to_3d(p3, transform)
|
||||
_draw_arc_3pt(work_part, p1_3d, p2_3d, p3_3d)
|
||||
# Second half of circle
|
||||
p4 = [cx, cy - r]
|
||||
p4_3d = unproject_point_to_3d(p4, transform)
|
||||
_draw_arc_3pt(work_part, p3_3d, p4_3d, p1_3d)
|
||||
holes_drawn += 1
|
||||
total_arcs += 2
|
||||
except Exception as exc:
|
||||
lister.WriteLine(f"[import] WARN: hole {hole.get('index','?')} failed: {exc}")
|
||||
lister.WriteLine(f"[import] Holes: {holes_drawn}/{len(holes)} drawn ({holes_drawn*2} arcs)")
|
||||
|
||||
else:
|
||||
# Legacy format: pockets are point lists
|
||||
lister.WriteLine(f"[import] Legacy format: {len(pockets)} pocket polylines")
|
||||
outer_lines, outer_arcs = _draw_outer_boundary(work_part, outer_2d, transform, lister)
|
||||
total_lines = outer_lines
|
||||
for pocket_pts in pockets:
|
||||
if len(pocket_pts) < 3:
|
||||
continue
|
||||
pocket_3d = unproject_to_3d(pocket_pts, transform)
|
||||
n = len(pocket_3d)
|
||||
d = math.sqrt(sum((a - b)**2 for a, b in zip(pocket_3d[0], pocket_3d[-1])))
|
||||
if rib_web:
|
||||
# ===== RIB WEB MODE: draw the actual material profile =====
|
||||
# rib_web is a list of polygon rings, each with 'exterior' and 'interiors'
|
||||
# The exterior is the outer boundary of the rib material
|
||||
# Each interior is a cutout (pocket or bolt hole)
|
||||
total_lines = 0
|
||||
for ring_idx, ring in enumerate(rib_web):
|
||||
# Draw exterior ring
|
||||
ext_pts = ring['exterior']
|
||||
ext_3d = unproject_to_3d(ext_pts, transform)
|
||||
n = len(ext_3d)
|
||||
# Close if needed
|
||||
d = math.sqrt(sum((a - b)**2 for a, b in zip(ext_3d[0], ext_3d[-1])))
|
||||
if d < 0.001:
|
||||
n -= 1
|
||||
for i in range(n):
|
||||
try:
|
||||
_draw_line(work_part, pocket_3d[i], pocket_3d[(i+1) % n])
|
||||
_draw_line(work_part, ext_3d[i], ext_3d[(i+1) % n])
|
||||
total_lines += 1
|
||||
except Exception:
|
||||
pass
|
||||
lister.WriteLine(f"[import] Done: {total_lines} lines in sketch")
|
||||
lister.WriteLine(f"[import] Ring {ring_idx}: exterior {total_lines} lines")
|
||||
|
||||
# Holes (legacy path too)
|
||||
# Draw interior rings (pocket/hole cutouts)
|
||||
for int_idx, interior in enumerate(ring.get('interiors', [])):
|
||||
int_3d = unproject_to_3d(interior, transform)
|
||||
m = len(int_3d)
|
||||
d2 = math.sqrt(sum((a - b)**2 for a, b in zip(int_3d[0], int_3d[-1])))
|
||||
if d2 < 0.001:
|
||||
m -= 1
|
||||
for i in range(m):
|
||||
try:
|
||||
_draw_line(work_part, int_3d[i], int_3d[(i+1) % m])
|
||||
total_lines += 1
|
||||
except Exception:
|
||||
pass
|
||||
if (int_idx + 1) % 50 == 0:
|
||||
lister.WriteLine(f"[import] ... {int_idx+1}/{len(ring['interiors'])} interiors drawn")
|
||||
|
||||
num_interiors = sum(len(r.get('interiors', [])) for r in rib_web)
|
||||
lister.WriteLine(f"[import] Rib web: {len(rib_web)} ring(s), {num_interiors} interiors, {total_lines} total lines")
|
||||
|
||||
else:
|
||||
# ===== LEGACY FALLBACK: pocket-based drawing =====
|
||||
pockets = profile.get("pockets", [])
|
||||
outer_2d = profile.get("outer_boundary", [])
|
||||
|
||||
# Check if pockets are structured (lines+arcs) or legacy (point lists)
|
||||
is_structured = (len(pockets) > 0 and isinstance(pockets[0], dict)
|
||||
and 'lines' in pockets[0])
|
||||
|
||||
if is_structured:
|
||||
lister.WriteLine(f"[import] Structured format: {len(pockets)} pockets + outer boundary")
|
||||
outer_lines, outer_arcs = _draw_outer_boundary(work_part, outer_2d, transform, lister)
|
||||
lister.WriteLine(f"[import] Outer boundary: {outer_lines} lines + {outer_arcs} arcs")
|
||||
total_lines = outer_lines
|
||||
total_arcs = outer_arcs
|
||||
for idx, pocket in enumerate(pockets):
|
||||
nl, na = _draw_structured_pocket(work_part, pocket, transform, lister)
|
||||
total_lines += nl
|
||||
total_arcs += na
|
||||
if (idx + 1) % 50 == 0:
|
||||
lister.WriteLine(f"[import] ... {idx+1}/{len(pockets)} pockets drawn")
|
||||
lister.WriteLine(f"[import] Done: {total_lines} lines + {total_arcs} arcs in sketch")
|
||||
else:
|
||||
lister.WriteLine(f"[import] Legacy format: {len(pockets)} pocket polylines")
|
||||
outer_lines, outer_arcs = _draw_outer_boundary(work_part, outer_2d, transform, lister)
|
||||
total_lines = outer_lines
|
||||
for pocket_pts in pockets:
|
||||
if len(pocket_pts) < 3:
|
||||
continue
|
||||
pocket_3d = unproject_to_3d(pocket_pts, transform)
|
||||
n = len(pocket_3d)
|
||||
d = math.sqrt(sum((a - b)**2 for a, b in zip(pocket_3d[0], pocket_3d[-1])))
|
||||
if d < 0.001:
|
||||
n -= 1
|
||||
for i in range(n):
|
||||
try:
|
||||
_draw_line(work_part, pocket_3d[i], pocket_3d[(i+1) % n])
|
||||
total_lines += 1
|
||||
except Exception:
|
||||
pass
|
||||
lister.WriteLine(f"[import] Done: {total_lines} lines in sketch")
|
||||
|
||||
# Holes for legacy/structured fallback
|
||||
holes = profile.get("holes", [])
|
||||
if holes:
|
||||
holes_drawn = 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user