Esempio n. 1
0
    def draw_polyline_entity(self, entity: DXFGraphic,
                             properties: Properties) -> None:
        dxftype = entity.dxftype()
        if dxftype == 'POLYLINE':
            e = cast(Polyface, entity)
            if e.is_polygon_mesh or e.is_poly_face_mesh:
                # draw 3D mesh or poly-face entity
                self.draw_mesh_builder_entity(
                    MeshBuilder.from_polyface(e),
                    properties,
                )
                return

        entity = cast(Union[LWPolyline, Polyline], entity)
        is_lwpolyline = dxftype == 'LWPOLYLINE'

        if entity.has_width:  # draw banded 2D polyline
            elevation = 0.0
            ocs = entity.ocs()
            transform = ocs.transform
            if transform:
                if is_lwpolyline:  # stored as float
                    elevation = entity.dxf.elevation
                else:  # stored as vector (0, 0, elevation)
                    elevation = Vec3(entity.dxf.elevation).z

            trace = TraceBuilder.from_polyline(
                entity, segments=self.circle_approximation_count // 2
            )
            for polygon in trace.polygons():  # polygon is a sequence of Vec2()
                if transform:
                    points = ocs.points_to_wcs(
                        Vec3(v.x, v.y, elevation) for v in polygon
                    )
                else:
                    points = Vec3.generate(polygon)
                # Set default SOLID filling for LWPOLYLINE
                properties.filling = Filling()
                self.out.draw_filled_polygon(points, properties)
            return

        path = make_path(entity)
        self.out.draw_path(path, properties)
Esempio n. 2
0
 def draw_text_entity_2d(self, entity: DXFGraphic,
                         properties: Properties) -> None:
     d, dxftype = entity.dxf, entity.dxftype()
     if dxftype in ('TEXT', 'MTEXT', 'ATTRIB'):
         entity = cast(Union[Text, MText, Attrib], entity)
         for line, transform, cap_height in simplified_text_chunks(
                 entity, self.out, font=properties.font):
             self.out.draw_text(line, transform, properties, cap_height)
     else:
         raise TypeError(dxftype)
Esempio n. 3
0
def test_set_hyperlink():
    entity = DXFGraphic()
    assert entity.has_hyperlink() is False
    entity.set_hyperlink('link')
    assert entity.has_hyperlink() is True
    hyperlink, description, location = entity.get_hyperlink()
    assert hyperlink == 'link'
    assert description == ''
    assert location == ''
Esempio n. 4
0
    def draw_composite_entity(self, entity: DXFGraphic) -> None:
        dxftype = entity.dxftype()
        if dxftype == 'INSERT':
            entity = cast(Insert, entity)
            self.ctx.push_state(self._resolve_properties(entity))
            self.parent_stack.append(entity)
            # visibility check is required:
            self.draw_entities(entity.attribs)
            try:
                children = list(entity.virtual_entities())
            except Exception as e:
                print(
                    f'Exception {type(e)}({e}) failed to get children of insert entity: {e}'
                )
                return
            # visibility check is required:
            self.draw_entities(children)
            self.parent_stack.pop()
            self.ctx.pop_state()

        # DIMENSION, ARC_DIMENSION, LARGE_RADIAL_DIMENSION and ACAD_TABLE
        # All these entities have an associated anonymous geometry block.
        elif hasattr(entity, 'virtual_entities'):
            children = []
            try:
                for child in entity.virtual_entities():
                    child.transparency = 0.0  # todo: defaults to 1.0 (fully transparent)???
                    children.append(child)
            except Exception as e:
                print(
                    f'Exception {type(e)}({e}) failed to get children of entity: {str(entity)}'
                )
                return

            self.parent_stack.append(entity)
            # visibility check is required:
            self.draw_entities(children)
            self.parent_stack.pop()

        else:
            raise TypeError(dxftype)
Esempio n. 5
0
    def override_properties(self, entity: DXFGraphic,
                            properties: Properties) -> None:
        """ The :meth:`override_properties` filter can change the properties of
        an entity independent from the DXF attributes.

        This filter has access to the DXF attributes by the `entity` object,
        the current render context, and the resolved properties by the
        `properties` object. It is recommended to modify only the `properties`
        object in this filter.
        """
        if entity.dxftype() == 'HATCH':
            properties.color = set_color_alpha(properties.color, 200)
