mline.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. # Created: 08.04.2018
  2. # Copyright (c) 2018, Manfred Moitzi
  3. # License: MIT-License
  4. from typing import TYPE_CHECKING, Iterable, Dict
  5. from ezdxf.lldxf.const import DXFIndexError
  6. from .graphics import ExtendedTags, DXFAttr, DefSubclass, DXFAttributes, XType
  7. from .graphics import none_subclass, entity_subclass, ModernGraphicEntity
  8. from .dxfobjects import DXFObject
  9. from .object_manager import ObjectManager
  10. if TYPE_CHECKING:
  11. from ezdxf.eztypes import Drawing, Tags
  12. # example: processing: D:\source\dxftest\CADKitSamples\Lock-Off.dxf
  13. _MLINE_TPL = """0
  14. MLINE
  15. 5
  16. 0
  17. 330
  18. 0
  19. 100
  20. AcDbEntity
  21. 8
  22. 0
  23. 100
  24. AcDbMline
  25. 2
  26. STANDARD
  27. 340
  28. 0
  29. 40
  30. 1.0
  31. 70
  32. 0
  33. 71
  34. 1
  35. 72
  36. 1
  37. 73
  38. 1
  39. 10
  40. 0.0
  41. 20
  42. 0.0
  43. 30
  44. 0.0
  45. 210
  46. 0.0
  47. 220
  48. 0.0
  49. 230
  50. 1.0
  51. """
  52. mline_subclass = DefSubclass('AcDbMline', {
  53. 'mline_style': DXFAttr(2),
  54. 'mline_style_id': DXFAttr(340),
  55. 'scale_factor': DXFAttr(40, default=1),
  56. 'justification': DXFAttr(70), # 0 = Top; 1 = Zero; 2 = Bottom
  57. 'flags': DXFAttr(71), # Flags (bit-coded values):
  58. # 1 = Has at least one vertex (code 72 is greater than 0)
  59. # 2 = Closed
  60. # 4 = Suppress start caps
  61. # 8 = Suppress end caps
  62. 'n_vertices': DXFAttr(72), # Number of vertices
  63. 'n_style_elements': DXFAttr(73), # Number of elements in MLINESTYLE definition
  64. 'start_point': DXFAttr(10, xtype=XType.point3d), # in WCS!
  65. 'extrusion': DXFAttr(210, xtype=XType.point3d), # but all vertices in WCS!
  66. # 11: vertex coordinates (multiple entries; one entry for each vertex)
  67. # 12: Direction vector of segment starting at this vertex (multiple entries; one for each vertex)
  68. # 13: Direction vector of miter at this vertex (multiple entries: one for each vertex)
  69. # 73: Number of parameters for this element (repeats for each element in segment)
  70. # 41: Element parameters (repeats based on previous code 74)
  71. # 75: Number of area fill parameters for this element (repeats for each element in segment)
  72. # 42: Area fill parameters (repeats based on previous code 75)
  73. })
  74. # The group code 41 parameterization is a list of real values, one real per group code 41. The list may contain zero or
  75. # more items. The first group code 41 value is the distance from the segment vertex along the miter vector to the point
  76. # where the line element's path intersects the miter vector. The next group code 41 value is the distance along the line
  77. # element's path from the point defined by the first group 41 to the actual start of the line element. The next is the
  78. # distance from the start of the line element to the first break (or cut) in the line element. The successive group
  79. # code 41 values continue to list the start and stop points of the line element in this segment of the mline. Linetypes
  80. # do not affect group 41 lists.
  81. #
  82. # The group code 42 parameterization is also a list of real values. Similar to the 41 parameterization, it describes the
  83. # parameterization of the fill area for this mline segment. The values are interpreted identically to the 41 parameters
  84. # and when taken as a whole for all line elements in the mline segment, they define the boundary of the fill area for
  85. # the mline segment.
  86. #
  87. # A common example of the use of the group code 42 mechanism is when an unfilled mline crosses over a filled mline and
  88. # mledit is used to cause the filled mline to appear unfilled in the crossing area. This would result in two group 42s
  89. # for each line element in the affected mline segment; one for the fill stop and one for the fill start.
  90. #
  91. # The 2 group codes in mline entities and mlinestyle objects are redundant fields. These groups should not be modified
  92. # under any circumstances, although it is safe to read them and use their values. The correct fields to modify are as
  93. # follows:
  94. #
  95. # Mline
  96. # The 340 group in the same object, which indicates the proper MLINESTYLE object.
  97. #
  98. # Mlinestyle
  99. # The 3 group value in the MLINESTYLE dictionary, which precedes the 350 group that has the handle or entity name of
  100. # the current mlinestyle.
  101. class MLine(ModernGraphicEntity):
  102. # Requires AC1021/R2007
  103. __slots__ = ()
  104. TEMPLATE = ExtendedTags.from_text(_MLINE_TPL)
  105. DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, mline_subclass)
  106. def get_points(self):
  107. return []
  108. _MLINE_STYLE_TPL = """0
  109. MLINESTYLE
  110. 5
  111. 0
  112. 102
  113. {ACAD_REACTORS
  114. 102
  115. }
  116. 330
  117. 0
  118. 100
  119. AcDbMlineStyle
  120. 2
  121. STANDARD
  122. 70
  123. 0
  124. 3
  125. 62
  126. 256
  127. 51
  128. 90.0
  129. 52
  130. 90.0
  131. 71
  132. 2
  133. 49
  134. 0.5
  135. 62
  136. 256
  137. 6
  138. BYLAYER
  139. 49
  140. -0.5
  141. 62
  142. 256
  143. 6
  144. BYLAYER
  145. """
  146. mline_style_subclass = DefSubclass('AcDbMlineStyle', {
  147. 'name': DXFAttr(2),
  148. 'flags': DXFAttr(70), # Flags (bit-coded):
  149. # 1 =Fill on
  150. # 2 = Display miters
  151. # 16 = Start square end (line) cap
  152. # 32 = Start inner arcs cap
  153. # 64 = Start round (outer arcs) cap
  154. # 256 = End square (line) cap
  155. # 512 = End inner arcs cap
  156. # 1024 = End round (outer arcs) cap
  157. 'description': DXFAttr(3), # Style description (string, 255 characters maximum)
  158. 'fill_color': DXFAttr(62), # Fill color (integer, default = 256)
  159. 'start_angle': DXFAttr(51), # Start angle (real, default is 90 degrees)
  160. 'end_angle': DXFAttr(52), # End angle (real, default is 90 degrees)
  161. 'n_elements': DXFAttr(71), # Number of elements
  162. # 49: Element offset (real, no default). Multiple entries can exist; one entry for each element
  163. # 62: Element color (integer, default = 0). Multiple entries can exist; one entry for each element
  164. # 6: Element linetype (string, default = BYLAYER). Multiple entries can exist; one entry for each element
  165. })
  166. class MLineStyle(DXFObject):
  167. # Requires AC1021/R2007
  168. __slots__ = ()
  169. TEMPLATE = ExtendedTags.from_text(_MLINE_STYLE_TPL)
  170. DXFATTRIBS = DXFAttributes(none_subclass, mline_style_subclass)
  171. @property
  172. def AcDbMLineStyle(self) -> 'Tags':
  173. return self.tags.subclasses[1]
  174. def get_elements(self) -> Iterable[Dict]:
  175. tags = self.AcDbMLineStyle
  176. try:
  177. start = tags.tag_index(71)
  178. except DXFIndexError:
  179. return
  180. else:
  181. collector = None
  182. for code, value in tags[start+1:]:
  183. if code == 49:
  184. if collector is not None:
  185. yield collector
  186. collector = {'offset': value}
  187. elif code == 62:
  188. collector['color'] = value
  189. elif code == 6:
  190. collector['linetype'] = value
  191. if collector is not None:
  192. yield collector
  193. class MLineStyleManager(ObjectManager):
  194. def __init__(self, drawing: 'Drawing'):
  195. super().__init__(drawing, dict_name='ACAD_MLINESTYLE', object_type='MLINESTYLE')
  196. self.create_required_entries()
  197. def create_required_entries(self) -> None:
  198. for name in ('STANDARD', ):
  199. if name not in self.object_dict:
  200. self.new(name)