database.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. # Purpose: database module
  2. # Created: 11.03.2011
  3. # Copyright (c) 2011-2018, Manfred Moitzi
  4. # License: MIT License
  5. from typing import Optional, Iterable, Tuple
  6. from ezdxf.tools.handle import HandleGenerator
  7. from ezdxf.lldxf.const import DXFValueError
  8. from ezdxf.lldxf.tags import DXFTag
  9. from ezdxf.lldxf.extendedtags import ExtendedTags
  10. from ezdxf.dxfentity import DXFEntity
  11. class EntityDB:
  12. """ A simple key/value database a.k.a. dict(), but can be replaced by other
  13. classes that implements all of the methods of `EntityDB`. The entities
  14. have no order.
  15. The Data Model
  16. Every entity/object, except tables and sections, are represented as
  17. tag-list (see ExtendedTags Class), this lists are stored in the drawing-associated
  18. database, database-key is the 'handle' tag (code == 5 or 105).
  19. For the entity/object manipulation this tag-list will be wrapped into
  20. separated classes, which are generated by the dxffactory-object.
  21. The dxffactory-object generates DXF-Version specific wrapper classes.
  22. """
  23. def __init__(self):
  24. self._database = {}
  25. self.handles = HandleGenerator()
  26. def __delitem__(self, handle: str) -> None:
  27. del self._database[handle]
  28. def __getitem__(self, handle: str) -> ExtendedTags:
  29. return self._database[handle]
  30. def get(self, handle: str) -> Optional[ExtendedTags]:
  31. try:
  32. return self.__getitem__(handle)
  33. except KeyError: # internal exception
  34. return None
  35. def __setitem__(self, handle: str, tags: ExtendedTags) -> None:
  36. self._database[handle] = tags
  37. def __contains__(self, handle: str) -> bool:
  38. """ Database contains handle? """
  39. return handle in self._database
  40. def __len__(self) -> int:
  41. """ Count of database items. """
  42. return len(self._database)
  43. def __iter__(self) -> Iterable[str]:
  44. """ Iterate over all handles. """
  45. return iter(self._database.keys())
  46. def keys(self) -> Iterable[str]:
  47. """ Iterate over all handles. """
  48. return self._database.keys()
  49. def values(self) -> Iterable[ExtendedTags]:
  50. """ Iterate over all entities. """
  51. return self._database.values()
  52. def items(self) -> Iterable[Tuple[str, ExtendedTags]]:
  53. """ Iterate over all (handle, entities) pairs. """
  54. return self._database.items()
  55. def add_tags(self, tags: ExtendedTags) -> str:
  56. try:
  57. handle = tags.get_handle()
  58. except DXFValueError: # create new handle
  59. handle = self.get_unique_handle()
  60. handle_code = 105 if tags.dxftype() == 'DIMSTYLE' else 5 # legacy shit!!!
  61. tags.noclass.insert(1, DXFTag(handle_code, handle)) # handle should be the 2. tag
  62. self.__setitem__(handle, tags)
  63. return handle
  64. def delete_entity(self, entity: DXFEntity) -> None:
  65. entity.destroy()
  66. self.delete_handle(entity.dxf.handle)
  67. def delete_handle(self, handle: str) -> None:
  68. del self._database[handle]
  69. def get_unique_handle(self)-> str:
  70. while True:
  71. handle = self.handles.next()
  72. if handle not in self._database: # you can not trust $HANDSEED value
  73. return handle
  74. def duplicate_tags(self, tags: ExtendedTags) -> ExtendedTags:
  75. """
  76. Deep copy of tags with new handle and duplicated linked entities (VERTEX, ATTRIB, SEQEND) with also new handles.
  77. An existing owner tag is not changed because this is not the domain of the EntityDB() class.
  78. The new entity tags are added to the drawing database.
  79. This is not a deep copy in the meaning of Python, because handle and link is changed.
  80. """
  81. new_tags = tags.clone()
  82. new_tags.noclass.replace_handle(self.get_unique_handle()) # set new handle
  83. self.add_tags(new_tags) # add new tags to database
  84. source_link = tags.link # follow link structure of original entity
  85. parent_copy = new_tags
  86. while source_link is not None: # duplicate linked entities (VERTEX, ATTRIB, SEQEND)
  87. source_linked_entity = self.get(source_link) # extended tags
  88. linked_entity_copy = source_linked_entity.clone()
  89. new_handle = self.get_unique_handle()
  90. linked_entity_copy.noclass.replace_handle(new_handle) # set new handle
  91. self.add_tags(linked_entity_copy) # add new tags to database
  92. parent_copy.link = new_handle
  93. source_link = source_linked_entity.link # follow link structure of original entity
  94. parent_copy = linked_entity_copy
  95. return new_tags