fix: v1 boundary handling — inset vertices, 3-point hole keepouts, boundary-aligned triangles, smooth plotting
- Triangulation: force inset boundary corner vertices for v1 geometry (Shapely buffer) - Hole keepouts: 3 evenly-spaced points per circular hole (not dense polyline) - Boundary layer: seed points derived from inset polygon for proper alignment - Triangle filtering: full polygon coverage check against inset-valid region - Plotting: uniform polyline resampling for smooth v1 boundaries, analytic circle rendering - Verified: 0 bad triangles on both Quicksat sandboxes
This commit is contained in:
@@ -48,7 +48,39 @@ def _plot_boundary_polyline(geometry: Dict[str, Any], arc_pts: int = 64) -> np.n
|
||||
pts = typed_segments_to_polyline(typed, arc_pts=arc_pts)
|
||||
if len(pts) >= 3:
|
||||
return np.asarray(pts, dtype=float)
|
||||
return np.asarray(geometry["outer_boundary"], dtype=float)
|
||||
|
||||
outer = np.asarray(geometry["outer_boundary"], dtype=float)
|
||||
if len(outer) < 4:
|
||||
return outer
|
||||
# v1 fallback: dense polyline boundaries may encode fillets.
|
||||
# Resample uniformly for smoother plotting while preserving the polygon path.
|
||||
if np.allclose(outer[0], outer[-1]):
|
||||
ring = outer
|
||||
else:
|
||||
ring = np.vstack([outer, outer[0]])
|
||||
seg = np.diff(ring, axis=0)
|
||||
seg_len = np.hypot(seg[:, 0], seg[:, 1])
|
||||
nonzero = seg_len[seg_len > 1e-9]
|
||||
if len(nonzero) == 0:
|
||||
return outer
|
||||
step = max(float(np.median(nonzero) * 0.5), 0.5)
|
||||
cum = np.r_[0.0, np.cumsum(seg_len)]
|
||||
total = float(cum[-1])
|
||||
if total <= step:
|
||||
return outer
|
||||
samples = np.arange(0.0, total, step, dtype=float)
|
||||
if samples[-1] < total:
|
||||
samples = np.r_[samples, total]
|
||||
out = []
|
||||
j = 0
|
||||
for s in samples:
|
||||
while j < len(cum) - 2 and cum[j + 1] < s:
|
||||
j += 1
|
||||
den = max(cum[j + 1] - cum[j], 1e-12)
|
||||
t = (s - cum[j]) / den
|
||||
p = ring[j] + t * (ring[j + 1] - ring[j])
|
||||
out.append([float(p[0]), float(p[1])])
|
||||
return np.asarray(out, dtype=float)
|
||||
|
||||
|
||||
def _plot_density(geometry: Dict[str, Any], params: Dict[str, Any], out_path: Path, resolution: float = 3.0) -> None:
|
||||
@@ -62,7 +94,13 @@ def _plot_density(geometry: Dict[str, Any], params: Dict[str, Any], out_path: Pa
|
||||
ax.plot(np.r_[outer[:, 0], outer[0, 0]], np.r_[outer[:, 1], outer[0, 1]], "w-", lw=1.5)
|
||||
|
||||
for hole in geometry.get("holes", []):
|
||||
hb = np.asarray(hole["boundary"])
|
||||
if hole.get("is_circular", False) and "center" in hole and "diameter" in hole:
|
||||
cx, cy = hole["center"]
|
||||
r = float(hole["diameter"]) * 0.5
|
||||
a = np.linspace(0.0, 2.0 * np.pi, 90, endpoint=True)
|
||||
hb = np.column_stack([cx + r * np.cos(a), cy + r * np.sin(a)])
|
||||
else:
|
||||
hb = np.asarray(hole["boundary"])
|
||||
ax.plot(np.r_[hb[:, 0], hb[0, 0]], np.r_[hb[:, 1], hb[0, 1]], "k-", lw=0.9)
|
||||
|
||||
ax.set_aspect("equal", adjustable="box")
|
||||
@@ -123,7 +161,13 @@ def _plot_triangulation(geometry: Dict[str, Any], triangulation: Dict[str, Any],
|
||||
|
||||
# Blue hole circles
|
||||
for hole in geometry.get("holes", []):
|
||||
hb = np.asarray(hole["boundary"])
|
||||
if hole.get("is_circular", False) and "center" in hole and "diameter" in hole:
|
||||
cx, cy = hole["center"]
|
||||
r = float(hole["diameter"]) * 0.5
|
||||
a = np.linspace(0.0, 2.0 * np.pi, 90, endpoint=True)
|
||||
hb = np.column_stack([cx + r * np.cos(a), cy + r * np.sin(a)])
|
||||
else:
|
||||
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)
|
||||
|
||||
@@ -182,7 +226,13 @@ def _plot_final_profile(geometry, pockets, ribbed_plate, out_path: Path, params:
|
||||
|
||||
# Blue hole circles
|
||||
for hole in geometry.get("holes", []):
|
||||
hb = np.asarray(hole["boundary"])
|
||||
if hole.get("is_circular", False) and "center" in hole and "diameter" in hole:
|
||||
cx, cy = hole["center"]
|
||||
r = float(hole["diameter"]) * 0.5
|
||||
a = np.linspace(0.0, 2.0 * np.pi, 90, endpoint=True)
|
||||
hb = np.column_stack([cx + r * np.cos(a), cy + r * np.sin(a)])
|
||||
else:
|
||||
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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user