コード例 #1
0
ファイル: mtext.py プロジェクト: yanbin-ha/ezdxf
 def mtext_handles(self) -> List[str]:
     """ Returns a list of all linked MTEXT handles. """
     if self.linked_handles:
         return self.linked_handles
     handles = []
     for column in self.linked_columns:
         if column.is_alive:
             handle = column.dxf.handle
             if handle is None:
                 raise const.DXFStructureError(
                     "Linked MTEXT column has no handle.")
             handles.append(handle)
         else:
             raise const.DXFStructureError("Linked MTEXT column deleted!")
     return handles
コード例 #2
0
ファイル: recover.py プロジェクト: ebrahimraeyat/ezdxf
def bytes_loader(stream: BinaryIO) -> Iterable[DXFTag]:
    """ Yields :class:``DXFTag`` objects from a bytes `stream`
    (untrusted external  source), skips all comment tags (group code == 999).

    ``DXFTag.code`` is always an ``int`` and ``DXFTag.value`` is always a
    raw bytes value without line endings. Works with file system streams and
    :class:`BytesIO` streams.

    Raises:
        DXFStructureError: Found invalid group code.

    """
    line = 1
    readline = stream.readline
    while True:
        code = readline()
        # ByteIO(): empty strings indicates EOF - does not raise an exception
        if code:
            try:
                code = int(code)
            except ValueError:
                code = code.decode(errors='ignore')
                raise const.DXFStructureError(
                    f'Invalid group code "{code}" at line {line}.')
        else:
            return

        value = readline()
        # ByteIO(): empty strings indicates EOF
        if value:
            if code != 999:
                yield DXFTag(code, value.rstrip(b'\r\n'))
            line += 2
        else:
            return
コード例 #3
0
ファイル: mline.py プロジェクト: Rahulghuge94/ezdxf
    def load_dxf_attribs(
        self, processor: SubclassProcessor = None
    ) -> "DXFNamespace":
        dxf = super().load_dxf_attribs(processor)
        if processor:
            tags = processor.subclass_by_index(1)
            if tags is None:
                raise const.DXFStructureError(
                    f"missing 'AcDbMLine' subclass in MLINE(#{dxf.handle})"
                )

            try:
                # Find index of the count tag:
                index71 = tags.tag_index(71)
            except const.DXFValueError:
                # The count tag does not exist: DXF structure error?
                pass
            else:
                self.elements = MLineStyleElements(tags[index71 + 1 :])  # type: ignore
                # Remove processed tags:
                del tags[index71:]
            processor.fast_load_dxfattribs(
                dxf, acdb_mline_style_group_codes, tags
            )
        return dxf
コード例 #4
0
 def load_edge(tags: Tags) -> 'EdgeTypes':
     edge_type = tags[0].value
     if 0 < edge_type < 5:
         return EDGE_CLASSES[edge_type].load_tags(tags[1:])
     else:
         raise const.DXFStructureError(
             "HATCH: unknown edge type: {}".format(edge_type))
コード例 #5
0
ファイル: mtext.py プロジェクト: yanbin-ha/ezdxf
 def export_linked_entities(self, tagwriter: 'TagWriter'):
     for mtext in self._columns.linked_columns:
         if mtext.dxf.handle is None:
             raise const.DXFStructureError(
                 "Linked MTEXT column has no handle.")
         # Export linked columns as separated DXF entities:
         mtext.export_dxf(tagwriter)
コード例 #6
0
    def load_tags(self, tags: Iterator[DXFTag]) -> None:
        """ Constructor to generate header variables loaded from DXF files
        (untrusted environment).

        Args:
            tags: DXF tags as Tags() or ExtendedTags()

        """
        tags = tags or self.MIN_HEADER_TAGS
        section_tag = next(tags)
        name_tag = next(tags)

        if section_tag != (0, 'SECTION') or name_tag != (2, 'HEADER'):
            raise const.DXFStructureError(
                "Critical structure error in HEADER section.")

        groups = group_tags(header_validator(tags), splitcode=9)
        custom_property_stack = []  # collect $CUSTOMPROPERTY/TAG
        for group in groups:
            name = group[0].value
            value = group[1]
            if name in ('$CUSTOMPROPERTYTAG', '$CUSTOMPROPERTY'):
                custom_property_stack.append(value.value)
            else:
                self.hdrvars[name] = HeaderVar(value)

        custom_property_stack.reverse()
        while len(custom_property_stack):
            try:
                self.custom_vars.append(tag=custom_property_stack.pop(),
                                        value=custom_property_stack.pop())
            except IndexError:  # internal exception
                break
