@design-core/core 0.0.6 → 0.0.7
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/TODO.md +49 -6
- package/core/core/core.js +0 -3
- package/core/dimensions/alignedDimension.js +5 -4
- package/core/dimensions/angularDimension.js +6 -5
- package/core/dimensions/baseCircularDimension.js +3 -2
- package/core/dimensions/baseDimension.js +59 -93
- package/core/dimensions/baseLinearDimension.js +6 -5
- package/core/dimensions/diametricDimension.js +4 -3
- package/core/dimensions/dimension.js +21 -14
- package/core/dimensions/radialDimension.js +4 -3
- package/core/dimensions/rotatedDimension.js +12 -11
- package/core/entities/arc.js +112 -145
- package/core/entities/arctext.js +212 -174
- package/core/entities/basePolyline.js +30 -282
- package/core/entities/circle.js +77 -99
- package/core/entities/entity.js +114 -93
- package/core/entities/hatch.js +322 -249
- package/core/entities/insert.js +66 -81
- package/core/entities/line.js +21 -142
- package/core/entities/lwpolyline.js +16 -11
- package/core/entities/polyline.js +4 -4
- package/core/entities/rectangle.js +3 -1
- package/core/entities/solid.js +6 -15
- package/core/entities/text.js +188 -199
- 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/canvas.js +228 -166
- package/core/lib/clipboard.js +7 -1
- 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 +4 -3
- package/core/lib/entityManager.js +18 -11
- package/core/lib/inputManager.js +35 -11
- package/core/lib/intersect.js +25 -0
- package/core/lib/patterns.js +8 -1
- 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 +27 -5
- package/core/lib/selectionManager.js +2 -2
- 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 +21 -2
- package/core/properties/entityProperties.js +104 -0
- package/core/properties/property.js +106 -2
- package/core/properties/propertyManager.js +29 -13
- package/core/tables/block.js +4 -37
- package/core/tables/endblk.js +1 -1
- package/core/tables/layer.js +8 -0
- package/core/tables/styleManagerBase.js +3 -2
- package/core/tables/tableManagerBase.js +8 -3
- package/core/tools/chamfer.js +111 -137
- package/core/tools/chamferFilletBase.js +135 -34
- package/core/tools/copy.js +3 -3
- package/core/tools/explode.js +2 -2
- package/core/tools/extend.js +132 -19
- package/core/tools/fillet.js +86 -183
- package/core/tools/matchProp.js +2 -11
- package/core/tools/mirror.js +7 -6
- package/core/tools/move.js +3 -3
- package/core/tools/offset.js +3 -5
- package/core/tools/pasteclip.js +1 -1
- package/core/tools/rotate.js +6 -3
- package/core/tools/scale.js +1 -1
- package/core/tools/trim.js +265 -23
- package/core/tools/zoom.js +1 -1
- package/jest.config.js +6 -0
- package/package.json +5 -3
- package/test/dimensions/alignedDimension.test.js +14 -7
- package/test/dimensions/angularDimension.test.js +6 -6
- package/test/dimensions/baseDimension.test.js +69 -8
- package/test/dimensions/baseLinearDimension.test.js +62 -0
- package/test/dimensions/diametricDimension.test.js +6 -6
- package/test/dimensions/radialDimension.test.js +6 -6
- package/test/dimensions/rotatedDimension.test.js +14 -7
- package/test/entities/arc.test.js +80 -83
- package/test/entities/arctext.test.js +180 -53
- package/test/entities/basePolyline.test.js +68 -2
- package/test/entities/circle.test.js +57 -85
- package/test/entities/entity.test.js +42 -8
- package/test/entities/hatch.test.js +543 -70
- package/test/entities/insert.test.js +96 -1
- package/test/entities/line.test.js +15 -41
- package/test/entities/lwpolyline.test.js +104 -0
- package/test/entities/polyline.test.js +11 -0
- package/test/entities/rectangle.test.js +11 -0
- package/test/entities/solid.test.js +1 -1
- package/test/entities/text.test.js +294 -69
- package/test/integration/exportIntegration.reference.dxf +9 -9
- package/test/integration/exportIntegration.test.js +2 -2
- 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/canvas.test.js +742 -123
- package/test/lib/constants.test.js +27 -0
- package/test/lib/entityManager.test.js +4 -4
- package/test/lib/inputManager.test.js +80 -19
- 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/settings.test.js +5 -6
- package/test/lib/snapping.test.js +71 -129
- 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 +3 -3
- 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 +31 -1
- package/test/tables/endblk.test.js +2 -2
- package/test/tables/layer.test.js +30 -0
- package/test/test-helpers/hatchGridRenderer.js +180 -0
- package/test/test-helpers/test-helpers.js +152 -0
- package/test/tools/chamfer.test.js +227 -5
- package/test/tools/chamferFilletBase.test.js +98 -9
- package/test/tools/copy.test.js +2 -2
- package/test/tools/explode.test.js +3 -3
- package/test/tools/extend.test.js +331 -0
- package/test/tools/fillet.test.js +181 -0
- package/test/tools/matchProp.test.js +5 -5
- package/test/tools/mirror.test.js +13 -13
- package/test/tools/offset.test.js +170 -3
- package/test/tools/pasteclip.test.js +5 -5
- package/test/tools/rotate.test.js +32 -2
- package/test/tools/scale.test.js +5 -5
- package/test/tools/trim.test.js +526 -0
- package/test/tools/zoom.test.js +7 -7
- package/core/lib/selectionWindow.js +0 -83
|
@@ -7,6 +7,8 @@ import { Point } from '../entities/point.js';
|
|
|
7
7
|
import { BaseLinearDimension } from './baseLinearDimension.js';
|
|
8
8
|
|
|
9
9
|
import { DesignCore } from '../designCore.js';
|
|
10
|
+
import { Property } from '../properties/property.js';
|
|
11
|
+
import { RubberBand } from '../lib/auxiliary/rubberBand.js';
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
/**
|
|
@@ -42,12 +44,12 @@ export class RotatedDimension extends BaseLinearDimension {
|
|
|
42
44
|
async execute() {
|
|
43
45
|
try {
|
|
44
46
|
DesignCore.Scene.selectionManager.reset();
|
|
45
|
-
this.
|
|
47
|
+
this.setProperty(Property.Names.DIMENSIONSTYLE, DesignCore.DimStyleManager.getCstyle());
|
|
46
48
|
this.dimType.setDimType(0); // Rotated dimension
|
|
47
49
|
|
|
48
50
|
const opAngle = new PromptOptions(Strings.Input.ROTATION, [Input.Type.NUMBER]);
|
|
49
51
|
const angleValue = await DesignCore.Scene.inputManager.requestInput(opAngle);
|
|
50
|
-
this.
|
|
52
|
+
this.setProperty(Property.Names.LINEARDIMANGLE, Number(angleValue) || 0);
|
|
51
53
|
|
|
52
54
|
const op = new PromptOptions(Strings.Input.START, [Input.Type.POINT]);
|
|
53
55
|
const pt13 = await DesignCore.Scene.inputManager.requestInput(op);
|
|
@@ -65,7 +67,7 @@ export class RotatedDimension extends BaseLinearDimension {
|
|
|
65
67
|
this.points.push(pt11);
|
|
66
68
|
|
|
67
69
|
const tempLine = new Line({ points: [pt13, pt14] });
|
|
68
|
-
this.points = RotatedDimension.getPointsFromSelection([tempLine], pt11, this.
|
|
70
|
+
this.points = RotatedDimension.getPointsFromSelection([tempLine], pt11, this.getProperty(Property.Names.LINEARDIMANGLE));
|
|
69
71
|
|
|
70
72
|
DesignCore.Scene.inputManager.executeCommand(this);
|
|
71
73
|
} catch (err) {
|
|
@@ -117,16 +119,15 @@ export class RotatedDimension extends BaseLinearDimension {
|
|
|
117
119
|
preview() {
|
|
118
120
|
if (this.points.length === 1) {
|
|
119
121
|
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
120
|
-
|
|
121
|
-
DesignCore.Scene.tempEntities.create('Line', { points: points });
|
|
122
|
+
DesignCore.Scene.auxiliaryEntities.add(new RubberBand([this.points.at(0), mousePoint]));
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
if (this.points.length > 1) {
|
|
125
126
|
const pt11 = DesignCore.Mouse.pointOnScene();
|
|
126
127
|
pt11.sequence = 11;
|
|
127
128
|
const tempLine = new Line({ points: [this.points[0], this.points[1]] });
|
|
128
|
-
const points = RotatedDimension.getPointsFromSelection([tempLine], pt11, this.
|
|
129
|
-
DesignCore.Scene.
|
|
129
|
+
const points = RotatedDimension.getPointsFromSelection([tempLine], pt11, this.getProperty(Property.Names.LINEARDIMANGLE));
|
|
130
|
+
DesignCore.Scene.previewEntities.create(this.type, { points: points, dimensionStyle: this.getProperty(Property.Names.DIMENSIONSTYLE) });
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
|
|
@@ -141,10 +142,10 @@ export class RotatedDimension extends BaseLinearDimension {
|
|
|
141
142
|
const Pt14 = this.getPointBySequence(this.points, 14);
|
|
142
143
|
|
|
143
144
|
file.writeGroupCode('0', 'DIMENSION');
|
|
144
|
-
file.writeGroupCode('5', this.
|
|
145
|
+
file.writeGroupCode('5', this.getProperty(Property.Names.HANDLE), DXFFile.Version.R2000); // Handle
|
|
145
146
|
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
146
147
|
file.writeGroupCode('100', 'AcDbDimension', DXFFile.Version.R2000);
|
|
147
|
-
file.writeGroupCode('8', this.
|
|
148
|
+
file.writeGroupCode('8', this.getProperty(Property.Names.LAYER));
|
|
148
149
|
// file.writeGroupCode('2', this.blockName); // Block not required
|
|
149
150
|
file.writeGroupCode('10', Pt10.x); // X - definition / arrow point
|
|
150
151
|
file.writeGroupCode('20', Pt10.y); // Y
|
|
@@ -153,7 +154,7 @@ export class RotatedDimension extends BaseLinearDimension {
|
|
|
153
154
|
file.writeGroupCode('21', Pt11.y); // Y
|
|
154
155
|
file.writeGroupCode('31', '0.0'); // Z
|
|
155
156
|
file.writeGroupCode('70', this.dimType.getDimType()); // DIMENSION TYPE
|
|
156
|
-
file.writeGroupCode('3', this.
|
|
157
|
+
file.writeGroupCode('3', this.getProperty(Property.Names.DIMENSIONSTYLE)); // DIMENSION STYLE
|
|
157
158
|
file.writeGroupCode('100', 'AcDbAlignedDimension', DXFFile.Version.R2000);
|
|
158
159
|
file.writeGroupCode('13', Pt13.x); // X - start point of first extension line
|
|
159
160
|
file.writeGroupCode('23', Pt13.y); // Y
|
|
@@ -161,7 +162,7 @@ export class RotatedDimension extends BaseLinearDimension {
|
|
|
161
162
|
file.writeGroupCode('14', Pt14.x); // X - start point of second extension line
|
|
162
163
|
file.writeGroupCode('24', Pt14.y); // Y
|
|
163
164
|
file.writeGroupCode('34', '0.0'); // Z
|
|
164
|
-
file.writeGroupCode('50', this.
|
|
165
|
+
file.writeGroupCode('50', this.getProperty(Property.Names.LINEARDIMANGLE)); // Utils.radians2degrees(Pt13.angle(Pt14))); // Rotation angle
|
|
165
166
|
file.writeGroupCode('100', 'AcDbRotatedDimension', DXFFile.Version.R2000);
|
|
166
167
|
}
|
|
167
168
|
}
|
package/core/entities/arc.js
CHANGED
|
@@ -6,11 +6,12 @@ import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
|
6
6
|
import { Logging } from '../lib/logging.js';
|
|
7
7
|
import { DXFFile } from '../lib/dxf/dxfFile.js';
|
|
8
8
|
import { BoundingBox } from '../lib/boundingBox.js';
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
|
|
11
11
|
import { DesignCore } from '../designCore.js';
|
|
12
12
|
import { Property } from '../properties/property.js';
|
|
13
|
-
import { SnapPoint } from '../lib/
|
|
13
|
+
import { SnapPoint } from '../lib/auxiliary/snapPoint.js';
|
|
14
|
+
import { RubberBand } from '../lib/auxiliary/rubberBand.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Arc Entity Class
|
|
@@ -25,46 +26,32 @@ export class Arc extends Entity {
|
|
|
25
26
|
*/
|
|
26
27
|
constructor(data) {
|
|
27
28
|
super(data);
|
|
28
|
-
this.radius = 1;
|
|
29
|
-
|
|
30
|
-
// direction: - ccw > 0, cw <= 0
|
|
31
|
-
// default to 1 - counter clockwise
|
|
32
|
-
Object.defineProperty(this, 'direction', {
|
|
33
|
-
value: 1,
|
|
34
|
-
writable: true,
|
|
35
|
-
});
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (radius !== undefined) {
|
|
44
|
-
this.radius = radius;
|
|
45
|
-
}
|
|
30
|
+
// If only the center point is present, project start/end from named scalar properties.
|
|
31
|
+
// Full-points data (post-execute or post-fromDxf) skips this block entirely.
|
|
32
|
+
if (data && this.points.length < 2) {
|
|
33
|
+
const radius = data.radius ?? 1;
|
|
34
|
+
if (data.hasOwnProperty('startAngle')) {
|
|
35
|
+
this.points[1] = this.points[0].project(Utils.degrees2radians(data.startAngle), radius);
|
|
46
36
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// DXF Groupcode 50 - Start Angle
|
|
50
|
-
|
|
51
|
-
const angle = Property.loadValue([data.startAngle, data[50]], 0);
|
|
52
|
-
const projectionAngle = Utils.degrees2radians(angle);
|
|
53
|
-
this.points[1] = this.points[0].project(projectionAngle, this.radius);
|
|
37
|
+
if (data.hasOwnProperty('endAngle')) {
|
|
38
|
+
this.points[2] = this.points[0].project(Utils.degrees2radians(data.endAngle), radius);
|
|
54
39
|
}
|
|
40
|
+
}
|
|
55
41
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
42
|
+
// direction: ccw > 0, cw <= 0
|
|
43
|
+
this.properties.add(Property.Names.DIRECTION, {
|
|
44
|
+
type: Property.Type.NUMBER,
|
|
45
|
+
value: data?.direction ?? 1,
|
|
46
|
+
dxfCode: 73,
|
|
47
|
+
});
|
|
62
48
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
49
|
+
// radius: computed from points — stored in EntityProperties
|
|
50
|
+
this.properties.add(Property.Names.RADIUS, {
|
|
51
|
+
type: Property.Type.NUMBER,
|
|
52
|
+
get: (entity) => entity.points[1] ? entity.points[0].distance(entity.points[1]) : 1,
|
|
53
|
+
dxfCode: 40,
|
|
54
|
+
});
|
|
68
55
|
}
|
|
69
56
|
|
|
70
57
|
/**
|
|
@@ -79,6 +66,30 @@ export class Arc extends Entity {
|
|
|
79
66
|
return command;
|
|
80
67
|
}
|
|
81
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Normalise DXF group codes into the canonical points-based representation.
|
|
71
|
+
* Called by the DXF loader before construction.
|
|
72
|
+
* @param {Object} data
|
|
73
|
+
* @return {Object}
|
|
74
|
+
*/
|
|
75
|
+
static fromDxf(data) {
|
|
76
|
+
const center = data.points?.[0];
|
|
77
|
+
if (!center) return data;
|
|
78
|
+
// validate required group codes for points-based arc representation are present
|
|
79
|
+
if (data[40] === undefined || data[50] === undefined || data[51] === undefined) return data;
|
|
80
|
+
|
|
81
|
+
const radius = data[40];
|
|
82
|
+
return {
|
|
83
|
+
...data,
|
|
84
|
+
points: [
|
|
85
|
+
center,
|
|
86
|
+
center.project(Utils.degrees2radians(data[50] ?? 0), radius),
|
|
87
|
+
center.project(Utils.degrees2radians(data[51] ?? 0), radius),
|
|
88
|
+
],
|
|
89
|
+
direction: data[73] ?? 1,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
82
93
|
/**
|
|
83
94
|
* Execute method
|
|
84
95
|
* executes the workflow, requesting input required to create an entity
|
|
@@ -90,13 +101,22 @@ export class Arc extends Entity {
|
|
|
90
101
|
if (pt === undefined) return;
|
|
91
102
|
this.points.push(pt);
|
|
92
103
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
104
|
+
let pt1;
|
|
105
|
+
while (true) {
|
|
106
|
+
const op1 = new PromptOptions(Strings.Input.START, [Input.Type.POINT]);
|
|
107
|
+
pt1 = await DesignCore.Scene.inputManager.requestInput(op1);
|
|
108
|
+
if (pt1 === undefined) return;
|
|
109
|
+
if (pt1.isSame?.(pt)) {
|
|
110
|
+
DesignCore.Core.notify(`${this.type} - ${Strings.Error.INVALIDPOINT}`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
96
115
|
this.points.push(pt1);
|
|
97
116
|
|
|
98
117
|
let pt2;
|
|
99
118
|
while (true) {
|
|
119
|
+
DesignCore.Scene.inputManager.inputPoint = pt; // polar/ortho tracks from center on each attempt
|
|
100
120
|
const op2 = new PromptOptions(`${Strings.Input.END} ${Strings.Strings.OR} ${Strings.Input.ANGLE}`, [Input.Type.POINT, Input.Type.NUMBER]);
|
|
101
121
|
pt2 = await DesignCore.Scene.inputManager.requestInput(op2);
|
|
102
122
|
if (pt2 === undefined) return;
|
|
@@ -109,10 +129,18 @@ export class Arc extends Entity {
|
|
|
109
129
|
DesignCore.Core.notify(`${this.type} - ${Strings.Error.INVALIDPOINT}`);
|
|
110
130
|
continue;
|
|
111
131
|
}
|
|
112
|
-
|
|
132
|
+
|
|
133
|
+
const angle = this.points[0].angle(pt2);
|
|
134
|
+
const projectedEnd = this.points[0].project(angle, this.getProperty(Property.Names.RADIUS));
|
|
135
|
+
if (projectedEnd.isSame(this.points[1])) {
|
|
136
|
+
DesignCore.Core.notify(`${this.type} - ${Strings.Error.INVALIDPOINT}`);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
this.points.push(projectedEnd);
|
|
140
|
+
|
|
113
141
|
// Infer arc direction using cross product if we have 3 points
|
|
114
142
|
if (this.points.length === 3) {
|
|
115
|
-
this.
|
|
143
|
+
this.setProperty(Property.Names.DIRECTION, Arc.#inferDirection(this.points[0], this.points[1], this.points[2]));
|
|
116
144
|
// Check total angle > 1 degree
|
|
117
145
|
if (Math.abs(this.totalAngle) <= 1) {
|
|
118
146
|
this.points.pop(); // Remove invalid end point
|
|
@@ -134,7 +162,7 @@ export class Arc extends Entity {
|
|
|
134
162
|
const point = startPoint.rotate(basePoint, angle);
|
|
135
163
|
this.points.push(point);
|
|
136
164
|
// Set direction based on sign of angle
|
|
137
|
-
this.
|
|
165
|
+
this.setProperty(Property.Names.DIRECTION, angle >= 0 ? 1 : -1);
|
|
138
166
|
// Check total angle > 1 degree
|
|
139
167
|
if (Math.abs(this.totalAngle) <= 1) {
|
|
140
168
|
this.points.pop(); // Remove invalid end point
|
|
@@ -159,13 +187,16 @@ export class Arc extends Entity {
|
|
|
159
187
|
preview() {
|
|
160
188
|
if (this.points.length >= 1) {
|
|
161
189
|
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
162
|
-
|
|
163
|
-
DesignCore.Scene.tempEntities.create('Line', { points: points });
|
|
190
|
+
DesignCore.Scene.auxiliaryEntities.add(new RubberBand([this.points.at(0), mousePoint]));
|
|
164
191
|
}
|
|
165
192
|
|
|
166
193
|
if (this.points.length >= 2) {
|
|
167
194
|
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
168
|
-
const points = [...this.points, mousePoint];
|
|
195
|
+
// const points = [...this.points, mousePoint];
|
|
196
|
+
const center = this.points[0];
|
|
197
|
+
const endPoint = center.project(center.angle(mousePoint), this.getProperty(Property.Names.RADIUS));
|
|
198
|
+
if (endPoint.isSame(this.points[1])) return;
|
|
199
|
+
const points = [...this.points, endPoint];
|
|
169
200
|
|
|
170
201
|
// Infer direction for preview, so it matches what will be created
|
|
171
202
|
let direction = 1;
|
|
@@ -173,7 +204,7 @@ export class Arc extends Entity {
|
|
|
173
204
|
direction = Arc.#inferDirection(points[0], points[1], points[2]);
|
|
174
205
|
}
|
|
175
206
|
|
|
176
|
-
DesignCore.Scene.
|
|
207
|
+
DesignCore.Scene.previewEntities.create(this.type, { points: points, direction: direction });
|
|
177
208
|
}
|
|
178
209
|
}
|
|
179
210
|
|
|
@@ -228,7 +259,7 @@ export class Arc extends Entity {
|
|
|
228
259
|
let endAngle = this.endAngle();
|
|
229
260
|
|
|
230
261
|
|
|
231
|
-
if (this.
|
|
262
|
+
if (this.getProperty(Property.Names.DIRECTION) > 0) {
|
|
232
263
|
if (startAngle > endAngle || startAngle === endAngle) {
|
|
233
264
|
endAngle += (Math.PI * 2);
|
|
234
265
|
}
|
|
@@ -245,7 +276,7 @@ export class Arc extends Entity {
|
|
|
245
276
|
* @return {number} - arc radius
|
|
246
277
|
*/
|
|
247
278
|
getRadius() {
|
|
248
|
-
return this.
|
|
279
|
+
return this.getProperty(Property.Names.RADIUS);
|
|
249
280
|
}
|
|
250
281
|
|
|
251
282
|
/**
|
|
@@ -253,9 +284,12 @@ export class Arc extends Entity {
|
|
|
253
284
|
* @param {Object} ctx - context
|
|
254
285
|
* @param {number} scale
|
|
255
286
|
*/
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Draw the arc
|
|
289
|
+
* @param {Object} renderer
|
|
290
|
+
*/
|
|
291
|
+
draw(renderer) {
|
|
292
|
+
renderer.drawShape(this.toPolylinePoints());
|
|
259
293
|
}
|
|
260
294
|
|
|
261
295
|
/**
|
|
@@ -264,19 +298,19 @@ export class Arc extends Entity {
|
|
|
264
298
|
*/
|
|
265
299
|
dxf(file) {
|
|
266
300
|
file.writeGroupCode('0', 'ARC');
|
|
267
|
-
file.writeGroupCode('5', this.
|
|
301
|
+
file.writeGroupCode('5', this.getProperty(Property.Names.HANDLE), DXFFile.Version.R2000); // Handle
|
|
268
302
|
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
269
303
|
file.writeGroupCode('100', 'AcDbCircle', DXFFile.Version.R2000);
|
|
270
|
-
file.writeGroupCode('8', this.
|
|
271
|
-
file.writeGroupCode('6', this.
|
|
304
|
+
file.writeGroupCode('8', this.getProperty(Property.Names.LAYER)); // LAYERNAME
|
|
305
|
+
file.writeGroupCode('6', this.getProperty(Property.Names.LINETYPE)); // LINETYPE
|
|
272
306
|
file.writeGroupCode('10', this.points[0].x); // X
|
|
273
307
|
file.writeGroupCode('20', this.points[0].y); // Y
|
|
274
308
|
file.writeGroupCode('30', '0.0'); // Z
|
|
275
|
-
file.writeGroupCode('39', this.
|
|
276
|
-
file.writeGroupCode('40', this.
|
|
309
|
+
file.writeGroupCode('39', this.getProperty(Property.Names.LINEWIDTH)); // Line Width
|
|
310
|
+
file.writeGroupCode('40', this.getProperty(Property.Names.RADIUS)); // Radius
|
|
277
311
|
file.writeGroupCode('100', 'AcDbArc', DXFFile.Version.R2000);
|
|
278
|
-
file.writeGroupCode('50', Utils.radians2degrees(this.
|
|
279
|
-
file.writeGroupCode('51', Utils.radians2degrees(this.
|
|
312
|
+
file.writeGroupCode('50', Utils.radians2degrees(this.getProperty(Property.Names.DIRECTION) > 0 ? this.startAngle() : this.endAngle())); // Start Angle
|
|
313
|
+
file.writeGroupCode('51', Utils.radians2degrees(this.getProperty(Property.Names.DIRECTION) > 0 ? this.endAngle() : this.startAngle())); // End Angle
|
|
280
314
|
}
|
|
281
315
|
|
|
282
316
|
/**
|
|
@@ -289,101 +323,32 @@ export class Arc extends Entity {
|
|
|
289
323
|
|
|
290
324
|
// If the arc forms a complete circle
|
|
291
325
|
// Split into two separate polyline arcs
|
|
326
|
+
const radius = this.getProperty(Property.Names.RADIUS);
|
|
292
327
|
if (Math.abs(this.totalAngle) === 360) {
|
|
293
|
-
const startPoint = this.points[0].project(0,
|
|
328
|
+
const startPoint = this.points[0].project(0, radius);
|
|
294
329
|
startPoint.bulge = 1;
|
|
295
|
-
const endPoint = this.points[0].project(0, -
|
|
330
|
+
const endPoint = this.points[0].project(0, -radius);
|
|
296
331
|
endPoint.bulge = 1;
|
|
297
|
-
const closurePoint = this.points[0].project(0,
|
|
332
|
+
const closurePoint = this.points[0].project(0, radius);
|
|
298
333
|
return [startPoint, endPoint, closurePoint];
|
|
299
334
|
}
|
|
300
335
|
|
|
301
|
-
const startPoint = this.points[0].project(this.startAngle(),
|
|
336
|
+
const startPoint = this.points[0].project(this.startAngle(), radius);
|
|
302
337
|
const bulge = Math.tan(Utils.degrees2radians(-this.totalAngle % 360) / 4);
|
|
303
338
|
startPoint.bulge = bulge;
|
|
304
|
-
const endPoint = this.points[0].project(this.endAngle(),
|
|
339
|
+
const endPoint = this.points[0].project(this.endAngle(), radius);
|
|
305
340
|
return [startPoint, endPoint];
|
|
306
341
|
}
|
|
307
342
|
|
|
308
343
|
/**
|
|
309
344
|
* Set entity points from a polyline point representation
|
|
310
345
|
* @param {Array} points
|
|
346
|
+
* @return {Arc}
|
|
311
347
|
*/
|
|
312
348
|
fromPolylinePoints(points) {
|
|
313
349
|
const center = points[0].bulgeCentrePoint(points[1]);
|
|
314
|
-
|
|
315
|
-
this
|
|
316
|
-
this.radius = radius;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Trim the entity
|
|
321
|
-
* @param {Array} intersections
|
|
322
|
-
* @return {Array} - array of state changes
|
|
323
|
-
*/
|
|
324
|
-
trim(intersections) {
|
|
325
|
-
// array to hold state changes
|
|
326
|
-
const stateChanges = [];
|
|
327
|
-
|
|
328
|
-
if (intersections?.length === 0 || !intersections) {
|
|
329
|
-
return stateChanges;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// get the mouse position
|
|
333
|
-
const mousePosition = DesignCore.Mouse.pointOnScene();
|
|
334
|
-
// get the point on the arc closest to the mouse
|
|
335
|
-
const pointOnArc = mousePosition.closestPointOnArc(this.points[1], this.points[2], this.points[0], this.direction);
|
|
336
|
-
// remove any intersections that are at the end points of the arc
|
|
337
|
-
intersections = intersections.filter((p) => !p.isSame(this.points[1]) && !p.isSame(this.points[2]));
|
|
338
|
-
// sort intersection points by distance to start point
|
|
339
|
-
Utils.sortPointsOnArc(intersections, this.points[1], this.points[2], this.points[0], this.direction);
|
|
340
|
-
// Add arc points to the start and the end of the point array
|
|
341
|
-
const testPoints = [this.points[1], ...intersections, this.points[2]];
|
|
342
|
-
|
|
343
|
-
// Test if mouse position is between two intersection points
|
|
344
|
-
if (testPoints.length > 1) {
|
|
345
|
-
for (let i = 0; i < testPoints.length - 1; i++) {
|
|
346
|
-
const startPoint = testPoints[i];
|
|
347
|
-
const endPoint = testPoints[i + 1];
|
|
348
|
-
|
|
349
|
-
// check if the mouse is between startPoint and endPoint
|
|
350
|
-
if (pointOnArc.isOnArc(startPoint, endPoint, this.points[0], this.direction)) {
|
|
351
|
-
// Store new entity points
|
|
352
|
-
const newPoints = [];
|
|
353
|
-
|
|
354
|
-
for (const p of testPoints) {
|
|
355
|
-
const inOriginalArc = this.points.indexOf(p) !== -1;
|
|
356
|
-
const inIntersections = intersections.indexOf(p) !== -1;
|
|
357
|
-
|
|
358
|
-
// Keep points which:
|
|
359
|
-
// - The mouse is between are intersections
|
|
360
|
-
// - The mouse is not between and in this arc
|
|
361
|
-
const isBetween = p.isSame(startPoint) || p.isSame(endPoint);
|
|
362
|
-
if ((isBetween && inIntersections) || (!isBetween && inOriginalArc)) {
|
|
363
|
-
newPoints.push(p);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
if (newPoints.length % 2 === 0) {
|
|
368
|
-
// Add arcs for each point pair
|
|
369
|
-
for (let j = 0; j < newPoints.length; j += 2) {
|
|
370
|
-
const arc = Utils.cloneObject(this);
|
|
371
|
-
arc.points = [this.points[0], newPoints[j], newPoints[j + 1]];
|
|
372
|
-
const addState = new AddState(arc);
|
|
373
|
-
stateChanges.push(addState);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (stateChanges.length > 0) {
|
|
378
|
-
// Remove the existing arc
|
|
379
|
-
const removeState = new RemoveState(this);
|
|
380
|
-
stateChanges.push(removeState);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return stateChanges;
|
|
350
|
+
this.points = [center, new Point(points[0].x, points[0].y), new Point(points.at(-1).x, points.at(-1).y)];
|
|
351
|
+
return this;
|
|
387
352
|
}
|
|
388
353
|
|
|
389
354
|
/**
|
|
@@ -417,12 +382,14 @@ export class Arc extends Entity {
|
|
|
417
382
|
const angleFromCentreToInput = centre.angle(fromPoint); // angle from centre toward fromPoint
|
|
418
383
|
|
|
419
384
|
// Tangent: only possible when fromPoint is outside the arc radius
|
|
420
|
-
|
|
421
|
-
|
|
385
|
+
const radius = this.getProperty(Property.Names.RADIUS);
|
|
386
|
+
const direction = this.getProperty(Property.Names.DIRECTION);
|
|
387
|
+
if (distanceToCenter > radius) {
|
|
388
|
+
const tangentHalfAngle = Math.acos(radius / distanceToCenter); // half-angle between the two tangent directions
|
|
422
389
|
|
|
423
390
|
for (const sign of [1, -1]) {
|
|
424
|
-
const tangentPoint = centre.project(angleFromCentreToInput + sign * tangentHalfAngle,
|
|
425
|
-
if (tangentPoint.isOnArc(this.points[1], this.points[2], centre,
|
|
391
|
+
const tangentPoint = centre.project(angleFromCentreToInput + sign * tangentHalfAngle, radius);
|
|
392
|
+
if (tangentPoint.isOnArc(this.points[1], this.points[2], centre, direction)) {
|
|
426
393
|
snaps.push(new SnapPoint(tangentPoint, SnapPoint.Type.TANGENT));
|
|
427
394
|
}
|
|
428
395
|
}
|
|
@@ -430,8 +397,8 @@ export class Arc extends Entity {
|
|
|
430
397
|
|
|
431
398
|
// Perpendicular: point on the arc that lies on the line from fromPoint through the centre
|
|
432
399
|
if (distanceToCenter > 0) {
|
|
433
|
-
const perpendicularPoint = centre.project(angleFromCentreToInput,
|
|
434
|
-
if (perpendicularPoint.isOnArc(this.points[1], this.points[2], centre,
|
|
400
|
+
const perpendicularPoint = centre.project(angleFromCentreToInput, radius);
|
|
401
|
+
if (perpendicularPoint.isOnArc(this.points[1], this.points[2], centre, direction)) {
|
|
435
402
|
snaps.push(new SnapPoint(perpendicularPoint, SnapPoint.Type.PERPENDICULAR));
|
|
436
403
|
}
|
|
437
404
|
}
|
|
@@ -450,7 +417,7 @@ export class Arc extends Entity {
|
|
|
450
417
|
const endPoint = this.points[2];
|
|
451
418
|
const centerPoint = this.points[0];
|
|
452
419
|
|
|
453
|
-
const pnt = P.closestPointOnArc(startPoint, endPoint, centerPoint, this.
|
|
420
|
+
const pnt = P.closestPointOnArc(startPoint, endPoint, centerPoint, this.getProperty(Property.Names.DIRECTION));
|
|
454
421
|
|
|
455
422
|
if (pnt !== null) {
|
|
456
423
|
const distance = P.distance(pnt);
|
|
@@ -466,6 +433,6 @@ export class Arc extends Entity {
|
|
|
466
433
|
* @return {BoundingBox}
|
|
467
434
|
*/
|
|
468
435
|
boundingBox() {
|
|
469
|
-
return BoundingBox.arcBoundingBox(this.points[0], this.points[1], this.points[2], this.
|
|
436
|
+
return BoundingBox.arcBoundingBox(this.points[0], this.points[1], this.points[2], this.getProperty(Property.Names.DIRECTION));
|
|
470
437
|
}
|
|
471
438
|
}
|