@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,5 +1,5 @@
1
1
 
2
- import {Point} from '../../core/entities/point.js';
2
+ import { Point } from '../../core/entities/point.js';
3
3
 
4
4
 
5
5
  test('Test Point.add', () => {
@@ -40,19 +40,19 @@ test('Test Point.angle', () => {
40
40
  expect(pt1.angle(new Point(10, 0))).toBe(0);
41
41
 
42
42
  /* 22.5 degrees */
43
- expect(pt1.angle(new Point(13.065629648764, 5.411961001462))).toBeCloseTo(Math.PI/8);
43
+ expect(pt1.angle(new Point(13.065629648764, 5.411961001462))).toBeCloseTo(Math.PI / 8);
44
44
 
45
45
  /* 45 degrees */
46
- expect(pt1.angle(new Point(10, 10))).toBe(Math.PI/4);
46
+ expect(pt1.angle(new Point(10, 10))).toBe(Math.PI / 4);
47
47
 
48
48
  /* 90 degrees */
49
- expect(pt1.angle(new Point(0, 10))).toBe(Math.PI/2);
49
+ expect(pt1.angle(new Point(0, 10))).toBe(Math.PI / 2);
50
50
 
51
51
  /* 180 degrees */
52
52
  expect(pt1.angle(new Point(-10, 0))).toBe(Math.PI);
53
53
 
54
54
  /* 270 degrees */
55
- expect(pt1.angle(new Point(0, -10))).toBe(Math.PI*1.5);
55
+ expect(pt1.angle(new Point(0, -10))).toBe(Math.PI * 1.5);
56
56
  });
57
57
 
58
58
  test('Test Point.clone', () => {
@@ -86,18 +86,87 @@ test('Test Point.dot', () => {
86
86
  expect(pt1.dot(pt3)).toBe(-200);
87
87
  });
88
88
 
89
+ test('Test Point.cross', () => {
90
+ // Perpendicular vectors
91
+ const pt1 = new Point(1, 0);
92
+ const pt2 = new Point(0, 1);
93
+ expect(pt1.cross(pt2)).toBe(1);
94
+
95
+ // Reversed order negates the result
96
+ expect(pt2.cross(pt1)).toBe(-1);
97
+
98
+ // Parallel vectors
99
+ const pt3 = new Point(2, 0);
100
+ expect(pt1.cross(pt3)).toBe(0);
101
+ });
102
+
103
+ test('Test Point.mirror', () => {
104
+ // Mirror across the X axis (y=0 line: from (0,0) to (1,0))
105
+ const xAxisPt1 = new Point(0, 0);
106
+ const xAxisPt2 = new Point(1, 0);
107
+ const pt1 = new Point(3, 4);
108
+ const r1 = pt1.mirror(xAxisPt1, xAxisPt2);
109
+ expect(r1.x).toBeCloseTo(3);
110
+ expect(r1.y).toBeCloseTo(-4);
111
+
112
+ // Mirror across the Y axis (x=0 line: from (0,0) to (0,1))
113
+ const yAxisPt1 = new Point(0, 0);
114
+ const yAxisPt2 = new Point(0, 1);
115
+ const pt2 = new Point(5, 3);
116
+ const r2 = pt2.mirror(yAxisPt1, yAxisPt2);
117
+ expect(r2.x).toBeCloseTo(-5);
118
+ expect(r2.y).toBeCloseTo(3);
119
+
120
+ // Mirror across a diagonal line y=x (from (0,0) to (1,1))
121
+ const diagPt1 = new Point(0, 0);
122
+ const diagPt2 = new Point(1, 1);
123
+ const pt3 = new Point(3, 0);
124
+ const r3 = pt3.mirror(diagPt1, diagPt2);
125
+ expect(r3.x).toBeCloseTo(0);
126
+ expect(r3.y).toBeCloseTo(3);
127
+
128
+ // A point on the mirror line is unchanged
129
+ const pt4 = new Point(2, 0);
130
+ const r4 = pt4.mirror(xAxisPt1, xAxisPt2);
131
+ expect(r4.x).toBeCloseTo(2);
132
+ expect(r4.y).toBeCloseTo(0);
133
+
134
+ // Mirror across an offset vertical line (x=5)
135
+ const vPt1 = new Point(5, 0);
136
+ const vPt2 = new Point(5, 1);
137
+ const pt5 = new Point(3, 2);
138
+ const r5 = pt5.mirror(vPt1, vPt2);
139
+ expect(r5.x).toBeCloseTo(7);
140
+ expect(r5.y).toBeCloseTo(2);
141
+
142
+ // Bulge is negated (arc direction reverses)
143
+ const pt6 = new Point(3, 4, 0.5, 10);
144
+ const r6 = pt6.mirror(xAxisPt1, xAxisPt2);
145
+ expect(r6.bulge).toBeCloseTo(-0.5);
146
+ expect(r6.sequence).toBe(10);
147
+
148
+ // Degenerate mirror line (pt1 === pt2) returns a clone of the point unchanged
149
+ const ptDegen = new Point(7, 8, 0.25, 3);
150
+ const samePt = new Point(5, 5);
151
+ const rDegen = ptDegen.mirror(samePt, samePt);
152
+ expect(rDegen.x).toBeCloseTo(7);
153
+ expect(rDegen.y).toBeCloseTo(8);
154
+ expect(rDegen.bulge).toBeCloseTo(0.25);
155
+ expect(rDegen.sequence).toBe(3);
156
+ });
157
+
89
158
  test('Test Point.rotate', () => {
90
159
  const centre = new Point();
91
160
 
92
161
  /* 90 degrees */
93
162
  const pt1 = new Point(10, 0);
94
- const result1 = pt1.rotate(centre, Math.PI/2);
163
+ const result1 = pt1.rotate(centre, Math.PI / 2);
95
164
  expect(result1.x).toBeCloseTo(0, 5);
96
165
  expect(result1.y).toBeCloseTo(10, 5);
97
166
 
98
167
  /* -90 degrees */
99
168
  const pt2 = new Point(-10, 0);
100
- const result2 = pt2.rotate(centre, -Math.PI/2);
169
+ const result2 = pt2.rotate(centre, -Math.PI / 2);
101
170
  expect(result2.x).toBeCloseTo(0, 5);
102
171
  expect(result2.y).toBeCloseTo(10, 5);
103
172
 
@@ -110,6 +179,114 @@ test('Test Point.rotate', () => {
110
179
  expect(result3.y).toBeCloseTo(30, 5);
111
180
  });
112
181
 
182
+ test('Test Point.length', () => {
183
+ expect(new Point(3, 4).length()).toBe(5);
184
+ expect(new Point(5, 0).length()).toBe(5);
185
+ expect(new Point(0, -7).length()).toBe(7);
186
+ expect(new Point(0, 0).length()).toBe(0);
187
+ expect(new Point(1, 1).length()).toBeCloseTo(Math.SQRT2);
188
+ });
189
+
190
+ test('Test Point.normalise', () => {
191
+ // Axis-aligned vector: (5, 0) → (1, 0)
192
+ const pt1 = new Point(5, 0);
193
+ const r1 = pt1.normalise();
194
+ expect(r1.x).toBeCloseTo(1);
195
+ expect(r1.y).toBeCloseTo(0);
196
+
197
+ // Axis-aligned vector: (0, -3) → (0, -1)
198
+ const pt2 = new Point(0, -3);
199
+ const r2 = pt2.normalise();
200
+ expect(r2.x).toBeCloseTo(0);
201
+ expect(r2.y).toBeCloseTo(-1);
202
+
203
+ // Diagonal vector: (3, 4) has length 5 → (0.6, 0.8)
204
+ const pt3 = new Point(3, 4);
205
+ const r3 = pt3.normalise();
206
+ expect(r3.x).toBeCloseTo(0.6);
207
+ expect(r3.y).toBeCloseTo(0.8);
208
+
209
+ // Result is a unit vector: length = 1
210
+ const pt4 = new Point(7, -24);
211
+ const r4 = pt4.normalise();
212
+ expect(Math.sqrt(r4.x ** 2 + r4.y ** 2)).toBeCloseTo(1);
213
+
214
+ // Zero vector: returns (0, 0) rather than NaN
215
+ const pt5 = new Point(0, 0);
216
+ const r5 = pt5.normalise();
217
+ expect(r5.x).toBe(0);
218
+ expect(r5.y).toBe(0);
219
+ });
220
+
221
+ test('Test Point.scale', () => {
222
+ // Scale by positive factor
223
+ const pt1 = new Point(3, 4);
224
+ const r1 = pt1.scale(2);
225
+ expect(r1.x).toBeCloseTo(6);
226
+ expect(r1.y).toBeCloseTo(8);
227
+
228
+ // Scale by fractional factor
229
+ const pt2 = new Point(10, -5);
230
+ const r2 = pt2.scale(0.5);
231
+ expect(r2.x).toBeCloseTo(5);
232
+ expect(r2.y).toBeCloseTo(-2.5);
233
+
234
+ // Scale by zero → origin
235
+ const pt3 = new Point(7, -3);
236
+ const r3 = pt3.scale(0);
237
+ expect(r3.x).toBeCloseTo(0);
238
+ expect(r3.y).toBeCloseTo(0);
239
+
240
+ // Scale by negative factor
241
+ const pt4 = new Point(1, 2);
242
+ const r4 = pt4.scale(-3);
243
+ expect(r4.x).toBeCloseTo(-3);
244
+ expect(r4.y).toBeCloseTo(-6);
245
+ });
246
+
247
+ test('Test Point.scaleFrom', () => {
248
+ const base = new Point();
249
+
250
+ // Scale by 2 from origin
251
+ const pt1 = new Point(5, 0);
252
+ const r1 = pt1.scaleFrom(base, 2);
253
+ expect(r1.x).toBeCloseTo(10);
254
+ expect(r1.y).toBeCloseTo(0);
255
+
256
+ // Scale by 0.5 from origin
257
+ const pt2 = new Point(0, 10);
258
+ const r2 = pt2.scaleFrom(base, 0.5);
259
+ expect(r2.x).toBeCloseTo(0);
260
+ expect(r2.y).toBeCloseTo(5);
261
+
262
+ // Scale by 1 leaves point unchanged
263
+ const pt3 = new Point(3, 7);
264
+ const r3 = pt3.scaleFrom(base, 1);
265
+ expect(r3.x).toBeCloseTo(3);
266
+ expect(r3.y).toBeCloseTo(7);
267
+
268
+ // Scale from an offset base point
269
+ const offsetBase = new Point(10, 10);
270
+ const pt4 = new Point(20, 10);
271
+ const r4 = pt4.scaleFrom(offsetBase, 2);
272
+ expect(r4.x).toBeCloseTo(30);
273
+ expect(r4.y).toBeCloseTo(10);
274
+
275
+ // Scale by 0 collapses point onto base
276
+ const pt5 = new Point(5, 5);
277
+ const r5 = pt5.scaleFrom(offsetBase, 0);
278
+ expect(r5.x).toBeCloseTo(10);
279
+ expect(r5.y).toBeCloseTo(10);
280
+
281
+ // Preserves bulge and sequence
282
+ const pt6 = new Point(4, 0, 0.5, 10);
283
+ const r6 = pt6.scaleFrom(base, 2);
284
+ expect(r6.x).toBeCloseTo(8);
285
+ expect(r6.y).toBeCloseTo(0);
286
+ expect(r6.bulge).toBe(0.5);
287
+ expect(r6.sequence).toBe(10);
288
+ });
289
+
113
290
  test('Test Point.min', () => {
114
291
  const pt1 = new Point(10, 10);
115
292
 
@@ -195,17 +372,17 @@ test('Test Point.project', () => {
195
372
  expect(project1.y).toBe(0);
196
373
 
197
374
  /* 45 degrees */
198
- const project2 = pt1.project(Math.PI/4, 10);
375
+ const project2 = pt1.project(Math.PI / 4, 10);
199
376
  expect(project2.x).toBeCloseTo(7.07);
200
377
  expect(project2.y).toBeCloseTo(7.07);
201
378
 
202
379
  /* 90 degrees */
203
- const project3 = pt1.project(Math.PI/2, 10);
380
+ const project3 = pt1.project(Math.PI / 2, 10);
204
381
  expect(project3.x).toBeCloseTo(0);
205
382
  expect(project3.y).toBeCloseTo(10);
206
383
 
207
384
  /* -90 degrees */
208
- const project4 = pt1.project(-Math.PI/2, 10);
385
+ const project4 = pt1.project(-Math.PI / 2, 10);
209
386
  expect(project4.x).toBeCloseTo(0);
210
387
  expect(project4.y).toBeCloseTo(-10);
211
388
 
@@ -215,13 +392,13 @@ test('Test Point.project', () => {
215
392
  expect(project5.y).toBeCloseTo(0);
216
393
 
217
394
  /* 270 degrees */
218
- const project6 = pt1.project(Math.PI*1.5, 10);
395
+ const project6 = pt1.project(Math.PI * 1.5, 10);
219
396
  expect(project6.x).toBeCloseTo(0);
220
397
  expect(project6.y).toBeCloseTo(-10);
221
398
 
222
399
  const pt2 = new Point(100, 100);
223
400
  /* Non-zero 45 degrees */
224
- const project7 = pt2.project(Math.PI/4, 100);
401
+ const project7 = pt2.project(Math.PI / 4, 100);
225
402
  expect(project7.x).toBeCloseTo(170.710);
226
403
  expect(project7.y).toBeCloseTo(170.710);
227
404
  });
@@ -285,48 +462,177 @@ test('Test Point.closestPointOnLine', () => {
285
462
 
286
463
  const pt4 = new Point(15, 15);
287
464
  const perp4 = pt4.closestPointOnLine(lineStart1, lineEnd1);
288
- expect(perp4).toBe(null);
465
+ expect(perp4).toBe(lineEnd1);
289
466
  });
290
467
 
291
468
  test('Test Point.closestPointOnArc', () => {
292
- const arc = {centre: new Point(), radius: 14.14, startPoint: new Point(10, 10), endPoint: new Point(-10, 10)};
469
+ // clockwise 270 degrees 45 - 135
470
+ // direction: ccw > 0, cw <= 0
471
+ let arc = { centre: new Point(), radius: 14.14, startPoint: new Point(10, 10), endPoint: new Point(-10, 10) };
293
472
 
294
- const pt3 = new Point(5, 5);
295
- const closest1 = pt3.closestPointOnArc(arc.startPoint, arc.endPoint, arc.centre);
296
- expect(closest1.x).toBe(10);
297
- expect(closest1.y).toBe(10);
473
+ let point = new Point(5, 5);
474
+ let closest = point.closestPointOnArc(arc.startPoint, arc.endPoint, arc.centre);
475
+ expect(closest.x).toBe(10);
476
+ expect(closest.y).toBe(10);
298
477
 
299
- const pt4 = new Point(0, 5);
300
- const closest2 = pt4.closestPointOnArc(arc.startPoint, arc.endPoint, arc.centre);
301
- expect(closest2.x).toBe(0);
302
- expect(closest2.y).toBeCloseTo(14.14);
478
+ point = new Point(0, 5);
479
+ closest = point.closestPointOnArc(arc.startPoint, arc.endPoint, arc.centre);
480
+ expect(closest).toBe(null);
303
481
 
304
- const pt5 = new Point(20, 10);
305
- const closest3 = pt5.closestPointOnArc(arc.startPoint, arc.endPoint, arc.centre);
306
- expect(closest3).toBe(null);
482
+ point = new Point(20, 10);
483
+ closest = point.closestPointOnArc(arc.startPoint, arc.endPoint, arc.centre, 0);
484
+ expect(closest.x).toBeCloseTo(12.649);
485
+ expect(closest.y).toBeCloseTo(6.3245);
307
486
 
308
487
  // test circle i.e. start and end points are the same
309
- const pt6 = new Point(5, 5);
310
- const onCircle = pt6.closestPointOnArc(arc.startPoint, arc.startPoint, arc.centre);
488
+ point = new Point(5, 5);
489
+ const onCircle = point.closestPointOnArc(arc.startPoint, arc.startPoint, arc.centre);
311
490
  expect(onCircle.x).toBe(10);
312
491
  expect(onCircle.y).toBe(10);
492
+
493
+
494
+ // counter clockwise 90 degrees 45 - 135
495
+ // direction: ccw > 0, cw <= 0
496
+ arc = { centre: new Point(), radius: 14.14, startPoint: new Point(10, 10), endPoint: new Point(-10, 10), direction: 1 };
497
+
498
+ point = new Point(5, 5);
499
+ closest = point.closestPointOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
500
+ expect(closest.x).toBe(10);
501
+ expect(closest.y).toBe(10);
502
+
503
+ point = new Point(0, 10);
504
+ closest = point.closestPointOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
505
+ expect(closest.x).toBeCloseTo(0);
506
+ expect(closest.y).toBeCloseTo(14.14);
313
507
  });
314
508
 
315
509
 
316
510
  test('Test Point.isOnArc', () => {
317
- const arc = {centre: new Point(), radius: 14.14, startPoint: new Point(10, 10), endPoint: new Point(-10, 10)};
511
+ // clockwise arc 270: 45 - 135
512
+ // direction: ccw > 0, cw <= 0
513
+ let arc = { centre: new Point(), radius: 14.14, startPoint: new Point(10, 10), endPoint: new Point(-10, 10) };
318
514
 
319
- const pt3 = new Point(5, 5);
320
- const onArc1 = pt3.isOnArc(arc.startPoint, arc.endPoint, arc.centre);
321
- expect(onArc1).toBe(true);
515
+ let point = new Point(5, 5);
516
+ let onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre);
517
+ expect(onArc).toBe(true);
322
518
 
323
- const pt4 = new Point(0, 5);
324
- const onArc2 = pt4.isOnArc(arc.startPoint, arc.endPoint, arc.centre);
325
- expect(onArc2).toBe(true);
519
+ point = new Point(0, 5);
520
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre);
521
+ expect(onArc).toBe(false);
326
522
 
327
- const pt5 = new Point(20, 10);
328
- const onArc3 = pt5.isOnArc(arc.startPoint, arc.endPoint, arc.centre);
329
- expect(onArc3).toBe(false);
523
+ point = new Point(20, 10);
524
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre);
525
+ expect(onArc).toBe(true);
526
+
527
+ point = new Point(0, 14.14);
528
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre);
529
+ expect(onArc).toBe(false);
530
+
531
+
532
+ // clockwise arc 90 degrees: 45 - 135
533
+ // direction: ccw > 0, cw <= 0
534
+ arc = { centre: new Point(), radius: 14.14, startPoint: new Point(10, 10), endPoint: new Point(-10, 10), direction: 1 };
535
+
536
+ point = new Point(5, 5);
537
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
538
+ expect(onArc).toBe(true);
539
+
540
+ point = new Point(0, 5);
541
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
542
+ expect(onArc).toBe(true);
543
+
544
+ point = new Point(20, 10);
545
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
546
+ expect(onArc).toBe(false);
547
+
548
+ point = new Point(0, 14.14);
549
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
550
+ expect(onArc).toBe(true);
551
+
552
+ // counter clockwise arc 270 degrees: 135 - 45
553
+ // direction: ccw > 0, cw <= 0
554
+ arc = { centre: new Point(), radius: 14.14, startPoint: new Point(-10, 10), endPoint: new Point(10, 10), direction: 1 };
555
+
556
+ point = new Point(5, 5);
557
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
558
+ expect(onArc).toBe(true);
559
+
560
+ point = new Point(0, 5);
561
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
562
+ expect(onArc).toBe(false);
563
+
564
+ point = new Point(20, 10);
565
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
566
+ expect(onArc).toBe(true);
567
+
568
+ point = new Point(0, 14.14);
569
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
570
+ expect(onArc).toBe(false);
571
+
572
+
573
+ // clockwise arc 180 degrees: 180 - 0
574
+ // direction: ccw > 0, cw <= 0
575
+ arc = { centre: new Point(), radius: 14.14, startPoint: new Point(-10, 0), endPoint: new Point(10, 0), direction: 0 };
576
+
577
+
578
+ point = new Point(5, 0);
579
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
580
+ expect(onArc).toBe(true);
581
+
582
+ point = new Point(-5, 0);
583
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
584
+ expect(onArc).toBe(true);
585
+
586
+ point = new Point(5, 5);
587
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
588
+ expect(onArc).toBe(true);
589
+
590
+ point = new Point(0, 5);
591
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
592
+ expect(onArc).toBe(true);
593
+
594
+ point = new Point(-5, 5);
595
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
596
+ expect(onArc).toBe(true);
597
+
598
+ point = new Point(5, -5);
599
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
600
+ expect(onArc).toBe(false);
601
+
602
+ // Counter clockwise arc 180 degrees: 180 - 0
603
+ // direction: ccw > 0, cw <= 0
604
+ arc = { centre: new Point(), radius: 14.14, startPoint: new Point(-10, 0), endPoint: new Point(10, 0), direction: 1 };
605
+
606
+ point = new Point(5, 0);
607
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
608
+ expect(onArc).toBe(true);
609
+
610
+ point = new Point(-5, 0);
611
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
612
+ expect(onArc).toBe(true);
613
+
614
+ point = new Point(5, 5);
615
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
616
+ expect(onArc).toBe(false);
617
+
618
+ point = new Point(0, 5);
619
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
620
+ expect(onArc).toBe(false);
621
+
622
+ point = new Point(-5, 5);
623
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
624
+ expect(onArc).toBe(false);
625
+
626
+ point = new Point(5, -5);
627
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
628
+ expect(onArc).toBe(true);
629
+
630
+ // clockwise arc 180 degrees: 180 - 0
631
+ // direction: ccw > 0, cw <= 0
632
+ arc = { centre: new Point(0, 5), radius: 5, startPoint: new Point(-5, 5), endPoint: new Point(5, 5), direction: -1 };
633
+ point = new Point(5, 7);
634
+ onArc = point.isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction);
635
+ expect(onArc).toBe(true);
330
636
  });
331
637
 
332
638
  test('Test Point.isOnLine', () => {
@@ -350,6 +656,38 @@ test('Test Point.isOnLine', () => {
350
656
  expect(isOnLine4).toBe(false);
351
657
  });
352
658
 
659
+
660
+ test('Test Point.isInRectangle', () => {
661
+ let pt = new Point(5, 5);
662
+ const bl = new Point(0, 0);
663
+ const br = new Point(10, 0);
664
+ const tr = new Point(10, 10);
665
+ const tl = new Point(0, 10);
666
+
667
+ const isInRect = pt.isInRectangle(bl, br, tr, tl);
668
+ expect(isInRect).toBe(true);
669
+
670
+ // not in rectangle
671
+ pt = new Point(-5, 5);
672
+ const notInRect = pt.isInRectangle(bl, br, tr, tl);
673
+ expect(notInRect).toBe(false);
674
+
675
+ // on edge of rectangle
676
+ pt = new Point(0, 0);
677
+ const onEdgeRect = pt.isInRectangle(bl, br, tr, tl);
678
+ expect(onEdgeRect).toBe(true);
679
+
680
+ // rotated rectangle
681
+ pt = new Point(0, 5);
682
+ const bl2 = new Point(0, 0);
683
+ const br2 = new Point(7, 7);
684
+ const tr2 = new Point(0, 10);
685
+ const tl2 = new Point(-7, 7);
686
+ const isInRotatedRect = pt.isInRectangle(bl2, br2, tr2, tl2);
687
+ expect(isInRotatedRect).toBe(true);
688
+ });
689
+
690
+
353
691
  test('Test Point.bulgeAngle', () => {
354
692
  const angle = Math.PI;
355
693
  const bulge = Math.tan(angle / 4);
@@ -0,0 +1,156 @@
1
+ import { Solid } from '../../core/entities/solid.js';
2
+ import { Point } from '../../core/entities/point.js';
3
+
4
+ import { File } from '../test-helpers/test-helpers.js';
5
+
6
+
7
+ test('Test Solid.boundingBox', () => {
8
+ const solid = new Solid({ points: [new Point(100, 100), new Point(200, 100), new Point(200, 200)] });
9
+ expect(solid.boundingBox().xMin).toBeCloseTo(100);
10
+ expect(solid.boundingBox().xMax).toBeCloseTo(200);
11
+ expect(solid.boundingBox().yMin).toBeCloseTo(100);
12
+ expect(solid.boundingBox().yMax).toBeCloseTo(200);
13
+ });
14
+
15
+
16
+ test('Test Solid.dxf', () => {
17
+ // test solid with 3 points
18
+ const solid = new Solid({ handle: '1', points: [new Point(100, 100), new Point(200, 100), new Point(200, 200)] });
19
+ let file = new File();
20
+ solid.dxf(file);
21
+ // console.log(file.contents);
22
+
23
+ const dxfString = `0
24
+ SOLID
25
+ 5
26
+ 1
27
+ 100
28
+ AcDbEntity
29
+ 100
30
+ AcDbTrace
31
+ 8
32
+ 0
33
+ 10
34
+ 100
35
+ 20
36
+ 100
37
+ 30
38
+ 0.0
39
+ 11
40
+ 200
41
+ 21
42
+ 100
43
+ 31
44
+ 0.0
45
+ 12
46
+ 200
47
+ 22
48
+ 200
49
+ 32
50
+ 0.0
51
+ 13
52
+ 200
53
+ 23
54
+ 200
55
+ 33
56
+ 0.0
57
+ `;
58
+
59
+ expect(file.contents).toEqual(dxfString);
60
+
61
+ // create new entity from entity data to ensure all props are loaded
62
+ const newSolid = new Solid(solid);
63
+ file = new File();
64
+ newSolid.dxf(file);
65
+ expect(file.contents).toEqual(dxfString);
66
+
67
+ // test solid with 4 points
68
+ const solid2 = new Solid({ handle: '1', points: [new Point(100, 100), new Point(200, 100), new Point(200, 200), new Point(300, 300)] });
69
+ const file2 = new File();
70
+ solid2.dxf(file2);
71
+ // console.log(file.contents);
72
+
73
+ const dxfString2 = `0
74
+ SOLID
75
+ 5
76
+ 1
77
+ 100
78
+ AcDbEntity
79
+ 100
80
+ AcDbTrace
81
+ 8
82
+ 0
83
+ 10
84
+ 100
85
+ 20
86
+ 100
87
+ 30
88
+ 0.0
89
+ 11
90
+ 200
91
+ 21
92
+ 100
93
+ 31
94
+ 0.0
95
+ 12
96
+ 200
97
+ 22
98
+ 200
99
+ 32
100
+ 0.0
101
+ 13
102
+ 300
103
+ 23
104
+ 300
105
+ 33
106
+ 0.0
107
+ `;
108
+
109
+ expect(file2.contents).toEqual(dxfString2);
110
+ });
111
+
112
+
113
+ test('Solid.closestPoint returns input point and Infinity', () => {
114
+ const solid = new Solid({ points: [new Point(0, 0), new Point(1, 0), new Point(1, 1), new Point(0, 1)] });
115
+ const testPoint = new Point(5, 5);
116
+ const [closest, dist] = solid.closestPoint(testPoint);
117
+ expect(closest).toBe(testPoint);
118
+ expect(dist).toBe(Infinity);
119
+ });
120
+
121
+ test('Solid.toPolylinePoints returns correct points array', () => {
122
+ const pts = [new Point(0, 0), new Point(1, 0), new Point(1, 1), new Point(0, 1)];
123
+ const solid = new Solid({ points: pts });
124
+ const result = solid.toPolylinePoints();
125
+ expect(result.length).toBe(5);
126
+ expect(result[0].x).toBe(0);
127
+ expect(result[0].y).toBe(0);
128
+ expect(result[4].x).toBe(0);
129
+ expect(result[4].y).toBe(0);
130
+ });
131
+
132
+ test('Test Solid.toPolylinePoints', () => {
133
+ const solid = new Solid({ points: [new Point(100, 100), new Point(200, 100), new Point(200, 200)] });
134
+ const solidPoints = solid.toPolylinePoints();
135
+ expect(solidPoints.length).toBe(4);
136
+ expect(solidPoints[0].x).toBe(100);
137
+ expect(solidPoints[0].y).toBe(100);
138
+ expect(solidPoints[0].bulge).toBe(0);
139
+ expect(solidPoints[1].x).toBe(200);
140
+ expect(solidPoints[1].y).toBe(100);
141
+ expect(solidPoints[2].x).toBe(200);
142
+ expect(solidPoints[2].y).toBe(200);
143
+ // closing point matches first point
144
+ expect(solidPoints[3].x).toBe(100);
145
+ expect(solidPoints[3].y).toBe(100);
146
+ });
147
+
148
+ test('Test Solid.toPolylinePoints with 4 points', () => {
149
+ const solid = new Solid({ points: [new Point(0, 0), new Point(1, 0), new Point(1, 1), new Point(0, 1)] });
150
+ const solidPoints = solid.toPolylinePoints();
151
+ expect(solidPoints.length).toBe(5);
152
+ expect(solidPoints[4].x).toBe(0);
153
+ expect(solidPoints[4].y).toBe(0);
154
+ });
155
+
156
+