Esempio n. 6
0
 def draw_elliptic_arc_entity(self, entity: DXFGraphic,
                              properties: Properties) -> None:
     dxftype = entity.dxftype()
     if dxftype == 'CIRCLE':
         path = Path.from_circle(cast('Circle', entity))
     elif dxftype == 'ARC':
         path = Path.from_arc(cast('Arc', entity))
     elif dxftype == 'ELLIPSE':
         path = Path.from_ellipse(cast('Ellipse', entity))
     else:  # API usage error
         raise TypeError(dxftype)
     self.out.draw_path(path, properties)
Esempio n. 7
0
    def write(self, entity: DXFGraphic):
        """Write a DXF entity from the source DXF file to the export file.

        Don't write entities from different documents than the source DXF file,
        dependencies and resources will not match, maybe it will work once, but
        not in a reliable way for different DXF documents.

        """
        # Not necessary to remove this dependencies by copying
        # them into the same document frame
        # ---------------------------------
        # remove all possible dependencies
        # entity.xdata = None
        # entity.appdata = None
        # entity.extension_dict = None
        # entity.reactors = None
        # reset text stream
        self.text.seek(0)
        self.text.truncate()

        if entity.dxf.handle is None:  # DXF R12 without handles
            self.entity_writer.write_handles = False

        entity.export_dxf(self.entity_writer)
        if entity.dxftype() == "POLYLINE":
            polyline = cast(Polyline, entity)
            for vertex in polyline.vertices:
                vertex.export_dxf(self.entity_writer)
            polyline.seqend.export_dxf(self.entity_writer)  # type: ignore
        elif entity.dxftype() == "INSERT":
            insert = cast(Insert, entity)
            if insert.attribs_follow:
                for attrib in insert.attribs:
                    attrib.export_dxf(self.entity_writer)
                insert.seqend.export_dxf(self.entity_writer)  # type: ignore
        data = self.text.getvalue().encode(self.loader.encoding)
        self.file.write(data)
Esempio n. 8
0
    def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None:
        """Draw a single DXF entity.

        Args:
            entity: DXF entity inherited from DXFGraphic()
            properties: resolved entity properties

        """
        self.out.enter_entity(entity, properties)
        if (entity.proxy_graphic and self.config.proxy_graphic_policy
                == ProxyGraphicPolicy.PREFER):
            self.draw_proxy_graphic(entity.proxy_graphic, entity.doc)
        else:
            draw_method = self._dispatch.get(entity.dxftype(), None)
            if draw_method is not None:
                draw_method(entity, properties)
            # Composite entities (INSERT, DIMENSION, ...) have to implement the
            # __virtual_entities__() protocol.
            # Unsupported DXF types which have proxy graphic, are wrapped into
            # DXFGraphicProxy, which also implements the __virtual_entities__()
            # protocol.
            elif isinstance(entity, SupportsVirtualEntities):
                assert isinstance(entity, DXFGraphic)
                # The __virtual_entities__() protocol does not distinguish
                # content from DXF entities or from proxy graphic.
                # In the long run ACAD_PROXY_ENTITY should be the only
                # supported DXF entity which uses proxy graphic. Unsupported
                # DXF entities (DXFGraphicProxy) do not get to this point if
                # proxy graphic is ignored.
                if (self.config.proxy_graphic_policy !=
                        ProxyGraphicPolicy.IGNORE or entity.dxftype()
                        not in self._proxy_graphic_only_entities):
                    self.draw_composite_entity(entity, properties)
            else:
                self.skip_entity(entity, "unsupported")

        self.out.exit_entity(entity)
