def diff_tags(a: Tags, b: Tags, ndigits: int = None) -> Iterator[Operation]: if ndigits is not None: a = Tags(round_tags(a, ndigits)) b = Tags(round_tags(b, ndigits)) sequencer = SequenceMatcher(a=a, b=b) return convert_opcodes(sequencer.get_opcodes())
def append_table(name: str): if name not in content: return head = heads.get(name) if head: tables.append(head) else: # The new table head gets a valid handle from Auditor. tables.append(Tags([DXFTag(0, 'TABLE'), DXFTag(2, name)])) tables.extend(content[name]) tables.append(Tags([DXFTag(0, 'ENDTAB')]))
def from_tags(cls, tags: Tags) -> Tuple['LWPolylinePoints', Tags]: """ Setup point array from tags. """ def get_vertex() -> LWPointType: point.append(attribs.get(cls.START_WIDTH_CODE, 0)) point.append(attribs.get(cls.END_WIDTH_CODE, 0)) point.append(attribs.get(cls.BULGE_CODE, 0)) return tuple(point) unprocessed_tags = Tags() data = [] point = None attribs = {} for tag in tags: if tag.code in LWPOINTCODES: if tag.code == 10: if point is not None: data.extend(get_vertex()) # just use x- and y-axis point = list(tag.value[0:2]) attribs = {} else: attribs[tag.code] = tag.value else: unprocessed_tags.append(tag) if point is not None: data.extend(get_vertex()) return cls(data=data), unprocessed_tags
def acad_mtext_defined_height_xdata(self) -> Tags: return Tags([ DXFTag(1000, "ACAD_MTEXT_DEFINED_HEIGHT_BEGIN"), DXFTag(1070, 46), DXFTag(1040, self.defined_height), DXFTag(1000, "ACAD_MTEXT_DEFINED_HEIGHT_END"), ])
def export_r12_dxf(self, tagwriter: 'TagWriter'): tags49 = Tags(tag for tag in self.tags if tag.code == 49) tagwriter.write_tag2(72, 65) tagwriter.write_tag2(73, len(tags49)) tagwriter.write_tag(self.tags.get_first_tag(40)) if len(tags49): tagwriter.write_tags(tags49)
def export_entity(self, tagwriter: 'TagWriter') -> None: # base class export is done by parent class super().export_entity(tagwriter) # AcDbEntity export is done by parent class tagwriter.write_tag2(SUBCLASS_MARKER, acdb_xrecord.name) tagwriter.write_tag2(280, self.dxf.cloning) tagwriter.write_tags(Tags(totags(self.tags)))
def load_dxf_attribs(self, processor: SubclassProcessor = None ) -> 'DXFNamespace': dxf = super().load_dxf_attribs(processor) if processor: try: tags = processor.subclasses[1] except IndexError: raise DXFStructureError( 'Missing subclass AcDbXrecord in XRecord (#{})'.format( dxf.handle)) start_index = 1 if len(tags) > 1: # first tag is group code 280, but not for DXF R13/R14 # for testing doc may be None, but then doc also can not be R13/R14 - ezdxf does not create R13/R14 if self.doc is None or self.doc.dxfversion >= DXF2000: code, value = tags[1] if code == 280: dxf.cloning = value start_index = 2 else: # just log recoverable error logger.info( 'XRecord (#{}): expected group code 280 as first tag in AcDbXrecord' .format(dxf.handle)) self.tags = Tags(tags[start_index:]) return dxf
def _set_path_tags(self, vertices): boundary = [DXFVertex(14, value) for value in vertices] subclasstags = Tags(tag for tag in self.tags.subclasses[2] if tag.code != 14) subclasstags.extend(boundary) self.tags.subclasses[2] = subclasstags self.dxf.count_boundary_points = len(vertices)
def rebuild_tables(self, tables: List[Tags]) -> List[Tags]: """ Rebuild TABLES section. """ def append_table(name: str): if name not in content: return head = heads.get(name) if head: tables.append(head) else: # The new table head gets a valid handle from Auditor. tables.append(Tags([DXFTag(0, 'TABLE'), DXFTag(2, name)])) tables.extend(content[name]) tables.append(Tags([DXFTag(0, 'ENDTAB')])) heads = dict() content = defaultdict(list) valid_tables = set(const.TABLE_NAMES_ACAD_ORDER) for entry in tables: name = entry[0].value.upper() if name == 'TABLE': try: table_name = entry[1].value.upper() except (IndexError, AttributeError): pass else: heads[table_name] = entry elif name in valid_tables: content[name].append(entry) tables = [Tags([DXFTag(0, 'SECTION'), DXFTag(2, 'TABLES')])] for name in const.TABLE_NAMES_ACAD_ORDER: append_table(name) return tables
def _add(self, tags: Tags) -> None: tags = Tags(tags) if len(tags): appid = tags[0].value if appid in self.data: logger.info(f'Duplicate XDATA appid {appid} in one entity') self.data[appid] = tags
def load_dxfattribs_into_namespace(self, dxf: DXFNamespace, subclass_definition: DefSubclass, index: int = None) -> Tags: """ Load all existing DXF attribute into DXFNamespace and return unprocessed tags, without leading subclass marker (102, ...). Args: dxf: target namespace subclass_definition: DXF attribute definitions (name=subclass_name, attribs={key=attribute name, value=DXFAttr}) index: locate subclass by location Returns: Tags: unprocessed tags """ # r12 has always unprocessed tags, because there are all tags in one subclass and one subclass definition never # covers all tags e.g. handle is processed in main_call, so it is an unprocessed tag in AcDbEntity. if self.r12: tags = self.subclasses[0] else: if index is None: tags = self.find_subclass(subclass_definition.name) else: tags = self.subclass_by_index(index) if tags is None: return Tags() return self.load_tags_into_namespace(dxf, tags[1:], subclass_definition)
def test_recover_acdb_entity_tags_ignores_unknown_tags(): entity = DXFGraphic() tags = Tags([DXFTag(62, 1), DXFTag(8, "Layer"), DXFTag(99, "Unknown")]) unprocessed_tags = recover_graphic_attributes(tags, entity.dxf) assert len(unprocessed_tags) == 1 assert unprocessed_tags[0] == (99, "Unknown")
def test_recover_acdb_entity_tags(): entity = DXFGraphic() tags = Tags([DXFTag(62, 1), DXFTag(8, "Layer"), DXFTag(6, "Linetype")]) recover_graphic_attributes(tags, entity.dxf) assert entity.dxf.color == 1 assert entity.dxf.layer == "Layer" assert entity.dxf.linetype == "Linetype"
def add(self, appid: str, data: Iterable[Sequence]) -> None: data = Tags(dxftag(code, value) for code, value in data) appid = uniform_appid(appid) if data[0] != (APP_DATA_MARKER, appid): data.insert(0, dxftag(APP_DATA_MARKER, appid)) if data[-1] != (APP_DATA_MARKER, '}'): data.append(dxftag(APP_DATA_MARKER, '}')) self.set(data)
def check_entities(self, entities: List[Tags]) -> Iterable[Tags]: for entity in entities: _, dxftype = entity[0] if dxftype in EXCLUDE_STRUCTURE_CHECK: yield entity else: # raises DXFStructureError() for invalid entities yield Tags(entity_structure_validator(entity))
def export_acis_data(self, tagwriter: 'TagWriter') -> None: """ Export ACIS data as DXF tags. (internal API)""" def cleanup(lines): for line in lines: yield line.rstrip().replace('\n', '') tags = Tags(textlines2tags(crypt.encode(cleanup(self.acis_data)))) tagwriter.write_tags(tags)
def load_frozen_layer_handles(self, tags: Tags) -> Tags: unprocessed_tags = Tags() for tag in tags: if tag.code == FROZEN_LAYER_GROUP_CODE: self._frozen_layers.append(tag.value) else: unprocessed_tags.append(tag) return unprocessed_tags
def index(self): data = { "ENTITIES": [ Tags([DXFTag(0, "ENTITY1"), DXFTag(5, "F001")]), Tags([DXFTag(0, "ENTITY2"), DXFTag(5, "F002")]), Tags([DXFTag(0, "ENTITY3"), DXFTag(5, "F003")]), Tags([DXFTag(0, "ENTITY4"), DXFTag(5, "F004")]), # last entity without handle, has dummy handle "*1" Tags([DXFTag(0, "ENTITY5"), DXFTag(1, "DATA")]), ] } return EntityIndex(data)
def load_dxf_attribs(self, processor: SubclassProcessor = None) -> 'DXFNamespace': dxf = super().load_dxf_attribs(processor) if processor: tags = processor.load_dxfattribs_into_namespace(dxf, acdb_leader) tags = Tags(self.load_vertices(tags)) if len(tags): # 76: Number of vertices in leader (ignored for OPEN) processor.log_unprocessed_tags(tags.filter((76,)), subclass=acdb_leader.name) return dxf
def acad_mtext_columns_xdata(self) -> Tags: tags = Tags([ DXFTag(1000, "ACAD_MTEXT_COLUMNS_BEGIN"), DXFTag(1070, 47), DXFTag(1070, self.count), # incl. main MTEXT ]) tags.extend( # writes only (count - 1) handles! DXFTag(1005, handle) for handle in self.mtext_handles()) tags.append(DXFTag(1000, "ACAD_MTEXT_COLUMNS_END")) return tags
def transform(self, m: Matrix44) -> None: """Transform XDATA tags with group codes 1011, 1012, 1013, 1041 and 1042 inplace. For more information see :ref:`xdata_internals` Internals. """ transformed_data = OrderedDict() for key, tags in self.data.items(): transformed_data[key] = Tags(transform_xdata_tags(tags, m)) self.data = transformed_data
def test_if_fast_load_handles_callback_group_codes(cls, subclass): data = Tags([ DXFTag(0, "ENTITY"), # First subclass tag should be ignored DXFTag(3, "X"), # callback value DXFTag(3, "Y"), # none callback value ]) ns, unprocessed_tags = load_tags_fast(cls, subclass, data) assert ns.none_callback == "Y" assert ns.hasattr("callback") is False
def export_entity(self, tagwriter: 'TagWriter') -> None: """ Export entity specific data as DXF tags. """ super().export_entity(tagwriter) tagwriter.write_tag2(SUBCLASS_MARKER, acdb_lwpolyline.name) self.dxf.export_dxf_attribs( tagwriter, ['count', 'flags', 'const_width', 'elevation', 'thickness']) tagwriter.write_tags(Tags(self.lwpoints.dxftags())) self.dxf.export_dxf_attribs(tagwriter, 'extrusion')
def export_entity(self, tagwriter: "TagWriter") -> None: """Export entity specific data as DXF tags.""" super().export_entity(tagwriter) tagwriter.write_tag2(SUBCLASS_MARKER, acdb_lwpolyline.name) self.dxf.export_dxf_attribs( tagwriter, ["count", "flags", "const_width", "elevation", "thickness"], ) tagwriter.write_tags(Tags(self.lwpoints.dxftags())) self.dxf.export_dxf_attribs(tagwriter, "extrusion")
def tags(self): return Tags( tuples_to_tags([ (1001, "EZDXF"), (1010, (10, 20, 30)), (1011, (11, 21, 31)), (1012, (12, 22, 32)), (1013, (13, 23, 33)), (1041, 2), (1042, 2), ]))
def entity_tags(entities: Iterable[Tags], handle: str) -> Optional[Tags]: def get_handle(tags: Tags): try: return tags.get_handle() except ValueError: return "0" for e in entities: if get_handle(e) == handle: return Tags(tag_compiler(iter(e))) return None
def load_dxf_attribs(self, processor: SubclassProcessor = None ) -> 'DXFNamespace': dxf = super().load_dxf_attribs(processor) if processor: tags = Tags(self.load_mtext(processor.subclass_by_index(2))) processor.fast_load_dxfattribs(dxf, acdb_mtext_group_codes, subclass=tags, recover=True) return dxf
def _add(self, tags: Tags) -> None: tags = Tags(tags) if len(tags): appid = tags[0].value if appid in self.data: logger.info(f"Duplicate XDATA appid {appid} in one entity") if has_valid_xdata_group_codes(tags): self.data[appid] = tags else: raise DXFValueError( f"found invalid XDATA group code in {tags}")
def test_recover_acdb_entity_tags_does_not_replace_existing_attribs(): entity = DXFGraphic() entity.dxf.color = 7 entity.dxf.layer = "HasLayer" entity.dxf.linetype = "HasLinetype" tags = Tags([DXFTag(62, 1), DXFTag(8, "Layer"), DXFTag(6, "Linetype")]) recover_graphic_attributes(tags, entity.dxf) assert entity.dxf.color == 7 assert entity.dxf.layer == "HasLayer" assert entity.dxf.linetype == "HasLinetype"
def recover_graphic_attributes(tags: Tags, dxf: DXFNamespace) -> Tags: unprocessed_tags = Tags() for tag in tags: attrib_name = GRAPHIC_ATTRIBUTES_TO_RECOVER.get(tag.code) # Don't know if the unprocessed tag is really a misplaced tag, # so check if the attribute already exist! if attrib_name and not dxf.hasattr(attrib_name): dxf.set(attrib_name, tag.value) else: unprocessed_tags.append(tag) return unprocessed_tags