@design-core/core 0.0.6 → 50.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +4 -0
- package/.github/workflows/DesignCoreQA.yml +3 -0
- package/TODO.md +49 -6
- package/core/core/core.js +0 -3
- package/core/designCore.js +1 -1
- package/core/dimensions/alignedDimension.js +12 -11
- package/core/dimensions/angularDimension.js +38 -37
- package/core/dimensions/{baseCircularDimension.js → circularDimensionBase.js} +22 -21
- package/core/dimensions/diametricDimension.js +14 -13
- package/core/dimensions/dimension.js +62 -55
- package/core/dimensions/{baseDimension.js → dimensionBase.js} +73 -107
- package/core/dimensions/{baseLinearDimension.js → linearDimensionBase.js} +15 -14
- package/core/dimensions/radialDimension.js +12 -11
- package/core/dimensions/rotatedDimension.js +20 -19
- package/core/entities/arc.js +123 -156
- package/core/entities/arctext.js +222 -184
- package/core/entities/circle.js +77 -99
- package/core/entities/entity.js +114 -93
- package/core/entities/hatch.js +346 -273
- package/core/entities/insert.js +68 -83
- package/core/entities/line.js +21 -142
- package/core/entities/lwpolyline.js +16 -11
- package/core/entities/point.js +19 -19
- package/core/entities/polyline.js +7 -7
- package/core/entities/{basePolyline.js → polylineBase.js} +47 -299
- package/core/entities/rectangle.js +3 -1
- package/core/entities/solid.js +6 -15
- package/core/entities/text.js +190 -201
- package/core/lib/auxiliary/rubberBand.js +32 -0
- package/core/lib/auxiliary/selectionWindow.js +63 -0
- package/core/lib/auxiliary/snapPoint.js +113 -0
- package/core/lib/auxiliary/trackingLine.js +76 -0
- package/core/lib/boundingBox.js +11 -11
- package/core/lib/canvas.js +232 -168
- package/core/lib/clipboard.js +9 -3
- package/core/lib/colour.js +16 -0
- package/core/lib/commandLine.js +1 -6
- package/core/lib/commandManager.js +18 -8
- package/core/lib/constants.js +28 -0
- package/core/lib/dxf/dxf.js +15 -14
- package/core/lib/dxf/dxfIterator.js +2 -2
- package/core/lib/entityManager.js +33 -26
- package/core/lib/inputManager.js +36 -12
- package/core/lib/intersect.js +25 -0
- package/core/lib/matrix.js +1 -1
- package/core/lib/patterns.js +9 -2
- package/core/lib/plotOptions.js +67 -0
- package/core/lib/polylineUtils.js +75 -0
- package/core/lib/renderers/cairoRenderer.js +371 -0
- package/core/lib/renderers/canvasRenderer.js +315 -0
- package/core/lib/renderers/pdfRenderer.js +366 -0
- package/core/lib/renderers/rendererBase.js +284 -0
- package/core/lib/renderers/svgRenderer.js +343 -0
- package/core/lib/scene.js +28 -6
- package/core/lib/selectionManager.js +20 -20
- package/core/lib/settings.js +4 -2
- package/core/lib/snapping.js +4 -191
- package/core/lib/stateManager.js +30 -1
- package/core/lib/utils.js +26 -7
- package/core/properties/entityProperties.js +104 -0
- package/core/properties/property.js +106 -2
- package/core/properties/propertyManager.js +60 -44
- package/core/tables/block.js +50 -81
- package/core/tables/dimStyle.js +5 -5
- package/core/tables/endblk.js +1 -1
- package/core/tables/layer.js +8 -0
- package/core/tables/ltypeManager.js +1 -1
- package/core/tables/styleManagerBase.js +3 -2
- package/core/tables/tableManagerBase.js +8 -3
- package/core/tables/vport.js +2 -2
- package/core/tools/chamfer.js +117 -143
- package/core/tools/chamferFilletBase.js +138 -37
- package/core/tools/copy.js +11 -11
- package/core/tools/copybase.js +3 -3
- package/core/tools/copyclip.js +3 -3
- package/core/tools/cornerEntity.js +2 -2
- package/core/tools/cutclip.js +3 -3
- package/core/tools/explode.js +7 -7
- package/core/tools/extend.js +138 -25
- package/core/tools/fillet.js +92 -189
- package/core/tools/matchProp.js +3 -12
- package/core/tools/mirror.js +15 -14
- package/core/tools/move.js +8 -8
- package/core/tools/offset.js +31 -33
- package/core/tools/pasteclip.js +1 -1
- package/core/tools/purge.js +10 -10
- package/core/tools/rotate.js +19 -16
- package/core/tools/scale.js +7 -7
- package/core/tools/trim.js +271 -29
- package/core/tools/zoom.js +1 -1
- package/cspell.json +321 -0
- package/jest.config.js +6 -0
- package/package.json +5 -3
- package/test/dimensions/alignedDimension.test.js +17 -10
- package/test/dimensions/angularDimension.test.js +13 -13
- package/test/dimensions/diametricDimension.test.js +15 -15
- package/test/dimensions/dimension.test.js +12 -12
- package/test/dimensions/{baseDimension.test.js → dimensionBase.test.js} +73 -12
- package/test/dimensions/linearDimensionBase.test.js +62 -0
- package/test/dimensions/radialDimension.test.js +15 -15
- package/test/dimensions/rotatedDimension.test.js +18 -11
- package/test/entities/arc.test.js +83 -86
- package/test/entities/arctext.test.js +184 -57
- package/test/entities/circle.test.js +68 -96
- package/test/entities/entity.test.js +42 -8
- package/test/entities/hatch.test.js +569 -96
- package/test/entities/insert.test.js +99 -4
- package/test/entities/line.test.js +15 -41
- package/test/entities/lwpolyline.test.js +104 -0
- package/test/entities/point.test.js +3 -3
- package/test/entities/polyline.test.js +11 -0
- package/test/entities/{basePolyline.test.js → polylineBase.test.js} +192 -57
- package/test/entities/rectangle.test.js +11 -0
- package/test/entities/solid.test.js +1 -1
- package/test/entities/text.test.js +302 -77
- package/test/integration/exportIntegration.reference.dxf +9 -9
- package/test/integration/exportIntegration.test.js +5 -5
- package/test/integration/intersectionIntegration.test.js +4 -5
- package/test/integration/pdfRendererIntegration.reference.pdf +17709 -0
- package/test/integration/pdfRendererIntegration.test.js +61 -0
- package/test/integration/svgRendererIntegration.reference.svg +3343 -0
- package/test/integration/svgRendererIntegration.test.js +61 -0
- package/test/integration/userInputIntegration.reference.dxf +1165 -105
- package/test/integration/userInputIntegration.test.js +239 -132
- package/test/lib/boundingBox.test.js +3 -3
- package/test/lib/canvas.test.js +744 -125
- package/test/lib/constants.test.js +27 -0
- package/test/lib/entityManager.test.js +4 -4
- package/test/lib/inputManager.test.js +81 -20
- package/test/lib/intersect.test.js +83 -0
- package/test/lib/plotOptions.test.js +179 -0
- package/test/lib/rubberBand.test.js +84 -0
- package/test/lib/scene.test.js +9 -9
- package/test/lib/selectionManager.test.js +3 -3
- package/test/lib/settings.test.js +5 -6
- package/test/lib/snapping.test.js +72 -130
- package/test/lib/stateManager.test.js +7 -7
- package/test/lib/utils.test.js +36 -2
- package/test/properties/entityProperties.test.js +132 -0
- package/test/properties/property.test.js +53 -0
- package/test/properties/propertyManager.test.js +25 -25
- package/test/renderers/canvasRenderer.test.js +317 -0
- package/test/renderers/pdfRenderer.test.js +271 -0
- package/test/renderers/rendererBase.test.js +213 -0
- package/test/renderers/svgRenderer.test.js +326 -0
- package/test/tables/block.test.js +92 -13
- package/test/tables/endblk.test.js +2 -2
- package/test/tables/layer.test.js +30 -0
- package/test/tables/layerManager.test.js +2 -2
- package/test/test-helpers/hatchGridRenderer.js +180 -0
- package/test/test-helpers/test-helpers.js +158 -6
- package/test/tools/chamfer.test.js +273 -51
- package/test/tools/chamferFilletBase.test.js +125 -36
- package/test/tools/copy.test.js +8 -8
- package/test/tools/copybase.test.js +2 -2
- package/test/tools/copyclip.test.js +2 -2
- package/test/tools/cornerEntity.test.js +8 -8
- package/test/tools/cutclip.test.js +2 -2
- package/test/tools/erase.test.js +6 -6
- package/test/tools/explode.test.js +5 -5
- package/test/tools/extend.test.js +373 -42
- package/test/tools/fillet.test.js +230 -49
- package/test/tools/matchProp.test.js +11 -11
- package/test/tools/mirror.test.js +39 -39
- package/test/tools/move.test.js +7 -7
- package/test/tools/offset.test.js +222 -55
- package/test/tools/pasteclip.test.js +5 -5
- package/test/tools/purge.test.js +4 -4
- package/test/tools/rotate.test.js +39 -9
- package/test/tools/scale.test.js +33 -33
- package/test/tools/trim.test.js +579 -53
- package/test/tools/zoom.test.js +12 -12
- package/core/lib/selectionWindow.js +0 -83
package/core/tools/trim.js
CHANGED
|
@@ -3,6 +3,10 @@ import { Strings } from '../lib/strings.js';
|
|
|
3
3
|
import { Tool } from './tool.js';
|
|
4
4
|
import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
5
5
|
import { Logging } from '../lib/logging.js';
|
|
6
|
+
import { AddState, RemoveState } from '../lib/stateManager.js';
|
|
7
|
+
import { Utils } from '../lib/utils.js';
|
|
8
|
+
import { Colour } from '../lib/colour.js';
|
|
9
|
+
import { PolylineUtils } from '../lib/polylineUtils.js';
|
|
6
10
|
|
|
7
11
|
import { DesignCore } from '../designCore.js';
|
|
8
12
|
|
|
@@ -16,7 +20,7 @@ export class Trim extends Tool {
|
|
|
16
20
|
/** Create a Trim command */
|
|
17
21
|
constructor() {
|
|
18
22
|
super();
|
|
19
|
-
this.
|
|
23
|
+
this.selectedEntity = null;
|
|
20
24
|
this.selectedBoundaryItems = [];
|
|
21
25
|
}
|
|
22
26
|
|
|
@@ -38,24 +42,24 @@ export class Trim extends Tool {
|
|
|
38
42
|
*/
|
|
39
43
|
async execute() {
|
|
40
44
|
try {
|
|
41
|
-
const
|
|
45
|
+
const boundaryOp = new PromptOptions(Strings.Input.BOUNDARY, [Input.Type.SELECTIONSET]);
|
|
42
46
|
|
|
43
47
|
if (!DesignCore.Scene.selectionManager.selectionSet.selectionSet.length) {
|
|
44
|
-
const boundary = await DesignCore.Scene.inputManager.requestInput(
|
|
48
|
+
const boundary = await DesignCore.Scene.inputManager.requestInput(boundaryOp);
|
|
45
49
|
if (boundary === undefined) return;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
// add all selected
|
|
52
|
+
// add all selected entities to boundary items
|
|
49
53
|
for (let i = 0; i < DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
|
|
50
54
|
const boundaryItem = DesignCore.Scene.entities.get(DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]);
|
|
51
55
|
this.selectedBoundaryItems.push(boundaryItem);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
const
|
|
58
|
+
const selectOp = new PromptOptions(Strings.Input.SELECT, [Input.Type.SINGLESELECTION]);
|
|
55
59
|
while (true) {
|
|
56
|
-
const selection = await DesignCore.Scene.inputManager.requestInput(
|
|
60
|
+
const selection = await DesignCore.Scene.inputManager.requestInput(selectOp);
|
|
57
61
|
if (selection === undefined) break;
|
|
58
|
-
this.
|
|
62
|
+
this.selectedEntity = DesignCore.Scene.entities.get(selection.selectedEntityIndex);
|
|
59
63
|
DesignCore.Scene.selectionManager.removeLastSelection();
|
|
60
64
|
DesignCore.Scene.inputManager.actionCommand();
|
|
61
65
|
}
|
|
@@ -70,44 +74,282 @@ export class Trim extends Tool {
|
|
|
70
74
|
* Preview the command during execution
|
|
71
75
|
*/
|
|
72
76
|
preview() {
|
|
73
|
-
|
|
77
|
+
if (!this.selectedBoundaryItems.length) return;
|
|
78
|
+
|
|
79
|
+
const index = DesignCore.Scene.selectionManager.findClosestItem(DesignCore.Mouse.pointOnScene());
|
|
80
|
+
if (index === undefined) return;
|
|
81
|
+
|
|
82
|
+
const entity = DesignCore.Scene.entities.get(index);
|
|
83
|
+
if (typeof entity.toPolylinePoints !== 'function' || typeof entity.fromPolylinePoints !== 'function') return;
|
|
84
|
+
const intersectPoints = this.#collectIntersectPoints(entity);
|
|
85
|
+
if (!intersectPoints.length) return;
|
|
86
|
+
|
|
87
|
+
const stateChanges = this.#trimEntity(entity, intersectPoints);
|
|
88
|
+
if (!stateChanges?.length) return;
|
|
89
|
+
|
|
90
|
+
// Draw the full entity in a dulled colour, then draw survivors on top.
|
|
91
|
+
const dulledEntity = Utils.cloneObject(entity);
|
|
92
|
+
dulledEntity.setProperty('colour', Colour.blend(entity.getDrawColour(), DesignCore.Settings.canvasbackgroundcolour, DesignCore.Settings.previewBlendFactor));
|
|
93
|
+
DesignCore.Scene.previewEntities.add(dulledEntity);
|
|
94
|
+
|
|
95
|
+
for (const change of stateChanges) {
|
|
96
|
+
if (change instanceof AddState) {
|
|
97
|
+
DesignCore.Scene.previewEntities.add(change.entity);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
74
100
|
}
|
|
75
101
|
|
|
76
102
|
/**
|
|
77
103
|
* Perform the command
|
|
78
104
|
*/
|
|
79
105
|
action() {
|
|
80
|
-
if (this.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
const intersect = Intersection.intersectPolylinePolyline(boundaryItem.toPolylinePoints(), this.selectedItem.toPolylinePoints());
|
|
87
|
-
if (intersect.points.length) {
|
|
88
|
-
for (let point = 0; point < intersect.points.length; point++) {
|
|
89
|
-
intersectPoints.push(intersect.points[point]);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
} catch {
|
|
93
|
-
Logging.instance.warn(`${this.constructor.name}: Error intersecting between ${boundaryItem.type} and ${this.selectedItem.type}`);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
106
|
+
if (this.selectedEntity && this.selectedBoundaryItems.length) {
|
|
107
|
+
if (typeof this.selectedEntity.fromPolylinePoints !== 'function') {
|
|
108
|
+
DesignCore.Core.notify(`${this.type} - ${this.selectedEntity.type} ${Strings.Message.NOTRIM}`);
|
|
109
|
+
this.selectedEntity = null;
|
|
110
|
+
return;
|
|
97
111
|
}
|
|
98
112
|
|
|
113
|
+
const intersectPoints = this.#collectIntersectPoints(this.selectedEntity);
|
|
114
|
+
|
|
99
115
|
if (intersectPoints.length) {
|
|
100
|
-
const stateChanges = this.
|
|
116
|
+
const stateChanges = this.#trimEntity(this.selectedEntity, intersectPoints);
|
|
101
117
|
if (stateChanges?.length) {
|
|
102
118
|
DesignCore.Scene.commit(stateChanges);
|
|
103
119
|
}
|
|
104
120
|
} else {
|
|
105
|
-
DesignCore.Core.notify(`${this.type} - ${this.
|
|
121
|
+
DesignCore.Core.notify(`${this.type} - ${this.selectedEntity.type} ${Strings.Message.NOTRIM}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.selectedEntity = null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Collect all intersection points between the boundary items and the given entity.
|
|
130
|
+
* Unsupported entity combinations are silently skipped.
|
|
131
|
+
* @param {Object} entity
|
|
132
|
+
* @return {Array}
|
|
133
|
+
*/
|
|
134
|
+
#collectIntersectPoints(entity) {
|
|
135
|
+
const intersectPoints = [];
|
|
136
|
+
for (const boundaryItem of this.selectedBoundaryItems) {
|
|
137
|
+
if (boundaryItem === entity) continue;
|
|
138
|
+
try {
|
|
139
|
+
const intersect = Intersection.intersectPolylinePolyline(boundaryItem.toPolylinePoints(), entity.toPolylinePoints());
|
|
140
|
+
intersectPoints.push(...intersect.points);
|
|
141
|
+
} catch {
|
|
142
|
+
// skip unsupported entity combinations
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return intersectPoints;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Compute state changes to trim entity at the pair of intersection points
|
|
150
|
+
* surrounding the mouse position. Operates entirely in polyline-point space
|
|
151
|
+
* via entity.toPolylinePoints() / entity.fromPolylinePoints(), so it works
|
|
152
|
+
* for any entity that implements that protocol (Line, Arc, Circle,
|
|
153
|
+
* PolylineBase, and future entities such as Spline or Ellipse).
|
|
154
|
+
* @param {Object} entity
|
|
155
|
+
* @param {Array} intersectPoints
|
|
156
|
+
* @return {Array}
|
|
157
|
+
*/
|
|
158
|
+
#trimEntity(entity, intersectPoints) {
|
|
159
|
+
const polyPoints = entity.toPolylinePoints();
|
|
160
|
+
const mousePosition = DesignCore.Mouse.pointOnScene();
|
|
161
|
+
const isClosed = polyPoints[0].isSame(polyPoints.at(-1));
|
|
162
|
+
|
|
163
|
+
// Drop any intersection point that coincides with an existing vertex
|
|
164
|
+
const filtered = intersectPoints.filter((p) => !polyPoints.some((v) => v.isSame(p)));
|
|
165
|
+
if (!filtered.length) return [];
|
|
166
|
+
|
|
167
|
+
// Locate each intersection point within the polyline segments
|
|
168
|
+
const locatedIntersections = [];
|
|
169
|
+
for (const point of filtered) {
|
|
170
|
+
for (let i = 1; i < polyPoints.length; i++) {
|
|
171
|
+
if (PolylineUtils.isPointOnSegment(point, polyPoints[i - 1], polyPoints[i])) {
|
|
172
|
+
locatedIntersections.push({
|
|
173
|
+
segmentIndex: i,
|
|
174
|
+
point,
|
|
175
|
+
positionAlongSegment: PolylineUtils.positionOnSegment(polyPoints, point, i),
|
|
176
|
+
});
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!locatedIntersections.length) return [];
|
|
183
|
+
|
|
184
|
+
locatedIntersections.sort((a, b) => {
|
|
185
|
+
if (a.segmentIndex !== b.segmentIndex) return a.segmentIndex - b.segmentIndex;
|
|
186
|
+
return a.positionAlongSegment - b.positionAlongSegment;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Find which segment the mouse is closest to
|
|
190
|
+
let mouseSegmentIndex = 0;
|
|
191
|
+
let mouseClosest = null;
|
|
192
|
+
let minDistance = Infinity;
|
|
193
|
+
for (let i = 1; i < polyPoints.length; i++) {
|
|
194
|
+
const closest = PolylineUtils.closestPointOnSegment(polyPoints, mousePosition, i);
|
|
195
|
+
if (closest) {
|
|
196
|
+
const dist = mousePosition.distance(closest);
|
|
197
|
+
if (dist < minDistance) {
|
|
198
|
+
minDistance = dist;
|
|
199
|
+
mouseSegmentIndex = i;
|
|
200
|
+
mouseClosest = closest;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const mousePos = mouseClosest ?
|
|
206
|
+
PolylineUtils.positionOnSegment(polyPoints, mouseClosest, mouseSegmentIndex) :
|
|
207
|
+
0;
|
|
208
|
+
|
|
209
|
+
// Find the nearest intersections before and after the mouse position
|
|
210
|
+
let trimBefore = null;
|
|
211
|
+
let trimAfter = null;
|
|
212
|
+
for (const loc of locatedIntersections) {
|
|
213
|
+
if (loc.segmentIndex < mouseSegmentIndex) {
|
|
214
|
+
trimBefore = loc;
|
|
215
|
+
} else if (loc.segmentIndex === mouseSegmentIndex) {
|
|
216
|
+
if (loc.positionAlongSegment <= mousePos) {
|
|
217
|
+
trimBefore = loc;
|
|
218
|
+
} else if (!trimAfter) {
|
|
219
|
+
trimAfter = loc;
|
|
220
|
+
}
|
|
221
|
+
} else if (!trimAfter) {
|
|
222
|
+
trimAfter = loc;
|
|
106
223
|
}
|
|
107
224
|
}
|
|
108
225
|
|
|
109
|
-
|
|
110
|
-
|
|
226
|
+
const stateChanges = [];
|
|
227
|
+
|
|
228
|
+
if (isClosed) {
|
|
229
|
+
// Wrap cyclically: if trimBefore is null use the last intersection,
|
|
230
|
+
// if trimAfter is null use the first.
|
|
231
|
+
if (!trimBefore) trimBefore = locatedIntersections.at(-1);
|
|
232
|
+
if (!trimAfter) trimAfter = locatedIntersections[0];
|
|
233
|
+
|
|
234
|
+
// A single intersection point cannot divide a closed shape.
|
|
235
|
+
if (trimBefore === trimAfter) return [];
|
|
236
|
+
|
|
237
|
+
// Build the single kept open portion from trimAfter to trimBefore,
|
|
238
|
+
// going away from the mouse (i.e. not through the mouse segment).
|
|
239
|
+
let outputPoints;
|
|
240
|
+
if (trimAfter.segmentIndex < trimBefore.segmentIndex ||
|
|
241
|
+
(trimAfter.segmentIndex === trimBefore.segmentIndex &&
|
|
242
|
+
trimAfter.positionAlongSegment < trimBefore.positionAlongSegment)) {
|
|
243
|
+
// Forward walk: trimAfter → trimBefore without crossing the seam
|
|
244
|
+
outputPoints = this.#buildPortion(polyPoints, trimAfter, trimBefore);
|
|
245
|
+
} else {
|
|
246
|
+
// Wrapping walk: trimAfter → end → seam → start → trimBefore
|
|
247
|
+
outputPoints = this.#buildWrappingPortion(polyPoints, trimAfter, trimBefore);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (outputPoints && outputPoints.length >= 2) {
|
|
251
|
+
const output = Utils.cloneObject(entity).fromPolylinePoints(outputPoints);
|
|
252
|
+
output.flags?.removeValue(1);
|
|
253
|
+
stateChanges.push(new AddState(output));
|
|
254
|
+
stateChanges.push(new RemoveState(entity));
|
|
255
|
+
}
|
|
256
|
+
return stateChanges;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Open entity: build portionOne (start → trimBefore) and portionTwo (trimAfter → end)
|
|
260
|
+
const startLoc = { segmentIndex: 1, point: polyPoints[0] };
|
|
261
|
+
const endLoc = { segmentIndex: polyPoints.length - 1, point: polyPoints.at(-1) };
|
|
262
|
+
const portionOnePoints = trimBefore ? this.#buildPortion(polyPoints, startLoc, trimBefore) : null;
|
|
263
|
+
const portionTwoPoints = trimAfter ? this.#buildPortion(polyPoints, trimAfter, endLoc) : null;
|
|
264
|
+
|
|
265
|
+
if (portionOnePoints) {
|
|
266
|
+
const output = Utils.cloneObject(entity).fromPolylinePoints(portionOnePoints);
|
|
267
|
+
output.flags?.removeValue(1);
|
|
268
|
+
stateChanges.push(new AddState(output));
|
|
269
|
+
}
|
|
270
|
+
if (portionTwoPoints) {
|
|
271
|
+
const output = Utils.cloneObject(entity).fromPolylinePoints(portionTwoPoints);
|
|
272
|
+
output.flags?.removeValue(1);
|
|
273
|
+
stateChanges.push(new AddState(output));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (trimBefore || trimAfter) {
|
|
277
|
+
stateChanges.push(new RemoveState(entity));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return stateChanges;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Build a sub-polyline from fromLoc to toLoc going forward (no seam crossing).
|
|
285
|
+
* Both locations must appear in forward order along the polyline.
|
|
286
|
+
* @param {Array} polyPoints
|
|
287
|
+
* @param {Object} fromLoc - { segmentIndex, point, positionAlongSegment }
|
|
288
|
+
* @param {Object} toLoc - { segmentIndex, point, positionAlongSegment }
|
|
289
|
+
* @return {Array|null}
|
|
290
|
+
*/
|
|
291
|
+
#buildPortion(polyPoints, fromLoc, toLoc) {
|
|
292
|
+
const fromSegStart = polyPoints[fromLoc.segmentIndex - 1];
|
|
293
|
+
const fromSegEnd = polyPoints[fromLoc.segmentIndex];
|
|
294
|
+
|
|
295
|
+
// Same-segment case: compute the sub-arc bulge directly from the arc geometry
|
|
296
|
+
if (fromLoc.segmentIndex === toLoc.segmentIndex) {
|
|
297
|
+
const startPoint = fromLoc.point.clone();
|
|
298
|
+
if (fromSegStart.bulge !== 0 && fromSegStart.bulge !== undefined) {
|
|
299
|
+
const centre = fromSegStart.bulgeCentrePoint(fromSegEnd);
|
|
300
|
+
const direction = fromSegStart.bulge > 0 ? 1 : -1;
|
|
301
|
+
const startAngle = centre.angle(fromLoc.point);
|
|
302
|
+
const endAngle = centre.angle(toLoc.point);
|
|
303
|
+
const includedAngle = ((endAngle - startAngle) * direction + 4 * Math.PI) % (2 * Math.PI);
|
|
304
|
+
startPoint.bulge = Math.tan(includedAngle / 4) * direction;
|
|
305
|
+
}
|
|
306
|
+
return [startPoint, toLoc.point.clone()];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const points = [];
|
|
310
|
+
|
|
311
|
+
// Start point: fromLoc.point with partial bulge covering the rest of its segment
|
|
312
|
+
const startPoint = fromLoc.point.clone();
|
|
313
|
+
if (fromSegStart.bulge !== 0 && fromSegStart.bulge !== undefined) {
|
|
314
|
+
startPoint.bulge = fromSegStart.partialBulge(fromSegEnd, fromLoc.point, true);
|
|
315
|
+
}
|
|
316
|
+
points.push(startPoint);
|
|
317
|
+
|
|
318
|
+
// Intermediate vertices between the two segments
|
|
319
|
+
for (let i = fromLoc.segmentIndex; i <= toLoc.segmentIndex - 2; i++) {
|
|
320
|
+
points.push(polyPoints[i].clone());
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Start of toLoc's segment with partial bulge trimmed to toLoc.point
|
|
324
|
+
const toSegStart = polyPoints[toLoc.segmentIndex - 1];
|
|
325
|
+
const toSegEnd = polyPoints[toLoc.segmentIndex];
|
|
326
|
+
const lastSegStart = toSegStart.clone();
|
|
327
|
+
if (toSegStart.bulge !== 0 && toSegStart.bulge !== undefined) {
|
|
328
|
+
lastSegStart.bulge = toSegStart.partialBulge(toSegEnd, toLoc.point);
|
|
329
|
+
}
|
|
330
|
+
if (!points.at(-1).isSame(lastSegStart)) points.push(lastSegStart);
|
|
331
|
+
|
|
332
|
+
const endPoint = toLoc.point.clone();
|
|
333
|
+
if (!points.at(-1).isSame(endPoint)) points.push(endPoint);
|
|
334
|
+
|
|
335
|
+
return points.length >= 2 ? points : null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Build a sub-polyline from fromLoc to toLoc crossing the seam (wrapping).
|
|
340
|
+
* Used for closed entities when the kept portion wraps through the closure point.
|
|
341
|
+
* Implemented as two forward #buildPortion calls joined at the seam.
|
|
342
|
+
* @param {Array} polyPoints
|
|
343
|
+
* @param {Object} fromLoc - { segmentIndex, point, positionAlongSegment }
|
|
344
|
+
* @param {Object} toLoc - { segmentIndex, point, positionAlongSegment }
|
|
345
|
+
* @return {Array|null}
|
|
346
|
+
*/
|
|
347
|
+
#buildWrappingPortion(polyPoints, fromLoc, toLoc) {
|
|
348
|
+
const firstHalf = this.#buildPortion(polyPoints, fromLoc, { segmentIndex: polyPoints.length - 1, point: polyPoints.at(-1) });
|
|
349
|
+
const secondHalf = this.#buildPortion(polyPoints, { segmentIndex: 1, point: polyPoints[0] }, toLoc);
|
|
350
|
+
if (!firstHalf || !secondHalf) return null;
|
|
351
|
+
firstHalf.pop(); // discard closure point before joining
|
|
352
|
+
return firstHalf.concat(secondHalf);
|
|
111
353
|
}
|
|
112
354
|
}
|
|
113
355
|
|
package/core/tools/zoom.js
CHANGED
package/cspell.json
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2",
|
|
3
|
+
"language": "en-GB",
|
|
4
|
+
"ignorePaths": [
|
|
5
|
+
"node_modules",
|
|
6
|
+
"_build",
|
|
7
|
+
"coverage",
|
|
8
|
+
"*.lock",
|
|
9
|
+
"package-lock.json",
|
|
10
|
+
"test/**"
|
|
11
|
+
],
|
|
12
|
+
"ignoreRegExpList": [
|
|
13
|
+
"[0-9a-fA-F]{6,}"
|
|
14
|
+
],
|
|
15
|
+
"words": [
|
|
16
|
+
"acad",
|
|
17
|
+
"ACADVER",
|
|
18
|
+
"autocad",
|
|
19
|
+
"ARCALIGNEDTEXT",
|
|
20
|
+
"ARCHTICK",
|
|
21
|
+
"arcpoints",
|
|
22
|
+
"ARCSIDE",
|
|
23
|
+
"arctext",
|
|
24
|
+
"ASME",
|
|
25
|
+
"AABB",
|
|
26
|
+
"basepoint",
|
|
27
|
+
"bbox",
|
|
28
|
+
"bboxes",
|
|
29
|
+
"bitmasked",
|
|
30
|
+
"byblock",
|
|
31
|
+
"bylayer",
|
|
32
|
+
"CANNOSCALE",
|
|
33
|
+
"CHARACTERSPACING",
|
|
34
|
+
"CHILDENTITIES",
|
|
35
|
+
"clayer",
|
|
36
|
+
"copybase",
|
|
37
|
+
"copyclip",
|
|
38
|
+
"cutclip",
|
|
39
|
+
"pasteclip",
|
|
40
|
+
"defpoints",
|
|
41
|
+
"dedup",
|
|
42
|
+
"DECIMALPLACES",
|
|
43
|
+
"DESTINATIONSET",
|
|
44
|
+
"dimstyle",
|
|
45
|
+
"dimstyles",
|
|
46
|
+
"dimline",
|
|
47
|
+
"DIMENSIONSTYLE",
|
|
48
|
+
"DIMADEC",
|
|
49
|
+
"DIMALI",
|
|
50
|
+
"DIMALT",
|
|
51
|
+
"DIMALTD",
|
|
52
|
+
"DIMALTF",
|
|
53
|
+
"DIMALTMZF",
|
|
54
|
+
"DIMALTMZS",
|
|
55
|
+
"DIMALTRND",
|
|
56
|
+
"DIMALTTD",
|
|
57
|
+
"DIMALTTZ",
|
|
58
|
+
"DIMALTU",
|
|
59
|
+
"DIMALTZ",
|
|
60
|
+
"DIMANG",
|
|
61
|
+
"DIMANNO",
|
|
62
|
+
"DIMAPOST",
|
|
63
|
+
"DIMARCSYM",
|
|
64
|
+
"DIMASO",
|
|
65
|
+
"DIMASSOC",
|
|
66
|
+
"DIMASZ",
|
|
67
|
+
"DIMATFIT",
|
|
68
|
+
"DIMAUNIT",
|
|
69
|
+
"DIMAZIN",
|
|
70
|
+
"DIMBLK",
|
|
71
|
+
"DIMCEN",
|
|
72
|
+
"DIMCENSTYL",
|
|
73
|
+
"DIMCENVALUE",
|
|
74
|
+
"DIMCLRD",
|
|
75
|
+
"DIMCLRE",
|
|
76
|
+
"DIMCLRT",
|
|
77
|
+
"DIMCONSTRAINTICON",
|
|
78
|
+
"DIMDEC",
|
|
79
|
+
"DIMDIA",
|
|
80
|
+
"DIMDLE",
|
|
81
|
+
"DIMDLI",
|
|
82
|
+
"DIMDSEP",
|
|
83
|
+
"DIMEXE",
|
|
84
|
+
"DIMEXO",
|
|
85
|
+
"DIMFIT",
|
|
86
|
+
"DIMFRAC",
|
|
87
|
+
"DIMFXL",
|
|
88
|
+
"DIMFXLON",
|
|
89
|
+
"DIMGAP",
|
|
90
|
+
"DIMJOGANG",
|
|
91
|
+
"DIMJUST",
|
|
92
|
+
"DIMLDRBLK",
|
|
93
|
+
"DIMLFAC",
|
|
94
|
+
"DIMLIM",
|
|
95
|
+
"DIMLIN",
|
|
96
|
+
"DIMLTEX",
|
|
97
|
+
"DIMLTYPE",
|
|
98
|
+
"DIMLUNIT",
|
|
99
|
+
"DIMLWD",
|
|
100
|
+
"DIMLWE",
|
|
101
|
+
"DIMMZF",
|
|
102
|
+
"DIMMZS",
|
|
103
|
+
"DIMPOST",
|
|
104
|
+
"DIMRAD",
|
|
105
|
+
"DIMRND",
|
|
106
|
+
"DIMROT",
|
|
107
|
+
"DIMSAH",
|
|
108
|
+
"DIMSCALE",
|
|
109
|
+
"DIMSD",
|
|
110
|
+
"DIMSE",
|
|
111
|
+
"DIMSHO",
|
|
112
|
+
"DIMSOXD",
|
|
113
|
+
"DIMTAD",
|
|
114
|
+
"DIMTDEC",
|
|
115
|
+
"DIMTFAC",
|
|
116
|
+
"DIMTFILL",
|
|
117
|
+
"DIMTFILLCLR",
|
|
118
|
+
"DIMTIH",
|
|
119
|
+
"DIMTIX",
|
|
120
|
+
"DIMTM",
|
|
121
|
+
"DIMTMOVE",
|
|
122
|
+
"DIMTOFL",
|
|
123
|
+
"DIMTOH",
|
|
124
|
+
"DIMTOL",
|
|
125
|
+
"DIMTOLJ",
|
|
126
|
+
"DIMTP",
|
|
127
|
+
"DIMTSZ",
|
|
128
|
+
"DIMTVP",
|
|
129
|
+
"DIMTXSTY",
|
|
130
|
+
"DIMTXT",
|
|
131
|
+
"DIMTXTDIRECTION",
|
|
132
|
+
"DIMTZIN",
|
|
133
|
+
"DIMUNIT",
|
|
134
|
+
"DIMUPT",
|
|
135
|
+
"DIMZIN",
|
|
136
|
+
"drawgrid",
|
|
137
|
+
"endblk",
|
|
138
|
+
"endsec",
|
|
139
|
+
"endsnap",
|
|
140
|
+
"EXTMAX",
|
|
141
|
+
"EXTMIN",
|
|
142
|
+
"FILLETRAD",
|
|
143
|
+
"FONTNAME",
|
|
144
|
+
"groupcode",
|
|
145
|
+
"groupcodes",
|
|
146
|
+
"groupvalue",
|
|
147
|
+
"handseed",
|
|
148
|
+
"HORIZONTALALIGNMENT",
|
|
149
|
+
"INSBASE",
|
|
150
|
+
"inputprompt",
|
|
151
|
+
"isopair",
|
|
152
|
+
"itemname",
|
|
153
|
+
"keypresses",
|
|
154
|
+
"lerp",
|
|
155
|
+
"LINEARDIMANGLE",
|
|
156
|
+
"linetype",
|
|
157
|
+
"linetypes",
|
|
158
|
+
"lineweight",
|
|
159
|
+
"ltscale",
|
|
160
|
+
"ltype",
|
|
161
|
+
"ltypes",
|
|
162
|
+
"lwpoly",
|
|
163
|
+
"lwpolyline",
|
|
164
|
+
"MLEADER",
|
|
165
|
+
"MLEADERSCALE",
|
|
166
|
+
"multileader",
|
|
167
|
+
"nearestsnap",
|
|
168
|
+
"midsnap",
|
|
169
|
+
"nodesnap",
|
|
170
|
+
"tangentsnap",
|
|
171
|
+
"quadrantsnap",
|
|
172
|
+
"perpendicularsnap",
|
|
173
|
+
"centresnap",
|
|
174
|
+
"NOCHAMFER",
|
|
175
|
+
"NOFILLET",
|
|
176
|
+
"NONCONSECUTIVESEGMENTS",
|
|
177
|
+
"NOREDO",
|
|
178
|
+
"NOTRIM",
|
|
179
|
+
"NOUNDO",
|
|
180
|
+
"OFFSETFROMARC",
|
|
181
|
+
"OFFSETFROMLEFT",
|
|
182
|
+
"OFFSETFROMRIGHT",
|
|
183
|
+
"Paperspace",
|
|
184
|
+
"PATTERNNAME",
|
|
185
|
+
"PLOTSTYLENAME",
|
|
186
|
+
"plottable",
|
|
187
|
+
"polarangle",
|
|
188
|
+
"polyface",
|
|
189
|
+
"postsuffix",
|
|
190
|
+
"preselection",
|
|
191
|
+
"RADIUSTOOLARGE",
|
|
192
|
+
"REFERENCELENGTH",
|
|
193
|
+
"RRGGBB",
|
|
194
|
+
"rubberbandcolour",
|
|
195
|
+
"SCALEFACTOR",
|
|
196
|
+
"selectedchild",
|
|
197
|
+
"SELECTIONSET",
|
|
198
|
+
"SEQEND",
|
|
199
|
+
"SINGLESELECTION",
|
|
200
|
+
"solidfill",
|
|
201
|
+
"standardflags",
|
|
202
|
+
"startxref",
|
|
203
|
+
"STYLENAME",
|
|
204
|
+
"TEXTALIGNMENT",
|
|
205
|
+
"TEXTORIENTATION",
|
|
206
|
+
"TEXTOVERRIDE",
|
|
207
|
+
"TEXTREVERSED",
|
|
208
|
+
"TEXTSIZE",
|
|
209
|
+
"TEXTSTYLE",
|
|
210
|
+
"THROUGHPOINT",
|
|
211
|
+
"truecolour",
|
|
212
|
+
"TRIMMODE",
|
|
213
|
+
"UCSICON",
|
|
214
|
+
"uncloseable",
|
|
215
|
+
"undrawn",
|
|
216
|
+
"UNKNOWNCOMMAND",
|
|
217
|
+
"unrecognised",
|
|
218
|
+
"VERTICALALIGNMENT",
|
|
219
|
+
"vport",
|
|
220
|
+
"WIDTHFACTOR",
|
|
221
|
+
"xgridmax",
|
|
222
|
+
"xgridmin",
|
|
223
|
+
"ygridmax",
|
|
224
|
+
"ygridmin",
|
|
225
|
+
"ZEROLENGTH",
|
|
226
|
+
"accentcolour",
|
|
227
|
+
"Alignedtext",
|
|
228
|
+
"BADINPUT",
|
|
229
|
+
"BLOCKNAME",
|
|
230
|
+
"boundingbox",
|
|
231
|
+
"BOXBLANK",
|
|
232
|
+
"BOXFILLED",
|
|
233
|
+
"BRELM",
|
|
234
|
+
"BRSTD",
|
|
235
|
+
"BRSTONE",
|
|
236
|
+
"canvasbackgroundcolour",
|
|
237
|
+
"CANNOTBEACTIONED",
|
|
238
|
+
"CANNOTBEDELETED",
|
|
239
|
+
"CANNOTBERENAMED",
|
|
240
|
+
"CHAMFERA",
|
|
241
|
+
"CHAMFERB",
|
|
242
|
+
"CHAMFERC",
|
|
243
|
+
"CHAMFERD",
|
|
244
|
+
"CHAMMODE",
|
|
245
|
+
"checkitems",
|
|
246
|
+
"CLOSEDBLANK",
|
|
247
|
+
"CONC",
|
|
248
|
+
"counterclockwise",
|
|
249
|
+
"cstyle",
|
|
250
|
+
"CSTYLEDELETE",
|
|
251
|
+
"currentstyle",
|
|
252
|
+
"DASHDOT",
|
|
253
|
+
"DATUMBLANK",
|
|
254
|
+
"DATUMFILLED",
|
|
255
|
+
"Degen",
|
|
256
|
+
"deleteblock",
|
|
257
|
+
"DOLMIT",
|
|
258
|
+
"DOTBLANK",
|
|
259
|
+
"DOTSMALL",
|
|
260
|
+
"Elec",
|
|
261
|
+
"ENDTAB",
|
|
262
|
+
"ERASESOURCE",
|
|
263
|
+
"Extline",
|
|
264
|
+
"FILEOPEN",
|
|
265
|
+
"fontbackwards",
|
|
266
|
+
"fontupsidedown",
|
|
267
|
+
"Gradians",
|
|
268
|
+
"gridcolour",
|
|
269
|
+
"gridlines",
|
|
270
|
+
"HBONE",
|
|
271
|
+
"INSUL",
|
|
272
|
+
"INVALIDBOUNDARY",
|
|
273
|
+
"INVALIDCLIPBOARD",
|
|
274
|
+
"INVALIDDXFFORMAT",
|
|
275
|
+
"INVALIDFILE",
|
|
276
|
+
"INVALIDGROUPCODE",
|
|
277
|
+
"INVALIDINTERSECTTYPE",
|
|
278
|
+
"INVALIDNUMBER",
|
|
279
|
+
"INVALIDPOINT",
|
|
280
|
+
"INVALIDTYPE",
|
|
281
|
+
"LAYERNAME",
|
|
282
|
+
"LEADERLENGTH",
|
|
283
|
+
"LWDEFAULT",
|
|
284
|
+
"MAXVALUE",
|
|
285
|
+
"midp",
|
|
286
|
+
"MINVALUE",
|
|
287
|
+
"MIRRORFIRST",
|
|
288
|
+
"MIRRORSECOND",
|
|
289
|
+
"MUDST",
|
|
290
|
+
"nendobj",
|
|
291
|
+
"NEWLENGTH",
|
|
292
|
+
"NEXTPOINT",
|
|
293
|
+
"NOEXTEND",
|
|
294
|
+
"nonexistent",
|
|
295
|
+
"NOTACOMMAND",
|
|
296
|
+
"NOTAPATTERN",
|
|
297
|
+
"NOTIMPLEMENTED",
|
|
298
|
+
"Offscreen",
|
|
299
|
+
"OFFSETDIST",
|
|
300
|
+
"PARALLELLINES",
|
|
301
|
+
"PARQ",
|
|
302
|
+
"PLAST",
|
|
303
|
+
"PLASTI",
|
|
304
|
+
"readblocks",
|
|
305
|
+
"renameitem",
|
|
306
|
+
"roundtrip",
|
|
307
|
+
"RROOF",
|
|
308
|
+
"RSHKE",
|
|
309
|
+
"SACNCR",
|
|
310
|
+
"Segs",
|
|
311
|
+
"TRIANG",
|
|
312
|
+
"underflowed",
|
|
313
|
+
"unminified",
|
|
314
|
+
"UNSUPPORTEDENTITIES",
|
|
315
|
+
"UPSIDEDOWN",
|
|
316
|
+
"Viewmode",
|
|
317
|
+
"xref",
|
|
318
|
+
"GOST",
|
|
319
|
+
"quot"
|
|
320
|
+
]
|
|
321
|
+
}
|