コード例 #7
0
ファイル: table.py プロジェクト: ericgcc/ezdxf
 def load(self, entities: Iterator['DXFEntity']) -> None:
     """ Loading interface. (internal API)"""
     self._head = next(entities)
     if self._head.dxftype() != 'TABLE':
         raise const.DXFStructureError(
             "Critical structure error in TABLES section.")
     for table_entry in entities:
         self._append(table_entry)
コード例 #8
0
ファイル: boundary_paths.py プロジェクト: Rahulghuge94/ezdxf
 def load_edge(tags: Tags) -> AbstractEdge:
     edge_type = tags[0].value
     if 0 < edge_type < 5:
         return EDGE_CLASSES[edge_type].load_tags(tags[1:])
     else:
         raise const.DXFStructureError(
             f"HATCH: unknown edge type: {edge_type}"
         )
コード例 #9
0
ファイル: dxfgroups.py プロジェクト: Rahulghuge94/ezdxf
    def set_data(self, entities: Iterable[DXFEntity]) -> None:
        """Set `entities` as new group content, entities should be an iterable
        :class:`DXFGraphic` or inherited (LINE, CIRCLE, ...).
        Raises :class:`DXFValueError` if not all entities be on the same layout
        (modelspace or any paperspace layout but not block)

        """
        assert self.doc is not None
        entities = list(entities)
        valid_entities = filter_invalid_entities(entities, self.doc, str(self))
        if len(valid_entities) != len(entities):
            raise const.DXFStructureError("invalid entities found")
        if not all_entities_on_same_layout(valid_entities):
            raise const.DXFStructureError(
                "All entities have to be in the same layout and are not allowed"
                " to be in a block layout.")
        self.clear()
        self._data = valid_entities
コード例 #10
0
ファイル: objects.py プロジェクト: Rahulghuge94/ezdxf
 def setup_rootdict(self) -> Dictionary:
     """Create a root dictionary. Has to be the first object in the objects
     section. (internal API)"""
     if len(self):
         raise const.DXFStructureError(
             "Can not create root dictionary in none empty objects section."
         )
     logger.debug("Creating ROOT dictionary.")
     # root directory has no owner
     return self.add_dictionary(owner="0", hard_owned=False)
コード例 #11
0
ファイル: dxfgroups.py プロジェクト: Rahulghuge94/ezdxf
 def preprocess_export(self, tagwriter: "TagWriter") -> bool:
     # remove invalid entities
     assert self.doc is not None
     self.purge(self.doc)
     # export GROUP only if all entities reside on the same layout
     if not all_entities_on_same_layout(self._data):
         raise const.DXFStructureError(
             "All entities have to be in the same layout and are not allowed"
             " to be in a block layout.")
     return True
コード例 #12
0
    def associate(self, path: AbstractBoundaryPath,
                  entities: Iterable["DXFEntity"]):
        """Set association from hatch boundary `path` to DXF geometry `entities`.

        A HATCH entity can be associative to a base geometry, this association
        is **not** maintained nor verified by `ezdxf`, so if you modify the base
        geometry the geometry of the boundary path is not updated and no
        verification is done to check if the associated geometry matches
        the boundary path, this opens many possibilities to create
        invalid DXF files: USE WITH CARE!

        """
        # I don't see this as a time critical operation, do as much checks as
        # needed to avoid invalid DXF files.
        if not self.is_alive:
            raise const.DXFStructureError("HATCH entity is destroyed")

        doc = self.doc
        owner = self.dxf.owner
        handle = self.dxf.handle
        if doc is None or owner is None or handle is None:
            raise const.DXFStructureError(
                "virtual entity can not have associated entities")

        for entity in entities:
            if not entity.is_alive or entity.is_virtual:
                raise const.DXFStructureError(
                    "associated entity is destroyed or a virtual entity")
            if doc is not entity.doc:
                raise const.DXFStructureError(
                    "associated entity is from a different document")
            if owner != entity.dxf.owner:
                raise const.DXFStructureError(
                    "associated entity is from a different layout")

            path.source_boundary_objects.append(entity.dxf.handle)
            entity.append_reactor_handle(handle)
        self.dxf.associative = 1 if len(path.source_boundary_objects) else 0
