@jscad/x3d-serializer 2.4.4 → 2.4.5

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 CHANGED
@@ -3,6 +3,17 @@
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.5](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/x3d-serializer@2.4.4...@jscad/x3d-serializer@2.4.5) (2023-06-27)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **x3d-serializer:** added specular highlights and conversion of shape names ([ba26567](https://github.com/jscad/OpenJSCAD.org/commit/ba26567f207a3e7529778ec89436956cf03592bf))
12
+
13
+
14
+
15
+
16
+
6
17
  ## [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
18
 
8
19
 
package/README.md CHANGED
@@ -27,7 +27,10 @@ The serialization of the following geometries are possible.
27
27
  - serialization of 2D geometries (geom2) to X3D Polyline2D
28
28
  - serialization of 2D paths (path2) to X3D Polyline2D
29
29
 
30
- Material (color) is added to X3D shapes when found on the geometry.
30
+ The id attribute is used as the DEF name for the generated X3D shape when found on a geometry.
31
+ Material (color) is added to X3D shapes when found on a geometry.
32
+
33
+ All shapes are wrapped in a rotation transform to align the positive Z direction of JSCAD with the vertical up direction in X3D.
31
34
 
32
35
  ## Table of Contents
33
36
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jscad/x3d-serializer",
3
- "version": "2.4.4",
3
+ "version": "2.4.5",
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.11.1",
36
+ "@jscad/modeling": "2.12.0",
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": "4313974b50957018d2edd010e3a251f59bea46a4"
43
+ "gitHead": "e269f212db5a00cda740d2f7ad3e5206d1eb839f"
44
44
  }
package/src/index.js CHANGED
@@ -43,11 +43,13 @@ const stringify = require('onml/lib/stringify')
43
43
  // https://x3dgraphics.com/examples/X3dForWebAuthors/Chapter13GeometryTrianglesQuadrilaterals/
44
44
 
45
45
  const mimeType = 'model/x3d+xml'
46
+ const defNames = new Map()
46
47
 
47
48
  /**
48
49
  * Serialize the give objects to X3D elements (XML).
49
50
  * @param {Object} options - options for serialization, REQUIRED
50
51
  * @param {Array} [options.color=[0,0,1,1]] - default color for objects
52
+ * @param {Number} [options.shininess=8/256] - x3d shininess for specular highlights
51
53
  * @param {Boolean} [options.smooth=false] - use averaged vertex normals
52
54
  * @param {Number} [options.decimals=1000] - multiplier before rounding to limit precision
53
55
  * @param {Boolean} [options.metadata=true] - add metadata to 3MF contents, such at CreationDate
@@ -63,6 +65,7 @@ const mimeType = 'model/x3d+xml'
63
65
  const serialize = (options, ...objects) => {
64
66
  const defaults = {
65
67
  color: [0, 0, 1, 1.0], // default colorRGBA specification
68
+ shininess: 8 / 256,
66
69
  smooth: false,
67
70
  decimals: 1000,
68
71
  metadata: true,
@@ -141,7 +144,7 @@ const convertObjects = (objects, options) => {
141
144
  const convertPath2 = (object, options) => {
142
145
  const points = path2.toPoints(object).slice()
143
146
  if (points.length > 1 && object.isClosed) points.push(points[0])
144
- const shape = ['Shape', {}, convertPolyline2D(poly2.create(points), options)]
147
+ const shape = ['Shape', shapeAttributes(object), convertPolyline2D(poly2.create(points), options)]
145
148
  if (object.color) {
146
149
  shape.push(convertAppearance(object, 'emissiveColor', options))
147
150
  }
@@ -156,7 +159,7 @@ const convertGeom2 = (object, options) => {
156
159
  const group = ['Group', {}]
157
160
  outlines.forEach((outline) => {
158
161
  if (outline.length > 1) outline.push(outline[0]) // close the outline for conversion
159
- const shape = ['Shape', {}, convertPolyline2D(poly2.create(outline), options)]
162
+ const shape = ['Shape', shapeAttributes(object), convertPolyline2D(poly2.create(outline), options)]
160
163
  if (object.color) {
161
164
  shape.push(convertAppearance(object, 'emissiveColor', options))
162
165
  }
@@ -165,6 +168,24 @@ const convertGeom2 = (object, options) => {
165
168
  return group
166
169
  }
167
170
 
171
+ /*
172
+ * generate attributes for Shape node
173
+ */
174
+
175
+ const shapeAttributes = (object, attributes = {}) => {
176
+ if (object.id) {
177
+ Object.assign(attributes, { DEF: checkDefName(object.id) })
178
+ }
179
+ return attributes
180
+ }
181
+
182
+ const checkDefName = (defName) => {
183
+ const count = defNames.get(defName) || 0
184
+ defNames.set(defName, count + 1)
185
+ if (count > 0) console.warn(`Warning: object.id set as DEF but not unique. ${defName} set ${count + 1} times.`)
186
+ return defName
187
+ }
188
+
168
189
  /*
169
190
  * Convert the given object (poly2) to X3D source
170
191
  */
@@ -180,14 +201,20 @@ const convertAppearance = (object, colorField, options) => {
180
201
  const colorRGB = object.color.slice(0, 3)
181
202
  const color = colorRGB.join(' ')
182
203
  const transparency = roundToDecimals(1.0 - object.color[3], options)
183
- return ['Appearance', ['Material', { [colorField]: color, transparency }]]
204
+ const materialFields = { [colorField]: color, transparency }
205
+ if (colorField === 'diffuseColor') {
206
+ Object.assign(
207
+ materialFields,
208
+ { specularColor: '0.2 0.2 0.2', shininess: options.shininess })
209
+ }
210
+ return ['Appearance', ['Material', materialFields]]
184
211
  }
185
212
 
186
213
  /*
187
214
  * Convert the given object (geom3) to X3D source
188
215
  */
189
216
  const convertGeom3 = (object, options) => {
190
- const shape = ['Shape', {}, convertMesh(object, options)]
217
+ const shape = ['Shape', shapeAttributes(object), convertMesh(object, options)]
191
218
  let appearance = ['Appearance', {}, ['Material']]
192
219
  if (object.color) {
193
220
  appearance = convertAppearance(object, 'diffuseColor', options)
@@ -24,7 +24,7 @@ test('serialize 2D geometry to X3D Polyline2D', (t) => {
24
24
 
25
25
  const shape2 = primitives.rectangle()
26
26
 
27
- results = serialize({metadata: false}, shape2)
27
+ results = serialize({ metadata: false }, shape2)
28
28
  t.is(results.length, 1)
29
29
 
30
30
  obs = results[0]
@@ -41,7 +41,7 @@ test('serialize 2D geometry to X3D Polyline2D', (t) => {
41
41
 
42
42
  const shape3 = colors.colorize([0, 0, 0], shape2)
43
43
 
44
- results = serialize({metadata: false}, shape3)
44
+ results = serialize({ metadata: false }, shape3)
45
45
  t.is(results.length, 1)
46
46
 
47
47
  obs = results[0]
@@ -61,8 +61,7 @@ test('serialize 2D geometry to X3D Polyline2D', (t) => {
61
61
  t.is(countOf('diffuseColor', obs), 0)
62
62
  t.is(countOf('emissiveColor', obs), 1)
63
63
 
64
-
65
- results = serialize({metadata: false}, shape2, shape3)
64
+ results = serialize({ metadata: false }, shape2, shape3)
66
65
  t.is(results.length, 1)
67
66
 
68
67
  obs = results[0]
@@ -80,6 +79,6 @@ test('serialize 2D geometry to X3D Polyline2D', (t) => {
80
79
  t.is(countOf('Appearance', obs), 2)
81
80
  t.is(countOf('Material', obs), 1)
82
81
  t.is(countOf('diffuseColor', obs), 0)
82
+ t.is(countOf('specularColor', obs), 0)
83
83
  t.is(countOf('emissiveColor', obs), 1)
84
84
  })
85
-
@@ -23,7 +23,7 @@ test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
23
23
 
24
24
  const geom2 = primitives.cube()
25
25
 
26
- results = serializer.serialize({metadata: false}, geom2)
26
+ results = serializer.serialize({ metadata: false }, geom2)
27
27
  t.is(results.length, 1)
28
28
 
29
29
  obs = results[0]
@@ -36,13 +36,15 @@ test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
36
36
  t.is(countOf('Scene', obs), 2)
37
37
  t.is(countOf('Transform', obs), 2)
38
38
  t.is(countOf('Shape', obs), 2)
39
+ t.is(countOf('DEF', obs), 0)
39
40
  t.is(countOf('IndexedTriangleSet', obs), 2)
40
41
  t.is(countOf('Coordinate', obs), 1)
41
42
  t.is(countOf('Color', obs), 1)
42
43
 
43
44
  const geom3 = colors.colorize([0.5, 1, 0.5, 1.0], transforms.center({ relativeTo: [5, 5, 5] }, primitives.cube()))
45
+ geom2.id = geom3.id = 'g23'
44
46
 
45
- results = serializer.serialize({metadata: false}, geom2, geom3)
47
+ results = serializer.serialize({ metadata: false }, geom2, geom3)
46
48
  t.is(results.length, 1)
47
49
 
48
50
  obs = results[0]
@@ -54,6 +56,7 @@ test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
54
56
  t.is(countOf('Created by JSCAD', obs), 1)
55
57
  t.is(countOf('Scene', obs), 2)
56
58
  t.is(countOf('Shape', obs), 4)
59
+ t.is(countOf('DEF', obs), 2)
57
60
  t.is(countOf('IndexedTriangleSet', obs), 4)
58
61
  t.is(countOf('Coordinate', obs), 2)
59
62
  // for color
@@ -61,7 +64,7 @@ test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
61
64
  t.is(countOf('Appearance', obs), 4)
62
65
  // for RGB
63
66
  t.is(countOf('diffuseColor="0.5 1 0.5"', obs), 1)
67
+ t.is(countOf('specularColor', obs), 1)
64
68
  // for facets
65
69
  t.is(countOf('normalPerVertex="false"', obs), 2)
66
-
67
- })
70
+ })
@@ -22,7 +22,7 @@ test('serialize 2D path to X3D Polyline2D', (t) => {
22
22
 
23
23
  const path2 = primitives.arc({ center: [5, 5], endAngle: 45, segments: 16 })
24
24
 
25
- results = serialize({metadata: false}, path2)
25
+ results = serialize({ metadata: false }, path2)
26
26
  t.is(results.length, 1)
27
27
 
28
28
  obs = results[0]
@@ -35,7 +35,7 @@ test('serialize 2D path to X3D Polyline2D', (t) => {
35
35
 
36
36
  const path3 = colors.colorize([0, 0, 0], path2)
37
37
 
38
- results = serialize({metadata: false}, path2, path3)
38
+ results = serialize({ metadata: false }, path2, path3)
39
39
  t.is(results.length, 1)
40
40
 
41
41
  obs = results[0]
@@ -50,6 +50,4 @@ test('serialize 2D path to X3D Polyline2D', (t) => {
50
50
  t.is(countOf('Material', obs), 1)
51
51
  t.is(countOf('diffuseColor', obs), 0)
52
52
  t.is(countOf('emissiveColor', obs), 1)
53
-
54
53
  })
55
-