objects.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # Purpose: entity section
  2. # Created: 13.03.2011
  3. # Copyright (c) 2011-2018, Manfred Moitzi
  4. # License: MIT License
  5. from typing import TYPE_CHECKING, Iterable, Tuple, cast
  6. import logging
  7. from ezdxf.modern.dxfdict import DXFDictionary
  8. from ezdxf.lldxf.const import DXFStructureError, DXFValueError, RASTER_UNITS, DXFKeyError
  9. from ezdxf.modern.dxfgroups import GroupManager
  10. from ezdxf.modern.material import MaterialManager
  11. from ezdxf.modern.mleader import MLeaderStyleManager
  12. from ezdxf.modern.mline import MLineStyleManager
  13. from ezdxf.modern.tablestyle import TableStyleManager
  14. from ezdxf.entityspace import EntitySpace
  15. from .abstract import AbstractSection
  16. if TYPE_CHECKING:
  17. from ezdxf.eztypes import Drawing, DXFEntity, GeoData
  18. logger = logging.getLogger('ezdxf')
  19. class ObjectsSection(AbstractSection):
  20. name = 'OBJECTS'
  21. def __init__(self, entities, drawing: 'Drawing'):
  22. entity_space = EntitySpace(drawing.entitydb)
  23. super(ObjectsSection, self).__init__(entity_space, entities, drawing)
  24. def __iter__(self) -> Iterable['DXFEntity']:
  25. for handle in self._entity_space:
  26. yield self.dxffactory.wrap_handle(handle)
  27. @property
  28. def roothandle(self) -> str:
  29. return self._entity_space[0]
  30. @property
  31. def rootdict(self) -> DXFDictionary:
  32. if len(self):
  33. return self.dxffactory.wrap_entity(self.entitydb[self.roothandle])
  34. else:
  35. return self.setup_rootdict()
  36. def setup_rootdict(self) -> DXFDictionary:
  37. """
  38. Create a root dictionary. Has to be the first object in the objects section.
  39. """
  40. if len(self):
  41. raise DXFStructureError("Can not create root dictionary in none empty objects section.")
  42. logger.debug('Creating ROOT dictionary.')
  43. # root directory has no owner
  44. return self.add_dictionary(owner='0')
  45. def setup_objects_management_tables(self, rootdict: DXFDictionary) -> None:
  46. def setup_plot_style_name_table():
  47. plot_style_name_dict = self.add_dictionary_with_default(owner=rootdict.dxf.handle)
  48. plot_style_name_dict_handle = plot_style_name_dict.dxf.handle
  49. placeholder = self.add_placeholder(owner=plot_style_name_dict_handle)
  50. placeholder_handle = placeholder.dxf.handle
  51. plot_style_name_dict.dxf.default = placeholder_handle
  52. plot_style_name_dict['Normal'] = placeholder_handle
  53. rootdict['ACAD_PLOTSTYLENAME'] = plot_style_name_dict_handle
  54. for name in _OBJECT_TABLE_NAMES:
  55. if name in rootdict:
  56. continue # just create not existing tables
  57. logger.info('creating {} dictionary'.format(name))
  58. if name == "ACAD_PLOTSTYLENAME":
  59. setup_plot_style_name_table()
  60. else:
  61. rootdict.add_new_dict(name)
  62. def add_dxf_object_with_reactor(self, dxftype: str, dxfattribs: dict) -> 'DXFEntity':
  63. dxfobject = self.create_new_dxf_entity(dxftype, dxfattribs)
  64. dxfobject.set_reactors([dxfattribs['owner']])
  65. return dxfobject
  66. def groups(self):
  67. return GroupManager(self.drawing)
  68. def materials(self):
  69. return MaterialManager(self.drawing)
  70. def mleader_styles(self):
  71. return MLeaderStyleManager(self.drawing)
  72. def mline_styles(self):
  73. return MLineStyleManager(self.drawing)
  74. def table_styles(self):
  75. return TableStyleManager(self.drawing)
  76. def add_dictionary(self, owner: str = '0') -> DXFDictionary:
  77. entity = self.create_new_dxf_entity('DICTIONARY', dxfattribs={'owner': owner})
  78. return cast(DXFDictionary, entity)
  79. def add_dictionary_with_default(self, owner='0', default="0") -> 'DXFDictionary':
  80. entity = self.create_new_dxf_entity('ACDBDICTIONARYWDFLT', dxfattribs={
  81. 'owner': owner,
  82. 'default': default,
  83. })
  84. return cast(DXFDictionary, entity)
  85. def add_xrecord(self, owner: str = '0') -> 'DXFEntity':
  86. return self.create_new_dxf_entity('XRECORD', dxfattribs={'owner': owner})
  87. def add_placeholder(self, owner: str = '0') -> 'DXFEntity':
  88. return self.create_new_dxf_entity('ACDBPLACEHOLDER', dxfattribs={'owner': owner})
  89. def set_raster_variables(self, frame: int = 0, quality: int = 1, units: str = 'm') -> None:
  90. units = RASTER_UNITS.get(units, 0)
  91. try:
  92. raster_vars = self.rootdict.get_entity('ACAD_IMAGE_VARS')
  93. except DXFKeyError:
  94. raster_vars = self.add_dxf_object_with_reactor('RASTERVARIABLES', dxfattribs={
  95. 'owner': self.rootdict.dxf.handle,
  96. 'frame': frame,
  97. 'quality': quality,
  98. 'units': units,
  99. })
  100. self.rootdict['ACAD_IMAGE_VARS'] = raster_vars.dxf.handle
  101. else:
  102. raster_vars.dxf.frame = frame
  103. raster_vars.dxf.quality = quality
  104. raster_vars.dxf.units = units
  105. def set_wipeout_variables(self, frame: int = 0) -> None:
  106. try:
  107. wipeout_vars = self.rootdict.get_entity('ACAD_WIPEOUT_VARS')
  108. except DXFKeyError:
  109. wipeout_vars = self.add_dxf_object_with_reactor('WIPEOUTVARIABLES', dxfattribs={
  110. 'owner': self.rootdict.dxf.handle,
  111. 'frame': int(frame),
  112. })
  113. self.rootdict['ACAD_WIPEOUT_VARS'] = wipeout_vars.dxf.handle
  114. else:
  115. wipeout_vars.dxf.frame = int(frame)
  116. def add_image_def(self, filename: str, size_in_pixel: Tuple[int, int], name=None) -> 'DXFEntity':
  117. # removed auto-generated name
  118. # use absolute image paths for filename and AutoCAD loads images automatically
  119. if name is None:
  120. name = filename
  121. image_dict = self.rootdict.get_required_dict('ACAD_IMAGE_DICT')
  122. image_def = self.add_dxf_object_with_reactor('IMAGEDEF', dxfattribs={
  123. 'owner': image_dict.dxf.handle,
  124. 'filename': filename,
  125. 'image_size': size_in_pixel,
  126. })
  127. image_dict[name] = image_def.dxf.handle
  128. return image_def
  129. def add_image_def_reactor(self, image_handle: str) -> 'DXFEntity':
  130. return self.create_new_dxf_entity('IMAGEDEF_REACTOR', dxfattribs={
  131. 'owner': image_handle,
  132. 'image': image_handle,
  133. })
  134. def add_underlay_def(self, filename: str, format: str = 'pdf', name: str = None) -> 'DXFEntity':
  135. fmt = format.upper()
  136. if fmt in ('PDF', 'DWF', 'DGN'):
  137. underlay_dict_name = 'ACAD_{}DEFINITIONS'.format(fmt)
  138. underlay_def_entity = "{}DEFINITION".format(fmt)
  139. else:
  140. raise DXFValueError("Unsupported file format: '{}'".format(fmt))
  141. if name is None:
  142. if fmt == 'PDF':
  143. name = '1' # Display first page by default
  144. elif fmt == 'DGN':
  145. name = 'default'
  146. else:
  147. name = 'Model' # Display model space for DWF ???
  148. underlay_dict = self.rootdict.get_required_dict(underlay_dict_name)
  149. underlay_def = self.create_new_dxf_entity(underlay_def_entity, dxfattribs={
  150. 'owner': underlay_dict.dxf.handle,
  151. 'filename': filename,
  152. 'name': name,
  153. })
  154. # auto-generated underlay key
  155. key = self.dxffactory.next_underlay_key(lambda k: k not in underlay_dict)
  156. underlay_dict[key] = underlay_def.dxf.handle
  157. return underlay_def
  158. def add_geodata(self, owner: str = '0', dxfattribs: dict = None) -> 'GeoData':
  159. if dxfattribs is None:
  160. dxfattribs = {}
  161. dxfattribs['owner'] = owner
  162. return cast('GeoData', self.add_dxf_object_with_reactor('GEODATA', dxfattribs))
  163. _OBJECT_TABLE_NAMES = [
  164. "ACAD_COLOR",
  165. "ACAD_GROUP",
  166. "ACAD_LAYOUT",
  167. "ACAD_MATERIAL",
  168. "ACAD_MLEADERSTYLE",
  169. "ACAD_MLINESTYLE",
  170. "ACAD_PLOTSETTINGS",
  171. "ACAD_PLOTSTYLENAME",
  172. "ACAD_SCALELIST",
  173. "ACAD_TABLESTYLE",
  174. "ACAD_VISUALSTYLE",
  175. ]