コード例 #13
0
ファイル: hatch.py プロジェクト: ptmcg/ezdxf
    def load_paths(self, tags: Tags) -> Tags:
        # find first group code 91 = count of loops, Spline data also contains group code 91!
        try:
            start_index = tags.tag_index(91)
        except const.DXFValueError:
            raise const.DXFStructureError(
                "HATCH: Missing required DXF tag 'Number of boundary paths (loops)' (code=91).")

        path_tags = tags.collect_consecutive_tags(PATH_CODES, start=start_index + 1)
        if len(path_tags):
            self.paths = BoundaryPaths.load_tags(path_tags)
        end_index = start_index + len(path_tags) + 1
        del tags[start_index: end_index]
        return tags
コード例 #14
0
    def import_entity(self,
                      entity: "DXFEntity",
                      target_layout: "BaseLayout" = None) -> None:
        """
        Imports a single DXF `entity` into `target_layout` or the modelspace
        of the target document, if `target_layout` is ``None``.

        Args:
            entity: DXF entity to import
            target_layout: any layout (modelspace, paperspace or block) from
                the target document

        Raises:
            DXFStructureError: `target_layout` is not a layout of target document

        """
        def set_dxf_attribs(e):
            e.doc = self.target
            # remove invalid resources
            e.dxf.discard("plotstyle_handle")
            e.dxf.discard("material_handle")
            e.dxf.discard("visualstyle_handle")

        if target_layout is None:
            target_layout = self.target.modelspace()
        elif target_layout.doc != self.target:
            raise const.DXFStructureError(
                "Target layout has to be a layout or block from the target "
                "document.")

        dxftype = entity.dxftype()
        if dxftype not in IMPORT_ENTITIES:
            logger.debug(f"Import of {str(entity)} not supported")
            return
        self._add_used_resources(entity)

        try:
            new_entity = cast("DXFGraphic", new_clean_entity(entity))
        except const.DXFTypeError:
            logger.debug(f"Copying for DXF type {dxftype} not supported.")
            return

        set_dxf_attribs(new_entity)
        self.target.entitydb.add(new_entity)
        target_layout.add_entity(new_entity)

        try:  # additional processing
            getattr(self, "_import_" + dxftype.lower())(new_entity)
        except AttributeError:
            pass
コード例 #15
0
ファイル: objects.py プロジェクト: Rahulghuge94/ezdxf
    def _build(self, entities: Iterator["DXFObject"]) -> None:
        section_head = cast("DXFTagStorage", next(entities))

        if section_head.dxftype() != "SECTION" or section_head.base_class[
            1
        ] != (2, "OBJECTS"):
            raise const.DXFStructureError(
                "Critical structure error in the OBJECTS section."
            )

        for entity in entities:
            # No check for valid entities here:
            # Use the audit- or the recover module to fix invalid DXF files!
            self._entity_space.add(entity)
コード例 #16
0
ファイル: dxfgroups.py プロジェクト: yanbin-ha/ezdxf
    def set_data(self, entities: Iterable[DXFEntity]) -> None:
        """  Set `entities` as new group content, entities should be an iterable
        :class:`DXFGraphic` or inherited (LINE, CIRCLE, ...).
        Raises :class:`DXFValueError` if not all entities be on the same layout
        (modelspace or any paperspace layout but not block)

        """
        entities = list(entities)
        if not all_entities_on_same_layout(entities):
            raise const.DXFStructureError(
                "All entities have to be in the same layout and are not allowed"
                " to be in a block layout."
            )
        self.clear()
        self._data = entities