Esempio n. 9
0
    def draw_line_entity(self, entity: DXFGraphic) -> None:
        d, dxftype = entity.dxf, entity.dxftype()
        properties = self._resolve_properties(entity)
        if dxftype == 'LINE':
            self.out.draw_line(d.start, d.end, properties)

        elif dxftype in ('XLINE', 'RAY'):
            start = d.start
            delta = Vector(d.unit_vector.x, d.unit_vector.y, 0) * INFINITE_LINE_LENGTH
            if dxftype == 'XLINE':
                self.out.draw_line(start - delta / 2, start + delta / 2, properties)
            elif dxftype == 'RAY':
                self.out.draw_line(start, start + delta, properties)
        else:
            raise TypeError(dxftype)
Esempio n. 10
0
    def draw_line_entity(self, entity: DXFGraphic,
                         properties: Properties) -> None:
        d, dxftype = entity.dxf, entity.dxftype()
        if dxftype == "LINE":
            self.out.draw_line(d.start, d.end, properties)

        elif dxftype in ("XLINE", "RAY"):
            start = d.start
            delta = d.unit_vector * self.config.infinite_line_length
            if dxftype == "XLINE":
                self.out.draw_line(start - delta / 2, start + delta / 2,
                                   properties)
            elif dxftype == "RAY":
                self.out.draw_line(start, start + delta, properties)
        else:
            raise TypeError(dxftype)
Esempio n. 11
0
    def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None:
        """ Draw a single DXF entity.

        Args:
            entity: DXF Entity
            properties: resolved entity properties

        """
        dxftype = entity.dxftype()
        self.out.enter_entity(entity, properties)
        if entity.proxy_graphic and self.proxy_graphics == PREFER_PROXY_GRAPHICS:
            self.draw_proxy_graphic(entity)
        elif dxftype in {'LINE', 'XLINE', 'RAY'}:
            self.draw_line_entity(entity, properties)
        elif dxftype in {'TEXT', 'MTEXT', 'ATTRIB'}:
            if is_spatial(Vec3(entity.dxf.extrusion)):
                self.draw_text_entity_3d(entity, properties)
            else:
                self.draw_text_entity_2d(entity, properties)
        elif dxftype in {'CIRCLE', 'ARC', 'ELLIPSE'}:
            self.draw_elliptic_arc_entity(entity, properties)
        elif dxftype == 'SPLINE':
            self.draw_spline_entity(entity, properties)
        elif dxftype == 'POINT':
            self.draw_point_entity(entity, properties)
        elif dxftype == 'HATCH':
            self.draw_hatch_entity(entity, properties)
        elif dxftype == 'MESH':
            self.draw_mesh_entity(entity, properties)
        elif dxftype in {'3DFACE', 'SOLID', 'TRACE'}:
            self.draw_solid_entity(entity, properties)
        elif dxftype in {'POLYLINE', 'LWPOLYLINE'}:
            self.draw_polyline_entity(entity, properties)
        elif dxftype in COMPOSITE_ENTITY_TYPES:
            self.draw_composite_entity(entity, properties)
        elif dxftype == 'WIPEOUT':
            self.draw_wipeout_entity(entity, properties)
        elif dxftype == 'VIEWPORT':
            self.draw_viewport_entity(entity)
        elif entity.proxy_graphic and self.proxy_graphics == USE_PROXY_GRAPHICS:
            self.draw_proxy_graphic(entity)
        else:
            self.skip_entity(entity, 'Unsupported entity')
        self.out.exit_entity(entity)
Esempio n. 12
0
    def write(self, entity: DXFGraphic):
        """ Write a DXF entity from the source DXF file to the export file.

        Don't write entities from different documents than the source DXF file, dependencies and resources will not
        match, maybe it will work once, but not in a reliable way for different DXF documents.

        """
        # remove all possible dependencies
        entity.xdata = None
        entity.appdata = None
        entity.extension_dict = None
        entity.reactors = None
        entity.export_dxf(self.entity_writer)
        if entity.dxftype() == 'POLYLINE':
            polyline = cast('Polyline', entity)
            for vertex in polyline.vertices:
                vertex.export_dxf(self.entity_writer)
            polyline.seqend.export_dxf(self.entity_writer)
