def tag_processor(tags: ExtendedTags) -> ExtendedTags: spline_tags = tags.get_subclass('AcDbSpline') control_points = ControlPoints.from_tags(spline_tags) fit_points = FitPoints.from_tags(spline_tags) knots = KnotTags.from_tags(spline_tags) weights = WeightTags.from_tags(spline_tags) spline_tags.remove_tags(codes=REMOVE_CODES) spline_tags.extend((knots, weights, control_points, fit_points)) return tags
def test_xrecord_with_group_code_102(): tags = ExtendedTags(Tags.from_text(XRECORD_WITH_GROUP_CODE_102)) assert tags.dxftype() == 'XRECORD' assert len(tags.appdata) == 1 assert tags.noclass[2] == (102, 0) # 0 == index in appdata list assert tags.appdata[0][0] == (102, '{ACAD_REACTORS') xrecord = tags.get_subclass('AcDbXrecord') assert xrecord[2] == (102, 'ACAD_ROUNDTRIP_PRE2007_TABLESTYLE') assert len(list(tags)) * 2 + 1 == len(XRECORD_WITH_GROUP_CODE_102.split('\n')) # +1 == appending '\n'
def test_group_code_1000_outside_XDATA(): tags = ExtendedTags(Tags.from_text(BLOCKBASEPOINTPARAMETER_CVIL_3D_2018)) assert tags.dxftype() == 'BLOCKBASEPOINTPARAMETER' assert len(tags.subclasses) == 6 block_base_point_parameter = tags.get_subclass('AcDbBlockBasepointParameter') assert len(block_base_point_parameter) == 3 assert block_base_point_parameter[0] == (100, 'AcDbBlockBasepointParameter') assert block_base_point_parameter[1] == (1011, (0., 0., 0.)) assert block_base_point_parameter[2] == (1012, (0., 0., 0.)) block_element = tags.get_subclass('AcDbBlockElement') assert block_element[4] == (1071, 0) stream = StringIO() tagwriter = TagWriter(stream) tagwriter.write_tags(tags) lines = stream.getvalue() stream.close() assert len(lines.split('\n')) == len(BLOCKBASEPOINTPARAMETER_CVIL_3D_2018.split('\n'))
def store_tags(self, tags: ExtendedTags) -> None: # store DXFTYPE, overrides class member # 1. tag of 1. subclass is the structure tag (0, DXFTYPE) self.xtags = tags self.DXFTYPE = self.base_class[0].value try: acdb_entity = tags.get_subclass('AcDbEntity') self.dxf.__dict__['paperspace'] = acdb_entity.get_first_value(67, 0) except const.DXFKeyError: # just fake it self.dxf.__dict__['paperspace'] = 0
def test_xrecord_with_long_closing_tag(): tags = ExtendedTags(Tags.from_text(XRECORD_APP_DATA_LONG_CLOSING_TAG)) assert tags.dxftype() == 'XRECORD' assert len(tags.appdata) == 5 attr_rec = tags.appdata[4] assert attr_rec[0] == (102, '{ATTRRECORD') assert attr_rec[1] == (341, '2FD') assert len(list(tags)) * 2 + 1 == len( XRECORD_APP_DATA_LONG_CLOSING_TAG.split('\n')) # +1 == appending '\n' # test USUAL_102_TAG_INSIDE_APP_DATA attr_rec = tags.appdata[1] assert attr_rec[0] == (102, '{ATTRRECORD') assert attr_rec[1] == (341, '2FA') assert attr_rec[2] == (102, 'USUAL_102_TAG_INSIDE_APP_DATA') # test USUAL_102_TAG_OUTSIDE_APP_DATA xrecord = tags.get_subclass('AcDbXrecord') assert xrecord[4] == (102, 'USUAL_102_TAG_OUTSIDE_APP_DATA')
def tag_processor(tags: ExtendedTags) -> ExtendedTags: subclass = tags.get_subclass('AcDbSubDMesh') handle = tags.get_handle() convert_and_replace_tags(subclass, handle) return tags
class Table: def __init__(self, entities: Iterable[Tags], drawing: 'Drawing'): self._table_header = None self._dxfname = None self._drawing = drawing self._table_entries = [] self._build_table_entries(iter(entities)) # start public interface @staticmethod def key(entity: Union[str, 'DXFEntity']) -> str: if not isinstance(entity, str): entity = entity.dxf.name return entity.lower() # table key is lower case @property def name(self) -> str: return tablename(self._dxfname) def has_entry(self, name: str) -> bool: """ Check if an table-entry 'name' exists. """ key = self.key(name) return any(self.key(entry) == key for entry in self) __contains__ = has_entry def new(self, name: str, dxfattribs: dict = None) -> 'DXFEntity': if self.has_entry(name): raise DXFTableEntryError('%s %s already exists!' % (self._dxfname, name)) dxfattribs = dxfattribs or {} dxfattribs['name'] = name return self.new_entry(dxfattribs) def get(self, name: str) -> 'DXFEntity': """ Get table-entry by name as WrapperClass(). """ key = self.key(name) for entry in iter(self): if self.key(entry) == key: return entry raise DXFTableEntryError(name) def remove(self, name: str) -> None: """ Remove table-entry from table and entitydb by name. """ entry = self.get(name) handle = entry.dxf.handle self.remove_handle(handle) def __len__(self) -> int: return len(self._table_entries) def __iter__(self) -> Iterable['DXFEntity']: for handle in self._table_entries: yield self.get_table_entry_wrapper(handle) # end public interface def _build_table_entries(self, entities: Iterator[Tags]) -> None: table_head = next(entities) if table_head[0].value != 'TABLE': raise DXFStructureError("Critical structure error in TABLES section.") self._dxfname = table_head[1].value self._table_header = ExtendedTags(table_head) # do not store the table head in the entity database for table_entry in entities: self._append_entry_handle(table_entry.get_handle()) @property def entitydb(self) -> 'EntityDB': return self._drawing.entitydb @property def handles(self) -> 'HandleGenerator': return self._drawing.entitydb.handles @property def dxffactory(self) -> 'DXFFactoryType': return self._drawing.dxffactory def _iter_table_entries_as_tags(self) -> Iterable[ExtendedTags]: """ Iterate over table-entries as Tags(). """ return (self.entitydb[handle] for handle in self._table_entries) def new_entry(self, dxfattribs: dict) -> 'DXFEntity': """ Create new table-entry of type 'self._dxfname', and add new entry to table. Does not check if an entry dxfattribs['name'] already exists! Duplicate entries are possible for Viewports. """ handle = self.handles.next() entry = self.dxffactory.new_entity(self._dxfname, handle, dxfattribs) self._add_entry(entry) return entry def duplicate_entry(self, name: str, new_name: str) -> 'DXFEntity': entry = self.get(name) xtags = self.entitydb.duplicate_tags(entry.tags) new_entity = self.dxffactory.wrap_entity(xtags) new_entity.dxf.name = new_name self._add_entry(new_entity) return new_entity def _add_entry(self, entry: Union[ExtendedTags, 'DXFEntity']) -> None: """ Add table-entry to table and entitydb. """ if isinstance(entry, ExtendedTags): tags = entry else: tags = entry.tags handle = self.entitydb.add_tags(tags) self._append_entry_handle(handle) def _append_entry_handle(self, handle: str) -> None: if handle not in self._table_entries: self._table_entries.append(handle) def get_table_entry_wrapper(self, handle: str) -> 'DXFEntity': tags = self.entitydb[handle] return self.dxffactory.wrap_entity(tags) def write(self, tagwriter: 'TagWriter') -> None: """ Write DXF representation to stream, stream opened with mode='wt'. """ def prologue(): self._update_owner_handles() self._update_meta_data() tagwriter.write_tags(self._table_header) def content(): for tags in self._iter_table_entries_as_tags(): tagwriter.write_tags(tags) def epilogue(): tagwriter.write_tag2(0, 'ENDTAB') prologue() content() epilogue() def _update_owner_handles(self) -> None: if self._drawing.dxfversion <= 'AC1009': return # no owner handles owner_handle = self._table_header.get_handle() for entry in iter(self): if not entry.supports_dxf_attrib('owner'): raise DXFAttributeError(repr(entry)) entry.dxf.owner = owner_handle def _update_meta_data(self) -> None: count = len(self) if self._drawing.dxfversion > 'AC1009': subclass = self._table_header.get_subclass('AcDbSymbolTable') else: subclass = self._table_header.noclass subclass.set_first(DXFTag(70, count)) def remove_handle(self, handle: str) -> None: """ Remove table-entry from table and entitydb by handle. """ self._table_entries.remove(handle) del self.entitydb[handle] def audit(self, auditor) -> None: """ Checks for table entries with same key. """ entries = sorted(self._table_entries, key=lambda e: self.key(e)) prev_key = None for entry in entries: key = self.key(entry) if key == prev_key: auditor.add_error( code=Error.DUPLICATE_TABLE_ENTRY_NAME, message="Duplicate table entry name '{1}' in table {0}".format(self.name, entry.dxf.name), dxf_entity=self, data=key, ) prev_key = key