@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/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 centre 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 centre = data.points?.[0];
|
|
77
|
+
if (!centre) 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
|
+
centre,
|
|
86
|
+
centre.project(Utils.degrees2radians(data[50] ?? 0), radius),
|
|
87
|
+
centre.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,29 +101,46 @@ 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 centre 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;
|
|
103
123
|
|
|
104
124
|
if (Input.getType(pt2) === Input.Type.POINT) {
|
|
105
|
-
// Must not be same as
|
|
106
|
-
const
|
|
125
|
+
// Must not be same as centre or start
|
|
126
|
+
const centre = this.points[0];
|
|
107
127
|
const start = this.points[1];
|
|
108
|
-
if (pt2.isSame?.(
|
|
128
|
+
if (pt2.isSame?.(centre) || pt2.isSame?.(start)) {
|
|
129
|
+
DesignCore.Core.notify(`${this.type} - ${Strings.Error.INVALIDPOINT}`);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
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])) {
|
|
109
136
|
DesignCore.Core.notify(`${this.type} - ${Strings.Error.INVALIDPOINT}`);
|
|
110
137
|
continue;
|
|
111
138
|
}
|
|
112
|
-
this.points.push(
|
|
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 centre = this.points[0];
|
|
197
|
+
const endPoint = centre.project(centre.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,28 +204,28 @@ 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
|
|
|
180
211
|
/**
|
|
181
212
|
* Infer arc direction from three points using cross product
|
|
182
|
-
* @param {Point}
|
|
213
|
+
* @param {Point} centre
|
|
183
214
|
* @param {Point} start
|
|
184
215
|
* @param {Point} end
|
|
185
216
|
* @return {number} 1 for ccw, -1 for cw
|
|
186
217
|
*/
|
|
187
|
-
static #inferDirection(
|
|
218
|
+
static #inferDirection(centre, start, end) {
|
|
188
219
|
// All points must be defined and distinct
|
|
189
|
-
if (!
|
|
220
|
+
if (!centre || !start || !end) {
|
|
190
221
|
return 1; // Default to counterclockwise
|
|
191
222
|
}
|
|
192
|
-
if (
|
|
223
|
+
if (centre.isSame?.(start) || centre.isSame?.(end) || start.isSame?.(end)) {
|
|
193
224
|
return 1;
|
|
194
225
|
}
|
|
195
226
|
|
|
196
|
-
const v1 = start.subtract(
|
|
197
|
-
const v2 = end.subtract(
|
|
227
|
+
const v1 = start.subtract(centre);
|
|
228
|
+
const v2 = end.subtract(centre);
|
|
198
229
|
const cross = v1.cross(v2);
|
|
199
230
|
const direction = cross > 0 ? 1 : -1;
|
|
200
231
|
return direction;
|
|
@@ -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
|
-
const
|
|
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;
|
|
349
|
+
const centre = points[0].bulgeCentrePoint(points[1]);
|
|
350
|
+
this.points = [centre, 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
|
}
|
|
@@ -448,9 +415,9 @@ export class Arc extends Entity {
|
|
|
448
415
|
closestPoint(P) {
|
|
449
416
|
const startPoint = this.points[1];
|
|
450
417
|
const endPoint = this.points[2];
|
|
451
|
-
const
|
|
418
|
+
const centrePoint = this.points[0];
|
|
452
419
|
|
|
453
|
-
const pnt = P.closestPointOnArc(startPoint, endPoint,
|
|
420
|
+
const pnt = P.closestPointOnArc(startPoint, endPoint, centrePoint, 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
|
}
|