@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
@@ -1,15 +1,38 @@
1
- import {Circle} from '../../core/entities/circle.js';
2
- import {Point} from '../../core/entities/point.js';
1
+ import { jest } from '@jest/globals';
2
+ import { Circle } from '../../core/entities/circle.js';
3
+ import { Core } from '../../core/core/core.js';
4
+ import { Point } from '../../core/entities/point.js';
5
+ import { DesignCore } from '../../core/designCore.js';
6
+ import { Strings } from '../../core/lib/strings.js';
3
7
 
8
+ import { File, withMockInput } from '../test-helpers/test-helpers.js';
9
+
10
+ // initialise core
11
+ new Core();
12
+
13
+ test('Circle.execute creates points from user input', async () => {
14
+ const pt0 = new Point(0, 0);
15
+ const pt1 = new Point(10, 0);
16
+
17
+ await withMockInput(DesignCore.Scene, [pt0, pt1], async () => {
18
+ const circle = new Circle({});
19
+ await circle.execute();
20
+
21
+ expect(circle.points.length).toBe(2);
22
+ expect(circle.points[0]).toBe(pt0);
23
+ expect(circle.points[1]).toBe(pt1);
24
+ expect(circle.getRadius()).toBe(10);
25
+ });
26
+ });
4
27
 
5
28
  test('Test Circle.getRadius', () => {
6
- const circle = new Circle({points: [new Point(100, 100), new Point(200, 100)]});
29
+ const circle = new Circle({ points: [new Point(100, 100), new Point(200, 100)] });
7
30
  expect(circle.getRadius()).toBe(100);
8
31
  });
9
32
 
