def test_angle_span(): assert ConstructionArc(start_angle=30, end_angle=270).angle_span == 240 # crossing 0-degree: assert ConstructionArc(start_angle=30, end_angle=270, is_counter_clockwise=False).angle_span == 120 # crossing 0-degree: assert ConstructionArc(start_angle=300, end_angle=60).angle_span == 120 assert ConstructionArc(start_angle=300, end_angle=60, is_counter_clockwise=False).angle_span == 240
def test_bounding_box(): bbox = ConstructionArc(center=(0, 0), radius=1, start_angle=0, end_angle=90).bounding_box assert bbox.extmin == (0, 0) assert bbox.extmax == (1, 1) bbox = ConstructionArc(center=(0, 0), radius=1, start_angle=0, end_angle=180).bounding_box assert bbox.extmin == (-1, 0) assert bbox.extmax == (1, 1) bbox = ConstructionArc(center=(0, 0), radius=1, start_angle=270, end_angle=90).bounding_box assert bbox.extmin == (0, -1) assert bbox.extmax == (1, 1)
def test_rational_spline_from_circular_arc_has_same_end_points(): arc = ConstructionArc( start_angle=30, end_angle=330) spline = rational_bspline_from_arc( start_angle=arc.start_angle, end_angle=arc.end_angle) assert arc.start_point.isclose(spline.control_points[0]) assert arc.end_point.isclose(spline.control_points[-1])
def test_vertices(): angles = [0, 45, 90, 135, -45, -90, -135, 180] arc = ConstructionArc(center=(1, 1)) vertices = list(arc.vertices(angles)) for v, a in zip(vertices, angles): a = math.radians(a) assert v.isclose(Vec2((1 + math.cos(a), 1 + math.sin(a))))
def test_point_is_not_in_arc_range(p): """ Test if the angle defined by arc.center and point "p" is NOT in the range arc.start_angle to arc.end_angle: """ arc = ConstructionArc((0, 0), 1, -90, 90) assert arc._is_point_in_arc_range(Vec2(p)) is False
def construction_tool(self) -> ConstructionArc: """Returns ConstructionArc() for the OCS representation.""" return ConstructionArc( center=self.center, radius=self.radius, start_angle=self.start_angle, end_angle=self.end_angle, )
def test_tangents(): angles = [0, 45, 90, 135, -45, -90, -135, 180] sin45 = math.sin(math.pi / 4) result = [(0, 1), (-sin45, sin45), (-1, 0), (-sin45, -sin45), (sin45, sin45), (1, 0), (sin45, -sin45), (0, -1)] arc = ConstructionArc(center=(1, 1)) vertices = list(arc.tangents(angles)) for v, r in zip(vertices, result): assert v.isclose(Vec2(r))
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 construction_tool(self) -> ConstructionArc: """ Returns 2D construction tool :class:`ezdxf.math.ConstructionArc`, ignoring the extrusion vector. """ dxf = self.dxf return ConstructionArc( dxf.center, dxf.radius, dxf.start_angle, dxf.end_angle, )
def test_angles(): arc = ConstructionArc(radius=1, start_angle=30, end_angle=60) assert tuple(arc.angles(2)) == (30, 60) assert tuple(arc.angles(3)) == (30, 45, 60) arc.start_angle = 180 arc.end_angle = 0 assert tuple(arc.angles(2)) == (180, 0) assert tuple(arc.angles(3)) == (180, 270, 0) arc.start_angle = -90 arc.end_angle = -180 assert tuple(arc.angles(2)) == (270, 180) assert tuple(arc.angles(4)) == (270, 0, 90, 180)
def dim_arc_3d(): doc = ezdxf.new(DXFVERSION, setup=True) msp = doc.modelspace() for center, radius, sa, ea, distance in [[Vec3(0, 0), 5, 60, 90, 2]]: arc = ConstructionArc(center, radius, sa, ea) ucs = UCS(origin=center + (5, 5)).rotate_local_x(math.radians(45)) msp.add_line(arc.center, arc.start_point).transform(ucs.matrix) msp.add_line(arc.center, arc.end_point).transform(ucs.matrix) dim = msp.add_arc_dim_arc(arc=arc, distance=distance, dimstyle="EZ_CURVED") dim.render(discard=BRICSCAD, ucs=ucs) doc.set_modelspace_vport(height=30) doc.saveas(OUTDIR / f"dim_arc_3d_{DXFVERSION}.dxf")
def test_arc_from_3p(): p1 = (-15.73335, 10.98719) p2 = (-12.67722, 8.76554) p3 = (-8.00817, 12.79635) arc = ConstructionArc.from_3p(start_point=p1, end_point=p2, def_point=p3) arc_result = ConstructionArc( center=(-12.08260, 12.79635), radius=4.07443, start_angle=-153.638906, end_angle=-98.391676, ) assert arc.center.isclose(arc_result.center, abs_tol=1e-5) assert isclose(arc.radius, arc_result.radius, abs_tol=1e-5) assert isclose(arc.start_angle, arc_result.start_angle, abs_tol=1e-4) assert isclose(arc.end_angle, arc_result.end_angle, abs_tol=1e-4)
def test_arc_from_2p_angle_complex(): p1 = (-15.73335, 10.98719) p2 = (-12.67722, 8.76554) angle = 55.247230 arc = ConstructionArc.from_2p_angle(start_point=p1, end_point=p2, angle=angle) arc_result = ConstructionArc( center=(-12.08260, 12.79635), radius=4.07443, start_angle=-153.638906, end_angle=-98.391676, ) assert arc.center.isclose(arc_result.center, abs_tol=1e-5) assert isclose(arc.radius, arc_result.radius, abs_tol=1e-5) assert isclose(arc.start_angle, arc_result.start_angle, abs_tol=1e-4) assert isclose(arc.end_angle, arc_result.end_angle, abs_tol=1e-4)
def test_rational_spline_from_circular_arc_has_expected_parameters(): arc = ConstructionArc(end_angle=90) spline = rational_bspline_from_arc(end_angle=arc.end_angle) assert spline.degree == 2 cpoints = spline.control_points assert len(cpoints) == 3 assert cpoints[0].isclose((1, 0, 0)) assert cpoints[1].isclose((1, 1, 0)) assert cpoints[2].isclose((0, 1, 0)) weights = spline.weights() assert len(weights) == 3 assert weights[0] == 1.0 assert weights[1] == math.cos(math.pi / 4) assert weights[2] == 1.0 # as BSpline constructor() s2 = BSpline.from_arc(arc) assert spline.control_points == s2.control_points
def cut_dxf(dxf_file: Drawing, center: Vector, side: Vector): """ 切割dxf文件. Args: dxf_file: dxf文件路径, R12格式推荐. center: 切割线起点 side: 切割线终点 Returns: (float, Vector) : 交点至起点距离, 交点坐标. 如无交点则返回 None,None. """ cutLine = ConstructionLine(center, side) pts = [] # doc = ezdxf.readfile(dxf_file) doc = dxf_file msp = doc.modelspace() for e in msp: if e.dxftype() == 'LINE': # byLine = ConstructionLine(e.dxf.start, e.dxf.end) coord = intersection_seg_seg(list(e.dxf.start), list(e.dxf.end), list(cutLine.start), list(cutLine.end)) # pt = cutLine.intersect(byLine) if coord != None and len(coord) != 0: pt = Vec2(*coord) pts.append(pt) elif e.dxftype() == 'ARC': byArc = ConstructionArc(e.dxf.center, e.dxf.radius, e.dxf.start_angle, e.dxf.end_angle) coord = intersection(cutLine, byArc) if coord != None and len(coord) != 0: pt = Vec2(*coord) pts.append(pt) if len(pts) != 0: pts.sort(key=lambda x: x.distance(center)) return pts[0].distance(center), pts[0] else: return None, None
def test_flattening(r, s, e, sagitta, count): arc = ConstructionArc((0, 0), r, s, e) assert len(list(arc.flattening(sagitta))) == count
def from_polyline(cls, polyline: 'DXFGraphic', segments: int = 64) -> 'TraceBuilder': """ Create a complete trace from a LWPOLYLINE or a 2D POLYLINE entity, the trace consist of multiple sub-traces if :term:`bulge` values are present. Args: polyline: :class:`~ezdxf.entities.LWPolyline` or 2D :class:`~ezdxf.entities.Polyline` segments: count of segments for bulge approximation, given count is for a full circle, partial arcs have proportional less segments, but at least 3 """ dxftype = polyline.dxftype() if dxftype == 'LWPOLYLINE': polyline = cast('LWPOLYLINE', polyline) const_width = polyline.dxf.const_width points = [] for x, y, start_width, end_width, bulge in polyline.lwpoints: location = Vec2(x, y) if const_width: # This is AutoCAD behavior, BricsCAD uses const width # only for missing width values. start_width = const_width end_width = const_width points.append((location, start_width, end_width, bulge)) closed = polyline.closed elif dxftype == 'POLYLINE': polyline = cast('POLYLINE', polyline) if not polyline.is_2d_polyline: raise TypeError('2D POLYLINE required') closed = polyline.is_closed default_start_width = polyline.dxf.default_start_width default_end_width = polyline.dxf.default_end_width points = [] for vertex in polyline.vertices: location = Vec2(vertex.dxf.location) if vertex.dxf.hasattr('start_width'): start_width = vertex.dxf.start_width else: start_width = default_start_width if vertex.dxf.hasattr('end_width'): end_width = vertex.dxf.end_width else: end_width = default_end_width bulge = vertex.dxf.bulge points.append((location, start_width, end_width, bulge)) else: raise TypeError(f'Invalid DXF type {dxftype}') if closed and not points[0][0].isclose(points[-1][0]): # close polyline explicit points.append(points[0]) trace = cls() store_bulge = None store_start_width = None store_end_width = None store_point = None linear_trace = LinearTrace() for point, start_width, end_width, bulge in points: if store_bulge: center, start_angle, end_angle, radius = bulge_to_arc( store_point, point, store_bulge) if radius > 0: arc = ConstructionArc( center, radius, math.degrees(start_angle), math.degrees(end_angle), is_counter_clockwise=True, ) if arc.start_point.isclose(point): sw = store_end_width ew = store_start_width else: ew = store_end_width sw = store_start_width trace.append(CurvedTrace.from_arc(arc, sw, ew, segments)) store_bulge = None if bulge != 0: # arc from prev_point to point if linear_trace.is_started: linear_trace.add_station(point, start_width, end_width) trace.append(linear_trace) linear_trace = LinearTrace() store_bulge = bulge store_start_width = start_width store_end_width = end_width store_point = point continue linear_trace.add_station(point, start_width, end_width) if linear_trace.is_started: trace.append(linear_trace) if closed and len(trace) > 1: # This is required for traces with multiple paths to create the correct # miter at the closing point. (only linear to linear trace). trace.close() return trace
def test_arc_intersect_line_in_two_points(s, e): arc = ConstructionArc((0, 0), 2, 0, 180) assert len(arc.intersect_line(ConstructionLine(s, e))) == 2
def test_arc_does_not_intersect_line(s, e): arc = ConstructionArc((0, 0), 1, 0, 90) assert len(arc.intersect_line(ConstructionLine(s, e))) == 0
def test_arc_intersect_circle_in_two_points(c, r): arc = ConstructionArc((0, 0), 1, -90, 90) assert len(arc.intersect_circle(ConstructionCircle(c, r))) == 2
def test_arc_does_not_intersect_circle(c, r): arc = ConstructionArc((0, 0), 1, -90, 90) assert len(arc.intersect_circle(ConstructionCircle(c, r))) == 0
def test_arc_intersect_arc_in_two_points(c, r, s, e): arc = ConstructionArc((0, 0), 1, -90, 90) assert len(arc.intersect_arc(ConstructionArc(c, r, s, e))) == 2
def test_arc_does_not_intersect_arc(c, r, s, e): arc = ConstructionArc((0, 0), 1, -90, 90) assert len(arc.intersect_arc(ConstructionArc(c, r, s, e))) == 0
def test_arc_intersect_line_in_one_point(s, e): arc = ConstructionArc((0, 0), 2, -90, 90) assert len(arc.intersect_line(ConstructionLine(s, e))) == 1