@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,529 @@
|
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { Point } from '../../core/entities/point.js';
|
|
3
|
+
import { Scale } from '../../core/tools/scale.js';
|
|
4
|
+
|
|
5
|
+
const core = new Core();
|
|
6
|
+
|
|
7
|
+
const inputScenarios = [
|
|
8
|
+
{
|
|
9
|
+
desc: 'numeric factor 2 from origin',
|
|
10
|
+
points: [new Point(10, 0), new Point(20, 0)],
|
|
11
|
+
inputs: [new Point(0, 0), 2],
|
|
12
|
+
result: [new Point(20, 0), new Point(40, 0)],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
desc: 'numeric factor 0.5 from origin',
|
|
16
|
+
points: [new Point(10, 0), new Point(20, 0)],
|
|
17
|
+
inputs: [new Point(0, 0), 0.5],
|
|
18
|
+
result: [new Point(5, 0), new Point(10, 0)],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
desc: 'point input uses distance from base as scale factor',
|
|
22
|
+
points: [new Point(1, 0), new Point(2, 0)],
|
|
23
|
+
inputs: [new Point(0, 0), new Point(3, 4)], // distance = 5 → factor = 5
|
|
24
|
+
result: [new Point(5, 0), new Point(10, 0)],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
desc: 'reference workflow with numeric ref and new length',
|
|
28
|
+
points: [new Point(10, 0), new Point(20, 0)],
|
|
29
|
+
inputs: [new Point(0, 0), 'Reference', 10, 30], // factor = 30/10 = 3
|
|
30
|
+
result: [new Point(30, 0), new Point(60, 0)],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
desc: 'reference workflow with point-based ref length',
|
|
34
|
+
points: [new Point(5, 0), new Point(10, 0)],
|
|
35
|
+
inputs: [new Point(0, 0), 'Reference', new Point(0, 0), new Point(10, 0), 20], // ref=10, new=20 → factor=2
|
|
36
|
+
result: [new Point(10, 0), new Point(20, 0)],
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
test.each(inputScenarios)('Scale.execute handles $desc', async (scenario) => {
|
|
41
|
+
const { points, inputs, result } = scenario;
|
|
42
|
+
|
|
43
|
+
core.scene.clear();
|
|
44
|
+
core.scene.selectionManager.reset();
|
|
45
|
+
|
|
46
|
+
core.scene.addItem('Line', { points });
|
|
47
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
48
|
+
|
|
49
|
+
const origInputManager = core.scene.inputManager;
|
|
50
|
+
let callCount = 0;
|
|
51
|
+
core.scene.inputManager = {
|
|
52
|
+
requestInput: async () => {
|
|
53
|
+
if (callCount < inputs.length) {
|
|
54
|
+
return inputs[callCount++];
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
executeCommand: () => {},
|
|
58
|
+
reset: () => {},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const scale = new Scale();
|
|
62
|
+
await scale.execute();
|
|
63
|
+
|
|
64
|
+
scale.action();
|
|
65
|
+
|
|
66
|
+
const line = core.scene.entities.get(0);
|
|
67
|
+
expect(line.points[0].x).toBeCloseTo(result[0].x);
|
|
68
|
+
expect(line.points[0].y).toBeCloseTo(result[0].y);
|
|
69
|
+
expect(line.points[1].x).toBeCloseTo(result[1].x);
|
|
70
|
+
expect(line.points[1].y).toBeCloseTo(result[1].y);
|
|
71
|
+
|
|
72
|
+
core.scene.inputManager = origInputManager;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('Scale.execute - cancel at base point does not scale', async () => {
|
|
76
|
+
core.scene.clear();
|
|
77
|
+
core.scene.selectionManager.reset();
|
|
78
|
+
|
|
79
|
+
core.scene.addItem('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
80
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
81
|
+
|
|
82
|
+
const origInputManager = core.scene.inputManager;
|
|
83
|
+
core.scene.inputManager = {
|
|
84
|
+
requestInput: async () => undefined,
|
|
85
|
+
executeCommand: () => {},
|
|
86
|
+
reset: () => {},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const scale = new Scale();
|
|
90
|
+
await scale.execute();
|
|
91
|
+
|
|
92
|
+
const line = core.scene.entities.get(0);
|
|
93
|
+
expect(line.points[0].x).toBeCloseTo(10);
|
|
94
|
+
expect(line.points[1].x).toBeCloseTo(20);
|
|
95
|
+
|
|
96
|
+
core.scene.inputManager = origInputManager;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('Scale.execute - cancel at factor prompt does not scale', async () => {
|
|
100
|
+
core.scene.clear();
|
|
101
|
+
core.scene.selectionManager.reset();
|
|
102
|
+
|
|
103
|
+
core.scene.addItem('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
104
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
105
|
+
|
|
106
|
+
const origInputManager = core.scene.inputManager;
|
|
107
|
+
let callCount = 0;
|
|
108
|
+
const inputs = [new Point(0, 0)]; // provides base point, then undefined on factor
|
|
109
|
+
core.scene.inputManager = {
|
|
110
|
+
requestInput: async () => {
|
|
111
|
+
if (callCount < inputs.length) {
|
|
112
|
+
return inputs[callCount++];
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
executeCommand: () => {},
|
|
116
|
+
reset: () => {},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const scale = new Scale();
|
|
120
|
+
await scale.execute();
|
|
121
|
+
|
|
122
|
+
const line = core.scene.entities.get(0);
|
|
123
|
+
expect(line.points[0].x).toBeCloseTo(10);
|
|
124
|
+
expect(line.points[1].x).toBeCloseTo(20);
|
|
125
|
+
|
|
126
|
+
core.scene.inputManager = origInputManager;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('Scale.execute - entity count unchanged after execute', async () => {
|
|
130
|
+
core.scene.clear();
|
|
131
|
+
core.scene.selectionManager.reset();
|
|
132
|
+
|
|
133
|
+
core.scene.addItem('Line', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
134
|
+
core.scene.addItem('Circle', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
135
|
+
|
|
136
|
+
const entityCount = core.scene.entities.count();
|
|
137
|
+
|
|
138
|
+
for (let i = 0; i < entityCount; i++) {
|
|
139
|
+
core.scene.selectionManager.addToSelectionSet(i);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const origInputManager = core.scene.inputManager;
|
|
143
|
+
let callCount = 0;
|
|
144
|
+
const inputs = [new Point(0, 0), 3];
|
|
145
|
+
core.scene.inputManager = {
|
|
146
|
+
requestInput: async () => {
|
|
147
|
+
if (callCount < inputs.length) {
|
|
148
|
+
return inputs[callCount++];
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
executeCommand: () => {},
|
|
152
|
+
reset: () => {},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const scale = new Scale();
|
|
156
|
+
await scale.execute();
|
|
157
|
+
scale.action();
|
|
158
|
+
|
|
159
|
+
expect(core.scene.entities.count()).toBe(entityCount);
|
|
160
|
+
|
|
161
|
+
core.scene.inputManager = origInputManager;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test('Test Scale.action - scale by factor 2 from origin', () => {
|
|
165
|
+
core.scene.clear();
|
|
166
|
+
core.scene.selectionManager.reset();
|
|
167
|
+
|
|
168
|
+
core.scene.addItem('Line', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
169
|
+
core.scene.addItem('Circle', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
170
|
+
core.scene.addItem('Polyline', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
171
|
+
core.scene.addItem('Arc', { points: [new Point(5, 0), new Point(10, 0), new Point(5, 5)] });
|
|
172
|
+
core.scene.addItem('Rectangle', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
173
|
+
|
|
174
|
+
for (let i = 0; i < core.scene.entities.count(); i++) {
|
|
175
|
+
core.scene.selectionManager.addToSelectionSet(i);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const scale = new Scale();
|
|
179
|
+
scale.points.push(new Point(0, 0)); // base point at origin
|
|
180
|
+
scale.scaleFactor = 2;
|
|
181
|
+
|
|
182
|
+
scale.action();
|
|
183
|
+
|
|
184
|
+
for (let i = 0; i < core.scene.entities.count(); i++) {
|
|
185
|
+
expect(core.scene.entities.get(i).points[0].x).toBeCloseTo(10);
|
|
186
|
+
expect(core.scene.entities.get(i).points[0].y).toBeCloseTo(0);
|
|
187
|
+
expect(core.scene.entities.get(i).points[1].x).toBeCloseTo(20);
|
|
188
|
+
expect(core.scene.entities.get(i).points[1].y).toBeCloseTo(0);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('Test Scale.action - scale by factor 0.5 from origin', () => {
|
|
193
|
+
core.scene.clear();
|
|
194
|
+
core.scene.selectionManager.reset();
|
|
195
|
+
|
|
196
|
+
core.scene.addItem('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
197
|
+
|
|
198
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
199
|
+
|
|
200
|
+
const scale = new Scale();
|
|
201
|
+
scale.points.push(new Point(0, 0));
|
|
202
|
+
scale.scaleFactor = 0.5;
|
|
203
|
+
|
|
204
|
+
scale.action();
|
|
205
|
+
|
|
206
|
+
const line = core.scene.entities.get(0);
|
|
207
|
+
expect(line.points[0].x).toBeCloseTo(5);
|
|
208
|
+
expect(line.points[0].y).toBeCloseTo(0);
|
|
209
|
+
expect(line.points[1].x).toBeCloseTo(10);
|
|
210
|
+
expect(line.points[1].y).toBeCloseTo(0);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('Test Scale.action - scale from offset base point', () => {
|
|
214
|
+
core.scene.clear();
|
|
215
|
+
core.scene.selectionManager.reset();
|
|
216
|
+
|
|
217
|
+
core.scene.addItem('Line', { points: [new Point(10, 10), new Point(20, 10)] });
|
|
218
|
+
|
|
219
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
220
|
+
|
|
221
|
+
const scale = new Scale();
|
|
222
|
+
scale.points.push(new Point(10, 10)); // base at first point
|
|
223
|
+
scale.scaleFactor = 2;
|
|
224
|
+
|
|
225
|
+
scale.action();
|
|
226
|
+
|
|
227
|
+
const line = core.scene.entities.get(0);
|
|
228
|
+
// base point stays fixed, second point doubles away from it
|
|
229
|
+
expect(line.points[0].x).toBeCloseTo(10);
|
|
230
|
+
expect(line.points[0].y).toBeCloseTo(10);
|
|
231
|
+
expect(line.points[1].x).toBeCloseTo(30);
|
|
232
|
+
expect(line.points[1].y).toBeCloseTo(10);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test('Test Scale.action - entity count unchanged (in-place update)', () => {
|
|
236
|
+
core.scene.clear();
|
|
237
|
+
core.scene.selectionManager.reset();
|
|
238
|
+
|
|
239
|
+
core.scene.addItem('Line', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
240
|
+
core.scene.addItem('Circle', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
241
|
+
|
|
242
|
+
const entityCount = core.scene.entities.count();
|
|
243
|
+
|
|
244
|
+
for (let i = 0; i < entityCount; i++) {
|
|
245
|
+
core.scene.selectionManager.addToSelectionSet(i);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const scale = new Scale();
|
|
249
|
+
scale.points.push(new Point(0, 0));
|
|
250
|
+
scale.scaleFactor = 3;
|
|
251
|
+
|
|
252
|
+
scale.action();
|
|
253
|
+
|
|
254
|
+
// Scale is in-place — no new entities added
|
|
255
|
+
expect(core.scene.entities.count()).toBe(entityCount);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test('Test Scale.action - scale factor 1 leaves points unchanged', () => {
|
|
259
|
+
core.scene.clear();
|
|
260
|
+
core.scene.selectionManager.reset();
|
|
261
|
+
|
|
262
|
+
core.scene.addItem('Line', { points: [new Point(10, 20), new Point(30, 40)] });
|
|
263
|
+
|
|
264
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
265
|
+
|
|
266
|
+
const scale = new Scale();
|
|
267
|
+
scale.points.push(new Point(0, 0));
|
|
268
|
+
scale.scaleFactor = 1;
|
|
269
|
+
|
|
270
|
+
scale.action();
|
|
271
|
+
|
|
272
|
+
const line = core.scene.entities.get(0);
|
|
273
|
+
expect(line.points[0].x).toBeCloseTo(10);
|
|
274
|
+
expect(line.points[0].y).toBeCloseTo(20);
|
|
275
|
+
expect(line.points[1].x).toBeCloseTo(30);
|
|
276
|
+
expect(line.points[1].y).toBeCloseTo(40);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test('Test Scale.action - scale 2D point (non-axis-aligned)', () => {
|
|
280
|
+
core.scene.clear();
|
|
281
|
+
core.scene.selectionManager.reset();
|
|
282
|
+
|
|
283
|
+
core.scene.addItem('Line', { points: [new Point(5, 5), new Point(10, 10)] });
|
|
284
|
+
|
|
285
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
286
|
+
|
|
287
|
+
const scale = new Scale();
|
|
288
|
+
scale.points.push(new Point(0, 0));
|
|
289
|
+
scale.scaleFactor = 2;
|
|
290
|
+
|
|
291
|
+
scale.action();
|
|
292
|
+
|
|
293
|
+
const line = core.scene.entities.get(0);
|
|
294
|
+
expect(line.points[0].x).toBeCloseTo(10);
|
|
295
|
+
expect(line.points[0].y).toBeCloseTo(10);
|
|
296
|
+
expect(line.points[1].x).toBeCloseTo(20);
|
|
297
|
+
expect(line.points[1].y).toBeCloseTo(20);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test('Test Scale.action - empty selection does not throw', () => {
|
|
301
|
+
core.scene.clear();
|
|
302
|
+
core.scene.selectionManager.reset();
|
|
303
|
+
|
|
304
|
+
core.scene.addItem('Line', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
305
|
+
// deliberately do not add anything to the selection set
|
|
306
|
+
|
|
307
|
+
const scale = new Scale();
|
|
308
|
+
scale.points.push(new Point(0, 0));
|
|
309
|
+
scale.scaleFactor = 2;
|
|
310
|
+
|
|
311
|
+
expect(() => scale.action()).not.toThrow();
|
|
312
|
+
|
|
313
|
+
// Entity should be unmodified
|
|
314
|
+
const line = core.scene.entities.get(0);
|
|
315
|
+
expect(line.points[0].x).toBeCloseTo(5);
|
|
316
|
+
expect(line.points[1].x).toBeCloseTo(10);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
test('Test Scale.getScaledPoints - from origin', () => {
|
|
320
|
+
const scale = new Scale();
|
|
321
|
+
const base = new Point(0, 0);
|
|
322
|
+
|
|
323
|
+
const points = [new Point(5, 0), new Point(0, 5)];
|
|
324
|
+
const result = scale.getScaledPoints(points, base, 2);
|
|
325
|
+
|
|
326
|
+
expect(result[0].x).toBeCloseTo(10);
|
|
327
|
+
expect(result[0].y).toBeCloseTo(0);
|
|
328
|
+
expect(result[1].x).toBeCloseTo(0);
|
|
329
|
+
expect(result[1].y).toBeCloseTo(10);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test('Test Scale.getScaledPoints - from offset base', () => {
|
|
333
|
+
const scale = new Scale();
|
|
334
|
+
const base = new Point(10, 10);
|
|
335
|
+
|
|
336
|
+
const points = [new Point(20, 10), new Point(10, 20)];
|
|
337
|
+
const result = scale.getScaledPoints(points, base, 3);
|
|
338
|
+
|
|
339
|
+
// (20-10)*3 + 10 = 40, (10-10)*3 + 10 = 10
|
|
340
|
+
expect(result[0].x).toBeCloseTo(40);
|
|
341
|
+
expect(result[0].y).toBeCloseTo(10);
|
|
342
|
+
// (10-10)*3 + 10 = 10, (20-10)*3 + 10 = 40
|
|
343
|
+
expect(result[1].x).toBeCloseTo(10);
|
|
344
|
+
expect(result[1].y).toBeCloseTo(40);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test('Test Scale.getScaledPoints - preserves bulge and sequence', () => {
|
|
348
|
+
const scale = new Scale();
|
|
349
|
+
const base = new Point(0, 0);
|
|
350
|
+
|
|
351
|
+
const points = [new Point(5, 0, 0.5, 1), new Point(10, 0, -0.25, 2)];
|
|
352
|
+
const result = scale.getScaledPoints(points, base, 2);
|
|
353
|
+
|
|
354
|
+
expect(result[0].bulge).toBe(0.5);
|
|
355
|
+
expect(result[0].sequence).toBe(1);
|
|
356
|
+
expect(result[1].bulge).toBe(-0.25);
|
|
357
|
+
expect(result[1].sequence).toBe(2);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
test('Scale.execute - requests selection set when none pre-selected', async () => {
|
|
361
|
+
core.scene.clear();
|
|
362
|
+
core.scene.selectionManager.reset();
|
|
363
|
+
|
|
364
|
+
core.scene.addItem('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
365
|
+
// Intentionally do NOT add to selection set — triggers the SELECTIONSET prompt
|
|
366
|
+
|
|
367
|
+
const origInputManager = core.scene.inputManager;
|
|
368
|
+
let callCount = 0;
|
|
369
|
+
core.scene.inputManager = {
|
|
370
|
+
requestInput: async () => {
|
|
371
|
+
callCount++;
|
|
372
|
+
if (callCount === 1) {
|
|
373
|
+
// SELECTIONSET prompt: populate the selection manually and return
|
|
374
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (callCount === 2) return new Point(0, 0); // base point
|
|
378
|
+
if (callCount === 3) return 2; // scale factor
|
|
379
|
+
},
|
|
380
|
+
executeCommand: () => {},
|
|
381
|
+
reset: () => {},
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const scale = new Scale();
|
|
385
|
+
await scale.execute();
|
|
386
|
+
scale.action();
|
|
387
|
+
|
|
388
|
+
const line = core.scene.entities.get(0);
|
|
389
|
+
expect(line.points[0].x).toBeCloseTo(20);
|
|
390
|
+
expect(line.points[1].x).toBeCloseTo(40);
|
|
391
|
+
|
|
392
|
+
core.scene.inputManager = origInputManager;
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
test('Scale.execute - reference with zero length returns without scaling', async () => {
|
|
396
|
+
core.scene.clear();
|
|
397
|
+
core.scene.selectionManager.reset();
|
|
398
|
+
|
|
399
|
+
core.scene.addItem('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
400
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
401
|
+
|
|
402
|
+
const origInputManager = core.scene.inputManager;
|
|
403
|
+
let callCount = 0;
|
|
404
|
+
// base point, then 'Reference', then ref length = 0
|
|
405
|
+
const inputs = [new Point(0, 0), 'Reference', 0];
|
|
406
|
+
core.scene.inputManager = {
|
|
407
|
+
requestInput: async () => {
|
|
408
|
+
if (callCount < inputs.length) {
|
|
409
|
+
return inputs[callCount++];
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
executeCommand: () => {},
|
|
413
|
+
reset: () => {},
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const scale = new Scale();
|
|
417
|
+
await scale.execute();
|
|
418
|
+
// action() should not be called — execute returned early, scaleFactor unchanged (1)
|
|
419
|
+
scale.action();
|
|
420
|
+
|
|
421
|
+
// Entity should be unchanged (scaleFactor stayed at 1 but no second point pushed,
|
|
422
|
+
// so points array only has base — action uses scaleFactor=1)
|
|
423
|
+
const line = core.scene.entities.get(0);
|
|
424
|
+
expect(line.points[0].x).toBeCloseTo(10);
|
|
425
|
+
expect(line.points[1].x).toBeCloseTo(20);
|
|
426
|
+
|
|
427
|
+
core.scene.inputManager = origInputManager;
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test('Scale.preview - no points set, adds no temp entities', () => {
|
|
431
|
+
core.scene.clear();
|
|
432
|
+
core.scene.selectionManager.reset();
|
|
433
|
+
|
|
434
|
+
core.scene.addItem('Line', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
435
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
436
|
+
|
|
437
|
+
const scale = new Scale();
|
|
438
|
+
// No points — guard condition prevents any work
|
|
439
|
+
scale.preview();
|
|
440
|
+
|
|
441
|
+
expect(core.scene.tempEntities.count()).toBe(0);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
test('Scale.preview - referencePoint set, suppresses preview', () => {
|
|
445
|
+
core.scene.clear();
|
|
446
|
+
core.scene.selectionManager.reset();
|
|
447
|
+
|
|
448
|
+
core.scene.addItem('Line', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
449
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
450
|
+
|
|
451
|
+
const scale = new Scale();
|
|
452
|
+
scale.points.push(new Point(0, 0));
|
|
453
|
+
scale.referencePoint = new Point(0, 0); // non-null blocks preview
|
|
454
|
+
|
|
455
|
+
scale.preview();
|
|
456
|
+
|
|
457
|
+
expect(core.scene.tempEntities.count()).toBe(0);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
test('Scale.preview - mouse on base point (distance 0), draws line but skips scaling', () => {
|
|
461
|
+
core.scene.clear();
|
|
462
|
+
core.scene.selectionManager.reset();
|
|
463
|
+
|
|
464
|
+
core.scene.addItem('Line', { points: [new Point(5, 0), new Point(10, 0)] });
|
|
465
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
466
|
+
|
|
467
|
+
const scale = new Scale();
|
|
468
|
+
// Push base point identical to default mouse scene position (0,0)
|
|
469
|
+
scale.points.push(new Point(0, 0));
|
|
470
|
+
scale.referencePoint = null;
|
|
471
|
+
|
|
472
|
+
scale.preview();
|
|
473
|
+
|
|
474
|
+
// Temp line is still created
|
|
475
|
+
expect(core.scene.tempEntities.count()).toBeGreaterThanOrEqual(1);
|
|
476
|
+
|
|
477
|
+
// Selected item points should be unchanged (scaling skipped)
|
|
478
|
+
const previewItem = core.scene.selectionManager.selectedItems[0];
|
|
479
|
+
expect(previewItem.points[0].x).toBeCloseTo(5);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
test('Scale.preview - one point set, draws temp line and scales selected items', () => {
|
|
483
|
+
core.scene.clear();
|
|
484
|
+
core.scene.selectionManager.reset();
|
|
485
|
+
|
|
486
|
+
core.scene.addItem('Line', { points: [new Point(1, 0), new Point(2, 0)] });
|
|
487
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
488
|
+
|
|
489
|
+
const scale = new Scale();
|
|
490
|
+
// Base point away from the default mouse scene position so distance > 0
|
|
491
|
+
scale.points.push(new Point(100, 100));
|
|
492
|
+
scale.referencePoint = null;
|
|
493
|
+
|
|
494
|
+
scale.preview();
|
|
495
|
+
|
|
496
|
+
// Temp line should be created
|
|
497
|
+
expect(core.scene.tempEntities.count()).toBeGreaterThanOrEqual(1);
|
|
498
|
+
|
|
499
|
+
// Preview item should have been scaled (x differs from original 1.0)
|
|
500
|
+
const previewItem = core.scene.selectionManager.selectedItems[0];
|
|
501
|
+
expect(previewItem.points[0].x).not.toBeCloseTo(1);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
test('Scale.preview - reference mode uses referenceLength to compute factor', () => {
|
|
505
|
+
core.scene.clear();
|
|
506
|
+
core.scene.selectionManager.reset();
|
|
507
|
+
|
|
508
|
+
// Line at x=10..20, y=0
|
|
509
|
+
core.scene.addItem('Line', { points: [new Point(10, 0), new Point(20, 0)] });
|
|
510
|
+
core.scene.selectionManager.addToSelectionSet(0);
|
|
511
|
+
|
|
512
|
+
const scale = new Scale();
|
|
513
|
+
scale.points.push(new Point(0, 0)); // base at origin
|
|
514
|
+
scale.referencePoint = null; // reference collection done — preview active
|
|
515
|
+
scale.referenceLength = 10; // established reference length
|
|
516
|
+
|
|
517
|
+
// The default mouse scene position will give some distance from (0,0).
|
|
518
|
+
// We can't control the mouse, so just verify the factor applied is
|
|
519
|
+
// distance/referenceLength rather than raw distance: reload the selectedItems
|
|
520
|
+
// before and after with a known referenceLength to confirm scaling occurred.
|
|
521
|
+
scale.preview();
|
|
522
|
+
|
|
523
|
+
expect(core.scene.tempEntities.count()).toBeGreaterThanOrEqual(1);
|
|
524
|
+
|
|
525
|
+
// The preview item's first point should differ from the original (10,0)
|
|
526
|
+
// because the factor (distance/10) is applied
|
|
527
|
+
const previewItem = core.scene.selectionManager.selectedItems[0];
|
|
528
|
+
expect(previewItem.points[0].x).not.toBeCloseTo(10);
|
|
529
|
+
});
|