@jscad/x3d-serializer 2.4.2 → 2.4.4
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 +20 -0
- package/package.json +3 -3
- package/src/index.js +33 -22
- package/tests/geom2ToX3D.test.js +2 -2
- package/tests/geom3ToX3D.test.js +10 -7
- package/tests/path2ToX3D.test.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
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.4.4](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/x3d-serializer@2.4.3...@jscad/x3d-serializer@2.4.4) (2023-04-30)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **x3d-serializer:** corrected color and transparency conversions ([cc99548](https://github.com/jscad/OpenJSCAD.org/commit/cc9954853c30c6a82fcd26cda686e7f51f9fa304))
|
|
12
|
+
* **x3d-serializer:** corrected colors, orientation of scene to Y up, and added new option for smoothing ([3444e2d](https://github.com/jscad/OpenJSCAD.org/commit/3444e2d462446694e62da71b130dfb4e56e92f82))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## [2.4.3](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/x3d-serializer@2.4.2...@jscad/x3d-serializer@2.4.3) (2022-11-26)
|
|
19
|
+
|
|
20
|
+
**Note:** Version bump only for package @jscad/x3d-serializer
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
## [2.4.2](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/x3d-serializer@2.4.1...@jscad/x3d-serializer@2.4.2) (2022-08-21)
|
|
7
27
|
|
|
8
28
|
**Note:** Version bump only for package @jscad/x3d-serializer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/x3d-serializer",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.4",
|
|
4
4
|
"description": "X3D Serializer for JSCAD",
|
|
5
5
|
"homepage": "https://openjscad.xyz/",
|
|
6
6
|
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@jscad/array-utils": "2.1.4",
|
|
36
|
-
"@jscad/modeling": "2.
|
|
36
|
+
"@jscad/modeling": "2.11.1",
|
|
37
37
|
"onml": "1.3.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"ava": "3.15.0",
|
|
41
41
|
"nyc": "15.1.0"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "4313974b50957018d2edd010e3a251f59bea46a4"
|
|
44
44
|
}
|
package/src/index.js
CHANGED
|
@@ -34,7 +34,7 @@ Notes:
|
|
|
34
34
|
const { geometries, modifiers } = require('@jscad/modeling')
|
|
35
35
|
const { geom2, geom3, path2, poly2, poly3 } = geometries
|
|
36
36
|
|
|
37
|
-
const { flatten
|
|
37
|
+
const { flatten } = require('@jscad/array-utils')
|
|
38
38
|
|
|
39
39
|
const stringify = require('onml/lib/stringify')
|
|
40
40
|
|
|
@@ -48,6 +48,8 @@ const mimeType = 'model/x3d+xml'
|
|
|
48
48
|
* Serialize the give objects to X3D elements (XML).
|
|
49
49
|
* @param {Object} options - options for serialization, REQUIRED
|
|
50
50
|
* @param {Array} [options.color=[0,0,1,1]] - default color for objects
|
|
51
|
+
* @param {Boolean} [options.smooth=false] - use averaged vertex normals
|
|
52
|
+
* @param {Number} [options.decimals=1000] - multiplier before rounding to limit precision
|
|
51
53
|
* @param {Boolean} [options.metadata=true] - add metadata to 3MF contents, such at CreationDate
|
|
52
54
|
* @param {String} [options.unit='millimeter'] - unit of design; millimeter, inch, feet, meter or micrometer
|
|
53
55
|
* @param {Function} [options.statusCallback] - call back function for progress ({ progress: 0-100 })
|
|
@@ -61,6 +63,7 @@ const mimeType = 'model/x3d+xml'
|
|
|
61
63
|
const serialize = (options, ...objects) => {
|
|
62
64
|
const defaults = {
|
|
63
65
|
color: [0, 0, 1, 1.0], // default colorRGBA specification
|
|
66
|
+
smooth: false,
|
|
64
67
|
decimals: 1000,
|
|
65
68
|
metadata: true,
|
|
66
69
|
unit: 'millimeter', // millimeter, inch, feet, meter or micrometer
|
|
@@ -80,20 +83,20 @@ const serialize = (options, ...objects) => {
|
|
|
80
83
|
let body = ['X3D',
|
|
81
84
|
{
|
|
82
85
|
profile: 'Interchange',
|
|
83
|
-
version: '
|
|
86
|
+
version: '3.3',
|
|
84
87
|
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema-instance',
|
|
85
|
-
'xsd:noNamespaceSchemaLocation': 'http://www.web3d.org/specifications/x3d-
|
|
88
|
+
'xsd:noNamespaceSchemaLocation': 'http://www.web3d.org/specifications/x3d-3.3.xsd'
|
|
86
89
|
}
|
|
87
90
|
]
|
|
88
91
|
if (options.metadata) {
|
|
89
92
|
body.push(['head', {},
|
|
90
93
|
['meta', { name: 'creator', content: 'Created by JSCAD' }],
|
|
91
94
|
['meta', { name: 'reference', content: 'https://www.openjscad.xyz' }],
|
|
92
|
-
['meta', { name: 'created', content: new Date().toISOString()}]
|
|
95
|
+
['meta', { name: 'created', content: new Date().toISOString() }]
|
|
93
96
|
])
|
|
94
97
|
} else {
|
|
95
98
|
body.push(['head', {},
|
|
96
|
-
['meta', { name: 'creator', content: 'Created by JSCAD' }]
|
|
99
|
+
['meta', { name: 'creator', content: 'Created by JSCAD' }]
|
|
97
100
|
])
|
|
98
101
|
}
|
|
99
102
|
body = body.concat(convertObjects(objects, options))
|
|
@@ -108,7 +111,6 @@ ${stringify(body, 2)}`
|
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
const convertObjects = (objects, options) => {
|
|
111
|
-
let scene = ['Scene', {}]
|
|
112
114
|
const shapes = []
|
|
113
115
|
objects.forEach((object, i) => {
|
|
114
116
|
options.statusCallback && options.statusCallback({ progress: 100 * i / objects.length })
|
|
@@ -128,7 +130,8 @@ const convertObjects = (objects, options) => {
|
|
|
128
130
|
shapes.push(convertPath2(object, options))
|
|
129
131
|
}
|
|
130
132
|
})
|
|
131
|
-
|
|
133
|
+
const transform = ['Transform', { rotation: '1 0 0 -1.5708' }, ...shapes]
|
|
134
|
+
const scene = ['Scene', {}, transform]
|
|
132
135
|
return [scene]
|
|
133
136
|
}
|
|
134
137
|
|
|
@@ -138,9 +141,9 @@ const convertObjects = (objects, options) => {
|
|
|
138
141
|
const convertPath2 = (object, options) => {
|
|
139
142
|
const points = path2.toPoints(object).slice()
|
|
140
143
|
if (points.length > 1 && object.isClosed) points.push(points[0])
|
|
141
|
-
shape = ['Shape', {}, convertPolyline2D(poly2.create(points), options)]
|
|
144
|
+
const shape = ['Shape', {}, convertPolyline2D(poly2.create(points), options)]
|
|
142
145
|
if (object.color) {
|
|
143
|
-
shape.push(convertAppearance(object, options))
|
|
146
|
+
shape.push(convertAppearance(object, 'emissiveColor', options))
|
|
144
147
|
}
|
|
145
148
|
return shape
|
|
146
149
|
}
|
|
@@ -155,7 +158,7 @@ const convertGeom2 = (object, options) => {
|
|
|
155
158
|
if (outline.length > 1) outline.push(outline[0]) // close the outline for conversion
|
|
156
159
|
const shape = ['Shape', {}, convertPolyline2D(poly2.create(outline), options)]
|
|
157
160
|
if (object.color) {
|
|
158
|
-
shape.push(convertAppearance(object, options))
|
|
161
|
+
shape.push(convertAppearance(object, 'emissiveColor', options))
|
|
159
162
|
}
|
|
160
163
|
group.push(shape)
|
|
161
164
|
})
|
|
@@ -167,13 +170,17 @@ const convertGeom2 = (object, options) => {
|
|
|
167
170
|
*/
|
|
168
171
|
const convertPolyline2D = (object, options) => {
|
|
169
172
|
const lineSegments = object.vertices.map((p) => `${p[0]} ${p[1]}`).join(' ')
|
|
170
|
-
return ['Polyline2D', {lineSegments}]
|
|
173
|
+
return ['Polyline2D', { lineSegments }]
|
|
171
174
|
}
|
|
172
175
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
/*
|
|
177
|
+
* Convert color to Appearance
|
|
178
|
+
*/
|
|
179
|
+
const convertAppearance = (object, colorField, options) => {
|
|
180
|
+
const colorRGB = object.color.slice(0, 3)
|
|
181
|
+
const color = colorRGB.join(' ')
|
|
182
|
+
const transparency = roundToDecimals(1.0 - object.color[3], options)
|
|
183
|
+
return ['Appearance', ['Material', { [colorField]: color, transparency }]]
|
|
177
184
|
}
|
|
178
185
|
|
|
179
186
|
/*
|
|
@@ -181,9 +188,11 @@ const convertAppearance = (object, options) => {
|
|
|
181
188
|
*/
|
|
182
189
|
const convertGeom3 = (object, options) => {
|
|
183
190
|
const shape = ['Shape', {}, convertMesh(object, options)]
|
|
191
|
+
let appearance = ['Appearance', {}, ['Material']]
|
|
184
192
|
if (object.color) {
|
|
185
|
-
|
|
193
|
+
appearance = convertAppearance(object, 'diffuseColor', options)
|
|
186
194
|
}
|
|
195
|
+
shape.push(appearance)
|
|
187
196
|
return shape
|
|
188
197
|
}
|
|
189
198
|
|
|
@@ -197,10 +206,10 @@ const convertMesh = (object, options) => {
|
|
|
197
206
|
|
|
198
207
|
const faceset = [
|
|
199
208
|
'IndexedTriangleSet',
|
|
200
|
-
{ ccw: 'true', colorPerVertex: 'false', solid: 'false', index: indexList },
|
|
201
|
-
['Coordinate', { point: pointList }]
|
|
209
|
+
{ ccw: 'true', colorPerVertex: 'false', normalPerVertex: options.smooth, solid: 'false', index: indexList },
|
|
210
|
+
['Coordinate', { point: pointList }]
|
|
202
211
|
]
|
|
203
|
-
if (!
|
|
212
|
+
if (!object.color) {
|
|
204
213
|
faceset.push(['Color', { color: colorList }])
|
|
205
214
|
}
|
|
206
215
|
return faceset
|
|
@@ -236,6 +245,8 @@ const convertToColor = (polygon, options) => {
|
|
|
236
245
|
return `${color[0]} ${color[1]} ${color[2]}`
|
|
237
246
|
}
|
|
238
247
|
|
|
248
|
+
const roundToDecimals = (float, options) => Math.round(float * options.decimals) / options.decimals
|
|
249
|
+
|
|
239
250
|
/*
|
|
240
251
|
* This function converts the given polygons into three lists
|
|
241
252
|
* - indexList : index of each vertex in the triangle (tuples)
|
|
@@ -257,9 +268,9 @@ const polygons2coordinates = (polygons, options) => {
|
|
|
257
268
|
|
|
258
269
|
// add the vertex to the list of points (and index) if not found
|
|
259
270
|
if (!vertexTagToCoordIndexMap.has(id)) {
|
|
260
|
-
const x =
|
|
261
|
-
const y =
|
|
262
|
-
const z =
|
|
271
|
+
const x = roundToDecimals(vertex[0], options)
|
|
272
|
+
const y = roundToDecimals(vertex[1], options)
|
|
273
|
+
const z = roundToDecimals(vertex[2], options)
|
|
263
274
|
pointList.push(`${x} ${y} ${z}`)
|
|
264
275
|
vertexTagToCoordIndexMap.set(id, pointList.length - 1)
|
|
265
276
|
}
|
package/tests/geom2ToX3D.test.js
CHANGED
|
@@ -58,7 +58,7 @@ test('serialize 2D geometry to X3D Polyline2D', (t) => {
|
|
|
58
58
|
// for color
|
|
59
59
|
t.is(countOf('Appearance', obs), 2)
|
|
60
60
|
t.is(countOf('Material', obs), 1)
|
|
61
|
-
t.is(countOf('diffuseColor', obs),
|
|
61
|
+
t.is(countOf('diffuseColor', obs), 0)
|
|
62
62
|
t.is(countOf('emissiveColor', obs), 1)
|
|
63
63
|
|
|
64
64
|
|
|
@@ -79,7 +79,7 @@ test('serialize 2D geometry to X3D Polyline2D', (t) => {
|
|
|
79
79
|
// for color
|
|
80
80
|
t.is(countOf('Appearance', obs), 2)
|
|
81
81
|
t.is(countOf('Material', obs), 1)
|
|
82
|
-
t.is(countOf('diffuseColor', obs),
|
|
82
|
+
t.is(countOf('diffuseColor', obs), 0)
|
|
83
83
|
t.is(countOf('emissiveColor', obs), 1)
|
|
84
84
|
})
|
|
85
85
|
|
package/tests/geom3ToX3D.test.js
CHANGED
|
@@ -19,7 +19,7 @@ test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
|
|
|
19
19
|
t.is(countOf('name', obs), 3)
|
|
20
20
|
t.is(countOf('content', obs), 3)
|
|
21
21
|
t.is(countOf('Created by JSCAD', obs), 1)
|
|
22
|
-
t.is(countOf('Scene', obs),
|
|
22
|
+
t.is(countOf('Scene', obs), 2)
|
|
23
23
|
|
|
24
24
|
const geom2 = primitives.cube()
|
|
25
25
|
|
|
@@ -34,12 +34,12 @@ test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
|
|
|
34
34
|
t.is(countOf('content', obs), 1)
|
|
35
35
|
t.is(countOf('Created by JSCAD', obs), 1)
|
|
36
36
|
t.is(countOf('Scene', obs), 2)
|
|
37
|
+
t.is(countOf('Transform', obs), 2)
|
|
37
38
|
t.is(countOf('Shape', obs), 2)
|
|
38
39
|
t.is(countOf('IndexedTriangleSet', obs), 2)
|
|
39
40
|
t.is(countOf('Coordinate', obs), 1)
|
|
40
41
|
t.is(countOf('Color', obs), 1)
|
|
41
42
|
|
|
42
|
-
|
|
43
43
|
const geom3 = colors.colorize([0.5, 1, 0.5, 1.0], transforms.center({ relativeTo: [5, 5, 5] }, primitives.cube()))
|
|
44
44
|
|
|
45
45
|
results = serializer.serialize({metadata: false}, geom2, geom3)
|
|
@@ -57,8 +57,11 @@ test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
|
|
|
57
57
|
t.is(countOf('IndexedTriangleSet', obs), 4)
|
|
58
58
|
t.is(countOf('Coordinate', obs), 2)
|
|
59
59
|
// for color
|
|
60
|
-
t.is(countOf('Color', obs),
|
|
61
|
-
t.is(countOf('Appearance', obs),
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
t.is(countOf('<Color', obs), 1)
|
|
61
|
+
t.is(countOf('Appearance', obs), 4)
|
|
62
|
+
// for RGB
|
|
63
|
+
t.is(countOf('diffuseColor="0.5 1 0.5"', obs), 1)
|
|
64
|
+
// for facets
|
|
65
|
+
t.is(countOf('normalPerVertex="false"', obs), 2)
|
|
66
|
+
|
|
67
|
+
})
|
package/tests/path2ToX3D.test.js
CHANGED
|
@@ -48,7 +48,7 @@ test('serialize 2D path to X3D Polyline2D', (t) => {
|
|
|
48
48
|
// and color on path3
|
|
49
49
|
t.is(countOf('Appearance', obs), 2)
|
|
50
50
|
t.is(countOf('Material', obs), 1)
|
|
51
|
-
t.is(countOf('diffuseColor', obs),
|
|
51
|
+
t.is(countOf('diffuseColor', obs), 0)
|
|
52
52
|
t.is(countOf('emissiveColor', obs), 1)
|
|
53
53
|
|
|
54
54
|
})
|