tableentries.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. # Created: 16.03.2011
  2. # Copyright (c) 2011-2018, Manfred Moitzi
  3. # License: MIT License
  4. from typing import TYPE_CHECKING, Sequence, Tuple, Iterable
  5. from ezdxf.dxfentity import DXFEntity
  6. from ezdxf.lldxf.tags import DXFTag
  7. from ezdxf.lldxf import const
  8. from ezdxf.lldxf.extendedtags import ExtendedTags
  9. from ezdxf.lldxf.attributes import DXFAttr, DXFAttributes, DefSubclass, XType
  10. from ezdxf.lldxf.validator import is_valid_layer_name
  11. from ezdxf.lldxf.const import DXFInvalidLayerName, DXFValueError, DXFKeyError, DXFVersionError, DIMJUST, DIMTAD
  12. from ezdxf.render.arrows import ARROWS
  13. from ezdxf.math.ucs import UCS as UserCoordinateSystem
  14. import logging
  15. logger = logging.getLogger('ezdxf')
  16. if TYPE_CHECKING:
  17. from ezdxf.eztypes import DXFFactoryType
  18. _LAYERTEMPLATE = """0
  19. LAYER
  20. 5
  21. 0
  22. 2
  23. LAYERNAME
  24. 70
  25. 0
  26. 62
  27. 7
  28. 6
  29. CONTINUOUS
  30. """
  31. # noinspection PyAugmentAssignment,PyUnresolvedReferences
  32. class Layer(DXFEntity):
  33. __slots__ = ()
  34. TEMPLATE = ExtendedTags.from_text(_LAYERTEMPLATE)
  35. DXFATTRIBS = DXFAttributes(DefSubclass(None, {
  36. 'handle': DXFAttr(5),
  37. 'name': DXFAttr(2),
  38. 'flags': DXFAttr(70),
  39. 'color': DXFAttr(62), # dxf color index, if < 0 layer is off
  40. 'linetype': DXFAttr(6),
  41. }))
  42. FROZEN = 0b00000001
  43. THAW = 0b11111110
  44. LOCK = 0b00000100
  45. UNLOCK = 0b11111011
  46. def post_new_hook(self) -> None:
  47. if not is_valid_layer_name(self.dxf.name):
  48. raise DXFInvalidLayerName("Invalid layer name '{}'".format(self.dxf.name))
  49. def is_frozen(self) -> bool:
  50. return self.dxf.flags & Layer.FROZEN > 0
  51. def freeze(self) -> None:
  52. self.dxf.flags = self.dxf.flags | Layer.FROZEN
  53. def thaw(self) -> None:
  54. self.dxf.flags = self.dxf.flags & Layer.THAW
  55. def is_locked(self) -> bool:
  56. return self.dxf.flags & Layer.LOCK > 0
  57. def lock(self) -> None:
  58. self.dxf.flags = self.dxf.flags | Layer.LOCK
  59. def unlock(self) -> None:
  60. self.dxf.flags = self.dxf.flags & Layer.UNLOCK
  61. def is_off(self) -> bool:
  62. return self.dxf.color < 0
  63. def is_on(self) -> bool:
  64. return not self.is_off()
  65. def on(self) -> None:
  66. self.dxf.color = abs(self.dxf.color)
  67. def off(self) -> None:
  68. self.dxf.color = -abs(self.dxf.color)
  69. def get_color(self) -> int:
  70. return abs(self.dxf.color)
  71. def set_color(self, color: int) -> None:
  72. color = abs(color) if self.is_on() else -abs(color)
  73. self.dxf.color = color
  74. _STYLETEMPLATE = """0
  75. STYLE
  76. 5
  77. 0
  78. 2
  79. STYLENAME
  80. 70
  81. 0
  82. 40
  83. 0.0
  84. 41
  85. 1.0
  86. 50
  87. 0.0
  88. 71
  89. 0
  90. 42
  91. 1.0
  92. 3
  93. OpenSans-Regular.ttf
  94. 4
  95. """
  96. class Style(DXFEntity):
  97. __slots__ = ()
  98. TEMPLATE = ExtendedTags.from_text(_STYLETEMPLATE)
  99. DXFATTRIBS = DXFAttributes(DefSubclass(None, {
  100. 'handle': DXFAttr(5),
  101. 'name': DXFAttr(2),
  102. 'flags': DXFAttr(70),
  103. 'height': DXFAttr(40), # fixed height, 0 if not fixed
  104. 'width': DXFAttr(41), # width factor
  105. 'oblique': DXFAttr(50), # oblique angle in degree, 0 = vertical
  106. 'generation_flags': DXFAttr(71), # 2 = backward, 4 = mirrored in Y
  107. 'last_height': DXFAttr(42), # last height used
  108. 'font': DXFAttr(3), # primary font file name
  109. 'bigfont': DXFAttr(4), # big font name, blank if none
  110. }))
  111. _LTYPETEMPLATE = """0
  112. LTYPE
  113. 5
  114. 0
  115. 2
  116. LTYPENAME
  117. 70
  118. 0
  119. 3
  120. LTYPEDESCRIPTION
  121. 72
  122. 65
  123. """
  124. class Linetype(DXFEntity):
  125. __slots__ = ()
  126. TEMPLATE = ExtendedTags.from_text(_LTYPETEMPLATE)
  127. DXFATTRIBS = DXFAttributes(DefSubclass(None, {
  128. 'handle': DXFAttr(5),
  129. 'name': DXFAttr(2),
  130. 'description': DXFAttr(3),
  131. 'length': DXFAttr(40),
  132. 'items': DXFAttr(73),
  133. }))
  134. @classmethod
  135. def new(cls, handle: str, dxfattribs: dict = None, dxffactory: 'DXFFactoryType' = None) -> DXFEntity:
  136. if dxfattribs is not None:
  137. pattern = dxfattribs.pop('pattern', [0.0])
  138. length = dxfattribs.pop('length', 0.)
  139. else:
  140. pattern = [0.0]
  141. length = 0.
  142. entity = super(Linetype, cls).new(handle, dxfattribs, dxffactory)
  143. entity._setup_pattern(pattern, length)
  144. return entity
  145. def _setup_pattern(self, pattern: Sequence[float], length: float) -> None:
  146. # length parameter is required for complex line types
  147. # pattern: [2.0, 1.25, -0.25, 0.25, -0.25] - 1. element is total pattern length
  148. # pattern elements: >0 line, <0 gap, =0 point
  149. self.tags.noclass.append(DXFTag(73, len(pattern) - 1))
  150. self.tags.noclass.append(DXFTag(40, float(pattern[0])))
  151. self.tags.noclass.extend((DXFTag(49, float(p)) for p in pattern[1:]))
  152. _VPORTTEMPLATE = """0
  153. VPORT
  154. 5
  155. 0
  156. 2
  157. VPORTNAME
  158. 70
  159. 0
  160. 10
  161. 0.0
  162. 20
  163. 0.0
  164. 11
  165. 1.0
  166. 21
  167. 1.0
  168. 12
  169. 70.0
  170. 22
  171. 50.0
  172. 13
  173. 0.0
  174. 23
  175. 0.0
  176. 14
  177. 0.5
  178. 24
  179. 0.5
  180. 15
  181. 0.5
  182. 25
  183. 0.5
  184. 16
  185. 0.0
  186. 26
  187. 0.0
  188. 36
  189. 1.0
  190. 17
  191. 0.0
  192. 27
  193. 0.0
  194. 37
  195. 0.0
  196. 40
  197. 70.
  198. 41
  199. 1.34
  200. 42
  201. 50.0
  202. 43
  203. 0.0
  204. 44
  205. 0.0
  206. 50
  207. 0.0
  208. 51
  209. 0.0
  210. 71
  211. 0
  212. 72
  213. 1000
  214. 73
  215. 1
  216. 74
  217. 3
  218. 75
  219. 0
  220. 76
  221. 0
  222. 77
  223. 0
  224. 78
  225. 0
  226. """
  227. class VPort(DXFEntity):
  228. __slots__ = ()
  229. TEMPLATE = ExtendedTags.from_text(_VPORTTEMPLATE)
  230. DXFATTRIBS = DXFAttributes(DefSubclass(None, {
  231. 'handle': DXFAttr(5),
  232. 'name': DXFAttr(2),
  233. 'flags': DXFAttr(70),
  234. 'lower_left': DXFAttr(10, xtype=XType.point2d),
  235. 'upper_right': DXFAttr(11, xtype=XType.point2d),
  236. 'center_point': DXFAttr(12, xtype=XType.point2d),
  237. 'snap_base': DXFAttr(13, xtype=XType.point2d),
  238. 'snap_spacing': DXFAttr(14, xtype=XType.point2d),
  239. 'grid_spacing': DXFAttr(15, xtype=XType.point2d),
  240. 'direction_point': DXFAttr(16, xtype=XType.point3d),
  241. 'target_point': DXFAttr(17, xtype=XType.point3d),
  242. 'height': DXFAttr(40),
  243. 'aspect_ratio': DXFAttr(41),
  244. 'lens_length': DXFAttr(42),
  245. 'front_clipping': DXFAttr(43),
  246. 'back_clipping': DXFAttr(44),
  247. 'snap_rotation': DXFAttr(50),
  248. 'view_twist': DXFAttr(51),
  249. 'status': DXFAttr(68),
  250. # group code 69: 'id' is never saved in DXF, and DXF R13 and later has no group code 69
  251. 'view_mode': DXFAttr(71),
  252. 'circle_zoom': DXFAttr(72),
  253. 'fast_zoom': DXFAttr(73),
  254. 'ucs_icon': DXFAttr(74),
  255. 'snap_on': DXFAttr(75),
  256. 'grid_on': DXFAttr(76),
  257. 'snap_style': DXFAttr(77),
  258. 'snap_isopair': DXFAttr(78),
  259. }))
  260. _UCSTEMPLATE = """0
  261. UCS
  262. 5
  263. 0
  264. 2
  265. UCSNAME
  266. 70
  267. 0
  268. 10
  269. 0.0
  270. 20
  271. 0.0
  272. 30
  273. 0.0
  274. 11
  275. 1.0
  276. 21
  277. 0.0
  278. 31
  279. 0.0
  280. 12
  281. 0.0
  282. 22
  283. 1.0
  284. 32
  285. 0.0
  286. """
  287. class UCS(DXFEntity):
  288. __slots__ = ()
  289. TEMPLATE = ExtendedTags.from_text(_UCSTEMPLATE)
  290. DXFATTRIBS = DXFAttributes(DefSubclass(None, {
  291. 'handle': DXFAttr(5),
  292. 'name': DXFAttr(2),
  293. 'flags': DXFAttr(70),
  294. 'origin': DXFAttr(10, xtype=XType.point3d),
  295. 'xaxis': DXFAttr(11, xtype=XType.point3d),
  296. 'yaxis': DXFAttr(12, xtype=XType.point3d),
  297. }))
  298. def ucs(self) -> UserCoordinateSystem:
  299. return UserCoordinateSystem(
  300. origin=self.get_dxf_attrib('origin', default=(0, 0, 0)),
  301. ux=self.get_dxf_attrib('xaxis', default=(1, 0, 0)),
  302. uy=self.get_dxf_attrib('yaxis', default=(0, 1, 0)),
  303. )
  304. _APPIDTEMPLATE = """0
  305. APPID
  306. 5
  307. 0
  308. 2
  309. APPNAME
  310. 70
  311. 0
  312. """
  313. class AppID(DXFEntity):
  314. __slots__ = ()
  315. TEMPLATE = ExtendedTags.from_text(_APPIDTEMPLATE)
  316. DXFATTRIBS = DXFAttributes(DefSubclass(None, {
  317. 'handle': DXFAttr(5),
  318. 'name': DXFAttr(2),
  319. 'flags': DXFAttr(70),
  320. }))
  321. _VIEWTEMPLATE = """0
  322. VIEW
  323. 5
  324. 0
  325. 2
  326. VIEWNAME
  327. 70
  328. 0
  329. 10
  330. 0.0
  331. 20
  332. 0.0
  333. 11
  334. 1.0
  335. 21
  336. 1.0
  337. 31
  338. 1.0
  339. 12
  340. 0.0
  341. 22
  342. 0.0
  343. 32
  344. 0.0
  345. 40
  346. 70.
  347. 41
  348. 1.0
  349. 42
  350. 50.0
  351. 43
  352. 0.0
  353. 44
  354. 0.0
  355. 50
  356. 0.0
  357. 71
  358. 0
  359. """
  360. class View(DXFEntity):
  361. __slots__ = ()
  362. TEMPLATE = ExtendedTags.from_text(_VIEWTEMPLATE)
  363. DXFATTRIBS = DXFAttributes(DefSubclass(None, {
  364. 'handle': DXFAttr(5),
  365. 'name': DXFAttr(2),
  366. 'flags': DXFAttr(70),
  367. 'height': DXFAttr(40),
  368. 'width': DXFAttr(41),
  369. 'center_point': DXFAttr(10, xtype=XType.point2d),
  370. 'direction_point': DXFAttr(11, xtype=XType.point3d),
  371. 'target_point': DXFAttr(12, xtype=XType.point3d),
  372. 'lens_length': DXFAttr(42),
  373. 'front_clipping': DXFAttr(43),
  374. 'back_clipping': DXFAttr(44),
  375. 'view_twist': DXFAttr(50),
  376. 'view_mode': DXFAttr(71),
  377. }))
  378. _DIMSTYLETEMPLATE = """0
  379. DIMSTYLE
  380. 105
  381. 0
  382. 2
  383. DIMSTYLENAME
  384. 70
  385. 0
  386. 3
  387. 4
  388. 5
  389. 6
  390. 7
  391. 40
  392. 1.0
  393. 41
  394. 1.0
  395. 42
  396. 0.0
  397. 43
  398. 3.75
  399. 44
  400. 0.0
  401. 45
  402. 0.0
  403. 46
  404. 0.0
  405. 47
  406. 0.0
  407. 48
  408. 0.0
  409. 140
  410. 2.5
  411. 141
  412. 2.5
  413. 142
  414. 0.0
  415. 143
  416. 25.4
  417. 144
  418. 1.0
  419. 145
  420. 0.0
  421. 146
  422. 1.0
  423. 147
  424. 0.625
  425. 71
  426. 0
  427. 72
  428. 0
  429. 73
  430. 1
  431. 74
  432. 1
  433. 75
  434. 0
  435. 76
  436. 0
  437. 77
  438. 0
  439. 78
  440. 0
  441. 170
  442. 0
  443. 171
  444. 2
  445. 172
  446. 0
  447. 173
  448. 0
  449. 174
  450. 0
  451. 175
  452. 0
  453. 176
  454. 0
  455. 177
  456. 0
  457. 178
  458. 0
  459. """
  460. def dim_filter(name: str) -> bool:
  461. return name.startswith('dim')
  462. class DimStyle(DXFEntity):
  463. __slots__ = ()
  464. TEMPLATE = ExtendedTags.from_text(_DIMSTYLETEMPLATE)
  465. DXFATTRIBS = DXFAttributes(DefSubclass(None, {
  466. 'handle': DXFAttr(105),
  467. 'name': DXFAttr(2),
  468. 'flags': DXFAttr(70),
  469. 'dimpost': DXFAttr(3),
  470. 'dimapost': DXFAttr(4),
  471. 'dimblk': DXFAttr(5),
  472. 'dimblk1': DXFAttr(6),
  473. 'dimblk2': DXFAttr(7),
  474. 'dimscale': DXFAttr(40),
  475. 'dimasz': DXFAttr(41),
  476. 'dimexo': DXFAttr(42),
  477. 'dimdli': DXFAttr(43),
  478. 'dimexe': DXFAttr(44),
  479. 'dimrnd': DXFAttr(45),
  480. 'dimdle': DXFAttr(46),
  481. 'dimtp': DXFAttr(47),
  482. 'dimtm': DXFAttr(48),
  483. 'dimtxt': DXFAttr(140),
  484. 'dimcen': DXFAttr(141),
  485. 'dimtsz': DXFAttr(142),
  486. 'dimaltf': DXFAttr(143, default=1.),
  487. 'dimlfac': DXFAttr(144),
  488. 'dimtvp': DXFAttr(145),
  489. 'dimtfac': DXFAttr(146),
  490. 'dimgap': DXFAttr(147),
  491. 'dimtol': DXFAttr(71),
  492. 'dimlim': DXFAttr(72),
  493. 'dimtih': DXFAttr(73),
  494. 'dimtoh': DXFAttr(74),
  495. 'dimse1': DXFAttr(75),
  496. 'dimse2': DXFAttr(76),
  497. 'dimtad': DXFAttr(77), # 0 center, 1 above, 4 below dimline
  498. 'dimzin': DXFAttr(78),
  499. 'dimalt': DXFAttr(170),
  500. 'dimaltd': DXFAttr(171),
  501. 'dimtofl': DXFAttr(172),
  502. 'dimsah': DXFAttr(173),
  503. 'dimtix': DXFAttr(174),
  504. 'dimsoxd': DXFAttr(175),
  505. 'dimclrd': DXFAttr(176),
  506. 'dimclre': DXFAttr(177),
  507. 'dimclrt': DXFAttr(178),
  508. }))
  509. CODE_TO_DXF_ATTRIB = dict(DXFATTRIBS.build_group_code_items(dim_filter))
  510. def dim_attribs(self) -> Iterable[Tuple[str, DXFAttr]]:
  511. return ((name, attrib) for name, attrib in self.DXFATTRIBS.items() if name.startswith('dim'))
  512. def print_dim_attribs(self) -> None:
  513. for name, attrib in self.dim_attribs():
  514. code = attrib.code
  515. value = self.get_dxf_attrib(name, None)
  516. if value is not None:
  517. print("{name} ({code}) = {value}".format(name=name, value=value, code=code))
  518. def copy_to_header(self, dwg):
  519. attribs = self.dxfattribs()
  520. header = dwg.header
  521. header['$DIMSTYLE'] = self.dxf.name
  522. for name, value in attribs.items():
  523. if name.startswith('dim'):
  524. header_var = '$' + name.upper()
  525. try:
  526. header[header_var] = value
  527. except DXFKeyError:
  528. logger.debug('Unsupported header variable: {}.'.format(header_var))
  529. def set_arrows(self, blk: str = '', blk1: str = '', blk2: str = '') -> None:
  530. """
  531. Set arrows by block names or AutoCAD standard arrow names, set dimtsz = 0 which disables tick.
  532. Args:
  533. blk: block/arrow name for both arrows, if dimsah == 0
  534. blk1: block/arrow name for first arrow, if dimsah == 1
  535. blk2: block/arrow name for second arrow, if dimsah == 1
  536. """
  537. self.set_dxf_attrib('dimblk', blk)
  538. self.set_dxf_attrib('dimblk1', blk1)
  539. self.set_dxf_attrib('dimblk2', blk2)
  540. self.set_dxf_attrib('dimtsz', 0) # use blocks
  541. # only existing BLOCK definitions allowed
  542. if self.drawing:
  543. blocks = self.drawing.blocks
  544. for b in (blk, blk1, blk2):
  545. if ARROWS.is_acad_arrow(b): # not real blocks
  546. continue
  547. if b and b not in blocks:
  548. raise DXFValueError('BLOCK "{}" does not exist.'.format(blk))
  549. def set_tick(self, size: float = 1) -> None:
  550. """
  551. Use oblique stroke as tick, disables arrows.
  552. Args:
  553. size: arrow size in daring units
  554. """
  555. self.set_dxf_attrib('dimtsz', size)
  556. def set_text_align(self, halign: str = None, valign: str = None, vshift: float = None) -> None:
  557. """
  558. Set measurement text alignment, `halign` defines the horizontal alignment (requires DXFR2000+),
  559. `valign` defines the vertical alignment, `above1` and `above2` means above extension line 1 or 2 and aligned
  560. with extension line.
  561. Args:
  562. halign: `left`, `right`, `center`, `above1`, `above2`, requires DXF R2000+
  563. valign: `above`, `center`, `below`
  564. vshift: vertical text shift, if `valign` is `center`; >0 shift upward, <0 shift downwards
  565. """
  566. if valign:
  567. valign = valign.lower()
  568. self.set_dxf_attrib('dimtad', DIMTAD[valign])
  569. if valign == 'center' and vshift is not None:
  570. self.set_dxf_attrib('dimtvp', vshift)
  571. try:
  572. if halign:
  573. self.set_dxf_attrib('dimjust', DIMJUST[halign.lower()])
  574. except const.DXFAttributeError:
  575. raise DXFVersionError('DIMJUST require DXF R2000+')
  576. def set_text_format(self, prefix: str = '', postfix: str = '', rnd: float = None, dec: int = None, sep: str = None,
  577. leading_zeros: bool = True, trailing_zeros: bool = True):
  578. """
  579. Set dimension text format, like prefix and postfix string, rounding rule and number of decimal places.
  580. Args:
  581. prefix: Dimension text prefix text as string
  582. postfix: Dimension text postfix text as string
  583. rnd: Rounds all dimensioning distances to the specified value, for instance, if DIMRND is set to 0.25, all
  584. distances round to the nearest 0.25 unit. If you set DIMRND to 1.0, all distances round to the nearest
  585. integer.
  586. dec: Sets the number of decimal places displayed for the primary units of a dimension. requires DXF R2000+
  587. sep: "." or "," as decimal separator requires DXF R2000+
  588. leading_zeros: suppress leading zeros for decimal dimensions if False
  589. trailing_zeros: suppress trailing zeros for decimal dimensions if False
  590. """
  591. if prefix or postfix:
  592. self.dxf.dimpost = prefix + '<>' + postfix
  593. if rnd is not None:
  594. self.dxf.dimrnd = rnd
  595. # works only with decimal dimensions not inch and feet, US user set dimzin directly
  596. if leading_zeros is not None or trailing_zeros is not None:
  597. dimzin = 0
  598. if leading_zeros is False:
  599. dimzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS
  600. if trailing_zeros is False:
  601. dimzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS
  602. self.dxf.dimzin = dimzin
  603. try:
  604. if dec is not None:
  605. self.dxf.dimdec = dec
  606. if sep is not None:
  607. self.dxf.dimdsep = ord(sep)
  608. except const.DXFAttributeError:
  609. raise DXFVersionError('DIMDSEP and DIMDEC require DXF R2000+')
  610. def set_dimline_format(self, color: int = None, linetype: str = None, lineweight: int = None,
  611. extension: float = None, disable1: bool = None, disable2: bool = None):
  612. """
  613. Set dimension line properties
  614. Args:
  615. color: color index
  616. linetype: linetype as string, requires DXF R2007+
  617. lineweight: line weight as int, 13 = 0.13mm, 200 = 2.00mm, requires DXF R2000+
  618. extension: extension length
  619. disable1: True to suppress first part of dimension line, requires DXF R2000+
  620. disable2: True to suppress second part of dimension line, requires DXF R2000+
  621. """
  622. if color is not None:
  623. self.dxf.dimclrd = color
  624. if extension is not None:
  625. self.dxf.dimdle = extension
  626. try:
  627. if lineweight is not None:
  628. self.dxf.dimlwd = lineweight
  629. if disable1 is not None:
  630. self.dxf.dimsd1 = disable1
  631. if disable2 is not None:
  632. self.dxf.dimsd2 = disable2
  633. except const.DXFAttributeError:
  634. raise DXFVersionError('DIMLWD, DIMSD1 and DIMSD2 requires DXF R2000+')
  635. try:
  636. if linetype is not None:
  637. self.dxf.dimltype = linetype
  638. except const.DXFAttributeError:
  639. raise DXFVersionError('DIMLTYPE requires DXF R2007+')
  640. def set_extline_format(self, color: int = None, lineweight: int = None, extension: float = None,
  641. offset: float = None, fixed_length: float = None):
  642. """
  643. Set common extension line attributes.
  644. Args:
  645. color: color index
  646. lineweight: line weight as int, 13 = 0.13mm, 200 = 2.00mm
  647. extension: extension length above dimension line
  648. offset: offset from measurement point
  649. fixed_length: set fixed length extension line, length below the dimension line
  650. """
  651. if color is not None:
  652. self.dxf.dimclre = color
  653. if extension is not None:
  654. self.dxf.dimexe = extension
  655. if offset is not None:
  656. self.dxf.dimexo = offset
  657. try:
  658. if lineweight is not None:
  659. self.dxf.dimlwe = lineweight
  660. except const.DXFAttributeError:
  661. raise DXFVersionError('DIMLWE requires DXF R2000+')
  662. try:
  663. if fixed_length is not None:
  664. self.dxf.dimfxlon = 1
  665. self.dxf.dimfxl = fixed_length
  666. except const.DXFAttributeError:
  667. raise DXFVersionError('DIMFXL requires DXF R2007+')
  668. def set_extline1(self, linetype: str = None, disable=False):
  669. """
  670. Set extension line 1 attributes.
  671. Args:
  672. linetype: linetype for extension line 1, requires DXF R2007+
  673. disable: disable extension line 1 if True
  674. """
  675. if disable:
  676. self.dxf.dimse1 = 1
  677. try:
  678. if linetype is not None:
  679. self.dxf.dimltex1 = linetype
  680. except const.DXFAttributeError:
  681. raise DXFVersionError('DIMLTEX1 requires DXF R2007+')
  682. def set_extline2(self, linetype: str = None, disable=False):
  683. """
  684. Set extension line 2 attributes.
  685. Args:
  686. linetype: linetype for extension line 2, requires DXF R2007+
  687. disable: disable extension line 2 if True
  688. """
  689. if disable:
  690. self.dxf.dimse2 = 1
  691. try:
  692. if linetype is not None:
  693. self.dxf.dimltex2 = linetype
  694. except const.DXFAttributeError:
  695. raise DXFVersionError('DIMLTEX2 requires DXF R2007+')
  696. def set_tolerance(self, upper: float, lower: float = None, hfactor: float = 1.0,
  697. align: str = None, dec: int = None, leading_zeros: bool = None,
  698. trailing_zeros: bool = None) -> None:
  699. """
  700. Set tolerance text format, upper and lower value, text height factor, number of decimal places or leading and
  701. trailing zero suppression.
  702. Args:
  703. upper: upper tolerance value
  704. lower: lower tolerance value, if None same as upper
  705. hfactor: tolerance text height factor in relation to the dimension text height
  706. align: tolerance text alignment "TOP", "MIDDLE", "BOTTOM", required DXF R2000+
  707. dec: Sets the number of decimal places displayed, required DXF R2000+
  708. leading_zeros: suppress leading zeros for decimal dimensions if False, required DXF R2000+
  709. trailing_zeros: suppress trailing zeros for decimal dimensions if False, required DXF R2000+
  710. """
  711. # exclusive tolerances
  712. self.dxf.dimtol = 1
  713. self.dxf.dimlim = 0
  714. self.dxf.dimtp = float(upper)
  715. if lower is not None:
  716. self.dxf.dimtm = float(lower)
  717. else:
  718. self.dxf.dimtm = float(upper)
  719. if hfactor is not None:
  720. self.dxf.dimtfac = float(hfactor)
  721. if self.dxfversion > 'AC1009':
  722. # works only with decimal dimensions not inch and feet, US user set dimzin directly
  723. if leading_zeros is not None or trailing_zeros is not None:
  724. dimtzin = 0
  725. if leading_zeros is False:
  726. dimtzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS
  727. if trailing_zeros is False:
  728. dimtzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS
  729. self.dxf.dimtzin = dimtzin
  730. if align is not None:
  731. self.dxf.dimtolj = const.MTEXT_INLINE_ALIGN[align.upper()]
  732. if dec is not None:
  733. self.dxf.dimtdec = int(dec)
  734. def set_limits(self, upper: float, lower: float, hfactor: float = 1.0,
  735. dec: int = None, leading_zeros: bool = None, trailing_zeros: bool = None) -> None:
  736. """
  737. Set limits text format, upper and lower limit values, text height factor, number of decimal places or
  738. leading and trailing zero suppression.
  739. Args:
  740. upper: upper limit value added to measurement value
  741. lower: lower lower value subtracted from measurement value
  742. hfactor: limit text height factor in relation to the dimension text height
  743. dec: Sets the number of decimal places displayed, required DXF R2000+
  744. leading_zeros: suppress leading zeros for decimal dimensions if False, required DXF R2000+
  745. trailing_zeros: suppress trailing zeros for decimal dimensions if False, required DXF R2000+
  746. """
  747. # exclusive limits
  748. self.dxf.dimlim = 1
  749. self.dxf.dimtol = 0
  750. self.dxf.dimtp = float(upper)
  751. self.dxf.dimtm = float(lower)
  752. self.dxf.dimtfac = float(hfactor)
  753. if self.dxfversion > 'AC1009':
  754. # works only with decimal dimensions not inch and feet, US user set dimzin directly
  755. if leading_zeros is not None or trailing_zeros is not None:
  756. dimtzin = 0
  757. if leading_zeros is False:
  758. dimtzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS
  759. if trailing_zeros is False:
  760. dimtzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS
  761. self.dxf.dimtzin = dimtzin
  762. self.dxf.dimtolj = 0 # set bottom as default
  763. if dec is not None:
  764. self.dxf.dimtdec = int(dec)