コード例 #17
0
ファイル: mtext.py プロジェクト: yanbin-ha/ezdxf
    def setup_columns(self, columns: MTextColumns,
                      linked: bool = False) -> None:
        assert columns.column_type != ColumnType.NONE
        assert columns.count > 0, "one or more columns required"
        assert columns.width > 0, "column width has to be > 0"
        assert columns.gutter_width >= 0, "gutter width has to be >= 0"

        if self.has_columns:
            raise const.DXFStructureError('Column setup already exist.')
        self._columns = columns
        self.dxf.width = columns.width
        self.dxf.defined_height = columns.defined_height
        if columns.total_height < 1e-6:
            columns.total_height = columns.defined_height
        if columns.total_width < 1e-6:
            columns.update_total_width()
        if linked:
            self._create_linked_columns()
コード例 #18
0
 def load(self, doc: "Drawing", entities: Iterator["DXFEntity"]) -> None:
     """Loading interface. (internal API)"""
     self.doc = doc
     table_head = next(entities)
     if isinstance(table_head, TableHead):
         self._head = table_head
     else:
         raise const.DXFStructureError(
             "Critical structure error in TABLES section."
         )
     expected_entry_dxftype = self.TABLE_TYPE
     for table_entry in entities:
         if table_entry.dxftype() == expected_entry_dxftype:
             self._append(cast(T, table_entry))
         else:
             logger.warning(
                 f"Ignored invalid DXF entity type '{table_entry.dxftype()}'"
                 f" in {self.TABLE_TYPE} table."
             )
コード例 #19
0
ファイル: underlay.py プロジェクト: Rahulghuge94/ezdxf
    def load_dxf_attribs(self,
                         processor: SubclassProcessor = None
                         ) -> "DXFNamespace":
        dxf = super().load_dxf_attribs(processor)
        if processor:
            tags = processor.subclass_by_index(2)

            if tags:
                tags = Tags(self.load_boundary_path(tags))
                processor.fast_load_dxfattribs(dxf,
                                               acdb_underlay_group_codes,
                                               subclass=tags)
                if len(self.boundary_path) < 2:
                    self.dxf = dxf
                    self.reset_boundary_path()
            else:
                raise const.DXFStructureError(
                    f"missing 'AcDbUnderlayReference' subclass in "
                    f"{self.DXFTYPE}(#{dxf.handle})")
        return dxf
コード例 #20
0
ファイル: mtext.py プロジェクト: Rahulghuge94/ezdxf
 def load_dxf_attribs(self,
                      processor: SubclassProcessor = None
                      ) -> "DXFNamespace":
     dxf = super().load_dxf_attribs(processor)
     if processor:
         tags = processor.subclass_by_index(2)
         if tags:
             tags = Tags(self.load_mtext_content(tags))
             processor.fast_load_dxfattribs(dxf,
                                            acdb_mtext_group_codes,
                                            subclass=tags,
                                            recover=True)
             if processor.embedded_objects:
                 obj = processor.embedded_objects[0]
                 self._columns = load_columns_from_embedded_object(dxf, obj)
             elif self.xdata:
                 self._columns = load_columns_from_xdata(dxf, self.xdata)
         else:
             raise const.DXFStructureError(
                 f"missing 'AcDbMText' subclass in MTEXT(#{dxf.handle})")
     return dxf
コード例 #21
0
ファイル: recover.py プロジェクト: luoyu-123/ezdxf
def bytes_loader(stream: BinaryIO) -> Iterable[DXFTag]:
    """ Yields :class:``DXFTag`` objects from a bytes `stream`
    (untrusted external  source), skips all comment tags (group code == 999).

    ``DXFTag.code`` is always an ``int`` and ``DXFTag.value`` is always a
    raw bytes value without line endings. Works with file system streams and
    :class:`BytesIO` streams.

    Raises:
        DXFStructureError: Found invalid group code.

    """
    line = 1
    while True:
        try:
            code = stream.readline()
            value = stream.readline()
        except EOFError:
            # EOFError indicates a DXFStructureError, but should be handled
            # in top layers.
            return

        # ByteIO(): empty strings indicates EOF
        if code and value:
            try:
                code = int(code)
            except ValueError:
                code = code.decode(const.DEFAULT_ENCODING)
                raise const.DXFStructureError(
                    f'Invalid group code "{code}" at line {line}.')
            else:
                if code != 999:
                    yield DXFTag(code, value.rstrip(b'\r\n'))
                line += 2
        else:
            return
