@design-core/core 0.0.2 → 0.0.4

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 +5 -4
  4. package/TODO.md +19 -0
  5. package/core/core/core.js +52 -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 -5
  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,152 @@
1
+ import { Tool } from './tool.js';
2
+ import { Input, PromptOptions } from '../lib/inputManager.js';
3
+ import { Strings } from '../lib/strings.js';
4
+ import { Logging } from '../lib/logging.js';
5
+ import { Point } from '../entities/point.js';
6
+
7
+ import { DesignCore } from '../designCore.js';
8
+
9
+ /**
10
+ * Zoom Command Class
11
+ * Provides: All, Extents, Window
12
+ * @extends Tool
13
+ */
14
+ export class Zoom extends Tool {
15
+ /** Create a Zoom command */
16
+ constructor() {
17
+ super();
18
+ this.modes = {
19
+ ALL: 'All',
20
+ EXTENTS: 'Extents',
21
+ WINDOW: 'Window',
22
+ OBJECT: 'Object',
23
+ };
24
+ this.mode = this.modes.WINDOW; // default to window mode
25
+ }
26
+
27
+ /**
28
+ * Register the command
29
+ * @return {Object}
30
+ */
31
+ static register() {
32
+ const command = { command: 'Zoom', shortcut: 'Z' };
33
+ return command;
34
+ }
35
+
36
+ /**
37
+ * Execute method
38
+ */
39
+ async execute() {
40
+ try {
41
+ const op = new PromptOptions(Strings.Input.POINT, [Input.Type.POINT], [this.modes.ALL, this.modes.EXTENTS, this.modes.WINDOW, this.modes.OBJECT]);
42
+ const input = await DesignCore.Scene.inputManager.requestInput(op);
43
+ if (input === undefined) return;
44
+
45
+ if (Object.values(this.modes).includes(input)) {
46
+ // input matches one of the mode values
47
+ this.mode = input;
48
+ }
49
+
50
+ // default window mode
51
+ if (this.mode === this.modes.WINDOW) {
52
+ if (Input.getType(input) === Input.Type.POINT) {
53
+ this.points.push(input);
54
+ } else {
55
+ const p1op = new PromptOptions(Strings.Input.POINT, [Input.Type.POINT]);
56
+ const pt1 = await DesignCore.Scene.inputManager.requestInput(p1op);
57
+ if (pt1 === undefined) return;
58
+ this.points.push(pt1);
59
+ }
60
+
61
+ const p2op = new PromptOptions(Strings.Input.END, [Input.Type.POINT]);
62
+ const pt2 = await DesignCore.Scene.inputManager.requestInput(p2op);
63
+ if (pt2 === undefined) return;
64
+ this.points.push(pt2);
65
+ }
66
+
67
+ // Zoom to objects in selection
68
+ if (this.mode === this.modes.OBJECT) {
69
+ const op = new PromptOptions(Strings.Input.SELECTIONSET, [Input.Type.SELECTIONSET]);
70
+
71
+ if (!DesignCore.Scene.selectionManager.selectionSet.selectionSet.length) {
72
+ const sel = await DesignCore.Scene.inputManager.requestInput(op);
73
+ if (sel === undefined) return;
74
+ }
75
+ }
76
+
77
+ DesignCore.Scene.inputManager.executeCommand();
78
+ } catch (err) {
79
+ Logging.instance.error(`${this.type} - ${err}`);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Preview the command during execution
85
+ */
86
+ preview() {
87
+ if (this.mode === this.modes.WINDOW && this.points.length === 1) {
88
+ const mousePoint = DesignCore.Mouse.pointOnScene();
89
+ const p1 = this.points[0];
90
+ const p2 = mousePoint;
91
+
92
+ const points = [
93
+ new Point(p1.x, p1.y),
94
+ new Point(p2.x, p1.y),
95
+ new Point(p2.x, p2.y),
96
+ new Point(p1.x, p2.y),
97
+ new Point(p1.x, p1.y),
98
+ ];
99
+
100
+ DesignCore.Scene.tempEntities.create('Polyline', { points: points });
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Perform the command
106
+ */
107
+ action() {
108
+ // Zoom to window
109
+ if (this.mode === this.modes.WINDOW && this.points.length === 2) {
110
+ DesignCore.Canvas.zoomToWindow(this.points[0], this.points[1]);
111
+ }
112
+
113
+ // Zoom Extents
114
+ if (this.mode === this.modes.ALL || this.mode === this.modes.EXTENTS) {
115
+ DesignCore.Canvas.zoomExtents();
116
+ }
117
+
118
+ // Zoom to Object(s)
119
+ if (this.mode === this.modes.OBJECT) {
120
+ let xmin = Infinity;
121
+ let xmax = -Infinity;
122
+ let ymin = Infinity;
123
+ let ymax = -Infinity;
124
+
125
+ // return if nothing selection
126
+ if (DesignCore.Scene.selectionManager.selectionSet.selectionSet.length === 0) {
127
+ return;
128
+ }
129
+
130
+ for (let i = 0; i <DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
131
+ const itemBoundingBox = DesignCore.Scene.entities.get(DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]).boundingBox();
132
+
133
+ xmin = Math.min(xmin, itemBoundingBox.xMin);
134
+ xmax = Math.max(xmax, itemBoundingBox.xMax);
135
+ ymin = Math.min(ymin, itemBoundingBox.yMin);
136
+ ymax = Math.max(ymax, itemBoundingBox.yMax);
137
+ }
138
+
139
+ // if all values are zero return undefined
140
+ if (xmin === 0 && xmax === 0, ymin === 0, ymax === 0) {
141
+ return;
142
+ }
143
+
144
+ const Pt1 = new Point(xmin, ymin);
145
+ const Pt2 = new Point(xmax, ymax);
146
+
147
+ DesignCore.Canvas.zoomToWindow(Pt1, Pt2);
148
+ }
149
+ }
150
+ }
151
+
152
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@design-core/core",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
@@ -12,7 +12,7 @@
12
12
  "eslint-plugin-import": "^2.26.0",
13
13
  "eslint-plugin-n": "^15.3.0",
14
14
  "eslint-plugin-promise": "^6.1.1",
15
- "jest": "^29.2.2"
15
+ "jest": "^29.7.0"
16
16
  },
17
17
  "description": "2D CAD Library",
18
18
  "exports": {
@@ -22,8 +22,6 @@
22
22
  "directories": {
23
23
  "test": "test"
24
24
  },
25
- "dependencies": {
26
- },
27
25
  "repository": {
28
26
  "type": "git",
29
27
  "url": "git+https://github.com/dubstar-04/Design-Core.git"
@@ -37,4 +35,4 @@
37
35
  "url": "https://github.com/dubstar-04/Design-Core/issues"
38
36
  },
39
37
  "homepage": "https://github.com/dubstar-04/Design-Core#readme"
40
- }
38
+ }
@@ -0,0 +1,211 @@
1
+ import { AlignedDimension } from '../../core/dimensions/alignedDimension.js';
2
+ import { Point } from '../../core/entities/point.js';
3
+ import { DesignCore } from '../../core/designCore.js';
4
+ import { Core } from '../../core/core/core.js';
5
+ import { Line } from '../../core/entities/line.js';
6
+ import { File, withMockInput } from '../test-helpers/test-helpers.js';
7
+
8
+ // initialise core
9
+ new Core();
10
+
11
+ // Test cases for user input
12
+ const scenarios = [
13
+
14
+ { desc: 'Aligned dimension from point selection',
15
+ input: [new Point(), new Point(10, 0), new Point(5, 5)],
16
+ selectedItems: [],
17
+ expectedDimType: 1,
18
+ dimensionValue: 10,
19
+ },
20
+ ];
21
+
22
+ test.each(scenarios)('Dimension.execute handles $desc', async (scenario) => {
23
+ const { input, selectedItems, expectedDimType, dimensionValue } = scenario;
24
+
25
+ await withMockInput(DesignCore.Scene, input, async () => {
26
+ const dim = new AlignedDimension();
27
+ await dim.execute();
28
+
29
+ expect(dim.dimType.getBaseDimType()).toBe(expectedDimType);
30
+ // get the text entities from the dimension block
31
+ const dimensionBlockEntities = dim.buildDimension();
32
+ expect(dimensionBlockEntities.length).toBe(7);
33
+
34
+ // check if the text value matches the expected dimension value
35
+ for (const entity of dimensionBlockEntities) {
36
+ if (entity.type === 'Text') {
37
+ expect(Number(entity.string)).toBeCloseTo(dimensionValue);
38
+ }
39
+ }
40
+ }, { selectedItems });
41
+ });
42
+
43
+ test('constructor sets default properties', () => {
44
+ const dim = new AlignedDimension();
45
+ expect(dim).toBeInstanceOf(AlignedDimension);
46
+ expect(dim.points).toBeDefined();
47
+ });
48
+
49
+
50
+ test('register returns command object', () => {
51
+ expect(AlignedDimension.register()).toEqual({ command: 'AlignedDimension', shortcut: 'DIMALI' });
52
+ });
53
+
54
+
55
+ describe('AlignedDimension.getPointsFromSelection', () => {
56
+ const scenarios = [
57
+ {
58
+ desc: 'horizontal line',
59
+ pt1: new Point(0, 0),
60
+ pt2: new Point(10, 0),
61
+ textPos: new Point(5, 5),
62
+ expected: {
63
+ text: { x: 5, y: 5 },
64
+ arrow: { x: 10, y: 5 },
65
+ },
66
+ },
67
+ {
68
+ desc: 'vertical line',
69
+ pt1: new Point(0, 0),
70
+ pt2: new Point(0, 10),
71
+ textPos: new Point(5, 5),
72
+ expected: {
73
+ text: { x: 5, y: 5 },
74
+ arrow: { x: 5, y: 10 },
75
+ },
76
+ },
77
+ {
78
+ desc: 'diagonal line',
79
+ pt1: new Point(0, 0),
80
+ pt2: new Point(10, 10),
81
+ textPos: new Point(5, 0),
82
+ expected: {
83
+ text: { x: 5, y: 0 },
84
+ arrow: { x: 12.5, y: 7.5 },
85
+ },
86
+ },
87
+ ];
88
+
89
+ test.each(scenarios)('returns correct sequenced points for $desc', ({ pt1, pt2, textPos, expected }) => {
90
+ const line = new Line({ points: [pt1, pt2] });
91
+ const result = AlignedDimension.getPointsFromSelection([line], textPos);
92
+ expect(result).toHaveLength(4);
93
+ expect(result[0].sequence).toBe(13);
94
+ expect(result[1].sequence).toBe(14);
95
+ expect(result[2].sequence).toBe(11);
96
+ expect(result[3].sequence).toBe(10);
97
+ // check text position
98
+ expect(result[2].x).toBeCloseTo(expected.text.x);
99
+ expect(result[2].y).toBeCloseTo(expected.text.y);
100
+ // check arrow position
101
+ expect(result[3].x).toBeCloseTo(expected.arrow.x);
102
+ expect(result[3].y).toBeCloseTo(expected.arrow.y);
103
+ });
104
+ });
105
+
106
+ test('AlignedDimension.preview runs without error and calls createTempItem', () => {
107
+ const origCreateTempItem = DesignCore.Scene.tempEntities.create;
108
+ const origPointOnScene = DesignCore.Mouse.pointOnScene;
109
+ // Manual mock for createTempItem
110
+ const createTempItemCalls = [];
111
+ DesignCore.Scene.tempEntities.create = function(type, obj) {
112
+ createTempItemCalls.push([type, obj]);
113
+ };
114
+ // Manual mock for pointOnScene
115
+ DesignCore.Mouse.pointOnScene = function() {
116
+ return new Point(5, 5);
117
+ };
118
+
119
+ // Test with 1 point (should call createTempItem with 'Line')
120
+ const dim1 = new AlignedDimension();
121
+ dim1.points = [new Point(0, 0)];
122
+ expect(() => dim1.preview()).not.toThrow();
123
+ expect(createTempItemCalls.some((call) => call[0] === 'Line')).toBe(true);
124
+
125
+ // Test with >1 point (should call createTempItem with this.type)
126
+ const dim2 = new AlignedDimension();
127
+ dim2.points = [new Point(0, 0), new Point(10, 0), new Point(5, 5)];
128
+ expect(() => dim2.preview()).not.toThrow();
129
+ expect(createTempItemCalls.some((call) => call[0] === dim2.type)).toBe(true);
130
+
131
+ // Restore
132
+ DesignCore.Scene.tempEntities.create = origCreateTempItem;
133
+ DesignCore.Mouse.pointOnScene = origPointOnScene;
134
+ });
135
+
136
+ test('Test AlignedDimension.dxf', () => {
137
+ const points = [];
138
+
139
+ const Pt13 = new Point(0, 0);
140
+ Pt13.sequence = 13;
141
+ points.push(Pt13);
142
+
143
+ const Pt14 = new Point(10, 0);
144
+ Pt14.sequence = 14;
145
+ points.push(Pt14);
146
+
147
+ const Pt10 = new Point(5, 5);
148
+ Pt10.sequence = 10;
149
+ points.push(Pt10);
150
+
151
+ const Pt11 = new Point(5, 5);
152
+ Pt11.sequence = 11;
153
+ points.push(Pt11);
154
+
155
+ points.push(Pt10, Pt14, Pt13, Pt11);
156
+
157
+ const dimension = new AlignedDimension({ points: points, handle: '1' });
158
+ let file = new File();
159
+ dimension.dxf(file);
160
+ // console.log(file.contents);
161
+
162
+ const dxfString = `0
163
+ DIMENSION
164
+ 5
165
+ 1
166
+ 100
167
+ AcDbEntity
168
+ 100
169
+ AcDbDimension
170
+ 8
171
+ 0
172
+ 10
173
+ 5
174
+ 20
175
+ 5
176
+ 30
177
+ 0.0
178
+ 11
179
+ 5
180
+ 21
181
+ 5
182
+ 31
183
+ 0.0
184
+ 70
185
+ 1
186
+ 3
187
+ STANDARD
188
+ 100
189
+ AcDbAlignedDimension
190
+ 13
191
+ 0
192
+ 23
193
+ 0
194
+ 33
195
+ 0.0
196
+ 14
197
+ 10
198
+ 24
199
+ 0
200
+ 34
201
+ 0.0
202
+ `;
203
+
204
+ expect(file.contents).toEqual(dxfString);
205
+
206
+ // create new entity from entity data to ensure all props are loaded
207
+ const newDimension = new AlignedDimension(dimension);
208
+ file = new File();
209
+ newDimension.dxf(file);
210
+ expect(file.contents).toEqual(dxfString);
211
+ });
@@ -0,0 +1,243 @@
1
+
2
+ import { AngularDimension } from '../../core/dimensions/angularDimension.js';
3
+ import { Point } from '../../core/entities/point.js';
4
+ import { Line } from '../../core/entities/line.js';
5
+ import { Polyline } from '../../core/entities/polyline.js';
6
+ import { Core } from '../../core/core/core.js';
7
+ import { DesignCore } from '../../core/designCore.js';
8
+ import { SingleSelection } from '../../core/lib/selectionManager.js';
9
+
10
+ import { File, withMockInput } from '../test-helpers/test-helpers.js';
11
+
12
+ // initialise core
13
+ new Core();
14
+
15
+
16
+ // Test cases for user input
17
+ const scenarios = [
18
+
19
+ { desc: 'Angular dimension from line selection - 45 degrees',
20
+ input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(5, 5)],
21
+ selectedItems: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
22
+ expectedDimType: 2,
23
+ dimensionValue: 45,
24
+ dimensionEntities: 5,
25
+ },
26
+ { desc: 'Angular dimension from line selection - 135 degrees',
27
+ input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(-5, 5)],
28
+ selectedItems: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
29
+ expectedDimType: 2,
30
+ dimensionValue: 135,
31
+ dimensionEntities: 6,
32
+ },
33
+ { desc: 'Angular dimension from line selection - 45 degrees',
34
+ input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(-5, -5)],
35
+ selectedItems: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
36
+ expectedDimType: 2,
37
+ dimensionValue: 45,
38
+ dimensionEntities: 7,
39
+ },
40
+ { desc: 'Angular dimension from line selection - 135 degrees',
41
+ input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(5, -5)],
42
+ selectedItems: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
43
+ expectedDimType: 2,
44
+ dimensionValue: 135,
45
+ dimensionEntities: 6,
46
+ },
47
+ { desc: 'Angular dimension from polyline selection - 45 degrees',
48
+ input: [new SingleSelection(0, new Point(5, 0)), new SingleSelection(1, new Point(5, 5)), new Point(5, 5)],
49
+ selectedItems: [new Polyline({ points: [new Point(0, 0), new Point(10, 0)] }), new Polyline({ points: [new Point(0, 0), new Point(10, 10)] })],
50
+ expectedDimType: 2,
51
+ dimensionValue: 45,
52
+ dimensionEntities: 5,
53
+ },
54
+ ];
55
+
56
+ test.each(scenarios)('Dimension.execute handles $desc', async (scenario) => {
57
+ const { input, selectedItems, expectedDimType, dimensionValue, dimensionEntities } = scenario;
58
+
59
+ await withMockInput(DesignCore.Scene, input, async () => {
60
+ const dim = new AngularDimension();
61
+ await dim.execute();
62
+
63
+ expect(dim.dimType.getBaseDimType()).toBe(expectedDimType);
64
+ // get the text entities from the dimension block
65
+ const dimensionBlockEntities = dim.buildDimension();
66
+ expect(dimensionBlockEntities.length).toBe(dimensionEntities);
67
+
68
+ // check if the text value matches the expected dimension value
69
+ for (const entity of dimensionBlockEntities) {
70
+ if (entity.type === 'Text') {
71
+ // remove all non-numeric characters except . and -
72
+ const numbersOnly = entity.string.replace(/[^0-9.-]+/g, '');
73
+ expect(Number(numbersOnly)).toBeCloseTo(dimensionValue);
74
+ expect(entity.string).toContain('°');
75
+ }
76
+ }
77
+ }, { selectedItems });
78
+ });
79
+
80
+ test('constructor sets default properties', () => {
81
+ const dim = new AngularDimension();
82
+ expect(dim).toBeInstanceOf(AngularDimension);
83
+ expect(dim.points).toBeDefined();
84
+ });
85
+
86
+ test('register returns command object', () => {
87
+ expect(AngularDimension.register()).toEqual({ command: 'AngularDimension', shortcut: 'DIMANG' });
88
+ });
89
+
90
+ test('getPointsFromSelection returns correct sequenced points', () => {
91
+ const pt1 = new Point(0, 0);
92
+ const pt2 = new Point(10, 0);
93
+ const pt3 = new Point(10, 10);
94
+ const textPos = new Point(5, 5);
95
+ const line1 = new Line({ points: [pt1, pt2] });
96
+ const line2 = new Line({ points: [pt2, pt3] });
97
+ const result = AngularDimension.getPointsFromSelection([line1, line2], textPos);
98
+ expect(Array.isArray(result)).toBe(true);
99
+ expect(result.length).toBeGreaterThanOrEqual(4);
100
+ });
101
+
102
+ test('AngularDimension.preview runs without error and calls createTempItem', () => {
103
+ const origCreateTempItem = DesignCore.Scene.tempEntities.create;
104
+ const origPointOnScene = DesignCore.Mouse.pointOnScene;
105
+ // Manual mock for createTempItem
106
+ const createTempItemCalls = [];
107
+ DesignCore.Scene.tempEntities.create = function(type, obj) {
108
+ createTempItemCalls.push([type, obj]);
109
+ };
110
+ // Manual mock for pointOnScene
111
+ DesignCore.Mouse.pointOnScene = function() {
112
+ return new Point(5, 5);
113
+ };
114
+
115
+
116
+ // Test with >4 point (should call createTempItem with this.type)
117
+ const dim2 = new AngularDimension();
118
+
119
+ dim2.points = [];
120
+
121
+ const Pt10 = new Point();
122
+ Pt10.sequence = 10;
123
+ dim2.points.push(Pt10);
124
+
125
+ const Pt13 = new Point();
126
+ Pt13.sequence = 13;
127
+ dim2.points.push(Pt13);
128
+
129
+ const Pt14 = new Point();
130
+ Pt14.sequence = 14;
131
+ dim2.points.push(Pt14);
132
+
133
+ const Pt15 = new Point();
134
+ Pt15.sequence = 15;
135
+ dim2.points.push(Pt15);
136
+
137
+ expect(() => dim2.preview()).not.toThrow();
138
+ expect(createTempItemCalls.some((call) => call[0] === dim2.type)).toBe(true);
139
+
140
+ // Restore
141
+ DesignCore.Scene.tempEntities.create = origCreateTempItem;
142
+ DesignCore.Mouse.pointOnScene = origPointOnScene;
143
+ });
144
+
145
+ test('Test AngularDimension.dxf', () => {
146
+ const points = [];
147
+
148
+ const Pt10 = new Point(5, 6);
149
+ Pt10.sequence = 10;
150
+ points.push(Pt10);
151
+
152
+ const Pt11 = new Point(7, 8);
153
+ Pt11.sequence = 11;
154
+ points.push(Pt11);
155
+
156
+ const Pt13 = new Point(9, 10);
157
+ Pt13.sequence = 13;
158
+ points.push(Pt13);
159
+
160
+ const Pt14 = new Point(11, 12);
161
+ Pt14.sequence = 14;
162
+ points.push(Pt14);
163
+
164
+ const Pt15 = new Point(13, 14);
165
+ Pt15.sequence = 15;
166
+ points.push(Pt15);
167
+
168
+ const Pt16 = new Point(15, 16);
169
+ Pt16.sequence = 16;
170
+ points.push(Pt16);
171
+
172
+
173
+ points.push(Pt10, Pt11, Pt13, Pt14, Pt15, Pt16);
174
+
175
+ const dimension = new AngularDimension({ points: points, handle: '1' });
176
+ let file = new File();
177
+ dimension.dxf(file);
178
+ // console.log(file.contents);
179
+
180
+ const dxfString = `0
181
+ DIMENSION
182
+ 5
183
+ 1
184
+ 100
185
+ AcDbEntity
186
+ 100
187
+ AcDbDimension
188
+ 8
189
+ 0
190
+ 10
191
+ 5
192
+ 20
193
+ 6
194
+ 30
195
+ 0.0
196
+ 11
197
+ 7
198
+ 21
199
+ 8
200
+ 31
201
+ 0.0
202
+ 70
203
+ 2
204
+ 3
205
+ STANDARD
206
+ 100
207
+ AcDb2LineAngularDimension
208
+ 13
209
+ 9
210
+ 23
211
+ 10
212
+ 33
213
+ 0.0
214
+ 14
215
+ 11
216
+ 24
217
+ 12
218
+ 34
219
+ 0.0
220
+ 15
221
+ 13
222
+ 25
223
+ 14
224
+ 35
225
+ 0.0
226
+ 16
227
+ 15
228
+ 26
229
+ 16
230
+ 36
231
+ 0.0
232
+ `;
233
+
234
+ expect(file.contents).toEqual(dxfString);
235
+
236
+ // create new entity from entity data to ensure all props are loaded
237
+ const newDimension = new AngularDimension(dimension);
238
+ file = new File();
239
+ newDimension.dxf(file);
240
+ expect(file.contents).toEqual(dxfString);
241
+ });
242
+
243
+