@design-core/core 0.0.6 → 50.1.0
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.
- package/.eslintrc.json +4 -0
- package/.github/workflows/DesignCoreQA.yml +3 -0
- package/TODO.md +49 -6
- package/core/core/core.js +0 -3
- package/core/designCore.js +1 -1
- package/core/dimensions/alignedDimension.js +12 -11
- package/core/dimensions/angularDimension.js +38 -37
- package/core/dimensions/{baseCircularDimension.js → circularDimensionBase.js} +22 -21
- package/core/dimensions/diametricDimension.js +14 -13
- package/core/dimensions/dimension.js +62 -55
- package/core/dimensions/{baseDimension.js → dimensionBase.js} +73 -107
- package/core/dimensions/{baseLinearDimension.js → linearDimensionBase.js} +15 -14
- package/core/dimensions/radialDimension.js +12 -11
- package/core/dimensions/rotatedDimension.js +20 -19
- package/core/entities/arc.js +123 -156
- package/core/entities/arctext.js +222 -184
- package/core/entities/circle.js +77 -99
- package/core/entities/entity.js +114 -93
- package/core/entities/hatch.js +346 -273
- package/core/entities/insert.js +68 -83
- package/core/entities/line.js +21 -142
- package/core/entities/lwpolyline.js +16 -11
- package/core/entities/point.js +19 -19
- package/core/entities/polyline.js +7 -7
- package/core/entities/{basePolyline.js → polylineBase.js} +47 -299
- package/core/entities/rectangle.js +3 -1
- package/core/entities/solid.js +6 -15
- package/core/entities/text.js +190 -201
- package/core/lib/auxiliary/rubberBand.js +32 -0
- package/core/lib/auxiliary/selectionWindow.js +63 -0
- package/core/lib/auxiliary/snapPoint.js +113 -0
- package/core/lib/auxiliary/trackingLine.js +76 -0
- package/core/lib/boundingBox.js +11 -11
- package/core/lib/canvas.js +232 -168
- package/core/lib/clipboard.js +9 -3
- package/core/lib/colour.js +16 -0
- package/core/lib/commandLine.js +1 -6
- package/core/lib/commandManager.js +18 -8
- package/core/lib/constants.js +28 -0
- package/core/lib/dxf/dxf.js +15 -14
- package/core/lib/dxf/dxfIterator.js +2 -2
- package/core/lib/entityManager.js +33 -26
- package/core/lib/inputManager.js +36 -12
- package/core/lib/intersect.js +25 -0
- package/core/lib/matrix.js +1 -1
- package/core/lib/patterns.js +9 -2
- package/core/lib/plotOptions.js +67 -0
- package/core/lib/polylineUtils.js +75 -0
- package/core/lib/renderers/cairoRenderer.js +371 -0
- package/core/lib/renderers/canvasRenderer.js +315 -0
- package/core/lib/renderers/pdfRenderer.js +366 -0
- package/core/lib/renderers/rendererBase.js +284 -0
- package/core/lib/renderers/svgRenderer.js +343 -0
- package/core/lib/scene.js +28 -6
- package/core/lib/selectionManager.js +20 -20
- package/core/lib/settings.js +4 -2
- package/core/lib/snapping.js +4 -191
- package/core/lib/stateManager.js +30 -1
- package/core/lib/utils.js +26 -7
- package/core/properties/entityProperties.js +104 -0
- package/core/properties/property.js +106 -2
- package/core/properties/propertyManager.js +60 -44
- package/core/tables/block.js +50 -81
- package/core/tables/dimStyle.js +5 -5
- package/core/tables/endblk.js +1 -1
- package/core/tables/layer.js +8 -0
- package/core/tables/ltypeManager.js +1 -1
- package/core/tables/styleManagerBase.js +3 -2
- package/core/tables/tableManagerBase.js +8 -3
- package/core/tables/vport.js +2 -2
- package/core/tools/chamfer.js +117 -143
- package/core/tools/chamferFilletBase.js +138 -37
- package/core/tools/copy.js +11 -11
- package/core/tools/copybase.js +3 -3
- package/core/tools/copyclip.js +3 -3
- package/core/tools/cornerEntity.js +2 -2
- package/core/tools/cutclip.js +3 -3
- package/core/tools/explode.js +7 -7
- package/core/tools/extend.js +138 -25
- package/core/tools/fillet.js +92 -189
- package/core/tools/matchProp.js +3 -12
- package/core/tools/mirror.js +15 -14
- package/core/tools/move.js +8 -8
- package/core/tools/offset.js +31 -33
- package/core/tools/pasteclip.js +1 -1
- package/core/tools/purge.js +10 -10
- package/core/tools/rotate.js +19 -16
- package/core/tools/scale.js +7 -7
- package/core/tools/trim.js +271 -29
- package/core/tools/zoom.js +1 -1
- package/cspell.json +321 -0
- package/jest.config.js +6 -0
- package/package.json +5 -3
- package/test/dimensions/alignedDimension.test.js +17 -10
- package/test/dimensions/angularDimension.test.js +13 -13
- package/test/dimensions/diametricDimension.test.js +15 -15
- package/test/dimensions/dimension.test.js +12 -12
- package/test/dimensions/{baseDimension.test.js → dimensionBase.test.js} +73 -12
- package/test/dimensions/linearDimensionBase.test.js +62 -0
- package/test/dimensions/radialDimension.test.js +15 -15
- package/test/dimensions/rotatedDimension.test.js +18 -11
- package/test/entities/arc.test.js +83 -86
- package/test/entities/arctext.test.js +184 -57
- package/test/entities/circle.test.js +68 -96
- package/test/entities/entity.test.js +42 -8
- package/test/entities/hatch.test.js +569 -96
- package/test/entities/insert.test.js +99 -4
- package/test/entities/line.test.js +15 -41
- package/test/entities/lwpolyline.test.js +104 -0
- package/test/entities/point.test.js +3 -3
- package/test/entities/polyline.test.js +11 -0
- package/test/entities/{basePolyline.test.js → polylineBase.test.js} +192 -57
- package/test/entities/rectangle.test.js +11 -0
- package/test/entities/solid.test.js +1 -1
- package/test/entities/text.test.js +302 -77
- package/test/integration/exportIntegration.reference.dxf +9 -9
- package/test/integration/exportIntegration.test.js +5 -5
- package/test/integration/intersectionIntegration.test.js +4 -5
- package/test/integration/pdfRendererIntegration.reference.pdf +17709 -0
- package/test/integration/pdfRendererIntegration.test.js +61 -0
- package/test/integration/svgRendererIntegration.reference.svg +3343 -0
- package/test/integration/svgRendererIntegration.test.js +61 -0
- package/test/integration/userInputIntegration.reference.dxf +1165 -105
- package/test/integration/userInputIntegration.test.js +239 -132
- package/test/lib/boundingBox.test.js +3 -3
- package/test/lib/canvas.test.js +744 -125
- package/test/lib/constants.test.js +27 -0
- package/test/lib/entityManager.test.js +4 -4
- package/test/lib/inputManager.test.js +81 -20
- package/test/lib/intersect.test.js +83 -0
- package/test/lib/plotOptions.test.js +179 -0
- package/test/lib/rubberBand.test.js +84 -0
- package/test/lib/scene.test.js +9 -9
- package/test/lib/selectionManager.test.js +3 -3
- package/test/lib/settings.test.js +5 -6
- package/test/lib/snapping.test.js +72 -130
- package/test/lib/stateManager.test.js +7 -7
- package/test/lib/utils.test.js +36 -2
- package/test/properties/entityProperties.test.js +132 -0
- package/test/properties/property.test.js +53 -0
- package/test/properties/propertyManager.test.js +25 -25
- package/test/renderers/canvasRenderer.test.js +317 -0
- package/test/renderers/pdfRenderer.test.js +271 -0
- package/test/renderers/rendererBase.test.js +213 -0
- package/test/renderers/svgRenderer.test.js +326 -0
- package/test/tables/block.test.js +92 -13
- package/test/tables/endblk.test.js +2 -2
- package/test/tables/layer.test.js +30 -0
- package/test/tables/layerManager.test.js +2 -2
- package/test/test-helpers/hatchGridRenderer.js +180 -0
- package/test/test-helpers/test-helpers.js +158 -6
- package/test/tools/chamfer.test.js +273 -51
- package/test/tools/chamferFilletBase.test.js +125 -36
- package/test/tools/copy.test.js +8 -8
- package/test/tools/copybase.test.js +2 -2
- package/test/tools/copyclip.test.js +2 -2
- package/test/tools/cornerEntity.test.js +8 -8
- package/test/tools/cutclip.test.js +2 -2
- package/test/tools/erase.test.js +6 -6
- package/test/tools/explode.test.js +5 -5
- package/test/tools/extend.test.js +373 -42
- package/test/tools/fillet.test.js +230 -49
- package/test/tools/matchProp.test.js +11 -11
- package/test/tools/mirror.test.js +39 -39
- package/test/tools/move.test.js +7 -7
- package/test/tools/offset.test.js +222 -55
- package/test/tools/pasteclip.test.js +5 -5
- package/test/tools/purge.test.js +4 -4
- package/test/tools/rotate.test.js +39 -9
- package/test/tools/scale.test.js +33 -33
- package/test/tools/trim.test.js +579 -53
- package/test/tools/zoom.test.js +12 -12
- package/core/lib/selectionWindow.js +0 -83
|
@@ -4,6 +4,7 @@ import { Offset } from '../../core/tools/offset.js';
|
|
|
4
4
|
import { Line } from '../../core/entities/line.js';
|
|
5
5
|
import { Arc } from '../../core/entities/arc.js';
|
|
6
6
|
import { Circle } from '../../core/entities/circle.js';
|
|
7
|
+
import { DesignCore } from '../../core/designCore.js';
|
|
7
8
|
import { expect, jest } from '@jest/globals';
|
|
8
9
|
|
|
9
10
|
const core = new Core();
|
|
@@ -13,7 +14,7 @@ const inputScenarios = [
|
|
|
13
14
|
desc: 'offset line to the left by distance 5',
|
|
14
15
|
entityType: 'Line',
|
|
15
16
|
entityData: { points: [new Point(0, 0), new Point(10, 0)] },
|
|
16
|
-
inputs: [5, {
|
|
17
|
+
inputs: [5, { selectedEntityIndex: 0 }, new Point(5, 5)],
|
|
17
18
|
checkIndex: 1,
|
|
18
19
|
expectedPoints: [new Point(0, 5), new Point(10, 5)],
|
|
19
20
|
},
|
|
@@ -21,7 +22,7 @@ const inputScenarios = [
|
|
|
21
22
|
desc: 'offset line to the right by distance 5',
|
|
22
23
|
entityType: 'Line',
|
|
23
24
|
entityData: { points: [new Point(0, 0), new Point(10, 0)] },
|
|
24
|
-
inputs: [5, {
|
|
25
|
+
inputs: [5, { selectedEntityIndex: 0 }, new Point(5, -5)],
|
|
25
26
|
checkIndex: 1,
|
|
26
27
|
expectedPoints: [new Point(0, -5), new Point(10, -5)],
|
|
27
28
|
},
|
|
@@ -29,7 +30,7 @@ const inputScenarios = [
|
|
|
29
30
|
desc: 'offset circle outward by distance 5',
|
|
30
31
|
entityType: 'Circle',
|
|
31
32
|
entityData: { points: [new Point(0, 0), new Point(10, 0)] },
|
|
32
|
-
inputs: [5, {
|
|
33
|
+
inputs: [5, { selectedEntityIndex: 0 }, new Point(20, 0)],
|
|
33
34
|
checkIndex: 1,
|
|
34
35
|
checkRadius: 15,
|
|
35
36
|
},
|
|
@@ -37,7 +38,7 @@ const inputScenarios = [
|
|
|
37
38
|
desc: 'offset circle inward by distance 3',
|
|
38
39
|
entityType: 'Circle',
|
|
39
40
|
entityData: { points: [new Point(0, 0), new Point(10, 0)] },
|
|
40
|
-
inputs: [3, {
|
|
41
|
+
inputs: [3, { selectedEntityIndex: 0 }, new Point(5, 0)],
|
|
41
42
|
checkIndex: 1,
|
|
42
43
|
checkRadius: 7,
|
|
43
44
|
},
|
|
@@ -45,7 +46,7 @@ const inputScenarios = [
|
|
|
45
46
|
desc: 'offset arc outward by distance 5',
|
|
46
47
|
entityType: 'Arc',
|
|
47
48
|
entityData: { points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)] },
|
|
48
|
-
inputs: [5, {
|
|
49
|
+
inputs: [5, { selectedEntityIndex: 0 }, new Point(20, 0)],
|
|
49
50
|
checkIndex: 1,
|
|
50
51
|
checkRadius: 15,
|
|
51
52
|
},
|
|
@@ -57,7 +58,7 @@ test.each(inputScenarios)('Offset.execute handles $desc', async (scenario) => {
|
|
|
57
58
|
core.scene.clear();
|
|
58
59
|
core.scene.selectionManager.reset();
|
|
59
60
|
|
|
60
|
-
core.scene.
|
|
61
|
+
core.scene.addEntity(entityType, entityData);
|
|
61
62
|
|
|
62
63
|
const origInputManager = core.scene.inputManager;
|
|
63
64
|
let callCount = 0;
|
|
@@ -99,7 +100,7 @@ test('Offset.execute - cancel at distance prompt does not offset', async () => {
|
|
|
99
100
|
core.scene.clear();
|
|
100
101
|
core.scene.selectionManager.reset();
|
|
101
102
|
|
|
102
|
-
core.scene.
|
|
103
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
103
104
|
|
|
104
105
|
const origInputManager = core.scene.inputManager;
|
|
105
106
|
core.scene.inputManager = {
|
|
@@ -120,7 +121,7 @@ test('Offset.execute - cancel at entity selection does not offset', async () =>
|
|
|
120
121
|
core.scene.clear();
|
|
121
122
|
core.scene.selectionManager.reset();
|
|
122
123
|
|
|
123
|
-
core.scene.
|
|
124
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
124
125
|
|
|
125
126
|
const origInputManager = core.scene.inputManager;
|
|
126
127
|
let callCount = 0;
|
|
@@ -147,11 +148,11 @@ test('Offset.execute - cancel at side point does not offset', async () => {
|
|
|
147
148
|
core.scene.clear();
|
|
148
149
|
core.scene.selectionManager.reset();
|
|
149
150
|
|
|
150
|
-
core.scene.
|
|
151
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
151
152
|
|
|
152
153
|
const origInputManager = core.scene.inputManager;
|
|
153
154
|
let callCount = 0;
|
|
154
|
-
const inputs = [5, {
|
|
155
|
+
const inputs = [5, { selectedEntityIndex: 0 }]; // distance + selection, then undefined
|
|
155
156
|
core.scene.inputManager = {
|
|
156
157
|
requestInput: async () => {
|
|
157
158
|
if (callCount < inputs.length) {
|
|
@@ -166,8 +167,8 @@ test('Offset.execute - cancel at side point does not offset', async () => {
|
|
|
166
167
|
await offset.execute();
|
|
167
168
|
|
|
168
169
|
expect(core.scene.entities.count()).toBe(1);
|
|
169
|
-
//
|
|
170
|
-
expect(offset.
|
|
170
|
+
// selectedEntity must be cleared so a stale action() call cannot create an unintended entity
|
|
171
|
+
expect(offset.selectedEntity).toBeNull();
|
|
171
172
|
|
|
172
173
|
core.scene.inputManager = origInputManager;
|
|
173
174
|
});
|
|
@@ -176,14 +177,14 @@ test('Offset.execute - entity count increases by one per offset', async () => {
|
|
|
176
177
|
core.scene.clear();
|
|
177
178
|
core.scene.selectionManager.reset();
|
|
178
179
|
|
|
179
|
-
core.scene.
|
|
180
|
-
core.scene.
|
|
180
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
181
|
+
core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
181
182
|
|
|
182
183
|
const entityCount = core.scene.entities.count();
|
|
183
184
|
|
|
184
185
|
const origInputManager = core.scene.inputManager;
|
|
185
186
|
let callCount = 0;
|
|
186
|
-
const inputs = [5, {
|
|
187
|
+
const inputs = [5, { selectedEntityIndex: 0 }, new Point(5, 5)];
|
|
187
188
|
core.scene.inputManager = {
|
|
188
189
|
requestInput: async () => {
|
|
189
190
|
if (callCount < inputs.length) {
|
|
@@ -209,10 +210,10 @@ test('Test Offset.action - offset line perpendicular', () => {
|
|
|
209
210
|
core.scene.clear();
|
|
210
211
|
core.scene.selectionManager.reset();
|
|
211
212
|
|
|
212
|
-
core.scene.
|
|
213
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
213
214
|
|
|
214
215
|
const offset = new Offset();
|
|
215
|
-
offset.
|
|
216
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
216
217
|
core.scene.headers.offsetDistance = 5;
|
|
217
218
|
offset.points = [new Point(5, 5)]; // side point above line
|
|
218
219
|
|
|
@@ -231,10 +232,10 @@ test('Test Offset.action - offset vertical line', () => {
|
|
|
231
232
|
core.scene.clear();
|
|
232
233
|
core.scene.selectionManager.reset();
|
|
233
234
|
|
|
234
|
-
core.scene.
|
|
235
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
|
|
235
236
|
|
|
236
237
|
const offset = new Offset();
|
|
237
|
-
offset.
|
|
238
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
238
239
|
core.scene.headers.offsetDistance = 3;
|
|
239
240
|
offset.points = [new Point(5, 5)]; // side point to the right
|
|
240
241
|
|
|
@@ -251,10 +252,10 @@ test('Test Offset.action - offset circle outward', () => {
|
|
|
251
252
|
core.scene.clear();
|
|
252
253
|
core.scene.selectionManager.reset();
|
|
253
254
|
|
|
254
|
-
core.scene.
|
|
255
|
+
core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
255
256
|
|
|
256
257
|
const offset = new Offset();
|
|
257
|
-
offset.
|
|
258
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
258
259
|
core.scene.headers.offsetDistance = 5;
|
|
259
260
|
offset.points = [new Point(20, 0)]; // outside the circle
|
|
260
261
|
|
|
@@ -267,17 +268,17 @@ test('Test Offset.action - offset circle outward', () => {
|
|
|
267
268
|
expect(newCircle.points[0].x).toBeCloseTo(0);
|
|
268
269
|
expect(newCircle.points[0].y).toBeCloseTo(0);
|
|
269
270
|
// New radius should be 15
|
|
270
|
-
expect(newCircle.radius).toBeCloseTo(15);
|
|
271
|
+
expect(newCircle.getProperty('radius')).toBeCloseTo(15);
|
|
271
272
|
});
|
|
272
273
|
|
|
273
274
|
test('Test Offset.action - offset circle inward', () => {
|
|
274
275
|
core.scene.clear();
|
|
275
276
|
core.scene.selectionManager.reset();
|
|
276
277
|
|
|
277
|
-
core.scene.
|
|
278
|
+
core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
278
279
|
|
|
279
280
|
const offset = new Offset();
|
|
280
|
-
offset.
|
|
281
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
281
282
|
core.scene.headers.offsetDistance = 3;
|
|
282
283
|
offset.points = [new Point(5, 0)]; // inside the circle
|
|
283
284
|
|
|
@@ -286,17 +287,17 @@ test('Test Offset.action - offset circle inward', () => {
|
|
|
286
287
|
const newCircle = core.scene.entities.get(1);
|
|
287
288
|
expect(newCircle.points[0].x).toBeCloseTo(0);
|
|
288
289
|
expect(newCircle.points[0].y).toBeCloseTo(0);
|
|
289
|
-
expect(newCircle.radius).toBeCloseTo(7);
|
|
290
|
+
expect(newCircle.getProperty('radius')).toBeCloseTo(7);
|
|
290
291
|
});
|
|
291
292
|
|
|
292
293
|
test('Test Offset.action - offset circle inward returns null when radius would be zero', () => {
|
|
293
294
|
core.scene.clear();
|
|
294
295
|
core.scene.selectionManager.reset();
|
|
295
296
|
|
|
296
|
-
core.scene.
|
|
297
|
+
core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
297
298
|
|
|
298
299
|
const offset = new Offset();
|
|
299
|
-
offset.
|
|
300
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
300
301
|
core.scene.headers.offsetDistance = 15; // larger than radius
|
|
301
302
|
offset.points = [new Point(5, 0)]; // inside
|
|
302
303
|
|
|
@@ -310,14 +311,14 @@ test('Test Offset.action - offset arc outward preserves angles', () => {
|
|
|
310
311
|
core.scene.clear();
|
|
311
312
|
core.scene.selectionManager.reset();
|
|
312
313
|
|
|
313
|
-
const
|
|
314
|
-
const start =
|
|
315
|
-
const end =
|
|
314
|
+
const centre = new Point(0, 0);
|
|
315
|
+
const start = centre.project(0, 10); // radius 10
|
|
316
|
+
const end = centre.project(Math.PI / 2, 10);
|
|
316
317
|
|
|
317
|
-
core.scene.
|
|
318
|
+
core.scene.addEntity('Arc', { points: [centre, start, end] });
|
|
318
319
|
|
|
319
320
|
const offset = new Offset();
|
|
320
|
-
offset.
|
|
321
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
321
322
|
core.scene.headers.offsetDistance = 5;
|
|
322
323
|
offset.points = [new Point(20, 0)]; // outside
|
|
323
324
|
|
|
@@ -329,8 +330,8 @@ test('Test Offset.action - offset arc outward preserves angles', () => {
|
|
|
329
330
|
expect(newRadius).toBeCloseTo(15);
|
|
330
331
|
|
|
331
332
|
// Start and end angles should be preserved
|
|
332
|
-
const originalStartAngle =
|
|
333
|
-
const originalEndAngle =
|
|
333
|
+
const originalStartAngle = centre.angle(start);
|
|
334
|
+
const originalEndAngle = centre.angle(end);
|
|
334
335
|
const newStartAngle = newArc.points[0].angle(newArc.points[1]);
|
|
335
336
|
const newEndAngle = newArc.points[0].angle(newArc.points[2]);
|
|
336
337
|
expect(newStartAngle).toBeCloseTo(originalStartAngle);
|
|
@@ -341,10 +342,10 @@ test('Test Offset.action - unsupported entity type does not create new entity',
|
|
|
341
342
|
core.scene.clear();
|
|
342
343
|
core.scene.selectionManager.reset();
|
|
343
344
|
|
|
344
|
-
core.scene.
|
|
345
|
+
core.scene.addEntity('Rectangle', { points: [new Point(0, 0), new Point(10, 10)] });
|
|
345
346
|
|
|
346
347
|
const offset = new Offset();
|
|
347
|
-
offset.
|
|
348
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
348
349
|
core.scene.headers.offsetDistance = 5;
|
|
349
350
|
offset.points = [new Point(20, 20)];
|
|
350
351
|
|
|
@@ -396,7 +397,7 @@ test('Test Offset.getThroughDistance - circle', () => {
|
|
|
396
397
|
|
|
397
398
|
test('Test Offset.getThroughDistance - arc uses same radial distance as circle', () => {
|
|
398
399
|
const offset = new Offset();
|
|
399
|
-
// Arc:
|
|
400
|
+
// Arc: centre (0,0), radius 10
|
|
400
401
|
const entity = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)] });
|
|
401
402
|
|
|
402
403
|
// Point inside the arc radius
|
|
@@ -408,7 +409,7 @@ test('Test Offset.getThroughDistance - arc uses same radial distance as circle',
|
|
|
408
409
|
test('Test Offset.getThroughDistance - polyline uses closestPoint distance', () => {
|
|
409
410
|
core.scene.clear();
|
|
410
411
|
core.scene.selectionManager.reset();
|
|
411
|
-
core.scene.
|
|
412
|
+
core.scene.addEntity('Polyline', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
412
413
|
const entity = core.scene.entities.get(0);
|
|
413
414
|
|
|
414
415
|
const offset = new Offset();
|
|
@@ -425,13 +426,13 @@ test('Test Offset.getThroughDistance - unsupported entity returns 0', () => {
|
|
|
425
426
|
|
|
426
427
|
// ─── action edge cases ────────────────────────────────────────────────────────
|
|
427
428
|
|
|
428
|
-
test('Test Offset.action - returns early when
|
|
429
|
+
test('Test Offset.action - returns early when selectedEntity is null', () => {
|
|
429
430
|
core.scene.clear();
|
|
430
431
|
core.scene.selectionManager.reset();
|
|
431
|
-
core.scene.
|
|
432
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
432
433
|
|
|
433
434
|
const offset = new Offset();
|
|
434
|
-
offset.
|
|
435
|
+
offset.selectedEntity = null;
|
|
435
436
|
core.scene.headers.offsetDistance = 5;
|
|
436
437
|
offset.action();
|
|
437
438
|
|
|
@@ -441,10 +442,10 @@ test('Test Offset.action - returns early when selectedItem is null', () => {
|
|
|
441
442
|
test('Test Offset.action - returns early when offsetDistance is 0', () => {
|
|
442
443
|
core.scene.clear();
|
|
443
444
|
core.scene.selectionManager.reset();
|
|
444
|
-
core.scene.
|
|
445
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
445
446
|
|
|
446
447
|
const offset = new Offset();
|
|
447
|
-
offset.
|
|
448
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
448
449
|
core.scene.headers.offsetDistance = 0;
|
|
449
450
|
offset.points = [new Point(5, 5)];
|
|
450
451
|
offset.action();
|
|
@@ -458,13 +459,13 @@ test('Test Offset.getOffsetPoints - arc inward offset shrinks radius', () => {
|
|
|
458
459
|
const offset = new Offset();
|
|
459
460
|
const entity = new Arc({ points: [new Point(0, 0), new Point(10, 0), new Point(0, 10)] });
|
|
460
461
|
|
|
461
|
-
// sidePoint inside the arc (between
|
|
462
|
+
// sidePoint inside the arc (between centre and circumference)
|
|
462
463
|
const result = offset.getOffsetPoints(entity, new Point(5, 0), 3);
|
|
463
464
|
|
|
464
465
|
expect(result).not.toBeNull();
|
|
465
466
|
const rebuilt = new Arc({});
|
|
466
467
|
rebuilt.fromPolylinePoints(result);
|
|
467
|
-
expect(rebuilt.radius).toBeCloseTo(7);
|
|
468
|
+
expect(rebuilt.getProperty('radius')).toBeCloseTo(7);
|
|
468
469
|
});
|
|
469
470
|
|
|
470
471
|
test('Test Offset.getOffsetPoints - arc returns null when inward offset collapses radius', () => {
|
|
@@ -537,7 +538,7 @@ test('Test Offset.getOffsetPolylinePoints - closed rectangle offset outward', ()
|
|
|
537
538
|
test('Test Offset.getOffsetPolylinePoints - arc segment (bulge) offset outward grows radius', () => {
|
|
538
539
|
const offset = new Offset();
|
|
539
540
|
// CW semicircle (bulge=-1) from (0,0) to (10,0): traces the TOP half through (5,5)
|
|
540
|
-
//
|
|
541
|
+
// centre=(5,0), radius=5
|
|
541
542
|
const start = new Point(0, 0, -1); // bulge=-1 → CW, arc goes upward
|
|
542
543
|
const end = new Point(10, 0);
|
|
543
544
|
const points = [start, end];
|
|
@@ -576,7 +577,7 @@ test('Offset.findJunction - parallel line/line falls back to midpoint', () => {
|
|
|
576
577
|
|
|
577
578
|
test('Offset.findJunction - arc/line returns circle-line intersection', () => {
|
|
578
579
|
const offset = new Offset();
|
|
579
|
-
// Arc: A=(-5,0) B=(5,0) bulge=1 →
|
|
580
|
+
// Arc: A=(-5,0) B=(5,0) bulge=1 → centre (0,0), radius 5 via bulgeCentrePoint
|
|
580
581
|
// Line: vertical at x=3 → circle intersects at (3,4) and (3,-4)
|
|
581
582
|
const seg = { A: new Point(-5, 0), B: new Point(5, 0), bulge: 1 };
|
|
582
583
|
const nextSeg = { A: new Point(3, 5), B: new Point(3, 10), bulge: 0 };
|
|
@@ -600,7 +601,7 @@ test('Offset.findJunction - line/arc returns line-circle intersection', () => {
|
|
|
600
601
|
|
|
601
602
|
test('Offset.findJunction - arc/arc returns circle-circle intersection', () => {
|
|
602
603
|
const offset = new Offset();
|
|
603
|
-
// Circle 1: A=(-4,0) B=(4,0) bulge=1 →
|
|
604
|
+
// Circle 1: A=(-4,0) B=(4,0) bulge=1 → centre (0,0), radius 4 via bulgeCentrePoint
|
|
604
605
|
// Circle 2: A=(0,4) B=(6,4) bulge=1 → center (3,4), radius 3 via bulgeCentrePoint
|
|
605
606
|
// Intersections: (0,4) and (96/25, 28/25)
|
|
606
607
|
const seg = { A: new Point(-4, 0), B: new Point(4, 0), bulge: 1 };
|
|
@@ -628,7 +629,7 @@ test('Offset.findJunction - non-intersecting arc/arc falls back to midpoint', ()
|
|
|
628
629
|
test('Offset.execute - single preselection skips entity selection prompt', async () => {
|
|
629
630
|
core.scene.clear();
|
|
630
631
|
core.scene.selectionManager.reset();
|
|
631
|
-
core.scene.
|
|
632
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
632
633
|
// Preselect the entity
|
|
633
634
|
core.scene.selectionManager.addToSelectionSet(0);
|
|
634
635
|
|
|
@@ -657,8 +658,8 @@ test('Offset.execute - single preselection skips entity selection prompt', async
|
|
|
657
658
|
test('Offset.execute - multi-preselection clears selection and prompts', async () => {
|
|
658
659
|
core.scene.clear();
|
|
659
660
|
core.scene.selectionManager.reset();
|
|
660
|
-
core.scene.
|
|
661
|
-
core.scene.
|
|
661
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
662
|
+
core.scene.addEntity('Line', { points: [new Point(0, 5), new Point(10, 5)] });
|
|
662
663
|
// Preselect two entities
|
|
663
664
|
core.scene.selectionManager.addToSelectionSet(0);
|
|
664
665
|
core.scene.selectionManager.addToSelectionSet(1);
|
|
@@ -666,7 +667,7 @@ test('Offset.execute - multi-preselection clears selection and prompts', async (
|
|
|
666
667
|
const origInputManager = core.scene.inputManager;
|
|
667
668
|
let callCount = 0;
|
|
668
669
|
// After clearing, distance + selection + side-point
|
|
669
|
-
const inputs = [5, {
|
|
670
|
+
const inputs = [5, { selectedEntityIndex: 0 }, new Point(5, 5)];
|
|
670
671
|
const offset = new Offset();
|
|
671
672
|
core.scene.inputManager = {
|
|
672
673
|
requestInput: async () => {
|
|
@@ -690,7 +691,7 @@ test('Offset.execute - multi-preselection clears selection and prompts', async (
|
|
|
690
691
|
test('Offset.execute - distance <= 0 notifies and does not offset', async () => {
|
|
691
692
|
core.scene.clear();
|
|
692
693
|
core.scene.selectionManager.reset();
|
|
693
|
-
core.scene.
|
|
694
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
694
695
|
|
|
695
696
|
const notifySpy = jest.spyOn(core, 'notify').mockImplementation(() => {});
|
|
696
697
|
|
|
@@ -714,12 +715,12 @@ test('Offset.execute - distance <= 0 notifies and does not offset', async () =>
|
|
|
714
715
|
test('Offset.execute - Through mode offsets entity to the through point distance', async () => {
|
|
715
716
|
core.scene.clear();
|
|
716
717
|
core.scene.selectionManager.reset();
|
|
717
|
-
core.scene.
|
|
718
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
718
719
|
|
|
719
720
|
const origInputManager = core.scene.inputManager;
|
|
720
721
|
let callCount = 0;
|
|
721
722
|
// 'Through' → select entity at index 0 → through point at (5, 7) → undefined exits loop
|
|
722
|
-
const inputs = ['Through', {
|
|
723
|
+
const inputs = ['Through', { selectedEntityIndex: 0 }, new Point(5, 7)];
|
|
723
724
|
|
|
724
725
|
const offset = new Offset();
|
|
725
726
|
core.scene.inputManager = {
|
|
@@ -746,3 +747,169 @@ test('Offset.execute - Through mode offsets entity to the through point distance
|
|
|
746
747
|
|
|
747
748
|
core.scene.inputManager = origInputManager;
|
|
748
749
|
});
|
|
750
|
+
|
|
751
|
+
// ─── register ─────────────────────────────────────────────────────────────────
|
|
752
|
+
|
|
753
|
+
test('Offset.register returns correct metadata', () => {
|
|
754
|
+
const reg = Offset.register();
|
|
755
|
+
expect(reg.command).toBe('Offset');
|
|
756
|
+
expect(reg.shortcut).toBe('O');
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
// ─── preview ──────────────────────────────────────────────────────────────────
|
|
760
|
+
|
|
761
|
+
test('Offset.preview does not add preview entity when selectedEntity is null', () => {
|
|
762
|
+
core.scene.clear();
|
|
763
|
+
DesignCore.Scene.previewEntities.clear();
|
|
764
|
+
core.scene.headers.offsetDistance = 5;
|
|
765
|
+
|
|
766
|
+
const offset = new Offset();
|
|
767
|
+
offset.selectedEntity = null;
|
|
768
|
+
expect(() => offset.preview()).not.toThrow();
|
|
769
|
+
expect(DesignCore.Scene.previewEntities.count()).toBe(0);
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
test('Offset.preview does not add preview entity when offsetDistance is 0', () => {
|
|
773
|
+
core.scene.clear();
|
|
774
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
775
|
+
DesignCore.Scene.previewEntities.clear();
|
|
776
|
+
core.scene.headers.offsetDistance = 0;
|
|
777
|
+
|
|
778
|
+
const savedPointOnScene = DesignCore.Mouse.pointOnScene;
|
|
779
|
+
DesignCore.Mouse.pointOnScene = () => new Point(5, 5);
|
|
780
|
+
|
|
781
|
+
const offset = new Offset();
|
|
782
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
783
|
+
offset.preview();
|
|
784
|
+
|
|
785
|
+
DesignCore.Mouse.pointOnScene = savedPointOnScene;
|
|
786
|
+
expect(DesignCore.Scene.previewEntities.count()).toBe(0);
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
test('Offset.preview adds entity to previewEntities for a valid line', () => {
|
|
790
|
+
core.scene.clear();
|
|
791
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
792
|
+
DesignCore.Scene.previewEntities.clear();
|
|
793
|
+
core.scene.headers.offsetDistance = 5;
|
|
794
|
+
|
|
795
|
+
const savedPointOnScene = DesignCore.Mouse.pointOnScene;
|
|
796
|
+
DesignCore.Mouse.pointOnScene = () => new Point(5, 5);
|
|
797
|
+
|
|
798
|
+
const offset = new Offset();
|
|
799
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
800
|
+
offset.preview();
|
|
801
|
+
|
|
802
|
+
DesignCore.Mouse.pointOnScene = savedPointOnScene;
|
|
803
|
+
expect(DesignCore.Scene.previewEntities.count()).toBe(1);
|
|
804
|
+
expect(DesignCore.Scene.previewEntities.get(0).points[0].y).toBeCloseTo(5);
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// ─── Lwpolyline action ─────────────────────────────────────────────────────────
|
|
808
|
+
|
|
809
|
+
test('Test Offset.action - offset open Lwpolyline', () => {
|
|
810
|
+
core.scene.clear();
|
|
811
|
+
core.scene.selectionManager.reset();
|
|
812
|
+
|
|
813
|
+
// L-shape: (0,0) → (10,0) → (10,10)
|
|
814
|
+
core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10)] });
|
|
815
|
+
|
|
816
|
+
const offset = new Offset();
|
|
817
|
+
offset.selectedEntity = core.scene.entities.get(0);
|
|
818
|
+
core.scene.headers.offsetDistance = 1;
|
|
819
|
+
offset.points = [new Point(5, 2)]; // above the bottom segment → offset upward/left
|
|
820
|
+
|
|
821
|
+
offset.action();
|
|
822
|
+
|
|
823
|
+
expect(core.scene.entities.count()).toBe(2);
|
|
824
|
+
const newPoly = core.scene.entities.get(1);
|
|
825
|
+
expect(newPoly.points[0].x).toBeCloseTo(0);
|
|
826
|
+
expect(newPoly.points[0].y).toBeCloseTo(1);
|
|
827
|
+
expect(newPoly.points[2].x).toBeCloseTo(9);
|
|
828
|
+
expect(newPoly.points[2].y).toBeCloseTo(10);
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
test('Test Offset.action - offset closed Lwpolyline outward', () => {
|
|
832
|
+
core.scene.clear();
|
|
833
|
+
core.scene.selectionManager.reset();
|
|
834
|
+
|
|
835
|
+
// Closed square: 5 points where first === last → constructor sets flag=1
|
|
836
|
+
core.scene.addEntity('Lwpolyline', {
|
|
837
|
+
points: [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10), new Point(0, 0)],
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
const polyline = core.scene.entities.get(0);
|
|
841
|
+
expect(polyline.flags.hasFlag(1)).toBe(true); // confirm closed
|
|
842
|
+
|
|
843
|
+
const offset = new Offset();
|
|
844
|
+
offset.selectedEntity = polyline;
|
|
845
|
+
core.scene.headers.offsetDistance = 1;
|
|
846
|
+
offset.points = [new Point(-5, 5)]; // outside the left edge
|
|
847
|
+
|
|
848
|
+
offset.action();
|
|
849
|
+
|
|
850
|
+
expect(core.scene.entities.count()).toBe(2);
|
|
851
|
+
const newPoly = core.scene.entities.get(1);
|
|
852
|
+
expect(newPoly.flags.hasFlag(1)).toBe(true); // closed flag preserved
|
|
853
|
+
const xs = newPoly.points.map((p) => p.x);
|
|
854
|
+
const ys = newPoly.points.map((p) => p.y);
|
|
855
|
+
expect(Math.min(...xs)).toBeCloseTo(-1);
|
|
856
|
+
expect(Math.max(...xs)).toBeCloseTo(11);
|
|
857
|
+
expect(Math.min(...ys)).toBeCloseTo(-1);
|
|
858
|
+
expect(Math.max(...ys)).toBeCloseTo(11);
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
// ─── closed inward offset ──────────────────────────────────────────────────────
|
|
862
|
+
|
|
863
|
+
test('Test Offset.getOffsetPolylinePoints - closed rectangle offset inward', () => {
|
|
864
|
+
const offset = new Offset();
|
|
865
|
+
const points = [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)];
|
|
866
|
+
|
|
867
|
+
// sidePoint inside the rectangle
|
|
868
|
+
const result = offset.getOffsetPolylinePoints(points, true, new Point(5, 5), 1);
|
|
869
|
+
|
|
870
|
+
expect(result).not.toBeNull();
|
|
871
|
+
expect(result.length).toBe(4);
|
|
872
|
+
const xs = result.map((p) => p.x);
|
|
873
|
+
const ys = result.map((p) => p.y);
|
|
874
|
+
expect(Math.min(...xs)).toBeCloseTo(1);
|
|
875
|
+
expect(Math.max(...xs)).toBeCloseTo(9);
|
|
876
|
+
expect(Math.min(...ys)).toBeCloseTo(1);
|
|
877
|
+
expect(Math.max(...ys)).toBeCloseTo(9);
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
// ─── Through mode with circle ──────────────────────────────────────────────────
|
|
881
|
+
|
|
882
|
+
test('Offset.execute - Through mode offsets circle to the through point', async () => {
|
|
883
|
+
core.scene.clear();
|
|
884
|
+
core.scene.selectionManager.reset();
|
|
885
|
+
|
|
886
|
+
// Circle: centre (0,0), radius 10
|
|
887
|
+
core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
888
|
+
|
|
889
|
+
const origInputManager = core.scene.inputManager;
|
|
890
|
+
let callCount = 0;
|
|
891
|
+
// Through → select circle → through point at (15,0) → undefined exits loop
|
|
892
|
+
const inputs = ['Through', { selectedEntityIndex: 0 }, new Point(15, 0)];
|
|
893
|
+
|
|
894
|
+
const offset = new Offset();
|
|
895
|
+
core.scene.inputManager = {
|
|
896
|
+
requestInput: async () => {
|
|
897
|
+
if (callCount < inputs.length) return inputs[callCount++];
|
|
898
|
+
},
|
|
899
|
+
actionCommand: () => {
|
|
900
|
+
offset.action();
|
|
901
|
+
},
|
|
902
|
+
executeCommand: () => {},
|
|
903
|
+
reset: () => {},
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
await offset.execute();
|
|
907
|
+
|
|
908
|
+
// getThroughDistance(circle at radius 10, throughPoint at r=15) = |15 - 10| = 5
|
|
909
|
+
expect(core.scene.headers.offsetDistance).toBeCloseTo(5);
|
|
910
|
+
expect(core.scene.entities.count()).toBe(2);
|
|
911
|
+
const newCircle = core.scene.entities.get(1);
|
|
912
|
+
expect(newCircle.getProperty('radius')).toBeCloseTo(15); // original 10 + outward 5
|
|
913
|
+
|
|
914
|
+
core.scene.inputManager = origInputManager;
|
|
915
|
+
});
|
|
@@ -12,7 +12,7 @@ describe('Pasteclip Tool', () => {
|
|
|
12
12
|
beforeEach(() => {
|
|
13
13
|
DesignCore.Scene.entities.clear();
|
|
14
14
|
DesignCore.Scene.selectionManager.reset();
|
|
15
|
-
DesignCore.Scene.
|
|
15
|
+
DesignCore.Scene.previewEntities.clear();
|
|
16
16
|
DesignCore.Clipboard.Entities = []; // also resets basePoint
|
|
17
17
|
});
|
|
18
18
|
|
|
@@ -57,8 +57,8 @@ describe('Pasteclip Tool', () => {
|
|
|
57
57
|
|
|
58
58
|
const tool = new Pasteclip();
|
|
59
59
|
tool.preview();
|
|
60
|
-
expect(DesignCore.Scene.
|
|
61
|
-
const tempLine = DesignCore.Scene.
|
|
60
|
+
expect(DesignCore.Scene.previewEntities.count()).toBeGreaterThan(0);
|
|
61
|
+
const tempLine = DesignCore.Scene.previewEntities.get(0);
|
|
62
62
|
const deltaX = targetPoint.x - basePoint.x;
|
|
63
63
|
const deltaY = targetPoint.y - basePoint.y;
|
|
64
64
|
expect(tempLine.points[0].x).toBe(line.points[0].x + deltaX);
|
|
@@ -94,7 +94,7 @@ describe('Pasteclip Tool', () => {
|
|
|
94
94
|
expect(pasted.points[0].y).toBe(0);
|
|
95
95
|
|
|
96
96
|
// Verify pasted entity has a unique handle
|
|
97
|
-
expect(newEntity.handle).toBeDefined();
|
|
98
|
-
expect(newEntity.handle).not.toBe(line.handle);
|
|
97
|
+
expect(newEntity.getProperty('handle')).toBeDefined();
|
|
98
|
+
expect(newEntity.getProperty('handle')).not.toBe(line.getProperty('handle'));
|
|
99
99
|
});
|
|
100
100
|
});
|
package/test/tools/purge.test.js
CHANGED
|
@@ -29,10 +29,10 @@ beforeEach(() => {
|
|
|
29
29
|
|
|
30
30
|
const data = { points: [point1, point2], layer: 'layerWithItems', lineType: 'ltypeWithItems' };
|
|
31
31
|
|
|
32
|
-
DesignCore.Scene.
|
|
33
|
-
DesignCore.Scene.
|
|
34
|
-
DesignCore.Scene.
|
|
35
|
-
DesignCore.Scene.
|
|
32
|
+
DesignCore.Scene.addEntity('Insert', { blockName: 'blockWithItems' });
|
|
33
|
+
DesignCore.Scene.addEntity('Line', data);
|
|
34
|
+
DesignCore.Scene.addEntity('Circle', data);
|
|
35
|
+
DesignCore.Scene.addEntity('Text', data);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
test('Test purge.action', () => {
|
|
@@ -49,7 +49,7 @@ test.each(inputScenarios)('Rotate.execute handles $desc', async (scenario) => {
|
|
|
49
49
|
// create line
|
|
50
50
|
const pointOne = new Point(10, 0);
|
|
51
51
|
const pointTwo = new Point(20, 0);
|
|
52
|
-
core.scene.
|
|
52
|
+
core.scene.addEntity('Line', { points: [pointOne, pointTwo] });
|
|
53
53
|
|
|
54
54
|
// select line
|
|
55
55
|
core.scene.selectionManager.addToSelectionSet(0);
|
|
@@ -57,9 +57,9 @@ test.each(inputScenarios)('Rotate.execute handles $desc', async (scenario) => {
|
|
|
57
57
|
const rotate = new Rotate();
|
|
58
58
|
await rotate.execute();
|
|
59
59
|
|
|
60
|
-
expect(core.scene.
|
|
60
|
+
expect(core.scene.previewEntities.count()).toBe(0); // no temp entities before preview
|
|
61
61
|
rotate.preview(); // to set up any preview state if needed
|
|
62
|
-
expect(core.scene.
|
|
62
|
+
expect(core.scene.auxiliaryEntities.count()).toBeGreaterThanOrEqual(1); // preview should create rubber-band
|
|
63
63
|
|
|
64
64
|
rotate.action();
|
|
65
65
|
|
|
@@ -78,12 +78,12 @@ test.each(inputScenarios)('Rotate.execute handles $desc', async (scenario) => {
|
|
|
78
78
|
|
|
79
79
|
test('Test Rotate.action', () => {
|
|
80
80
|
// Add items to scene
|
|
81
|
-
core.scene.
|
|
82
|
-
core.scene.
|
|
83
|
-
core.scene.
|
|
84
|
-
core.scene.
|
|
85
|
-
core.scene.
|
|
86
|
-
core.scene.
|
|
81
|
+
core.scene.addEntity('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
82
|
+
core.scene.addEntity('Circle', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
83
|
+
core.scene.addEntity('Polyline', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
84
|
+
core.scene.addEntity('Arc', { points: [new Point(10, 0), new Point(10, 10), new Point(0, 10)] });
|
|
85
|
+
core.scene.addEntity('Rectangle', { points: [new Point(10, 0), new Point(0, 10)] });
|
|
86
|
+
core.scene.addEntity('Text', { points: [new Point(10, 0), new Point(0, 10)], height: 10, rotation: 0, string: 'text test' });
|
|
87
87
|
|
|
88
88
|
// Add items to selection set
|
|
89
89
|
for (let i = 0; i < core.scene.entities.count(); i++) {
|
|
@@ -131,3 +131,33 @@ test('Test Rotate.action', () => {
|
|
|
131
131
|
expect(core.scene.entities.get(i).points[0].y).toBeCloseTo(0);
|
|
132
132
|
}
|
|
133
133
|
});
|
|
134
|
+
|
|
135
|
+
test('Rotate.execute with reference - resets inputPoint to rotation centre', async () => {
|
|
136
|
+
const origInputManager = core.scene.inputManager;
|
|
137
|
+
|
|
138
|
+
const basePoint = new Point(10, 0);
|
|
139
|
+
// inputs: basePoint, 'r' (reference option), refBase, refEnd, then undefined to exit the while loop
|
|
140
|
+
const inputs = [basePoint, 'r', new Point(5, 0), new Point(5, 10), undefined];
|
|
141
|
+
let callCount = 0;
|
|
142
|
+
const mockInputManager = {
|
|
143
|
+
requestInput: async () => {
|
|
144
|
+
if (callCount < inputs.length) return inputs[callCount++];
|
|
145
|
+
},
|
|
146
|
+
executeCommand: () => {},
|
|
147
|
+
inputPoint: null,
|
|
148
|
+
};
|
|
149
|
+
core.scene.inputManager = mockInputManager;
|
|
150
|
+
|
|
151
|
+
core.scene.clear();
|
|
152
|
+
core.scene.addEntity('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
153
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
154
|
+
|
|
155
|
+
const rotate = new Rotate();
|
|
156
|
+
await rotate.execute();
|
|
157
|
+
|
|
158
|
+
// After the reference sequence completes, inputPoint must be reset to the
|
|
159
|
+
// rotation centre (points[0]) so the tracking line uses the correct origin.
|
|
160
|
+
expect(mockInputManager.inputPoint).toEqual(basePoint);
|
|
161
|
+
|
|
162
|
+
core.scene.inputManager = origInputManager;
|
|
163
|
+
});
|