dimension.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # Created: 25.03.2011
  2. # Copyright (c) 2011-2018, Manfred Moitzi
  3. # License: MIT License
  4. from typing import TYPE_CHECKING, Type
  5. from ezdxf.lldxf.const import DXFInternalEzdxfError, DXFValueError
  6. from ezdxf.lldxf.types import get_xcode_for
  7. from ezdxf.tools import take2
  8. import logging
  9. from .graphics import GraphicEntity, ExtendedTags, make_attribs, DXFAttr, XType, DXFAttributes
  10. if TYPE_CHECKING:
  11. from ezdxf.eztypes import DimStyle
  12. logger = logging.getLogger('ezdxf')
  13. _DIMENSION_TPL = """0
  14. DIMENSION
  15. 5
  16. 0
  17. 8
  18. 0
  19. 2
  20. *BLOCKNAME
  21. 3
  22. DIMSTYLE
  23. 10
  24. 0.0
  25. 20
  26. 0.0
  27. 30
  28. 0.0
  29. 11
  30. 0.0
  31. 21
  32. 0.0
  33. 31
  34. 0.0
  35. 70
  36. 0
  37. 1
  38. 13
  39. 0.0
  40. 23
  41. 0.0
  42. 33
  43. 0.0
  44. 14
  45. 0.0
  46. 24
  47. 0.0
  48. 34
  49. 0.0
  50. 40
  51. 1.0
  52. 50
  53. 0.0
  54. """
  55. class Dimension(GraphicEntity):
  56. __slots__ = ()
  57. LINEAR = 0
  58. ALIGNED = 1
  59. ANGULAR = 2
  60. DIAMETER = 3
  61. RADIUS = 4
  62. ANGULAR_3P = 5
  63. ORDINATE = 6
  64. ORDINATE_TYPE = 64
  65. USER_LOCATION_OVERRIDE = 128
  66. TEMPLATE = ExtendedTags.from_text(_DIMENSION_TPL)
  67. DXFATTRIBS = make_attribs({
  68. 'geometry': DXFAttr(2), # name of pseudo-Block containing the current dimension entity geometry
  69. 'dimstyle': DXFAttr(3, default='STANDARD'), # dimension style name
  70. # The dimension style is stored in Drawing.sections.tables.dimstyles,
  71. # shortcut Drawings.dimstyles property
  72. 'defpoint': DXFAttr(10, xtype=XType.any_point), # WCS, definition point for all dimension types
  73. 'text_midpoint': DXFAttr(11, xtype=XType.any_point), # OCS, middle point of dimension text !!! projected onto
  74. # the dimension line, not below or above, -> LINEAR: both defpoint and text_midpoint are located at the dimline
  75. 'insert': DXFAttr(12, xtype=XType.point3d), # OCS, Insertion point for clones of a dimension — Baseline and Continue
  76. 'dimtype': DXFAttr(70, default=0), # Dimension type:
  77. # Values 0–6 are integer values that represent the dimension type.
  78. # Values 64 and 128 are bit values, which are added to the integer values
  79. # 0 = Rotated, horizontal, or vertical;
  80. # 1 = Aligned
  81. # 2 = Angular;
  82. # 3 = Diameter;
  83. # 4 = Radius
  84. # 5 = Angular 3 point;
  85. # 6 = Ordinate
  86. # 64 = Ordinate type. This is a bit value (bit 7) used only with integer
  87. # value 6. If set, ordinate is X-type; if not set, ordinate is Y-type
  88. # 128 = This is a bit value (bit 8) added to the other group 70 values if
  89. # the dimension text has been positioned at a user-defined location
  90. # rather than at the default location
  91. 'text': DXFAttr(1), # dimension text explicitly entered by the user.
  92. # If null or "<>", the dimension measurement is drawn as the text,
  93. # if " " [one blank space], the text is suppressed.
  94. # Anything else is drawn as the text.
  95. 'defpoint2': DXFAttr(13, xtype=XType.any_point), # WCS, definition point for linear and angular dimensions
  96. 'defpoint3': DXFAttr(14, xtype=XType.any_point), # WCS, definition point for linear and angular dimensions
  97. 'defpoint4': DXFAttr(15, xtype=XType.any_point), # WCS, definition point for diameter, radius, and angular dimensions
  98. 'defpoint5': DXFAttr(16, xtype=XType.any_point), # OCS, point defining dimension arc for angular dimensions
  99. 'leader_length': DXFAttr(40), # leader length for radius and diameter dimensions
  100. 'angle': DXFAttr(50), # angle of rotated, horizontal, or vertical linear dimensions
  101. 'horizontal_direction': DXFAttr(51),
  102. # In addition, all dimension types have an optional group
  103. # (code 51) that indicates the horizontal direction for the
  104. # Dimension entity. This determines the orientation of
  105. # dimension text and dimension lines for horizontal,
  106. # vertical, and rotated linear dimensions. The group value
  107. # is the negative of the Entity Coordinate Systems (ECS)
  108. # angle of the UCS X axis in effect when the Dimension was
  109. # drawn. The X axis of the UCS in effect when the Dimension
  110. # was drawn is always parallel to the XY plane for the
  111. # Dimension's ECS, and the angle between the UCS X axis and
  112. # the ECS X axis is a single 2D angle. The value in group 51
  113. # is the angle from horizontal (the effective X axis) to the
  114. # ECS X axis. Entity Coordinate Systems (ECS) are described
  115. # later in this section.
  116. 'oblique_angle': DXFAttr(52),
  117. # Linear dimension types with an oblique angle have an
  118. # optional group (code 52).When added to the rotation angle
  119. # of the linear dimension (group code 50) this gives the
  120. # angle of the extension lines
  121. 'text_rotation': DXFAttr(53),
  122. # The optional group code 53 is the rotation angle of the
  123. # dimension text away from its default orientation (the direction
  124. # of the dimension line).
  125. })
  126. @property
  127. def dim_type(self) -> int:
  128. return self.dxf.dimtype & 7
  129. def dim_style(self) -> 'DimStyle':
  130. if self.drawing is None:
  131. raise DXFInternalEzdxfError('Dimension.drawing attribute not initialized.')
  132. dim_style_name = self.dxf.dimstyle
  133. # raises ValueError if not exists, but all used dim styles should exists!
  134. return self.drawing.dimstyles.get(dim_style_name)
  135. def cast(self) -> 'Dimension': # for modern dimension lines
  136. return self
  137. def dim_style_attributes(self)->'DXFAttributes':
  138. return self.dim_style().DXFATTRIBS
  139. def set_acad_dstyle(self, data: dict) -> None:
  140. tags = []
  141. dim_style_attributes = self.dim_style_attributes()
  142. for key, value in data.items():
  143. if key not in dim_style_attributes: # ignore unknown attributes, but log
  144. logging.debug('ignore unknown DIMSTYLE attribute: "{}"'.format(key))
  145. continue
  146. dxf_attr = dim_style_attributes.get(key)
  147. if dxf_attr and dxf_attr.code > 0: # skip internal and virtual tags
  148. code = dxf_attr.code
  149. tags.append((1070, code))
  150. if code == 5: # DimStyle 'dimblk' has group code 5 but is not a handle
  151. tags.append((1000, value))
  152. else:
  153. tags.append((get_xcode_for(code), value))
  154. if len(tags):
  155. self.set_xdata_list('ACAD', 'DSTYLE', tags)
  156. def get_acad_dstyle(self, dim_style: 'DimStyle') -> dict:
  157. try:
  158. data = self.get_xdata_list('ACAD', 'DSTYLE')
  159. except DXFValueError:
  160. return {}
  161. attribs = {}
  162. codes = dim_style.CODE_TO_DXF_ATTRIB
  163. for code_tag, value_tag in take2(data):
  164. group_code = code_tag.value
  165. value = value_tag.value
  166. if group_code in codes:
  167. attribs[codes[group_code]] = value
  168. return attribs