def spline_interpolation(vertices: Iterable['Vertex'], degree: int = 3, method: str = 'uniform', power: float = .5, subdivide: int = 4) -> List[Vector]: """ B-spline interpolation, vertices are fit points for the spline definition. Only method 'uniform', yields vertices at fit points. Args: vertices: fit points degree: degree of B-spline method: 'uniform', 'distance' or 'centripetal', calculation method for parameter t power: power for 'centripetal', default is distance ^ .5 subdivide: count of sub vertices + 1, e.g. 4 creates 3 sub-vertices Returns: list of vertices """ vertices = list(vertices) spline = bspline_control_frame(vertices, degree=degree, method=method, power=power) return list(spline.approximate(segments=(len(vertices) - 1) * subdivide))
def render_as_fit_points(self, layout: 'BaseLayout', degree: int = 3, method: str = 'distance', power: float = .5, dxfattribs: dict = None) -> None: """ Render a B-spline as 2D/3D :class:`~ezdxf.entities.Polyline`, where the definition points are fit points. - 2D spline vertices uses: :meth:`~ezdxf.layouts.BaseLayout.add_polyline2d` - 3D spline vertices uses: :meth:`~ezdxf.layouts.BaseLayout.add_polyline3d` Args: layout: :class:`~ezdxf.layouts.BaseLayout` object degree: degree of B-spline (order = `degree` + 1) method: ``'uniform'``, ``'distance'`` or ``'centripetal'``, calculation method for parameter t power: power for ``'centripetal'``, default = ``0.5`` dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` """ spline = bspline_control_frame(self.points, degree=degree, method=method, power=power) vertices = list(spline.approximate(self.segments)) if any(vertex.z != 0. for vertex in vertices): layout.add_polyline3d(vertices, dxfattribs=dxfattribs) else: layout.add_polyline2d(vertices, dxfattribs=dxfattribs)
def render_as_fit_points(self, layout: 'GenericLayoutType', degree: int = 3, method: str = 'distance', power: float = .5, dxfattribs: dict = None) -> None: """ Render a B-spline as 2d/3d polyline, where the definition points are fit points. - 2d points in -> add_polyline2d() - 3d points in -> add_polyline3d() To get vertices at fit points, use method='uniform' and use Spline.subdivide(count), where count is the sub-segment count, count=4, means 4 line segments between two definition points. Args: layout: ezdxf layout degree: degree of B-spline method: 'uniform', 'distance' or 'centripetal', calculation method for parameter t power: power for 'centripetal', default is distance ^ .5 dxfattribs: DXF attributes for POLYLINE """ spline = bspline_control_frame(self.points, degree=degree, method=method, power=power) vertices = list(spline.approximate(self.segments)) if any(vertex.z != 0. for vertex in vertices): layout.add_polyline3d(vertices, dxfattribs=dxfattribs) else: layout.add_polyline2d(vertices, dxfattribs=dxfattribs)
def test_check_values(): test_points = [(0., 0.), (1., 2.), (3., 1.), (5., 3.)] spline = bspline_control_frame(test_points, degree=3, method='distance') result = list(spline.approximate(49)) assert len(result) == 50 for p1, p2 in zip(result, expected): assert isclose(p1[0], p2[0], abs_tol=1e-6) assert isclose(p1[1], p2[1], abs_tol=1e-6)
def test_control_frame(fit_points): spline = bspline_control_frame(fit_points, degree=3) assert len(spline.control_points) == len(fit_points) assert spline.t_array[0] == 0. assert spline.t_array[-1] == 1. assert len(spline.t_array) == len(fit_points) t_points = [spline.point(t) for t in spline.t_array] for p1, p2 in zip(t_points, fit_points): assert p1 == p2
def add_spline_control_frame(self, fit_points: Iterable[Tuple[float, float]], degree: int = 3, method: str = 'distance', power: float = .5) -> 'SplineEdge': bspline = bspline_control_frame(fit_points=fit_points, degree=degree, method=method, power=power) return self.add_spline( fit_points=fit_points, control_points=bspline.control_points, knot_values=bspline.knot_values(), )
def add_spline(degree=2, color=3): spline = bspline_control_frame(fit_points, degree=degree, method='distance') msp.add_polyline2d(spline.control_points, dxfattribs={ 'color': color, 'linetype': 'DASHED' }) msp.add_open_spline(spline.control_points, degree=spline.degree, dxfattribs={'color': color})
def bspline(self, length: float, segments: int = 10, degree: int = 3, method: str = 'uniform') -> BSpline: """ Approximate euler spiral by B-spline. Args: length: length of euler spiral segments: count of fit points for B-spline calculation degree: degree of BSpline method: calculation method for parameter vector t """ fit_points = list(self.approximate(length, segments=segments)) spline = bspline_control_frame(fit_points, degree, method=method) knots = [v * length for v in spline.knot_values()] # scale knot values to length spline.basis.knots = knots return spline