diff --git a/src/build123d/topology.py b/src/build123d/topology.py index dab92e22..d33ff4a4 100644 --- a/src/build123d/topology.py +++ b/src/build123d/topology.py @@ -161,6 +161,7 @@ Geom_TrimmedCurve, Geom_Line, ) +from OCP.GeomAdaptor import GeomAdaptor_Curve from OCP.Geom2d import Geom2d_Curve, Geom2d_Line, Geom2d_TrimmedCurve from OCP.Geom2dAPI import Geom2dAPI_InterCurveCurve from OCP.GeomAbs import GeomAbs_C0, GeomAbs_Intersection, GeomAbs_JoinType @@ -558,7 +559,8 @@ def common_plane(self, *lines: Union[Edge, Wire]) -> Union[None, Plane]: Union[None, Plane]: Either the common plane or None """ # pylint: disable=too-many-locals - # BRepLib_FindSurface could help here + # Note: BRepLib_FindSurface is not helpful as it requires the + # Edges to form a surface perimeter. points: list[Vector] = [] all_lines: list[Edge, Wire] = [ line for line in [self, *lines] if line is not None @@ -4621,6 +4623,39 @@ def trim(self, start: float, end: float) -> Edge: new_edge = BRepBuilderAPI_MakeEdge(trimmed_curve).Edge() return Edge(new_edge) + def trim_to_length(self, start: float, length: float) -> Edge: + """trim_to_length + + Create a new edge starting at the given normalized parameter of a + given length. + + Args: + start (float): 0.0 <= start < 1.0 + length (float): target length + + Returns: + Edge: trimmed edge + """ + new_curve = BRep_Tool.Curve_s( + copy.deepcopy(self).wrapped, self.param_at(0), self.param_at(1) + ) + + # Create an adaptor for the curve + adaptor_curve = GeomAdaptor_Curve(new_curve) + + # Find the parameter corresponding to the desired length + parm_start = self.param_at(start) + abscissa_point = GCPnts_AbscissaPoint(adaptor_curve, length, parm_start) + + # Get the parameter at the desired length + parm_end = abscissa_point.Parameter() + + # Trim the curve to the desired length + trimmed_curve = Geom_TrimmedCurve(new_curve, parm_start, parm_end) + + new_edge = BRepBuilderAPI_MakeEdge(trimmed_curve).Edge() + return Edge(new_edge) + def param_at_point(self, point: VectorLike) -> float: """Parameter at point of Edge""" diff --git a/tests/test_direct_api.py b/tests/test_direct_api.py index 1f747ff9..85789cf2 100644 --- a/tests/test_direct_api.py +++ b/tests/test_direct_api.py @@ -944,6 +944,29 @@ def test_trim(self): with self.assertRaises(ValueError): line.trim(0.75, 0.25) + def test_trim_to_length(self): + + e1 = Edge.make_line((0, 0), (10, 10)) + e1_trim = e1.trim_to_length(0.0, 10) + self.assertAlmostEqual(e1_trim.length, 10, 5) + + e2 = Edge.make_circle(10, start_angle=0, end_angle=90) + e2_trim = e2.trim_to_length(0.5, 1) + self.assertAlmostEqual(e2_trim.length, 1, 5) + self.assertVectorAlmostEquals( + e2_trim.position_at(0), Vector(10, 0, 0).rotate(Axis.Z, 45), 5 + ) + + e3 = Edge.make_spline( + [(0, 10, 0), (-4, 5, 2), (0, 0, 0)], tangents=[(-1, 0), (1, 0)] + ) + e3_trim = e3.trim_to_length(0, 7) + self.assertAlmostEqual(e3_trim.length, 7, 5) + + a4 = Axis((0, 0, 0), (1, 1, 1)) + e4_trim = a4.as_infinite_edge().trim_to_length(0.5, 2) + self.assertAlmostEqual(e4_trim.length, 2, 5) + def test_bezier(self): with self.assertRaises(ValueError): Edge.make_bezier((1, 1))