コード例 #22
0
ファイル: boundary_paths.py プロジェクト: Rahulghuge94/ezdxf
 def to_line_edges(spline_edge: SplineEdge):
     weights = spline_edge.weights
     if len(spline_edge.control_points):
         bspline = BSpline(
             control_points=spline_edge.control_points,
             order=spline_edge.degree + 1,
             knots=spline_edge.knot_values,
             weights=weights if len(weights) else None,
         )
     elif len(spline_edge.fit_points):
         bspline = BSpline.from_fit_points(
             spline_edge.fit_points, spline_edge.degree
         )
     else:
         raise const.DXFStructureError(
             "SplineEdge() without control points or fit points."
         )
     segment_count = (max(len(bspline.control_points), 3) - 1) * factor
     vertices = list(bspline.approximate(segment_count))
     for v1, v2 in zip(vertices[:-1], vertices[1:]):
         edge = LineEdge()
         edge.start = v1.vec2
         edge.end = v2.vec2
         yield edge
コード例 #23
0
    def _build(self, entities: Iterator["DXFEntity"]) -> None:
        assert self.doc is not None
        section_head = cast("DXFTagStorage", next(entities))
        if section_head.dxftype(
        ) != "SECTION" or section_head.base_class[1] != (2, "ENTITIES"):
            raise const.DXFStructureError(
                "Critical structure error in ENTITIES section.")

        def add(entity: "DXFGraphic"):
            handle = entity.dxf.owner
            # higher priority for owner handle
            paperspace = 0
            if handle == msp_layout_key:
                paperspace = 0
            elif handle == psp_layout_key:
                paperspace = 1
            elif entity.dxf.hasattr(
                    "paperspace"):  # paperspace flag as fallback
                paperspace = entity.dxf.paperspace

            if paperspace:
                psp.add_entity(entity)
            else:
                msp.add_entity(entity)

        msp = cast("BlockRecord", self.doc.block_records.get("*Model_Space"))
        psp = cast("BlockRecord", self.doc.block_records.get("*Paper_Space"))
        msp_layout_key: str = msp.dxf.handle
        psp_layout_key: str = psp.dxf.handle
        linked_entities = entity_linker()
        # Don't store linked entities (VERTEX, ATTRIB, SEQEND) in entity space
        for entity in entities:
            # No check for valid entities here:
            # Use the audit- or the recover module to fix invalid DXF files!
            if not linked_entities(entity):
                add(entity)  # type: ignore
