@design-core/core 0.0.7 → 51.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/.github/workflows/DesignCoreQA.yml +3 -0
- package/core/designCore.js +1 -1
- package/core/dimensions/alignedDimension.js +7 -7
- package/core/dimensions/angularDimension.js +32 -32
- package/core/dimensions/{baseCircularDimension.js → circularDimensionBase.js} +19 -19
- package/core/dimensions/diametricDimension.js +10 -10
- package/core/dimensions/dimension.js +42 -42
- package/core/dimensions/{baseDimension.js → dimensionBase.js} +17 -17
- package/core/dimensions/{baseLinearDimension.js → linearDimensionBase.js} +9 -9
- package/core/dimensions/radialDimension.js +8 -8
- package/core/dimensions/rotatedDimension.js +8 -8
- package/core/entities/arc.js +22 -22
- package/core/entities/arctext.js +13 -13
- package/core/entities/circle.js +7 -7
- package/core/entities/hatch.js +210 -40
- package/core/entities/insert.js +11 -6
- package/core/entities/point.js +19 -19
- package/core/entities/polyline.js +3 -3
- package/core/entities/{basePolyline.js → polylineBase.js} +18 -18
- package/core/entities/text.js +4 -4
- package/core/lib/boundingBox.js +11 -11
- package/core/lib/canvas.js +13 -6
- package/core/lib/clipboard.js +2 -2
- package/core/lib/dxf/dxf.js +11 -11
- package/core/lib/dxf/dxfIterator.js +2 -2
- package/core/lib/entityManager.js +19 -19
- package/core/lib/inputManager.js +1 -1
- package/core/lib/matrix.js +1 -1
- package/core/lib/patterns.js +1 -1
- package/core/lib/polylineUtils.js +9 -9
- package/core/lib/renderers/cairoRenderer.js +5 -5
- package/core/lib/renderers/canvasRenderer.js +4 -4
- package/core/lib/renderers/pdfRenderer.js +7 -7
- package/core/lib/renderers/rendererBase.js +1 -1
- package/core/lib/scene.js +1 -1
- package/core/lib/selectionManager.js +18 -18
- package/core/lib/utils.js +5 -5
- package/core/properties/entityProperties.js +2 -1
- package/core/properties/flags.js +12 -0
- package/core/properties/property.js +8 -3
- package/core/properties/propertyManager.js +52 -37
- package/core/tables/block.js +50 -46
- package/core/tables/dimStyle.js +5 -5
- package/core/tables/ltypeManager.js +1 -1
- package/core/tables/vport.js +2 -2
- package/core/tools/chamfer.js +6 -6
- package/core/tools/chamferFilletBase.js +4 -4
- package/core/tools/copy.js +8 -8
- 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 +6 -6
- package/core/tools/extend.js +13 -13
- package/core/tools/fillet.js +6 -6
- package/core/tools/matchProp.js +1 -1
- package/core/tools/mirror.js +11 -11
- package/core/tools/move.js +5 -5
- package/core/tools/offset.js +29 -29
- package/core/tools/purge.js +10 -10
- package/core/tools/rotate.js +16 -16
- package/core/tools/scale.js +6 -6
- package/core/tools/trim.js +15 -15
- package/cspell.json +323 -0
- package/package.json +1 -1
- package/test/dimensions/alignedDimension.test.js +3 -3
- package/test/dimensions/angularDimension.test.js +7 -7
- package/test/dimensions/diametricDimension.test.js +9 -9
- package/test/dimensions/dimension.test.js +12 -12
- package/test/dimensions/{baseDimension.test.js → dimensionBase.test.js} +12 -12
- package/test/dimensions/{baseLinearDimension.test.js → linearDimensionBase.test.js} +7 -7
- package/test/dimensions/radialDimension.test.js +9 -9
- package/test/dimensions/rotatedDimension.test.js +4 -4
- package/test/entities/arc.test.js +10 -10
- package/test/entities/arctext.test.js +6 -6
- package/test/entities/circle.test.js +18 -18
- package/test/entities/hatch.test.js +362 -39
- package/test/entities/insert.test.js +9 -9
- package/test/entities/point.test.js +3 -3
- package/test/entities/{basePolyline.test.js → polylineBase.test.js} +131 -62
- package/test/entities/text.test.js +19 -19
- package/test/integration/exportIntegration.test.js +3 -3
- package/test/integration/userInputIntegration.test.js +5 -5
- package/test/lib/boundingBox.test.js +3 -3
- package/test/lib/canvas.test.js +9 -9
- package/test/lib/clipboard.test.js +73 -0
- package/test/lib/inputManager.test.js +4 -4
- package/test/lib/scene.test.js +9 -9
- package/test/lib/selectionManager.test.js +3 -3
- package/test/lib/snapping.test.js +1 -1
- package/test/properties/flags.test.js +24 -0
- package/test/properties/propertyManager.test.js +93 -22
- package/test/renderers/pdfRenderer.test.js +2 -2
- package/test/tables/block.test.js +63 -14
- package/test/tables/layerManager.test.js +2 -2
- package/test/test-helpers/hatchGridRenderer.js +3 -3
- package/test/test-helpers/test-helpers.js +6 -6
- package/test/tools/chamfer.test.js +60 -60
- package/test/tools/chamferFilletBase.test.js +36 -36
- package/test/tools/copy.test.js +6 -6
- 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 +2 -2
- package/test/tools/extend.test.js +84 -84
- package/test/tools/fillet.test.js +62 -62
- package/test/tools/matchProp.test.js +6 -6
- package/test/tools/mirror.test.js +26 -26
- package/test/tools/move.test.js +7 -7
- package/test/tools/offset.test.js +65 -65
- package/test/tools/purge.test.js +4 -4
- package/test/tools/rotate.test.js +10 -10
- package/test/tools/scale.test.js +28 -28
- package/test/tools/trim.test.js +109 -109
- package/test/tools/zoom.test.js +15 -17
package/test/tools/trim.test.js
CHANGED
|
@@ -24,9 +24,9 @@ test.each(inputScenarios)('Trim.execute handles $desc', async (scenario) => {
|
|
|
24
24
|
// clear all scene entities
|
|
25
25
|
core.scene.clear();
|
|
26
26
|
// create line
|
|
27
|
-
core.scene.
|
|
27
|
+
core.scene.addEntity('Line', { points: [new Point(), new Point(10, 0)] });
|
|
28
28
|
// create circle
|
|
29
|
-
core.scene.
|
|
29
|
+
core.scene.addEntity('Circle', { points: [new Point(), new Point(10, 0)] });
|
|
30
30
|
// select line
|
|
31
31
|
core.scene.selectionManager.selectionSet.selectionSet.push(0);
|
|
32
32
|
|
|
@@ -35,7 +35,7 @@ test.each(inputScenarios)('Trim.execute handles $desc', async (scenario) => {
|
|
|
35
35
|
await trim.execute();
|
|
36
36
|
|
|
37
37
|
expect(trim.selectedBoundaryItems[0]).toEqual(core.scene.entities.get(0));
|
|
38
|
-
expect(trim.
|
|
38
|
+
expect(trim.selectedEntity).toBe(core.scene.entities.get(1));
|
|
39
39
|
expect(actionSpy).toHaveBeenCalled();
|
|
40
40
|
}, { extraMethods: { actionCommand: () => actionSpy() } });
|
|
41
41
|
});
|
|
@@ -60,12 +60,12 @@ test('Test Trim.action', () => {
|
|
|
60
60
|
// clear all scene entities
|
|
61
61
|
core.scene.clear();
|
|
62
62
|
// Add items to scene
|
|
63
|
-
core.scene.
|
|
64
|
-
core.scene.
|
|
63
|
+
core.scene.addEntity('Line', { points: [lineOneStart, lineOneEnd] });
|
|
64
|
+
core.scene.addEntity('Line', { points: [lineTwoStart, lineTwoEnd] });
|
|
65
65
|
// Select boundary item
|
|
66
66
|
trim.selectedBoundaryItems = [core.scene.entities.get(0)];
|
|
67
67
|
// select item to trim
|
|
68
|
-
trim.
|
|
68
|
+
trim.selectedEntity = core.scene.entities.get(1);
|
|
69
69
|
// set mouse location - required for trim
|
|
70
70
|
core.mouse.setPosFromScenePoint(new Point(10, 50));
|
|
71
71
|
// Perform trim
|
|
@@ -91,12 +91,12 @@ test('Test Trim.action', () => {
|
|
|
91
91
|
// clear scene items
|
|
92
92
|
core.scene.clear();
|
|
93
93
|
// Add items to scene
|
|
94
|
-
core.scene.
|
|
95
|
-
core.scene.
|
|
94
|
+
core.scene.addEntity('Line', { points: [lineOneStart, lineOneEnd] });
|
|
95
|
+
core.scene.addEntity('Line', { points: [lineTwoStart, lineTwoEnd] });
|
|
96
96
|
// Select boundary item
|
|
97
97
|
trim.selectedBoundaryItems = [core.scene.entities.get(0)];
|
|
98
98
|
// select item to trim
|
|
99
|
-
trim.
|
|
99
|
+
trim.selectedEntity = core.scene.entities.get(1);
|
|
100
100
|
// set mouse location - required for trim
|
|
101
101
|
core.mouse.setPosFromScenePoint(new Point(-10, 50));
|
|
102
102
|
// Perform trim
|
|
@@ -122,12 +122,12 @@ test('Test Trim.action', () => {
|
|
|
122
122
|
// clear scene items
|
|
123
123
|
core.scene.clear();
|
|
124
124
|
// Add items to scene
|
|
125
|
-
core.scene.
|
|
126
|
-
core.scene.
|
|
125
|
+
core.scene.addEntity('Line', { points: [lineOneStart, lineOneEnd] });
|
|
126
|
+
core.scene.addEntity('Line', { points: [lineTwoStart, lineTwoEnd] });
|
|
127
127
|
// Select boundary item
|
|
128
128
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
129
129
|
// select item to trim
|
|
130
|
-
trim.
|
|
130
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
131
131
|
// set mouse location - required for trim
|
|
132
132
|
core.mouse.setPosFromScenePoint(new Point(0, 60));
|
|
133
133
|
// Perform trim
|
|
@@ -155,12 +155,12 @@ test('Test Trim.action', () => {
|
|
|
155
155
|
// clear scene items
|
|
156
156
|
core.scene.clear();
|
|
157
157
|
// Add items to scene
|
|
158
|
-
core.scene.
|
|
159
|
-
core.scene.
|
|
158
|
+
core.scene.addEntity('Line', { points: [lineOneStart, lineOneEnd] });
|
|
159
|
+
core.scene.addEntity('Line', { points: [lineTwoStart, lineTwoEnd] });
|
|
160
160
|
// Select boundary item
|
|
161
161
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
162
162
|
// select item to trim
|
|
163
|
-
trim.
|
|
163
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
164
164
|
// set mouse location - required for trim
|
|
165
165
|
core.mouse.setPosFromScenePoint(new Point(0, 30));
|
|
166
166
|
// Perform trim
|
|
@@ -189,12 +189,12 @@ test('Test Trim.action', () => {
|
|
|
189
189
|
// clear scene items
|
|
190
190
|
core.scene.clear();
|
|
191
191
|
// Add items to scene
|
|
192
|
-
core.scene.
|
|
193
|
-
core.scene.
|
|
192
|
+
core.scene.addEntity('Line', { points: [lineOneStart, lineOneEnd] });
|
|
193
|
+
core.scene.addEntity('Line', { points: [crossingLineStart, crossingLineEnd] });
|
|
194
194
|
// Select boundary item
|
|
195
195
|
trim.selectedBoundaryItems = [core.scene.entities.get(0)];
|
|
196
196
|
// select item to trim
|
|
197
|
-
trim.
|
|
197
|
+
trim.selectedEntity = core.scene.entities.get(1);
|
|
198
198
|
// set mouse location - required for trim
|
|
199
199
|
core.mouse.setPosFromScenePoint(new Point(25, 75));
|
|
200
200
|
// Perform trim
|
|
@@ -220,12 +220,12 @@ test('Test Trim.action', () => {
|
|
|
220
220
|
// clear scene items
|
|
221
221
|
core.scene.clear();
|
|
222
222
|
// Add items to scene
|
|
223
|
-
core.scene.
|
|
224
|
-
core.scene.
|
|
223
|
+
core.scene.addEntity('Line', { points: [lineOneStart, lineOneEnd] });
|
|
224
|
+
core.scene.addEntity('Line', { points: [crossingLineStart, crossingLineEnd] });
|
|
225
225
|
// Select boundary item
|
|
226
226
|
trim.selectedBoundaryItems = [core.scene.entities.get(0)];
|
|
227
227
|
// select item to trim
|
|
228
|
-
trim.
|
|
228
|
+
trim.selectedEntity = core.scene.entities.get(1);
|
|
229
229
|
// set mouse location - required for trim
|
|
230
230
|
core.mouse.setPosFromScenePoint(new Point(-25, 25));
|
|
231
231
|
// Perform trim
|
|
@@ -253,11 +253,11 @@ test('Test Trim.action polyline - trim end segment', () => {
|
|
|
253
253
|
const trim = new Trim();
|
|
254
254
|
core.scene.clear();
|
|
255
255
|
|
|
256
|
-
core.scene.
|
|
257
|
-
core.scene.
|
|
256
|
+
core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0), new Point(50, 0), new Point(100, 0)] });
|
|
257
|
+
core.scene.addEntity('Line', { points: [new Point(75, -50), new Point(75, 50)] });
|
|
258
258
|
|
|
259
259
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
260
|
-
trim.
|
|
260
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
261
261
|
core.mouse.setPosFromScenePoint(new Point(90, 0));
|
|
262
262
|
trim.action();
|
|
263
263
|
|
|
@@ -296,11 +296,11 @@ test('Test Trim.action polyline - trim start segment', () => {
|
|
|
296
296
|
const trim = new Trim();
|
|
297
297
|
core.scene.clear();
|
|
298
298
|
|
|
299
|
-
core.scene.
|
|
300
|
-
core.scene.
|
|
299
|
+
core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0), new Point(50, 0), new Point(100, 0)] });
|
|
300
|
+
core.scene.addEntity('Line', { points: [new Point(25, -50), new Point(25, 50)] });
|
|
301
301
|
|
|
302
302
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
303
|
-
trim.
|
|
303
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
304
304
|
core.mouse.setPosFromScenePoint(new Point(10, 0));
|
|
305
305
|
trim.action();
|
|
306
306
|
|
|
@@ -334,12 +334,12 @@ test('Test Trim.action polyline - trim middle segment', () => {
|
|
|
334
334
|
const trim = new Trim();
|
|
335
335
|
core.scene.clear();
|
|
336
336
|
|
|
337
|
-
core.scene.
|
|
338
|
-
core.scene.
|
|
339
|
-
core.scene.
|
|
337
|
+
core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0), new Point(50, 0), new Point(100, 0), new Point(150, 0)] });
|
|
338
|
+
core.scene.addEntity('Line', { points: [new Point(25, -50), new Point(25, 50)] });
|
|
339
|
+
core.scene.addEntity('Line', { points: [new Point(75, -50), new Point(75, 50)] });
|
|
340
340
|
|
|
341
341
|
trim.selectedBoundaryItems = [core.scene.entities.get(1), core.scene.entities.get(2)];
|
|
342
|
-
trim.
|
|
342
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
343
343
|
core.mouse.setPosFromScenePoint(new Point(50, 0));
|
|
344
344
|
trim.action();
|
|
345
345
|
|
|
@@ -376,7 +376,7 @@ test('Test Trim.action polyline - trim middle segment', () => {
|
|
|
376
376
|
test('Test Trim.action polyline - trim bulged arc segment', () => {
|
|
377
377
|
// Polyline: (0,0) with bulge=1 -> arc -> (100,0) -> straight -> (200,0)
|
|
378
378
|
// With bulge=1 (CCW) the semicircular arc goes through (50,-50)
|
|
379
|
-
// Arc
|
|
379
|
+
// Arc centre: (50,0), radius: 50
|
|
380
380
|
// Boundary: vertical line at x=50
|
|
381
381
|
// Intersection at (50,-50) — bottom of semicircle
|
|
382
382
|
// Mouse at (75,-40) — right of intersection on the arc
|
|
@@ -385,11 +385,11 @@ test('Test Trim.action polyline - trim bulged arc segment', () => {
|
|
|
385
385
|
const trim = new Trim();
|
|
386
386
|
core.scene.clear();
|
|
387
387
|
|
|
388
|
-
core.scene.
|
|
389
|
-
core.scene.
|
|
388
|
+
core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0, 1), new Point(100, 0), new Point(200, 0)] });
|
|
389
|
+
core.scene.addEntity('Line', { points: [new Point(50, -100), new Point(50, 100)] });
|
|
390
390
|
|
|
391
391
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
392
|
-
trim.
|
|
392
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
393
393
|
core.mouse.setPosFromScenePoint(new Point(75, -40));
|
|
394
394
|
trim.action();
|
|
395
395
|
|
|
@@ -434,7 +434,7 @@ test('Trim.preview does not throw', () => {
|
|
|
434
434
|
|
|
435
435
|
test('Trim.preview returns early when no boundary items set', () => {
|
|
436
436
|
core.scene.clear();
|
|
437
|
-
core.scene.
|
|
437
|
+
core.scene.addEntity('Line', { points: [new Point(0, -10), new Point(0, 10)] });
|
|
438
438
|
DesignCore.Scene.previewEntities.clear();
|
|
439
439
|
|
|
440
440
|
const trim = new Trim();
|
|
@@ -446,8 +446,8 @@ test('Trim.preview returns early when no boundary items set', () => {
|
|
|
446
446
|
|
|
447
447
|
test('Trim.preview returns early when findClosestItem returns undefined', () => {
|
|
448
448
|
core.scene.clear();
|
|
449
|
-
core.scene.
|
|
450
|
-
core.scene.
|
|
449
|
+
core.scene.addEntity('Line', { points: [new Point(0, -10), new Point(0, 10)] });
|
|
450
|
+
core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(10, 0)] });
|
|
451
451
|
DesignCore.Scene.previewEntities.clear();
|
|
452
452
|
|
|
453
453
|
const trim = new Trim();
|
|
@@ -463,8 +463,8 @@ test('Trim.preview returns early when findClosestItem returns undefined', () =>
|
|
|
463
463
|
test('Trim.preview returns early when hovered entity does not implement trim', () => {
|
|
464
464
|
// Text does not override Entity.trim() — preview must not emit a notification.
|
|
465
465
|
core.scene.clear();
|
|
466
|
-
core.scene.
|
|
467
|
-
core.scene.
|
|
466
|
+
core.scene.addEntity('Line', { points: [new Point(0, -10), new Point(0, 10)] }); // boundary
|
|
467
|
+
core.scene.addEntity('Text', { points: [new Point(5, 0)], string: 'hello' }); // unsupported
|
|
468
468
|
DesignCore.Scene.previewEntities.clear();
|
|
469
469
|
|
|
470
470
|
const notifySpy = jest.spyOn(core, 'notify');
|
|
@@ -486,12 +486,12 @@ test('Trim.preview returns early when hovered entity does not implement trim', (
|
|
|
486
486
|
test('Trim.preview returns early when hovered entity has no intersections with boundary', () => {
|
|
487
487
|
// Two parallel horizontal lines — no intersection with the vertical boundary
|
|
488
488
|
core.scene.clear();
|
|
489
|
-
core.scene.
|
|
490
|
-
core.scene.
|
|
489
|
+
core.scene.addEntity('Line', { points: [new Point(0, -10), new Point(0, 10)] }); // boundary (vertical)
|
|
490
|
+
core.scene.addEntity('Line', { points: [new Point(-10, 5), new Point(10, 5)] }); // hovered (horizontal, no intersection with boundary)
|
|
491
491
|
DesignCore.Scene.previewEntities.clear();
|
|
492
492
|
|
|
493
493
|
// Boundary is entity 0; hovered is entity 1 — they are parallel on the y-axis, so no intersection
|
|
494
|
-
core.scene.
|
|
494
|
+
core.scene.addEntity('Line', { points: [new Point(-10, 20), new Point(10, 20)] }); // extra line, no intersection
|
|
495
495
|
|
|
496
496
|
const trim = new Trim();
|
|
497
497
|
trim.selectedBoundaryItems = [core.scene.entities.get(2)]; // horizontal boundary — parallel to hovered
|
|
@@ -510,8 +510,8 @@ test('Trim.preview populates previewEntities when entity can be trimmed', () =>
|
|
|
510
510
|
// Vertical boundary at x=0; horizontal line from (-10,0) to (10,0) is the hovered entity.
|
|
511
511
|
// Mouse at (5,0) → trims the right half, leaving the left half as a preview.
|
|
512
512
|
core.scene.clear();
|
|
513
|
-
core.scene.
|
|
514
|
-
core.scene.
|
|
513
|
+
core.scene.addEntity('Line', { points: [new Point(0, -10), new Point(0, 10)] }); // boundary
|
|
514
|
+
core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(10, 0)] }); // hovered
|
|
515
515
|
DesignCore.Scene.previewEntities.clear();
|
|
516
516
|
|
|
517
517
|
const trim = new Trim();
|
|
@@ -531,7 +531,7 @@ test('Trim.preview populates previewEntities when entity can be trimmed', () =>
|
|
|
531
531
|
test('Trim.execute returns early when boundary input is undefined', async () => {
|
|
532
532
|
core.scene.clear();
|
|
533
533
|
core.scene.selectionManager.reset();
|
|
534
|
-
core.scene.
|
|
534
|
+
core.scene.addEntity('Line', { points: [new Point(), new Point(10, 0)] });
|
|
535
535
|
|
|
536
536
|
await withMockInput(core.scene, [undefined], async () => {
|
|
537
537
|
const trim = new Trim();
|
|
@@ -543,8 +543,8 @@ test('Trim.execute returns early when boundary input is undefined', async () =>
|
|
|
543
543
|
test('Trim.execute exits selection loop when selection input is undefined', async () => {
|
|
544
544
|
core.scene.clear();
|
|
545
545
|
core.scene.selectionManager.reset();
|
|
546
|
-
core.scene.
|
|
547
|
-
core.scene.
|
|
546
|
+
core.scene.addEntity('Line', { points: [new Point(), new Point(10, 0)] });
|
|
547
|
+
core.scene.addEntity('Circle', { points: [new Point(), new Point(5, 0)] });
|
|
548
548
|
// preselect first item as boundary
|
|
549
549
|
core.scene.selectionManager.selectionSet.selectionSet.push(0);
|
|
550
550
|
|
|
@@ -560,9 +560,9 @@ test('Trim.execute exits selection loop when selection input is undefined', asyn
|
|
|
560
560
|
test('Trim.execute calls actionCommand once per trim selection', async () => {
|
|
561
561
|
core.scene.clear();
|
|
562
562
|
core.scene.selectionManager.reset();
|
|
563
|
-
core.scene.
|
|
564
|
-
core.scene.
|
|
565
|
-
core.scene.
|
|
563
|
+
core.scene.addEntity('Line', { points: [new Point(0, -10), new Point(0, 10)] });
|
|
564
|
+
core.scene.addEntity('Circle', { points: [new Point(-5, 0), new Point(0, 0)] });
|
|
565
|
+
core.scene.addEntity('Circle', { points: [new Point(-5, 0), new Point(0, 0)] });
|
|
566
566
|
// preselect line as boundary
|
|
567
567
|
core.scene.selectionManager.selectionSet.selectionSet.push(0);
|
|
568
568
|
|
|
@@ -579,11 +579,11 @@ test('Trim.execute calls actionCommand once per trim selection', async () => {
|
|
|
579
579
|
);
|
|
580
580
|
});
|
|
581
581
|
|
|
582
|
-
test('Trim.action does nothing when
|
|
582
|
+
test('Trim.action does nothing when selectedEntity is null', () => {
|
|
583
583
|
core.scene.clear();
|
|
584
|
-
core.scene.
|
|
584
|
+
core.scene.addEntity('Line', { points: [new Point(), new Point(10, 0)] });
|
|
585
585
|
const trim = new Trim();
|
|
586
|
-
trim.
|
|
586
|
+
trim.selectedEntity = null;
|
|
587
587
|
trim.selectedBoundaryItems = [core.scene.entities.get(0)];
|
|
588
588
|
|
|
589
589
|
expect(() => trim.action()).not.toThrow();
|
|
@@ -591,24 +591,24 @@ test('Trim.action does nothing when selectedItem is null', () => {
|
|
|
591
591
|
|
|
592
592
|
test('Trim.action does nothing when selectedBoundaryItems is empty', () => {
|
|
593
593
|
core.scene.clear();
|
|
594
|
-
core.scene.
|
|
594
|
+
core.scene.addEntity('Line', { points: [new Point(), new Point(10, 0)] });
|
|
595
595
|
const trim = new Trim();
|
|
596
|
-
trim.
|
|
596
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
597
597
|
trim.selectedBoundaryItems = [];
|
|
598
598
|
|
|
599
599
|
expect(() => trim.action()).not.toThrow();
|
|
600
|
-
expect(trim.
|
|
600
|
+
expect(trim.selectedEntity).toBeNull();
|
|
601
601
|
});
|
|
602
602
|
|
|
603
603
|
test('Trim.action notifies NOTRIM when selected entity lacks fromPolylinePoints', () => {
|
|
604
604
|
// Use a stub entity that has toPolylinePoints but no fromPolylinePoints.
|
|
605
605
|
// action() must notify and not throw.
|
|
606
606
|
core.scene.clear();
|
|
607
|
-
core.scene.
|
|
607
|
+
core.scene.addEntity('Line', { points: [new Point(0, -10), new Point(0, 10)] }); // boundary
|
|
608
608
|
|
|
609
609
|
const trim = new Trim();
|
|
610
610
|
trim.selectedBoundaryItems = [core.scene.entities.get(0)];
|
|
611
|
-
trim.
|
|
611
|
+
trim.selectedEntity = {
|
|
612
612
|
type: 'FakeEntity',
|
|
613
613
|
toPolylinePoints: () => [new Point(-5, 0), new Point(5, 0)],
|
|
614
614
|
// deliberately no fromPolylinePoints
|
|
@@ -618,7 +618,7 @@ test('Trim.action notifies NOTRIM when selected entity lacks fromPolylinePoints'
|
|
|
618
618
|
trim.action();
|
|
619
619
|
|
|
620
620
|
expect(notifySpy).toHaveBeenCalledWith(expect.stringContaining(Strings.Message.NOTRIM));
|
|
621
|
-
expect(trim.
|
|
621
|
+
expect(trim.selectedEntity).toBeNull();
|
|
622
622
|
notifySpy.mockRestore();
|
|
623
623
|
});
|
|
624
624
|
|
|
@@ -626,7 +626,7 @@ test('Trim.preview silently skips entity that lacks fromPolylinePoints', () => {
|
|
|
626
626
|
// Stub entity implements toPolylinePoints but not fromPolylinePoints.
|
|
627
627
|
// preview() must return early without calling notify.
|
|
628
628
|
core.scene.clear();
|
|
629
|
-
core.scene.
|
|
629
|
+
core.scene.addEntity('Line', { points: [new Point(0, -10), new Point(0, 10)] }); // boundary
|
|
630
630
|
DesignCore.Scene.previewEntities.clear();
|
|
631
631
|
|
|
632
632
|
const stubEntity = {
|
|
@@ -655,29 +655,29 @@ test('Trim.preview silently skips entity that lacks fromPolylinePoints', () => {
|
|
|
655
655
|
test('Trim.action notifies when no intersection found (parallel lines)', () => {
|
|
656
656
|
core.scene.clear();
|
|
657
657
|
// Two parallel vertical lines - no intersection
|
|
658
|
-
core.scene.
|
|
659
|
-
core.scene.
|
|
658
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 100)] });
|
|
659
|
+
core.scene.addEntity('Line', { points: [new Point(10, 0), new Point(10, 100)] });
|
|
660
660
|
|
|
661
661
|
const trim = new Trim();
|
|
662
662
|
trim.selectedBoundaryItems = [core.scene.entities.get(0)];
|
|
663
|
-
trim.
|
|
663
|
+
trim.selectedEntity = core.scene.entities.get(1);
|
|
664
664
|
|
|
665
665
|
const notifySpy = jest.spyOn(core, 'notify').mockImplementation(() => {});
|
|
666
666
|
trim.action();
|
|
667
667
|
|
|
668
668
|
expect(notifySpy).toHaveBeenCalledWith(expect.stringContaining(Strings.Message.NOTRIM));
|
|
669
|
-
expect(trim.
|
|
669
|
+
expect(trim.selectedEntity).toBeNull();
|
|
670
670
|
notifySpy.mockRestore();
|
|
671
671
|
});
|
|
672
672
|
|
|
673
673
|
test('Trim.action notifies when boundary item equals selected item', () => {
|
|
674
674
|
core.scene.clear();
|
|
675
|
-
core.scene.
|
|
675
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(100, 0)] });
|
|
676
676
|
const entity = core.scene.entities.get(0);
|
|
677
677
|
|
|
678
678
|
const trim = new Trim();
|
|
679
679
|
trim.selectedBoundaryItems = [entity];
|
|
680
|
-
trim.
|
|
680
|
+
trim.selectedEntity = entity;
|
|
681
681
|
|
|
682
682
|
const notifySpy = jest.spyOn(core, 'notify').mockImplementation(() => {});
|
|
683
683
|
trim.action();
|
|
@@ -687,7 +687,7 @@ test('Trim.action notifies when boundary item equals selected item', () => {
|
|
|
687
687
|
});
|
|
688
688
|
|
|
689
689
|
test('Trim.action trims an arc', () => {
|
|
690
|
-
// Arc:
|
|
690
|
+
// Arc: centre (0,0), start (10,0), end (-10,0) — CCW upper semicircle through (0,10)
|
|
691
691
|
// Boundary: vertical line at x=0, intersects arc at (0,10)
|
|
692
692
|
// Mouse at (7,7) — in the right half, selects (10,0)→(0,10) segment for removal
|
|
693
693
|
// Expected: original arc removed, shorter arc from (0,10) to (-10,0) added
|
|
@@ -695,11 +695,11 @@ test('Trim.action trims an arc', () => {
|
|
|
695
695
|
const trim = new Trim();
|
|
696
696
|
core.scene.clear();
|
|
697
697
|
|
|
698
|
-
core.scene.
|
|
699
|
-
core.scene.
|
|
698
|
+
core.scene.addEntity('Arc', { points: [new Point(0, 0), new Point(10, 0), new Point(-10, 0)] });
|
|
699
|
+
core.scene.addEntity('Line', { points: [new Point(0, -20), new Point(0, 20)] });
|
|
700
700
|
|
|
701
701
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
702
|
-
trim.
|
|
702
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
703
703
|
core.mouse.setPosFromScenePoint(new Point(7, 7));
|
|
704
704
|
trim.action();
|
|
705
705
|
|
|
@@ -718,7 +718,7 @@ test('Trim.action trims an arc', () => {
|
|
|
718
718
|
});
|
|
719
719
|
|
|
720
720
|
test('Trim.action trims a circle', () => {
|
|
721
|
-
// Circle:
|
|
721
|
+
// Circle: centre (0,0), radius 10
|
|
722
722
|
// Boundary: vertical line at x=0, intersects circle at (0,10) and (0,-10)
|
|
723
723
|
// Mouse at (8,0) — on the right side
|
|
724
724
|
// Expected: original circle removed, arc covering the right side added
|
|
@@ -726,11 +726,11 @@ test('Trim.action trims a circle', () => {
|
|
|
726
726
|
const trim = new Trim();
|
|
727
727
|
core.scene.clear();
|
|
728
728
|
|
|
729
|
-
core.scene.
|
|
730
|
-
core.scene.
|
|
729
|
+
core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
730
|
+
core.scene.addEntity('Line', { points: [new Point(0, -20), new Point(0, 20)] });
|
|
731
731
|
|
|
732
732
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
733
|
-
trim.
|
|
733
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
734
734
|
core.mouse.setPosFromScenePoint(new Point(8, 0));
|
|
735
735
|
trim.action();
|
|
736
736
|
|
|
@@ -742,7 +742,7 @@ test('Trim.action trims a circle', () => {
|
|
|
742
742
|
if (core.scene.entities.get(i).type === 'Arc') arc = core.scene.entities.get(i);
|
|
743
743
|
}
|
|
744
744
|
expect(arc).toBeDefined();
|
|
745
|
-
// Arc
|
|
745
|
+
// Arc centre should match the original circle centre
|
|
746
746
|
expect(arc.points[0].x).toBeCloseTo(0, 10);
|
|
747
747
|
expect(arc.points[0].y).toBeCloseTo(0, 10);
|
|
748
748
|
});
|
|
@@ -757,16 +757,16 @@ test('Trim.action trims a closed polyline - produces open polyline with closed f
|
|
|
757
757
|
core.scene.clear();
|
|
758
758
|
|
|
759
759
|
// Five points where first === last → constructor pops last and sets flag=1
|
|
760
|
-
core.scene.
|
|
760
|
+
core.scene.addEntity('Lwpolyline', {
|
|
761
761
|
points: [new Point(0, 0), new Point(100, 0), new Point(100, 100), new Point(0, 100), new Point(0, 0)],
|
|
762
762
|
});
|
|
763
|
-
core.scene.
|
|
763
|
+
core.scene.addEntity('Line', { points: [new Point(50, -10), new Point(50, 110)] });
|
|
764
764
|
|
|
765
765
|
const polyline = core.scene.entities.get(0);
|
|
766
766
|
expect(polyline.flags.hasFlag(1)).toBe(true); // confirm closed before trim
|
|
767
767
|
|
|
768
768
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
769
|
-
trim.
|
|
769
|
+
trim.selectedEntity = polyline;
|
|
770
770
|
core.mouse.setPosFromScenePoint(new Point(75, 50));
|
|
771
771
|
trim.action();
|
|
772
772
|
|
|
@@ -791,18 +791,18 @@ test('Trim.action trims middle of a line - circle boundary creates two intersect
|
|
|
791
791
|
// segment index 1. The sort comparator falls through to the
|
|
792
792
|
// positionAlongSegment comparison (line 179 of trim.js) because the segment
|
|
793
793
|
// indices are equal.
|
|
794
|
-
// Circle:
|
|
794
|
+
// Circle: centre (50,0) radius 20 → intersects the x-axis at (30,0) and (70,0)
|
|
795
795
|
// Line: (0,0) → (100,0), mouse at (50,0) — inside the circle
|
|
796
796
|
// Expected: original line removed, two shorter lines (0→30) and (70→100) added
|
|
797
797
|
|
|
798
798
|
const trim = new Trim();
|
|
799
799
|
core.scene.clear();
|
|
800
800
|
|
|
801
|
-
core.scene.
|
|
802
|
-
core.scene.
|
|
801
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(100, 0)] });
|
|
802
|
+
core.scene.addEntity('Circle', { points: [new Point(50, 0), new Point(70, 0)] }); // radius 20
|
|
803
803
|
|
|
804
804
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
805
|
-
trim.
|
|
805
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
806
806
|
core.mouse.setPosFromScenePoint(new Point(50, 0));
|
|
807
807
|
trim.action();
|
|
808
808
|
|
|
@@ -838,7 +838,7 @@ test('Trim.execute catches and logs errors thrown during input', async () => {
|
|
|
838
838
|
});
|
|
839
839
|
|
|
840
840
|
test('Trim.action trims a circle near the seam (right side, mouse at angle 0)', () => {
|
|
841
|
-
// Circle:
|
|
841
|
+
// Circle: centre (0,0), radius 10.
|
|
842
842
|
// Circle.toPolylinePoints() always places the seam at angle 0 → vertex (10,0).
|
|
843
843
|
// The old code failed when the mouse was near that seam because both intersections
|
|
844
844
|
// appeared "after" the mouse in linear polyline order, leaving trimBefore=null.
|
|
@@ -851,11 +851,11 @@ test('Trim.action trims a circle near the seam (right side, mouse at angle 0)',
|
|
|
851
851
|
const trim = new Trim();
|
|
852
852
|
core.scene.clear();
|
|
853
853
|
|
|
854
|
-
core.scene.
|
|
855
|
-
core.scene.
|
|
854
|
+
core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
855
|
+
core.scene.addEntity('Line', { points: [new Point(0, -20), new Point(0, 20)] });
|
|
856
856
|
|
|
857
857
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
858
|
-
trim.
|
|
858
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
859
859
|
core.mouse.setPosFromScenePoint(new Point(8, 0));
|
|
860
860
|
trim.action();
|
|
861
861
|
|
|
@@ -867,7 +867,7 @@ test('Trim.action trims a circle near the seam (right side, mouse at angle 0)',
|
|
|
867
867
|
}
|
|
868
868
|
expect(arc).toBeDefined();
|
|
869
869
|
// Remaining arc is the left half: from (0,10) CCW through (-10,0) to (0,-10)
|
|
870
|
-
expect(arc.points[0].x).toBeCloseTo(0); //
|
|
870
|
+
expect(arc.points[0].x).toBeCloseTo(0); // centre
|
|
871
871
|
expect(arc.points[0].y).toBeCloseTo(0);
|
|
872
872
|
expect(arc.points[1].x).toBeCloseTo(0); // start at (0,10)
|
|
873
873
|
expect(arc.points[1].y).toBeCloseTo(10);
|
|
@@ -889,16 +889,16 @@ test('Trim.action trims a closed polyline near the seam vertex', () => {
|
|
|
889
889
|
const trim = new Trim();
|
|
890
890
|
core.scene.clear();
|
|
891
891
|
|
|
892
|
-
core.scene.
|
|
892
|
+
core.scene.addEntity('Lwpolyline', {
|
|
893
893
|
points: [new Point(0, 0), new Point(100, 0), new Point(100, 100), new Point(0, 100), new Point(0, 0)],
|
|
894
894
|
});
|
|
895
|
-
core.scene.
|
|
895
|
+
core.scene.addEntity('Line', { points: [new Point(-10, 50), new Point(110, 50)] });
|
|
896
896
|
|
|
897
897
|
const polyline = core.scene.entities.get(0);
|
|
898
898
|
expect(polyline.flags.hasFlag(1)).toBe(true);
|
|
899
899
|
|
|
900
900
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
901
|
-
trim.
|
|
901
|
+
trim.selectedEntity = polyline;
|
|
902
902
|
// Mouse in the BOTTOM half — forward arc between the two intersections, crosses the seam
|
|
903
903
|
core.mouse.setPosFromScenePoint(new Point(50, 25));
|
|
904
904
|
trim.action();
|
|
@@ -922,8 +922,8 @@ test('Trim.action trims a closed polyline near the seam vertex', () => {
|
|
|
922
922
|
|
|
923
923
|
test('Trim.action trims an open polyline with two consecutive arc segments', () => {
|
|
924
924
|
// Polyline: (0,0,b=1) -> arc1 -> (100,0,b=1) -> arc2 -> (200,0)
|
|
925
|
-
// arc1
|
|
926
|
-
// arc2
|
|
925
|
+
// arc1 centre (50,0) radius 50, through (50,-50)
|
|
926
|
+
// arc2 centre (150,0) radius 50, through (150,-50)
|
|
927
927
|
// Boundary: vertical line at x=150, intersection at (150,-50) on arc2.
|
|
928
928
|
// Mouse at (120,-40): on arc2 BEFORE the intersection (in arc-travel order).
|
|
929
929
|
// Expected: keep right portion = (150,-50) -> (200,0); discard left side.
|
|
@@ -931,11 +931,11 @@ test('Trim.action trims an open polyline with two consecutive arc segments', ()
|
|
|
931
931
|
const trim = new Trim();
|
|
932
932
|
core.scene.clear();
|
|
933
933
|
|
|
934
|
-
core.scene.
|
|
935
|
-
core.scene.
|
|
934
|
+
core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0, 1), new Point(100, 0, 1), new Point(200, 0)] });
|
|
935
|
+
core.scene.addEntity('Line', { points: [new Point(150, -100), new Point(150, 100)] });
|
|
936
936
|
|
|
937
937
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
938
|
-
trim.
|
|
938
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
939
939
|
core.mouse.setPosFromScenePoint(new Point(120, -40));
|
|
940
940
|
trim.action();
|
|
941
941
|
|
|
@@ -955,7 +955,7 @@ test('Trim.action trims an open polyline with two consecutive arc segments', ()
|
|
|
955
955
|
});
|
|
956
956
|
|
|
957
957
|
test('Trim.action trims an arc from the start (portionOne same-segment bulge)', () => {
|
|
958
|
-
// Arc:
|
|
958
|
+
// Arc: centre (0,0), start (10,0), end (-10,0) — CCW upper semicircle through (0,10).
|
|
959
959
|
// Boundary: vertical line at x=0, intersection at (0,10).
|
|
960
960
|
// Mouse at (-7,7) — LEFT of intersection, so trimBefore=(0,10), trimAfter=null.
|
|
961
961
|
// portionOne = startLoc(seg1,(10,0)) → trimBefore(seg1,(0,10)) — same-segment arc split.
|
|
@@ -964,11 +964,11 @@ test('Trim.action trims an arc from the start (portionOne same-segment bulge)',
|
|
|
964
964
|
const trim = new Trim();
|
|
965
965
|
core.scene.clear();
|
|
966
966
|
|
|
967
|
-
core.scene.
|
|
968
|
-
core.scene.
|
|
967
|
+
core.scene.addEntity('Arc', { points: [new Point(0, 0), new Point(10, 0), new Point(-10, 0)] });
|
|
968
|
+
core.scene.addEntity('Line', { points: [new Point(0, -20), new Point(0, 20)] });
|
|
969
969
|
|
|
970
970
|
trim.selectedBoundaryItems = [core.scene.entities.get(1)];
|
|
971
|
-
trim.
|
|
971
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
972
972
|
core.mouse.setPosFromScenePoint(new Point(-7, 7));
|
|
973
973
|
trim.action();
|
|
974
974
|
|
|
@@ -987,7 +987,7 @@ test('Trim.action trims an arc from the start (portionOne same-segment bulge)',
|
|
|
987
987
|
});
|
|
988
988
|
|
|
989
989
|
test('Trim.action trims the middle of an arc (two intersections on same arc segment)', () => {
|
|
990
|
-
// Arc:
|
|
990
|
+
// Arc: centre (0,0), start (10,0), end (-10,0) — CCW upper semicircle through (0,10).
|
|
991
991
|
// Two boundaries: vertical line at x=-5 and x=5.
|
|
992
992
|
// Intersections at (5,√75)≈(5,8.66) and (-5,√75)≈(-5,8.66), both on segment 1.
|
|
993
993
|
// Mouse at (0,9) — between both intersections at the top.
|
|
@@ -996,12 +996,12 @@ test('Trim.action trims the middle of an arc (two intersections on same arc segm
|
|
|
996
996
|
const trim = new Trim();
|
|
997
997
|
core.scene.clear();
|
|
998
998
|
|
|
999
|
-
core.scene.
|
|
1000
|
-
core.scene.
|
|
1001
|
-
core.scene.
|
|
999
|
+
core.scene.addEntity('Arc', { points: [new Point(0, 0), new Point(10, 0), new Point(-10, 0)] });
|
|
1000
|
+
core.scene.addEntity('Line', { points: [new Point(5, -20), new Point(5, 20)] });
|
|
1001
|
+
core.scene.addEntity('Line', { points: [new Point(-5, -20), new Point(-5, 20)] });
|
|
1002
1002
|
|
|
1003
1003
|
trim.selectedBoundaryItems = [core.scene.entities.get(1), core.scene.entities.get(2)];
|
|
1004
|
-
trim.
|
|
1004
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
1005
1005
|
core.mouse.setPosFromScenePoint(new Point(0, 9));
|
|
1006
1006
|
trim.action();
|
|
1007
1007
|
|
|
@@ -1036,12 +1036,12 @@ test('Trim.action trims with multiple boundary items', () => {
|
|
|
1036
1036
|
const trim = new Trim();
|
|
1037
1037
|
core.scene.clear();
|
|
1038
1038
|
|
|
1039
|
-
core.scene.
|
|
1040
|
-
core.scene.
|
|
1041
|
-
core.scene.
|
|
1039
|
+
core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(200, 0)] });
|
|
1040
|
+
core.scene.addEntity('Line', { points: [new Point(50, -20), new Point(50, 20)] });
|
|
1041
|
+
core.scene.addEntity('Line', { points: [new Point(150, -20), new Point(150, 20)] });
|
|
1042
1042
|
|
|
1043
1043
|
trim.selectedBoundaryItems = [core.scene.entities.get(1), core.scene.entities.get(2)];
|
|
1044
|
-
trim.
|
|
1044
|
+
trim.selectedEntity = core.scene.entities.get(0);
|
|
1045
1045
|
core.mouse.setPosFromScenePoint(new Point(100, 0));
|
|
1046
1046
|
trim.action();
|
|
1047
1047
|
|