@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.
- package/.eslintrc.json +14 -7
- package/.github/workflows/DesignCoreQA.yml +3 -1
- package/README.md +11 -4
- package/TODO.md +19 -0
- package/core/core/core.js +49 -42
- package/core/designCore.js +61 -2
- package/core/dimensions/alignedDimension.js +142 -0
- package/core/dimensions/angularDimension.js +550 -0
- package/core/dimensions/baseCircularDimension.js +244 -0
- package/core/dimensions/baseDimension.js +558 -0
- package/core/dimensions/baseLinearDimension.js +371 -0
- package/core/dimensions/diametricDimension.js +82 -0
- package/core/dimensions/dimension.js +298 -0
- package/core/dimensions/linearDimension.js +29 -0
- package/core/dimensions/radialDimension.js +78 -0
- package/core/dimensions/rotatedDimension.js +167 -0
- package/core/entities/arc.js +314 -60
- package/core/entities/arctext.js +642 -0
- package/core/entities/basePolyline.js +553 -94
- package/core/entities/circle.js +181 -54
- package/core/entities/entity.js +154 -74
- package/core/entities/hatch.js +807 -0
- package/core/entities/insert.js +200 -39
- package/core/entities/line.js +196 -134
- package/core/entities/lwpolyline.js +21 -44
- package/core/entities/point.js +194 -29
- package/core/entities/polyline.js +54 -7
- package/core/entities/rectangle.js +43 -13
- package/core/entities/solid.js +43 -6
- package/core/entities/text.js +324 -181
- package/core/lib/boundingBox.js +73 -13
- package/core/lib/canvas.js +256 -65
- package/core/lib/clipboard.js +198 -0
- package/core/lib/colour.js +144 -0
- package/core/lib/colours.js +367 -301
- package/core/lib/commandLine.js +16 -28
- package/core/lib/commandManager.js +115 -58
- package/core/lib/constants.js +23 -0
- package/core/lib/dxf/dxf.js +249 -34
- package/core/lib/dxf/dxfFile.js +23 -38
- package/core/lib/dxf/dxfIterator.js +17 -5
- package/core/lib/dxf/dxfRead.js +23 -7
- package/core/lib/dxf/dxfWrite.js +39 -129
- package/core/lib/dxf/handleManager.js +97 -0
- package/core/lib/dxf/sections/blocks.js +16 -2
- package/core/lib/dxf/sections/entities.js +17 -3
- package/core/lib/dxf/sections/header.js +10 -1
- package/core/lib/dxf/sections/objects.js +36 -0
- package/core/lib/dxf/sections/section.js +43 -5
- package/core/lib/dxf/sections/tables.js +17 -3
- package/core/lib/entityManager.js +178 -0
- package/core/lib/fileio.js +14 -4
- package/core/lib/headers.js +229 -0
- package/core/lib/input.js +46 -0
- package/core/lib/inputManager.js +199 -194
- package/core/lib/intersect.js +341 -468
- package/core/lib/logging.js +25 -1
- package/core/lib/matrix.js +6 -8
- package/core/lib/mouse.js +24 -79
- package/core/lib/patterns.js +690 -0
- package/core/lib/promptOptions.js +133 -0
- package/core/lib/scene.js +71 -174
- package/core/lib/selectionManager.js +74 -48
- package/core/lib/selectionWindow.js +24 -10
- package/core/lib/settings.js +18 -11
- package/core/lib/snapping.js +129 -21
- package/core/lib/stateManager.js +288 -0
- package/core/lib/strings.js +57 -5
- package/core/lib/utils.js +95 -11
- package/core/objects/dictionary.js +43 -0
- package/core/objects/dictionaryManager.js +80 -0
- package/core/properties/dimType.js +117 -0
- package/core/properties/flags.js +66 -0
- package/core/properties/property.js +26 -0
- package/core/properties/propertyManager.js +65 -19
- package/core/tables/appId.js +31 -0
- package/core/tables/appIdManager.js +44 -0
- package/core/tables/block.js +323 -0
- package/core/tables/blockManager.js +48 -0
- package/core/tables/blockRecord.js +29 -0
- package/core/tables/blockRecordManager.js +37 -0
- package/core/tables/dimStyle.js +627 -0
- package/core/tables/dimStyleManager.js +187 -0
- package/core/tables/endblk.js +28 -0
- package/core/tables/layer.js +219 -0
- package/core/tables/layerManager.js +47 -0
- package/core/tables/ltype.js +85 -0
- package/core/tables/ltypeManager.js +65 -0
- package/core/tables/style.js +145 -0
- package/core/tables/styleManager.js +55 -0
- package/core/tables/styleManagerBase.js +110 -0
- package/core/tables/tableManagerBase.js +354 -0
- package/core/tables/ucs.js +28 -0
- package/core/tables/ucsManager.js +44 -0
- package/core/tables/view.js +28 -0
- package/core/tables/viewManager.js +44 -0
- package/core/tables/vport.js +70 -0
- package/core/tables/vportManager.js +65 -0
- package/core/tools/chamfer.js +343 -0
- package/core/tools/chamferFilletBase.js +162 -0
- package/core/tools/copy.js +68 -40
- package/core/tools/copybase.js +65 -0
- package/core/tools/copyclip.js +59 -0
- package/core/tools/cornerEntity.js +138 -0
- package/core/tools/cutclip.js +72 -0
- package/core/tools/distance.js +37 -9
- package/core/tools/erase.js +43 -13
- package/core/tools/explode.js +117 -0
- package/core/tools/extend.js +71 -32
- package/core/tools/fillet.js +336 -0
- package/core/tools/identify.js +33 -6
- package/core/tools/matchProp.js +106 -0
- package/core/tools/mirror.js +141 -0
- package/core/tools/move.js +65 -32
- package/core/tools/offset.js +321 -0
- package/core/tools/pan.js +54 -0
- package/core/tools/pasteclip.js +93 -0
- package/core/tools/purge.js +90 -0
- package/core/tools/rotate.js +105 -70
- package/core/tools/scale.js +166 -0
- package/core/tools/tool.js +14 -4
- package/core/tools/trim.js +71 -32
- package/core/tools/zoom.js +152 -0
- package/package.json +3 -305
- package/test/dimensions/alignedDimension.test.js +211 -0
- package/test/dimensions/angularDimension.test.js +243 -0
- package/test/dimensions/baseDimension.test.js +239 -0
- package/test/dimensions/diametricDimension.test.js +203 -0
- package/test/dimensions/dimension.test.js +102 -0
- package/test/dimensions/radialDimension.test.js +203 -0
- package/test/dimensions/rotatedDimension.test.js +224 -0
- package/test/entities/arc.test.js +463 -41
- package/test/entities/arctext.test.js +329 -0
- package/test/entities/basePolyline.test.js +459 -10
- package/test/entities/circle.test.js +312 -7
- package/test/entities/entity.test.js +28 -9
- package/test/entities/hatch.test.js +606 -0
- package/test/entities/insert.test.js +90 -0
- package/test/entities/line.test.js +182 -6
- package/test/entities/point.test.js +375 -37
- package/test/entities/solid.test.js +156 -0
- package/test/entities/text.test.js +533 -7
- package/test/integration/exportIntegration.reference.dxf +1706 -0
- package/test/integration/exportIntegration.test.js +186 -0
- package/test/integration/importExportIntegration.test.js +126 -0
- package/test/integration/intersectionIntegration.test.js +880 -0
- package/test/integration/userInputIntegration.reference.dxf +1410 -0
- package/test/integration/userInputIntegration.test.js +269 -0
- package/test/lib/boundingBox.test.js +26 -2
- package/test/lib/canvas.test.js +613 -5
- package/test/lib/clipboard.test.js +70 -0
- package/test/lib/colour.test.js +114 -0
- package/test/lib/colours.test.js +63 -18
- package/test/lib/commandLine.test.js +159 -22
- package/test/lib/commandManager.test.js +4 -4
- package/test/lib/constants.test.js +9 -0
- package/test/lib/dxf/dxfFile.test.js +6 -2
- package/test/lib/dxf/dxfIterator.test.js +1 -1
- package/test/lib/dxf/dxfWrite.test.js +173 -0
- package/test/lib/dxf/handleManager.test.js +137 -0
- package/test/lib/dxf/sections/blocks.test.js +5 -5
- package/test/lib/dxf/sections/entities.test.js +4 -4
- package/test/lib/dxf/sections/header.test.js +18 -4
- package/test/lib/dxf/sections/objects.test.js +132 -0
- package/test/lib/dxf/sections/section.test.js +29 -29
- package/test/lib/dxf/sections/tables.test.js +3 -3
- package/test/lib/entityManager.test.js +163 -0
- package/test/lib/headers.test.js +233 -0
- package/test/lib/inputManager.test.js +1144 -5
- package/test/lib/intersect.test.js +454 -331
- package/test/lib/logging.test.js +1 -1
- package/test/lib/matrix.test.js +1 -1
- package/test/lib/mouse.test.js +327 -4
- package/test/lib/patterns.test.js +105 -0
- package/test/lib/promptOptions.test.js +179 -0
- package/test/lib/scene.test.js +16 -52
- package/test/lib/selectionManager.test.js +17 -5
- package/test/lib/settings.test.js +111 -5
- package/test/lib/snapping.test.js +142 -4
- package/test/lib/stateManager.test.js +155 -0
- package/test/lib/utils.test.js +81 -1
- package/test/objects/dictionary.test.js +81 -0
- package/test/objects/dictionaryManager.test.js +34 -0
- package/test/properties/dimType.test.js +62 -0
- package/test/properties/flags.test.js +164 -0
- package/test/properties/property.test.js +13 -0
- package/test/properties/propertyManager.test.js +10 -11
- package/test/tables/appId.test.js +46 -0
- package/test/tables/appIdManager.test.js +72 -0
- package/test/tables/block.test.js +157 -0
- package/test/tables/blockManager.test.js +52 -0
- package/test/tables/blockRecord.test.js +39 -0
- package/test/tables/blockRecordManager.test.js +60 -0
- package/test/tables/dimstyle.test.js +72 -0
- package/test/tables/endblk.test.js +30 -0
- package/test/tables/layer.test.js +95 -0
- package/test/tables/layerManager.test.js +172 -0
- package/test/{styles → tables}/ltype.test.js +7 -7
- package/test/{styles → tables}/ltypeManager.test.js +2 -2
- package/test/tables/style.test.js +44 -0
- package/test/tables/stylemanagerbase.test.js +220 -0
- package/test/tables/tableManagerBase.test.js +194 -0
- package/test/tables/ucs.test.js +37 -0
- package/test/tables/ucsManager.test.js +48 -0
- package/test/tables/view.test.js +37 -0
- package/test/tables/viewManager.test.js +48 -0
- package/test/tables/vport.test.js +117 -0
- package/test/tables/vportManager.test.js +54 -0
- package/test/test-helpers/test-helpers.js +66 -0
- package/test/tools/chamfer.test.js +970 -0
- package/test/tools/chamferFilletBase.test.js +446 -0
- package/test/tools/copy.test.js +22 -14
- package/test/tools/copybase.test.js +93 -0
- package/test/tools/copyclip.test.js +92 -0
- package/test/tools/cornerEntity.test.js +201 -0
- package/test/tools/cutclip.test.js +94 -0
- package/test/tools/distance.test.js +140 -18
- package/test/tools/erase.test.js +12 -12
- package/test/tools/explode.test.js +45 -0
- package/test/tools/extend.test.js +326 -44
- package/test/tools/fillet.test.js +831 -0
- package/test/tools/identify.test.js +115 -16
- package/test/tools/matchProp.test.js +84 -0
- package/test/tools/mirror.test.js +475 -0
- package/test/tools/move.test.js +75 -19
- package/test/tools/offset.test.js +748 -0
- package/test/tools/pan.test.js +72 -0
- package/test/tools/pasteclip.test.js +100 -0
- package/test/tools/purge.test.js +89 -0
- package/test/tools/rotate.test.js +89 -23
- package/test/tools/scale.test.js +529 -0
- package/test/tools/trim.test.js +419 -84
- package/test/tools/zoom.test.js +504 -0
- package/core/entities/alignedDimension.js +0 -279
- package/core/entities/angularDimension.js +0 -194
- package/core/entities/baseDimension.js +0 -227
- package/core/entities/block.js +0 -247
- package/core/entities/diametricDimension.js +0 -133
- package/core/entities/dimension.js +0 -202
- package/core/entities/radialDimension.js +0 -126
- package/core/styles/dimStyle.js +0 -719
- package/core/styles/dimStyleManager.js +0 -47
- package/core/styles/layer.js +0 -133
- package/core/styles/layerManager.js +0 -40
- package/core/styles/ltype.js +0 -86
- package/core/styles/ltypeManager.js +0 -50
- package/core/styles/style.js +0 -158
- package/core/styles/styleManager.js +0 -43
- package/core/styles/styleManagerBase.js +0 -299
- package/test/entities/block.test.js +0 -22
- package/test/styles/dimstyle.test.js +0 -19
- package/test/styles/layerManager.test.js +0 -150
- package/test/styles/style.test.js +0 -33
- package/test/styles/stylemanagerbase.test.js +0 -219
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { Point } from '../../core/entities/point.js';
|
|
3
|
+
import { Copyclip } from '../../core/tools/copyclip.js';
|
|
4
|
+
import { DesignCore } from '../../core/designCore.js';
|
|
5
|
+
|
|
6
|
+
import { jest } from '@jest/globals';
|
|
7
|
+
|
|
8
|
+
// Initialize core (sets DesignCore.Core)
|
|
9
|
+
new Core();
|
|
10
|
+
|
|
11
|
+
describe('Copyclip Tool', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
// reset scene entities and selection
|
|
14
|
+
DesignCore.Scene.entities.clear();
|
|
15
|
+
DesignCore.Scene.selectionManager.reset();
|
|
16
|
+
// clear clipboard
|
|
17
|
+
DesignCore.Clipboard.Entities = [];
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('action copies selected entities and sets base point to bounding box bottom-left', () => {
|
|
21
|
+
// Create two line entities and add to scene
|
|
22
|
+
const line1 = DesignCore.CommandManager.createNew('Line', { layer: '0', points: [new Point(10, 20), new Point(30, 40)] });
|
|
23
|
+
const line2 = DesignCore.CommandManager.createNew('Line', { layer: '0', points: [new Point(-5, 100), new Point(0, 80)] });
|
|
24
|
+
DesignCore.Scene.entities.add(line1);
|
|
25
|
+
DesignCore.Scene.entities.add(line2);
|
|
26
|
+
|
|
27
|
+
// Select both
|
|
28
|
+
DesignCore.Scene.selectionManager.addToSelectionSet(0);
|
|
29
|
+
DesignCore.Scene.selectionManager.addToSelectionSet(1);
|
|
30
|
+
expect(DesignCore.Scene.selectionManager.selectedItems).toHaveLength(2);
|
|
31
|
+
|
|
32
|
+
const tool = new Copyclip();
|
|
33
|
+
tool.action();
|
|
34
|
+
|
|
35
|
+
// Clipboard now holds selected items (cloned)
|
|
36
|
+
expect(DesignCore.Clipboard.Entities).toHaveLength(2);
|
|
37
|
+
// BasePoint should be min x (-5), min y (20) across all points
|
|
38
|
+
expect(DesignCore.Clipboard.BasePoint.x).toBe(-5);
|
|
39
|
+
expect(DesignCore.Clipboard.BasePoint.y).toBe(20);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('clipboard entities are clones (mutating original does not change clipboard)', () => {
|
|
43
|
+
const line = DesignCore.CommandManager.createNew('Line', { layer: '0', points: [new Point(0, 0), new Point(10, 0)] });
|
|
44
|
+
DesignCore.Scene.entities.add(line);
|
|
45
|
+
DesignCore.Scene.selectionManager.addToSelectionSet(0);
|
|
46
|
+
const originalClonePoints = DesignCore.Scene.selectionManager.selectedItems[0].points.map((p) => ({ x: p.x, y: p.y }));
|
|
47
|
+
|
|
48
|
+
const tool = new Copyclip();
|
|
49
|
+
tool.action();
|
|
50
|
+
expect(DesignCore.Clipboard.Entities).toHaveLength(1);
|
|
51
|
+
|
|
52
|
+
// Mutate original entity
|
|
53
|
+
line.points[0].x = 999;
|
|
54
|
+
// Clipboard should remain with old coordinates
|
|
55
|
+
expect(DesignCore.Clipboard.Entities[0].points[0].x).toBe(originalClonePoints[0].x);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('execute requests selection when none selected then calls executeCommand', async () => {
|
|
59
|
+
const tool = new Copyclip();
|
|
60
|
+
const requestSpy = jest.fn().mockResolvedValue(undefined);
|
|
61
|
+
const execSpy = jest.fn();
|
|
62
|
+
DesignCore.Scene.selectionManager.reset();
|
|
63
|
+
|
|
64
|
+
// Mock inputManager methods
|
|
65
|
+
DesignCore.Scene.inputManager.requestInput = requestSpy;
|
|
66
|
+
DesignCore.Scene.inputManager.executeCommand = execSpy;
|
|
67
|
+
|
|
68
|
+
await tool.execute();
|
|
69
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
70
|
+
expect(execSpy).toHaveBeenCalledTimes(1);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('execute skips requestInput when selection exists', async () => {
|
|
74
|
+
// Prepare selection
|
|
75
|
+
const ent = DesignCore.CommandManager.createNew('Line', { layer: '0', points: [new Point(1, 1), new Point(2, 2)] });
|
|
76
|
+
DesignCore.Scene.entities.add(ent);
|
|
77
|
+
DesignCore.Scene.selectionManager.addToSelectionSet(0);
|
|
78
|
+
expect(DesignCore.Scene.selectionManager.selectionSet.selectionSet.length).toBe(1);
|
|
79
|
+
|
|
80
|
+
const tool = new Copyclip();
|
|
81
|
+
const requestSpy = jest.fn().mockResolvedValue(undefined);
|
|
82
|
+
const execSpy = jest.fn();
|
|
83
|
+
DesignCore.Scene.inputManager.requestInput = requestSpy;
|
|
84
|
+
DesignCore.Scene.inputManager.executeCommand = execSpy;
|
|
85
|
+
|
|
86
|
+
await tool.execute();
|
|
87
|
+
expect(requestSpy).not.toHaveBeenCalled();
|
|
88
|
+
expect(execSpy).toHaveBeenCalledTimes(1);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { Point } from '../../core/entities/point.js';
|
|
3
|
+
import { Line } from '../../core/entities/line.js';
|
|
4
|
+
import { CornerEntity } from '../../core/tools/cornerEntity.js';
|
|
5
|
+
import { expect, jest } from '@jest/globals';
|
|
6
|
+
|
|
7
|
+
const core = new Core();
|
|
8
|
+
|
|
9
|
+
// ─── activeSeg ────────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
test('CornerEntity.activeSeg returns entity when segment is null', () => {
|
|
12
|
+
const corner = new CornerEntity();
|
|
13
|
+
const entity = {};
|
|
14
|
+
corner.entity = entity;
|
|
15
|
+
expect(corner.activeSeg).toBe(entity);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('CornerEntity.activeSeg returns segment when segment is set', () => {
|
|
19
|
+
const corner = new CornerEntity();
|
|
20
|
+
corner.entity = {};
|
|
21
|
+
const seg = {};
|
|
22
|
+
corner.segment = seg;
|
|
23
|
+
expect(corner.activeSeg).toBe(seg);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// ─── direction ────────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
test('CornerEntity.direction returns lineEnd minus lineStart', () => {
|
|
29
|
+
const corner = new CornerEntity();
|
|
30
|
+
corner.lineStart = new Point(1, 2);
|
|
31
|
+
corner.lineEnd = new Point(4, 6);
|
|
32
|
+
const dir = corner.direction;
|
|
33
|
+
expect(dir.x).toBeCloseTo(3);
|
|
34
|
+
expect(dir.y).toBeCloseTo(4);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// ─── resolveEndpoints ─────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
test('CornerEntity.resolveEndpoints returns true and sets lineStart/lineEnd for a Line', () => {
|
|
40
|
+
core.scene.clear();
|
|
41
|
+
core.scene.addItem('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
42
|
+
const line = core.scene.entities.get(0);
|
|
43
|
+
|
|
44
|
+
const corner = new CornerEntity();
|
|
45
|
+
corner.entity = line;
|
|
46
|
+
|
|
47
|
+
expect(corner.resolveEndpoints()).toBe(true);
|
|
48
|
+
expect(corner.lineStart).toBe(line.points[0]);
|
|
49
|
+
expect(corner.lineEnd).toBe(line.points[1]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('CornerEntity.resolveEndpoints returns false and leaves endpoints null for a non-Line', () => {
|
|
53
|
+
core.scene.clear();
|
|
54
|
+
core.scene.addItem('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
|
|
55
|
+
const circle = core.scene.entities.get(0);
|
|
56
|
+
|
|
57
|
+
const corner = new CornerEntity();
|
|
58
|
+
corner.entity = circle;
|
|
59
|
+
|
|
60
|
+
expect(corner.resolveEndpoints()).toBe(false);
|
|
61
|
+
expect(corner.lineStart).toBeNull();
|
|
62
|
+
expect(corner.lineEnd).toBeNull();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// ─── setEntity ────────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
test('CornerEntity.setEntity returns true and clears segment for a plain Line entity', () => {
|
|
68
|
+
core.scene.clear();
|
|
69
|
+
core.scene.addItem('Line', { points: [new Point(0, 0), new Point(10, 0)] });
|
|
70
|
+
const line = core.scene.entities.get(0);
|
|
71
|
+
|
|
72
|
+
const corner = new CornerEntity();
|
|
73
|
+
expect(corner.setPick(line, new Point(5, 0), 'error')).toBe(true);
|
|
74
|
+
expect(corner.segment).toBeNull();
|
|
75
|
+
expect(corner.segmentIndex).toBeNull();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('CornerEntity.setEntity sets segment and segmentIndex for a polyline straight segment', () => {
|
|
79
|
+
core.scene.clear();
|
|
80
|
+
core.scene.addItem('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10)] });
|
|
81
|
+
const poly = core.scene.entities.get(0);
|
|
82
|
+
|
|
83
|
+
const corner = new CornerEntity();
|
|
84
|
+
expect(corner.setPick(poly, new Point(5, 0), 'error')).toBe(true); // near first (horizontal) segment
|
|
85
|
+
expect(corner.segment).toBeInstanceOf(Line);
|
|
86
|
+
expect(corner.segmentIndex).toBe(1);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('CornerEntity.setEntity notifies and returns false for a polyline arc segment', () => {
|
|
90
|
+
core.scene.clear();
|
|
91
|
+
const notifySpy = jest.spyOn(core, 'notify');
|
|
92
|
+
|
|
93
|
+
// bulge on the start point makes the segment an arc
|
|
94
|
+
const arcStart = new Point(0, 0);
|
|
95
|
+
arcStart.bulge = 1;
|
|
96
|
+
core.scene.addItem('Lwpolyline', { points: [arcStart, new Point(10, 0)] });
|
|
97
|
+
const poly = core.scene.entities.get(0);
|
|
98
|
+
|
|
99
|
+
const errorMsg = 'arc segment error';
|
|
100
|
+
expect(new CornerEntity().setPick(poly, new Point(5, 2), errorMsg)).toBe(false);
|
|
101
|
+
expect(notifySpy).toHaveBeenCalledWith(errorMsg);
|
|
102
|
+
notifySpy.mockRestore();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// ─── click-side geometry getters ─────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
test('CornerEntity click-side geometry methods return correct values', () => {
|
|
108
|
+
// Horizontal line (0,0)→(10,0), intersection at (5,0), click at (3,2)
|
|
109
|
+
// clickOnLine = perpendicular foot of (3,2) on the line = (3,0)
|
|
110
|
+
// clickDir = (3,0)−(5,0) = (−2,0)
|
|
111
|
+
// clickDistance = 2, clickUnit = (−1,0)
|
|
112
|
+
// lineKeptEnd = lineStart because clickDir points toward start
|
|
113
|
+
const corner = new CornerEntity();
|
|
114
|
+
corner.lineStart = new Point(0, 0);
|
|
115
|
+
corner.lineEnd = new Point(10, 0);
|
|
116
|
+
corner.clickPoint = new Point(3, 2);
|
|
117
|
+
const ip = new Point(5, 0);
|
|
118
|
+
|
|
119
|
+
expect(corner.clickDistance(ip)).toBeCloseTo(2);
|
|
120
|
+
expect(corner.clickDir(ip).x).toBeCloseTo(-2);
|
|
121
|
+
expect(corner.clickDir(ip).y).toBeCloseTo(0);
|
|
122
|
+
expect(corner.clickUnit(ip).x).toBeCloseTo(-1);
|
|
123
|
+
expect(corner.clickUnit(ip).y).toBeCloseTo(0);
|
|
124
|
+
expect(corner.lineKeptEnd(ip)).toBe(corner.lineStart);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('CornerEntity.clickDistance is near zero when click projects exactly to intersection', () => {
|
|
128
|
+
// clickOnLine = (5,0) = intersectionPoint → clickDistance = 0 → ambiguous corner
|
|
129
|
+
const corner = new CornerEntity();
|
|
130
|
+
corner.lineStart = new Point(0, 0);
|
|
131
|
+
corner.lineEnd = new Point(10, 0);
|
|
132
|
+
corner.clickPoint = new Point(5, 0);
|
|
133
|
+
|
|
134
|
+
expect(corner.clickDistance(new Point(5, 0))).toBeCloseTo(0);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('CornerEntity.lineKeptEnd is lineEnd when click is past intersection', () => {
|
|
138
|
+
// Click at (8,1): clickOnLine = (8,0), clickDir from (5,0) = (3,0) → points toward end
|
|
139
|
+
const corner = new CornerEntity();
|
|
140
|
+
corner.lineStart = new Point(0, 0);
|
|
141
|
+
corner.lineEnd = new Point(10, 0);
|
|
142
|
+
corner.clickPoint = new Point(8, 1);
|
|
143
|
+
|
|
144
|
+
expect(corner.lineKeptEnd(new Point(5, 0))).toBe(corner.lineEnd);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// ─── keepStart ───────────────────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
test('CornerEntity.keepStart returns true when segment start is on the click side', () => {
|
|
150
|
+
// Polyline: (0,0)→(10,0)→(10,10), click at (3,2), intersection=(10,0)
|
|
151
|
+
// clickOnLine=(3,0), clickDir=(−7,0) → points toward start side
|
|
152
|
+
core.scene.clear();
|
|
153
|
+
core.scene.addItem('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10)] });
|
|
154
|
+
const poly = core.scene.entities.get(0);
|
|
155
|
+
|
|
156
|
+
const corner = new CornerEntity();
|
|
157
|
+
corner.entity = poly;
|
|
158
|
+
corner.segmentIndex = 1;
|
|
159
|
+
corner.lineStart = new Point(0, 0);
|
|
160
|
+
corner.lineEnd = new Point(10, 0);
|
|
161
|
+
corner.clickPoint = new Point(3, 2);
|
|
162
|
+
|
|
163
|
+
expect(corner.keepStart(new Point(10, 0))).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('CornerEntity.keepStart returns false when segment end is on the click side', () => {
|
|
167
|
+
// Same polyline, click at (8,2), intersection=(0,0)
|
|
168
|
+
// clickOnLine=(8,0), clickDir=(8,0) → points toward end side
|
|
169
|
+
core.scene.clear();
|
|
170
|
+
core.scene.addItem('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10)] });
|
|
171
|
+
const poly = core.scene.entities.get(0);
|
|
172
|
+
|
|
173
|
+
const corner = new CornerEntity();
|
|
174
|
+
corner.entity = poly;
|
|
175
|
+
corner.segmentIndex = 1;
|
|
176
|
+
corner.lineStart = new Point(0, 0);
|
|
177
|
+
corner.lineEnd = new Point(10, 0);
|
|
178
|
+
corner.clickPoint = new Point(8, 2);
|
|
179
|
+
|
|
180
|
+
expect(corner.keepStart(new Point(0, 0))).toBe(false);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('CornerEntity.keepStart handles closing segment of closed polyline (segmentIndex === points.length)', () => {
|
|
184
|
+
// Closed polyline: (0,0)→(10,0)→(10,10), closing segment is index 3 (back to (0,0))
|
|
185
|
+
// segmentIndex === points.length wraps segEnd to points[0] = (0,0)
|
|
186
|
+
// lineStart=(10,10), lineEnd=(0,0), click at (9,9), intersection=(10,0)
|
|
187
|
+
// clickOnLine=(10,9.something...) but we just need keepStart not to throw
|
|
188
|
+
core.scene.clear();
|
|
189
|
+
core.scene.addItem('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10)] });
|
|
190
|
+
const poly = core.scene.entities.get(0);
|
|
191
|
+
|
|
192
|
+
const corner = new CornerEntity();
|
|
193
|
+
corner.entity = poly;
|
|
194
|
+
corner.segmentIndex = poly.points.length; // closing segment
|
|
195
|
+
corner.lineStart = new Point(10, 10);
|
|
196
|
+
corner.lineEnd = new Point(0, 0);
|
|
197
|
+
corner.clickPoint = new Point(9, 9);
|
|
198
|
+
|
|
199
|
+
// Should not throw; segEnd wraps to points[0] = (0,0)
|
|
200
|
+
expect(() => corner.keepStart(new Point(10, 0))).not.toThrow();
|
|
201
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { Point } from '../../core/entities/point.js';
|
|
3
|
+
import { Cutclip } from '../../core/tools/cutclip.js';
|
|
4
|
+
import { DesignCore } from '../../core/designCore.js';
|
|
5
|
+
|
|
6
|
+
import { jest } from '@jest/globals';
|
|
7
|
+
|
|
8
|
+
// Initialize core (sets DesignCore.Core)
|
|
9
|
+
new Core();
|
|
10
|
+
|
|
11
|
+
describe('Cutclip Tool', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
// reset scene entities and selection
|
|
14
|
+
DesignCore.Scene.entities.clear();
|
|
15
|
+
DesignCore.Scene.selectionManager.reset();
|
|
16
|
+
// clear clipboard
|
|
17
|
+
DesignCore.Clipboard.Entities = [];
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('action copies selected entities and sets base point to bounding box bottom-left', () => {
|
|
21
|
+
// Create two line entities and add to scene
|
|
22
|
+
const line1 = DesignCore.CommandManager.createNew('Line', { layer: '0', points: [new Point(10, 20), new Point(30, 40)] });
|
|
23
|
+
const line2 = DesignCore.CommandManager.createNew('Line', { layer: '0', points: [new Point(-5, 100), new Point(0, 80)] });
|
|
24
|
+
DesignCore.Scene.entities.add(line1);
|
|
25
|
+
DesignCore.Scene.entities.add(line2);
|
|
26
|
+
|
|
27
|
+
// Select both
|
|
28
|
+
DesignCore.Scene.selectionManager.addToSelectionSet(0);
|
|
29
|
+
DesignCore.Scene.selectionManager.addToSelectionSet(1);
|
|
30
|
+
expect(DesignCore.Scene.selectionManager.selectedItems).toHaveLength(2);
|
|
31
|
+
|
|
32
|
+
const tool = new Cutclip();
|
|
33
|
+
tool.action();
|
|
34
|
+
|
|
35
|
+
// Clipboard now holds selected items (cloned)
|
|
36
|
+
expect(DesignCore.Clipboard.Entities).toHaveLength(2);
|
|
37
|
+
// BasePoint should be min x (-5), min y (20) across all points
|
|
38
|
+
expect(DesignCore.Clipboard.BasePoint.x).toBe(-5);
|
|
39
|
+
expect(DesignCore.Clipboard.BasePoint.y).toBe(20);
|
|
40
|
+
// Scene entities should be removed
|
|
41
|
+
expect(DesignCore.Scene.entities.count()).toBe(0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('clipboard entities are clones (mutating original does not change clipboard)', () => {
|
|
45
|
+
const line = DesignCore.CommandManager.createNew('Line', { layer: '0', points: [new Point(0, 0), new Point(10, 0)] });
|
|
46
|
+
DesignCore.Scene.entities.add(line);
|
|
47
|
+
DesignCore.Scene.selectionManager.addToSelectionSet(0);
|
|
48
|
+
const originalClonePoints = DesignCore.Scene.selectionManager.selectedItems[0].points.map((p) => ({ x: p.x, y: p.y }));
|
|
49
|
+
|
|
50
|
+
const tool = new Cutclip();
|
|
51
|
+
tool.action();
|
|
52
|
+
expect(DesignCore.Clipboard.Entities).toHaveLength(1);
|
|
53
|
+
|
|
54
|
+
// Mutate original entity
|
|
55
|
+
line.points[0].x = 999;
|
|
56
|
+
// Clipboard should remain with old coordinates
|
|
57
|
+
expect(DesignCore.Clipboard.Entities[0].points[0].x).toBe(originalClonePoints[0].x);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('execute requests selection when none selected then calls executeCommand', async () => {
|
|
61
|
+
const tool = new Cutclip();
|
|
62
|
+
const requestSpy = jest.fn().mockResolvedValue(undefined);
|
|
63
|
+
const execSpy = jest.fn();
|
|
64
|
+
DesignCore.Scene.selectionManager.reset();
|
|
65
|
+
|
|
66
|
+
// Mock inputManager methods
|
|
67
|
+
DesignCore.Scene.inputManager.requestInput = requestSpy;
|
|
68
|
+
DesignCore.Scene.inputManager.executeCommand = execSpy;
|
|
69
|
+
|
|
70
|
+
await tool.execute();
|
|
71
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
72
|
+
expect(execSpy).toHaveBeenCalledTimes(1);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('execute skips requestInput when selection exists', async () => {
|
|
76
|
+
// Prepare selection
|
|
77
|
+
const ent = DesignCore.CommandManager.createNew('Line', { layer: '0', points: [new Point(1, 1), new Point(2, 2)] });
|
|
78
|
+
DesignCore.Scene.entities.add(ent);
|
|
79
|
+
DesignCore.Scene.selectionManager.addToSelectionSet(0);
|
|
80
|
+
expect(DesignCore.Scene.selectionManager.selectionSet.selectionSet.length).toBe(1);
|
|
81
|
+
|
|
82
|
+
const tool = new Cutclip();
|
|
83
|
+
const requestSpy = jest.fn().mockResolvedValue(undefined);
|
|
84
|
+
const execSpy = jest.fn();
|
|
85
|
+
DesignCore.Scene.inputManager.requestInput = requestSpy;
|
|
86
|
+
DesignCore.Scene.inputManager.executeCommand = execSpy;
|
|
87
|
+
|
|
88
|
+
await tool.execute();
|
|
89
|
+
expect(requestSpy).not.toHaveBeenCalled();
|
|
90
|
+
expect(execSpy).toHaveBeenCalledTimes(1);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
|
|
@@ -1,30 +1,152 @@
|
|
|
1
|
-
import {Core} from '../../core/core/core.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { Point } from '../../core/entities/point.js';
|
|
3
|
+
import { Distance } from '../../core/tools/distance.js';
|
|
4
|
+
import { Strings } from '../../core/lib/strings.js';
|
|
5
|
+
import { expect, jest } from '@jest/globals';
|
|
6
|
+
import { withMockInput } from '../test-helpers/test-helpers.js';
|
|
5
7
|
|
|
6
8
|
const core = new Core();
|
|
7
|
-
let output;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
output = notification;
|
|
11
|
-
};
|
|
10
|
+
// ─── register ────────────────────────────────────────────────────────────────
|
|
12
11
|
|
|
13
|
-
test('
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
test('Distance.register returns correct command object', () => {
|
|
13
|
+
const reg = Distance.register();
|
|
14
|
+
expect(reg.command).toBe('Distance');
|
|
15
|
+
expect(reg.shortcut).toBe('DI');
|
|
16
|
+
});
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
// ─── action ───────────────────────────────────────────────────────────────────
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
test('Distance.action vertical line: correct length, angle, and deltas', () => {
|
|
21
|
+
const notifySpy = jest.spyOn(core, 'notify');
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
const distance = new Distance();
|
|
24
|
+
distance.points.push(new Point(0, 0));
|
|
23
25
|
distance.points.push(new Point(0, 10));
|
|
26
|
+
distance.action();
|
|
27
|
+
|
|
28
|
+
expect(notifySpy).toHaveBeenCalledWith(`${Strings.Strings.LENGTH}: 10.0 Angle: 90.0${Strings.Symbol.DEGREE} ${Strings.Symbol.DELTA}X: 0.0 ${Strings.Symbol.DELTA}Y: 10.0`);
|
|
29
|
+
notifySpy.mockRestore();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('Distance.action horizontal line: correct length, angle, and deltas', () => {
|
|
33
|
+
const notifySpy = jest.spyOn(core, 'notify');
|
|
34
|
+
|
|
35
|
+
const distance = new Distance();
|
|
36
|
+
distance.points.push(new Point(0, 0));
|
|
37
|
+
distance.points.push(new Point(10, 0));
|
|
38
|
+
distance.action();
|
|
39
|
+
|
|
40
|
+
expect(notifySpy).toHaveBeenCalledWith(`${Strings.Strings.LENGTH}: 10.0 Angle: 0.0${Strings.Symbol.DEGREE} ${Strings.Symbol.DELTA}X: 10.0 ${Strings.Symbol.DELTA}Y: 0.0`);
|
|
41
|
+
notifySpy.mockRestore();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('Distance.action diagonal 3-4-5 triangle: correct length and angle', () => {
|
|
45
|
+
const notifySpy = jest.spyOn(core, 'notify');
|
|
24
46
|
|
|
25
|
-
|
|
47
|
+
const distance = new Distance();
|
|
48
|
+
distance.points.push(new Point(0, 0));
|
|
49
|
+
distance.points.push(new Point(3, 4));
|
|
26
50
|
distance.action();
|
|
27
51
|
|
|
28
|
-
|
|
29
|
-
expect(
|
|
52
|
+
// length = 5, angle = atan2(4,3) ≈ 53.1°
|
|
53
|
+
expect(notifySpy).toHaveBeenCalledWith(`${Strings.Strings.LENGTH}: 5.0 Angle: 53.1${Strings.Symbol.DEGREE} ${Strings.Symbol.DELTA}X: 3.0 ${Strings.Symbol.DELTA}Y: 4.0`);
|
|
54
|
+
notifySpy.mockRestore();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('Distance.action reversed horizontal line: negative delta and 180° angle', () => {
|
|
58
|
+
const notifySpy = jest.spyOn(core, 'notify');
|
|
59
|
+
|
|
60
|
+
const distance = new Distance();
|
|
61
|
+
distance.points.push(new Point(10, 0));
|
|
62
|
+
distance.points.push(new Point(0, 0));
|
|
63
|
+
distance.action();
|
|
64
|
+
|
|
65
|
+
// angle = atan2(0, -10) = 180°
|
|
66
|
+
expect(notifySpy).toHaveBeenCalledWith(`${Strings.Strings.LENGTH}: 10.0 Angle: 180.0${Strings.Symbol.DEGREE} ${Strings.Symbol.DELTA}X: -10.0 ${Strings.Symbol.DELTA}Y: 0.0`);
|
|
67
|
+
notifySpy.mockRestore();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('Distance.action non-origin start point: deltas computed from actual coordinates', () => {
|
|
71
|
+
const notifySpy = jest.spyOn(core, 'notify');
|
|
72
|
+
|
|
73
|
+
const distance = new Distance();
|
|
74
|
+
distance.points.push(new Point(5, 5));
|
|
75
|
+
distance.points.push(new Point(5, 10));
|
|
76
|
+
distance.action();
|
|
77
|
+
|
|
78
|
+
// dx=0, dy=5, length=5, angle=90°
|
|
79
|
+
expect(notifySpy).toHaveBeenCalledWith(`${Strings.Strings.LENGTH}: 5.0 Angle: 90.0${Strings.Symbol.DEGREE} ${Strings.Symbol.DELTA}X: 0.0 ${Strings.Symbol.DELTA}Y: 5.0`);
|
|
80
|
+
notifySpy.mockRestore();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// ─── execute ──────────────────────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
test('Distance.execute collects two points and calls executeCommand', async () => {
|
|
86
|
+
const executeCommandSpy = jest.fn();
|
|
87
|
+
|
|
88
|
+
await withMockInput(
|
|
89
|
+
core.scene,
|
|
90
|
+
[new Point(0, 0), new Point(10, 0)],
|
|
91
|
+
async () => {
|
|
92
|
+
const distance = new Distance();
|
|
93
|
+
await distance.execute();
|
|
94
|
+
},
|
|
95
|
+
{ extraMethods: { executeCommand: executeCommandSpy } },
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(executeCommandSpy).toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('Distance.execute returns early when first point is undefined', async () => {
|
|
102
|
+
const executeCommandSpy = jest.fn();
|
|
103
|
+
|
|
104
|
+
await withMockInput(
|
|
105
|
+
core.scene,
|
|
106
|
+
[],
|
|
107
|
+
async () => {
|
|
108
|
+
const distance = new Distance();
|
|
109
|
+
await distance.execute();
|
|
110
|
+
},
|
|
111
|
+
{ extraMethods: { executeCommand: executeCommandSpy } },
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
expect(executeCommandSpy).not.toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('Distance.execute returns early when second point is undefined', async () => {
|
|
118
|
+
const executeCommandSpy = jest.fn();
|
|
119
|
+
|
|
120
|
+
await withMockInput(
|
|
121
|
+
core.scene,
|
|
122
|
+
[new Point(0, 0)],
|
|
123
|
+
async () => {
|
|
124
|
+
const distance = new Distance();
|
|
125
|
+
await distance.execute();
|
|
126
|
+
},
|
|
127
|
+
{ extraMethods: { executeCommand: executeCommandSpy } },
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
expect(executeCommandSpy).not.toHaveBeenCalled();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('Distance.execute stores collected points for action', async () => {
|
|
134
|
+
let capturedDistance;
|
|
135
|
+
const executeCommandSpy = jest.fn();
|
|
136
|
+
|
|
137
|
+
await withMockInput(
|
|
138
|
+
core.scene,
|
|
139
|
+
[new Point(0, 0), new Point(0, 5)],
|
|
140
|
+
async () => {
|
|
141
|
+
capturedDistance = new Distance();
|
|
142
|
+
await capturedDistance.execute();
|
|
143
|
+
},
|
|
144
|
+
{ extraMethods: { executeCommand: executeCommandSpy } },
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
expect(capturedDistance.points).toHaveLength(2);
|
|
148
|
+
expect(capturedDistance.points[0].x).toBe(0);
|
|
149
|
+
expect(capturedDistance.points[0].y).toBe(0);
|
|
150
|
+
expect(capturedDistance.points[1].x).toBe(0);
|
|
151
|
+
expect(capturedDistance.points[1].y).toBe(5);
|
|
30
152
|
});
|
package/test/tools/erase.test.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import {Core} from '../../core/core/core.js';
|
|
2
|
-
import {Point} from '../../core/entities/point.js';
|
|
3
|
-
import {Erase} from '../../core/tools/erase.js';
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { Point } from '../../core/entities/point.js';
|
|
3
|
+
import { Erase } from '../../core/tools/erase.js';
|
|
4
4
|
|
|
5
5
|
const core = new Core();
|
|
6
6
|
|
|
7
7
|
test('Test Erase.action', () => {
|
|
8
8
|
// Add items to scene
|
|
9
|
-
core.scene.addItem('Line', {points: [new Point(10, 0), new Point(20, 0)]});
|
|
10
|
-
core.scene.addItem('Circle', {points: [new Point(10, 0), new Point(20, 0)]});
|
|
11
|
-
core.scene.addItem('Polyline', {points: [new Point(10, 0), new Point(20, 0)]});
|
|
12
|
-
core.scene.addItem('Arc', {points: [new Point(10, 0), new Point(10, 10), new Point(0, 10)]});
|
|
13
|
-
core.scene.addItem('Rectangle', {points: [new Point(10, 0), new Point(0, 10)]});
|
|
14
|
-
core.scene.addItem('Text', {points: [new Point(10, 0), new Point(0, 10)], height: 10, rotation: 0, string: 'text test'});
|
|
9
|
+
core.scene.addItem('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
10
|
+
core.scene.addItem('Circle', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
11
|
+
core.scene.addItem('Polyline', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
12
|
+
core.scene.addItem('Arc', { points: [new Point(10, 0), new Point(10, 10), new Point(0, 10)] });
|
|
13
|
+
core.scene.addItem('Rectangle', { points: [new Point(10, 0), new Point(0, 10)] });
|
|
14
|
+
core.scene.addItem('Text', { points: [new Point(10, 0), new Point(0, 10)], height: 10, rotation: 0, string: 'text test' });
|
|
15
15
|
|
|
16
16
|
// Add items to selection set
|
|
17
|
-
for (let i = 0; i < core.scene.
|
|
17
|
+
for (let i = 0; i < core.scene.entities.count(); i++) {
|
|
18
18
|
core.scene.selectionManager.addToSelectionSet(i);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
expect(core.scene.
|
|
21
|
+
expect(core.scene.entities.count()).toBe(6);
|
|
22
22
|
|
|
23
23
|
// Perform Erase
|
|
24
24
|
const erase = new Erase();
|
|
25
25
|
erase.action();
|
|
26
26
|
|
|
27
|
-
expect(core.scene.
|
|
27
|
+
expect(core.scene.entities.count()).toBe(0);
|
|
28
28
|
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { Point } from '../../core/entities/point.js';
|
|
3
|
+
import { Explode } from '../../core/tools/explode.js';
|
|
4
|
+
import { Line } from '../../core/entities/line.js';
|
|
5
|
+
|
|
6
|
+
const core = new Core();
|
|
7
|
+
|
|
8
|
+
test('Test Explode.action', () => {
|
|
9
|
+
const insertPoint = new Point(100, 100);
|
|
10
|
+
const insertIndex = core.scene.addItem('Insert', { points: [insertPoint] });
|
|
11
|
+
const insert = core.scene.entities.get(insertIndex);
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < 5; i++) {
|
|
14
|
+
const line = new Line({ points: [new Point(0, i * 10), new Point(100, i * 10)] });
|
|
15
|
+
insert.block.addItem(line);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
expect(core.scene.entities.count()).toBe(1);
|
|
19
|
+
|
|
20
|
+
// Add items to selection set
|
|
21
|
+
for (let i = 0; i < core.scene.entities.count(); i++) {
|
|
22
|
+
core.scene.selectionManager.addToSelectionSet(i);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Perform Explode
|
|
26
|
+
const explode = new Explode();
|
|
27
|
+
explode.action();
|
|
28
|
+
|
|
29
|
+
expect(core.scene.entities.count()).toBe(5);
|
|
30
|
+
|
|
31
|
+
// loop through all exploded items, check the type and
|
|
32
|
+
// check the points have been modified when exploded
|
|
33
|
+
const handles = new Set();
|
|
34
|
+
for (let i = 0; i < core.scene.entities.count(); i++) {
|
|
35
|
+
const item = core.scene.entities.get(i);
|
|
36
|
+
expect(item instanceof Line).toBe(true);
|
|
37
|
+
expect(item.points[0].x).toBe(0 + insertPoint.x);
|
|
38
|
+
expect(item.points[0].y).toBe(i * 10 + insertPoint.y);
|
|
39
|
+
|
|
40
|
+
// Verify each exploded entity has a unique handle
|
|
41
|
+
expect(item.handle).toBeDefined();
|
|
42
|
+
expect(handles.has(item.handle)).toBe(false);
|
|
43
|
+
handles.add(item.handle);
|
|
44
|
+
}
|
|
45
|
+
});
|