예제 #1
0
def test_factory_load():
    tags = ExtendedTags.from_text(POINT)
    e = factory.load(tags)
    assert e.dxftype() == 'POINT'
    assert e.doc is None
    assert e.dxf.handle == 'FEFE'
    assert e.dxf.owner is None
    assert e.is_alive is True
    assert e.is_virtual is True
예제 #2
0
def test_empty_section():
    sec = load_section(EMPTYSEC, "CLASSES")
    cls_entities = [factory.load(ExtendedTags(e)) for e in sec]

    section = ClassesSection(None, iter(cls_entities))
    stream = StringIO()
    section.export_dxf(TagWriter(stream))
    result = stream.getvalue()
    stream.close()
    assert EMPTYSEC == result
예제 #3
0
def test_support_for_proxy_graphic_stored_in_acdb_entity():
    tag_storage = factory.load(ExtendedTags.from_text(DXF_STORAGE))
    assert tag_storage.dxftype() == "TAG_STORAGE"
    proxy = DXFGraphicProxy(tag_storage)
    # reusing data from test suite 252
    types = [e.dxftype() for e in query_virtual_entities(proxy)]
    assert types == [
        "POLYLINE",
        "POLYLINE",
        "ARC",
        "ARC",
        "POLYLINE",
        "POLYLINE",
    ]
예제 #4
0
def load_dxf_entities(entities: Iterable[Tags]) -> Iterable['DXFEntity']:
    check_tag_structure = options.check_entity_tag_structures
    for entity in entities:
        if len(entity) == 0:
            logger.debug('Ignore empty DXF entity.')
            continue
        code, dxftype = entity[0]
        if code != 0:
            raise DXFStructureError(
                f'Invalid first tag in DXF entity, group code={code}.')

        if check_tag_structure and (dxftype not in EXCLUDE_STRUCTURE_CHECK):
            entity = entity_structure_validator(entity)
        yield factory.load(ExtendedTags(entity))
예제 #5
0
def modelspace(filename: Filename,
               types: Iterable[str] = None) -> Iterable[DXFGraphic]:
    """
    Iterate over all modelspace entities as :class:`DXFGraphic` objects of a seekable file.

    Use this function to 'quick' iterate over modelspace entities of a DXF file,
    filtering DXF types may speed up things if many entity types will be skipped.

    Args:
        filename: filename of a seekable DXF file
        types: DXF types like ``['LINE', '3DFACE']`` which should be returned, ``None`` returns all supported types.

    """
    info = dxf_file_info(filename)
    prev_code: int = -1
    prev_value: str = ''
    entities = False
    requested_types = _requested_types(types)

    with open(filename, mode='rt', encoding=info.encoding) as fp:
        tagger = ascii_tags_loader(fp)
        queued: Optional[DXFEntity] = None
        tags: List[DXFTag] = []
        linked_entity = entity_linker()

        for tag in tag_compiler(tagger):
            code = tag.code
            value = tag.value
            if entities:
                if code == 0:
                    if len(tags) and tags[0].value in requested_types:
                        entity = factory.load(ExtendedTags(tags))
                        if not linked_entity(
                                entity) and entity.dxf.paperspace == 0:
                            if queued:  # queue one entity for collecting linked entities (VERTEX, ATTRIB)
                                yield queued
                            queued = entity
                    tags = [tag]
                else:
                    tags.append(tag)
                if code == 0 and value == 'ENDSEC':
                    if queued:
                        yield queued
                    return
                continue  # if entities - nothing else matters
            elif code == 2 and prev_code == 0 and prev_value == 'SECTION':
                entities = (value == 'ENTITIES')

            prev_code = code
            prev_value = value
예제 #6
0
    def load_entities(self, start: int,
                      requested_types: Set[str]) -> Iterable[DXFGraphic]:
        def to_str(data: bytes) -> str:
            return data.decode(self.encoding,
                               errors=self.errors).replace("\r\n", "\n")

        index = start
        entry = self.structure.index[index]
        self.file.seek(entry.location)
        while entry.value != "ENDSEC":
            index += 1
            next_entry = self.structure.index[index]
            size = next_entry.location - entry.location
            data = self.file.read(size)
            if entry.value in requested_types:
                xtags = ExtendedTags.from_text(to_str(data))
                yield factory.load(xtags)  # type: ignore
            entry = next_entry
