def from_spline( cls, spline: BSpline, start_width: float, end_width: float, segments: int, ) -> "CurvedTrace": """ Create curved trace from a B-spline. Args: spline: :class:`~ezdxf.math.BSpline` object start_width: start width end_width: end width segments: count of segments for approximation """ curve_trace = cls() count = segments + 1 t = linspace(0, spline.max_t, count) for ((point, derivative), width) in zip(spline.derivatives(t, n=1), linspace(start_width, end_width, count)): normal = Vec2(derivative).orthogonal(True) curve_trace._append(Vec2(point), normal, width) return curve_trace
def from_arc(cls, arc: ConstructionArc, start_width: float, end_width: float, segments: int = 64) -> 'CurvedTrace': """ Create curved trace from an arc. Args: arc: :class:`~ezdxf.math.ConstructionArc` object start_width: start width end_width: end width segments: count of segments for full circle (360 degree) approximation, partial arcs have proportional less segments, but at least 3 Raises: ValueError: if arc.radius <= 0 """ if arc.radius <= 0: raise ValueError(f'Invalid radius: {arc.radius}.') curve_trace = cls() count = max(math.ceil(arc.angle_span / 360.0 * segments), 3) + 1 center = Vec2(arc.center) for point, width in zip(arc.vertices(arc.angles(count)), linspace(start_width, end_width, count)): curve_trace._append(point, point - center, width) return curve_trace
def draw_elliptic_arc_entity_3d(self, entity: DXFGraphic) -> None: dxf, dxftype = entity.dxf, entity.dxftype() properties = self._resolve_properties(entity) if dxftype in {'CIRCLE', 'ARC'}: center = dxf.center # ocs transformation in .from_arc() radius = dxf.radius if dxftype == 'CIRCLE': start_angle = 0 end_angle = 360 else: start_angle = dxf.start_angle end_angle = dxf.end_angle e = ConstructionEllipse.from_arc(center, radius, dxf.extrusion, start_angle, end_angle) elif dxftype == 'ELLIPSE': e = cast(Ellipse, entity).construction_tool() else: raise TypeError(dxftype) # Approximate as 3D polyline segments = int((e.end_param - e.start_param) / math.tau * self.circle_approximation_count) points = list( e.vertices( linspace(e.start_param, e.end_param, max(4, segments + 1)))) self.out.start_path() for a, b in zip(points, points[1:]): self.out.draw_line(a, b, properties) self.out.end_path()
def build(): circle = Circle() vertices = list(circle.vertices(linspace(0, 360, vertex_count, endpoint=False))) m = Matrix44.chain( Matrix44.axis_rotate(axis=Vec3.random(), angle=random.uniform(0, math.tau)), Matrix44.translate(dx=random.uniform(-2, 2), dy=random.uniform(-2, 2), dz=random.uniform(-2, 2)), ) return synced_transformation(circle, vertices, m)
def circle(radius=1, count=16): circle_ = Circle.new(dxfattribs={ 'center': (0, 0, 0), 'radius': radius }, doc=doc) control_vertices = list(circle_.vertices(linspace(0, 360, count))) return circle_, control_vertices
def test_rational_spline_curve_points_by_nurbs_python(): arc = ConstructionArc(end_angle=90) spline = rational_bspline_from_arc(end_angle=arc.end_angle) curve = spline.to_nurbs_python_curve() t = list(linspace(0, 1, 10)) points = list(spline.points(t)) expected = list(curve.evaluate_list(t)) for p, e in zip(points, expected): assert p.isclose(e)
def test_rational_spline_derivatives_by_nurbs_python(): arc = ConstructionArc(end_angle=90) spline = rational_bspline_from_arc(end_angle=arc.end_angle) curve = spline.to_nurbs_python_curve() t = list(linspace(0, 1, 10)) derivatives = list(spline.derivatives(t, n=1)) expected = [curve.derivatives(u, 1) for u in t] for (p, d1), (e, ed1) in zip(derivatives, expected): assert p.isclose(e) assert d1.isclose(ed1)
def divide(self, count: int) -> Iterator[Vec3]: """Returns `count` interpolated vertices along the polyline. Argument `count` has to be greater than 2 and the start- and end vertices are always included. """ if count < 2: raise ValueError(f"invalid count: {count}") vertex_at = self._vertex_at for distance in linspace(0.0, self.length, count): yield vertex_at(distance)
def __init__( self, curve: SupportsPointMethod, *, max_t: float = 1.0, segments: int = 100, ): assert hasattr(curve, "point") assert segments > 0 self._polyline = ConstructionPolyline( curve.point(t) for t in linspace(0.0, max_t, segments + 1)) self._max_t = max_t self._step = max_t / segments
def flattening(self, sagitta: float) -> Iterator[Vec2]: """Approximate the circle by vertices, argument `sagitta` is the max. distance from the center of an arc segment to the center of its chord. Returns a closed polygon where the start vertex is coincident with the end vertex! .. versionadded:: 0.17.1 """ from .arc import arc_segment_count count = arc_segment_count(self.radius, math.tau, sagitta) yield from self.vertices(linspace(0.0, math.tau, count + 1))
def get_params(start: float, end: float, num: int) -> Iterable[float]: """Returns `num` params from start- to end param in counter clockwise order. All params are normalized in the range from [0, 2π). """ if num < 2: raise ValueError("num >= 2") if end <= start: end += math.tau for param in linspace(start, end, num): yield param % math.tau
def angles(self, num: int) -> Iterable[float]: """ Returns `num` angles from start- to end angle in degrees in counter clockwise order. All angles are normalized in the range from [0, 360). """ if num < 2: raise ValueError('num >= 2') start = self.dxf.start_angle % 360 stop = self.dxf.end_angle % 360 if stop <= start: stop += 360 for angle in linspace(start, stop, num=num, endpoint=True): yield angle % 360
def flattening(self, sagitta: float) -> Iterable[Vec3]: """Approximate the circle by vertices in WCS, argument `sagitta` is the max. distance from the center of an arc segment to the center of its chord. Returns a closed polygon: start vertex == end vertex! Yields always :class:`~ezdxf.math.Vec3` objects. .. versionadded:: 0.15 """ radius = abs(self.dxf.radius) if radius > 0.0: count = arc_segment_count(radius, math.tau, sagitta) yield from self.vertices(linspace(0.0, 360.0, count + 1))
def test_random_ellipse_transformations(sx, sy, sz, start, end): vertex_count = 8 for angle in linspace(0, math.tau, 19): for dx, dy, dz in product([2, 0, -2], repeat=3): axis = Vec3.random() # TODO: fixed rotation axis config = f"CONFIG sx={sx}, sy={sy}, sz={sz}; " \ f"start={start:.4f}, end={end:.4f}; angle={angle};" \ f"dx={dx}, dy={dy}, dz={dz}; axis={str(axis)}" ellipse0, vertices0 = build(angle, dx, dy, dz, axis, start, end, vertex_count) assert check(ellipse0, vertices0, vertex_count) is True, config ellipse1, vertices1 = synced_scaling(ellipse0, vertices0, sx, sy, sz) assert check(ellipse1, vertices1, vertex_count) is True, config
def profile_bspline_point_new(count, spline): for _ in range(count): for t in linspace(0, 1.0, 100): spline.point(t)
def profile_vertex_calculation(count, spline, num): for _ in range(count): for t in linspace(0.0, spline.max_t, num): spline.point(t)
def test_params(): count = 9 e = ConstructionEllipse(start_param=math.pi / 2, end_param=-math.pi / 2) params = list(e.params(count)) expected = list(linspace(math.pi / 2, math.pi / 2.0 * 3.0, count)) assert params == expected
def profile_bspline_derivatives_new(count, spline): for _ in range(count): list(spline.derivatives(t=linspace(0, 1.0, 100)))
def sine_wave(count: int, scale: float = 1.0) -> Iterable[Vec3]: for t in linspace(0, math.tau, count): yield Vec3(t * scale, math.sin(t) * scale)
def t_vector(): return list(linspace(0, max(KNOTS), 20))
def sine_wave(count: int, scale: float = 1.0): for t in linspace(0, math.tau, count): yield Vector(t * scale, math.sin(t) * scale)
def bspline_points_rational(cls, count): for curve in splines: weights = [1.0] * curve.count spline = cls(curve, weights) for u in linspace(0, spline.basis.max_t, count): spline.point(u)
def bspline_points(cls, count): for curve in splines: spline = cls(curve) for u in linspace(0, spline.basis.max_t, count): spline.point(u)
def bspline_multi_points(cls, count): for curve in splines: spline = cls(curve) list(spline.points(linspace(0, spline.basis.max_t, count)))
def bspline_multi_derivative(cls, count): for curve in splines: spline = cls(curve) list(spline.derivatives(linspace(0, spline.basis.max_t, count), 1))
def bspline_derivative(cls, count): for curve in splines: spline = cls(curve) for u in linspace(0, spline.basis.max_t, count): spline.derivative(u, 1)