def from_fit_points(edge: SplineEdge, fit_points): tangents = None if edge.start_tangent and edge.end_tangent: tangents = ( wcs_tangent(edge.start_tangent), wcs_tangent(edge.end_tangent), ) return fit_points_to_cad_cv( # only a degree of 3 is supported fit_points, tangents=tangents, )
def construction_tool(self) -> BSpline: """Returns the construction tool :class:`ezdxf.math.BSpline`.""" if self.control_point_count(): weights = self.weights if len(self.weights) else None knots = self.knots if len(self.knots) else None return BSpline( control_points=self.control_points, order=self.dxf.degree + 1, knots=knots, weights=weights, ) elif self.fit_point_count(): tangents = None if self.dxf.hasattr("start_tangent") and self.dxf.hasattr( "end_tangent"): tangents = [self.dxf.start_tangent, self.dxf.end_tangent] # SPLINE from fit points has always a degree of 3! return fit_points_to_cad_cv( self.fit_points, tangents=tangents, ) else: raise ValueError( "Construction tool requires control- or fit points.")
start_tangent = Vec3.from_deg_angle(100) end_tangent = Vec3.from_deg_angle(-100) # Create SPLINE defined by fit points only: spline = msp.add_spline( points, degree=2, # degree is ignored by BricsCAD and AutoCAD, both use degree=3 dxfattribs={ 'layer': 'SPLINE from fit points by CAD applications', 'color': 2 }) spline.dxf.start_tangent = start_tangent spline.dxf.end_tangent = end_tangent # Create SPLINE defined by control vertices from fit points: s = fit_points_to_cad_cv(points, tangents=[start_tangent, end_tangent]) msp.add_spline(dxfattribs={ 'color': 4, 'layer': 'SPLINE from control vertices by ezdxf' }).apply_construction_tool(s) zoom.extents(msp) doc.saveas(DIR / 'fit_points_to_cad_cv_with_tangents.dxf') # ------------------------------------------------------------------------------ # SPLINE from fit points WITHOUT given end tangents. # ------------------------------------------------------------------------------ # Cubic Bézier curve Interpolation: # # This works only for cubic B-splines (the most common used B-spline), and # BricsCAD/AutoCAD allow only a degree of 2 or 3 for SPLINE entities defined
def virtual_leader_entities(leader: 'Leader') -> Iterable['DXFGraphic']: # Source: https://atlight.github.io/formats/dxf-leader.html # GDAL: DXF LEADER implementation: # https://github.com/OSGeo/gdal/blob/master/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_leader.cpp # LEADER DXF Reference: # http://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-396B2369-F89F-47D7-8223-8B7FB794F9F3 from ezdxf.entities import DimStyleOverride assert leader.dxftype() == 'LEADER' vertices = Vector.list(leader.vertices) # WCS if len(vertices) < 2: # This LEADER entities should be removed by the auditor if loaded or # ignored at exporting, if created by an ezdxf-user (log). raise ValueError('More than 1 vertex required.') dxf = leader.dxf doc = leader.doc # Some default values depend on the measurement system # 0/1 = imperial/metric if doc: measurement = doc.header.get('$MEASUREMENT', 0) else: measurement = 0 # Set default styling attributes values: dimtad = 1 dimgap = 0.625 if measurement else 0.0625 dimscale = 1.0 dimclrd = dxf.color dimltype = dxf.linetype dimlwd = dxf.lineweight override = None if doc: # get styling attributes from associated DIMSTYLE and/or XDATA override override = DimStyleOverride(cast('Dimension', leader)) dimtad = override.get('dimtad', dimtad) dimgap = override.get('dimgap', dimgap) dimscale = override.get('dimscale', dimscale) if dimscale == 0.0: # special but unknown meaning dimscale = 1.0 dimclrd = override.get('dimclrd', dimclrd) dimltype = override.get('dimltype', dimltype) dimlwd = override.get('dimlwd', dimlwd) text_width = dxf.text_width hook_line_vector = Vector(dxf.horizontal_direction) has_text_annotation = dxf.annotation_type == 0 if has_text_annotation and dxf.has_hookline: if dxf.hookline_direction == 1: hook_line_vector = -hook_line_vector if dimtad != 0 and text_width > 0: vertices.append(vertices[-1] + hook_line_vector * (dimgap * dimscale + text_width)) dxfattribs = leader.graphic_properties() dxfattribs['color'] = dimclrd dxfattribs['linetype'] = dimltype dxfattribs['lineweight'] = dimlwd if dxfattribs.get('color') == BYBLOCK: dxfattribs['color'] = dxf.block_color if dxf.path_type == 1: # Spline start_tangent = (vertices[1] - vertices[0]) end_tangent = (vertices[-1] - vertices[-2]) bspline = fit_points_to_cad_cv(vertices, degree=3, tangents=[start_tangent, end_tangent]) # noinspection PyUnresolvedReferences spline = factory.new('SPLINE', doc=doc).apply_construction_tool(bspline) yield spline else: attribs = dict(dxfattribs) prev = vertices[0] for vertex in vertices[1:]: attribs['start'] = prev attribs['end'] = vertex yield factory.new(dxftype='LINE', dxfattribs=attribs, doc=doc) prev = vertex if dxf.has_arrowhead and override: arrow_name = override.get('dimldrblk', '') if arrow_name is None: return size = override.get('dimasz', 2.5 if measurement else 0.1875) * dimscale rotation = (vertices[0] - vertices[1]).angle_deg if doc and arrow_name in doc.blocks: dxfattribs.update({ 'name': arrow_name, 'insert': vertices[0], 'rotation': rotation, 'xscale': size, 'yscale': size, 'zscale': size, }) # create a virtual block reference insert = factory.new('INSERT', dxfattribs=dxfattribs, doc=doc) yield from insert.virtual_entities() else: # render standard arrows yield from ARROWS.virtual_entities( name=arrow_name, insert=vertices[0], size=size, rotation=rotation, dxfattribs=dxfattribs, )
if USE_C_EXT is False: print('C-extension disabled or not available. (pypy3?)') print('Cython implementation == Python implementation.') CBasis = Basis CEvaluator = Evaluator else: # Cython implementations: from ezdxf.acc.bspline import Basis as CBasis, Evaluator as CEvaluator from ezdxf.render import random_3d_path from ezdxf.math import fit_points_to_cad_cv, linspace SPLINE_COUNT = 20 POINT_COUNT = 20 splines = [ fit_points_to_cad_cv(random_3d_path(POINT_COUNT)) for _ in range(SPLINE_COUNT) ] class PySpline: def __init__(self, bspline, weights=None): self.basis = Basis(bspline.knots(), bspline.order, bspline.count, weights) self.evaluator = Evaluator(self.basis, bspline.control_points) def point(self, u): return self.evaluator.point(u) def points(self, t): return self.evaluator.points(t) def derivative(self, u, n):
if USE_C_EXT is False: print("C-extension disabled or not available. (pypy3?)") print("Cython implementation == Python implementation.") CBasis = Basis CEvaluator = Evaluator else: # Cython implementations: from ezdxf.acc.bspline import Basis as CBasis, Evaluator as CEvaluator from ezdxf.render import random_3d_path from ezdxf.math import fit_points_to_cad_cv, linspace SPLINE_COUNT = 20 POINT_COUNT = 20 splines = [ fit_points_to_cad_cv(random_3d_path(POINT_COUNT)) for _ in range(SPLINE_COUNT) ] class PySpline: def __init__(self, bspline, weights=None): self.basis = Basis(bspline.knots(), bspline.order, bspline.count, weights) self.evaluator = Evaluator(self.basis, bspline.control_points) def point(self, u): return self.evaluator.point(u) def points(self, t): return self.evaluator.points(t)