From 173c7b08e22f961265377b595c49fa9ca7920c3a Mon Sep 17 00:00:00 2001 From: x0pherl Date: Thu, 30 Oct 2025 21:08:26 -0400 Subject: [PATCH] added support for passing an iterable of radii to FilletPolyline. --- src/build123d/objects_curve.py | 22 +++++++++++++---- tests/test_build_line.py | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/build123d/objects_curve.py b/src/build123d/objects_curve.py index 262f9cf..6fbfbf6 100644 --- a/src/build123d/objects_curve.py +++ b/src/build123d/objects_curve.py @@ -793,7 +793,7 @@ class FilletPolyline(BaseLineObject): Args: pts (VectorLike | Iterable[VectorLike]): sequence of two or more points - radius (float): fillet radius + radius (float | Iterable[float]): radius to fillet at each vertex or a single value for all vertices close (bool, optional): close end points with extra Edge and corner fillets. Defaults to False mode (Mode, optional): combination mode. Defaults to Mode.ADD @@ -808,7 +808,7 @@ class FilletPolyline(BaseLineObject): def __init__( self, *pts: VectorLike | Iterable[VectorLike], - radius: float, + radius: float | Iterable[float], close: bool = False, mode: Mode = Mode.ADD, ): @@ -819,7 +819,16 @@ class FilletPolyline(BaseLineObject): if len(points) < 2: raise ValueError("FilletPolyline requires two or more pts") - if radius <= 0: + + if isinstance(radius, (int, float)): + radius_list = [radius] * len(points) # Single radius for all points + else: + radius_list = list(radius) + if len(radius_list) != len(points): + raise ValueError( + f"radius list length ({len(radius_list)}) must match points ({len(points)})" + ) + if any(r <= 0 for r in radius_list): raise ValueError("radius must be positive") lines_pts = WorkplaneList.localize(*points) @@ -852,12 +861,14 @@ class FilletPolyline(BaseLineObject): # For each corner vertex create a new fillet Edge fillets = [] - for vertex, edges in vertex_to_edges.items(): + for i, (vertex, edges) in enumerate(vertex_to_edges.items()): if len(edges) != 2: continue other_vertices = {ve for e in edges for ve in e.vertices() if ve != vertex} third_edge = Edge.make_line(*[v for v in other_vertices]) - fillet_face = Face(Wire(edges + [third_edge])).fillet_2d(radius, [vertex]) + fillet_face = Face(Wire(edges + [third_edge])).fillet_2d( + radius_list[i], [vertex] + ) fillets.append(fillet_face.edges().filter_by(GeomType.CIRCLE)[0]) # Create the Edges that join the fillets @@ -1597,6 +1608,7 @@ class ArcArcTangentLine(BaseEdgeObject): Defaults to Keep.INSIDE mode (Mode, optional): combination mode. Defaults to Mode.ADD """ + warnings.warn( "The 'ArcArcTangentLine' object is deprecated and will be removed in a future version.", DeprecationWarning, diff --git a/tests/test_build_line.py b/tests/test_build_line.py index 01c2fbe..7b5858f 100644 --- a/tests/test_build_line.py +++ b/tests/test_build_line.py @@ -183,6 +183,49 @@ class BuildLineTests(unittest.TestCase): self.assertEqual(len(p.edges().filter_by(GeomType.CIRCLE)), 2) self.assertEqual(len(p.edges().filter_by(GeomType.LINE)), 3) + with self.assertRaises(ValueError): + p = FilletPolyline( + (0, 0), + (10, 0), + (10, 10), + (0, 10), + radius=(1, 2, 3, 0), + close=True, + ) + + with self.assertRaises(ValueError): + p = FilletPolyline( + (0, 0), + (10, 0), + (10, 10), + (0, 10), + radius=-1, + close=True, + ) + + with self.assertRaises(ValueError): + p = FilletPolyline( + (0, 0), + (10, 0), + (10, 10), + (0, 10), + radius=(1, 2), + close=True, + ) + + with BuildLine(Plane.YZ): + p = FilletPolyline( + (0, 0), + (10, 0), + (10, 10), + (0, 10), + radius=(1, 2, 3, 4), + close=True, + ) + self.assertEqual(len(p.edges()), 8) + self.assertEqual(len(p.edges().filter_by(GeomType.CIRCLE)), 4) + self.assertEqual(len(p.edges().filter_by(GeomType.LINE)), 4) + with BuildLine(Plane.YZ): p = FilletPolyline( (0, 0, 0), (0, 0, 10), (10, 2, 10), (10, 0, 0), radius=2, close=True