polyline.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. # Created: 25.03.2011
  2. # Copyright (c) 2011-2018, Manfred Moitzi
  3. # License: MIT License
  4. from typing import TYPE_CHECKING, Optional
  5. from ezdxf.lldxf.types import DXFTag
  6. from ezdxf.lldxf.tags import Tags
  7. from ezdxf.lldxf import loader
  8. from ezdxf.legacy import polyline
  9. from ezdxf.legacy.facemixins import PolyfaceMixin, PolymeshMixin
  10. from .graphics import ExtendedTags, DXFAttr, DefSubclass, DXFAttributes, XType
  11. from .graphics import none_subclass, entity_subclass, ModernGraphicEntityExtension
  12. if TYPE_CHECKING:
  13. from ezdxf.eztypes import Tags
  14. _POLYLINE_TPL = """0
  15. POLYLINE
  16. 5
  17. 0
  18. 330
  19. 0
  20. 100
  21. AcDbEntity
  22. 8
  23. 0
  24. 100
  25. AcDb2dPolyline
  26. 66
  27. 1
  28. 70
  29. 0
  30. 10
  31. 0.0
  32. 20
  33. 0.0
  34. 30
  35. 0.0
  36. """
  37. polyline_subclass = DefSubclass('AcDb2dPolyline', {
  38. 'elevation': DXFAttr(10, xtype=XType.point3d),
  39. 'flags': DXFAttr(70, default=0),
  40. 'default_start_width': DXFAttr(40, default=0.0),
  41. 'default_end_width': DXFAttr(41, default=0.0),
  42. 'm_count': DXFAttr(71, default=0),
  43. 'n_count': DXFAttr(72, default=0),
  44. 'm_smooth_density': DXFAttr(73, default=0),
  45. 'n_smooth_density': DXFAttr(74, default=0),
  46. 'smooth_type': DXFAttr(75, default=0),
  47. 'thickness': DXFAttr(39, default=0.0),
  48. 'extrusion': DXFAttr(210, xtype=XType.point3d, default=(0.0, 0.0, 1.0)),
  49. })
  50. class Polyline(polyline.Polyline, ModernGraphicEntityExtension):
  51. __slots__ = ()
  52. TEMPLATE = ExtendedTags.from_text(_POLYLINE_TPL)
  53. DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, polyline_subclass)
  54. def post_new_hook(self) -> None:
  55. super(Polyline, self).post_new_hook()
  56. self.update_subclass_specifier()
  57. def update_subclass_specifier(self) -> None:
  58. # For dxf attribute access not the name of the subclass is important, but
  59. # the order of the subclasses 1st, 2nd, 3rd and so on.
  60. # The 3rd subclass is the AcDb3dPolyline or AcDb2dPolyline subclass
  61. subclass = self.tags.subclasses[2] # type: Tags
  62. subclass[0] = DXFTag(100, self.get_mode())
  63. def cast(self) -> 'Polyline':
  64. mode = self.get_mode()
  65. if mode == 'AcDbPolyFaceMesh':
  66. return Polyface.convert(self)
  67. elif mode == 'AcDbPolygonMesh':
  68. return Polymesh.convert(self)
  69. else:
  70. return self
  71. class Polyface(Polyline, PolyfaceMixin):
  72. __slots__ = ()
  73. """
  74. PolyFace structure:
  75. POLYLINE
  76. AcDbEntity
  77. AcDbPolyFaceMesh
  78. VERTEX - Vertex
  79. AcDbEntity
  80. AcDbVertex
  81. AcDbPolyFaceMeshVertex
  82. VERTEX - Face
  83. AcDbEntity
  84. AcDbFaceRecord
  85. SEQEND
  86. """
  87. @staticmethod
  88. def convert(polyline: 'Polyline') -> 'Polyface':
  89. return Polyface(polyline.tags, polyline.drawing)
  90. class Polymesh(Polyline, PolymeshMixin):
  91. __slots__ = ()
  92. """
  93. PolyMesh structure:
  94. POLYLINE
  95. AcDbEntity
  96. AcDbPolygonMesh
  97. VERTEX
  98. AcDbEntity
  99. AcDbVertex
  100. AcDbPolygonMeshVertex
  101. """
  102. @staticmethod
  103. def convert(polyline: 'Polyline') -> 'Polymesh':
  104. return Polymesh(polyline.tags, polyline.drawing)
  105. _VERTEX_TPL = """0
  106. VERTEX
  107. 5
  108. 0
  109. 330
  110. 0
  111. 100
  112. AcDbEntity
  113. 8
  114. 0
  115. 100
  116. AcDbVertex
  117. 100
  118. AcDb2dVertex
  119. 10
  120. 0.0
  121. 20
  122. 0.0
  123. 30
  124. 0.0
  125. 70
  126. 0
  127. """
  128. vertex_subclass = (
  129. DefSubclass('AcDbVertex', {}), # subclasses[2]
  130. DefSubclass('AcDb2dVertex', { # subclasses[3]
  131. 'location': DXFAttr(10, xtype=XType.any_point),
  132. 'start_width': DXFAttr(40, default=0.0),
  133. 'end_width': DXFAttr(41, default=0.0),
  134. 'bulge': DXFAttr(42, default=0),
  135. 'flags': DXFAttr(70),
  136. 'tangent': DXFAttr(50),
  137. 'vtx0': DXFAttr(71),
  138. 'vtx1': DXFAttr(72),
  139. 'vtx2': DXFAttr(73),
  140. 'vtx3': DXFAttr(74),
  141. })
  142. )
  143. EMPTY_VERTEX_SUBCLASS = Tags()
  144. class DXFVertex(polyline.DXFVertex, ModernGraphicEntityExtension):
  145. __slots__ = ()
  146. TEMPLATE = ExtendedTags.from_text(_VERTEX_TPL)
  147. DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, *vertex_subclass)
  148. def post_new_hook(self) -> None:
  149. self.update_subclass_specifier()
  150. def update_subclass_specifier(self) -> None:
  151. def set_subclass(subclassname: str) -> None:
  152. subclass = self.tags.subclasses[3]
  153. subclass[0] = DXFTag(100, subclassname)
  154. if self.is_3d_polyline_vertex: # flags & const.VTX_3D_POLYLINE_VERTEX
  155. set_subclass('AcDb3dPolylineVertex')
  156. elif self.is_face_record: # (flags & Vertex.FACE_FLAGS) == const.VTX_3D_POLYFACE_MESH_VERTEX:
  157. set_subclass('AcDbFaceRecord')
  158. self.tags.subclasses[2] = EMPTY_VERTEX_SUBCLASS # clear subclass AcDbVertex
  159. elif self.is_poly_face_mesh_vertex: # flags & Vertex.FACE_FLAGS == Vertex.FACE_FLAGS:
  160. set_subclass('AcDbPolyFaceMeshVertex')
  161. elif self.is_polygon_mesh_vertex: # flags & const.VTX_3D_POLYGON_MESH_VERTEX:
  162. set_subclass('AcDbPolygonMeshVertex')
  163. else:
  164. set_subclass('AcDb2dVertex')
  165. @loader.register('VERTEX', legacy=False)
  166. def vertex_tags_processor(tags: ExtendedTags) -> Optional[ExtendedTags]:
  167. """
  168. If subclass[2] is not 'AcDbVertex', insert empty subclass
  169. """
  170. if not isinstance(tags, ExtendedTags):
  171. return
  172. if tags.subclasses[2][0].value != 'AcDbVertex':
  173. tags.subclasses.insert(2, EMPTY_VERTEX_SUBCLASS)
  174. return tags