@jscad/x3d-serializer 2.4.4 → 3.0.0-alpha.0

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/src/index.js CHANGED
@@ -1,20 +1,8 @@
1
- /*
2
- JSCAD Object to X3D (XML) Format Serialization
3
-
4
- ## License
1
+ import { generalize, geom2, geom3, path2, poly2, poly3 } from '@jscad/modeling'
5
2
 
6
- Copyright (c) 2018-2022 JSCAD Organization https://github.com/jscad
3
+ import { flatten } from '@jscad/array-utils'
7
4
 
8
- All code released under MIT license
9
-
10
- Notes:
11
- 1) geom2 conversion to:
12
- Polyline2D with lineSegment and Color
13
- 2) geom3 conversion to:
14
- IndexedTriangleSet with Coordinates and Colors
15
- 3) path2 conversion to:
16
- Polyline2D with lineSegment and Color
17
- */
5
+ import { stringify } from '@jscad/io-utils'
18
6
 
19
7
  /**
20
8
  * Serializer of JSCAD geometries to X3D source data (XML).
@@ -31,23 +19,14 @@ Notes:
31
19
  * const { serializer, mimeType } = require('@jscad/x3d-serializer')
32
20
  */
33
21
 
34
- const { geometries, modifiers } = require('@jscad/modeling')
35
- const { geom2, geom3, path2, poly2, poly3 } = geometries
36
-
37
- const { flatten } = require('@jscad/array-utils')
38
-
39
- const stringify = require('onml/lib/stringify')
40
-
41
- // http://www.web3d.org/x3d/content/X3dTooltips.html
42
- // http://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html#Meshes
43
- // https://x3dgraphics.com/examples/X3dForWebAuthors/Chapter13GeometryTrianglesQuadrilaterals/
44
-
45
22
  const mimeType = 'model/x3d+xml'
23
+ const defNames = new Map()
46
24
 
47
25
  /**
48
26
  * Serialize the give objects to X3D elements (XML).
49
27
  * @param {Object} options - options for serialization, REQUIRED
50
28
  * @param {Array} [options.color=[0,0,1,1]] - default color for objects
29
+ * @param {Number} [options.shininess=8/256] - x3d shininess for specular highlights
51
30
  * @param {Boolean} [options.smooth=false] - use averaged vertex normals
52
31
  * @param {Number} [options.decimals=1000] - multiplier before rounding to limit precision
53
32
  * @param {Boolean} [options.metadata=true] - add metadata to 3MF contents, such at CreationDate
@@ -63,6 +42,7 @@ const mimeType = 'model/x3d+xml'
63
42
  const serialize = (options, ...objects) => {
64
43
  const defaults = {
65
44
  color: [0, 0, 1, 1.0], // default colorRGBA specification
45
+ shininess: 8 / 256,
66
46
  smooth: false,
67
47
  decimals: 1000,
68
48
  metadata: true,
@@ -117,7 +97,7 @@ const convertObjects = (objects, options) => {
117
97
 
118
98
  if (geom3.isA(object)) {
119
99
  // convert to triangles
120
- object = modifiers.generalize({ snap: true, triangulate: true }, object)
100
+ object = generalize({ snap: true, triangulate: true }, object)
121
101
  const polygons = geom3.toPolygons(object)
122
102
  if (polygons.length > 0) {
123
103
  shapes.push(convertGeom3(object, options))
@@ -141,7 +121,7 @@ const convertObjects = (objects, options) => {
141
121
  const convertPath2 = (object, options) => {
142
122
  const points = path2.toPoints(object).slice()
143
123
  if (points.length > 1 && object.isClosed) points.push(points[0])
144
- const shape = ['Shape', {}, convertPolyline2D(poly2.create(points), options)]
124
+ const shape = ['Shape', shapeAttributes(object), convertPolyline2D(poly2.create(points), options)]
145
125
  if (object.color) {
146
126
  shape.push(convertAppearance(object, 'emissiveColor', options))
147
127
  }
@@ -156,7 +136,7 @@ const convertGeom2 = (object, options) => {
156
136
  const group = ['Group', {}]
157
137
  outlines.forEach((outline) => {
158
138
  if (outline.length > 1) outline.push(outline[0]) // close the outline for conversion
159
- const shape = ['Shape', {}, convertPolyline2D(poly2.create(outline), options)]
139
+ const shape = ['Shape', shapeAttributes(object), convertPolyline2D(poly2.create(outline), options)]
160
140
  if (object.color) {
161
141
  shape.push(convertAppearance(object, 'emissiveColor', options))
162
142
  }
@@ -165,11 +145,29 @@ const convertGeom2 = (object, options) => {
165
145
  return group
166
146
  }
167
147
 
148
+ /*
149
+ * generate attributes for Shape node
150
+ */
151
+
152
+ const shapeAttributes = (object, attributes = {}) => {
153
+ if (object.id) {
154
+ Object.assign(attributes, { DEF: checkDefName(object.id) })
155
+ }
156
+ return attributes
157
+ }
158
+
159
+ const checkDefName = (defName) => {
160
+ const count = defNames.get(defName) || 0
161
+ defNames.set(defName, count + 1)
162
+ if (count > 0) console.warn(`Warning: object.id set as DEF but not unique. ${defName} set ${count + 1} times.`)
163
+ return defName
164
+ }
165
+
168
166
  /*
169
167
  * Convert the given object (poly2) to X3D source
170
168
  */
