@jscad/svg-deserializer 2.5.10 → 2.5.12
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/CHANGELOG.md +19 -0
- package/LICENSE +1 -1
- package/package.json +4 -4
- package/src/shapesMapGeometry.js +32 -13
- package/tests/instantiate.test.js +32 -26
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.5.12](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/svg-deserializer@2.5.11...@jscad/svg-deserializer@2.5.12) (2025-09-20)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **svg-deserializer:** svg path should return one geom2 ([4500b71](https://github.com/jscad/OpenJSCAD.org/commit/4500b71579fd805e5f740a7b4605b14986bbe14e))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [2.5.11](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/svg-deserializer@2.5.10...@jscad/svg-deserializer@2.5.11) (2024-12-29)
|
|
18
|
+
|
|
19
|
+
**Note:** Version bump only for package @jscad/svg-deserializer
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
## [2.5.10](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/svg-deserializer@2.5.9...@jscad/svg-deserializer@2.5.10) (2024-11-10)
|
|
7
26
|
|
|
8
27
|
**Note:** Version bump only for package @jscad/svg-deserializer
|
package/LICENSE
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
The MIT License (MIT)
|
|
3
3
|
|
|
4
|
-
Copyright (c) 2017-
|
|
4
|
+
Copyright (c) 2017-2024 JSCAD Organization
|
|
5
5
|
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
of this software and associated documentation files (the "Software"), to deal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/svg-deserializer",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.12",
|
|
4
4
|
"description": "SVG Deserializer for JSCAD",
|
|
5
5
|
"homepage": "https://openjscad.xyz/",
|
|
6
6
|
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@jscad/array-utils": "2.1.4",
|
|
36
|
-
"@jscad/io-utils": "2.0.
|
|
37
|
-
"@jscad/modeling": "2.12.
|
|
36
|
+
"@jscad/io-utils": "2.0.31",
|
|
37
|
+
"@jscad/modeling": "2.12.6",
|
|
38
38
|
"saxes": "5.0.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"ava": "3.15.0",
|
|
42
42
|
"nyc": "15.1.0"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "11a9a2d9235d804360116f776076c9f3237a3eb0"
|
|
45
45
|
}
|
package/src/shapesMapGeometry.js
CHANGED
|
@@ -133,16 +133,23 @@ const shapesMapGeometry = (obj, objectify, params) => {
|
|
|
133
133
|
const listofpaths = expandPath(obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments, pathSelfClosed)
|
|
134
134
|
// order is important
|
|
135
135
|
const listofentries = Object.entries(listofpaths).sort((a, b) => a[0].localeCompare(b[0]))
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
136
|
+
|
|
137
|
+
if (target === 'geom2') {
|
|
138
|
+
// concatenate all sides to a single geom2
|
|
139
|
+
const outlines = []
|
|
140
|
+
listofentries.forEach((entry) => {
|
|
141
|
+
const path = entry[1]
|
|
142
|
+
// discard unclosed paths
|
|
143
|
+
if (path.isClosed) {
|
|
144
|
+
const points = geometries.path2.toPoints(path)
|
|
145
|
+
outlines.push(points)
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
if (outlines.length === 0) return []
|
|
149
|
+
return geometries.geom2.create(outlines)
|
|
150
|
+
} else {
|
|
151
|
+
return listofentries.map((entry) => entry[1])
|
|
152
|
+
}
|
|
146
153
|
}
|
|
147
154
|
}
|
|
148
155
|
|
|
@@ -156,6 +163,18 @@ const appendPoints = (points, geometry) => {
|
|
|
156
163
|
return geometries.path2.fromPoints({ }, points)
|
|
157
164
|
}
|
|
158
165
|
|
|
166
|
+
/*
|
|
167
|
+
* Expands the given SVG path object into a set of path segments.
|
|
168
|
+
* @param {object} obj - SVG path object to expand
|
|
169
|
+
* @param {number} svgUnitsPmm - SVG units per millimeter
|
|
170
|
+
* @param {number} svgUnitsX - X-axis SVG units
|
|
171
|
+
* @param {number} svgUnitsY - Y-axis SVG units
|
|
172
|
+
* @param {number} svgUnitsV - SVG units value
|
|
173
|
+
* @param {object} svgGroups - SVG groups object
|
|
174
|
+
* @param {number} segments - number of segments per full rotation
|
|
175
|
+
* @param {boolean} pathSelfClosed - Whether the path is self-closed
|
|
176
|
+
* @returns {object} a object containing the named paths
|
|
177
|
+
*/
|
|
159
178
|
const expandPath = (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments, pathSelfClosed) => {
|
|
160
179
|
const paths = {}
|
|
161
180
|
const on = 'path'
|
|
@@ -454,13 +473,13 @@ const expandPath = (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups
|
|
|
454
473
|
by = rf[1]
|
|
455
474
|
}
|
|
456
475
|
break
|
|
457
|
-
case 'h': // relative
|
|
476
|
+
case 'h': // relative Horizontal line to
|
|
458
477
|
while (pts.length >= i + 1) {
|
|
459
478
|
cx = cx + parseFloat(pts[i++])
|
|
460
479
|
paths[pathName] = appendPoints([svg2cag([cx, cy], svgUnitsPmm)], paths[pathName])
|
|
461
480
|
}
|
|
462
481
|
break
|
|
463
|
-
case 'H': // absolute
|
|
482
|
+
case 'H': // absolute Horizontal line to
|
|
464
483
|
while (pts.length >= i + 1) {
|
|
465
484
|
cx = parseFloat(pts[i++])
|
|
466
485
|
paths[pathName] = appendPoints([svg2cag([cx, cy], svgUnitsPmm)], paths[pathName])
|
|
@@ -500,7 +519,7 @@ const expandPath = (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups
|
|
|
500
519
|
pc = true
|
|
501
520
|
break
|
|
502
521
|
default:
|
|
503
|
-
console.log('Warning:
|
|
522
|
+
console.log('Warning: Unknown PATH command [' + co.c + ']')
|
|
504
523
|
break
|
|
505
524
|
}
|
|
506
525
|
|
|
@@ -2,7 +2,7 @@ const test = require('ava')
|
|
|
2
2
|
|
|
3
3
|
const deserializer = require('../src/index.js')
|
|
4
4
|
|
|
5
|
-
const { measurements } = require('@jscad/modeling')
|
|
5
|
+
const { geometries, measurements } = require('@jscad/modeling')
|
|
6
6
|
|
|
7
7
|
// deserializer
|
|
8
8
|
|
|
@@ -173,7 +173,8 @@ test('deserialize : instantiate svg (path: simple) to objects', (t) => {
|
|
|
173
173
|
let observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
174
174
|
t.is(observed.length, 1)
|
|
175
175
|
let shape = observed[0]
|
|
176
|
-
t.is(shape.sides.length,
|
|
176
|
+
t.is(shape.sides.length, 1)
|
|
177
|
+
t.true(geometries.geom2.isA(shape))
|
|
177
178
|
|
|
178
179
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
179
180
|
t.is(observed.length, 1)
|
|
@@ -190,7 +191,8 @@ test('deserialize : instantiate svg (path: simple) to objects', (t) => {
|
|
|
190
191
|
observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
191
192
|
t.is(observed.length, 1)
|
|
192
193
|
shape = observed[0]
|
|
193
|
-
t.is(shape.sides.length,
|
|
194
|
+
t.is(shape.sides.length, 1)
|
|
195
|
+
t.true(geometries.geom2.isA(shape))
|
|
194
196
|
|
|
195
197
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
196
198
|
t.is(observed.length, 1)
|
|
@@ -204,7 +206,8 @@ test('deserialize : instantiate svg (path: simple) to objects', (t) => {
|
|
|
204
206
|
observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
205
207
|
t.is(observed.length, 1)
|
|
206
208
|
shape = observed[0]
|
|
207
|
-
t.is(shape.sides.length,
|
|
209
|
+
t.is(shape.sides.length, 1)
|
|
210
|
+
t.true(geometries.geom2.isA(shape))
|
|
208
211
|
|
|
209
212
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
210
213
|
t.is(observed.length, 1)
|
|
@@ -218,7 +221,8 @@ test('deserialize : instantiate svg (path: simple) to objects', (t) => {
|
|
|
218
221
|
observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
219
222
|
t.is(observed.length, 1)
|
|
220
223
|
shape = observed[0]
|
|
221
|
-
t.is(shape.sides.length,
|
|
224
|
+
t.is(shape.sides.length, 1)
|
|
225
|
+
t.true(geometries.geom2.isA(shape))
|
|
222
226
|
|
|
223
227
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
224
228
|
t.is(observed.length, 1)
|
|
@@ -237,7 +241,11 @@ test('deserialize : instantiate svg (path: arc) to objects', (t) => {
|
|
|
237
241
|
let observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
238
242
|
t.is(observed.length, 2)
|
|
239
243
|
let shape = observed[0]
|
|
240
|
-
t.is(shape.sides.length,
|
|
244
|
+
t.is(shape.sides.length, 1)
|
|
245
|
+
t.true(geometries.geom2.isA(shape))
|
|
246
|
+
shape = observed[1]
|
|
247
|
+
t.is(shape.sides.length, 1)
|
|
248
|
+
t.true(geometries.geom2.isA(shape))
|
|
241
249
|
|
|
242
250
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
243
251
|
t.is(observed.length, 2)
|
|
@@ -264,7 +272,8 @@ test('deserialize : instantiate svg (path: with bezier) to objects', (t) => {
|
|
|
264
272
|
let observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
265
273
|
t.is(observed.length, 1)
|
|
266
274
|
let shape = observed[0]
|
|
267
|
-
t.is(shape.sides.length,
|
|
275
|
+
t.is(shape.sides.length, 1)
|
|
276
|
+
t.true(geometries.geom2.isA(shape))
|
|
268
277
|
|
|
269
278
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
270
279
|
t.is(observed.length, 1)
|
|
@@ -285,7 +294,8 @@ test('deserialize : instantiate svg (path: with bezier) to objects', (t) => {
|
|
|
285
294
|
observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
286
295
|
t.is(observed.length, 1)
|
|
287
296
|
shape = observed[0]
|
|
288
|
-
t.is(shape.sides.length,
|
|
297
|
+
t.is(shape.sides.length, 1)
|
|
298
|
+
t.true(geometries.geom2.isA(shape))
|
|
289
299
|
|
|
290
300
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
291
301
|
t.is(observed.length, 1)
|
|
@@ -300,7 +310,8 @@ test('deserialize : instantiate svg (path: with bezier) to objects', (t) => {
|
|
|
300
310
|
observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
301
311
|
t.is(observed.length, 1)
|
|
302
312
|
shape = observed[0]
|
|
303
|
-
t.is(shape.sides.length,
|
|
313
|
+
t.is(shape.sides.length, 1)
|
|
314
|
+
t.true(geometries.geom2.isA(shape))
|
|
304
315
|
|
|
305
316
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
306
317
|
t.is(observed.length, 1)
|
|
@@ -314,9 +325,7 @@ test('deserialize : instantiate svg (path: with bezier) to objects', (t) => {
|
|
|
314
325
|
</svg>`
|
|
315
326
|
|
|
316
327
|
observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
317
|
-
t.is(observed.length,
|
|
318
|
-
shape = observed[0]
|
|
319
|
-
t.is(shape.points.length, 14) // open path
|
|
328
|
+
t.is(observed.length, 0) // open path
|
|
320
329
|
|
|
321
330
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
322
331
|
t.is(observed.length, 2)
|
|
@@ -332,9 +341,7 @@ test('deserialize : instantiate svg (path: with bezier) to objects', (t) => {
|
|
|
332
341
|
</svg>`
|
|
333
342
|
|
|
334
343
|
observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
335
|
-
t.is(observed.length,
|
|
336
|
-
shape = observed[0]
|
|
337
|
-
t.is(shape.points.length, 29) // open path
|
|
344
|
+
t.is(observed.length, 0) // open path
|
|
338
345
|
|
|
339
346
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
340
347
|
t.is(observed.length, 1)
|
|
@@ -349,7 +356,7 @@ test('deserialize : instantiate svg (path: with bezier) to objects', (t) => {
|
|
|
349
356
|
observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
350
357
|
t.is(observed.length, 1)
|
|
351
358
|
shape = observed[0]
|
|
352
|
-
t.is(shape.sides.length,
|
|
359
|
+
t.is(shape.sides.length, 1)
|
|
353
360
|
t.deepEqual(shape.color, [1, 0, 0, 1])
|
|
354
361
|
|
|
355
362
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
@@ -408,11 +415,10 @@ test('deserialize : instantiate svg produced by inkscape to objects', (t) => {
|
|
|
408
415
|
`
|
|
409
416
|
|
|
410
417
|
let observed = deserializer.deserialize({ filename: 'inkscape', output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
411
|
-
t.is(observed.length,
|
|
418
|
+
t.is(observed.length, 1)
|
|
412
419
|
let shape = observed[0]
|
|
413
|
-
t.is(shape.sides.length,
|
|
414
|
-
shape
|
|
415
|
-
t.is(shape.sides.length, 20)
|
|
420
|
+
t.is(shape.sides.length, 2)
|
|
421
|
+
t.true(geometries.geom2.isA(shape))
|
|
416
422
|
|
|
417
423
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
418
424
|
t.is(observed.length, 2)
|
|
@@ -432,11 +438,10 @@ test('deserialize : instantiate shape with a hole to objects', (t) => {
|
|
|
432
438
|
`
|
|
433
439
|
|
|
434
440
|
let observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
435
|
-
t.is(observed.length,
|
|
441
|
+
t.is(observed.length, 1)
|
|
436
442
|
let shape = observed[0]
|
|
437
|
-
t.is(shape.sides.length,
|
|
438
|
-
shape
|
|
439
|
-
t.is(shape.sides.length, 38)
|
|
443
|
+
t.is(shape.sides.length, 2)
|
|
444
|
+
t.true(geometries.geom2.isA(shape))
|
|
440
445
|
|
|
441
446
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
442
447
|
t.is(observed.length, 2)
|
|
@@ -456,9 +461,10 @@ test('deserialize : instantiate shape with a nested hole to objects', (t) => {
|
|
|
456
461
|
`
|
|
457
462
|
|
|
458
463
|
let observed = deserializer.deserialize({ output: 'geometry', target: 'geom2', addMetaData: false }, sourceSvg)
|
|
459
|
-
t.is(observed.length,
|
|
464
|
+
t.is(observed.length, 1)
|
|
460
465
|
let shape = observed[0]
|
|
461
|
-
t.is(shape.sides.length,
|
|
466
|
+
t.is(shape.sides.length, 4)
|
|
467
|
+
t.true(geometries.geom2.isA(shape))
|
|
462
468
|
|
|
463
469
|
observed = deserializer.deserialize({ output: 'geometry', target: 'path', addMetaData: false }, sourceSvg)
|
|
464
470
|
t.is(observed.length, 4)
|