Esempio n. 1
0
    def draw_elliptic_arc_entity(self, entity: DXFGraphic,
                                 properties: Properties) -> None:
        dxftype = entity.dxftype()
        if NULLVEC.isclose(entity.dxf.extrusion):
            self.skip_entity(
                f'Invalid extrusion (0, 0, 0) in entity: {str(entity)}')
            return

        if dxftype == 'CIRCLE':
            if entity.dxf.radius <= 0:
                self.skip_entity(f'Invalid radius in entity: {str(entity)}')
                return
            path = Path.from_circle(cast('Circle', entity))
        elif dxftype == 'ARC':
            if entity.dxf.radius <= 0:
                self.skip_entity(f'Invalid radius in entity: {str(entity)}')
                return
            path = Path.from_arc(cast('Arc', entity))
        elif dxftype == 'ELLIPSE':
            if NULLVEC.isclose(entity.dxf.major_axis):
                self.skip_entity(
                    f'Invalid major axis (0, 0, 0) in entity: {str(entity)}')
                return

            path = Path.from_ellipse(cast('Ellipse', entity))
        else:  # API usage error
            raise TypeError(dxftype)
        self.out.draw_path(path, properties)
Esempio n. 2
0
    def audit(self, auditor: 'Auditor') -> None:
        """ Validity check. """
        def reset_mline_style(name='Standard'):
            auditor.fixed_error(
                code=AuditError.RESET_MLINE_STYLE,
                message=f'Reset MLINESTYLE to "{name}" in {str(self)}.',
                dxf_entity=self,
            )
            self.dxf.style_name = name
            style = doc.mline_styles.get(name)
            self.dxf.style_handle = style.dxf.handle

        super().audit(auditor)
        doc = auditor.doc
        if doc is None:
            return

        # Audit associated MLINESTYLE name and handle:
        style = doc.entitydb.get(self.dxf.style_handle)
        if style is None:  # handle is invalid, get style by name
            style = doc.mline_styles.get(self.dxf.style_name, None)
            if style is None:
                reset_mline_style()
            else:  # fix MLINESTYLE handle:
                auditor.fixed_error(
                    code=AuditError.INVALID_MLINESTYLE_HANDLE,
                    message=f'Fixed invalid style handle in {str(self)}.',
                    dxf_entity=self,
                )
                self.dxf.style_handle = style.dxf.handle
        else:  # update MLINESTYLE name silently
            self.dxf.style_name = style.dxf.name

        # Get current (maybe fixed) MLINESTYLE:
        style = self.style

        # Update style element count silently:
        element_count = len(style.elements)
        self.dxf.style_element_count = element_count

        # Audit vertices:
        for vertex in self.vertices:
            if NULLVEC.isclose(vertex.line_direction):
                break
            if NULLVEC.isclose(vertex.miter_direction):
                break
            if len(vertex.line_params) != element_count:
                break
            # Ignore fill parameters.
        else:  # no break
            return

        # Invalid vertices found:
        auditor.fixed_error(
            code=AuditError.INVALID_MLINE_VERTEX,
            message=f'Execute geometry update for {str(self)}.',
            dxf_entity=self,
        )
        self.update_geometry()
Esempio n. 3
0
 def load_spline_data(self, tags) -> Iterable:
     """Load and set spline data (fit points, control points, weights,
     knots) and remove invalid start- and end tangents.
     Yields the remaining unprocessed tags.
     """
     control_points = []
     fit_points = []
     knots = []
     weights = []
     for tag in tags:
         code, value = tag
         if code == 10:
             control_points.append(value)
         elif code == 11:
             fit_points.append(value)
         elif code == 40:
             knots.append(value)
         elif code == 41:
             weights.append(value)
         elif code in (12, 13) and NULLVEC.isclose(value):
             # Tangent values equal to (0, 0, 0) are invalid and ignored at
             # the loading stage!
             pass
         else:
             yield tag
     self.control_points = control_points
     self.fit_points = fit_points
     self.knots = knots
     self.weights = weights
Esempio n. 4
0
    def from_arc(cls,
                 center: 'Vertex' = NULLVEC,
                 radius: float = 1,
                 extrusion: 'Vertex' = Z_AXIS,
                 start_angle: float = 0,
                 end_angle: float = 360,
                 ccw: bool = True) -> 'ConstructionEllipse':
        """ Returns :class:`ConstructionEllipse` from arc or circle.

        Arc and Circle parameters defined in OCS.

        Args:
             center: center in OCS
             radius: arc or circle radius
             extrusion: OCS extrusion vector
             start_angle: start angle in degrees
             end_angle: end angle in degrees
             ccw: arc curve goes counter clockwise from start to end if ``True``
        """
        radius = abs(radius)
        if NULLVEC.isclose(extrusion):
            raise ValueError(f'Invalid extrusion: {str(extrusion)}')
        ratio = 1.0
        ocs = OCS(extrusion)
        center = ocs.to_wcs(center)
        # Major axis along the OCS x-axis.
        major_axis = ocs.to_wcs(Vec3(radius, 0, 0))
        # No further adjustment of start- and end angle required.
        start_param = math.radians(start_angle)
        end_param = math.radians(end_angle)
        return cls(center, major_axis, extrusion, ratio, start_param,
                   end_param, bool(ccw))
