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 __init__(self, dxfversion=DXF2013): self.entitydb = EntityDB() self.dxffactory = EntityFactory(self) self.tracker = Tracker() target_dxfversion = dxfversion.upper() self._dxfversion: str = acad_release_to_dxf_version.get( target_dxfversion, target_dxfversion) if self._dxfversion not in versions_supported_by_new: raise DXFVersionError( f'Unsupported DXF version "{self.dxfversion}".') # Store original dxf version if loaded (and maybe converted R13/14) from file. self._loaded_dxfversion: Optional[str] = None self.encoding: str = 'cp1252' # read/write self.filename: Optional[str] = None # named objects dictionary self.rootdict: 'Dictionary' = None # DXF sections self.header: HeaderSection = None self.classes: ClassesSection = None self.tables: TablesSection = None self.blocks: BlocksSection = None self.entities: EntitySection = None self.objects: ObjectsSection = None # DXF R2013 and later self.acdsdata: AcDsDataSection = None self.stored_sections = [] self.layouts: Layouts = None self.groups: GroupCollection = None self.materials: MaterialCollection = None self.mleader_styles: MLeaderStyleCollection = None self.mline_styles: MLineStyleCollection = None self._acad_compatible = True # will generated DXF file compatible with AutoCAD self._dimension_renderer = DimensionRenderer( ) # set DIMENSION rendering engine self._acad_incompatibility_reason = set( ) # avoid multiple warnings for same reason # Don't create any new entities here: # New created handles could collide with handles loaded from DXF file. assert len(self.entitydb) == 0
def __init__(self, dxfversion=DXF2013): self.entitydb = EntityDB() self.dxffactory = EntityFactory(self) self.tracker = Tracker() # still required # Targeted DXF version, but drawing could be exported as another DXF version. # If target version is set, it is possible to warn user, if they try to use unsupported features, where they # use it and not at exporting, where the location of the code who created that features is not known. target_dxfversion = dxfversion.upper() self._dxfversion = acad_release_to_dxf_version.get( target_dxfversion, target_dxfversion) self._loaded_dxfversion = None # if loaded from file, store original dxf version self.encoding = 'cp1252' self.filename = None # type: str # read/write # named objects dictionary self.rootdict = None # type: Dictionary # DXF sections self.header = None # type: HeaderSection self.classes = None # type: ClassesSection self.tables = None # type: TablesSection self.blocks = None # type: BlocksSection self.entities = None # type: EntitySection self.objects = None # type: ObjectsSection # DXF R2013 and later self.acdsdata = None # type: AcDsDataSection self.stored_sections = [] self.layouts = None # type: Layouts self.groups = None # type: GroupCollection # read only self.materials = None # type: MaterialCollection # read only self.mleader_styles = None # type: MLeaderStyleCollection # read only self.mline_styles = None # type: MLineStyleCollection # read only self._acad_compatible = True # will generated DXF file compatible with AutoCAD self._dimension_renderer = DimensionRenderer( ) # set DIMENSION rendering engine self._acad_incompatibility_reason = set( ) # avoid multiple warnings for same reason # Don't create any new entities here: # New created handles could collide with handles loaded from DXF file. assert len(self.entitydb) == 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] = [] 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