10
33
  test('Test Circle.setRadius', () => {
11
34
  // create a circle with radius 100
12
- const circle = new Circle({points: [new Point(100, 100), new Point(200, 100)]});
35
+ const circle = new Circle({ points: [new Point(100, 100), new Point(200, 100)] });
13
36
  // set radius to 200
14
37
  circle.setRadius(200);
15
38
  expect(circle.getRadius()).toBe(200);
@@ -18,7 +41,7 @@ test('Test Circle.setRadius', () => {
18
41
 
19
42
  test('Test Circle.closestPoint', () => {
20
43
  // create a circle with radius 100
21
- const circle = new Circle({points: [new Point(100, 100), new Point(200, 100)]});
44
+ const circle = new Circle({ points: [new Point(100, 100), new Point(200, 100)] });
22
45
  // inside
23
46
  const point1 = new Point(150, 100);
24
47
  const closest1 = circle.closestPoint(point1);
@@ -35,15 +58,297 @@ test('Test Circle.closestPoint', () => {
35
58
  });
36
59
 
37
60
  test('Test Circle.boundingBox', () => {
38
- let circle = new Circle({points: [new Point(100, 100), new Point(200, 100)]});
61
+ let circle = new Circle({ points: [new Point(100, 100), new Point(200, 100)] });
39
62
  expect(circle.boundingBox().xMin).toBeCloseTo(0);
40
63
  expect(circle.boundingBox().xMax).toBeCloseTo(200);
41
64
  expect(circle.boundingBox().yMin).toBeCloseTo(0);
42
65
  expect(circle.boundingBox().yMax).toBeCloseTo(200);
43
66
 
44
- circle = new Circle({points: [new Point(0, 0)], radius: 100});
67
+ circle = new Circle({ points: [new Point(0, 0)], radius: 100 });
45
68
  expect(circle.boundingBox().xMin).toBeCloseTo(-100);
46
69
  expect(circle.boundingBox().xMax).toBeCloseTo(100);
47
70
  expect(circle.boundingBox().yMin).toBeCloseTo(-100);
48
71
  expect(circle.boundingBox().yMax).toBeCloseTo(100);
49
72
  });
73
+
74
+ test('Test Circle.dxf', () => {
75
+ const circle = new Circle({ handle: '1', points: [new Point(100, 100), new Point(200, 100)] });
76
+ let file = new File();
77
+ circle.dxf(file);
78
+ // console.log(file.contents);
79
+
80
+ const dxfString = `0
81
+ CIRCLE
82
+ 5
83
+ 1
84
+ 100
85
+ AcDbEntity
86
+ 100
87
+ AcDbCircle
88
+ 8
89
+ 0
90
+ 6
91
+ ByLayer
92
+ 10
93
+ 100
94
+ 20
95
+ 100
96
+ 30
97
+ 0.0
98
+ 39
99
+ 2
100
+ 40
101
+ 100
102
+ `;
103
+
104
+ expect(file.contents).toEqual(dxfString);
105
+
106
+
107
+ // create new entity from entity data to ensure all props are loaded
108
+ const newCircle = new Circle(circle);
109
+ file = new File();
110
+ newCircle.dxf(file);
111
+ expect(file.contents).toEqual(dxfString);
112
+ });
113
+
114
+ test('Test Circle.toPolylinePoints', () => {
115
+ const circle = new Circle({ points: [new Point(100, 100), new Point(200, 100)] });
116
+ const circlePoints = circle.toPolylinePoints();
117
+ expect(circlePoints[0].x).toBe(200);
118
+ expect(circlePoints[0].y).toBe(100);
119
+ expect(circlePoints[0].bulge).toBeCloseTo(1);
120
+
121
+ expect(circlePoints[1].x).toBe(0);
122
+ expect(circlePoints[1].y).toBe(100);
123
+ expect(circlePoints[1].bulge).toBeCloseTo(1);
124
+
125
+ expect(circlePoints[2].x).toBe(200);
126
+ expect(circlePoints[2].y).toBe(100);
127
+ expect(circlePoints[2].bulge).toBe(0);
128
+ });
129
+
130
+ test('Test Circle.trim returns empty array when provided with empty intersection list', () => {
131
+ const circle = new Circle({ points: [new Point(0, 0), new Point(100, 0)] });
132
+
133
+ expect(circle.trim([])).toEqual([]);
134
+ expect(circle.trim()).toEqual([]);
135
+ });
136
+
137
+ test('Test Circle.trim does not modify circle', () => {
138
+ const circle = new Circle({ points: [new Point(0, 0), new Point(10, 0)] });
139
+
140
+ DesignCore.Mouse.pointOnScene = () => new Point(7.71, 7.71);
141
+
142
+ // test a single intersection - not valid
143
+ const intersections = [new Point(10, 0)];
144
+ expect(circle.trim(intersections)).toEqual([]);
145
+
146
+ // test two intersections - should return an arc
147
+ intersections.push(new Point(-10, 0));
148
+ let trimWithTwoPoints = circle.trim(intersections);
149
+ let trimResult = trimWithTwoPoints[0].entity;
150
+ expect(trimResult.type).toEqual('Arc');
151
+ // Verify trimmed arc has a unique handle (not the circle's)
152
+ expect(trimResult.handle).toBeUndefined();
153
+ expect(trimResult.points[0].x).toEqual(0);
154
+ expect(trimResult.points[0].y).toEqual(0);
155
+
156
+ expect(trimResult.points[1].x).toEqual(10);
157
+ expect(trimResult.points[1].y).toEqual(0);
158
+
159
+ expect(trimResult.points[2].x).toEqual(-10);
160
+ expect(trimResult.points[2].y).toEqual(0);
161
+
162
+ expect(trimWithTwoPoints[1].entity).toEqual(circle);
163
+
164
+ // test three intersections - should return an arc from first two points found
165
+ intersections.push(new Point(0, 10));
166
+ trimWithTwoPoints = circle.trim(intersections);
167
+ trimResult = trimWithTwoPoints[0].entity;
168
+ expect(trimResult.type).toEqual('Arc');
169
+ expect(trimResult.points[0].x).toEqual(0);
170
+ expect(trimResult.points[0].y).toEqual(0);
171
+
172
+ expect(trimResult.points[1].x).toEqual(10);
173
+ expect(trimResult.points[1].y).toEqual(0);
174
+
175
+ expect(trimResult.points[2].x).toEqual(0);
176
+ expect(trimResult.points[2].y).toEqual(10);
177
+
178
+ expect(trimWithTwoPoints[1].entity).toEqual(circle);
179
+
180
+ // test four intersections - should return an arc from first two points found
181
+ intersections.push(new Point(0, -10));
182
+ trimWithTwoPoints = circle.trim(intersections);
183
+ trimResult = trimWithTwoPoints[0].entity;
184
+ expect(trimResult.type).toEqual('Arc');
185
+ expect(trimResult.points[0].x).toEqual(0);
186
+ expect(trimResult.points[0].y).toEqual(0);
187
+
188
+ expect(trimResult.points[1].x).toEqual(10);
189
+ expect(trimResult.points[1].y).toEqual(0);
190
+
191
+ expect(trimResult.points[2].x).toEqual(0);
192
+ expect(trimResult.points[2].y).toEqual(10);
193
+
194
+ expect(trimWithTwoPoints[1].entity).toEqual(circle);
195
+ });
196
+
197
+ test('Circle.execute creates circle from diameter input', async () => {
198
+ const center = new Point(0, 0);
199
+
200
+ await withMockInput(DesignCore.Scene, [center, 'Diameter', 20], async () => {
201
+ const circle = new Circle({});
202
+ await circle.execute();
203
+
204
+ expect(circle.points[0]).toBe(center);
205
+ expect(circle.getRadius()).toBeCloseTo(10);
206
+ });
207
+ });
208
+
209
+ test('Circle.execute re-prompts on zero or negative radius', async () => {
210
+ const center = new Point(0, 0);
211
+
212
+ // 0 and -5 are rejected; 10 is accepted
213
+ await withMockInput(DesignCore.Scene, [center, 0, -5, 10], async () => {
214
+ const circle = new Circle({});
215
+ await circle.execute();
216
+
217
+ expect(circle.getRadius()).toBeCloseTo(10);
218
+ });
219
+ });
220
+
221
+ test('Circle.execute re-prompts on zero or negative diameter', async () => {
222
+ const center = new Point(0, 0);
223
+
224
+ // 'Diameter', then 0 and -20 rejected, then 20 accepted (radius = 10)
225
+ await withMockInput(DesignCore.Scene, [center, 'Diameter', 0, -20, 20], async () => {
226
+ const circle = new Circle({});
227
+ await circle.execute();
228
+
229
+ expect(circle.getRadius()).toBeCloseTo(10);
230
+ });
231
+ });
232
+
233
+ test('Circle.register returns command object', () => {
234
+ expect(Circle.register()).toEqual({ command: 'Circle', shortcut: 'C', type: 'Entity' });
235
+ });
236
+
237
+ test('Circle constructor loads radius from DXF group code 40', () => {
238
+ const circle = new Circle({ points: [new Point(0, 0)], 40: 50 });
239
+ expect(circle.getRadius()).toBeCloseTo(50);
240
+ expect(circle.points[1].x).toBeCloseTo(50);
241
+ expect(circle.points[1].y).toBeCloseTo(0);
242
+ });
243
+
244
+ test('Circle.execute creates circle from numeric radius input', async () => {
245
+ const center = new Point(0, 0);
246
+ await withMockInput(DesignCore.Scene, [center, 25], async () => {
247
+ const circle = new Circle({});
248
+ await circle.execute();
249
+ expect(circle.getRadius()).toBeCloseTo(25);
250
+ });
251
+ });
252
+
253
+ test('Circle.execute re-prompts on zero-distance point input', async () => {
254
+ const notifySpy = jest.spyOn(DesignCore.Core, 'notify').mockImplementation(() => {});
255
+ const center = new Point(0, 0);
256
+ await withMockInput(DesignCore.Scene, [center, new Point(0, 0), new Point(10, 0)], async () => {
257
+ const circle = new Circle({});
258
+ await circle.execute();
259
+ expect(notifySpy).toHaveBeenCalledWith(expect.stringContaining(Strings.Error.NONZERO));
260
+ expect(circle.getRadius()).toBeCloseTo(10);
261
+ });
262
+ notifySpy.mockRestore();
263
+ });
264
+
265
+ test('Circle.preview does not throw with 0 or 1 points', () => {
266
+ const origCreate = DesignCore.Scene.tempEntities.create;
267
+ const origMouse = DesignCore.Mouse.pointOnScene;
268
+ const calls = [];
269
+ DesignCore.Scene.tempEntities.create = (type, obj) => calls.push([type, obj]);
270
+ DesignCore.Mouse.pointOnScene = () => new Point(5, 5);
271
+
272
+ const circle0 = new Circle({});
273
+ expect(() => circle0.preview()).not.toThrow();
274
+ expect(calls.length).toBe(0);
275
+
276
+ const circle1 = new Circle({});
277
+ circle1.points = [new Point(0, 0)];
278
+ expect(() => circle1.preview()).not.toThrow();
279
+ expect(calls.some(([type]) => type === 'Circle')).toBe(true);
280
+
281
+ DesignCore.Scene.tempEntities.create = origCreate;
282
+ DesignCore.Mouse.pointOnScene = origMouse;
283
+ });
284
+
285
+ test('Circle.draw does not throw', () => {
286
+ const circle = new Circle({ points: [new Point(0, 0), new Point(10, 0)] });
287
+ const ctx = { arc: jest.fn(), stroke: jest.fn() };
288
+ expect(() => circle.draw(ctx, 1)).not.toThrow();
289
+ expect(ctx.arc).toHaveBeenCalledTimes(1);
290
+ expect(ctx.stroke).toHaveBeenCalledTimes(1);
291
+ });
292
+
293
+ test('Circle.snaps returns centre snap', () => {
294
+ const circle = new Circle({ points: [new Point(0, 0), new Point(10, 0)] });
295
+ DesignCore.Settings.centresnap = true;
296
+ DesignCore.Settings.quadrantsnap = false;
297
+ DesignCore.Settings.nearestsnap = false;
298
+ const snaps = circle.snaps(new Point(5, 0), 100);
299
+ expect(snaps).toHaveLength(1);
300
+ expect(snaps[0].x).toBe(0);
301
+ expect(snaps[0].y).toBe(0);
302
+ });
303
+
304
+ test('Circle.snaps returns four quadrant snaps', () => {
305
+ const circle = new Circle({ points: [new Point(0, 0), new Point(10, 0)] });
306
+ DesignCore.Settings.centresnap = false;
307
+ DesignCore.Settings.quadrantsnap = true;
308
+ DesignCore.Settings.nearestsnap = false;
309
+ const snaps = circle.snaps(new Point(5, 0), 100);
310
+ expect(snaps).toHaveLength(4);
311
+ expect(snaps.some((p) => p.x === 10 && p.y === 0)).toBe(true);// 0°
312
+ expect(snaps.some((p) => p.x === 0 && p.y === 10)).toBe(true);// 90°
313
+ expect(snaps.some((p) => p.x === -10 && p.y === 0)).toBe(true);// 180°
314
+ expect(snaps.some((p) => p.x === 0 && p.y === -10)).toBe(true);// 270°
315
+ });
316
+
317
+ test('Circle.snaps nearest snap fires when close enough', () => {
318
+ const circle = new Circle({ points: [new Point(0, 0), new Point(10, 0)] });
319
+ DesignCore.Settings.centresnap = false;
320
+ DesignCore.Settings.quadrantsnap = false;
321
+ DesignCore.Settings.nearestsnap = true;
322
+ // Mouse on the circle surface with large delta
323
+ const snaps = circle.snaps(new Point(10, 0), 1000);
324
+ expect(snaps.length).toBeGreaterThanOrEqual(1);
325
+ });
326
+
327
+ test('Circle.snaps nearest snap does not fire when too far', () => {
328
+ const circle = new Circle({ points: [new Point(0, 0), new Point(10, 0)] });
329
+ DesignCore.Settings.centresnap = false;
330
+ DesignCore.Settings.quadrantsnap = false;
331
+ DesignCore.Settings.nearestsnap = true;
332
+ const snaps = circle.snaps(new Point(100, 100), 1);
333
+ expect(snaps.length).toBe(0);
334
+ });
335
+
336
+ test('Circle.fromPolylinePoints round-trip preserves centre and radius', () => {
337
+ const circle = new Circle({ points: [new Point(5, 10), new Point(5, 10).project(0, 8)] });
338
+ const polyPts = circle.toPolylinePoints();
339
+ const rebuilt = new Circle({});
340
+ rebuilt.fromPolylinePoints(polyPts);
341
+ expect(rebuilt.points[0].x).toBeCloseTo(5, 10);
342
+ expect(rebuilt.points[0].y).toBeCloseTo(10, 10);
343
+ expect(rebuilt.radius).toBeCloseTo(8, 10);
344
+ });
345
+
346
+ test('Circle.fromPolylinePoints precision drift is negligible', () => {
347
+ const circle = new Circle({ points: [new Point(123.456, -789.012), new Point(123.456, -789.012).project(1.234, 56.789)] });
348
+ const polyPts = circle.toPolylinePoints();
349
+ const rebuilt = new Circle({});
350
+ rebuilt.fromPolylinePoints(polyPts);
351
+ const drift = Math.hypot(rebuilt.points[0].x - circle.points[0].x, rebuilt.points[0].y - circle.points[0].y);
352
+ expect(drift).toBeLessThan(1e-10);
353
+ expect(Math.abs(rebuilt.radius - circle.radius)).toBeLessThan(1e-10);
354
+ });
@@ -1,16 +1,16 @@
1
1
 
2
2
 
3
- import {Core} from '../../core/core/core.js';
4
- import {Entity} from '../../core/entities/entity.js';
5
- import {Line} from '../../core/entities/line.js';
6
- import {Point} from '../../core/entities/point.js';
3
+ import { Core } from '../../core/core/core.js';
4
+ import { Entity } from '../../core/entities/entity.js';
5
+ import { Line } from '../../core/entities/line.js';
6
+ import { Point } from '../../core/entities/point.js';
7
7
 
8
8
  // initialise core
9
9
  new Core();
10
10
 
11
- test('Test Entity.getColour', () => {
11
+ test('Test Entity.colour', () => {
12
12
  const entity = new Entity();
13
- expect(entity.getColour()).toBe('#00BFFF');
13
+ expect(entity.colour).toEqual({ 'r': 1, 'g': 1, 'b': 1 });
14
14
  });
15
15
 
16
16
  test('Test Entity.getLineType', () => {
@@ -19,10 +19,29 @@ test('Test Entity.getLineType', () => {
19
19
  });
20
20
 
21
21
  test('Test Entity.Within', () => {
22
- const entity = new Line({points: [new Point(100, 100), new Point(200, 200)]});
23
- const selectionExtremesFalse = [101, 199, 101, 199];
24
- const selectionExtremesTrue = [99, 201, 99, 201];
22
+ const entity = new Line({ points: [new Point(100, 100), new Point(200, 200)] });
23
+ const selectionExtremesFalse = { min: new Point(101, 101), max: new Point(199, 199) };
24
+ const selectionExtremesTrue = { min: new Point(99, 99), max: new Point(201, 201) };
25
25
 
26
26
  expect(entity.within(selectionExtremesFalse)).toBe(false);
27
27
  expect(entity.within(selectionExtremesTrue)).toBe(true);
28
28
  });
29
+
30
+ test('Test Entity.touched', () => {
31
+ const entity = new Line({ points: [new Point(100, 100), new Point(200, 200)] });
32
+ const selectionExtremesTrue = { min: new Point(101, 101), max: new Point(199, 199) };
33
+ const selectionExtremesFalse = { min: new Point(99, 99), max: new Point(201, 201) };
34
+
35
+ expect(entity.touched(selectionExtremesFalse)).toBe(false);
36
+ expect(entity.touched(selectionExtremesTrue)).toBe(true);
37
+ });
38
+
39
+ test('Test Entity.trim', () => {
40
+ const entity = new Entity();
41
+ expect(entity.trim()).toEqual([]);
42
+ });
43
+
44
+ test('Test Entity.extend', () => {
45
+ const entity = new Entity();
46
+ expect(entity.extend()).toEqual([]);
47
+ });