Esempio n. 5
0
 def check_extrusion_vector(self, entity: 'DXFEntity') -> None:
     if NULLVEC.isclose(entity.dxf.extrusion):
         entity.dxf.discard('extrusion')
         self.fixed_error(
             code=AuditError.INVALID_EXTRUSION_VECTOR,
             message=f'Fixed extrusion vector for entity: {str(self)}.',
             dxf_entity=entity,
         )
Esempio n. 6
0
 def remove_invalid_data(spline_tags: 'Tags') -> None:
     # The loading function use the regular validator/fixer
     # infrastructure and I don't want to ignore (0, 0, 0) as tangent values
     # silently, so I remove invalid start- and end tangent values at the
     # DXF loadings stage:
     codes = [
         code for code, value in spline_tags
         if code in (12, 13) and NULLVEC.isclose(value)
     ]
     if codes:
         spline_tags.remove_tags(codes=codes)
Esempio n. 7
0
 def audit(self, auditor: 'Auditor') -> None:
     """ Validity check. """
     super().audit(auditor)
     if self.dxf.hasattr('major_axis') and NULLVEC.isclose(
             self.dxf.major_axis):
         auditor.fixed_error(
             code=AuditError.INVALID_MAJOR_AXIS,
             message=f'Deleted entity {str(self)} with invalid major axis.',
             dxf_entity=self,
         )
         if self.doc and self.doc.entitydb:
             self.entitydb.trash(self.dxf.handle)
         else:
             self.destroy()
Esempio n. 8
0
def is_not_null_vector(v) -> bool:
    return not NULLVEC.isclose(v)
Esempio n. 9
0
def from_hatch_edge_path(edges: 'EdgePath',
                         ocs: OCS = None,
                         elevation: float = 0) -> 'Path':
    """ Returns a :class:`Path` object from a :class:`~ezdxf.entities.Hatch`
    edge path.
    """
    def add_line_edge(edge):
        start = wcs(edge.start)
        end = wcs(edge.end)
        if len(path):
            if path.end.isclose(start):
                # path-end -> line-end
                path.line_to(end)
            elif path.end.isclose(end):
                # path-end (==line-end) -> line-start
                path.line_to(start)
            else:
                # path-end -> edge-start -> edge-end
                path.line_to(start)
                path.line_to(end)
        else:  # start path
            path.start = start
            path.line_to(end)

    def add_arc_edge(edge):
        x, y, *_ = edge.center
        # from_arc() requires OCS data:
        ellipse = ConstructionEllipse.from_arc(
            center=(x, y, elevation),
            radius=edge.radius,
            extrusion=extrusion,
            start_angle=edge.start_angle,
            end_angle=edge.end_angle,
        )
        tools.add_ellipse(path, ellipse, reset=not bool(path))

    def add_ellipse_edge(edge):
        ocs_ellipse = edge.construction_tool()
        # ConstructionEllipse has WCS representation:
        ellipse = ConstructionEllipse(
            center=wcs(ocs_ellipse.center.replace(z=elevation)),
            major_axis=wcs(ocs_ellipse.major_axis),
            ratio=ocs_ellipse.ratio,
            extrusion=extrusion,
            start_param=ocs_ellipse.start_param,
            end_param=ocs_ellipse.end_param,
        )
        tools.add_ellipse(path, ellipse, reset=not bool(path))

    def add_spline_edge(edge):
        control_points = [wcs(p) for p in edge.control_points]
        if len(control_points) == 0:
            fit_points = [wcs(p) for p in edge.fit_points]
            if len(fit_points):
                bspline = from_fit_points(edge, fit_points)
            else:
                # No control points and no fit points:
                # DXF structure error
                return
        else:
            bspline = from_control_points(edge, control_points)
        tools.add_spline(path, bspline, reset=not bool(path))

    def from_fit_points(edge, fit_points):
        tangents = None
        if edge.start_tangent and edge.end_tangent:
            tangents = (wcs(edge.start_tangent), wcs(edge.end_tangent))
        return global_bspline_interpolation(
            fit_points,
            degree=edge.degree,
            tangents=tangents,
        )

    def from_control_points(edge, control_points):
        return BSpline(control_points=control_points,
                       order=edge.degree + 1,
                       knots=edge.knot_values,
                       weights=edge.weights if edge.weights else None)

    def wcs(vertex):
        if ocs and ocs.transform:
            return ocs.to_wcs((vertex.x, vertex.y, elevation))
        else:
            return Vec3(vertex)

    extrusion = ocs.uz if ocs else Z_AXIS
    path = Path()
    for edge in edges:
        if edge.EDGE_TYPE == "LineEdge":
            add_line_edge(edge)
        elif edge.EDGE_TYPE == "ArcEdge":
            if not math.isclose(edge.radius, 0):
                add_arc_edge(edge)
        elif edge.EDGE_TYPE == "EllipseEdge":
            if not NULLVEC.isclose(edge.major_axis):
                add_ellipse_edge(edge)
        elif edge.EDGE_TYPE == "SplineEdge":
            add_spline_edge(edge)

    return path