acdsdata.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. # Purpose: acdsdata section manager
  2. # Created: 05.05.2014
  3. # Copyright (c) 2014-2018, Manfred Moitzi
  4. # License: MIT License
  5. """
  6. ACDSDATA entities have NO handles, therefore they can not be stored in the drawing entity database.
  7. every routine written until now (2014-05-05), expects entities with valid handle
  8. section structure (work in progress):
  9. 0 <str> SECTION
  10. 2 <str> ACDSDATA
  11. 70 <int> 2 # flag?
  12. 71 <int> 6 # count of following ACDSSCHEMA entities ??? no, just another flag
  13. 0 <str> ACDSSCHEMA # dxftype: schema definition
  14. 90 <int> 0 # schema number 0, 1, 2, 3 ...
  15. 1 <str> AcDb3DSolid_ASM_Data # schema name
  16. 2 <str> AcDbDs::ID # subsection name
  17. 280 <int> 10 # subsection type 10 = ???
  18. 91 <int> 8 # data ???
  19. 2 <str> ASM_Data # subsection name
  20. 280 <int> 15 # subsection type
  21. 91 <int> 0 # data ???
  22. 101 <str> ACDSRECORD # data
  23. 95 <int> 0
  24. 90 <int> 2
  25. ...
  26. 0 <str> ACDSSCHEMA
  27. 90 <int> 1
  28. 1 <str> AcDb_Thumbnail_Schema
  29. ...
  30. 0 <str> ACDSSCHEMA
  31. 90 <int> 2
  32. 1 <str> AcDbDs::TreatedAsObjectDataSchema
  33. ...
  34. 0 <str> ACDSSCHEMA
  35. 90 <int> 3
  36. 1 <str> AcDbDs::LegacySchema
  37. 2 <str> AcDbDs::Legacy
  38. 280 <int> 1
  39. 91 <int> 0
  40. 0 <str> ACDSSCHEMA
  41. 90 <int> 4
  42. 1 <str> AcDbDs::IndexedPropertySchema
  43. 2 <str> AcDs:Indexable
  44. 280 <int> 1
  45. 91 <int> 0
  46. 0 <str> ACDSSCHEMA
  47. 90 <int> 5
  48. 1 <str> AcDbDs::HandleAttributeSchema
  49. 2 <str> AcDbDs::HandleAttribute
  50. 280 <int> 7
  51. 91 <int> 1
  52. 284 <int> 1
  53. 0 <str> ACDSRECORD # dxftype: data record
  54. 90 <int> 0 # ??? flag
  55. 2 <str> AcDbDs::ID # subsection name
  56. 280 <int> 10 # subsection type 10 = handle to owner entity, 3DSOLID???
  57. 320 <str> 339 # handle
  58. 2 <str> ASM_Data # subsection name
  59. 280 <int> 15 # subsection type 15 = binary data
  60. 94 <int> 1088 # size of data
  61. 310 <binary encoded data> # data
  62. 310 <binary encoded data> # data
  63. ...
  64. 0 <str> ENDSEC
  65. """
  66. from typing import TYPE_CHECKING, Iterator, Iterable, List, Any
  67. from itertools import islice
  68. from ezdxf.lldxf.tags import group_tags, Tags
  69. from ezdxf.lldxf.const import DXFKeyError, DXFStructureError
  70. if TYPE_CHECKING: # import forward declarations
  71. from ezdxf.eztypes import Drawing, TagWriter, EntityDB, DXFFactoryType
  72. class AcDsDataSection:
  73. name = 'ACDSDATA'
  74. def __init__(self, entities: Iterable[Tags], drawing: 'Drawing'):
  75. self.entities = [] # type: List[AcDsData]
  76. self.section_info = [] # type: Tags
  77. self.drawing = drawing
  78. if entities is not None:
  79. self._build(iter(entities))
  80. @property
  81. def dxffactory(self) -> 'DXFFactoryType':
  82. return self.drawing.dxffactory
  83. @property
  84. def entitydb(self) -> 'EntityDB':
  85. return self.drawing.entitydb
  86. def _build(self, entities: Iterator[Tags]) -> None:
  87. section_head = next(entities)
  88. if section_head[0] != (0, 'SECTION') or section_head[1] != (2, 'ACDSDATA'):
  89. raise DXFStructureError("Critical structure error in ACDSDATA section.")
  90. self.section_info = section_head
  91. for entity in entities:
  92. self._append_entity(AcDsData(entity)) # tags have no subclasses
  93. def _append_entity(self, entity: 'AcDsData') -> None:
  94. cls = ACDSDATA_TYPES.get(entity.dxftype())
  95. if cls is not None:
  96. entity = cls(entity.tags)
  97. self.entities.append(entity)
  98. def write(self, tagwriter: 'TagWriter') -> None:
  99. tagwriter.write_str(" 0\nSECTION\n 2\nACDSDATA\n")
  100. tagwriter.write_tags(self.section_info)
  101. for entity in self.entities:
  102. entity.write(tagwriter)
  103. tagwriter.write_tag2(0, 'ENDSEC')
  104. class AcDsData:
  105. def __init__(self, tags: Tags):
  106. self.tags = tags
  107. def write(self, tagwriter: 'TagWriter'):
  108. tagwriter.write_tags(self.tags)
  109. def dxftype(self) -> str:
  110. return self.tags[0].value
  111. class Section(Tags):
  112. @property
  113. def name(self) -> str:
  114. return self[0].value
  115. @property
  116. def type(self) -> str:
  117. return self[1].value
  118. @property
  119. def data(self) -> Tags:
  120. return self[2:]
  121. class AcDsRecord:
  122. def __init__(self, tags: Tags):
  123. self._dxftype = tags[0]
  124. self.flags = tags[1]
  125. self.sections = [Section(tags) for tags in group_tags(islice(tags, 2, None), splitcode=2)]
  126. def dxftype(self) -> str:
  127. return self._dxftype.value
  128. def has_section(self, name: str) -> bool:
  129. return self.get_section(name, default=None) is not None
  130. def get_section(self, name: str, default: Any = DXFKeyError) -> Section:
  131. for section in self.sections:
  132. if section.name == name:
  133. return section
  134. if default is DXFKeyError:
  135. raise DXFKeyError(name)
  136. else:
  137. return default
  138. def __getitem__(self, name: str) -> Section:
  139. return self.get_section(name)
  140. def _write_header(self, tagwriter: 'TagWriter') -> None:
  141. tagwriter.write_tags(Tags([self._dxftype, self.flags]))
  142. def write(self, tagwriter: 'TagWriter') -> None:
  143. self._write_header(tagwriter)
  144. for section in self.sections:
  145. tagwriter.write_tags(section)
  146. ACDSDATA_TYPES = {
  147. 'ACDSRECORD': AcDsRecord,
  148. }