def modelspace(filename: str, 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 = low_level_tagger(fp) queued: Optional[DXFEntity] = None tags: List[DXFTag] = [] factory = EntityFactory() linked_entity = entity_linker() for tag in tag_compiler(tagger): 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.entity(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
def modelspace(self) -> Iterable[DXFGraphic]: """ Returns an iterator for all supported DXF entities in the modelspace. These entities are regular :class:`~ezdxf.entities.DXFGraphic` objects but without a valid document assigned. It is **not** possible to add these entities to other `ezdxf` documents. It is only possible to recreate the objects by factory functions base on attributes of the source entity. For MESH, POLYMESH and POLYFACE it is possible to use the :class:`~ezdxf.render.MeshTransformer` class to render (recreate) this objects as new entities in another document. """ if self._fp_entities_section is None: self._fp_entities_section = self._seek_to_section('ENTITIES') self.file.seek(self._fp_entities_section) tags = [] factory = EntityFactory() polyline: Optional[Polyline] = None for tag in tag_compiler(low_level_tagger(self.file)): if tag.code == 0: # start new entity if len(tags): xtags = ExtendedTags(tags) dxftype = xtags.dxftype() if dxftype in SUPPORTED_DXF_TYPES: entity = factory.entity(xtags) if dxftype == 'SEQEND': if polyline is not None: polyline.seqend = entity yield polyline polyline = None # suppress all other SEQEND entities -> ATTRIB elif dxftype == 'VERTEX' and polyline is not None: # vertices without POLYLINE are DXF structure errors, but here just ignore it. polyline.vertices.append(entity) elif dxftype == 'POLYLINE': polyline = entity else: # POLYLINE without SEQEND is a DXF structure error, but here just ignore it. # By using this add-on be sure to get valid DXF files. polyline = None yield entity if tag == (0, 'ENDSEC'): break tags = [tag] else: tags.append(tag)
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') factory = EntityFactory() 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.entity(xtags) entry = next_entry
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] = [] factory = EntityFactory() 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.entity(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