@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
|
@@ -10,17 +10,18 @@ import { Line } from './line.js';
|
|
|
10
10
|
import { Arc } from './arc.js';
|
|
11
11
|
import { Flags } from '../properties/flags.js';
|
|
12
12
|
import { Property } from '../properties/property.js';
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
|
|
15
15
|
import { DesignCore } from '../designCore.js';
|
|
16
|
-
import { SnapPoint } from '../lib/
|
|
16
|
+
import { SnapPoint } from '../lib/auxiliary/snapPoint.js';
|
|
17
|
+
import { RubberBand } from '../lib/auxiliary/rubberBand.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Base Polyline Entity Class
|
|
20
21
|
* @extends Entity
|
|
21
22
|
*/
|
|
22
|
-
export class
|
|
23
|
-
static type = '
|
|
23
|
+
export class PolylineBase extends Entity {
|
|
24
|
+
static type = 'PolylineBase';
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Create a Base Polyline
|
|
@@ -75,6 +76,14 @@ export class BasePolyline extends Entity {
|
|
|
75
76
|
|
|
76
77
|
this.flags.setFlagValue(Property.loadValue([data?.flags, data?.[70]], 0));
|
|
77
78
|
|
|
79
|
+
// DXF Groupcode 70 bit 1 - closed flag exposed via EntityProperties
|
|
80
|
+
this.properties.add(Property.Names.CLOSED, {
|
|
81
|
+
type: Property.Type.BOOLEAN,
|
|
82
|
+
get: (entity) => entity.flags.hasFlag(1),
|
|
83
|
+
set: (entity, value) => value ? entity.flags.addValue(1) : entity.flags.removeValue(1),
|
|
84
|
+
dxfCode: 70,
|
|
85
|
+
});
|
|
86
|
+
|
|
78
87
|
// If the first and last points are the same the polyline should be considered closed.
|
|
79
88
|
// Require at least 4 points so that after removing the duplicate endpoint at least 3 remain.
|
|
80
89
|
if (this.points.length >= 4 && this.points[0].isSame(this.points.at(-1))) {
|
|
@@ -161,54 +170,25 @@ export class BasePolyline extends Entity {
|
|
|
161
170
|
|
|
162
171
|
if (this.points.length >= 1) {
|
|
163
172
|
const points = [...this.points, mousePoint];
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
173
|
+
if (this.inputMode === this.modes.ARC) {
|
|
174
|
+
// Straight segment is not the final form — show as rubber-band indicator
|
|
175
|
+
DesignCore.Scene.auxiliaryEntities.add(new RubberBand([this.points.at(-1), mousePoint]));
|
|
176
|
+
// Arc segment is the final form — draw on the current layer
|
|
177
|
+
const arcpoints = Utils.cloneObject(this.points);
|
|
178
|
+
arcpoints.at(-1).bulge = this.getBulgeFromSegment(mousePoint);
|
|
179
|
+
DesignCore.Scene.previewEntities.create(this.type, { points: [...arcpoints, mousePoint] });
|
|
180
|
+
} else {
|
|
181
|
+
DesignCore.Scene.previewEntities.create(this.type, { points: points });
|
|
182
|
+
}
|
|
172
183
|
}
|
|
173
184
|
}
|
|
174
185
|
|
|
175
186
|
/**
|
|
176
187
|
* Draw the polyline
|
|
177
|
-
* @param {Object}
|
|
178
|
-
* @param {number} scale
|
|
179
|
-
* @param {boolean} stroke - don't stroke hatch boundary shapes
|
|
188
|
+
* @param {Object} renderer
|
|
180
189
|
*/
|
|
181
|
-
draw(
|
|
182
|
-
|
|
183
|
-
if (this.points[i].bulge === 0) {
|
|
184
|
-
ctx.lineTo(this.points[i].x, this.points[i].y);
|
|
185
|
-
} else {
|
|
186
|
-
// define the next point or the first point for closed shapes
|
|
187
|
-
const nextPoint = this.points[i + 1] || this.points[0];
|
|
188
|
-
const centerPoint = this.points[i].bulgeCentrePoint(nextPoint);
|
|
189
|
-
const radius = this.points[i].bulgeRadius(nextPoint);
|
|
190
|
-
|
|
191
|
-
if (this.points[i].bulge > 0) {
|
|
192
|
-
// TODO: make this work with canvas
|
|
193
|
-
ctx.arc(centerPoint.x, centerPoint.y, radius, centerPoint.angle(this.points[i]), centerPoint.angle(nextPoint));
|
|
194
|
-
} else {
|
|
195
|
-
try { // HTML
|
|
196
|
-
ctx.arc(centerPoint.x, centerPoint.y, radius, centerPoint.angle(this.points[i]), centerPoint.angle(nextPoint), true);
|
|
197
|
-
} catch { // Cairo
|
|
198
|
-
ctx.arcNegative(centerPoint.x, centerPoint.y, radius, centerPoint.angle(this.points[i]), centerPoint.angle(nextPoint));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// handle a closed shape
|
|
205
|
-
if (this.flags.hasFlag(1)) {
|
|
206
|
-
ctx.lineTo(this.points[0].x, this.points[0].y);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (stroke) {
|
|
210
|
-
ctx.stroke();
|
|
211
|
-
}
|
|
190
|
+
draw(renderer) {
|
|
191
|
+
renderer.drawShape(this.toPolylinePoints());
|
|
212
192
|
}
|
|
213
193
|
|
|
214
194
|
/**
|
|
@@ -217,12 +197,12 @@ export class BasePolyline extends Entity {
|
|
|
217
197
|
*/
|
|
218
198
|
dxf(file) {
|
|
219
199
|
file.writeGroupCode('0', 'LWPOLYLINE');
|
|
220
|
-
file.writeGroupCode('5', this.
|
|
200
|
+
file.writeGroupCode('5', this.getProperty(Property.Names.HANDLE), DXFFile.Version.R2000); // Handle
|
|
221
201
|
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
222
202
|
file.writeGroupCode('100', 'AcDbPolyline', DXFFile.Version.R2000);
|
|
223
|
-
file.writeGroupCode('8', this.
|
|
224
|
-
file.writeGroupCode('6', this.
|
|
225
|
-
file.writeGroupCode('39', this.
|
|
203
|
+
file.writeGroupCode('8', this.getProperty(Property.Names.LAYER)); // LAYERNAME
|
|
204
|
+
file.writeGroupCode('6', this.getProperty(Property.Names.LINETYPE));
|
|
205
|
+
file.writeGroupCode('39', this.getProperty(Property.Names.LINEWIDTH));
|
|
226
206
|
file.writeGroupCode('90', this.points.length);
|
|
227
207
|
file.writeGroupCode('70', this.flags.getFlagValue());
|
|
228
208
|
for (let i = 0; i < this.points.length; i++) {
|
|
@@ -253,6 +233,7 @@ export class BasePolyline extends Entity {
|
|
|
253
233
|
/**
|
|
254
234
|
* Set entity points from a polyline point representation
|
|
255
235
|
* @param {Array} points
|
|
236
|
+
* @return {PolylineBase}
|
|
256
237
|
*/
|
|
257
238
|
fromPolylinePoints(points) {
|
|
258
239
|
const pts = points.map((p) => new Point(p.x, p.y, p.bulge));
|
|
@@ -260,6 +241,7 @@ export class BasePolyline extends Entity {
|
|
|
260
241
|
pts.pop();
|
|
261
242
|
}
|
|
262
243
|
this.points = pts;
|
|
244
|
+
return this;
|
|
263
245
|
}
|
|
264
246
|
|
|
265
247
|
/**
|
|
@@ -329,10 +311,10 @@ export class BasePolyline extends Entity {
|
|
|
329
311
|
let closestPoint;
|
|
330
312
|
let candidateSegment;
|
|
331
313
|
if (A.bulge !== 0) {
|
|
332
|
-
const
|
|
314
|
+
const centre = A.bulgeCentrePoint(B);
|
|
333
315
|
const direction = A.bulge > 0 ? 1 : -1;
|
|
334
|
-
closestPoint = P.closestPointOnArc(A, B,
|
|
335
|
-
candidateSegment = new Arc({ points: [
|
|
316
|
+
closestPoint = P.closestPointOnArc(A, B, centre, direction);
|
|
317
|
+
candidateSegment = new Arc({ points: [centre, A, B], direction });
|
|
336
318
|
} else {
|
|
337
319
|
closestPoint = P.closestPointOnLine(A, B);
|
|
338
320
|
candidateSegment = new Line({ points: [A, B] });
|
|
@@ -438,9 +420,9 @@ export class BasePolyline extends Entity {
|
|
|
438
420
|
*/
|
|
439
421
|
isPointOnSegment(point, A, B) {
|
|
440
422
|
if (A.bulge !== 0) {
|
|
441
|
-
const
|
|
423
|
+
const centre = A.bulgeCentrePoint(B);
|
|
442
424
|
const direction = A.bulge > 0 ? 1 : -1;
|
|
443
|
-
return point.isOnArc(A, B,
|
|
425
|
+
return point.isOnArc(A, B, centre, direction);
|
|
444
426
|
}
|
|
445
427
|
return point.isOnLine(A, B);
|
|
446
428
|
}
|
|
@@ -456,9 +438,9 @@ export class BasePolyline extends Entity {
|
|
|
456
438
|
const B = this.points[segmentIndex % this.points.length];
|
|
457
439
|
|
|
458
440
|
if (A.bulge !== 0) {
|
|
459
|
-
const
|
|
441
|
+
const centre = A.bulgeCentrePoint(B);
|
|
460
442
|
const direction = A.bulge > 0 ? 1 : -1;
|
|
461
|
-
const closest = point.closestPointOnArc(A, B,
|
|
443
|
+
const closest = point.closestPointOnArc(A, B, centre, direction);
|
|
462
444
|
|
|
463
445
|
if (closest) {
|
|
464
446
|
return closest;
|
|
@@ -482,250 +464,16 @@ export class BasePolyline extends Entity {
|
|
|
482
464
|
const B = this.points[segmentIndex % this.points.length];
|
|
483
465
|
|
|
484
466
|
if (A.bulge !== 0) {
|
|
485
|
-
const
|
|
467
|
+
const centre = A.bulgeCentrePoint(B);
|
|
486
468
|
const direction = A.bulge > 0 ? 1 : -1;
|
|
487
|
-
const startAngle =
|
|
488
|
-
const pointAngle =
|
|
469
|
+
const startAngle = centre.angle(A);
|
|
470
|
+
const pointAngle = centre.angle(point);
|
|
489
471
|
return ((pointAngle - startAngle) * direction + 4 * Math.PI) % (2 * Math.PI);
|
|
490
472
|
}
|
|
491
473
|
|
|
492
474
|
return A.distance(point);
|
|
493
475
|
}
|
|
494
476
|
|
|
495
|
-
/**
|
|
496
|
-
* Extend the entity
|
|
497
|
-
* Only extends when the end segment closest to the mouse is a line segment (bulge === 0)
|
|
498
|
-
* @param {Array} intersections - array of intersection points
|
|
499
|
-
* @return {Array} - array of state changes
|
|
500
|
-
*/
|
|
501
|
-
extend(intersections) {
|
|
502
|
-
const stateChanges = [];
|
|
503
|
-
|
|
504
|
-
if (!intersections?.length) {
|
|
505
|
-
return stateChanges;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const mousePosition = DesignCore.Mouse.pointOnScene();
|
|
509
|
-
const lastIndex = this.points.length - 1;
|
|
510
|
-
|
|
511
|
-
// Determine which end segment is closer to the mouse
|
|
512
|
-
const closestOnFirst = this.closestPointOnSegment(mousePosition, 1);
|
|
513
|
-
const closestOnLast = this.closestPointOnSegment(mousePosition, lastIndex);
|
|
514
|
-
const distToFirst = mousePosition.distance(closestOnFirst);
|
|
515
|
-
const distToLast = mousePosition.distance(closestOnLast);
|
|
516
|
-
|
|
517
|
-
// Identify the selected end: the endpoint index and the bulge of its segment
|
|
518
|
-
let endPointIndex;
|
|
519
|
-
let endSegmentBulge;
|
|
520
|
-
|
|
521
|
-
if (distToFirst < distToLast) {
|
|
522
|
-
endPointIndex = 0;
|
|
523
|
-
endSegmentBulge = this.points[0].bulge;
|
|
524
|
-
} else if (distToLast < distToFirst) {
|
|
525
|
-
endPointIndex = lastIndex;
|
|
526
|
-
endSegmentBulge = this.points[lastIndex - 1].bulge;
|
|
527
|
-
} else {
|
|
528
|
-
// Tie (includes 2-point polyline where both segments are the same)
|
|
529
|
-
// Break tie by distance to the actual endpoints
|
|
530
|
-
if (mousePosition.distance(this.points[0]) <= mousePosition.distance(this.points[lastIndex])) {
|
|
531
|
-
endPointIndex = 0;
|
|
532
|
-
endSegmentBulge = this.points[0].bulge;
|
|
533
|
-
} else {
|
|
534
|
-
endPointIndex = lastIndex;
|
|
535
|
-
endSegmentBulge = this.points[lastIndex - 1].bulge;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// Only allow extending line segments (not arcs)
|
|
540
|
-
if (endSegmentBulge !== 0) {
|
|
541
|
-
DesignCore.Core.notify(`${this.type} - ${Strings.Message.NOEXTEND}`);
|
|
542
|
-
return stateChanges;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
const endPoint = this.points[endPointIndex];
|
|
546
|
-
const adjacentPoint = endPointIndex === 0 ? this.points[1] : this.points[lastIndex - 1];
|
|
547
|
-
|
|
548
|
-
// Sort intersections by distance from the end point
|
|
549
|
-
Utils.sortPointsByDistance(intersections, endPoint);
|
|
550
|
-
|
|
551
|
-
// Find the closest intersection that lies beyond the endpoint
|
|
552
|
-
const direction = endPoint.subtract(adjacentPoint);
|
|
553
|
-
const newEndPoint = intersections.find((p) => {
|
|
554
|
-
if (p.isSame(endPoint)) return false;
|
|
555
|
-
if (p.subtract(endPoint).dot(direction) <= 0) return false;
|
|
556
|
-
if (adjacentPoint.distance(p) <= adjacentPoint.distance(endPoint)) return false;
|
|
557
|
-
return true;
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
if (!newEndPoint) {
|
|
561
|
-
return stateChanges;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// Build the new points array
|
|
565
|
-
const newPoints = this.points.map((p) => p.clone());
|
|
566
|
-
newPoints[endPointIndex] = newEndPoint;
|
|
567
|
-
|
|
568
|
-
if (newPoints[endPointIndex].isSame(this.points[endPointIndex])) {
|
|
569
|
-
return stateChanges;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
stateChanges.push(new UpdateState(this, { points: newPoints }));
|
|
573
|
-
return stateChanges;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
/**
|
|
577
|
-
* Trim the entity
|
|
578
|
-
* @param {Array} intersections - array of intersection points
|
|
579
|
-
* @return {Array} - array of state changes
|
|
580
|
-
*/
|
|
581
|
-
trim(intersections) {
|
|
582
|
-
const stateChanges = [];
|
|
583
|
-
|
|
584
|
-
if (!intersections?.length) {
|
|
585
|
-
return stateChanges;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
const mousePosition = DesignCore.Mouse.pointOnScene();
|
|
589
|
-
|
|
590
|
-
// Find the segment index closest to the mouse
|
|
591
|
-
let mouseSegmentIndex = 0;
|
|
592
|
-
let minDistance = Infinity;
|
|
593
|
-
|
|
594
|
-
for (let i = 1; i < this.points.length; i++) {
|
|
595
|
-
const closestPoint = this.closestPointOnSegment(mousePosition, i);
|
|
596
|
-
if (closestPoint) {
|
|
597
|
-
const dist = mousePosition.distance(closestPoint);
|
|
598
|
-
if (dist < minDistance) {
|
|
599
|
-
minDistance = dist;
|
|
600
|
-
mouseSegmentIndex = i;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// Filter out intersections that coincide with existing polyline vertices
|
|
606
|
-
const filteredIntersections = intersections.filter((point) => !this.points.some((vertex) => vertex.isSame(point)));
|
|
607
|
-
|
|
608
|
-
if (!filteredIntersections.length) {
|
|
609
|
-
return stateChanges;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// Locate each intersection on its segment with an ordering value
|
|
613
|
-
const locatedIntersections = [];
|
|
614
|
-
|
|
615
|
-
for (const point of filteredIntersections) {
|
|
616
|
-
for (let i = 1; i < this.points.length; i++) {
|
|
617
|
-
if (this.isPointOnSegment(point, this.points[i - 1], this.points[i])) {
|
|
618
|
-
locatedIntersections.push({
|
|
619
|
-
segmentIndex: i,
|
|
620
|
-
point: point,
|
|
621
|
-
positionAlongSegment: this.positionOnSegment(point, i),
|
|
622
|
-
});
|
|
623
|
-
break;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
if (!locatedIntersections.length) {
|
|
629
|
-
return stateChanges;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// Sort by segment index, then by position along segment
|
|
633
|
-
locatedIntersections.sort((a, b) => {
|
|
634
|
-
if (a.segmentIndex !== b.segmentIndex) return a.segmentIndex - b.segmentIndex;
|
|
635
|
-
return a.positionAlongSegment - b.positionAlongSegment;
|
|
636
|
-
});
|
|
637
|
-
|
|
638
|
-
// Precompute the mouse position along its segment
|
|
639
|
-
const mouseClosest = this.closestPointOnSegment(mousePosition, mouseSegmentIndex);
|
|
640
|
-
const mousePos = mouseClosest ? this.positionOnSegment(mouseClosest, mouseSegmentIndex) : 0;
|
|
641
|
-
|
|
642
|
-
// Find the nearest intersections that bracket the mouse segment
|
|
643
|
-
// - trimBefore: the last intersection at or before the mouse
|
|
644
|
-
// - trimAfter: the first intersection at or after the mouse
|
|
645
|
-
let trimBefore = null;
|
|
646
|
-
let trimAfter = null;
|
|
647
|
-
|
|
648
|
-
for (const loc of locatedIntersections) {
|
|
649
|
-
if (loc.segmentIndex < mouseSegmentIndex) {
|
|
650
|
-
trimBefore = loc;
|
|
651
|
-
} else if (loc.segmentIndex === mouseSegmentIndex) {
|
|
652
|
-
if (loc.positionAlongSegment <= mousePos) {
|
|
653
|
-
trimBefore = loc;
|
|
654
|
-
} else if (!trimAfter) {
|
|
655
|
-
trimAfter = loc;
|
|
656
|
-
}
|
|
657
|
-
} else if (!trimAfter) {
|
|
658
|
-
trimAfter = loc;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// Build new polyline(s) from the remaining portions
|
|
663
|
-
// Portion 1: start of polyline to trimBefore point
|
|
664
|
-
if (trimBefore) {
|
|
665
|
-
const points = [];
|
|
666
|
-
|
|
667
|
-
for (let i = 0; i < trimBefore.segmentIndex - 1; i++) {
|
|
668
|
-
points.push(this.points[i].clone());
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// Add the segment start point (with adjusted bulge for arcs)
|
|
672
|
-
const segStart = this.points[trimBefore.segmentIndex - 1];
|
|
673
|
-
const segStartClone = segStart.clone();
|
|
674
|
-
if (segStart.bulge !== 0) {
|
|
675
|
-
segStartClone.bulge = segStart.partialBulge(this.points[trimBefore.segmentIndex], trimBefore.point);
|
|
676
|
-
}
|
|
677
|
-
points.push(segStartClone);
|
|
678
|
-
|
|
679
|
-
// Add the trim point (skip if it coincides with the last added point)
|
|
680
|
-
const trimPoint = trimBefore.point.clone();
|
|
681
|
-
if (!points.at(-1).isSame(trimPoint)) {
|
|
682
|
-
points.push(trimPoint);
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
if (points.length >= 2) {
|
|
686
|
-
const polyline = Utils.cloneObject(this);
|
|
687
|
-
polyline.points = points;
|
|
688
|
-
polyline.flags.removeValue(1); // clear closed bit
|
|
689
|
-
stateChanges.push(new AddState(polyline));
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// Portion 2: trimAfter point to end of polyline
|
|
694
|
-
if (trimAfter) {
|
|
695
|
-
const points = [];
|
|
696
|
-
const trimPoint = trimAfter.point.clone();
|
|
697
|
-
|
|
698
|
-
// If the segment is an arc, set remaining arc bulge
|
|
699
|
-
const segStart = this.points[trimAfter.segmentIndex - 1];
|
|
700
|
-
if (segStart.bulge !== 0) {
|
|
701
|
-
trimPoint.bulge = segStart.partialBulge(this.points[trimAfter.segmentIndex], trimPoint, true);
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
points.push(trimPoint);
|
|
705
|
-
|
|
706
|
-
// Add remaining points (skip if coincides with the trim point)
|
|
707
|
-
for (let i = trimAfter.segmentIndex; i < this.points.length; i++) {
|
|
708
|
-
const nextPoint = this.points[i].clone();
|
|
709
|
-
if (!points.at(-1).isSame(nextPoint)) {
|
|
710
|
-
points.push(nextPoint);
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
if (points.length >= 2) {
|
|
715
|
-
const polyline = Utils.cloneObject(this);
|
|
716
|
-
polyline.points = points;
|
|
717
|
-
polyline.flags.removeValue(1); // clear closed bit
|
|
718
|
-
stateChanges.push(new AddState(polyline));
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
if (trimBefore || trimAfter) {
|
|
723
|
-
stateChanges.push(new RemoveState(this));
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
return stateChanges;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
477
|
/**
|
|
730
478
|
* Return boundingbox for entity
|
|
731
479
|
* @return {BoundingBox}
|
|
@@ -742,8 +490,8 @@ export class BasePolyline extends Entity {
|
|
|
742
490
|
let boundingBox = BoundingBox.lineBoundingBox(this.points[i], nextPoint);
|
|
743
491
|
|
|
744
492
|
if (this.points[i].bulge !== 0) {
|
|
745
|
-
const
|
|
746
|
-
boundingBox = BoundingBox.arcBoundingBox(
|
|
493
|
+
const centrePoint = this.points[i].bulgeCentrePoint(nextPoint);
|
|
494
|
+
boundingBox = BoundingBox.arcBoundingBox(centrePoint, this.points[i], nextPoint, this.points[i].bulge);
|
|
747
495
|
}
|
|
748
496
|
|
|
749
497
|
xmin = Math.min(xmin, boundingBox.xMin);
|
|
@@ -771,9 +519,9 @@ export class BasePolyline extends Entity {
|
|
|
771
519
|
// get the angle at the end of the previous segment
|
|
772
520
|
let lastSegAngle;
|
|
773
521
|
if (lastSegIsArc) {
|
|
774
|
-
const
|
|
775
|
-
// angle is perpendicular to the
|
|
776
|
-
lastSegAngle =
|
|
522
|
+
const centrePoint = this.points.at(-2).bulgeCentrePoint(this.points.at(-1));
|
|
523
|
+
// angle is perpendicular to the centre-to-end point ray, in the direction of the bulge
|
|
524
|
+
lastSegAngle = centrePoint.angle(this.points.at(-1)) + (Math.PI / 2) * Math.sign(lastSegBulge);
|
|
777
525
|
} else {
|
|
778
526
|
// line segment angle is the angle from point 0 to point 1
|
|
779
527
|
lastSegAngle = this.points.at(-2).angle(this.points.at(-1));
|
|
@@ -4,6 +4,7 @@ import { Entity } from './entity.js';
|
|
|
4
4
|
import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
5
5
|
import { Logging } from '../lib/logging.js';
|
|
6
6
|
import { Polyline } from './polyline.js';
|
|
7
|
+
import { RubberBand } from '../lib/auxiliary/rubberBand.js';
|
|
7
8
|
|
|
8
9
|
import { DesignCore } from '../designCore.js';
|
|
9
10
|
|
|
@@ -67,8 +68,9 @@ export class Rectangle extends Entity {
|
|
|
67
68
|
preview() {
|
|
68
69
|
if (this.points.length >= 1) {
|
|
69
70
|
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
71
|
+
DesignCore.Scene.auxiliaryEntities.add(new RubberBand([this.points.at(-1), mousePoint]));
|
|
70
72
|
const points = this.rectPoints(this.points.at(-1), mousePoint);
|
|
71
|
-
DesignCore.Scene.
|
|
73
|
+
DesignCore.Scene.previewEntities.create('Polyline', { points: points });
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
|
package/core/entities/solid.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Entity } from './entity.js';
|
|
2
2
|
import { DXFFile } from '../lib/dxf/dxfFile.js';
|
|
3
3
|
import { BoundingBox } from '../lib/boundingBox.js';
|
|
4
|
+
import { Property } from '../properties/property.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Solid Entity Class
|
|
@@ -19,20 +20,10 @@ export class Solid extends Entity {
|
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Draw the entity
|
|
22
|
-
* @param {Object}
|
|
23
|
-
* @param {number} scale
|
|
23
|
+
* @param {Object} renderer
|
|
24
24
|
*/
|
|
25
|
-
draw(
|
|
26
|
-
this.points
|
|
27
|
-
if (index == 0) {
|
|
28
|
-
ctx.moveTo(point.x, point.y);
|
|
29
|
-
} else {
|
|
30
|
-
ctx.lineTo(point.x, point.y);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
ctx.closePath();
|
|
35
|
-
ctx.fill();
|
|
25
|
+
draw(renderer) {
|
|
26
|
+
renderer.drawShape(this.points, { closed: true, fill: true, stroke: false });
|
|
36
27
|
}
|
|
37
28
|
|
|
38
29
|
/**
|
|
@@ -41,10 +32,10 @@ export class Solid extends Entity {
|
|
|
41
32
|
*/
|
|
42
33
|
dxf(file) {
|
|
43
34
|
file.writeGroupCode('0', 'SOLID');
|
|
44
|
-
file.writeGroupCode('5', this.
|
|
35
|
+
file.writeGroupCode('5', this.getProperty(Property.Names.HANDLE), DXFFile.Version.R2000); // Handle
|
|
45
36
|
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
46
37
|
file.writeGroupCode('100', 'AcDbTrace', DXFFile.Version.R2000);
|
|
47
|
-
file.writeGroupCode('8', this.
|
|
38
|
+
file.writeGroupCode('8', this.getProperty(Property.Names.LAYER));
|
|
48
39
|
file.writeGroupCode('10', this.points[0].x);
|
|
49
40
|
file.writeGroupCode('20', this.points[0].y);
|
|
50
41
|
file.writeGroupCode('30', '0.0');
|