171
169
  const convertPolyline2D = (object, options) => {
172
- const lineSegments = object.vertices.map((p) => `${p[0]} ${p[1]}`).join(' ')
170
+ const lineSegments = object.points.map((p) => `${p[0]} ${p[1]}`).join(' ')
173
171
  return ['Polyline2D', { lineSegments }]
174
172
  }
175
173
 
@@ -180,14 +178,20 @@ const convertAppearance = (object, colorField, options) => {
180
178
  const colorRGB = object.color.slice(0, 3)
181
179
  const color = colorRGB.join(' ')
182
180
  const transparency = roundToDecimals(1.0 - object.color[3], options)
183
- return ['Appearance', ['Material', { [colorField]: color, transparency }]]
181
+ const materialFields = { [colorField]: color, transparency }
182
+ if (colorField === 'diffuseColor') {
183
+ Object.assign(
184
+ materialFields,
185
+ { specularColor: '0.2 0.2 0.2', shininess: options.shininess })
186
+ }
187
+ return ['Appearance', ['Material', materialFields]]
184
188
  }
185
189
 
186
190
  /*
187
191
  * Convert the given object (geom3) to X3D source
188
192
  */
189
193
  const convertGeom3 = (object, options) => {
190
- const shape = ['Shape', {}, convertMesh(object, options)]
194
+ const shape = ['Shape', shapeAttributes(object), convertMesh(object, options)]
191
195
  let appearance = ['Appearance', {}, ['Material']]
192
196
  if (object.color) {
193
197
  appearance = convertAppearance(object, 'diffuseColor', options)
@@ -221,7 +225,7 @@ const convertToTriangles = (object, options) => {
221
225
  polygons.forEach((poly) => {
222
226
  const firstVertex = poly.vertices[0]
223
227
  for (let i = poly.vertices.length - 3; i >= 0; i--) {
224
- const triangle = poly3.fromPoints([
228
+ const triangle = poly3.create([
225
229
  firstVertex,
226
230
  poly.vertices[i + 1],
227
231
  poly.vertices[i + 2]
@@ -285,7 +289,7 @@ const polygons2coordinates = (polygons, options) => {
285
289
  return [indexList, pointList, colorList]
286
290
  }
287
291
 
288
- module.exports = {
289
- serialize,
290
- mimeType
292
+ export {
293
+ mimeType,
294
+ serialize
291
295
  }
@@ -1,13 +1,13 @@
1
- const test = require('ava')
1
+ import test from 'ava'
2
2
 
3
- const countOf = require('../../test/helpers/countOf')
3
+ import { countOf } from '../../test/helpers/countOf.js'
4
4
 
5
- const { colors, geometries, primitives } = require('@jscad/modeling')
5
+ import { colorize, geom2, rectangle } from '@jscad/modeling'
6
6
 
7
- const { serialize } = require('../src/index.js')
7
+ import { serialize } from '../src/index.js'
8
8
 
9
9
  test('serialize 2D geometry to X3D Polyline2D', (t) => {
10
- const shape1 = geometries.geom2.create()
10
+ const shape1 = geom2.create()
11
11
 
12
12
  let results = serialize({}, shape1)
13
13
  t.is(results.length, 1)
@@ -22,9 +22,9 @@ test('serialize 2D geometry to X3D Polyline2D', (t) => {
22
22
  t.is(countOf('Scene', obs), 2)
23
23
  t.is(countOf('Group', obs), 1)
24
24
 
25
- const shape2 = primitives.rectangle()
25
+ const shape2 = 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]
@@ -39,9 +39,9 @@ test('serialize 2D geometry to X3D Polyline2D', (t) => {
39
39
  t.is(countOf('Shape', obs), 2)
40
40
  t.is(countOf('Polyline2D', obs), 1)
41
41
 
42
- const shape3 = colors.colorize([0, 0, 0], shape2)
42
+ const shape3 = 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
-
@@ -1,15 +1,15 @@
1
- const test = require('ava')
1
+ import test from 'ava'
2
2
 
3
- const countOf = require('../../test/helpers/countOf')
3
+ import { countOf } from '../../test/helpers/countOf.js'
4
4
 
5
- const { colors, geometries, primitives, transforms } = require('@jscad/modeling')
5
+ import { center, colorize, cube, geom3 } from '@jscad/modeling'
6
6
 
7
- const serializer = require('../src/index.js')
7
+ import { serialize } from '../src/index.js'
8
8
 
9
9
  test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
10
- const geom1 = geometries.geom3.create()
10
+ const g1 = geom3.create()
11
11
 
12
- let results = serializer.serialize({}, geom1)
12
+ let results = serialize({}, g1)
13
13
  t.is(results.length, 1)
14
14
 
15
15
  let obs = results[0]
@@ -21,9 +21,9 @@ test('serialize 3D geometry to X3D IndexedTriangleSet', (t) => {
21
21
  t.is(countOf('Created by JSCAD', obs), 1)
22
22
  t.is(countOf('Scene', obs), 2)
23
23
 
24
- const geom2 = primitives.cube()
24
+ const g2 = cube()
25
25
 
26
- results = serializer.serialize({metadata: false}, geom2)
26
+ results = serialize({ metadata: false }, g2)
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
- const geom3 = colors.colorize([0.5, 1, 0.5, 1.0], transforms.center({ relativeTo: [5, 5, 5] }, primitives.cube()))
44
+ const g3 = colorize([0.5, 1, 0.5, 1.0], center({ relativeTo: [5, 5, 5] }, cube()))
45
+ g2.id = g3.id = 'g23'
44
46
 
45
- results = serializer.serialize({metadata: false}, geom2, geom3)
47
+ results = serialize({ metadata: false }, g2, g3)
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
+ })
@@ -1,15 +1,15 @@
1
- const test = require('ava')
1
+ import test from 'ava'
2
2
 
3
- const countOf = require('../../test/helpers/countOf')
3
+ import { countOf } from '../../test/helpers/countOf.js'
4
4
 
5
- const { colors, geometries, primitives } = require('@jscad/modeling')
5
+ import { arc, colorize, path2 } from '@jscad/modeling'
6
6
 
7
- const { serialize } = require('../src/index.js')
7
+ import { serialize } from '../src/index.js'
8
8
 
9
9
  test('serialize 2D path to X3D Polyline2D', (t) => {
10
- const path1 = geometries.path2.create()
10
+ const p1 = path2.create()
11
11
 
12
- let results = serialize({}, path1)
12
+ let results = serialize({}, p1)
13
13
  t.is(results.length, 1)
14
14
 
15
15
  let obs = results[0]
@@ -20,9 +20,9 @@ test('serialize 2D path to X3D Polyline2D', (t) => {
20
20
  t.is(countOf('content', obs), 3)
21
21
  t.is(countOf('Created by JSCAD', obs), 1)
22
22
 
23
- const path2 = primitives.arc({ center: [5, 5], endAngle: 45, segments: 16 })
23
+ const p2 = arc({ center: [5, 5], endAngle: 45, segments: 16 })
24
24
 
25
- results = serialize({metadata: false}, path2)
25
+ results = serialize({ metadata: false }, p2)
26
26
  t.is(results.length, 1)
27
27
 
28
28
  obs = results[0]
@@ -33,9 +33,9 @@ test('serialize 2D path to X3D Polyline2D', (t) => {
33
33
  t.is(countOf('Polyline2D', obs), 1)
34
34
  t.is(countOf('lineSegments', obs), 1)
35
35
 
36
- const path3 = colors.colorize([0, 0, 0], path2)
36
+ const p3 = colorize([0, 0, 0], p2)
37
37
 
38
- results = serialize({metadata: false}, path2, path3)
38
+ results = serialize({ metadata: false }, p2, p3)
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
-