Esempio n. 13
0
    def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None:
        """ Draw a single DXF entity.

        Args:
            entity: DXF Entity
            properties: resolved entity properties

        """
        self.out.enter_entity(entity, properties)

        if entity.proxy_graphic and self.proxy_graphics == PREFER_PROXY_GRAPHICS:
            self.draw_proxy_graphic(entity)
        else:
            draw_method = self._dispatch.get(entity.dxftype(), None)
            if draw_method is not None:
                draw_method(entity, properties)
            elif entity.proxy_graphic and self.proxy_graphics == USE_PROXY_GRAPHICS:
                self.draw_proxy_graphic(entity)
            else:
                self.skip_entity(entity, 'Unsupported entity')
        self.out.exit_entity(entity)
Esempio n. 14
0
    def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None:
        """
        Draw a single DXF entity.

        Args:
            entity: DXF Entity
            properties: resolved entity properties

        """
        dxftype = entity.dxftype()
        self.out.set_current_entity(entity, tuple(self.parent_stack))
        if dxftype in {'LINE', 'XLINE', 'RAY'}:
            self.draw_line_entity(entity, properties)
        elif dxftype in {'TEXT', 'MTEXT', 'ATTRIB'}:
            if is_spatial(Vector(entity.dxf.extrusion)):
                self.draw_text_entity_3d(entity, properties)
            else:
                self.draw_text_entity_2d(entity, properties)
        elif dxftype in {'CIRCLE', 'ARC', 'ELLIPSE'}:
            self.draw_elliptic_arc_entity(entity, properties)
        elif dxftype == 'SPLINE':
            self.draw_spline_entity(entity, properties)
        elif dxftype == 'POINT':
            self.draw_point_entity(entity, properties)
        elif dxftype == 'HATCH':
            self.draw_hatch_entity(entity, properties)
        elif dxftype == 'MESH':
            self.draw_mesh_entity(entity, properties)
        elif dxftype in {'3DFACE', 'SOLID', 'TRACE'}:
            self.draw_solid_entity(entity, properties)
        elif dxftype in {'POLYLINE', 'LWPOLYLINE'}:
            self.draw_polyline_entity(entity, properties)
        elif dxftype in COMPOSITE_ENTITY_TYPES:
            self.draw_composite_entity(entity, properties)
        elif dxftype == 'VIEWPORT':
            self.draw_viewport_entity(entity)
        else:
            self.skip_entity(f'Unsupported entity: {str(entity)}')
        self.out.set_current_entity(None)
Esempio n. 15
0
    def draw_viewport_entity(self, entity: DXFGraphic) -> None:
        assert entity.dxftype() == 'VIEWPORT'
        dxf = entity.dxf
        view_vector: Vector = dxf.view_direction_vector
        mag = view_vector.magnitude
        if math.isclose(mag, 0.0):
            print('warning: viewport with null view vector')
            return
        view_vector /= mag
        if not math.isclose(view_vector.dot(Vector(0, 0, 1)), 1.0):
            print(f'cannot render viewport with non-perpendicular view direction: {dxf.view_direction_vector}')
            return

        cx, cy = dxf.center.x, dxf.center.y
        dx = dxf.width / 2
        dy = dxf.height / 2
        minx, miny = cx - dx, cy - dy
        maxx, maxy = cx + dx, cy + dy
        points = [(minx, miny), (maxx, miny), (maxx, maxy), (minx, maxy), (minx, miny)]
        props = Properties()
        props.color = VIEWPORT_COLOR
        self.out.draw_filled_polygon([Vector(x, y, 0) for x, y in points], props)