예제 #7
0
    def load_entities(
            self,
            start: int,
            requested_types: Iterable[str] = None) -> Iterable[DXFGraphic]:
        def to_str(data: bytes) -> str:
            return data.decode(self.encoding).replace('\r\n', '\n')

        index = start
        entry = self.structure.index[index]
        self.file.seek(entry.location)
        while entry.value != 'ENDSEC':
            index += 1
            next_entry = self.structure.index[index]
            size = next_entry.location - entry.location
            data = self.file.read(size)
            if entry.value in requested_types:
                xtags = ExtendedTags.from_text(to_str(data))
                yield factory.load(xtags)
            entry = next_entry
예제 #8
0
def single_pass_modelspace(
    stream: BinaryIO,
    types: Iterable[str] = None,
    errors: str = "surrogateescape",
) -> Iterable[DXFGraphic]:
    """Iterate over all modelspace entities as :class:`DXFGraphic` objects in
    one single pass.

    Use this function to 'quick' iterate over modelspace entities of a **not**
    seekable binary DXF stream, filtering DXF types may speed up things if many
    entity types will be skipped.

    Args:
        stream: (not seekable) binary DXF stream
        types: DXF types like ``['LINE', '3DFACE']`` which should be returned,
            ``None`` returns all supported types.
        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: Invalid or incomplete DXF file
        UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs

    """
    fetch_header_var: Optional[str] = None
    encoding = "cp1252"
    version = "AC1009"
    prev_code: int = -1
    prev_value: str = ""
    entities = False
    requested_types = _requested_types(types)

    for code, value in binary_tagger(stream):
        if code == 0 and value == b"ENDSEC":
            break
        elif code == 2 and prev_code == 0 and value != b"HEADER":
            # (0, SECTION), (2, name)
            # First section is not the HEADER section
            entities = value == b"ENTITIES"
            break
        elif code == 9 and value == b"$DWGCODEPAGE":
            fetch_header_var = "ENCODING"
        elif code == 9 and value == b"$ACADVER":
            fetch_header_var = "VERSION"
        elif fetch_header_var == "ENCODING":
            encoding = toencoding(value.decode())
            fetch_header_var = None
        elif fetch_header_var == "VERSION":
            version = value.decode()
            fetch_header_var = None
        prev_code = code

    if version >= "AC1021":
        encoding = "utf-8"

    queued: Optional[DXFGraphic] = None
    tags: List[DXFTag] = []
    linked_entity = entity_linker()

    for tag in tag_compiler(binary_tagger(stream, encoding, errors)):
        code = tag.code
        value = tag.value
        if entities:
            if code == 0 and value == "ENDSEC":
                if queued:
                    yield queued
                return
            if code == 0:
                if len(tags) and tags[0].value in requested_types:
                    entity = cast(DXFGraphic, factory.load(ExtendedTags(tags)))
                    if not linked_entity(
                            entity) and entity.dxf.paperspace == 0:
                        # queue one entity for collecting linked entities:
                        # VERTEX, ATTRIB
                        if queued:
                            yield queued
                        queued = entity
                tags = [tag]
            else:
                tags.append(tag)
            continue  # if entities - nothing else matters
        elif code == 2 and prev_code == 0 and prev_value == "SECTION":
            entities = value == "ENTITIES"

        prev_code = code
        prev_value = value
예제 #9
0
def modelspace(
    filename: Filename,
    types: Iterable[str] = None,
    errors: str = "surrogateescape",
) -> Iterable[DXFGraphic]:
    """Iterate over all modelspace entities as :class:`DXFGraphic` objects of
    a seekable file.

    Use this function to iterate "quick" over modelspace entities of a DXF file,
    filtering DXF types may speed up things if many entity types will be skipped.

    Args:
        filename: filename of a seekable DXF file
        types: DXF types like ``['LINE', '3DFACE']`` which should be returned,
            ``None`` returns all supported types.
        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: invalid or incomplete DXF file
        UnicodeDecodeError: if `errors` is "strict" and a decoding error occurs

    """
    info = dxf_file_info(str(filename))
    prev_code: int = -1
    prev_value: Any = ""
    entities = False
    requested_types = _requested_types(types)

    with open(filename, mode="rt", encoding=info.encoding,
              errors=errors) as fp:
        tagger = ascii_tags_loader(fp)
        queued: Optional[DXFEntity] = None
        tags: List[DXFTag] = []
        linked_entity = entity_linker()

        for tag in tag_compiler(tagger):
            code = tag.code
            value = tag.value
            if entities:
                if code == 0:
                    if len(tags) and tags[0].value in requested_types:
                        entity = factory.load(ExtendedTags(tags))
                        if (not linked_entity(entity)
                                and entity.dxf.paperspace == 0):
                            # queue one entity for collecting linked entities:
                            # VERTEX, ATTRIB
                            if queued:
                                yield queued  # type: ignore
                            queued = entity
                    tags = [tag]
                else:
                    tags.append(tag)
                if code == 0 and value == "ENDSEC":
                    if queued:
                        yield queued  # type: ignore
                    return
                continue  # if entities - nothing else matters
            elif code == 2 and prev_code == 0 and prev_value == "SECTION":
                entities = value == "ENTITIES"

            prev_code = code
            prev_value = value
