@design-core/core 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/.eslintrc.json +14 -7
  2. package/.github/workflows/DesignCoreQA.yml +3 -1
  3. package/README.md +11 -4
  4. package/TODO.md +19 -0
  5. package/core/core/core.js +49 -42
  6. package/core/designCore.js +61 -2
  7. package/core/dimensions/alignedDimension.js +142 -0
  8. package/core/dimensions/angularDimension.js +550 -0
  9. package/core/dimensions/baseCircularDimension.js +244 -0
  10. package/core/dimensions/baseDimension.js +558 -0
  11. package/core/dimensions/baseLinearDimension.js +371 -0
  12. package/core/dimensions/diametricDimension.js +82 -0
  13. package/core/dimensions/dimension.js +298 -0
  14. package/core/dimensions/linearDimension.js +29 -0
  15. package/core/dimensions/radialDimension.js +78 -0
  16. package/core/dimensions/rotatedDimension.js +167 -0
  17. package/core/entities/arc.js +314 -60
  18. package/core/entities/arctext.js +642 -0
  19. package/core/entities/basePolyline.js +553 -94
  20. package/core/entities/circle.js +181 -54
  21. package/core/entities/entity.js +154 -74
  22. package/core/entities/hatch.js +807 -0
  23. package/core/entities/insert.js +200 -39
  24. package/core/entities/line.js +196 -134
  25. package/core/entities/lwpolyline.js +21 -44
  26. package/core/entities/point.js +194 -29
  27. package/core/entities/polyline.js +54 -7
  28. package/core/entities/rectangle.js +43 -13
  29. package/core/entities/solid.js +43 -6
  30. package/core/entities/text.js +324 -181
  31. package/core/lib/boundingBox.js +73 -13
  32. package/core/lib/canvas.js +256 -65
  33. package/core/lib/clipboard.js +198 -0
  34. package/core/lib/colour.js +144 -0
  35. package/core/lib/colours.js +367 -301
  36. package/core/lib/commandLine.js +16 -28
  37. package/core/lib/commandManager.js +115 -58
  38. package/core/lib/constants.js +23 -0
  39. package/core/lib/dxf/dxf.js +249 -34
  40. package/core/lib/dxf/dxfFile.js +23 -38
  41. package/core/lib/dxf/dxfIterator.js +17 -5
  42. package/core/lib/dxf/dxfRead.js +23 -7
  43. package/core/lib/dxf/dxfWrite.js +39 -129
  44. package/core/lib/dxf/handleManager.js +97 -0
  45. package/core/lib/dxf/sections/blocks.js +16 -2
  46. package/core/lib/dxf/sections/entities.js +17 -3
  47. package/core/lib/dxf/sections/header.js +10 -1
  48. package/core/lib/dxf/sections/objects.js +36 -0
  49. package/core/lib/dxf/sections/section.js +43 -5
  50. package/core/lib/dxf/sections/tables.js +17 -3
  51. package/core/lib/entityManager.js +178 -0
  52. package/core/lib/fileio.js +14 -4
  53. package/core/lib/headers.js +229 -0
  54. package/core/lib/input.js +46 -0
  55. package/core/lib/inputManager.js +199 -194
  56. package/core/lib/intersect.js +341 -468
  57. package/core/lib/logging.js +25 -1
  58. package/core/lib/matrix.js +6 -8
  59. package/core/lib/mouse.js +24 -79
  60. package/core/lib/patterns.js +690 -0
  61. package/core/lib/promptOptions.js +133 -0
  62. package/core/lib/scene.js +71 -174
  63. package/core/lib/selectionManager.js +74 -48
  64. package/core/lib/selectionWindow.js +24 -10
  65. package/core/lib/settings.js +18 -11
  66. package/core/lib/snapping.js +129 -21
  67. package/core/lib/stateManager.js +288 -0
  68. package/core/lib/strings.js +57 -5
  69. package/core/lib/utils.js +95 -11
  70. package/core/objects/dictionary.js +43 -0
  71. package/core/objects/dictionaryManager.js +80 -0
  72. package/core/properties/dimType.js +117 -0
  73. package/core/properties/flags.js +66 -0
  74. package/core/properties/property.js +26 -0
  75. package/core/properties/propertyManager.js +65 -19
  76. package/core/tables/appId.js +31 -0
  77. package/core/tables/appIdManager.js +44 -0
  78. package/core/tables/block.js +323 -0
  79. package/core/tables/blockManager.js +48 -0
  80. package/core/tables/blockRecord.js +29 -0
  81. package/core/tables/blockRecordManager.js +37 -0
  82. package/core/tables/dimStyle.js +627 -0
  83. package/core/tables/dimStyleManager.js +187 -0
  84. package/core/tables/endblk.js +28 -0
  85. package/core/tables/layer.js +219 -0
  86. package/core/tables/layerManager.js +47 -0
  87. package/core/tables/ltype.js +85 -0
  88. package/core/tables/ltypeManager.js +65 -0
  89. package/core/tables/style.js +145 -0
  90. package/core/tables/styleManager.js +55 -0
  91. package/core/tables/styleManagerBase.js +110 -0
  92. package/core/tables/tableManagerBase.js +354 -0
  93. package/core/tables/ucs.js +28 -0
  94. package/core/tables/ucsManager.js +44 -0
  95. package/core/tables/view.js +28 -0
  96. package/core/tables/viewManager.js +44 -0
  97. package/core/tables/vport.js +70 -0
  98. package/core/tables/vportManager.js +65 -0
  99. package/core/tools/chamfer.js +343 -0
  100. package/core/tools/chamferFilletBase.js +162 -0
  101. package/core/tools/copy.js +68 -40
  102. package/core/tools/copybase.js +65 -0
  103. package/core/tools/copyclip.js +59 -0
  104. package/core/tools/cornerEntity.js +138 -0
  105. package/core/tools/cutclip.js +72 -0
  106. package/core/tools/distance.js +37 -9
  107. package/core/tools/erase.js +43 -13
  108. package/core/tools/explode.js +117 -0
  109. package/core/tools/extend.js +71 -32
  110. package/core/tools/fillet.js +336 -0
  111. package/core/tools/identify.js +33 -6
  112. package/core/tools/matchProp.js +106 -0
  113. package/core/tools/mirror.js +141 -0
  114. package/core/tools/move.js +65 -32
  115. package/core/tools/offset.js +321 -0
  116. package/core/tools/pan.js +54 -0
  117. package/core/tools/pasteclip.js +93 -0
  118. package/core/tools/purge.js +90 -0
  119. package/core/tools/rotate.js +105 -70
  120. package/core/tools/scale.js +166 -0
  121. package/core/tools/tool.js +14 -4
  122. package/core/tools/trim.js +71 -32
  123. package/core/tools/zoom.js +152 -0
  124. package/package.json +3 -305
  125. package/test/dimensions/alignedDimension.test.js +211 -0
  126. package/test/dimensions/angularDimension.test.js +243 -0
  127. package/test/dimensions/baseDimension.test.js +239 -0
  128. package/test/dimensions/diametricDimension.test.js +203 -0
  129. package/test/dimensions/dimension.test.js +102 -0
  130. package/test/dimensions/radialDimension.test.js +203 -0
  131. package/test/dimensions/rotatedDimension.test.js +224 -0
  132. package/test/entities/arc.test.js +463 -41
  133. package/test/entities/arctext.test.js +329 -0
  134. package/test/entities/basePolyline.test.js +459 -10
  135. package/test/entities/circle.test.js +312 -7
  136. package/test/entities/entity.test.js +28 -9
  137. package/test/entities/hatch.test.js +606 -0
  138. package/test/entities/insert.test.js +90 -0
  139. package/test/entities/line.test.js +182 -6
  140. package/test/entities/point.test.js +375 -37
  141. package/test/entities/solid.test.js +156 -0
  142. package/test/entities/text.test.js +533 -7
  143. package/test/integration/exportIntegration.reference.dxf +1706 -0
  144. package/test/integration/exportIntegration.test.js +186 -0
  145. package/test/integration/importExportIntegration.test.js +126 -0
  146. package/test/integration/intersectionIntegration.test.js +880 -0
  147. package/test/integration/userInputIntegration.reference.dxf +1410 -0
  148. package/test/integration/userInputIntegration.test.js +269 -0
  149. package/test/lib/boundingBox.test.js +26 -2
  150. package/test/lib/canvas.test.js +613 -5
  151. package/test/lib/clipboard.test.js +70 -0
  152. package/test/lib/colour.test.js +114 -0
  153. package/test/lib/colours.test.js +63 -18
  154. package/test/lib/commandLine.test.js +159 -22
  155. package/test/lib/commandManager.test.js +4 -4
  156. package/test/lib/constants.test.js +9 -0
  157. package/test/lib/dxf/dxfFile.test.js +6 -2
  158. package/test/lib/dxf/dxfIterator.test.js +1 -1
  159. package/test/lib/dxf/dxfWrite.test.js +173 -0
  160. package/test/lib/dxf/handleManager.test.js +137 -0
  161. package/test/lib/dxf/sections/blocks.test.js +5 -5
  162. package/test/lib/dxf/sections/entities.test.js +4 -4
  163. package/test/lib/dxf/sections/header.test.js +18 -4
  164. package/test/lib/dxf/sections/objects.test.js +132 -0
  165. package/test/lib/dxf/sections/section.test.js +29 -29
  166. package/test/lib/dxf/sections/tables.test.js +3 -3
  167. package/test/lib/entityManager.test.js +163 -0
  168. package/test/lib/headers.test.js +233 -0
  169. package/test/lib/inputManager.test.js +1144 -5
  170. package/test/lib/intersect.test.js +454 -331
  171. package/test/lib/logging.test.js +1 -1
  172. package/test/lib/matrix.test.js +1 -1
  173. package/test/lib/mouse.test.js +327 -4
  174. package/test/lib/patterns.test.js +105 -0
  175. package/test/lib/promptOptions.test.js +179 -0
  176. package/test/lib/scene.test.js +16 -52
  177. package/test/lib/selectionManager.test.js +17 -5
  178. package/test/lib/settings.test.js +111 -5
  179. package/test/lib/snapping.test.js +142 -4
  180. package/test/lib/stateManager.test.js +155 -0
  181. package/test/lib/utils.test.js +81 -1
  182. package/test/objects/dictionary.test.js +81 -0
  183. package/test/objects/dictionaryManager.test.js +34 -0
  184. package/test/properties/dimType.test.js +62 -0
  185. package/test/properties/flags.test.js +164 -0
  186. package/test/properties/property.test.js +13 -0
  187. package/test/properties/propertyManager.test.js +10 -11
  188. package/test/tables/appId.test.js +46 -0
  189. package/test/tables/appIdManager.test.js +72 -0
  190. package/test/tables/block.test.js +157 -0
  191. package/test/tables/blockManager.test.js +52 -0
  192. package/test/tables/blockRecord.test.js +39 -0
  193. package/test/tables/blockRecordManager.test.js +60 -0
  194. package/test/tables/dimstyle.test.js +72 -0
  195. package/test/tables/endblk.test.js +30 -0
  196. package/test/tables/layer.test.js +95 -0
  197. package/test/tables/layerManager.test.js +172 -0
  198. package/test/{styles → tables}/ltype.test.js +7 -7
  199. package/test/{styles → tables}/ltypeManager.test.js +2 -2
  200. package/test/tables/style.test.js +44 -0
  201. package/test/tables/stylemanagerbase.test.js +220 -0
  202. package/test/tables/tableManagerBase.test.js +194 -0
  203. package/test/tables/ucs.test.js +37 -0
  204. package/test/tables/ucsManager.test.js +48 -0
  205. package/test/tables/view.test.js +37 -0
  206. package/test/tables/viewManager.test.js +48 -0
  207. package/test/tables/vport.test.js +117 -0
  208. package/test/tables/vportManager.test.js +54 -0
  209. package/test/test-helpers/test-helpers.js +66 -0
  210. package/test/tools/chamfer.test.js +970 -0
  211. package/test/tools/chamferFilletBase.test.js +446 -0
  212. package/test/tools/copy.test.js +22 -14
  213. package/test/tools/copybase.test.js +93 -0
  214. package/test/tools/copyclip.test.js +92 -0
  215. package/test/tools/cornerEntity.test.js +201 -0
  216. package/test/tools/cutclip.test.js +94 -0
  217. package/test/tools/distance.test.js +140 -18
  218. package/test/tools/erase.test.js +12 -12
  219. package/test/tools/explode.test.js +45 -0
  220. package/test/tools/extend.test.js +326 -44
  221. package/test/tools/fillet.test.js +831 -0
  222. package/test/tools/identify.test.js +115 -16
  223. package/test/tools/matchProp.test.js +84 -0
  224. package/test/tools/mirror.test.js +475 -0
  225. package/test/tools/move.test.js +75 -19
  226. package/test/tools/offset.test.js +748 -0
  227. package/test/tools/pan.test.js +72 -0
  228. package/test/tools/pasteclip.test.js +100 -0
  229. package/test/tools/purge.test.js +89 -0
  230. package/test/tools/rotate.test.js +89 -23
  231. package/test/tools/scale.test.js +529 -0
  232. package/test/tools/trim.test.js +419 -84
  233. package/test/tools/zoom.test.js +504 -0
  234. package/core/entities/alignedDimension.js +0 -279
  235. package/core/entities/angularDimension.js +0 -194
  236. package/core/entities/baseDimension.js +0 -227
  237. package/core/entities/block.js +0 -247
  238. package/core/entities/diametricDimension.js +0 -133
  239. package/core/entities/dimension.js +0 -202
  240. package/core/entities/radialDimension.js +0 -126
  241. package/core/styles/dimStyle.js +0 -719
  242. package/core/styles/dimStyleManager.js +0 -47
  243. package/core/styles/layer.js +0 -133
  244. package/core/styles/layerManager.js +0 -40
  245. package/core/styles/ltype.js +0 -86
  246. package/core/styles/ltypeManager.js +0 -50
  247. package/core/styles/style.js +0 -158
  248. package/core/styles/styleManager.js +0 -43
  249. package/core/styles/styleManagerBase.js +0 -299
  250. package/test/entities/block.test.js +0 -22
  251. package/test/styles/dimstyle.test.js +0 -19
  252. package/test/styles/layerManager.test.js +0 -150
  253. package/test/styles/style.test.js +0 -33
  254. package/test/styles/stylemanagerbase.test.js +0 -219