Esempio n. 16
0
    def draw_viewport_entity(self, entity: DXFGraphic,
                             properties: Properties) -> None:
        assert entity.dxftype() == 'VIEWPORT'
        # Special VIEWPORT id == 1, this viewport defines the "active viewport"
        # which is the area currently shown in the layout tab by the CAD
        # application.
        # BricsCAD set id to -1 if the viewport is off and 'status' (group
        # code 68) is not present.
        if entity.dxf.id < 2 or entity.dxf.status < 1:
            return
        dxf = entity.dxf
        view_vector: Vec3 = dxf.view_direction_vector
        mag = view_vector.magnitude
        if math.isclose(mag, 0.0):
            self.log_message('Warning: viewport with null view vector')
            return
        view_vector /= mag
        if not math.isclose(view_vector.dot(Vec3(0, 0, 1)), 1.0):
            self.log_message(
                f'Cannot render viewport with non-perpendicular view direction:'
                f' {dxf.view_direction_vector}'
            )
            return

        cx, cy = dxf.center.x, dxf.center.y
        dx = dxf.width / 2
        dy = dxf.height / 2
        minx, miny = cx - dx, cy - dy
        maxx, maxy = cx + dx, cy + dy
        points = [
            (minx, miny), (maxx, miny), (maxx, maxy), (minx, maxy), (minx, miny)
        ]
        props = Properties()
        props.color = VIEWPORT_COLOR
        # Set default SOLID filling for VIEWPORT
        props.filling = Filling()
        self.out.draw_filled_polygon([Vec3(x, y, 0) for x, y in points],
                                     props)
Esempio n. 17
0
    def draw_hatch_entity(self, entity: DXFGraphic,
                          properties: Properties) -> None:
        entity = cast(Hatch, entity)
        ocs = entity.ocs()
        # all OCS coordinates have the same z-axis stored as vector (0, 0, z),
        # default (0, 0, 0)
        elevation = entity.dxf.elevation.z
        paths = copy.deepcopy(entity.paths)
        paths.polyline_to_edge_path(just_with_bulge=False)

        # For hatches, the approximation don't have to be that precise.
        paths.all_to_line_edges(num=64, spline_factor=8)
        for p in paths:
            assert p.PATH_TYPE == 'EdgePath'
            vertices = []
            last_vertex = None
            for e in p.edges:
                assert e.EDGE_TYPE == 'LineEdge'
                start, end = ocs.points_to_wcs([
                    Vector(e.start[0], e.start[1], elevation),
                    Vector(e.end[0], e.end[1], elevation),
                ])
                if last_vertex is None:
                    vertices.append(start)
                elif not last_vertex.isclose(start):
                    # this sometimes happens when a curved section is the
                    # wrong way round. This should be fixed by moving to
                    # rendering using Path objects:
                    # https://github.com/mozman/ezdxf/issues/202
                    vertices.append(start)
                vertices.append(end)
                last_vertex = end

            if vertices:
                if not last_vertex.isclose(vertices[0]):
                    vertices.append(last_vertex)
                self.out.draw_filled_polygon(vertices, properties)
Esempio n. 18
0
    def draw_polyline_entity(self, entity: DXFGraphic):
        dxftype = entity.dxftype()

        if dxftype == 'POLYLINE':
            e = cast(Polyface, entity)
            if e.is_polygon_mesh or e.is_poly_face_mesh:
                self.draw_mesh_builder_entity(
                    MeshBuilder.from_polyface(e),
                    self._resolve_properties(entity),
                )
                return

        entity = cast(Union[LWPolyline, Polyline], entity)
        if not entity.has_arc:
            properties = self._resolve_properties(entity)
            if dxftype == 'LWPOLYLINE':
                self.out.draw_line_string(Vector.generate(
                    entity.vertices_in_wcs()),
                                          close=entity.closed,
                                          properties=properties)
            else:  # POLYLINE
                if entity.is_2d_polyline:
                    ocs = entity.ocs()
                    elevation = Vector(entity.dxf.elevation).z
                    vertices = ocs.points_to_wcs(
                        Vector(p[0], p[1], elevation) for p in entity.points())
                else:
                    vertices = Vector.generate(entity.points())
                self.out.draw_line_string(vertices,
                                          close=entity.is_closed,
                                          properties=properties)
            return

        self.parent_stack.append(entity)
        self.out.set_current_entity(entity, tuple(self.parent_stack))
        # todo: end points of virtual entities are not in correct order
        #  can't use self.out.start_path()
        for child in entity.virtual_entities():
            # all child entities have the same properties as the parent,
            # no visibility check required:
            self.draw_entity(child)
        # self.out.end_path()
        self.parent_stack.pop()
        self.out.set_current_entity(None)