@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/circle.js
CHANGED
|
@@ -5,12 +5,11 @@ import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
|
5
5
|
import { Logging } from '../lib/logging.js';
|
|
6
6
|
import { DXFFile } from '../lib/dxf/dxfFile.js';
|
|
7
7
|
import { BoundingBox } from '../lib/boundingBox.js';
|
|
8
|
-
import { Property } from '../properties/property.js';
|
|
9
|
-
import { Utils } from '../lib/utils.js';
|
|
10
|
-
|
|
11
8
|
import { DesignCore } from '../designCore.js';
|
|
12
|
-
|
|
13
|
-
import {
|
|
9
|
+
|
|
10
|
+
import { Property } from '../properties/property.js';
|
|
11
|
+
import { SnapPoint } from '../lib/auxiliary/snapPoint.js';
|
|
12
|
+
import { RubberBand } from '../lib/auxiliary/rubberBand.js';
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Circle Entity Class
|
|
@@ -26,19 +25,20 @@ export class Circle extends Entity {
|
|
|
26
25
|
constructor(data) {
|
|
27
26
|
super(data);
|
|
28
27
|
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
get:
|
|
33
|
-
set:
|
|
34
|
-
|
|
28
|
+
// radius: computed from points — stored in EntityProperties
|
|
29
|
+
this.properties.add(Property.Names.RADIUS, {
|
|
30
|
+
type: Property.Type.NUMBER,
|
|
31
|
+
get: (entity) => entity.points[1] ? entity.points[0].distance(entity.points[1]) : 0,
|
|
32
|
+
set: (entity, rad) => {
|
|
33
|
+
entity.points[1] = entity.points[0].project(0, rad);
|
|
34
|
+
},
|
|
35
|
+
dxfCode: 40,
|
|
35
36
|
});
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
38
|
+
// Named scalar radius (internal API / named prop) — projects points[1] from centre.
|
|
39
|
+
// Full-points data (post-execute or post-fromDxf) skips this.
|
|
40
|
+
if (data?.radius !== undefined && this.points.length < 2) {
|
|
41
|
+
this.setRadius(data.radius);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -54,6 +54,21 @@ export class Circle extends Entity {
|
|
|
54
54
|
return command;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Normalise DXF group codes into the canonical points-based representation.
|
|
59
|
+
* Called by the DXF loader before construction.
|
|
60
|
+
* @param {Object} data
|
|
61
|
+
* @return {Object}
|
|
62
|
+
*/
|
|
63
|
+
static fromDxf(data) {
|
|
64
|
+
const centre = data.points?.[0];
|
|
65
|
+
if (!centre || data[40] === undefined) return data;
|
|
66
|
+
return {
|
|
67
|
+
...data,
|
|
68
|
+
points: [centre, centre.project(0, data[40])],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
57
72
|
/**
|
|
58
73
|
* Execute method
|
|
59
74
|
* executes the workflow, requesting input required to create an entity
|
|
@@ -113,8 +128,8 @@ export class Circle extends Entity {
|
|
|
113
128
|
preview() {
|
|
114
129
|
if (this.points.length >= 1) {
|
|
115
130
|
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
116
|
-
|
|
117
|
-
DesignCore.Scene.
|
|
131
|
+
DesignCore.Scene.auxiliaryEntities.add(new RubberBand([this.points.at(0), mousePoint]));
|
|
132
|
+
DesignCore.Scene.previewEntities.create(this.type, { points: [this.points.at(0), mousePoint] });
|
|
118
133
|
}
|
|
119
134
|
}
|
|
120
135
|
|
|
@@ -139,9 +154,12 @@ export class Circle extends Entity {
|
|
|
139
154
|
* @param {Object} ctx - context
|
|
140
155
|
* @param {number} scale
|
|
141
156
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Draw the circle
|
|
159
|
+
* @param {Object} renderer
|
|
160
|
+
*/
|
|
161
|
+
draw(renderer) {
|
|
162
|
+
renderer.drawShape(this.toPolylinePoints());
|
|
145
163
|
}
|
|
146
164
|
|
|
147
165
|
/**
|
|
@@ -150,17 +168,17 @@ export class Circle extends Entity {
|
|
|
150
168
|
*/
|
|
151
169
|
dxf(file) {
|
|
152
170
|
file.writeGroupCode('0', 'CIRCLE');
|
|
153
|
-
file.writeGroupCode('5', this.
|
|
171
|
+
file.writeGroupCode('5', this.getProperty(Property.Names.HANDLE), DXFFile.Version.R2000); // Handle
|
|
154
172
|
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
155
173
|
file.writeGroupCode('100', 'AcDbCircle', DXFFile.Version.R2000);
|
|
156
|
-
file.writeGroupCode('8', this.
|
|
157
|
-
file.writeGroupCode('6', this.
|
|
174
|
+
file.writeGroupCode('8', this.getProperty(Property.Names.LAYER));
|
|
175
|
+
file.writeGroupCode('6', this.getProperty(Property.Names.LINETYPE));
|
|
158
176
|
this.writeDxfColour(file);
|
|
159
177
|
file.writeGroupCode('10', this.points[0].x);
|
|
160
178
|
file.writeGroupCode('20', this.points[0].y);
|
|
161
179
|
file.writeGroupCode('30', '0.0');
|
|
162
|
-
file.writeGroupCode('39', this.
|
|
163
|
-
file.writeGroupCode('40', this.
|
|
180
|
+
file.writeGroupCode('39', this.getProperty(Property.Names.LINEWIDTH));
|
|
181
|
+
file.writeGroupCode('40', this.getProperty(Property.Names.RADIUS));
|
|
164
182
|
}
|
|
165
183
|
|
|
166
184
|
/**
|
|
@@ -168,76 +186,34 @@ export class Circle extends Entity {
|
|
|
168
186
|
* @return {Array}
|
|
169
187
|
*/
|
|
170
188
|
toPolylinePoints() {
|
|
171
|
-
const
|
|
189
|
+
const radius = this.getProperty(Property.Names.RADIUS);
|
|
190
|
+
const startPoint = this.points[0].project(0, radius);
|
|
172
191
|
startPoint.bulge = 1;
|
|
173
|
-
const endPoint = this.points[0].project(0, -
|
|
192
|
+
const endPoint = this.points[0].project(0, -radius);
|
|
174
193
|
endPoint.bulge = 1;
|
|
175
|
-
const closurePoint = this.points[0].project(0,
|
|
194
|
+
const closurePoint = this.points[0].project(0, radius);
|
|
176
195
|
return [startPoint, endPoint, closurePoint];
|
|
177
196
|
}
|
|
178
197
|
|
|
179
198
|
/**
|
|
180
|
-
* Set entity points from a polyline point representation
|
|
199
|
+
* Set entity points from a polyline point representation.
|
|
200
|
+
* If the points describe a full circle (start === end), mutates this Circle
|
|
201
|
+
* in place and returns it. Otherwise creates and returns an Arc, since a
|
|
202
|
+
* Circle cannot represent an open arc.
|
|
181
203
|
* @param {Array} points
|
|
204
|
+
* @return {Circle|Arc}
|
|
182
205
|
*/
|
|
183
206
|
fromPolylinePoints(points) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Trim the entity
|
|
191
|
-
* @param {Array} intersections
|
|
192
|
-
* @return {Array} - array of state changes
|
|
193
|
-
*/
|
|
194
|
-
trim(intersections) {
|
|
195
|
-
// array to hold state changes
|
|
196
|
-
const stateChanges = [];
|
|
197
|
-
|
|
198
|
-
if (intersections?.length === 0 || !intersections) {
|
|
199
|
-
return stateChanges;
|
|
207
|
+
if (points.length >= 3 && points[0].isSame(points.at(-1))) {
|
|
208
|
+
const centre = points[0].bulgeCentrePoint(points[1]);
|
|
209
|
+
const radius = centre.distance(points[0]);
|
|
210
|
+
this.points = [centre, centre.project(0, radius)];
|
|
211
|
+
return this;
|
|
200
212
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const mousePosition = DesignCore.Mouse.pointOnScene();
|
|
206
|
-
// get the point on the arc closest to the mouse
|
|
207
|
-
const pointOnCircle = mousePosition.closestPointOnArc(this.points[1], this.points[1], this.points[0]);
|
|
208
|
-
// sort intersection points
|
|
209
|
-
Utils.sortPointsOnArc(intersections, this.points[0], this.points[0], this.points[0], direction);
|
|
210
|
-
// Repeat the first point to close the circle
|
|
211
|
-
const testPoints = [...intersections, intersections.at(0)]; // Closing the circle
|
|
212
|
-
|
|
213
|
-
// Test if mouse position is between two intersection points
|
|
214
|
-
if (testPoints.length > 1) {
|
|
215
|
-
for (let i = 0; i < testPoints.length - 1; i++) {
|
|
216
|
-
const startPoint = testPoints[i];
|
|
217
|
-
const endPoint = testPoints[i + 1];
|
|
218
|
-
|
|
219
|
-
// check if the mouse is between startPoint and endPoint
|
|
220
|
-
if (pointOnCircle.isOnArc(startPoint, endPoint, this.points[0], direction)) {
|
|
221
|
-
// create a new arc entity
|
|
222
|
-
const arc = DesignCore.CommandManager.createNew('Arc', this);
|
|
223
|
-
arc.handle = undefined;
|
|
224
|
-
// flip direction
|
|
225
|
-
arc.direction = direction * -1;
|
|
226
|
-
arc.points = [this.points[0], startPoint, endPoint];
|
|
227
|
-
const addState = new AddState(arc);
|
|
228
|
-
stateChanges.push(addState);
|
|
229
|
-
|
|
230
|
-
// Remove the existing arc
|
|
231
|
-
if (stateChanges.length > 0) {
|
|
232
|
-
const removeState = new RemoveState(this);
|
|
233
|
-
stateChanges.push(removeState);
|
|
234
|
-
return stateChanges;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return stateChanges;
|
|
213
|
+
const arc = DesignCore.CommandManager.createNew('Arc', this);
|
|
214
|
+
arc.setProperty('handle', undefined);
|
|
215
|
+
arc.fromPolylinePoints(points);
|
|
216
|
+
return arc;
|
|
241
217
|
}
|
|
242
218
|
|
|
243
219
|
/**
|
|
@@ -251,13 +227,14 @@ export class Circle extends Entity {
|
|
|
251
227
|
|
|
252
228
|
const centre = this.points[0]; // circle centre point
|
|
253
229
|
|
|
230
|
+
const radius = this.getProperty(Property.Names.RADIUS);
|
|
254
231
|
snaps.push(new SnapPoint(centre, SnapPoint.Type.CENTRE));
|
|
255
232
|
|
|
256
233
|
snaps.push(
|
|
257
|
-
new SnapPoint(new Point(centre.x +
|
|
258
|
-
new SnapPoint(new Point(centre.x, centre.y +
|
|
259
|
-
new SnapPoint(new Point(centre.x -
|
|
260
|
-
new SnapPoint(new Point(centre.x, centre.y -
|
|
234
|
+
new SnapPoint(new Point(centre.x + radius, centre.y), SnapPoint.Type.QUADRANT), // 0°
|
|
235
|
+
new SnapPoint(new Point(centre.x, centre.y + radius), SnapPoint.Type.QUADRANT), // 90°
|
|
236
|
+
new SnapPoint(new Point(centre.x - radius, centre.y), SnapPoint.Type.QUADRANT), // 180°
|
|
237
|
+
new SnapPoint(new Point(centre.x, centre.y - radius), SnapPoint.Type.QUADRANT), // 270°
|
|
261
238
|
);
|
|
262
239
|
|
|
263
240
|
if (mousePoint) {
|
|
@@ -274,16 +251,16 @@ export class Circle extends Entity {
|
|
|
274
251
|
const angleFromCentreToInput = centre.angle(fromPoint); // angle from centre toward fromPoint
|
|
275
252
|
|
|
276
253
|
// Tangent: only possible when fromPoint is outside the circle radius
|
|
277
|
-
if (distanceToCenter >
|
|
278
|
-
const tangentHalfAngle = Math.acos(
|
|
254
|
+
if (distanceToCenter > radius) {
|
|
255
|
+
const tangentHalfAngle = Math.acos(radius / distanceToCenter); // half-angle between the two tangent directions
|
|
279
256
|
|
|
280
|
-
snaps.push(new SnapPoint(centre.project(angleFromCentreToInput + tangentHalfAngle,
|
|
281
|
-
snaps.push(new SnapPoint(centre.project(angleFromCentreToInput - tangentHalfAngle,
|
|
257
|
+
snaps.push(new SnapPoint(centre.project(angleFromCentreToInput + tangentHalfAngle, radius), SnapPoint.Type.TANGENT));
|
|
258
|
+
snaps.push(new SnapPoint(centre.project(angleFromCentreToInput - tangentHalfAngle, radius), SnapPoint.Type.TANGENT));
|
|
282
259
|
}
|
|
283
260
|
|
|
284
261
|
// Perpendicular: point on the circle that lies on the line from fromPoint through the centre
|
|
285
262
|
if (distanceToCenter > 0) {
|
|
286
|
-
snaps.push(new SnapPoint(centre.project(angleFromCentreToInput,
|
|
263
|
+
snaps.push(new SnapPoint(centre.project(angleFromCentreToInput, radius), SnapPoint.Type.PERPENDICULAR));
|
|
287
264
|
}
|
|
288
265
|
}
|
|
289
266
|
|
|
@@ -308,10 +285,11 @@ export class Circle extends Entity {
|
|
|
308
285
|
* @return {BoundingBox}
|
|
309
286
|
*/
|
|
310
287
|
boundingBox() {
|
|
311
|
-
const
|
|
312
|
-
const
|
|
313
|
-
const
|
|
314
|
-
const
|
|
288
|
+
const radius = this.getProperty(Property.Names.RADIUS);
|
|
289
|
+
const xmin = this.points[0].x - radius;
|
|
290
|
+
const xmax = this.points[0].x + radius;
|
|
291
|
+
const ymin = this.points[0].y - radius;
|
|
292
|
+
const ymax = this.points[0].y + radius;
|
|
315
293
|
|
|
316
294
|
const topLeft = new Point(xmin, ymax);
|
|
317
295
|
const bottomRight = new Point(xmax, ymin);
|
package/core/entities/entity.js
CHANGED
|
@@ -2,8 +2,9 @@ import { Colours } from '../lib/colours.js';
|
|
|
2
2
|
import { EntityColour } from '../lib/colour.js';
|
|
3
3
|
import { Intersection } from '../lib/intersect.js';
|
|
4
4
|
import { Point } from './point.js';
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import { Property } from '../properties/property.js';
|
|
7
|
+
import { EntityProperties } from '../properties/entityProperties.js';
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
import { DesignCore } from '../designCore.js';
|
|
@@ -23,80 +24,130 @@ export class Entity {
|
|
|
23
24
|
writable: true,
|
|
24
25
|
});
|
|
25
26
|
|
|
26
|
-
Object.defineProperty(this, '
|
|
27
|
-
value:
|
|
27
|
+
Object.defineProperty(this, 'entityColour', {
|
|
28
|
+
value: new EntityColour(),
|
|
28
29
|
writable: true,
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
// DXF Groupcode 62 (normalised to colourACI by Entity.fromDxf) - ACI colour index
|
|
33
|
+
// DXF Groupcode 420 (normalised to trueColour by Entity.fromDxf) - 24-bit true colour
|
|
34
|
+
if (data?.colourACI !== undefined) {
|
|
35
|
+
this.entityColour.setColourFromACI(data.colourACI);
|
|
36
|
+
}
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
if (data?.trueColour !== undefined) {
|
|
39
|
+
const trueColour = Colours.trueColourToRGB(data.trueColour);
|
|
40
|
+
if (trueColour) this.entityColour.setColour(trueColour);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Typed property store — non-enumerable so it doesn't appear in serialisation
|
|
44
|
+
Object.defineProperty(this, 'properties', {
|
|
45
|
+
value: new EntityProperties(),
|
|
38
46
|
writable: true,
|
|
39
47
|
});
|
|
40
48
|
|
|
41
|
-
this.lineWidth = 2;
|
|
42
|
-
this.lineType = 'ByLayer';
|
|
43
|
-
this.layer = '0';
|
|
44
|
-
|
|
45
49
|
// DXF Groupcode 5 - Handle
|
|
46
|
-
|
|
50
|
+
this.properties.add(Property.Names.HANDLE, {
|
|
51
|
+
type: Property.Type.STRING,
|
|
47
52
|
value: Property.loadValue([data?.handle, data?.[5]]),
|
|
48
|
-
|
|
53
|
+
visible: false,
|
|
54
|
+
dxfCode: 5,
|
|
55
|
+
});
|
|
56
|
+
// DXF Groupcode 8 - Layer name
|
|
57
|
+
this.properties.add(Property.Names.LAYER, {
|
|
58
|
+
type: Property.Type.LIST,
|
|
59
|
+
value: Property.loadValue([data?.layer, data?.[8]], '0'),
|
|
60
|
+
dxfCode: 8,
|
|
61
|
+
options: () => DesignCore.LayerManager.getItems().map((l) => ({ display: l.name, value: l.name })),
|
|
62
|
+
});
|
|
63
|
+
// DXF Groupcode 6 - Line type
|
|
64
|
+
this.properties.add(Property.Names.LINETYPE, {
|
|
65
|
+
type: Property.Type.LIST,
|
|
66
|
+
value: Property.loadValue([data?.lineType, data?.[6]], 'ByLayer'),
|
|
67
|
+
dxfCode: 6,
|
|
68
|
+
options: () => DesignCore.LTypeManager.getItems().map((s) => ({ display: s.name, value: s.name })),
|
|
49
69
|
});
|
|
50
|
-
// DXF Groupcode 6 - lineType
|
|
51
|
-
this.lineType = Property.loadValue([data?.lineType, data?.[6]], 'ByLayer');
|
|
52
70
|
// DXF Groupcode 39 - Thickness (lineWidth)
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.colour = data.colour;
|
|
70
|
-
}
|
|
71
|
-
} else if (data.hasOwnProperty('62')) {
|
|
72
|
-
this.entityColour.setColourFromACI(Math.abs(data[62]));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (data.hasOwnProperty('trueColour') || data.hasOwnProperty('420')) {
|
|
77
|
-
// DXF Groupcode 420 - true color
|
|
78
|
-
// A 24-bit color value that should be dealt with in terms of bytes with values
|
|
79
|
-
// of 0 to 255. The lowest byte is the blue value, the middle byte is the
|
|
80
|
-
// green value, and the third byte is the red value. The top byte is always
|
|
81
|
-
// 0. The group code cannot be used by custom entities for their own data
|
|
82
|
-
// because the group code is reserved for AcDbEntity, class-level color data
|
|
83
|
-
// and AcDbEntity, class-level transparency data
|
|
84
|
-
|
|
85
|
-
const trueColour = Colours.trueColourToRGB(data.trueColour || data[420]);
|
|
86
|
-
if (trueColour) {
|
|
87
|
-
this.colour = trueColour;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
71
|
+
this.properties.add(Property.Names.LINEWIDTH, {
|
|
72
|
+
type: Property.Type.NUMBER,
|
|
73
|
+
value: Property.loadValue([data?.lineWidth, data?.[39]], 1),
|
|
74
|
+
dxfCode: 39,
|
|
75
|
+
});
|
|
76
|
+
// DXF Groupcode 62/420 - colour (computed, backed by entityColour)
|
|
77
|
+
this.properties.add(Property.Names.COLOUR, {
|
|
78
|
+
type: Property.Type.COLOUR,
|
|
79
|
+
get: (entity) => entity.entityColour.getColour(),
|
|
80
|
+
set: (entity, value) => entity.entityColour.setColour(value),
|
|
81
|
+
dxfCode: 62,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Apply colour from data if RGB was passed directly
|
|
85
|
+
if (data?.colour && Colours.isRGB(data.colour)) {
|
|
86
|
+
this.entityColour.setColour(data.colour);
|
|
90
87
|
}
|
|
88
|
+
|
|
89
|
+
// points — stored value in EntityProperties
|
|
90
|
+
this.properties.add(Property.Names.POINTS, {
|
|
91
|
+
visible: false,
|
|
92
|
+
value: data?.points ?? [],
|
|
93
|
+
});
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Get the entity's geometry points.
|
|
98
|
+
* @return {Array<Point>}
|
|
99
|
+
*/
|
|
100
|
+
get points() {
|
|
101
|
+
return this.properties.get(Property.Names.POINTS, this);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Set the entity's geometry points.
|
|
106
|
+
* @param {Array<Point>} value
|
|
107
|
+
*/
|
|
108
|
+
set points(value) {
|
|
109
|
+
this.properties.set(Property.Names.POINTS, value, this);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Normalise entity-level DXF group codes before construction.
|
|
114
|
+
* Subclasses override this for geometric transformation; they receive data
|
|
115
|
+
* that has already passed through this method via CommandManager.
|
|
116
|
+
* @param {Object} data - raw DXF group code object
|
|
117
|
+
* @return {Object} normalised data
|
|
118
|
+
*
|
|
119
|
+
* Handles:
|
|
120
|
+
* - Group code 62: ACI colour index → colourACI (absolute value)
|
|
121
|
+
* - Group code 420: 24-bit true colour integer → trueColour
|
|
122
|
+
*/
|
|
123
|
+
static fromDxf(data) {
|
|
124
|
+
const normalised = { ...data };
|
|
125
|
+
// DXF group code 62 - Color Number (ACI)
|
|
126
|
+
if (data[62] !== undefined) {
|
|
127
|
+
normalised.colourACI = Math.abs(data[62]);
|
|
128
|
+
}
|
|
129
|
+
// DXF group code 420 - True Color (24-bit integer)
|
|
130
|
+
if (data[420] !== undefined) {
|
|
131
|
+
normalised.trueColour = data[420];
|
|
132
|
+
}
|
|
133
|
+
return normalised;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get a property value by name.
|
|
138
|
+
* @param {string} name
|
|
139
|
+
* @return {any}
|
|
140
|
+
*/
|
|
141
|
+
getProperty(name) {
|
|
142
|
+
return this.properties.get(name, this);
|
|
143
|
+
}
|
|
93
144
|
|
|
94
145
|
/**
|
|
95
146
|
* get rgb colour
|
|
96
147
|
* @return {number} rgb colour object
|
|
97
148
|
*/
|
|
98
149
|
getColour() {
|
|
99
|
-
return this.entityColour.getColour();
|
|
150
|
+
return this.entityColour.getColour();
|
|
100
151
|
}
|
|
101
152
|
|
|
102
153
|
/**
|
|
@@ -107,30 +158,22 @@ export class Entity {
|
|
|
107
158
|
let rgb = this.getColour();
|
|
108
159
|
|
|
109
160
|
if (this.entityColour.byLayer) {
|
|
110
|
-
const layer = DesignCore.LayerManager.getItemByName(this.
|
|
161
|
+
const layer = DesignCore.LayerManager.getItemByName(this.getProperty(Property.Names.LAYER));
|
|
111
162
|
rgb = layer?.colour;
|
|
112
163
|
}
|
|
113
164
|
|
|
114
165
|
return rgb;
|
|
115
166
|
}
|
|
116
167
|
|
|
117
|
-
/**
|
|
118
|
-
* Set the entity colour
|
|
119
|
-
* @param {Object} rgb
|
|
120
|
-
*/
|
|
121
|
-
setColour(rgb) {
|
|
122
|
-
this.entityColour.setColour(rgb);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
168
|
/**
|
|
126
169
|
* Get the line type
|
|
127
170
|
* @return {LType}
|
|
128
171
|
*/
|
|
129
172
|
getLineType() {
|
|
130
|
-
let lineTypeName = this.
|
|
173
|
+
let lineTypeName = this.getProperty(Property.Names.LINETYPE) ?? 'ByLayer';
|
|
131
174
|
|
|
132
175
|
if (lineTypeName.toUpperCase() === 'BYLAYER') {
|
|
133
|
-
const layer = DesignCore.LayerManager.getItemByName(this.
|
|
176
|
+
const layer = DesignCore.LayerManager.getItemByName(this.getProperty(Property.Names.LAYER));
|
|
134
177
|
lineTypeName = layer?.lineType;
|
|
135
178
|
}
|
|
136
179
|
|
|
@@ -148,7 +191,7 @@ export class Entity {
|
|
|
148
191
|
file.writeGroupCode('62', this.entityColour.aci);
|
|
149
192
|
}
|
|
150
193
|
if (this.entityColour.isTrueColour) {
|
|
151
|
-
file.writeGroupCode('420', Colours.rgbToTrueColour(this.
|
|
194
|
+
file.writeGroupCode('420', Colours.rgbToTrueColour(this.getColour()));
|
|
152
195
|
}
|
|
153
196
|
}
|
|
154
197
|
|
|
@@ -158,7 +201,7 @@ export class Entity {
|
|
|
158
201
|
* @return {boolean} true if within
|
|
159
202
|
*/
|
|
160
203
|
within(selection) {
|
|
161
|
-
const layer = DesignCore.LayerManager.getItemByName(this.
|
|
204
|
+
const layer = DesignCore.LayerManager.getItemByName(this.getProperty(Property.Names.LAYER));
|
|
162
205
|
|
|
163
206
|
if (!layer?.isSelectable) {
|
|
164
207
|
return;
|
|
@@ -182,7 +225,7 @@ export class Entity {
|
|
|
182
225
|
* @return {boolean} true if touched
|
|
183
226
|
*/
|
|
184
227
|
touched(selection) {
|
|
185
|
-
const layer = DesignCore.LayerManager.getItemByName(this.
|
|
228
|
+
const layer = DesignCore.LayerManager.getItemByName(this.getProperty(Property.Names.LAYER));
|
|
186
229
|
|
|
187
230
|
if (!layer?.isSelectable) {
|
|
188
231
|
return;
|
|
@@ -205,36 +248,14 @@ export class Entity {
|
|
|
205
248
|
return false;
|
|
206
249
|
}
|
|
207
250
|
|
|
208
|
-
/**
|
|
209
|
-
* Extend the entity
|
|
210
|
-
* @param {Array} points
|
|
211
|
-
* @return {Array} - array of state changes
|
|
212
|
-
*/
|
|
213
|
-
extend(points) {
|
|
214
|
-
// extend function to be overridden by implementation
|
|
215
|
-
DesignCore.Core.notify(`${this.type} - ${Strings.Message.NOEXTEND}`);
|
|
216
|
-
return [];
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Trim the entity
|
|
221
|
-
* @param {Array} points
|
|
222
|
-
* @return {Array} - array of state changes
|
|
223
|
-
*/
|
|
224
|
-
trim(points) {
|
|
225
|
-
// trim function to be overridden by implementation
|
|
226
|
-
DesignCore.Core.notify(`${this.type} - ${Strings.Message.NOTRIM}`);
|
|
227
|
-
return [];
|
|
228
|
-
}
|
|
229
|
-
|
|
230
251
|
/**
|
|
231
252
|
* Set a property if it exists
|
|
232
253
|
* @param {string} property
|
|
233
254
|
* @param {any} value
|
|
234
255
|
*/
|
|
235
256
|
setProperty(property, value) {
|
|
236
|
-
if (this.
|
|
237
|
-
this
|
|
257
|
+
if (this.properties.has(property)) {
|
|
258
|
+
this.properties.set(property, value, this);
|
|
238
259
|
}
|
|
239
260
|
}
|
|
240
261
|
}
|