diff --git a/masque/shapes/arc.py b/masque/shapes/arc.py index a068700..ab2e47b 100644 --- a/masque/shapes/arc.py +++ b/masque/shapes/arc.py @@ -268,7 +268,7 @@ class Arc(PositionableImpl, Shape): """ Figure out the parameter values at which we should place vertices to meet the arclength constraint""" dr = -wh if inner else wh - n_pts = numpy.ceil(2 * pi * max(self.radii + dr) / max_arclen).astype(int) + n_pts = max(2, int(numpy.ceil(2 * pi * max(self.radii + dr) / max_arclen))) arc_lengths, thetas = get_arclens(n_pts, *a_ranges[0 if inner else 1], dr=dr) keep = [0] diff --git a/masque/shapes/circle.py b/masque/shapes/circle.py index 8dad165..a6f7af1 100644 --- a/masque/shapes/circle.py +++ b/masque/shapes/circle.py @@ -108,7 +108,7 @@ class Circle(PositionableImpl, Shape): n += [num_vertices] if max_arclen is not None: n += [2 * pi * self.radius / max_arclen] - num_vertices = int(round(max(n))) + num_vertices = max(3, int(round(max(n)))) thetas = numpy.linspace(2 * pi, 0, num_vertices, endpoint=False) xs = numpy.cos(thetas) * self.radius ys = numpy.sin(thetas) * self.radius diff --git a/masque/shapes/ellipse.py b/masque/shapes/ellipse.py index 8a5c287..55ce9fd 100644 --- a/masque/shapes/ellipse.py +++ b/masque/shapes/ellipse.py @@ -168,7 +168,7 @@ class Ellipse(PositionableImpl, Shape): n += [num_vertices] if max_arclen is not None: n += [perimeter / max_arclen] - num_vertices = int(round(max(n))) + num_vertices = max(3, int(round(max(n)))) thetas = numpy.linspace(2 * pi, 0, num_vertices, endpoint=False) sin_th, cos_th = (numpy.sin(thetas), numpy.cos(thetas)) diff --git a/masque/test/test_shape_advanced.py b/masque/test/test_shape_advanced.py index ab42b4b..fc76fcb 100644 --- a/masque/test/test_shape_advanced.py +++ b/masque/test/test_shape_advanced.py @@ -109,6 +109,19 @@ def test_rotated_arc_bounds_match_polygonized_geometry() -> None: bounds = arc.get_bounds_single() poly_bounds = arc.to_polygons(num_vertices=8192)[0].get_bounds_single() assert_allclose(bounds, poly_bounds, atol=1e-3) + + +def test_curve_polygonizers_clamp_large_max_arclen() -> None: + for shape in ( + Circle(radius=10), + Ellipse(radii=(10, 20)), + Arc(radii=(10, 20), angles=(0, 1), width=2), + ): + polys = shape.to_polygons(num_vertices=None, max_arclen=1e9) + assert len(polys) == 1 + assert len(polys[0].vertices) >= 3 + + def test_path_edge_cases() -> None: # Zero-length segments p = MPath(vertices=[[0, 0], [0, 0], [10, 0]], width=2)