@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
|
@@ -29,12 +29,12 @@ test.each(arcInputScenarios)('ArcText.execute handles $desc', async (scenario) =
|
|
|
29
29
|
const arcText = new ArcAlignedText();
|
|
30
30
|
await arcText.execute();
|
|
31
31
|
|
|
32
|
-
expect(arcText.styleName).toBe('STANDARD');
|
|
33
|
-
expect(arcText.height).toBe(expectedTextHeight);
|
|
34
|
-
expect(arcText.string).toBe(expectedText);
|
|
32
|
+
expect(arcText.getProperty('styleName')).toBe('STANDARD');
|
|
33
|
+
expect(arcText.getProperty('height')).toBe(expectedTextHeight);
|
|
34
|
+
expect(arcText.getProperty('string')).toBe(expectedText);
|
|
35
35
|
|
|
36
36
|
// arc props
|
|
37
|
-
expect(arcText.radius).toBe(100);
|
|
37
|
+
expect(arcText.getProperty('radius')).toBe(100);
|
|
38
38
|
expect(arcText.startAngle()).toBe(0);
|
|
39
39
|
expect(arcText.endAngle()).toBeCloseTo(3.14159);
|
|
40
40
|
}, { selectedItems });
|
|
@@ -52,7 +52,7 @@ test('ArcAlignedCharacter', () => {
|
|
|
52
52
|
expect(ac.position.y).toBe(point.y);
|
|
53
53
|
expect(ac.angle).toBeCloseTo(angle);
|
|
54
54
|
expect(ac.baseline.x).toBe(10.5);
|
|
55
|
-
expect(ac.baseline.y).toBe(19.
|
|
55
|
+
expect(ac.baseline.y).toBe(19.5);
|
|
56
56
|
expect(ac.boundingBox).toBeInstanceOf(BoundingBox);
|
|
57
57
|
});
|
|
58
58
|
|
|
@@ -115,14 +115,14 @@ test('ArcText getArcAlignedCharacters', () => {
|
|
|
115
115
|
expect(chars.length).toBe(4);
|
|
116
116
|
// First character
|
|
117
117
|
expect(chars[0].character).toBe('T');
|
|
118
|
-
expect(chars[0].position.x).toBeCloseTo(-2.
|
|
119
|
-
expect(chars[0].position.y).toBeCloseTo(101.
|
|
120
|
-
expect(chars[0].angle).toBeCloseTo(0.
|
|
118
|
+
expect(chars[0].position.x).toBeCloseTo(-2.05483);
|
|
119
|
+
expect(chars[0].position.y).toBeCloseTo(101.22915);
|
|
120
|
+
expect(chars[0].angle).toBeCloseTo(0.02030);
|
|
121
121
|
// Fourth character
|
|
122
122
|
expect(chars.at(-1).character).toBe('t');
|
|
123
|
-
expect(chars.at(-1).position.x).toBeCloseTo(2.
|
|
124
|
-
expect(chars.at(-1).position.y).toBeCloseTo(101.
|
|
125
|
-
expect(chars.at(-1).angle).toBeCloseTo(-0.
|
|
123
|
+
expect(chars.at(-1).position.x).toBeCloseTo(2.05483);
|
|
124
|
+
expect(chars.at(-1).position.y).toBeCloseTo(101.22915);
|
|
125
|
+
expect(chars.at(-1).angle).toBeCloseTo(-0.02030);
|
|
126
126
|
|
|
127
127
|
|
|
128
128
|
// //////// Text Alignment Tests //////////
|
|
@@ -133,29 +133,29 @@ test('ArcText getArcAlignedCharacters', () => {
|
|
|
133
133
|
expect(chars.length).toBe(4);
|
|
134
134
|
// First character - Reversed!
|
|
135
135
|
expect(chars[0].character).toBe('t');
|
|
136
|
-
expect(chars[0].position.x).toBeCloseTo(101.
|
|
137
|
-
expect(chars[0].position.y).toBeCloseTo(
|
|
138
|
-
expect(chars[0].angle).toBeCloseTo(-1.
|
|
136
|
+
expect(chars[0].position.x).toBeCloseTo(101.23852);
|
|
137
|
+
expect(chars[0].position.y).toBeCloseTo(1.52491);
|
|
138
|
+
expect(chars[0].angle).toBeCloseTo(-1.55573);
|
|
139
139
|
// Last character - Reversed!
|
|
140
140
|
expect(chars.at(-1).character).toBe('T');
|
|
141
|
-
expect(chars.at(-1).position.x).toBeCloseTo(101.
|
|
142
|
-
expect(chars.at(-1).position.y).toBeCloseTo(5.
|
|
143
|
-
expect(chars.at(-1).angle).toBeCloseTo(-1.
|
|
141
|
+
expect(chars.at(-1).position.x).toBeCloseTo(101.09324);
|
|
142
|
+
expect(chars.at(-1).position.y).toBeCloseTo(5.63200);
|
|
143
|
+
expect(chars.at(-1).angle).toBeCloseTo(-1.51514);
|
|
144
144
|
|
|
145
|
-
// Create ArcAlignedText - left aligned - textAlignment =
|
|
145
|
+
// Create ArcAlignedText - left aligned - textAlignment = 2
|
|
146
146
|
const arcTextAlignLeft = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100, textAlignment: 2 });
|
|
147
147
|
chars = arcTextAlignLeft.getArcAlignedCharacters();
|
|
148
148
|
expect(chars.length).toBe(4);
|
|
149
149
|
// First character
|
|
150
150
|
expect(chars[0].character).toBe('T');
|
|
151
|
-
expect(chars[0].position.x).toBeCloseTo(-101.
|
|
152
|
-
expect(chars[0].position.y).toBeCloseTo(0.
|
|
153
|
-
expect(chars[0].angle).toBeCloseTo(1.
|
|
151
|
+
expect(chars[0].position.x).toBeCloseTo(-101.24664);
|
|
152
|
+
expect(chars[0].position.y).toBeCloseTo(0.82499);
|
|
153
|
+
expect(chars[0].angle).toBeCloseTo(1.56265);
|
|
154
154
|
// Last character
|
|
155
155
|
expect(chars.at(-1).character).toBe('t');
|
|
156
|
-
expect(chars.at(-1).position.x).toBeCloseTo(-101.
|
|
157
|
-
expect(chars.at(-1).position.y).toBeCloseTo(
|
|
158
|
-
expect(chars.at(-1).angle).toBeCloseTo(1.
|
|
156
|
+
expect(chars.at(-1).position.x).toBeCloseTo(-101.12976);
|
|
157
|
+
expect(chars.at(-1).position.y).toBeCloseTo(4.93298);
|
|
158
|
+
expect(chars.at(-1).angle).toBeCloseTo(1.52206);
|
|
159
159
|
|
|
160
160
|
// Create ArcAlignedText - fit to arc - textAlignment = 1
|
|
161
161
|
const arcTextFitToArc = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100, textAlignment: 1 });
|
|
@@ -163,14 +163,14 @@ test('ArcText getArcAlignedCharacters', () => {
|
|
|
163
163
|
expect(chars.length).toBe(4);
|
|
164
164
|
// First character
|
|
165
165
|
expect(chars[0].character).toBe('T');
|
|
166
|
-
expect(chars[0].position.x).toBeCloseTo(-101.
|
|
167
|
-
expect(chars[0].position.y).toBeCloseTo(0.
|
|
168
|
-
expect(chars[0].angle).toBeCloseTo(1.
|
|
166
|
+
expect(chars[0].position.x).toBeCloseTo(-101.24664);
|
|
167
|
+
expect(chars[0].position.y).toBeCloseTo(0.82499);
|
|
168
|
+
expect(chars[0].angle).toBeCloseTo(1.56265);
|
|
169
169
|
// Last character
|
|
170
170
|
expect(chars.at(-1).character).toBe('t');
|
|
171
|
-
expect(chars.at(-1).position.x).toBeCloseTo(101.
|
|
172
|
-
expect(chars.at(-1).position.y).toBeCloseTo(
|
|
173
|
-
expect(chars.at(-1).angle).toBeCloseTo(-1.
|
|
171
|
+
expect(chars.at(-1).position.x).toBeCloseTo(101.23852);
|
|
172
|
+
expect(chars.at(-1).position.y).toBeCloseTo(1.52491);
|
|
173
|
+
expect(chars.at(-1).angle).toBeCloseTo(-1.55573);
|
|
174
174
|
|
|
175
175
|
// //////// Arc Side Tests //////////
|
|
176
176
|
|
|
@@ -180,14 +180,14 @@ test('ArcText getArcAlignedCharacters', () => {
|
|
|
180
180
|
expect(chars.length).toBe(4);
|
|
181
181
|
// First character
|
|
182
182
|
expect(chars[0].character).toBe('T');
|
|
183
|
-
expect(chars[0].position.x).toBeCloseTo(-2.
|
|
184
|
-
expect(chars[0].position.y).toBeCloseTo(101.
|
|
185
|
-
expect(chars[0].angle).toBeCloseTo(0.
|
|
183
|
+
expect(chars[0].position.x).toBeCloseTo(-2.05483);
|
|
184
|
+
expect(chars[0].position.y).toBeCloseTo(101.22915);
|
|
185
|
+
expect(chars[0].angle).toBeCloseTo(0.02030);
|
|
186
186
|
// Fourth character
|
|
187
187
|
expect(chars.at(-1).character).toBe('t');
|
|
188
|
-
expect(chars.at(-1).position.x).toBeCloseTo(2.
|
|
189
|
-
expect(chars.at(-1).position.y).toBeCloseTo(101.
|
|
190
|
-
expect(chars.at(-1).angle).toBeCloseTo(-0.
|
|
188
|
+
expect(chars.at(-1).position.x).toBeCloseTo(2.05483);
|
|
189
|
+
expect(chars.at(-1).position.y).toBeCloseTo(101.22915);
|
|
190
|
+
expect(chars.at(-1).angle).toBeCloseTo(-0.02030);
|
|
191
191
|
|
|
192
192
|
// Create ArcAlignedText with string 'Test' and radius 100
|
|
193
193
|
const arcTextConcave = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100, arcSide: 2 });
|
|
@@ -195,14 +195,14 @@ test('ArcText getArcAlignedCharacters', () => {
|
|
|
195
195
|
expect(chars.length).toBe(4);
|
|
196
196
|
// First character
|
|
197
197
|
expect(chars[0].character).toBe('T');
|
|
198
|
-
expect(chars[0].position.x).toBeCloseTo(-2.
|
|
199
|
-
expect(chars[0].position.y).toBeCloseTo(98.
|
|
200
|
-
expect(chars[0].angle).toBeCloseTo(0.
|
|
198
|
+
expect(chars[0].position.x).toBeCloseTo(-2.05482);
|
|
199
|
+
expect(chars[0].position.y).toBeCloseTo(98.72862);
|
|
200
|
+
expect(chars[0].angle).toBeCloseTo(0.02081);
|
|
201
201
|
// Fourth character
|
|
202
202
|
expect(chars.at(-1).character).toBe('t');
|
|
203
|
-
expect(chars.at(-1).position.x).toBeCloseTo(2.
|
|
204
|
-
expect(chars.at(-1).position.y).toBeCloseTo(98.
|
|
205
|
-
expect(chars.at(-1).angle).toBeCloseTo(-0.
|
|
203
|
+
expect(chars.at(-1).position.x).toBeCloseTo(2.05482);
|
|
204
|
+
expect(chars.at(-1).position.y).toBeCloseTo(98.72862);
|
|
205
|
+
expect(chars.at(-1).angle).toBeCloseTo(-0.02081);
|
|
206
206
|
});
|
|
207
207
|
|
|
208
208
|
test('ArcText.dxf', () => {
|
|
@@ -290,7 +290,21 @@ STANDARD
|
|
|
290
290
|
expect(file.contents).toEqual(dxfString);
|
|
291
291
|
|
|
292
292
|
// create new entity from entity data to ensure all props are loaded
|
|
293
|
-
const newArcAlignedText = new ArcAlignedText(
|
|
293
|
+
const newArcAlignedText = new ArcAlignedText({
|
|
294
|
+
handle: arctext.getProperty('handle'),
|
|
295
|
+
points: arctext.points,
|
|
296
|
+
string: arctext.getProperty('string'),
|
|
297
|
+
styleName: arctext.getProperty('styleName'),
|
|
298
|
+
radius: arctext.getProperty('radius'),
|
|
299
|
+
height: arctext.getProperty('height'),
|
|
300
|
+
characterSpacing: arctext.getProperty('characterSpacing'),
|
|
301
|
+
offsetFromArc: arctext.getProperty('offsetFromArc'),
|
|
302
|
+
offsetFromRight: arctext.getProperty('offsetFromRight'),
|
|
303
|
+
offsetFromLeft: arctext.getProperty('offsetFromLeft'),
|
|
304
|
+
textOrientation: arctext.getProperty('textOrientation'),
|
|
305
|
+
textAlignment: arctext.getProperty('textAlignment'),
|
|
306
|
+
arcSide: arctext.getProperty('arcSide'),
|
|
307
|
+
});
|
|
294
308
|
file = new File();
|
|
295
309
|
newArcAlignedText.dxf(file);
|
|
296
310
|
expect(file.contents).toEqual(dxfString);
|
|
@@ -301,32 +315,32 @@ test('Test ArcText.snaps', () => {
|
|
|
301
315
|
const point = new Point(100, 100);
|
|
302
316
|
const snaps = arcText.snaps(point, 1);
|
|
303
317
|
const nodeSnaps = snaps.filter((s) => s.type === 'node');
|
|
304
|
-
expect(nodeSnaps[0].snapPoint.x).toBeCloseTo(-2.
|
|
305
|
-
expect(nodeSnaps[0].snapPoint.y).toBeCloseTo(101.
|
|
318
|
+
expect(nodeSnaps[0].snapPoint.x).toBeCloseTo(-2.05483);
|
|
319
|
+
expect(nodeSnaps[0].snapPoint.y).toBeCloseTo(101.22915);
|
|
306
320
|
});
|
|
307
321
|
|
|
308
322
|
test('Test ArcText.closestPoint', () => {
|
|
309
323
|
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100 });
|
|
310
324
|
const point = new Point(100, 100);
|
|
311
325
|
const closest = arcText.closestPoint(point);
|
|
312
|
-
expect(closest[0].x).toBeCloseTo(2.
|
|
313
|
-
expect(closest[0].y).toBeCloseTo(101.
|
|
326
|
+
expect(closest[0].x).toBeCloseTo(2.05483);
|
|
327
|
+
expect(closest[0].y).toBeCloseTo(101.22915);
|
|
314
328
|
});
|
|
315
329
|
|
|
316
330
|
test('Test ArcText.boundingBox', () => {
|
|
317
331
|
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100 });
|
|
318
|
-
expect(arcText.boundingBox().xMin).toBeCloseTo(-
|
|
319
|
-
expect(arcText.boundingBox().xMax).toBeCloseTo(
|
|
320
|
-
expect(arcText.boundingBox().yMin).toBeCloseTo(99.
|
|
321
|
-
expect(arcText.boundingBox().yMax).toBeCloseTo(102.
|
|
332
|
+
expect(arcText.boundingBox().xMin).toBeCloseTo(-2.81733);
|
|
333
|
+
expect(arcText.boundingBox().xMax).toBeCloseTo(2.46733);
|
|
334
|
+
expect(arcText.boundingBox().yMin).toBeCloseTo(99.97915);
|
|
335
|
+
expect(arcText.boundingBox().yMax).toBeCloseTo(102.49878);
|
|
322
336
|
});
|
|
323
337
|
|
|
324
338
|
test('Test ArcText.toPolylinePoints - returns correct points array', () => {
|
|
325
339
|
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100 });
|
|
326
340
|
const result = arcText.toPolylinePoints();
|
|
327
341
|
expect(result.length).toBe(4);
|
|
328
|
-
expect(result[0].x).toBeCloseTo(-2.
|
|
329
|
-
expect(result[0].y).toBeCloseTo(101.
|
|
342
|
+
expect(result[0].x).toBeCloseTo(-2.05483);
|
|
343
|
+
expect(result[0].y).toBeCloseTo(101.22915);
|
|
330
344
|
});
|
|
331
345
|
|
|
332
346
|
test('ArcText.snaps returns a centre snap at points[0]', () => {
|
|
@@ -343,3 +357,116 @@ test('ArcText.snaps returns node snaps only for non-space characters', () => {
|
|
|
343
357
|
const nodeSnaps = arcText.snaps(new Point(0, 0), 100).filter((s) => s.type === 'node');
|
|
344
358
|
expect(nodeSnaps.length).toBe(2);
|
|
345
359
|
});
|
|
360
|
+
|
|
361
|
+
test('ArcAlignedCharacter respects explicit height and width', () => {
|
|
362
|
+
const ac = new ArcAlignedCharacter('A', new Point(0, 0), 0, 5, 3);
|
|
363
|
+
expect(ac.height).toBe(5);
|
|
364
|
+
expect(ac.width).toBe(3);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test('ArcText getArcAlignedCharacters empty string returns empty array', () => {
|
|
368
|
+
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: '', radius: 100 });
|
|
369
|
+
expect(arcText.getArcAlignedCharacters()).toHaveLength(0);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test('ArcText boundingBox empty string returns BoundingBox instance', () => {
|
|
373
|
+
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: '', radius: 100 });
|
|
374
|
+
expect(arcText.boundingBox()).toBeInstanceOf(BoundingBox);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test('ArcText toPolylinePoints empty string returns empty array', () => {
|
|
378
|
+
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: '', radius: 100 });
|
|
379
|
+
expect(arcText.toPolylinePoints()).toHaveLength(0);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test('ArcText snaps with empty string returns only centre snap', () => {
|
|
383
|
+
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: '', radius: 100 });
|
|
384
|
+
const snaps = arcText.snaps(new Point(0, 0), 1);
|
|
385
|
+
expect(snaps).toHaveLength(1);
|
|
386
|
+
expect(snaps[0].type).toBe('centre');
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
test('ArcText closestPoint returns distance 0.1 when within height * 0.35', () => {
|
|
390
|
+
// Single char 'T' center-aligned sits at (0, 101.25); height = 2.5, threshold = 0.875
|
|
391
|
+
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: 'T', radius: 100 });
|
|
392
|
+
const chars = arcText.getArcAlignedCharacters();
|
|
393
|
+
const charPos = chars[0].position;
|
|
394
|
+
// 0.5 units away is within the 0.875 threshold
|
|
395
|
+
const closePoint = new Point(charPos.x + 0.5, charPos.y);
|
|
396
|
+
const [, dist] = arcText.closestPoint(closePoint);
|
|
397
|
+
expect(dist).toBe(0.1);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
test('ArcText getArcAlignedCharacters fit-to-arc single character places at midpoint', () => {
|
|
401
|
+
const t = new ArcAlignedText({ points: [new Point(0, 0)], radius: 10, string: 'X',
|
|
402
|
+
startAngle: 0, endAngle: 180, textAlignment: 1 });
|
|
403
|
+
const chars = t.getArcAlignedCharacters();
|
|
404
|
+
expect(chars).toHaveLength(1);
|
|
405
|
+
// midpoint of 0°–180° arc at radius 10 is 90° → point near (0, 10)
|
|
406
|
+
expect(chars[0].position.x).toBeCloseTo(0, 0);
|
|
407
|
+
expect(chars[0].position.y).toBeGreaterThan(0);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test('ArcText getArcAlignedCharacters single character is placed at arc midpoint', () => {
|
|
411
|
+
// Single char with center alignment: charOffsetAngles = [0], stringStartPoint = arcMidPoint
|
|
412
|
+
// arcMidAngle(0, PI) = PI/2 → project(PI/2, 101.25) = (0, 101.25), angle = PI/2 - PI/2 = 0
|
|
413
|
+
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: 'X', radius: 100 });
|
|
414
|
+
const chars = arcText.getArcAlignedCharacters();
|
|
415
|
+
expect(chars).toHaveLength(1);
|
|
416
|
+
expect(chars[0].character).toBe('X');
|
|
417
|
+
expect(chars[0].position.x).toBeCloseTo(0, 4);
|
|
418
|
+
expect(chars[0].position.y).toBeCloseTo(101.25, 4);
|
|
419
|
+
expect(chars[0].angle).toBeCloseTo(0, 4);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test('ArcText getArcAlignedCharacters textOrientation inward reverses character order', () => {
|
|
423
|
+
// textOrientation 2 reverses the string before placing characters
|
|
424
|
+
const arcText = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100, textOrientation: 2 });
|
|
425
|
+
const chars = arcText.getArcAlignedCharacters();
|
|
426
|
+
expect(chars).toHaveLength(4);
|
|
427
|
+
expect(chars[0].character).toBe('t'); // reversed
|
|
428
|
+
expect(chars.at(-1).character).toBe('T'); // reversed
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
test('ArcText getArcAlignedCharacters offsetFromLeft shifts character positions', () => {
|
|
432
|
+
// offsetFromLeft moves the string start away from the arc end for left-aligned text
|
|
433
|
+
const base = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100, textAlignment: 2, offsetFromLeft: 0 });
|
|
434
|
+
const offset = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100, textAlignment: 2, offsetFromLeft: 10 });
|
|
435
|
+
const baseChars = base.getArcAlignedCharacters();
|
|
436
|
+
const offsetChars = offset.getArcAlignedCharacters();
|
|
437
|
+
expect(offsetChars[0].position.x).not.toBeCloseTo(baseChars[0].position.x, 1);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
test('ArcText getArcAlignedCharacters offsetFromRight shifts character positions', () => {
|
|
441
|
+
// offsetFromRight moves the string start away from the arc start for right-aligned text
|
|
442
|
+
const base = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100, textAlignment: 3, offsetFromRight: 0 });
|
|
443
|
+
const offset = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Test', radius: 100, textAlignment: 3, offsetFromRight: 10 });
|
|
444
|
+
const baseChars = base.getArcAlignedCharacters();
|
|
445
|
+
const offsetChars = offset.getArcAlignedCharacters();
|
|
446
|
+
expect(offsetChars[0].position.x).not.toBeCloseTo(baseChars[0].position.x, 1);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test('ArcAlignedText.toCharacters returns one entry per character with scene coords', () => {
|
|
450
|
+
const arc = new ArcAlignedText({ points: [new Point(0, 0)], string: 'AB', radius: 100 });
|
|
451
|
+
const chars = arc.toCharacters();
|
|
452
|
+
expect(chars).toHaveLength(2);
|
|
453
|
+
expect(chars[0].char).toBe('A');
|
|
454
|
+
expect(chars[1].char).toBe('B');
|
|
455
|
+
expect(typeof chars[0].x).toBe('number');
|
|
456
|
+
expect(typeof chars[0].y).toBe('number');
|
|
457
|
+
expect(typeof chars[0].rotation).toBe('number');
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
test('ArcAlignedText.draw calls renderer.drawText with all characters', () => {
|
|
461
|
+
const arc = new ArcAlignedText({ points: [new Point(0, 0)], string: 'Hi', radius: 50 });
|
|
462
|
+
let calledChars;
|
|
463
|
+
const mockRenderer = {
|
|
464
|
+
drawText(characters) {
|
|
465
|
+
calledChars = characters;
|
|
466
|
+
},
|
|
467
|
+
};
|
|
468
|
+
arc.draw(mockRenderer);
|
|
469
|
+
expect(calledChars).toHaveLength(2);
|
|
470
|
+
expect(calledChars[0].char).toBe('H');
|
|
471
|
+
expect(calledChars[1].char).toBe('i');
|
|
472
|
+
});
|
|
@@ -46,6 +46,18 @@ test.each(inputScenarios)('Polyline.execute handles $desc', async (scenario) =>
|
|
|
46
46
|
}, { extraMethods: { actionCommand: () => {} } });
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
test('Test BasePolyline.draw calls renderer.drawShape with toPolylinePoints', () => {
|
|
50
|
+
const polyline = new Polyline({ points: [new Point(0, 0), new Point(10, 0), new Point(10, 5)] });
|
|
51
|
+
let capturedPoints;
|
|
52
|
+
const mockRenderer = {
|
|
53
|
+
drawShape(points) {
|
|
54
|
+
capturedPoints = points;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
polyline.draw(mockRenderer);
|
|
58
|
+
expect(capturedPoints).toEqual(polyline.toPolylinePoints());
|
|
59
|
+
});
|
|
60
|
+
|
|
49
61
|
test('Test BasePolyline.getClosestSegment', () => {
|
|
50
62
|
// Polyline with a line and an arc segment
|
|
51
63
|
const points = [new Point(0, 0), new Point(10, 0), new Point(10, 10)];
|
|
@@ -322,7 +334,7 @@ AcDbPolyline
|
|
|
322
334
|
6
|
|
323
335
|
ByLayer
|
|
324
336
|
39
|
|
325
|
-
|
|
337
|
+
1
|
|
326
338
|
90
|
|
327
339
|
3
|
|
328
340
|
70
|
|
@@ -350,7 +362,7 @@ ByLayer
|
|
|
350
362
|
expect(file.contents).toEqual(dxfString);
|
|
351
363
|
|
|
352
364
|
// create new entity from entity data to ensure all props are loaded
|
|
353
|
-
const newPolyline = new Polyline(polyline);
|
|
365
|
+
const newPolyline = new Polyline({ handle: polyline.getProperty('handle'), points: polyline.points });
|
|
354
366
|
file = new File();
|
|
355
367
|
newPolyline.dxf(file);
|
|
356
368
|
|
|
@@ -626,3 +638,118 @@ test('BasePolyline.fromPolylinePoints round-trip strips closure point for closed
|
|
|
626
638
|
expect(rebuilt.points[3].x).toBe(0);
|
|
627
639
|
expect(rebuilt.points[3].y).toBe(10);
|
|
628
640
|
});
|
|
641
|
+
|
|
642
|
+
// ─── closestPoint: closed polyline closing segment ───────────────────────────
|
|
643
|
+
|
|
644
|
+
test('BasePolyline.closestPoint finds closest point on closing segment of closed polyline', () => {
|
|
645
|
+
// Square: P0=(0,0), P1=(10,0), P2=(10,10), P3=(0,10), closed flag set.
|
|
646
|
+
// Closing segment is P3=(0,10) → P0=(0,0).
|
|
647
|
+
// A test point on the left edge (0, 5) must resolve to (0, 5) on the closing segment.
|
|
648
|
+
const points = [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)];
|
|
649
|
+
const poly = new BasePolyline({ points });
|
|
650
|
+
poly.flags.setFlagValue(1);
|
|
651
|
+
|
|
652
|
+
const [closest, dist] = poly.closestPoint(new Point(0, 5));
|
|
653
|
+
expect(closest.x).toBeCloseTo(0);
|
|
654
|
+
expect(closest.y).toBeCloseTo(5);
|
|
655
|
+
expect(dist).toBeCloseTo(0);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
test('BasePolyline.closestPoint closing segment is preferred over other segments', () => {
|
|
659
|
+
// The test point (-1, 5) is clearly nearest the closing segment (left edge),
|
|
660
|
+
// not the bottom, right, or top edges.
|
|
661
|
+
const points = [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)];
|
|
662
|
+
const poly = new BasePolyline({ points });
|
|
663
|
+
poly.flags.setFlagValue(1);
|
|
664
|
+
|
|
665
|
+
const [closest, dist] = poly.closestPoint(new Point(-1, 5));
|
|
666
|
+
expect(closest.x).toBeCloseTo(0);
|
|
667
|
+
expect(closest.y).toBeCloseTo(5);
|
|
668
|
+
expect(dist).toBeCloseTo(1);
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
test('BasePolyline.closestPoint for open polyline does not include closing segment', () => {
|
|
672
|
+
// For point (-1, 1) on the open square:
|
|
673
|
+
// – Nearest on seg P0→P1 (y=0): foot (-1,0) clips to (0,0), dist = √2 ≈ 1.41
|
|
674
|
+
// – Nearest on seg P2→P3 (y=10): foot (-1,10) clips to (0,10), dist ≈ 9.06
|
|
675
|
+
// – If the closing segment existed (x=0, y∈[0,10]): foot (0,1), dist = 1 ← closer!
|
|
676
|
+
// An open polyline must NOT check the closing segment, so it returns (0,0).
|
|
677
|
+
const points = [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)];
|
|
678
|
+
const poly = new BasePolyline({ points });
|
|
679
|
+
// flag NOT set — open polyline
|
|
680
|
+
|
|
681
|
+
const [closest] = poly.closestPoint(new Point(-1, 1));
|
|
682
|
+
expect(closest.x).toBeCloseTo(0);
|
|
683
|
+
expect(closest.y).toBeCloseTo(0);
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
test('BasePolyline.closestPoint is consistent with getClosestSegmentIndex for closed polyline', () => {
|
|
687
|
+
// For a closed square, both methods should agree that the closing segment
|
|
688
|
+
// is nearest for a point on the left edge.
|
|
689
|
+
const points = [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)];
|
|
690
|
+
const poly = new BasePolyline({ points });
|
|
691
|
+
poly.flags.setFlagValue(1);
|
|
692
|
+
|
|
693
|
+
const testPoint = new Point(-2, 5);
|
|
694
|
+
const [closest] = poly.closestPoint(testPoint);
|
|
695
|
+
const segIdx = poly.getClosestSegmentIndex(testPoint);
|
|
696
|
+
|
|
697
|
+
// Closing segment index == points.length == 4
|
|
698
|
+
expect(segIdx).toBe(points.length);
|
|
699
|
+
expect(closest.x).toBeCloseTo(0);
|
|
700
|
+
expect(closest.y).toBeCloseTo(5);
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// ─── preview ─────────────────────────────────────────────────────────────────
|
|
704
|
+
|
|
705
|
+
test('BasePolyline.preview - 0 points does nothing', () => {
|
|
706
|
+
const poly = new BasePolyline({});
|
|
707
|
+
DesignCore.Scene.auxiliaryEntities.clear();
|
|
708
|
+
DesignCore.Scene.previewEntities.clear();
|
|
709
|
+
|
|
710
|
+
expect(() => poly.preview()).not.toThrow();
|
|
711
|
+
expect(DesignCore.Scene.auxiliaryEntities.count()).toBe(0);
|
|
712
|
+
expect(DesignCore.Scene.previewEntities.count()).toBe(0);
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
test('BasePolyline.preview - LINE mode creates temp entity', () => {
|
|
716
|
+
const poly = new BasePolyline({});
|
|
717
|
+
poly.points.push(new Point(0, 0));
|
|
718
|
+
|
|
719
|
+
const origCreate = DesignCore.Scene.previewEntities.create;
|
|
720
|
+
const calls = [];
|
|
721
|
+
DesignCore.Scene.previewEntities.create = (type, data) => calls.push({ type, data });
|
|
722
|
+
|
|
723
|
+
DesignCore.Scene.auxiliaryEntities.clear();
|
|
724
|
+
poly.preview();
|
|
725
|
+
|
|
726
|
+
expect(calls.length).toBeGreaterThanOrEqual(1);
|
|
727
|
+
// LINE mode: no rubber-band auxiliary entity
|
|
728
|
+
expect(DesignCore.Scene.auxiliaryEntities.count()).toBe(0);
|
|
729
|
+
|
|
730
|
+
DesignCore.Scene.previewEntities.create = origCreate;
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
test('BasePolyline.preview - ARC mode adds rubber band and creates arc temp entity', () => {
|
|
734
|
+
const poly = new BasePolyline({});
|
|
735
|
+
poly.points.push(new Point(0, 0));
|
|
736
|
+
poly.points.push(new Point(10, 0));
|
|
737
|
+
poly.inputMode = poly.modes.ARC;
|
|
738
|
+
|
|
739
|
+
const origAdd = DesignCore.Scene.auxiliaryEntities.add;
|
|
740
|
+
const origCreate = DesignCore.Scene.previewEntities.create;
|
|
741
|
+
const auxAdded = [];
|
|
742
|
+
const tempCreated = [];
|
|
743
|
+
DesignCore.Scene.auxiliaryEntities.add = (item) => auxAdded.push(item);
|
|
744
|
+
DesignCore.Scene.previewEntities.create = (type, data) => tempCreated.push({ type, data });
|
|
745
|
+
|
|
746
|
+
poly.preview();
|
|
747
|
+
|
|
748
|
+
// ARC mode: rubber-band drawn in auxiliaryEntities
|
|
749
|
+
expect(auxAdded.length).toBeGreaterThanOrEqual(1);
|
|
750
|
+
// ARC mode: arc preview drawn in previewEntities
|
|
751
|
+
expect(tempCreated.length).toBeGreaterThanOrEqual(1);
|
|
752
|
+
|
|
753
|
+
DesignCore.Scene.auxiliaryEntities.add = origAdd;
|
|
754
|
+
DesignCore.Scene.previewEntities.create = origCreate;
|
|
755
|
+
});
|