[Arc] return clearer errors when working with an invalid arclength

This commit is contained in:
Jan Petykiewicz 2026-04-16 19:39:42 -07:00
commit d95ddbb6b9
2 changed files with 16 additions and 2 deletions

View file

@ -231,6 +231,8 @@ class Arc(PositionableImpl, Shape):
if (num_vertices is None) and (max_arclen is None): if (num_vertices is None) and (max_arclen is None):
raise PatternError('Max number of points and arclength left unspecified' raise PatternError('Max number of points and arclength left unspecified'
+ ' (default was also overridden)') + ' (default was also overridden)')
if max_arclen is not None and (numpy.isnan(max_arclen) or max_arclen <= 0):
raise PatternError('Max arclength must be positive and not NaN')
r0, r1 = self.radii r0, r1 = self.radii
@ -257,13 +259,19 @@ class Arc(PositionableImpl, Shape):
return arc_lengths, tt return arc_lengths, tt
wh = self.width / 2.0 wh = self.width / 2.0
arclen_limits: list[float] = []
if max_arclen is not None:
arclen_limits.append(max_arclen)
if num_vertices is not None: if num_vertices is not None:
n_pts = numpy.ceil(max(self.radii + wh) / min(self.radii) * num_vertices * 100).astype(int) n_pts = numpy.ceil(max(self.radii + wh) / min(self.radii) * num_vertices * 100).astype(int)
perimeter_inner = get_arclens(n_pts, *a_ranges[0], dr=-wh)[0].sum() perimeter_inner = get_arclens(n_pts, *a_ranges[0], dr=-wh)[0].sum()
perimeter_outer = get_arclens(n_pts, *a_ranges[1], dr= wh)[0].sum() perimeter_outer = get_arclens(n_pts, *a_ranges[1], dr= wh)[0].sum()
implied_arclen = (perimeter_outer + perimeter_inner + self.width * 2) / num_vertices implied_arclen = (perimeter_outer + perimeter_inner + self.width * 2) / num_vertices
max_arclen = min(implied_arclen, max_arclen if max_arclen is not None else numpy.inf) if not (numpy.isnan(implied_arclen) or implied_arclen <= 0):
assert max_arclen is not None arclen_limits.append(implied_arclen)
if not arclen_limits:
raise PatternError('Arc polygonization could not determine a valid max_arclen')
max_arclen = min(arclen_limits)
def get_thetas(inner: bool) -> NDArray[numpy.float64]: def get_thetas(inner: bool) -> NDArray[numpy.float64]:
""" Figure out the parameter values at which we should place vertices to meet the arclength constraint""" """ Figure out the parameter values at which we should place vertices to meet the arclength constraint"""

View file

@ -122,6 +122,12 @@ def test_curve_polygonizers_clamp_large_max_arclen() -> None:
assert len(polys[0].vertices) >= 3 assert len(polys[0].vertices) >= 3
def test_arc_polygonization_rejects_nan_implied_arclen() -> None:
arc = Arc(radii=(10, 20), angles=(0, numpy.nan), width=2)
with pytest.raises(PatternError, match='valid max_arclen'):
arc.to_polygons(num_vertices=24)
def test_ellipse_integer_radii_scale_cleanly() -> None: def test_ellipse_integer_radii_scale_cleanly() -> None:
ellipse = Ellipse(radii=(10, 20)) ellipse = Ellipse(radii=(10, 20))
ellipse.scale_by(0.5) ellipse.scale_by(0.5)