diff --git a/src/build123d/topology.py b/src/build123d/topology.py index 476a5862..9fa5deaf 100644 --- a/src/build123d/topology.py +++ b/src/build123d/topology.py @@ -6786,9 +6786,13 @@ def trim(self, start: float, end: float) -> Wire: trim_start_point = self.position_at(start) trim_end_point = self.position_at(end) + # If this is really just an edge, skip the complexity of a Wire + if len(self.edges()) == 1: + return Wire.make_wire([self.edge().trim(start, end)]) + # Get all the edges modified_edges: list[Edge] = [] - original_edges: list[Edge] = [] + unmodified_edges: list[Edge] = [] for edge in self.edges(): # Is edge flipped flipped = self.param_at_point(edge.position_at(0)) > self.param_at_point( @@ -6800,7 +6804,11 @@ def trim(self, start: float, end: float) -> Wire: # Trim edges containing start or end points degenerate = False - if contains_start: + if contains_start and contains_end: + u_start = edge.param_at_point(trim_start_point) + u_end = edge.param_at_point(trim_end_point) + edge = edge.trim(u_start, u_end) + elif contains_start: u_value = edge.param_at_point(trim_start_point) if not flipped: degenerate = u_value == 1.0 @@ -6810,7 +6818,7 @@ def trim(self, start: float, end: float) -> Wire: degenerate = u_value == 0.0 if not degenerate: edge = edge.trim(0.0, u_value) - if contains_end: + elif contains_end: u_value = edge.param_at_point(trim_end_point) if not flipped: degenerate = u_value == 0.0 @@ -6824,10 +6832,10 @@ def trim(self, start: float, end: float) -> Wire: if contains_start or contains_end: modified_edges.append(edge) else: - original_edges.append(edge) + unmodified_edges.append(edge) # Select the wire containing the start and end points - wire_segments = edges_to_wires(modified_edges + original_edges) + wire_segments = edges_to_wires(modified_edges + unmodified_edges) trimmed_wire = filter( lambda w: all( [ @@ -6837,9 +6845,10 @@ def trim(self, start: float, end: float) -> Wire: ), wire_segments, ) - if not trimmed_wire: - raise RuntimeError("Invalid trim result") - return next(trimmed_wire) + try: + return next(trimmed_wire) + except StopIteration as exc: + raise RuntimeError("Invalid trim result") from exc def order_edges(self) -> ShapeList[Edge]: """Return the edges in self ordered by wire direction and orientation""" diff --git a/tests/test_direct_api.py b/tests/test_direct_api.py index abaffea8..2f3e9b39 100644 --- a/tests/test_direct_api.py +++ b/tests/test_direct_api.py @@ -48,6 +48,7 @@ from build123d.objects_curve import Polyline from build123d.build_sketch import BuildSketch from build123d.build_line import BuildLine +from build123d.objects_curve import Spline from build123d.objects_sketch import Circle, Rectangle, RegularPolygon from build123d.geometry import ( Axis, @@ -3513,6 +3514,15 @@ def test_trim(self): with self.assertRaises(ValueError): o.trim(0.75, 0.25) + spline = Spline( + (0, 0, 0), + (0, 10, 0), + tangents=((0, 0, 1), (0, 0, -1)), + tangent_scalars=(2, 2), + ) + half = spline.trim(0.5, 1) + self.assertVectorAlmostEquals(spline @ 0.5, half @ 0, 4) + self.assertVectorAlmostEquals(spline @ 1, half @ 1, 4) def test_param_at_point(self): e = Edge.make_three_point_arc((0, -20), (5, 0), (0, 20))