@@ -0,0 +1,642 @@
1
+ import { Arc } from './arc.js';
2
+ import { Point } from './point.js';
3
+ import { Utils } from '../lib/utils.js';
4
+ import { Strings } from '../lib/strings.js';
5
+ import { Entity } from './entity.js';
6
+ import { Input, PromptOptions } from '../lib/inputManager.js';
7
+ import { Logging } from '../lib/logging.js';
8
+ import { DXFFile } from '../lib/dxf/dxfFile.js';
9
+ import { BoundingBox } from '../lib/boundingBox.js';
10
+ import { Property } from '../properties/property.js';
11
+ import { Text } from './text.js';
12
+
13
+ import { DesignCore } from '../designCore.js';
14
+
15
+ /**
16
+ * Arc Aligned Character Class
17
+ */
18
+ export class ArcAlignedCharacter {
19
+ #character;
20
+ #position;
21
+ #angle;
22
+ #height;
23
+
24
+ /**
25
+ * @param {string} character - text character
26
+ * @param {Point} position - center mid point of character
27
+ * @param {number} angle - in radians
28
+ * @param {number} height - character height
29
+ */
30
+ constructor(character, position, angle, height = 1) {
31
+ this.#character = character;
32
+ this.#position = position;
33
+ this.#angle = angle;
34
+ this.#height = height;
35
+ }
36
+
37
+ /**
38
+ * Get character
39
+ * @return {string}
40
+ */
41
+ get character() {
42
+ return this.#character;
43
+ }
44
+
45
+ /**
46
+ * Get position
47
+ * @return {Point}
48
+ */
49
+ get position() {
50
+ return this.#position;
51
+ }
52
+
53
+ /**
54
+ * Get angle
55
+ * @return {number}
56
+ */
57
+ get angle() {
58
+ return this.#angle;
59
+ }
60
+
61
+ /**
62
+ * Get height
63
+ * @return {number}
64
+ */
65
+ get height() {
66
+ return this.#height;
67
+ }
68
+
69
+ /**
70
+ * Get baseline point
71
+ * @return {Point}
72
+ */
73
+ get baseline() {
74
+ const bb = this.boundingBox;
75
+ const baselinePoint = new Point(this.#position.x - bb.xLength*0.5, this.#position.y - bb.yLength*0.5).rotate(this.#position, this.#angle);
76
+ return baselinePoint;
77
+ }
78
+
79
+ /**
80
+ * Get bounding box
81
+ * @return {BoundingBox}
82
+ */
83
+ get boundingBox() {
84
+ const halfHeight = this.#height / 2;
85
+ const halfWidth = halfHeight * 0.6; // approximate width as half height
86
+ const pt1 = new Point(this.position.x - halfWidth, this.position.y - halfHeight);
87
+ const pt2 = new Point(this.position.x + halfWidth, this.position.y + halfHeight);
88
+ return new BoundingBox(pt1, pt2);
89
+ }
90
+ }
91
+
92
+
93
+ /**
94
+ * Text Entity Class
95
+ * @extends Entity
96
+ */
97
+ export class ArcAlignedText extends Entity {
98
+ /**
99
+ * Create a Text Entity
100
+ * @param {Array} data
101
+ */
102
+ constructor(data) {
103
+ super(data);
104
+
105
+ // hide inherited properties
106
+ // needs to be enumerable=false to not appear in the object props
107
+ Object.defineProperty(this, 'lineType', {
108
+ enumerable: false,
109
+ });
110
+
111
+ Object.defineProperty(this, 'lineWidth', {
112
+ enumerable: false,
113
+ });
114
+
115
+ // DXF Groupcode 1 - Text String
116
+ this.string = (Property.loadValue([data?.string, data?.[1]], ''));
117
+
118
+ // DXF Groupcode 2 - Font name
119
+ // not implemented - enumerable=false to not appear in the object props
120
+ // get font from selected style: this.styleName.font
121
+ Object.defineProperty(this, 'fontName', {
122
+ value: Property.loadValue([data?.fontName, data?.[2]], 'Arial'),
123
+ writable: true,
124
+ });
125
+
126
+ // DXF Groupcode 3
127
+ // not implemented - always empty in acad output
128
+
129
+ // DXF Groupcode 7 - Text style name
130
+ this.styleName = (Property.loadValue([data?.styleName, data?.[7]], 'STANDARD'));
131
+
132
+ // DXF Groupcode 40 - Radius
133
+ this.radius = Property.loadValue([data?.radius, data?.[40]], 10);
134
+
135
+ // DXF Groupcode 41 - Width Factor
136
+ // not implemented - enumerable=false to not appear in the object props
137
+ Object.defineProperty(this, 'widthFactor', {
138
+ value: Property.loadValue([data?.widthFactor, data?.[41]], 1),
139
+ writable: true,
140
+ });
141
+
142
+ // DXF Groupcode 42 - Text Height
143
+ this.height = Property.loadValue([data?.height, data?.[42]], 2.5);
144
+ // DXF Groupcode 43 - Character Spacing
145
+ this.characterSpacing = Property.loadValue([data?.characterSpacing, data?.[43]], 0.095);
146
+ // DXF Groupcode 44 - Offset from Arc
147
+ this.offsetFromArc = Property.loadValue([data?.offsetFromArc, data?.[44]], 0);
148
+ // DXF Groupcode 45 - Offset from right
149
+ this.offsetFromRight = Property.loadValue([data?.offsetFromRight, data?.[45]], 0);
150
+ // DXF Groupcode 46 - Offset from left
151
+ this.offsetFromLeft = Property.loadValue([data?.offsetFromLeft, data?.[46]], 0);
152
+
153
+ // ensure points array has at least one point - the arc center
154
+ if (!this.points.length) {
155
+ this.points = [];
156
+ this.points.push(new Point(0, 0)); // center point
157
+ }
158
+
159
+ // DXF Groupcode 50 - Start Angle in degrees
160
+ const startAngle = Utils.round(Property.loadValue([data?.startAngle, data?.[50]], 0));
161
+ if (this.points[1] === undefined) {
162
+ this.points[1] = this.points[0].project(Utils.degrees2radians(startAngle), this.radius);
163
+ }
164
+
165
+ // DXF Groupcode 51 - End Angle in degrees
166
+ const endAngle = Utils.round(Property.loadValue([data?.endAngle, data?.[51]], 180));
167
+ if (this.points[2] === undefined) {
168
+ this.points[2] = this.points[0].project(Utils.degrees2radians(endAngle), this.radius);
169
+ }
170
+
171
+ // DXF Groupcode 70 - Text Direction 0 = forward, 1 = reversed
172
+ // not implemented - enumerable=false to not appear in the object props
173
+ Object.defineProperty(this, 'textReversed', {
174
+ value: Property.loadValue([data?.textReversed, Boolean(parseInt(data?.[70]))], false),
175
+ writable: true,
176
+ });
177
+
178
+ // DXF Groupcode 71 - 1 = outward, 2 = inward
179
+ this.textOrientation = Property.loadValue([data?.textOrientation, data?.[71]], 1);
180
+ // DXF Groupcode 72 - 1 = fit to arc, 2 = left align, 3 = right align, 4 = center
181
+ this.textAlignment = Property.loadValue([data?.textAlignment, data?.[72]], 4);
182
+ // DXF Groupcode 73 - Arc Side: convex = 1, concave = 2
183
+ this.arcSide = Property.loadValue([data?.arcSide, data?.[73]], 1);
184
+
185
+ // DXF Groupcode 74 - Bold 0 = off, 1 = on
186
+ // not implemented - enumerable=false to not appear in the object props
187
+ Object.defineProperty(this, 'bold', {
188
+ value: Property.loadValue([data?.bold, Boolean(parseInt(data?.[74]))], false),
189
+ writable: true,
190
+ });
191
+
192
+ // DXF Groupcode 75 - Italic 0 = off, 1 = on
193
+ // not implemented - enumerable=false to not appear in the object props
194
+ Object.defineProperty(this, 'italic', {
195
+ value: Property.loadValue([data?.italic, Boolean(parseInt(data?.[75]))], false),
196
+ writable: true,
197
+ });
198
+
199
+ // DXF Groupcode 76 - Underline 0 = off, 1 = on
200
+ // not implemented - enumerable=false to not appear in the object props
201
+ Object.defineProperty(this, 'underline', {
202
+ value: Property.loadValue([data?.underline, Boolean(parseInt(data?.[76]))], false),
203
+ writable: true,
204
+ });
205
+
206
+ // Not Implemented:
207
+ // DXF Groupcode 77 -
208
+ // DXF Groupcode 78 -
209
+ // DXF Groupcode 79 -
210
+ // DXF Groupcode 90 -
211
+ // DXF Groupcode 210 -
212
+ // DXF Groupcode 220 -
213
+ // DXF Groupcode 230 -
214
+ // DXF Groupcode 280 -
215
+ }
216
+
217
+ /**
218
+ * Register the command
219
+ * @return {Object}
220
+ * command = name of the command
221
+ * shortcut = shortcut for the command
222
+ * type = type to group command in toolbars (omitted if not shown)
223
+ */
224
+ static register() {
225
+ const command = { command: 'ArcAlignedText', shortcut: 'ArcText' };
226
+ return command;
227
+ }
228
+
229
+ /**
230
+ * Execute method
231
+ * executes the workflow, requesting input required to create an entity
232
+ */
233
+ async execute() {
234
+ try {
235
+ const op = new PromptOptions(Strings.Input.SELECT, [Input.Type.SINGLESELECTION]);
236
+
237
+ let selectedArc = null;
238
+ while (selectedArc instanceof Arc !== true) {
239
+ // reset selection
240
+ DesignCore.Scene.selectionManager.reset();
241
+
242
+ const selection = await DesignCore.Scene.inputManager.requestInput(op);
243
+ if (selection === undefined) return;
244
+ selectedArc = DesignCore.Scene.entities.get(selection.selectedItemIndex);
245
+
246
+ if (selectedArc instanceof Arc === false) {
247
+ const msg = `${this.type} - ${Strings.Error.INVALIDTYPE}: ${selectedArc.type}`;
248
+ DesignCore.Core.notify(msg);
249
+ }
250
+ }
251
+
252
+ // Get the arc properties
253
+ // direction: - ccw > 0, cw <= 0
254
+ this.radius = selectedArc.radius;
255
+ const startPoint = selectedArc.direction > 0 ? selectedArc.points[1] : selectedArc.points[2];
256
+ const endPoint = selectedArc.direction > 0 ? selectedArc.points[2] : selectedArc.points[1];
257
+
258
+ // set the points
259
+ this.points[0] = new Point(selectedArc.points[0].x, selectedArc.points[0].y);
260
+ this.points[1] = new Point(startPoint.x, startPoint.y);
261
+ this.points[2] = new Point(endPoint.x, endPoint.y);
262
+
263
+ // set the text style to the current style
264
+ const currentStyle = DesignCore.StyleManager.getCstyle();
265
+ this.styleName = currentStyle;
266
+
267
+ // get properties from style
268
+ const style = DesignCore.StyleManager.getItemByName(this.styleName);
269
+ if (style?.textHeight) {
270
+ this.height = style.textHeight;
271
+ }
272
+
273
+ // Get the font size when standard style is used
274
+ if (this.styleName.toUpperCase() === 'STANDARD') {
275
+ const op2 = new PromptOptions(Strings.Input.HEIGHT, [Input.Type.NUMBER], [], this.height);
276
+ const height = await DesignCore.Scene.inputManager.requestInput(op2);
277
+ if (height === undefined) return;
278
+ this.height = height;
279
+ }
280
+
281
+ const op4 = new PromptOptions(Strings.Input.STRING, [Input.Type.STRING, Input.Type.NUMBER]);
282
+ const string = await DesignCore.Scene.inputManager.requestInput(op4);
283
+ if (string === undefined) return;
284
+ this.string = String(string);
285
+
286
+ DesignCore.Scene.inputManager.executeCommand(this);
287
+ } catch (err) {
288
+ Logging.instance.error(`${this.type} - ${err}`);
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Preview the entity during creation
294
+ */
295
+ preview() {
296
+ if (this.points.length >= 1) {
297
+ if (DesignCore.Scene.inputManager.promptOption.types.includes(Input.Type.STRING)) {
298
+ const data = {
299
+ points: this.points,
300
+ height: this.height,
301
+ rotation: this.rotation,
302
+ startAngle: Utils.radians2degrees(this.startAngle()),
303
+ endAngle: Utils.radians2degrees(this.endAngle()),
304
+ radius: this.radius,
305
+ string: DesignCore.CommandLine.command,
306
+ };
307
+
308
+ DesignCore.Scene.tempEntities.create(this.type, data);
309
+ }
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Get start angle in radians
315
+ * @return {number}
316
+ */
317
+ startAngle() {
318
+ return this.points[0].angle(this.points[1]);
319
+ }
320
+
321
+ /**
322
+ * Get end angle in radians
323
+ * @return {number}
324
+ */
325
+ endAngle() {
326
+ return this.points[0].angle(this.points[2]);
327
+ }
328
+
329
+ /**
330
+ * Convert linear length to angular length on arc
331
+ * @param {number} length - linear length
332
+ * @param {number} radius - radius of arc
333
+ * @return {number} angle in radians
334
+ */
335
+ linearToAngular(length, radius) {
336
+ if (radius === 0) {
337
+ return 0;
338
+ }
339
+
340
+ return 2 * Math.atan((length)/Math.abs(radius));
341
+ }
342
+
343
+ /**
344
+ * Get mid angle of arc
345
+ * @param {number} startAngle - in radians
346
+ * @param {number} endAngle - in radians
347
+ * @return {number} mid angle in radians
348
+ */
349
+ arcMidAngle(startAngle, endAngle) {
350
+ let startAng = startAngle % (Math.PI*2);
351
+ let endAng = endAngle % (Math.PI*2);
352
+
353
+ if (startAng < 0) startAng += Math.PI*2;
354
+ if (endAng < 0) endAng += Math.PI*2;
355
+
356
+ let midAngle;
357
+ if (endAng < startAng) {
358
+ midAngle = ((endAng + Math.PI*2) + startAng) / 2;
359
+ if (midAngle >= Math.PI*2) midAngle -= Math.PI*2;
360
+ } else {
361
+ midAngle = (startAng + endAng) / 2;
362
+ }
363
+
364
+ return midAngle;
365
+ }
366
+
367
+ /**
368
+ * Get characters aligned on arc
369
+ * @return {Array} - array of ArcAlignedCharacter
370
+ */
371
+ getArcAlignedCharacters() {
372
+ // character positions on arc
373
+ const arcAlignedCharacters = [];
374
+
375
+ if (this.string.length === 0) {
376
+ return arcAlignedCharacters;
377
+ }
378
+
379
+ // calculate the radial distance - Arc Side: convex = 1, concave = 2
380
+ const radialDistance = this.arcSide === 2 ? this.radius - this.offsetFromArc - this.height * 0.5 : this.radius + this.offsetFromArc + this.height * 0.5;
381
+ // calculate character width
382
+ const charWidth = Text.getApproximateWidth(this.string[0], this.height);
383
+ // calculate total char width including additional spacing
384
+ const totalCharWidth = charWidth + this.characterSpacing;
385
+ // convert the linear width of a character as an angle on the arc
386
+ const charWidthAsAngle = this.linearToAngular(charWidth*0.5, radialDistance);
387
+ // get total charwidth as angle
388
+ let totalCharWidthAsAngle = this.linearToAngular(totalCharWidth*0.5, radialDistance);
389
+
390
+ // calculate start and end offsets
391
+ const startOffsetAngle = this.linearToAngular(this.offsetFromRight, radialDistance) + charWidthAsAngle * 0.5;
392
+ const endOffsetAngle = this.linearToAngular(this.offsetFromLeft, radialDistance) + charWidthAsAngle * 0.5;
393
+
394
+ // total arc angle
395
+ const totalArcAngle = Math.abs(this.endAngle() - this.startAngle()) - startOffsetAngle - endOffsetAngle;
396
+
397
+ // defined positions - Start and end angles +/- half char width
398
+ const startPosition = this.points[0].project(this.startAngle() + startOffsetAngle, radialDistance);
399
+ const endPosition = this.points[0].project(this.endAngle() - endOffsetAngle, radialDistance);
400
+
401
+ // default to the arc end position as the string start
402
+ let stringStartPoint = endPosition;
403
+ // direction: - ccw > 0, cw <= 0
404
+ let direction = 1; // default to ccw
405
+
406
+ let string = this.string.slice(); // make a copy of the string
407
+
408
+ // 1 = fit to arc, 2 = left align, 3 = right align, 4 = center
409
+ if (this.textAlignment === 1) { // fit to arc
410
+ totalCharWidthAsAngle = totalArcAngle / (this.string.length - 1);
411
+ }
412
+ if (this.textAlignment === 2) { // left align
413
+ // default
414
+ }
415
+ if (this.textAlignment === 3) { // right align
416
+ // start at the arc start position and create the text cw around the arc
417
+ stringStartPoint = startPosition;
418
+ direction = -1;
419
+ string = string.split('').reverse().join('');
420
+ }
421
+ if (this.textAlignment === 4) { // center
422
+ const arcMidPoint = this.points[0].project(this.arcMidAngle(this.startAngle(), this.endAngle()), radialDistance);
423
+ stringStartPoint = arcMidPoint.rotate(this.points[0], 0.5 * totalCharWidthAsAngle * (string.length - 1));
424
+ }
425
+
426
+ // calculate the text rotation angle: 1 = outward, 2 = inward
427
+ const textRotationAngle = this.textOrientation === 2 ? -Math.PI*0.5 : Math.PI*0.5;
428
+
429
+ if (this.textOrientation === 2) {
430
+ // direction = -direction;
431
+ string = string.split('').reverse().join('');
432
+ }
433
+
434
+ /*
435
+ if (this.textReversed === 1) {
436
+ // reverse the string
437
+ string = string.split('').reverse().join('');
438
+ // reverse the direction
439
+ direction = -direction;
440
+ }
441
+ */
442
+
443
+ // loop through string and calculate position and angle of each character
444
+ for (let index = 0; index < string.length; index++) {
445
+ const charPosition = stringStartPoint.rotate(this.points[0], -totalCharWidthAsAngle*((index) * direction));
446
+ const charAngle = this.points[0].angle(charPosition) - textRotationAngle;
447
+ const arcChar = new ArcAlignedCharacter(string[index], charPosition, charAngle, this.height);
448
+ arcAlignedCharacters.push(arcChar);
449
+ }
450
+
451
+ return arcAlignedCharacters;
452
+ }
453
+
454
+ /**
455
+ * Draw the entity
456
+ * @param {Object} ctx - context
457
+ * @param {number} scale
458
+ */
459
+ draw(ctx, scale) {
460
+ ctx.save(); // save current context before scale and translate
461
+ ctx.scale(1, -1);
462
+
463
+ const style = DesignCore.StyleManager.getItemByName(this.styleName);
464
+
465
+ // Cairo
466
+ ctx.setFontSize(this.height);
467
+ ctx.selectFontFace(style?.font, null, null); // (FontName, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL);
468
+
469
+ const ArcAlignedCharacters = this.getArcAlignedCharacters();
470
+
471
+ for (const arcAlignedChar of ArcAlignedCharacters) {
472
+ ctx.save(); // save current context
473
+ ctx.translate(arcAlignedChar.baseline.x, -arcAlignedChar.baseline.y);
474
+ ctx.rotate(-arcAlignedChar.angle);
475
+ ctx.showText(String(arcAlignedChar.character));
476
+
477
+ ctx.stroke();
478
+ ctx.restore(); // restore context
479
+
480
+ /*
481
+ // debug draw character bounding box
482
+ const bb = arcAlignedChar.boundingBox;
483
+ const center = arcAlignedChar.position;
484
+
485
+ const posOne = new Point(center.x - bb.xLength*0.5, center.y - bb.yLength*0.5).rotate(arcAlignedChar.position, arcAlignedChar.angle);
486
+ const posTwo = new Point(center.x + bb.xLength*0.5, center.y - bb.yLength*0.5).rotate(arcAlignedChar.position, arcAlignedChar.angle);
487
+ const posThree = new Point(center.x + bb.xLength*0.5, center.y + bb.yLength*0.5).rotate(arcAlignedChar.position, arcAlignedChar.angle);
488
+ const posFour = new Point(center.x - bb.xLength*0.5, center.y + bb.yLength*0.5).rotate(arcAlignedChar.position, arcAlignedChar.angle);
489
+
490
+ ctx.moveTo(posOne.x, -posOne.y);
491
+ ctx.lineTo(posTwo.x, -posTwo.y);
492
+ ctx.lineTo(posThree.x, -posThree.y);
493
+ ctx.lineTo(posFour.x, -posFour.y);
494
+ ctx.lineTo(posOne.x, -posOne.y);
495
+ ctx.stroke();
496
+ */
497
+
498
+ /*
499
+ // debug draw the arcText bounding box
500
+ const bb = this.boundingBox();
501
+ ctx.moveTo(bb.xMin, -bb.yMin);
502
+ ctx.lineTo(bb.xMax, -bb.yMin);
503
+ ctx.lineTo(bb.xMax, -bb.yMax);
504
+ ctx.lineTo(bb.xMin, -bb.yMax);
505
+ ctx.lineTo(bb.xMin, -bb.yMin);
506
+ ctx.stroke();
507
+ */
508
+ }
509
+
510
+ ctx.stroke();
511
+ ctx.restore(); // restore context before scale and translate
512
+ }
513
+
514
+ /**
515
+ * Write the entity to file in the dxf format
516
+ * @param {DXFFile} file
517
+ */
518
+ dxf(file) {
519
+ const style = DesignCore.StyleManager.getItemByName(this.styleName);
520
+
521
+ file.writeGroupCode('0', 'ARCALIGNEDTEXT');
522
+ file.writeGroupCode('5', this.handle, DXFFile.Version.R2000); // Handle
523
+ file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
524
+ file.writeGroupCode('8', this.layer);
525
+ file.writeGroupCode('100', 'AcDbArcAlignedText', DXFFile.Version.R2000);
526
+ file.writeGroupCode('1', this.string);
527
+ file.writeGroupCode('2', style?.font);
528
+ file.writeGroupCode('3', '');
529
+ file.writeGroupCode('7', this.styleName); // Test style name
530
+ file.writeGroupCode('10', this.points[0].x); // x of arc center
531
+ file.writeGroupCode('20', this.points[0].y); // y of arc center
532
+ file.writeGroupCode('30', '0.0'); // z of arc center
533
+ file.writeGroupCode('40', this.radius);
534
+ file.writeGroupCode('41', this.widthFactor);
535
+ file.writeGroupCode('42', this.height);
536
+ file.writeGroupCode('43', this.characterSpacing);
537
+ file.writeGroupCode('44', this.offsetFromArc);
538
+ file.writeGroupCode('45', this.offsetFromRight);
539
+ file.writeGroupCode('46', this.offsetFromLeft);
540
+ file.writeGroupCode('50', Utils.radians2degrees(this.startAngle()));
541
+ file.writeGroupCode('51', Utils.radians2degrees(this.endAngle()));
542
+ file.writeGroupCode('70', this.textReversed ? 1 : 0); // Text direction
543
+ file.writeGroupCode('71', this.textOrientation); // Text orientation
544
+ file.writeGroupCode('72', this.textAlignment); // Text alignment
545
+ file.writeGroupCode('73', this.arcSide); // Arc side
546
+ file.writeGroupCode('74', this.bold ? 1 : 0);
547
+ file.writeGroupCode('75', this.italic ? 1 : 0);
548
+ file.writeGroupCode('76', this.underline ? 1 : 0);
549
+ file.writeGroupCode('77', 0);
550
+ file.writeGroupCode('78', 34);
551
+ file.writeGroupCode('79', 0);
552
+ file.writeGroupCode('90', 256);
553
+ file.writeGroupCode('210', 0); // X extrusion
554
+ file.writeGroupCode('220', 0); // Y extrusion
555
+ file.writeGroupCode('230', 1); // Z extrusion
556
+ file.writeGroupCode('280', 1);
557
+ file.writeGroupCode('330', ''); // Handle of arc object?
558
+ }
559
+
560
+ /**
561
+ * Get snap points
562
+ * @param {Point} mousePoint
563
+ * @param {number} delta
564
+ * @return {Array} - array of snap points
565
+ */
566
+ snaps(mousePoint, delta) {
567
+ const snaps = [];
568
+
569
+ const ArcAlignedCharacters = this.getArcAlignedCharacters();
570
+
571
+ for (const arcAlignedChar of ArcAlignedCharacters) {
572
+ // Don't snap to space characters
573
+ if (arcAlignedChar.character.trim() === '') continue;
574
+ snaps.push(arcAlignedChar.position);
575
+ }
576
+
577
+ snaps.push(this.points[0]); // arc center
578
+
579
+ return snaps;
580
+ }
581
+
582
+ /**
583
+ * Get closest point on entity
584
+ * @param {Point} P
585
+ * @return {Array} - [Point, distance]
586
+ */
587
+ closestPoint(P) {
588
+ let distance = Infinity;
589
+ let minPnt = P;
590
+
591
+ const ArcAlignedCharacters = this.getArcAlignedCharacters();
592
+
593
+ for (const arcAlignedChar of ArcAlignedCharacters) {
594
+ let pntDist = P.distance(arcAlignedChar.position);
595
+
596
+ if (pntDist < arcAlignedChar.height * 0.35) {
597
+ pntDist = 0.1; // this is a hack to make selecting easier
598
+ }
599
+
600
+ if (pntDist < distance) {
601
+ distance = pntDist;
602
+ minPnt = arcAlignedChar.position;
603
+ }
604
+ }
605
+
606
+ return [minPnt, distance];
607
+ }
608
+
609
+ /**
610
+ * Return boundingbox for entity
611
+ * @return {BoundingBox}
612
+ */
613
+ boundingBox() {
614
+ const ArcAlignedCharacters = this.getArcAlignedCharacters();
615
+ const points = [];
616
+
617
+ // get all corner points from each character bounding box
618
+ ArcAlignedCharacters.forEach((char) => {
619
+ const bb = char.boundingBox;
620
+ points.push(new Point(bb.xMin, bb.yMin));
621
+ points.push(new Point(bb.xMax, bb.yMin));
622
+ points.push(new Point(bb.xMin, bb.yMax));
623
+ points.push(new Point(bb.xMax, bb.yMax));
624
+ });
625
+
626
+ // create bounding box from points
627
+ if (points.length > 0) {
628
+ return BoundingBox.fromPoints(points);
629
+ }
630
+
631
+ return new BoundingBox();
632
+ }
633
+
634
+ /**
635
+ * Return a list of points representing a polyline version of this entity
636
+ * @return {Array}
637
+ */
638
+ toPolylinePoints() {
639
+ const characters = this.getArcAlignedCharacters();
640
+ return characters.map((char) => char.position);
641
+ }
642
+ }