def approximate(self, segments: int = 40, ucs: 'UCS' = None) -> List['Vertex']: """ Approximate the B-spline by a polyline with `segments` line segments. If `ucs` is not ``None``, ucs defines an :class:`~ezdxf.math.UCS`, to transformed the curve into :ref:`OCS`. The control points are placed xy-plane of the UCS, don't use z-axis coordinates, if so make sure all control points are in a plane parallel to the OCS base plane (UCS xy-plane), else the result is unpredictable and depends on the CAD application used to open the DXF file - it may crash. Args: segments: count of line segments for approximation, vertex count is `segments` + 1 ucs: :class:`~ezdxf.math.UCS` definition, control points in ucs coordinates Returns: list of vertices in :class:`~ezdxf.math.OCS` as :class:`~ezdxf.math.Vec3` objects """ if self.closed: spline = closed_uniform_bspline(self.control_points, order=self.degree + 1) else: spline = BSpline(self.control_points, order=self.degree + 1) vertices = spline.approximate(segments) if ucs is not None: vertices = (ucs.to_ocs(vertex) for vertex in vertices) return list(vertices)
def test_rbspline(): curve = BSpline(DEFPOINTS, order=3, weights=DEFWEIGHTS) expected = RBSPLINE points = list(curve.approximate(40)) for rpoint, epoint in zip(points, expected): epx, epy, epz = epoint rpx, rpy, rpz = rpoint assert isclose(epx, rpx) assert isclose(epy, rpy) assert isclose(epz, rpz)
def render_open_bspline( self, layout: "BaseLayout", degree: int = 3, dxfattribs: dict = None ) -> None: """Render an open uniform B-spline as 3D :class:`~ezdxf.entities.Polyline`. Definition points are control points. Args: layout: :class:`~ezdxf.layouts.BaseLayout` object degree: degree of B-spline (order = `degree` + 1) dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` """ spline = BSpline(self.points, order=degree + 1) layout.add_polyline3d( list(spline.approximate(self.segments)), dxfattribs=dxfattribs )
def render_open_rbspline(self, layout: 'BaseLayout', weights: Iterable[float], degree: int = 3, dxfattribs: dict = None) -> None: """ Render a rational open uniform BSpline as 3D :class:`~ezdxf.entities.Polyline`. Definition points are control points. Args: layout: :class:`~ezdxf.layouts.BaseLayout` object weights: list of weights, requires a weight value (float) for each definition point. degree: degree of B-spline (order = `degree` + 1) dxfattribs: DXF attributes for :class:`~ezdxf.entities.Polyline` """ spline = BSpline(self.points, order=degree + 1, weights=weights) layout.add_polyline3d(list(spline.approximate(self.segments)), dxfattribs=dxfattribs)
def to_line_edges(spline_edge: SplineEdge): weights = spline_edge.weights if len(spline_edge.control_points): bspline = BSpline( control_points=spline_edge.control_points, order=spline_edge.degree + 1, knots=spline_edge.knot_values, weights=weights if len(weights) else None, ) elif len(spline_edge.fit_points): bspline = BSpline.from_fit_points( spline_edge.fit_points, spline_edge.degree ) else: raise const.DXFStructureError( "SplineEdge() without control points or fit points." ) segment_count = (max(len(bspline.control_points), 3) - 1) * factor vertices = list(bspline.approximate(segment_count)) for v1, v2 in zip(vertices[:-1], vertices[1:]): edge = LineEdge() edge.start = v1.vec2 edge.end = v2.vec2 yield edge
from typing import cast from pathlib import Path import ezdxf from ezdxf.math import Vector, BSpline DIR = Path('~/Desktop/Outbox').expanduser() doc = ezdxf.readfile('../../examples/addons/drawing/test_files/hatches_2.dxf') msp = doc.modelspace() hatch = cast('Hatch', msp.query('HATCH').first) if hatch: for edge in hatch.paths[0].edges: if edge.EDGE_TYPE == 'SplineEdge': s = BSpline(control_points=edge.control_points, knots=edge.knot_values, order=edge.degree + 1) print(s.knots()) c = s.to_nurbs_python_curve() print(c.knotvector) print(s) print(list(s.approximate(10)))