예제 #10
0
def section():
    sec = load_section(TESTCLASSES, "CLASSES")
    cls_entities = [factory.load(ExtendedTags(e)) for e in sec]
    return ClassesSection(None, iter(cls_entities))
def proxy() -> ACADProxyEntity:
    xtags = ExtendedTags.from_text(AEC_DOOR)
    return cast(ACADProxyEntity, factory.load(xtags, ezdxf.new("R2018")))
예제 #12
0
def load_dxf_entities(entities: Iterable[Tags]) -> Iterable['DXFEntity']:
    for entity in entities:
        yield factory.load(ExtendedTags(entity))
예제 #13
0
def load_dxf_entities(entities: Iterable[Tags],
                      doc: "Drawing" = None) -> Iterable["DXFEntity"]:
    for entity in entities:
        yield factory.load(ExtendedTags(entity), doc)
예제 #14
0
def single_pass_modelspace(stream: BinaryIO,
                           types: Iterable[str] = None
                           ) -> Iterable[DXFGraphic]:
    """
    Iterate over all modelspace entities as :class:`DXFGraphic` objects in one single pass.

    Use this function to 'quick' iterate over modelspace entities of a **not** seekable binary DXF stream,
    filtering DXF types may speed up things if many entity types will be skipped.

    Args:
        stream: (not seekable) binary DXF stream
        types: DXF types like ``['LINE', '3DFACE']`` which should be returned, ``None`` returns all supported types.

    """
    fetch_header_var: Optional[str] = None
    encoding = 'cp1252'
    version = 'AC1009'
    prev_code: int = -1
    prev_value: str = ''
    entities = False
    requested_types = _requested_types(types)

    for code, value in binary_tagger(stream):
        if code == 0 and value == b'ENDSEC':
            break
        elif code == 2 and prev_code == 0 and value != b'HEADER':
            # (0, SECTION), (2, name)
            # First section is not the HEADER section
            entities = (value == b'ENTITIES')
            break
        elif code == 9 and value == b'$DWGCODEPAGE':
            fetch_header_var = 'ENCODING'
        elif code == 9 and value == b'$ACADVER':
            fetch_header_var = 'VERSION'
        elif fetch_header_var == 'ENCODING':
            encoding = toencoding(value.decode())
            fetch_header_var = None
        elif fetch_header_var == 'VERSION':
            version = value.decode()
            fetch_header_var = None
        prev_code = code

    if version >= 'AC1021':
        encoding = 'utf-8'

    queued: Optional[DXFEntity] = None
    tags: List[DXFTag] = []
    linked_entity = entity_linker()

    for tag in tag_compiler(binary_tagger(stream, encoding)):
        code = tag.code
        value = tag.value
        if entities:
            if code == 0 and value == 'ENDSEC':
                if queued:
                    yield queued
                return
            if code == 0:
                if len(tags) and tags[0].value in requested_types:
                    entity = factory.load(ExtendedTags(tags))
                    if not linked_entity(
                            entity) and entity.dxf.paperspace == 0:
                        if queued:  # queue one entity for collecting linked entities (VERTEX, ATTRIB)
                            yield queued
                        queued = entity
                tags = [tag]
            else:
                tags.append(tag)
            continue  # if entities - nothing else matters
        elif code == 2 and prev_code == 0 and prev_value == 'SECTION':
            entities = (value == 'ENTITIES')

        prev_code = code
        prev_value = value