コード例 #24
0
def byte_tag_compiler(
    tags: Iterable[DXFTag],
    encoding=const.DEFAULT_ENCODING,
    messages: List = None,
    errors: str = 'surrogateescape',
) -> Iterable[DXFTag]:
    """ Compiles DXF tag values imported by bytes_loader() into Python types.

    Raises DXFStructureError() for invalid float values and invalid coordinate
    values.

    Expects DXF coordinates written in x, y[, z] order, see function
    :func:`safe_tag_loader` for usage with applied repair filters.

    Args:
        tags: DXF tag generator, yielding tag values as bytes like bytes_loader()
        encoding: text encoding
        messages: list to store error messages
        errors: specify decoding error handler

            - "surrogateescape" to preserve possible binary data (default)
            - "ignore" to use the replacement char U+FFFD "\ufffd" for invalid data
            - "strict" to raise an :class:`UnicodeDecodeError` exception for invalid data

    Raises:
        DXFStructureError: Found invalid DXF tag or unexpected coordinate order.

    """
    def error_msg(tag):
        code = tag.code
        value = tag.value.decode(encoding)
        return f'Invalid tag ({code}, "{value}") near line: {line}.'

    if messages is None:
        messages = []
    tags = iter(tags)
    undo_tag = None
    line = 0
    while True:
        try:
            if undo_tag is not None:
                x = undo_tag
                undo_tag = None
            else:
                x = next(tags)
                line += 2
            code = x.code
            if code in POINT_CODES:
                y = next(tags)  # y coordinate is mandatory
                line += 2
                # e.g. y-code for x-code=10 is 20
                if y.code != code + 10:
                    raise const.DXFStructureError(
                        f"Missing required y-coordinate near line: {line}.")
                # optional z coordinate
                z = next(tags)
                line += 2
                try:
                    # is it a z-coordinate like (30, 0.0) for base x-code=10
                    if z.code == code + 20:
                        try:
                            point = (float(x.value), float(y.value),
                                     float(z.value))
                        except ValueError:  # search for any float values
                            point = (_search_float(x.value),
                                     _search_float(y.value),
                                     _search_float(z.value))
                    else:
                        try:
                            point = (float(x.value), float(y.value))
                        except ValueError:  # seach for any float values
                            point = (
                                _search_float(x.value),
                                _search_float(y.value),
                            )
                        undo_tag = z
                except ValueError:
                    raise const.DXFStructureError(
                        f'Invalid floating point values near line: {line}.')
                yield DXFVertex(code, point)
            elif code in BINARY_DATA:
                # maybe pre compiled in low level tagger (binary DXF)
                if isinstance(x, DXFBinaryTag):
                    tag = x
                else:
                    try:
                        tag = DXFBinaryTag.from_string(code, x.value)
                    except ValueError:
                        raise const.DXFStructureError(
                            f'Invalid binary data near line: {line}.')
                yield tag
            else:  # just a single tag
                type_ = TYPE_TABLE.get(code, str)
                value: bytes = x.value
                if type_ is str:
                    if code == 0:
                        # remove white space from structure tags
                        value = x.value.strip().upper()
                    try:  # 2 stages to document decoding errors
                        str_ = value.decode(encoding, errors='strict')
                    except UnicodeDecodeError:
                        str_ = value.decode(encoding, errors=errors)
                        messages.append(
                            (AuditError.DECODING_ERROR,
                             f'Fixed unicode decoding error near line {line}'))

                    # Convert DXF unicode notation "\U+xxxx" to unicode,
                    # but exclude structure tags (code>0):
                    if code and has_dxf_unicode(str_):
                        str_ = decode_dxf_unicode(str_)

                    yield DXFTag(code, str_)
                else:
                    try:
                        # fast path for int and float
                        yield DXFTag(code, type_(value))
                    except ValueError:
                        # slow path - e.g. ProE stores int values as floats :((
                        if type_ is int:
                            try:
                                yield DXFTag(code, _search_int(x.value))
                            except ValueError:
                                raise const.DXFStructureError(error_msg(x))
                        elif type_ is float:
                            try:
                                yield DXFTag(code, _search_float(x.value))
                            except ValueError:
                                raise const.DXFStructureError(error_msg(x))
                        else:
                            raise const.DXFStructureError(error_msg(x))
        except StopIteration:
            return
コード例 #25
0
ファイル: mline.py プロジェクト: Rahulghuge94/ezdxf
    def generate_geometry(self, vertices: List[Vec3]) -> None:
        """Regenerate the MLINE geometry for new reference line defined by
        `vertices`.
        """
        vertices = list(filter_close_vertices(vertices, abs_tol=1e-6))
        if len(vertices) == 0:
            self.clear()
            return
        elif len(vertices) == 1:
            self.vertices = [MLineVertex.new(vertices[0], X_AXIS, Y_AXIS)]
            return

        style = self.style
        assert style is not None, "valid MLINE style required"
        if len(style.elements) == 0:
            raise const.DXFStructureError(
                f"No line elements defined in {str(style)}."
            )

        def miter(dir1: Vec3, dir2: Vec3):
            return ((dir1 + dir2) * 0.5).normalize().orthogonal()

        ucs = UCS.from_z_axis_and_point_in_xz(
            origin=vertices[0],
            point=vertices[1],
            axis=self.dxf.extrusion,
        )
        # Transform given vertices into UCS and project them into the
        # UCS-xy-plane by setting the z-axis to 0:
        vertices = [v.replace(z=0) for v in ucs.points_from_wcs(vertices)]
        start_angle = style.dxf.start_angle
        end_angle = style.dxf.end_angle

        line_directions = [
            (v2 - v1).normalize() for v1, v2 in zip(vertices, vertices[1:])
        ]

        if self.is_closed:
            line_directions.append((vertices[0] - vertices[-1]).normalize())
            closing_miter = miter(line_directions[0], line_directions[-1])
            miter_directions = [closing_miter]
        else:
            closing_miter = None
            line_directions.append(line_directions[-1])
            miter_directions = [line_directions[0].rotate_deg(start_angle)]

        for d1, d2 in zip(line_directions, line_directions[1:]):
            miter_directions.append(miter(d1, d2))

        if closing_miter is None:
            miter_directions.pop()
            miter_directions.append(line_directions[-1].rotate_deg(end_angle))
        else:
            miter_directions.append(closing_miter)

        self.vertices = [
            MLineVertex.new(v, d, m)
            for v, d, m in zip(vertices, line_directions, miter_directions)
        ]
        self._update_parametrization()

        # reverse transformation into WCS
        for v in self.vertices:
            v.transform(ucs.matrix)
