@design-core/core 0.0.5 → 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 +33 -284
- 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 +36 -13
- 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 +129 -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 +296 -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
package/core/entities/insert.js
CHANGED
|
@@ -5,11 +5,11 @@ import { Block } from '../tables/block.js';
|
|
|
5
5
|
import { BoundingBox } from '../lib/boundingBox.js';
|
|
6
6
|
import { Point } from './point.js';
|
|
7
7
|
import { Utils } from '../lib/utils.js';
|
|
8
|
-
import { Property } from '../properties/property.js';
|
|
9
8
|
import { Logging } from '../lib/logging.js';
|
|
9
|
+
import { Property } from '../properties/property.js';
|
|
10
10
|
|
|
11
11
|
import { DesignCore } from '../designCore.js';
|
|
12
|
-
import { SnapPoint } from '../lib/
|
|
12
|
+
import { SnapPoint } from '../lib/auxiliary/snapPoint.js';
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -34,59 +34,29 @@ export class Insert extends Entity {
|
|
|
34
34
|
writable: true,
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
get:
|
|
41
|
-
set:
|
|
42
|
-
enumerable: true,
|
|
37
|
+
this.properties.add(Property.Names.ROTATION, {
|
|
38
|
+
type: Property.Type.NUMBER,
|
|
39
|
+
dxfCode: 50,
|
|
40
|
+
get: (entity) => entity.getRotation(),
|
|
41
|
+
set: (entity, value) => entity.setRotation(value),
|
|
43
42
|
});
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
this.properties.add(Property.Names.BLOCKNAME, {
|
|
45
|
+
type: Property.Type.LABEL,
|
|
46
|
+
readOnly: true,
|
|
47
|
+
get: (entity) => entity.block?.name ?? '',
|
|
48
|
+
});
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
if (data) {
|
|
51
|
+
// DXF Groupcode 2 - Block name
|
|
52
|
+
if (data.blockName !== undefined) {
|
|
53
|
+
const block = DesignCore.Scene.blockManager.getItemByName(data.blockName);
|
|
51
54
|
this.block = block;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
Logging.instance.warn(`${this.type} - ${err}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (data.hasOwnProperty('42')) {
|
|
61
|
-
// DXF Groupcode 42 - Y Scale Factor (optional, default = 1)
|
|
62
|
-
const err = 'Groupcode 42 not implemented';
|
|
63
|
-
Logging.instance.warn(`${this.type} - ${err}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (data.hasOwnProperty('43')) {
|
|
67
|
-
// DXF Groupcode 43 - Z Scale Factor (optional, default = 1)
|
|
68
|
-
const err = 'Groupcode 43 not implemented';
|
|
69
|
-
Logging.instance.warn(`${this.type} - ${err}`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (data.hasOwnProperty('44')) {
|
|
73
|
-
// DXF Groupcode 44 - Column Spacing (optional, default = 0)
|
|
74
|
-
const err = 'Groupcode 44 not implemented';
|
|
75
|
-
Logging.instance.warn(`${this.type} - ${err}`);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (data.hasOwnProperty('45')) {
|
|
79
|
-
// DXF Groupcode 45 - Row Spacing (optional, default = 0)
|
|
80
|
-
const err = 'Groupcode 45 not implemented';
|
|
81
|
-
Logging.instance.warn(`${this.type} - ${err}`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (data.hasOwnProperty('rotation') || data.hasOwnProperty('50')) {
|
|
85
|
-
// DXF Groupcode 50 - Text Rotation, angle in degrees
|
|
86
|
-
// if we get rotation data store this as a point[1] at an angle from point[0]
|
|
87
|
-
// this allows all the entities to be rotated by rotating the points i.e. not all entities have a rotation property
|
|
88
|
-
|
|
89
|
-
this.setRotation(Property.loadValue([data.rotation, data[50]], 0));
|
|
57
|
+
// Named scalar rotation (internal API); DXF code 50 is handled by fromDxf
|
|
58
|
+
if (data.rotation !== undefined) {
|
|
59
|
+
this.setRotation(data.rotation);
|
|
90
60
|
} else {
|
|
91
61
|
// create points[1] used to determine the rotation
|
|
92
62
|
if (this.points[0] === undefined) {
|
|
@@ -95,18 +65,6 @@ export class Insert extends Entity {
|
|
|
95
65
|
|
|
96
66
|
this.points[1] = this.points[0].add(new Point(10, 0));
|
|
97
67
|
}
|
|
98
|
-
|
|
99
|
-
if (data.hasOwnProperty('70')) {
|
|
100
|
-
// DXF Groupcode 70 - Column Count (optional, default = 1)
|
|
101
|
-
const err = 'Groupcode 70 not implemented';
|
|
102
|
-
Logging.instance.warn(`${this.type} - ${err}`);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (data.hasOwnProperty('71')) {
|
|
106
|
-
// DXF Groupcode 71 - Row Count(optional, default = 1)
|
|
107
|
-
const err = 'Groupcode 71 not implemented';
|
|
108
|
-
Logging.instance.warn(`${this.type} - ${err}`);
|
|
109
|
-
}
|
|
110
68
|
}
|
|
111
69
|
}
|
|
112
70
|
|
|
@@ -122,6 +80,40 @@ export class Insert extends Entity {
|
|
|
122
80
|
return command;
|
|
123
81
|
}
|
|
124
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Normalise raw DXF data before construction
|
|
85
|
+
* @param {Object} data - raw DXF group code object
|
|
86
|
+
* @return {Object} normalised data with blockName and rotation encoded as points[1]
|
|
87
|
+
*
|
|
88
|
+
* Handles:
|
|
89
|
+
* - Group code 2: block name
|
|
90
|
+
* - Group code 50: rotation angle (degrees) encoded into points[1]
|
|
91
|
+
* - Group codes 41–45, 70, 71: unimplemented — logged as warnings
|
|
92
|
+
*/
|
|
93
|
+
static fromDxf(data) {
|
|
94
|
+
const normalised = { ...data };
|
|
95
|
+
|
|
96
|
+
// DXF group code 2 - Block name
|
|
97
|
+
if (data[2] !== undefined) {
|
|
98
|
+
normalised.blockName = data[2];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// DXF group code 50 - rotation angle in degrees; encode into points
|
|
102
|
+
if (data[50] !== undefined) {
|
|
103
|
+
normalised.rotation = data[50];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Unimplemented group codes
|
|
107
|
+
const unimplemented = { 41: 'X Scale Factor', 42: 'Y Scale Factor', 43: 'Z Scale Factor', 44: 'Column Spacing', 45: 'Row Spacing', 70: 'Column Count', 71: 'Row Count' };
|
|
108
|
+
for (const [code, label] of Object.entries(unimplemented)) {
|
|
109
|
+
if (data[code] !== undefined) {
|
|
110
|
+
Logging.instance.warn(`Insert - Groupcode ${code} (${label}) not implemented`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return normalised;
|
|
115
|
+
}
|
|
116
|
+
|
|
125
117
|
/**
|
|
126
118
|
* Execute method
|
|
127
119
|
* executes the workflow, requesting input required to create an entity
|
|
@@ -144,37 +136,30 @@ export class Insert extends Entity {
|
|
|
144
136
|
*/
|
|
145
137
|
dxf(file) {
|
|
146
138
|
file.writeGroupCode('0', 'INSERT');
|
|
147
|
-
file.writeGroupCode('5', this.
|
|
139
|
+
file.writeGroupCode('5', this.getProperty(Property.Names.HANDLE), DXFFile.Version.R2000); // Handle
|
|
148
140
|
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
149
|
-
file.writeGroupCode('8', this.
|
|
141
|
+
file.writeGroupCode('8', this.getProperty(Property.Names.LAYER));
|
|
150
142
|
this.writeDxfColour(file);
|
|
151
143
|
file.writeGroupCode('100', 'AcDbBlockReference', DXFFile.Version.R2000);
|
|
152
144
|
file.writeGroupCode('2', this.block.name);
|
|
153
145
|
file.writeGroupCode('10', this.points[0].x);
|
|
154
146
|
file.writeGroupCode('20', this.points[0].y);
|
|
155
147
|
file.writeGroupCode('30', '0.0');
|
|
156
|
-
if (this.
|
|
157
|
-
file.writeGroupCode('50', this.
|
|
148
|
+
if (this.getProperty(Property.Names.ROTATION)) {
|
|
149
|
+
file.writeGroupCode('50', this.getProperty(Property.Names.ROTATION));
|
|
158
150
|
}
|
|
159
151
|
}
|
|
160
152
|
|
|
161
153
|
/**
|
|
162
154
|
* Draw the entity
|
|
163
|
-
* @param {Object}
|
|
164
|
-
* @
|
|
155
|
+
* @param {Object} renderer
|
|
156
|
+
* @return {Array} block items for the canvas to render recursively
|
|
165
157
|
*/
|
|
166
|
-
draw(
|
|
158
|
+
draw(renderer) {
|
|
167
159
|
// blocks are associated with an insert point.
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
ctx.save();
|
|
172
|
-
ctx.translate(this.points[0].x, this.points[0].y);
|
|
173
|
-
const rotation = Utils.degrees2radians(this.rotation);
|
|
174
|
-
ctx.rotate(rotation);
|
|
175
|
-
// pass *this* to the block to allow colour ByBlock
|
|
176
|
-
this.block.draw(ctx, scale, this);
|
|
177
|
-
ctx.restore();
|
|
160
|
+
// Apply the insert location and rotation so block items draw correctly.
|
|
161
|
+
renderer.applyTransform({ x: this.points[0].x, y: this.points[0].y, rotation: Utils.degrees2radians(this.getRotation()) });
|
|
162
|
+
return this.block.items;
|
|
178
163
|
}
|
|
179
164
|
|
|
180
165
|
/**
|
|
@@ -222,7 +207,7 @@ export class Insert extends Entity {
|
|
|
222
207
|
// offset the item snap point by the block insert location
|
|
223
208
|
const rotatedPoint = sp.snapPoint.add(this.points[0]);
|
|
224
209
|
// rotate the snap point to match the item positions
|
|
225
|
-
const adjustedPoint = rotatedPoint.rotate(this.points[0], Utils.degrees2radians(this.
|
|
210
|
+
const adjustedPoint = rotatedPoint.rotate(this.points[0], Utils.degrees2radians(this.getRotation()));
|
|
226
211
|
snaps.push(new SnapPoint(adjustedPoint, sp.type));
|
|
227
212
|
}
|
|
228
213
|
|
|
@@ -250,7 +235,7 @@ export class Insert extends Entity {
|
|
|
250
235
|
closestPoint(P) {
|
|
251
236
|
// get the closest point from the blocks entities
|
|
252
237
|
// rotate P to match the block rotation
|
|
253
|
-
const rotatedPoint = P.rotate(this.points[0], Utils.degrees2radians(-this.
|
|
238
|
+
const rotatedPoint = P.rotate(this.points[0], Utils.degrees2radians(-this.getRotation()));
|
|
254
239
|
// adjust P by the insert position
|
|
255
240
|
const adjustedPoint = rotatedPoint.subtract(this.points[0]);
|
|
256
241
|
return this.block.closestPoint(adjustedPoint);
|
|
@@ -273,7 +258,7 @@ export class Insert extends Entity {
|
|
|
273
258
|
* @return {boolean} true if touched
|
|
274
259
|
*/
|
|
275
260
|
touched(selection) {
|
|
276
|
-
const layer = DesignCore.LayerManager.getItemByName(this.
|
|
261
|
+
const layer = DesignCore.LayerManager.getItemByName(this.getProperty(Property.Names.LAYER));
|
|
277
262
|
|
|
278
263
|
if (!layer?.isSelectable) {
|
|
279
264
|
return;
|
package/core/entities/line.js
CHANGED
|
@@ -5,11 +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 {
|
|
8
|
+
import { Property } from '../properties/property.js';
|
|
9
9
|
|
|
10
10
|
import { DesignCore } from '../designCore.js';
|
|
11
|
-
|
|
12
|
-
import { SnapPoint } from '../lib/
|
|
11
|
+
|
|
12
|
+
import { SnapPoint } from '../lib/auxiliary/snapPoint.js';
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -70,13 +70,18 @@ export class Line extends Entity {
|
|
|
70
70
|
if (pt2 === undefined) break;
|
|
71
71
|
|
|
72
72
|
if (Input.getType(pt2) === Input.Type.STRING && pt2 === 'Close') {
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
// Commit a 2-point segment from the last accumulated point back to pt1
|
|
74
|
+
const segment = new Line({ points: [this.points.at(-1), pt1] });
|
|
75
|
+
DesignCore.Scene.inputManager.executeCommand(segment);
|
|
75
76
|
return;
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
// Commit a fresh 2-point segment; keep this.points as the accumulator
|
|
80
|
+
// so preview() always draws from the last confirmed point to the mouse.
|
|
81
|
+
const segStart = this.points.at(-1);
|
|
78
82
|
this.points.push(pt2);
|
|
79
|
-
|
|
83
|
+
const segment = new Line({ points: [segStart, pt2] });
|
|
84
|
+
DesignCore.Scene.inputManager.actionCommand(segment);
|
|
80
85
|
}
|
|
81
86
|
} catch (err) {
|
|
82
87
|
Logging.instance.error(`${this.type} - ${err}`);
|
|
@@ -90,19 +95,16 @@ export class Line extends Entity {
|
|
|
90
95
|
if (this.points.length >= 1) {
|
|
91
96
|
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
92
97
|
const points = [this.points.at(-1), mousePoint];
|
|
93
|
-
DesignCore.Scene.
|
|
98
|
+
DesignCore.Scene.previewEntities.create(this.type, { points: points });
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
/**
|
|
98
103
|
* Draw the entity
|
|
99
|
-
* @param {Object}
|
|
100
|
-
* @param {number} scale
|
|
104
|
+
* @param {Object} renderer
|
|
101
105
|
*/
|
|
102
|
-
draw(
|
|
103
|
-
|
|
104
|
-
ctx.lineTo(this.points[1].x, this.points[1].y);
|
|
105
|
-
ctx.stroke();
|
|
106
|
+
draw(renderer) {
|
|
107
|
+
renderer.drawShape(this.toPolylinePoints());
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
/**
|
|
@@ -111,18 +113,18 @@ export class Line extends Entity {
|
|
|
111
113
|
*/
|
|
112
114
|
dxf(file) {
|
|
113
115
|
file.writeGroupCode('0', 'LINE');
|
|
114
|
-
file.writeGroupCode('5', this.
|
|
116
|
+
file.writeGroupCode('5', this.getProperty(Property.Names.HANDLE), DXFFile.Version.R2000); // Handle
|
|
115
117
|
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
116
118
|
file.writeGroupCode('100', 'AcDbLine', DXFFile.Version.R2000);
|
|
117
|
-
file.writeGroupCode('8', this.
|
|
118
|
-
file.writeGroupCode('6', this.
|
|
119
|
+
file.writeGroupCode('8', this.getProperty(Property.Names.LAYER));
|
|
120
|
+
file.writeGroupCode('6', this.getProperty(Property.Names.LINETYPE));
|
|
119
121
|
file.writeGroupCode('10', this.points[0].x);
|
|
120
122
|
file.writeGroupCode('20', this.points[0].y);
|
|
121
123
|
file.writeGroupCode('30', '0.0');
|
|
122
124
|
file.writeGroupCode('11', this.points[1].x);
|
|
123
125
|
file.writeGroupCode('21', this.points[1].y);
|
|
124
126
|
file.writeGroupCode('31', '0.0');
|
|
125
|
-
file.writeGroupCode('39', this.
|
|
127
|
+
file.writeGroupCode('39', this.getProperty(Property.Names.LINEWIDTH));
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
/**
|
|
@@ -136,134 +138,11 @@ export class Line extends Entity {
|
|
|
136
138
|
/**
|
|
137
139
|
* Set entity points from a polyline point representation
|
|
138
140
|
* @param {Array} points
|
|
141
|
+
* @return {Line}
|
|
139
142
|
*/
|
|
140
143
|
fromPolylinePoints(points) {
|
|
141
144
|
this.points = [new Point(points[0].x, points[0].y), new Point(points[1].x, points[1].y)];
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Trim the entity
|
|
146
|
-
* @param {Array} intersections
|
|
147
|
-
* @return {Array} - array of state changes
|
|
148
|
-
*/
|
|
149
|
-
trim(intersections) {
|
|
150
|
-
// array to hold state changes
|
|
151
|
-
const stateChanges = [];
|
|
152
|
-
|
|
153
|
-
if (intersections?.length === 0 || !intersections) {
|
|
154
|
-
return stateChanges;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// get the mouse position
|
|
158
|
-
const mousePosition = DesignCore.Mouse.pointOnScene();
|
|
159
|
-
// get the point on the line closest to the mouse
|
|
160
|
-
const pointOnLine = mousePosition.closestPointOnLine(this.points[0], this.points[1]);
|
|
161
|
-
// remove any intersections that are at the end points of the line
|
|
162
|
-
intersections = intersections.filter((p) => !p.isSame(this.points[0]) && !p.isSame(this.points[1]));
|
|
163
|
-
|
|
164
|
-
Utils.sortPointsByDistance(intersections, this.points[0]);
|
|
165
|
-
|
|
166
|
-
// Add line points to the start and the end of the point array
|
|
167
|
-
const testPoints = [this.points[0], ...intersections, this.points[1]];
|
|
168
|
-
|
|
169
|
-
// Test if mouse position is between two intersection points
|
|
170
|
-
if (testPoints.length > 1) {
|
|
171
|
-
for (let i = 0; i < testPoints.length - 1; i++) {
|
|
172
|
-
const startPoint = testPoints[i];
|
|
173
|
-
const endPoint = testPoints[i + 1];
|
|
174
|
-
|
|
175
|
-
// check if the mouse is between startPoint and endPoint
|
|
176
|
-
if (pointOnLine.isOnLine(startPoint, endPoint)) {
|
|
177
|
-
const newPoints = [];
|
|
178
|
-
|
|
179
|
-
for (const p of testPoints) {
|
|
180
|
-
const inOriginalLine = this.points.indexOf(p) !== -1;
|
|
181
|
-
const inIntersections = intersections.indexOf(p) !== -1;
|
|
182
|
-
|
|
183
|
-
// Keep points which:
|
|
184
|
-
// - The mouse is between are intersections
|
|
185
|
-
// - The mouse is not between and in this line
|
|
186
|
-
const isBetween = p.isSame(startPoint) || p.isSame(endPoint);
|
|
187
|
-
if ((isBetween && inIntersections) || (!isBetween && inOriginalLine)) {
|
|
188
|
-
newPoints.push(p);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (newPoints.length % 2 === 0) {
|
|
193
|
-
// Add lines for each point pair
|
|
194
|
-
for (let j = 0; j < newPoints.length; j += 2) {
|
|
195
|
-
const line = Utils.cloneObject(this);
|
|
196
|
-
line.points = [newPoints[j], newPoints[j + 1]];
|
|
197
|
-
const addState = new AddState(line);
|
|
198
|
-
stateChanges.push(addState);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
// Remove the existing line
|
|
202
|
-
const removeState = new RemoveState(this);
|
|
203
|
-
stateChanges.push(removeState);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return stateChanges;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Extend the entity
|
|
213
|
-
* @param {Array} intersections
|
|
214
|
-
* @return {Array} - array of state changes
|
|
215
|
-
*/
|
|
216
|
-
extend(intersections) {
|
|
217
|
-
// array to hold state changes
|
|
218
|
-
const stateChanges = [];
|
|
219
|
-
|
|
220
|
-
if (intersections?.length === 0 || !intersections) {
|
|
221
|
-
return stateChanges;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
let originPoint;
|
|
225
|
-
// Find which end is closer to the mouse
|
|
226
|
-
if (this.points[0].distance(DesignCore.Mouse.pointOnScene()) < this.points[1].distance(DesignCore.Mouse.pointOnScene())) {
|
|
227
|
-
originPoint = 0;
|
|
228
|
-
} else {
|
|
229
|
-
originPoint = 1;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
Utils.sortPointsByDistance(intersections, this.points[originPoint]);
|
|
233
|
-
|
|
234
|
-
const endPoint = this.points[originPoint];
|
|
235
|
-
const adjacentPoint = this.points[1 - originPoint];
|
|
236
|
-
|
|
237
|
-
// Find the closest intersection that lies beyond the endpoint
|
|
238
|
-
const direction = endPoint.subtract(adjacentPoint);
|
|
239
|
-
const newEndPoint = intersections.find((p) => {
|
|
240
|
-
if (p.isSame(endPoint)) return false;
|
|
241
|
-
if (p.subtract(endPoint).dot(direction) <= 0) return false;
|
|
242
|
-
if (adjacentPoint.distance(p) <= adjacentPoint.distance(endPoint)) return false;
|
|
243
|
-
return true;
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
if (!newEndPoint) {
|
|
247
|
-
return stateChanges;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const newPoints = [];
|
|
251
|
-
if (originPoint === 0) {
|
|
252
|
-
newPoints.push(newEndPoint, this.points[1]);
|
|
253
|
-
} else {
|
|
254
|
-
newPoints.push(this.points[0], newEndPoint);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (newPoints[0].isSame(this.points[0]) && newPoints[1].isSame(this.points[1])) {
|
|
258
|
-
// No change
|
|
259
|
-
return stateChanges;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// update the line
|
|
263
|
-
const addState = new UpdateState(this, { points: newPoints });
|
|
264
|
-
stateChanges.push(addState);
|
|
265
|
-
|
|
266
|
-
return stateChanges;
|
|
145
|
+
return this;
|
|
267
146
|
}
|
|
268
147
|
|
|
269
148
|
/**
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Logging } from '../lib/logging.js';
|
|
2
|
-
import { BasePolyline } from './basePolyline.js';
|
|
3
2
|
import { Polyline } from './polyline.js';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* LWPolyline Entity Class
|
|
7
|
-
*
|
|
6
|
+
* LWPolyline is a DXF import-only entity. The constructor pre-processes the
|
|
7
|
+
* raw DXF data and returns a {@link Polyline} instance. It is never
|
|
8
|
+
* instantiated as a standalone entity within the application.
|
|
8
9
|
*/
|
|
9
|
-
export class Lwpolyline
|
|
10
|
+
export class Lwpolyline {
|
|
10
11
|
static type = 'Lwpolyline';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -14,16 +15,20 @@ export class Lwpolyline extends BasePolyline {
|
|
|
14
15
|
* @param {Array} data
|
|
15
16
|
*/
|
|
16
17
|
constructor(data) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Logging.instance.error(`LWPOLYLINE Vertices Count`);
|
|
24
|
-
}
|
|
18
|
+
if (data?.hasOwnProperty('90')) {
|
|
19
|
+
// DXF Groupcode 90 - Number of vertices
|
|
20
|
+
if (!Array.isArray(data.points)) {
|
|
21
|
+
Logging.instance.error(`LWPOLYLINE: group code 90 specifies ${data[90]} vertices but points array is missing or invalid`);
|
|
22
|
+
} else if (data.points.length !== data[90]) {
|
|
23
|
+
Logging.instance.error(`LWPOLYLINE: group code 90 specifies ${data[90]} vertices but ${data.points.length} were parsed`);
|
|
25
24
|
}
|
|
26
25
|
}
|
|
26
|
+
|
|
27
|
+
if (data?.points?.length >= 4 && data.points[0].isSame(data.points.at(-1))) {
|
|
28
|
+
data.points.pop();
|
|
29
|
+
data[70] = (data[70] ?? 0) | 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
27
32
|
return new Polyline(data);
|
|
28
33
|
}
|
|
29
34
|
|
|
@@ -47,14 +47,14 @@ export class Polyline extends BasePolyline {
|
|
|
47
47
|
if (file.version < DXFFile.Version.R2000) {
|
|
48
48
|
// POLYLINE/VERTEX/SEQEND format for R12
|
|
49
49
|
file.writeGroupCode('0', 'POLYLINE');
|
|
50
|
-
file.writeGroupCode('8', this.layer);
|
|
51
|
-
file.writeGroupCode('6', this.lineType);
|
|
50
|
+
file.writeGroupCode('8', this.getProperty('layer'));
|
|
51
|
+
file.writeGroupCode('6', this.getProperty('lineType'));
|
|
52
52
|
file.writeGroupCode('66', 1); // vertices-follow flag
|
|
53
53
|
file.writeGroupCode('70', this.flags.getFlagValue());
|
|
54
54
|
|
|
55
55
|
for (let i = 0; i < this.points.length; i++) {
|
|
56
56
|
file.writeGroupCode('0', 'VERTEX');
|
|
57
|
-
file.writeGroupCode('8', this.layer);
|
|
57
|
+
file.writeGroupCode('8', this.getProperty('layer'));
|
|
58
58
|
file.writeGroupCode('10', this.points[i].x);
|
|
59
59
|
file.writeGroupCode('20', this.points[i].y);
|
|
60
60
|
file.writeGroupCode('30', '0.0');
|
|
@@ -62,7 +62,7 @@ export class Polyline extends BasePolyline {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
file.writeGroupCode('0', 'SEQEND');
|
|
65
|
-
file.writeGroupCode('8', this.layer);
|
|
65
|
+
file.writeGroupCode('8', this.getProperty('layer'));
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -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');
|