@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,162 @@
|
|
|
1
|
+
import { Tool } from './tool.js';
|
|
2
|
+
import { Strings } from '../lib/strings.js';
|
|
3
|
+
import { Constants } from '../lib/constants.js';
|
|
4
|
+
import { BasePolyline } from '../entities/basePolyline.js';
|
|
5
|
+
import { RemoveState, UpdateState } from '../lib/stateManager.js';
|
|
6
|
+
import { CornerEntity } from './cornerEntity.js';
|
|
7
|
+
import { Intersection } from '../lib/intersect.js';
|
|
8
|
+
|
|
9
|
+
import { DesignCore } from '../designCore.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* ChamferFilletBase Class
|
|
13
|
+
* Base class for Chamfer and Fillet commands, providing shared entity selection
|
|
14
|
+
* state, segment resolution, and sharp-trim logic.
|
|
15
|
+
* @extends Tool
|
|
16
|
+
*/
|
|
17
|
+
export class ChamferFilletBase extends Tool {
|
|
18
|
+
/** Create a ChamferFilletBase command */
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.firstPick = new CornerEntity();
|
|
22
|
+
this.secondPick = new CornerEntity();
|
|
23
|
+
// Shared corner geometry computed by resolveCornerGeometry() before action()
|
|
24
|
+
// If the lines form a cross there are four possible locations.
|
|
25
|
+
// The click points are used to determine which corner to operate on.
|
|
26
|
+
this.intersectionPoint = null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Compute the corner geometry shared by Fillet and Chamfer and store it on the instance.
|
|
31
|
+
* Validates that both resolved segments are Lines, finds the virtual intersection
|
|
32
|
+
* of the two infinite lines, and derives click-side directions and kept endpoints.
|
|
33
|
+
* Returns false and notifies the user on any invalid configuration.
|
|
34
|
+
* @param {string} noEntityMsg - message shown when a resolved segment is not a Line
|
|
35
|
+
* @return {boolean}
|
|
36
|
+
*/
|
|
37
|
+
resolveCornerGeometry(noEntityMsg) {
|
|
38
|
+
if (!this.firstPick.resolveEndpoints()) {
|
|
39
|
+
DesignCore.Core.notify(`${this.type} - ${this.firstPick.entity.type} ${noEntityMsg}`);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (!this.secondPick.resolveEndpoints()) {
|
|
43
|
+
DesignCore.Core.notify(`${this.type} - ${this.secondPick.entity.type} ${noEntityMsg}`);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const result = Intersection.intersectSegmentSegment(
|
|
48
|
+
this.firstPick.lineStart, this.firstPick.lineEnd,
|
|
49
|
+
this.secondPick.lineStart, this.secondPick.lineEnd,
|
|
50
|
+
true, true,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Reject parallel, collinear, or overlapping segments — no unique corner exists.
|
|
54
|
+
const status = result.status;
|
|
55
|
+
if (status === Intersection.Status.PARALLEL ||
|
|
56
|
+
status === Intersection.Status.OVERLAPPING ||
|
|
57
|
+
status === Intersection.Status.COINCIDENT) {
|
|
58
|
+
DesignCore.Core.notify(`${this.type} - ${Strings.Error.ERROR}:${Strings.Error.PARALLELLINES}`);
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Guard against near-parallel directions that pass the status check but
|
|
63
|
+
// produce an unreliable intersection point far from both segments.
|
|
64
|
+
const dir1 = this.firstPick.lineEnd.subtract(this.firstPick.lineStart);
|
|
65
|
+
const dir2 = this.secondPick.lineEnd.subtract(this.secondPick.lineStart);
|
|
66
|
+
const cross = dir1.cross(dir2);
|
|
67
|
+
const len1 = dir1.length();
|
|
68
|
+
const len2 = dir2.length();
|
|
69
|
+
if (len1 === 0 || len2 === 0 || Math.abs(cross) / (len1 * len2) < Constants.Tolerance.EPSILON) {
|
|
70
|
+
DesignCore.Core.notify(`${this.type} - ${Strings.Error.ERROR}:${Strings.Error.PARALLELLINES}`);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this.intersectionPoint = result.points[0] || null;
|
|
75
|
+
|
|
76
|
+
if (!this.intersectionPoint) {
|
|
77
|
+
DesignCore.Core.notify(`${this.type} - ${Strings.Error.ERROR}:${Strings.Error.PARALLELLINES}`);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (this.firstPick.clickDistance(this.intersectionPoint) < Constants.Tolerance.EPSILON ||
|
|
82
|
+
this.secondPick.clickDistance(this.intersectionPoint) < Constants.Tolerance.EPSILON) {
|
|
83
|
+
DesignCore.Core.notify(`${this.type} - ${Strings.Error.SELECTION}`);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Trim both entities to the sharp intersection point with no arc or chamfer line.
|
|
92
|
+
* Handles Line+Line, Polyline+Polyline (same entity), and Line+Polyline cases.
|
|
93
|
+
* Reads geometry from instance fields set by resolveCornerGeometry().
|
|
94
|
+
* @return {Array} - array of state changes to be committed by the caller
|
|
95
|
+
*/
|
|
96
|
+
applySharpTrim() {
|
|
97
|
+
const firstIsPolyline = this.firstPick.entity instanceof BasePolyline;
|
|
98
|
+
const secondIsPolyline = this.secondPick.entity instanceof BasePolyline;
|
|
99
|
+
|
|
100
|
+
// Line + Line: trim both lines to the intersection point.
|
|
101
|
+
if (!firstIsPolyline && !secondIsPolyline) {
|
|
102
|
+
return [
|
|
103
|
+
new UpdateState(this.firstPick.entity, { points: [this.firstPick.lineKeptEnd(this.intersectionPoint), this.intersectionPoint] }),
|
|
104
|
+
new UpdateState(this.secondPick.entity, { points: [this.secondPick.lineKeptEnd(this.intersectionPoint), this.intersectionPoint] }),
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Polyline + Polyline (same entity): replace the shared corner vertex (or open endpoints)
|
|
109
|
+
// with the intersection point.
|
|
110
|
+
if (firstIsPolyline && secondIsPolyline && this.firstPick.entity === this.secondPick.entity) {
|
|
111
|
+
const lastIdx = this.firstPick.entity.points.length - 1;
|
|
112
|
+
const segDiff = Math.abs(this.firstPick.segmentIndex - this.secondPick.segmentIndex);
|
|
113
|
+
const isOpenEnds = !this.firstPick.entity.flags.hasFlag(1) && segDiff !== 1 && (
|
|
114
|
+
(this.firstPick.segmentIndex === 1 && this.secondPick.segmentIndex === lastIdx) ||
|
|
115
|
+
(this.firstPick.segmentIndex === lastIdx && this.secondPick.segmentIndex === 1)
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const newPoints = this.firstPick.entity.points.map((p) => p.clone());
|
|
119
|
+
|
|
120
|
+
if (isOpenEnds) {
|
|
121
|
+
newPoints[0] = this.intersectionPoint.clone();
|
|
122
|
+
newPoints[lastIdx] = this.intersectionPoint.clone();
|
|
123
|
+
} else {
|
|
124
|
+
const closeSegIdx = this.firstPick.entity.points.length;
|
|
125
|
+
const seg1 = this.firstPick.segmentIndex;
|
|
126
|
+
const seg2 = this.secondPick.segmentIndex;
|
|
127
|
+
const isClosingWrap = (seg1 === closeSegIdx && seg2 === 1) || (seg2 === closeSegIdx && seg1 === 1);
|
|
128
|
+
const cornerIdx = isClosingWrap ? 0 : Math.min(seg1, seg2);
|
|
129
|
+
newPoints.splice(cornerIdx, 1, this.intersectionPoint.clone());
|
|
130
|
+
}
|
|
131
|
+
return [new UpdateState(this.firstPick.entity, { points: newPoints })];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Line + Polyline (or Polyline + Line): consume the line into the polyline.
|
|
135
|
+
const poly = firstIsPolyline ? this.firstPick : this.secondPick;
|
|
136
|
+
const line = firstIsPolyline ? this.secondPick : this.firstPick;
|
|
137
|
+
const polySegIdx = poly.segmentIndex;
|
|
138
|
+
const keepStart = poly.keepStart(this.intersectionPoint);
|
|
139
|
+
let newPoints;
|
|
140
|
+
if (keepStart) {
|
|
141
|
+
// Keep the polyline points up to (not including) the selected segment start,
|
|
142
|
+
// trim to the intersection and append the kept end of the line.
|
|
143
|
+
newPoints = [
|
|
144
|
+
...poly.entity.points.slice(0, polySegIdx).map((p) => p.clone()),
|
|
145
|
+
this.intersectionPoint.clone(),
|
|
146
|
+
line.lineKeptEnd(this.intersectionPoint).clone(),
|
|
147
|
+
];
|
|
148
|
+
} else {
|
|
149
|
+
// Keep the polyline points from the selected segment start onwards,
|
|
150
|
+
// prepending the kept end of the line and the intersection.
|
|
151
|
+
newPoints = [
|
|
152
|
+
line.lineKeptEnd(this.intersectionPoint).clone(),
|
|
153
|
+
this.intersectionPoint.clone(),
|
|
154
|
+
...poly.entity.points.slice(polySegIdx).map((p) => p.clone()),
|
|
155
|
+
];
|
|
156
|
+
}
|
|
157
|
+
return [
|
|
158
|
+
new RemoveState(line.entity),
|
|
159
|
+
new UpdateState(poly.entity, { points: newPoints }),
|
|
160
|
+
];
|
|
161
|
+
}
|
|
162
|
+
}
|
package/core/tools/copy.js
CHANGED
|
@@ -1,21 +1,39 @@
|
|
|
1
|
-
import {Utils} from '../lib/utils.js';
|
|
2
|
-
import {Strings} from '../lib/strings.js';
|
|
3
|
-
import {Tool} from './tool.js';
|
|
4
|
-
import {Input, PromptOptions} from '../lib/inputManager.js';
|
|
5
|
-
import {Logging} from '../lib/logging.js';
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
|
|
1
|
+
import { Utils } from '../lib/utils.js';
|
|
2
|
+
import { Strings } from '../lib/strings.js';
|
|
3
|
+
import { Tool } from './tool.js';
|
|
4
|
+
import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
5
|
+
import { Logging } from '../lib/logging.js';
|
|
6
|
+
import { Point } from '../entities/point.js';
|
|
7
|
+
import { AddState } from '../lib/stateManager.js';
|
|
8
|
+
|
|
9
|
+
import { DesignCore } from '../designCore.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Copy Command Class
|
|
13
|
+
* @extends Tool
|
|
14
|
+
*/
|
|
9
15
|
export class Copy extends Tool {
|
|
16
|
+
/** Create a Copy command */
|
|
10
17
|
constructor() {
|
|
11
18
|
super();
|
|
12
19
|
}
|
|
13
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Register the command
|
|
23
|
+
* @return {Object}
|
|
24
|
+
* command = name of the command
|
|
25
|
+
* shortcut = shortcut for the command
|
|
26
|
+
* type = type to group command in toolbars (omitted if not shown)
|
|
27
|
+
*/
|
|
14
28
|
static register() {
|
|
15
|
-
const command = {command: 'Copy', shortcut: 'CO', type: 'Tool'};
|
|
29
|
+
const command = { command: 'Copy', shortcut: 'CO', type: 'Tool' };
|
|
16
30
|
return command;
|
|
17
31
|
}
|
|
18
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Execute method
|
|
35
|
+
* executes the workflow, requesting input required to perform the command
|
|
36
|
+
*/
|
|
19
37
|
async execute() {
|
|
20
38
|
try {
|
|
21
39
|
const op = new PromptOptions(Strings.Input.SELECTIONSET, [Input.Type.SELECTIONSET]);
|
|
@@ -26,60 +44,70 @@ export class Copy extends Tool {
|
|
|
26
44
|
|
|
27
45
|
const op2 = new PromptOptions(Strings.Input.BASEPOINT, [Input.Type.POINT]);
|
|
28
46
|
const pt1 = await DesignCore.Scene.inputManager.requestInput(op2);
|
|
47
|
+
if (pt1 === undefined) return;
|
|
29
48
|
this.points.push(pt1);
|
|
30
49
|
|
|
31
|
-
const op3 = new PromptOptions(Strings.Input.DESTINATION, [Input.Type.POINT, Input.Type.
|
|
32
|
-
|
|
50
|
+
const op3 = new PromptOptions(Strings.Input.DESTINATION, [Input.Type.POINT, Input.Type.DYNAMIC]);
|
|
51
|
+
while (true) {
|
|
52
|
+
// Reset to just the base point
|
|
53
|
+
this.points = [this.points[0]];
|
|
54
|
+
|
|
55
|
+
// Anchor inputPoint to the base point so DYNAMIC (distance) input always
|
|
56
|
+
// projects relative to it, not relative to the last copied position.
|
|
57
|
+
DesignCore.Scene.inputManager.inputPoint = this.points[0];
|
|
33
58
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const angle = Utils.degrees2radians(DesignCore.Mouse.inputAngle());
|
|
39
|
-
const point = basePoint.project(angle, pt2);
|
|
40
|
-
this.points.push(point);
|
|
59
|
+
const pt2 = await DesignCore.Scene.inputManager.requestInput(op3);
|
|
60
|
+
if (pt2 === undefined) break;
|
|
61
|
+
this.points[1] = pt2;
|
|
62
|
+
DesignCore.Scene.inputManager.actionCommand();
|
|
41
63
|
}
|
|
42
64
|
|
|
43
65
|
DesignCore.Scene.inputManager.executeCommand();
|
|
44
|
-
} catch (
|
|
66
|
+
} catch (err) {
|
|
45
67
|
Logging.instance.error(`${this.type} - ${err}`);
|
|
46
68
|
}
|
|
47
69
|
}
|
|
48
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Preview the command during execution
|
|
73
|
+
*/
|
|
49
74
|
preview() {
|
|
50
75
|
if (this.points.length >= 1) {
|
|
51
76
|
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
52
77
|
|
|
53
78
|
// Draw a line
|
|
54
79
|
const points = [this.points.at(-1), mousePoint];
|
|
80
|
+
DesignCore.Scene.tempEntities.create('Line', { points: points });
|
|
55
81
|
|
|
56
|
-
|
|
82
|
+
const delta = mousePoint.subtract(this.lastMousePoint || this.points[0]);
|
|
83
|
+
this.lastMousePoint = mousePoint;
|
|
57
84
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
for (let j = 0; j <DesignCore.Scene.selectionManager.selectedItems[i].points.length; j++) {
|
|
63
|
-
DesignCore.Scene.selectionManager.selectedItems[i].points[j].x = DesignCore.Scene.items[DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]].points[j].x + xDelta;
|
|
64
|
-
DesignCore.Scene.selectionManager.selectedItems[i].points[j].y = DesignCore.Scene.items[DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]].points[j].y + yDelta;
|
|
65
|
-
}
|
|
85
|
+
for (let i = 0; i < DesignCore.Scene.selectionManager.selectedItems.length; i++) {
|
|
86
|
+
const item = DesignCore.Scene.selectionManager.selectedItems[i];
|
|
87
|
+
const offsetPoints = item.points.map((p) => new Point(p.x, p.y, p.bulge, p.sequence).add(delta));
|
|
88
|
+
item.setProperty('points', offsetPoints);
|
|
66
89
|
}
|
|
67
90
|
}
|
|
68
91
|
}
|
|
69
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Perform the command
|
|
95
|
+
*/
|
|
70
96
|
action() {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
// points[1] is cleared before each destination prompt
|
|
98
|
+
// executeCommand() calls action() - guard on missing points and duplication
|
|
99
|
+
if (!this.points[1]) return;
|
|
100
|
+
const delta = this.points[1].subtract(this.points[0]);
|
|
101
|
+
const stateChanges = [];
|
|
102
|
+
|
|
103
|
+
for (let i = 0; i < DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
|
|
104
|
+
const copyofitem = Utils.cloneObject(DesignCore.Scene.entities.get(DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]));
|
|
105
|
+
const offsetPoints = copyofitem.points.map((p) => new Point(p.x, p.y, p.bulge, p.sequence).add(delta));
|
|
106
|
+
copyofitem.setProperty('points', offsetPoints);
|
|
107
|
+
const stateChange = new AddState(copyofitem);
|
|
108
|
+
stateChanges.push(stateChange);
|
|
83
109
|
}
|
|
110
|
+
|
|
111
|
+
DesignCore.Scene.commit(stateChanges);
|
|
84
112
|
};
|
|
85
113
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Strings } from '../lib/strings.js';
|
|
2
|
+
import { Tool } from './tool.js';
|
|
3
|
+
import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
4
|
+
import { Logging } from '../lib/logging.js';
|
|
5
|
+
|
|
6
|
+
import { DesignCore } from '../designCore.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Copybase Command Class
|
|
10
|
+
* @extends Tool
|
|
11
|
+
*/
|
|
12
|
+
export class Copybase extends Tool {
|
|
13
|
+
/** Create a Copybase command */
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Register the command
|
|
20
|
+
* @return {Object}
|
|
21
|
+
* command = name of the command
|
|
22
|
+
* shortcut = shortcut for the command
|
|
23
|
+
* type = type to group command in toolbars (omitted if not shown)
|
|
24
|
+
*/
|
|
25
|
+
static register() {
|
|
26
|
+
const command = { command: 'Copybase', shortcut: 'COPYBASE' };
|
|
27
|
+
return command;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Execute method
|
|
32
|
+
* executes the workflow, requesting input required to perform the command
|
|
33
|
+
*/
|
|
34
|
+
async execute() {
|
|
35
|
+
try {
|
|
36
|
+
const op = new PromptOptions(Strings.Input.SELECTIONSET, [Input.Type.SELECTIONSET]);
|
|
37
|
+
|
|
38
|
+
if (!DesignCore.Scene.selectionManager.selectionSet.selectionSet.length) {
|
|
39
|
+
await DesignCore.Scene.inputManager.requestInput(op);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const op1 = new PromptOptions(Strings.Input.BASEPOINT, [Input.Type.POINT]);
|
|
43
|
+
const pt0 = await DesignCore.Scene.inputManager.requestInput(op1);
|
|
44
|
+
this.points.push(pt0);
|
|
45
|
+
|
|
46
|
+
DesignCore.Scene.inputManager.executeCommand();
|
|
47
|
+
} catch (err) {
|
|
48
|
+
Logging.instance.error(`${this.type} - ${err}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Perform the command
|
|
55
|
+
*/
|
|
56
|
+
action() {
|
|
57
|
+
// generate clipboard data from selected items
|
|
58
|
+
const selectedItems = DesignCore.Scene.selectionManager.selectedItems;
|
|
59
|
+
|
|
60
|
+
// create clipboard data
|
|
61
|
+
DesignCore.Clipboard.Entities = selectedItems;
|
|
62
|
+
// set base point
|
|
63
|
+
DesignCore.Clipboard.BasePoint = this.points[0];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Strings } from '../lib/strings.js';
|
|
2
|
+
import { Tool } from './tool.js';
|
|
3
|
+
import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
4
|
+
import { Logging } from '../lib/logging.js';
|
|
5
|
+
|
|
6
|
+
import { DesignCore } from '../designCore.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Copyclip Command Class
|
|
10
|
+
* @extends Tool
|
|
11
|
+
*/
|
|
12
|
+
export class Copyclip extends Tool {
|
|
13
|
+
/** Create a Copyclip command */
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Register the command
|
|
20
|
+
* @return {Object}
|
|
21
|
+
* command = name of the command
|
|
22
|
+
* shortcut = shortcut for the command
|
|
23
|
+
* type = type to group command in toolbars (omitted if not shown)
|
|
24
|
+
*/
|
|
25
|
+
static register() {
|
|
26
|
+
const command = { command: 'Copyclip', shortcut: 'COPYCLIP' };
|
|
27
|
+
return command;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Execute method
|
|
32
|
+
* executes the workflow, requesting input required to perform the command
|
|
33
|
+
*/
|
|
34
|
+
async execute() {
|
|
35
|
+
try {
|
|
36
|
+
const op = new PromptOptions(Strings.Input.SELECTIONSET, [Input.Type.SELECTIONSET]);
|
|
37
|
+
|
|
38
|
+
if (!DesignCore.Scene.selectionManager.selectionSet.selectionSet.length) {
|
|
39
|
+
await DesignCore.Scene.inputManager.requestInput(op);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
DesignCore.Scene.inputManager.executeCommand();
|
|
43
|
+
} catch (err) {
|
|
44
|
+
Logging.instance.error(`${this.type} - ${err}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Perform the command
|
|
51
|
+
*/
|
|
52
|
+
action() {
|
|
53
|
+
// generate clipboard data from selected items
|
|
54
|
+
const selectedItems = DesignCore.Scene.selectionManager.selectedItems;
|
|
55
|
+
|
|
56
|
+
// create clipboard data
|
|
57
|
+
DesignCore.Clipboard.Entities = selectedItems;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Line } from '../entities/line.js';
|
|
2
|
+
import { BasePolyline } from '../entities/basePolyline.js';
|
|
3
|
+
|
|
4
|
+
import { DesignCore } from '../designCore.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* CornerEntity
|
|
8
|
+
* Holds the per-side state for one of the two entities involved in a Chamfer or Fillet operation.
|
|
9
|
+
*/
|
|
10
|
+
export class CornerEntity {
|
|
11
|
+
/** Create a CornerEntity */
|
|
12
|
+
constructor() {
|
|
13
|
+
// Set during execute() when the user selects an entity
|
|
14
|
+
this.entity = null;
|
|
15
|
+
this.clickPoint = null;
|
|
16
|
+
// For polyline selections: the resolved Line segment and its 1-based index
|
|
17
|
+
this.segment = null;
|
|
18
|
+
this.segmentIndex = null;
|
|
19
|
+
// Geometry set by resolveCornerGeometry() before action()
|
|
20
|
+
this.lineStart = null;
|
|
21
|
+
this.lineEnd = null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The direction vector of the line segment (lineEnd − lineStart).
|
|
25
|
+
* @return {Point}
|
|
26
|
+
*/
|
|
27
|
+
get direction() {
|
|
28
|
+
return this.lineEnd.subtract(this.lineStart);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The active line segment: the resolved polyline segment, or the entity itself for a plain Line.
|
|
33
|
+
* @return {Line|null}
|
|
34
|
+
*/
|
|
35
|
+
get activeSeg() {
|
|
36
|
+
return this.segment ?? this.entity;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Validate that the active segment is a Line and populate lineStart and lineEnd from it.
|
|
41
|
+
* Returns false if the active segment is not a Line.
|
|
42
|
+
* @return {boolean}
|
|
43
|
+
*/
|
|
44
|
+
resolveEndpoints() {
|
|
45
|
+
if (!(this.activeSeg instanceof Line)) return false;
|
|
46
|
+
this.lineStart = this.activeSeg.points[0];
|
|
47
|
+
this.lineEnd = this.activeSeg.points[1];
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Set the entity and click point, then resolve the polyline segment.
|
|
53
|
+
* For polylines, populates segment and segmentIndex from the closest segment.
|
|
54
|
+
* For plain Lines, segment and segmentIndex are cleared to null.
|
|
55
|
+
* Returns false and notifies the user if the closest polyline segment is an arc.
|
|
56
|
+
* @param {object} entity - the selected entity
|
|
57
|
+
* @param {Point} clickPoint - the point where the user clicked
|
|
58
|
+
* @param {string} arcSegmentErrorMsg - notification string shown when the segment is an arc
|
|
59
|
+
* @return {boolean}
|
|
60
|
+
*/
|
|
61
|
+
setPick(entity, clickPoint, arcSegmentErrorMsg) {
|
|
62
|
+
this.entity = entity;
|
|
63
|
+
this.clickPoint = clickPoint;
|
|
64
|
+
if (!(this.entity instanceof BasePolyline)) {
|
|
65
|
+
this.segment = null;
|
|
66
|
+
this.segmentIndex = null;
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
const index = this.entity.getClosestSegmentIndex(this.clickPoint);
|
|
70
|
+
const segment = this.entity.getClosestSegment(this.clickPoint);
|
|
71
|
+
if (!(segment instanceof Line)) {
|
|
72
|
+
DesignCore.Core.notify(arcSegmentErrorMsg);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
this.segment = segment;
|
|
76
|
+
this.segmentIndex = index;
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The perpendicular foot of clickPoint onto the line defined by lineStart/lineEnd.
|
|
82
|
+
* @return {Point}
|
|
83
|
+
*/
|
|
84
|
+
get #clickOnLine() {
|
|
85
|
+
return this.clickPoint.perpendicular(this.lineStart, this.lineEnd);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Distance from the perpendicular foot to the intersection point.
|
|
90
|
+
* A value below Constants.Tolerance.EPSILON indicates an ambiguous corner.
|
|
91
|
+
* @param {Point} intersectionPoint - the corner intersection point
|
|
92
|
+
* @return {number}
|
|
93
|
+
*/
|
|
94
|
+
clickDistance(intersectionPoint) {
|
|
95
|
+
return this.#clickOnLine.distance(intersectionPoint);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Vector from the intersection point toward the perpendicular foot (i.e. toward the click side).
|
|
100
|
+
* @param {Point} intersectionPoint - the corner intersection point
|
|
101
|
+
* @return {Point}
|
|
102
|
+
*/
|
|
103
|
+
clickDir(intersectionPoint) {
|
|
104
|
+
return this.#clickOnLine.subtract(intersectionPoint);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Unit vector in the clickDir direction.
|
|
109
|
+
* @param {Point} intersectionPoint - the corner intersection point
|
|
110
|
+
* @return {Point}
|
|
111
|
+
*/
|
|
112
|
+
clickUnit(intersectionPoint) {
|
|
113
|
+
return this.clickDir(intersectionPoint).normalise();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The line endpoint on the same side of the intersection as the click.
|
|
118
|
+
* @param {Point} intersectionPoint - the corner intersection point
|
|
119
|
+
* @return {Point}
|
|
120
|
+
*/
|
|
121
|
+
lineKeptEnd(intersectionPoint) {
|
|
122
|
+
const dir = this.clickDir(intersectionPoint);
|
|
123
|
+
return dir.dot(this.lineStart.subtract(intersectionPoint)) >= dir.dot(this.lineEnd.subtract(intersectionPoint)) ?
|
|
124
|
+
this.lineStart : this.lineEnd;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Determine whether the start of the polyline segment should be kept when trimming.
|
|
129
|
+
* @param {Point} intersectionPoint - the corner intersection point
|
|
130
|
+
* @return {boolean}
|
|
131
|
+
*/
|
|
132
|
+
keepStart(intersectionPoint) {
|
|
133
|
+
const segStart = this.entity.points[this.segmentIndex - 1];
|
|
134
|
+
const segEnd = this.entity.points[this.segmentIndex % this.entity.points.length];
|
|
135
|
+
const dir = this.clickDir(intersectionPoint);
|
|
136
|
+
return dir.dot(segStart.subtract(intersectionPoint)) >= dir.dot(segEnd.subtract(intersectionPoint));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Strings } from '../lib/strings.js';
|
|
2
|
+
import { Tool } from './tool.js';
|
|
3
|
+
import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
4
|
+
import { Logging } from '../lib/logging.js';
|
|
5
|
+
import { RemoveState } from '../lib/stateManager.js';
|
|
6
|
+
|
|
7
|
+
import { DesignCore } from '../designCore.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Cutclip Command Class
|
|
11
|
+
* @extends Tool
|
|
12
|
+
*/
|
|
13
|
+
export class Cutclip extends Tool {
|
|
14
|
+
/** Create a Cutclip command */
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Register the command
|
|
21
|
+
* @return {Object}
|
|
22
|
+
* command = name of the command
|
|
23
|
+
* shortcut = shortcut for the command
|
|
24
|
+
* type = type to group command in toolbars (omitted if not shown)
|
|
25
|
+
*/
|
|
26
|
+
static register() {
|
|
27
|
+
const command = { command: 'Cutclip', shortcut: 'CUTCLIP' };
|
|
28
|
+
return command;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Execute method
|
|
33
|
+
* executes the workflow, requesting input required to perform the command
|
|
34
|
+
*/
|
|
35
|
+
async execute() {
|
|
36
|
+
try {
|
|
37
|
+
const op = new PromptOptions(Strings.Input.SELECTIONSET, [Input.Type.SELECTIONSET]);
|
|
38
|
+
|
|
39
|
+
if (!DesignCore.Scene.selectionManager.selectionSet.selectionSet.length) {
|
|
40
|
+
await DesignCore.Scene.inputManager.requestInput(op);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
DesignCore.Scene.inputManager.executeCommand();
|
|
44
|
+
} catch (err) {
|
|
45
|
+
Logging.instance.error(`${this.type} - ${err}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Perform the command
|
|
52
|
+
*/
|
|
53
|
+
action() {
|
|
54
|
+
// generate clipboard data from selected items
|
|
55
|
+
const selectedItems = DesignCore.Scene.selectionManager.selectedItems;
|
|
56
|
+
|
|
57
|
+
// create clipboard data
|
|
58
|
+
DesignCore.Clipboard.Entities = selectedItems;
|
|
59
|
+
// get a copy of the selection set
|
|
60
|
+
const selections = DesignCore.Scene.selectionManager.selectionSet.selectionSet.slice();
|
|
61
|
+
// create state changes for each of the selections
|
|
62
|
+
const stateChanges = [];
|
|
63
|
+
|
|
64
|
+
for (let i = 0; i < selections.length; i++) {
|
|
65
|
+
const stateChange = new RemoveState(DesignCore.Scene.entities.get(selections[i]));
|
|
66
|
+
stateChanges.push(stateChange);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// delete each of the selections from the scene items
|
|
70
|
+
DesignCore.Scene.commit(stateChanges);
|
|
71
|
+
}
|
|
72
|
+
}
|