コード例 #26
0
def byte_tag_compiler(tags: Iterable[DXFTag],
                      encoding=const.DEFAULT_ENCODING) -> Iterable[DXFTag]:
    """ Compiles DXF tag values imported by bytes_loader() into Python types.

    Raises DXFStructureError() for invalid float values and invalid coordinate
    values.

    Expects DXF coordinates written in x, y[, z] order, see function
    :func:`safe_tag_loader` for usage with applied repair filters.

    Args:
        tags: DXF tag generator, yielding tag values as bytes like bytes_loader()
        encoding: text encoding

    Raises:
        DXFStructureError: Found invalid DXF tag or unexpected coordinate order.

    """
    def error_msg(tag):
        code = tag.code
        value = tag.value.decode(encoding)
        return f'Invalid tag ({code}, "{value}") near line: {line}.'

    tags = iter(tags)
    undo_tag = None
    line = 0
    while True:
        try:
            if undo_tag is not None:
                x = undo_tag
                undo_tag = None
            else:
                x = next(tags)
                line += 2
            code = x.code
            if code in POINT_CODES:
                y = next(tags)  # y coordinate is mandatory
                line += 2
                # e.g. y-code for x-code=10 is 20
                if y.code != code + 10:
                    raise const.DXFStructureError(
                        f"Missing required y-coordinate near line: {line}.")
                # optional z coordinate
                z = next(tags)
                line += 2
                try:
                    # is it a z-coordinate like (30, 0.0) for base x-code=10
                    if z.code == code + 20:
                        point = (float(x.value), float(y.value),
                                 float(z.value))
                    else:
                        point = (float(x.value), float(y.value))
                        undo_tag = z
                except ValueError:
                    raise const.DXFStructureError(
                        f'Invalid floating point values near line: {line}.')
                yield DXFVertex(code, point)
            elif code in BINARY_DATA:
                # maybe pre compiled in low level tagger (binary DXF)
                if isinstance(x, DXFBinaryTag):
                    tag = x
                else:
                    try:
                        tag = DXFBinaryTag.from_string(code, x.value)
                    except ValueError:
                        raise const.DXFStructureError(
                            f'Invalid binary data near line: {line}.')
                yield tag
            else:  # just a single tag
                type_ = TYPE_TABLE.get(code, str)
                value: bytes = x.value
                if type_ is str:
                    if code == 0:
                        # remove white space from structure tags
                        value = x.value.strip()
                    yield DXFTag(code, value.decode(encoding))
                else:
                    try:
                        # fast path for int and float
                        yield DXFTag(code, type_(value))
                    except ValueError:
                        # slow path - ProE stores int values as floats :((
                        if type_ is int:
                            try:
                                yield DXFTag(code, int(float(x.value)))
                            except ValueError:
                                raise const.DXFStructureError(error_msg(x))
                        else:
                            raise const.DXFStructureError(error_msg(x))
        except StopIteration:
            return
