fix: match reference rib profile style — green boundary, pink outlines, blue holes, 2mm w_frame, zoomed corner view, pocket clipping to inner plate
This commit is contained in:
@@ -63,23 +63,30 @@ def _plot_density(geometry: Dict[str, Any], params: Dict[str, Any], out_path: Pa
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def _plot_triangulation(geometry: Dict[str, Any], triangulation: Dict[str, Any], out_path: Path) -> None:
|
||||
from shapely.geometry import Polygon as ShapelyPolygon, LineString
|
||||
def _plot_triangulation(geometry: Dict[str, Any], triangulation: Dict[str, Any], out_path: Path, params: Dict[str, Any] = None) -> None:
|
||||
"""
|
||||
Plot the Delaunay triangulation clipped to the inner frame (w_frame inset).
|
||||
Green boundary, blue rib edges, blue hole circles.
|
||||
"""
|
||||
from shapely.geometry import Polygon as ShapelyPolygon, LineString, Point
|
||||
|
||||
verts = triangulation["vertices"]
|
||||
tris = triangulation["triangles"]
|
||||
|
||||
fig, ax = plt.subplots(figsize=(8, 6), dpi=160)
|
||||
|
||||
outer = np.asarray(geometry["outer_boundary"])
|
||||
plate_poly = ShapelyPolygon(outer)
|
||||
w_frame = (params or {}).get("w_frame", 2.0)
|
||||
inner_plate = plate_poly.buffer(-w_frame)
|
||||
if inner_plate.is_empty or not inner_plate.is_valid:
|
||||
inner_plate = plate_poly
|
||||
|
||||
# Draw only triangle edges that are inside the boundary (clipped)
|
||||
fig, ax = plt.subplots(figsize=(8, 6), dpi=160)
|
||||
|
||||
# Draw triangle edges clipped to inner plate
|
||||
drawn_edges = set()
|
||||
for tri in tris:
|
||||
centroid = verts[tri].mean(axis=0)
|
||||
from shapely.geometry import Point
|
||||
if not plate_poly.contains(Point(centroid)):
|
||||
centroid = Point(verts[tri].mean(axis=0))
|
||||
if not inner_plate.contains(centroid):
|
||||
continue
|
||||
for i in range(3):
|
||||
edge = tuple(sorted([tri[i], tri[(i + 1) % 3]]))
|
||||
@@ -88,22 +95,26 @@ def _plot_triangulation(geometry: Dict[str, Any], triangulation: Dict[str, Any],
|
||||
drawn_edges.add(edge)
|
||||
p1, p2 = verts[edge[0]], verts[edge[1]]
|
||||
line = LineString([p1, p2])
|
||||
clipped = plate_poly.intersection(line)
|
||||
clipped = inner_plate.intersection(line)
|
||||
if clipped.is_empty:
|
||||
continue
|
||||
if clipped.geom_type == "LineString":
|
||||
cx, cy = clipped.xy
|
||||
ax.plot(cx, cy, color="#1f77b4", lw=0.4, alpha=0.85)
|
||||
ax.plot(cx, cy, color="#1f77b4", lw=0.5, alpha=0.85)
|
||||
elif clipped.geom_type == "MultiLineString":
|
||||
for seg in clipped.geoms:
|
||||
cx, cy = seg.xy
|
||||
ax.plot(cx, cy, color="#1f77b4", lw=0.4, alpha=0.85)
|
||||
ax.plot(cx, cy, color="#1f77b4", lw=0.5, alpha=0.85)
|
||||
|
||||
ax.plot(np.r_[outer[:, 0], outer[0, 0]], np.r_[outer[:, 1], outer[0, 1]], "k-", lw=1.6)
|
||||
# Green sandbox boundary
|
||||
ax.plot(np.r_[outer[:, 0], outer[0, 0]], np.r_[outer[:, 1], outer[0, 1]],
|
||||
color="#228833", lw=1.8, zorder=5)
|
||||
|
||||
# Blue hole circles
|
||||
for hole in geometry.get("holes", []):
|
||||
hb = np.asarray(hole["boundary"])
|
||||
ax.fill(hb[:, 0], hb[:, 1], color="white", zorder=2)
|
||||
ax.plot(np.r_[hb[:, 0], hb[0, 0]], np.r_[hb[:, 1], hb[0, 1]], "r-", lw=1.0, zorder=3)
|
||||
ax.plot(np.r_[hb[:, 0], hb[0, 0]], np.r_[hb[:, 1], hb[0, 1]],
|
||||
"b-", lw=0.8, zorder=3)
|
||||
|
||||
ax.set_aspect("equal", adjustable="box")
|
||||
ax.set_title("Constrained Delaunay Triangulation / Rib Pattern")
|
||||
@@ -114,60 +125,77 @@ def _plot_triangulation(geometry: Dict[str, Any], triangulation: Dict[str, Any],
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def _plot_final_profile(geometry, pockets, ribbed_plate, out_path: Path) -> None:
|
||||
def _plot_final_profile(geometry, pockets, ribbed_plate, out_path: Path, params: Dict[str, Any] = None) -> None:
|
||||
"""
|
||||
Plot the rib profile: green sandbox boundary, pink pocket outlines (clipped),
|
||||
blue hole circles. Pockets must respect w_frame inset from boundary.
|
||||
Also produces a zoomed corner view as a second subplot.
|
||||
"""
|
||||
from shapely.geometry import Polygon as ShapelyPolygon
|
||||
from matplotlib.patches import PathPatch
|
||||
from matplotlib.path import Path as MplPath
|
||||
|
||||
fig, ax = plt.subplots(figsize=(8, 6), dpi=160)
|
||||
|
||||
outer = np.asarray(geometry["outer_boundary"])
|
||||
plate_poly = ShapelyPolygon(outer)
|
||||
ax.plot(np.r_[outer[:, 0], outer[0, 0]], np.r_[outer[:, 1], outer[0, 1]], "k-", lw=1.8, label="Outer boundary")
|
||||
w_frame = (params or {}).get("w_frame", 2.0)
|
||||
inner_plate = plate_poly.buffer(-w_frame)
|
||||
if inner_plate.is_empty or not inner_plate.is_valid:
|
||||
inner_plate = plate_poly
|
||||
|
||||
# Draw pockets clipped to the plate boundary — no crossovers
|
||||
for pocket in pockets:
|
||||
polyline = pocket.get("polyline", pocket.get("vertices", []))
|
||||
pv = np.asarray(polyline)
|
||||
if len(pv) >= 3:
|
||||
fig, (ax_full, ax_zoom) = plt.subplots(1, 2, figsize=(14, 6), dpi=160)
|
||||
|
||||
for ax in (ax_full, ax_zoom):
|
||||
# Green sandbox boundary
|
||||
ax.plot(np.r_[outer[:, 0], outer[0, 0]], np.r_[outer[:, 1], outer[0, 1]],
|
||||
color="#228833", lw=1.8, zorder=5)
|
||||
|
||||
# Draw pockets clipped to inner plate (w_frame inset) — outlines only
|
||||
for pocket in pockets:
|
||||
polyline = pocket.get("polyline", pocket.get("vertices", []))
|
||||
pv = np.asarray(polyline)
|
||||
if len(pv) < 3:
|
||||
continue
|
||||
pocket_poly = ShapelyPolygon(pv)
|
||||
if not pocket_poly.is_valid:
|
||||
pocket_poly = pocket_poly.buffer(0)
|
||||
if pocket_poly.is_empty:
|
||||
continue
|
||||
clipped = plate_poly.intersection(pocket_poly)
|
||||
clipped = inner_plate.intersection(pocket_poly)
|
||||
if clipped.is_empty:
|
||||
continue
|
||||
# Draw clipped geometry
|
||||
clip_geoms = [clipped] if clipped.geom_type == "Polygon" else list(clipped.geoms)
|
||||
clip_geoms = [clipped] if clipped.geom_type == "Polygon" else list(getattr(clipped, "geoms", []))
|
||||
for cg in clip_geoms:
|
||||
if cg.geom_type != "Polygon" or cg.is_empty:
|
||||
continue
|
||||
cx, cy = cg.exterior.xy
|
||||
ax.fill(cx, cy, color="#88ccee", alpha=0.35, lw=0.0)
|
||||
ax.fill(cx, cy, color="#ffcccc", alpha=0.25, lw=0.0)
|
||||
ax.plot(cx, cy, color="#cc6677", lw=0.9, zorder=4)
|
||||
|
||||
# Draw holes from geometry
|
||||
for hole in geometry.get("holes", []):
|
||||
hb = np.asarray(hole["boundary"])
|
||||
ax.fill(hb[:, 0], hb[:, 1], color="white", lw=0.0)
|
||||
ax.plot(np.r_[hb[:, 0], hb[0, 0]], np.r_[hb[:, 1], hb[0, 1]], "k-", lw=0.7)
|
||||
# Blue hole circles
|
||||
for hole in geometry.get("holes", []):
|
||||
hb = np.asarray(hole["boundary"])
|
||||
ax.plot(np.r_[hb[:, 0], hb[0, 0]], np.r_[hb[:, 1], hb[0, 1]],
|
||||
"b-", lw=0.8, zorder=3)
|
||||
|
||||
if ribbed_plate.geom_type == "Polygon":
|
||||
geoms = [ribbed_plate]
|
||||
else:
|
||||
geoms = list(ribbed_plate.geoms)
|
||||
ax.set_aspect("equal", adjustable="box")
|
||||
ax.set_xlabel("x [mm]")
|
||||
ax.set_ylabel("y [mm]")
|
||||
|
||||
for g in geoms:
|
||||
x, y = g.exterior.xy
|
||||
ax.plot(x, y, color="#228833", lw=1.2)
|
||||
for i in g.interiors:
|
||||
ix, iy = i.xy
|
||||
ax.plot(ix, iy, color="#cc6677", lw=0.9)
|
||||
# Full view
|
||||
num_pockets_shown = sum(
|
||||
1 for p in pockets
|
||||
if len(p.get("polyline", p.get("vertices", []))) >= 3
|
||||
and not inner_plate.intersection(
|
||||
ShapelyPolygon(p.get("polyline", p.get("vertices", []))).buffer(0)
|
||||
).is_empty
|
||||
)
|
||||
ax_full.set_title(f"Full view ({num_pockets_shown} pockets)")
|
||||
|
||||
# Zoomed view on a corner area (top-right where crossovers were worst)
|
||||
bounds = plate_poly.bounds # minx, miny, maxx, maxy
|
||||
mid_x = (bounds[0] + bounds[2]) / 2
|
||||
ax_zoom.set_xlim(mid_x - 30, bounds[2] + 10)
|
||||
ax_zoom.set_ylim(bounds[3] - 60, bounds[3] + 10)
|
||||
ax_zoom.set_title("Zoomed: corner area")
|
||||
|
||||
ax.set_aspect("equal", adjustable="box")
|
||||
ax.set_title("Final Ribbed Plate Profile with Pockets")
|
||||
ax.set_xlabel("x [mm]")
|
||||
ax.set_ylabel("y [mm]")
|
||||
fig.tight_layout()
|
||||
fig.savefig(out_path)
|
||||
plt.close(fig)
|
||||
@@ -199,8 +227,8 @@ def run_pipeline(geometry_path: Path, params_path: Path | None, output_dir: Path
|
||||
|
||||
stem = geometry_path.stem
|
||||
_plot_density(geometry, params, output_dir / f"{stem}_density.png")
|
||||
_plot_triangulation(geometry, triangulation, output_dir / f"{stem}_triangulation.png")
|
||||
_plot_final_profile(geometry, pockets, ribbed_plate, output_dir / f"{stem}_final_profile.png")
|
||||
_plot_triangulation(geometry, triangulation, output_dir / f"{stem}_triangulation.png", params=params)
|
||||
_plot_final_profile(geometry, pockets, ribbed_plate, output_dir / f"{stem}_final_profile.png", params=params)
|
||||
|
||||
summary = {
|
||||
"geometry": geometry.get("plate_id", geometry_path.name),
|
||||
|
||||
Reference in New Issue
Block a user