Skip to content

Commit

Permalink
add BSpline.split() method
Browse files Browse the repository at this point in the history
  • Loading branch information
mozman committed Jan 18, 2025
1 parent 5eb847b commit 9c06811
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 4 deletions.
2 changes: 2 additions & 0 deletions docs/source/math/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,8 @@ BSpline

.. automethod:: measure

.. automethod:: split


.. autoclass:: ezdxf.math.bspline.Measurement

Expand Down
1 change: 1 addition & 0 deletions notes/pages/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- NEW: `BSpline.degree_elevation()` method
- NEW: `BSpline.point_inversion()` method
- NEW: `BSpline.measure()` method
- NEW: `BSpline.split()` method
- NEW: `BSpline.insert_knot()` and `BSpline.knot_refinement()` supports rational splines
- BUGFIX: Exported `MESH` entities without vertices or faces create invalid DXF files
- {{issue 1219}}
Expand Down
27 changes: 23 additions & 4 deletions src/ezdxf/math/bspline.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
estimate_end_tangent_magnitude,
distance_point_line_3d,
arc_angle_span_deg,
ABS_TOL,
)
from .bbox import BoundingBox
from ezdxf.math import linalg
Expand Down Expand Up @@ -1396,6 +1395,18 @@ def measure(self, segments: int = 100) -> Measurement:
"""
return Measurement(self, segments)

def split(self, t: float) -> tuple[BSpline, BSpline]:
"""Splits the B-spline at parameter `t` and returns two new B-splines.
Raises:
ValuerError: t out of range 0 < t < max_t
.. versionadded:: 1.4
"""

return split_bspline(self, t)


def subdivide_params(p: list[float]) -> Iterable[float]:
for i in range(len(p) - 1):
Expand Down Expand Up @@ -2025,10 +2036,18 @@ def _measure_spline(self, segments: int) -> None:


def split_bspline(spline: BSpline, t: float) -> tuple[BSpline, BSpline]:
"""Splits a B-spline at a specified parameter value."""
if t < ABS_TOL:
"""Splits a B-spline at a parameter t.
Raises:
ValuerError: t out of range 0 < t < max_t
.. versionadded:: 1.4
"""
tol = 1e-12
if t < tol:
raise ValueError("t must be greater than 0")
if t > spline.max_t - ABS_TOL:
if t > spline.max_t - tol:
raise ValueError("t must be smaller than max_t")
order = spline.order

Expand Down
9 changes: 9 additions & 0 deletions tests/test_06_math/test_628_bspline_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,5 +219,14 @@ def test_extents(self, spline):
assert mtool.extmax.isclose((5, 1.19263675))


def test_split_spline():
spline = BSpline(CONTROL_POINTS)
_, mid_t, _ = spline.measure().divide(2)
sp1, sp2 = spline.split(mid_t)
l1 = sp1.measure().length
l2 = sp2.measure().length
assert abs(l1 - l2) < 0.01


if __name__ == "__main__":
pytest.main([__file__])

0 comments on commit 9c06811

Please sign in to comment.