コード例 #27
0
    def entity_linker_(entity: DXFEntity) -> bool:
        """Collect and link entities which are linked to a parent entity:

        - VERTEX -> POLYLINE
        - ATTRIB -> INSERT

        Args:
             entity: examined DXF entity

        Returns:
             True if `entity` is linked to a parent entity

        """
        nonlocal main_entity, expected_dxftype
        dxftype: str = entity.dxftype()
        # INSERT & POLYLINE are not linked entities, they are stored in the
        # entity space.
        are_linked_entities = False
        if main_entity is not None:
            # VERTEX, ATTRIB & SEQEND are linked tags, they are NOT stored in
            # the entity space.
            are_linked_entities = True
            if dxftype == "SEQEND":
                main_entity.link_seqend(entity)  # type: ignore
                # Marks also the end of the main entity
                main_entity = None
            # Check for valid DXF structure:
            #   VERTEX follows POLYLINE
            #   ATTRIB follows INSERT
            elif dxftype == expected_dxftype:
                main_entity.link_entity(entity)  # type: ignore
            else:
                raise const.DXFStructureError(
                    f"Expected DXF entity {dxftype} or SEQEND")

        elif dxftype in LINKED_ENTITIES:
            # Only INSERT and POLYLINE have a linked entities structure:
            if dxftype == "INSERT" and not entity.dxf.get("attribs_follow", 0):
                # INSERT must not have following ATTRIBS:
                #
                #   INSERT with no ATTRIBS, attribs_follow == 0
                #   ATTRIB as a stand alone entity, which is a DXF structure
                #   error, but this error should be handled in the audit
                #   process.
                #   ....
                #   INSERT with ATTRIBS, attribs_follow == 1
                #   ATTRIB as connected entity
                #   SEQEND
                #
                # Therefore a ATTRIB following an INSERT doesn't mean that
                # these entities are linked.
                pass
            else:
                main_entity = entity
                expected_dxftype = LINKED_ENTITIES[dxftype]

        # Attached MTEXT entity - this feature most likely does not exist!
        elif (dxftype == "MTEXT") and (entity.dxf.handle is None):
            logger.error(
                "Found attached MTEXT entity. Please open an issue at github: "
                "https://github.com/mozman/ezdxf/issues and provide a DXF "
                "example file.")
        return are_linked_entities
コード例 #28
0
    def entity_linker_(entity: DXFEntity) -> bool:
        """ Collect and link entities which are linked to a parent entity:

        - VERTEX -> POLYLINE
        - ATTRIB -> INSERT
        - attached MTEXT entity

        Args:
             entity: examined DXF entity

        Returns:
             True if `entity` is linked to a parent entity

        """
        nonlocal main_entity, expected_dxftype, prev
        dxftype: str = entity.dxftype()
        # INSERT & POLYLINE are not linked entities, they are stored in the
        # entity space.
        are_linked_entities = False
        if main_entity is not None:
            # VERTEX, ATTRIB & SEQEND are linked tags, they are NOT stored in
            # the entity space.
            are_linked_entities = True
            if dxftype == 'SEQEND':
                main_entity.link_seqend(entity)
                # Marks also the end of the main entity
                main_entity = None
            # Check for valid DXF structure:
            #   VERTEX follows POLYLINE
            #   ATTRIB follows INSERT
            elif dxftype == expected_dxftype:
                main_entity.link_entity(entity)
            else:
                raise const.DXFStructureError(
                    f"Expected DXF entity {dxftype} or SEQEND")

        elif dxftype in LINKED_ENTITIES:
            # Only INSERT and POLYLINE have a linked entities structure:
            if dxftype == 'INSERT' and not entity.dxf.get('attribs_follow', 0):
                # INSERT must not have following ATTRIBS, ATTRIB can be a stand
                # alone entity:
                #
                #   INSERT with no ATTRIBS, attribs_follow == 0
                #   ATTRIB as stand alone entity
                #   ....
                #   INSERT with ATTRIBS, attribs_follow == 1
                #   ATTRIB as connected entity
                #   SEQEND
                #
                # Therefore a ATTRIB following an INSERT doesn't mean that
                # these entities are linked.
                pass
            else:
                main_entity = entity
                expected_dxftype = LINKED_ENTITIES[dxftype]

        # Attached MTEXT entity:
        elif (dxftype == 'MTEXT') and (entity.dxf.handle is None):
            if prev:
                prev.link_entity(entity)
                are_linked_entities = True
            else:
                raise const.DXFStructureError(
                    "Found attached MTEXT entity without a preceding entity.")
        prev = entity
        return are_linked_entities