@jscad/3mf-serializer 2.1.1
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 +22 -0
- package/README.md +54 -0
- package/package.json +39 -0
- package/src/index.js +256 -0
- package/tests/serialize.test.js +335 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [2.1.1](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/3mf-serializer@2.1.0...@jscad/3mf-serializer@2.1.1) (2022-04-03)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @jscad/3mf-serializer
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# 2.1.0 (2022-04-03)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **3mf-serializer:** new serializer from JSCAD geometry to 3MF packages ([6b51aed](https://github.com/jscad/OpenJSCAD.org/commit/6b51aed63ee40674822a04ced773564552689763))
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
The MIT License (MIT)
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2017-2021 JSCAD Organization
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
## @jscad/3mf-serializer
|
|
2
|
+
|
|
3
|
+
> Serializer of JSCAD geometries to 3MF shapes
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/%40jscad%2F3mf-serializer)
|
|
6
|
+
[](https://travis-ci.org/jscad/3mf-serializer)
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
This serializer outputs a 'blobable' array of data from one or more JSCAD geometries. Only XML output is supported.
|
|
11
|
+
The array of data can either be used to create a Blob (`new Blob(blobable)`), or converted to a Node.js buffer.
|
|
12
|
+
|
|
13
|
+
The serialization of the following geometries are possible.
|
|
14
|
+
- serialization of 3D geometry (geom3) to 3MF mesh(s)
|
|
15
|
+
|
|
16
|
+
In addition, both color and name attributes are converted to 3MF attributes if found on the JSCAD geometry.
|
|
17
|
+
|
|
18
|
+
## Table of Contents
|
|
19
|
+
|
|
20
|
+
- [Installation](#installation)
|
|
21
|
+
- [Usage](#usage)
|
|
22
|
+
- [Contribute](#contribute)
|
|
23
|
+
- [License](#license)
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
npm install @jscad/3mf-serializer
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
const { serialize } = require('@jscad/3mf-serializer')
|
|
35
|
+
|
|
36
|
+
const rawData = serialize({unit: inch}, geometry)
|
|
37
|
+
|
|
38
|
+
//in browser (with browserify etc)
|
|
39
|
+
const blob = new Blob(rawData)
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Contribute
|
|
44
|
+
|
|
45
|
+
For questions about the API, please contact the [User Group](https://openjscad.xyz/forum.html)
|
|
46
|
+
|
|
47
|
+
Please see the README information of the OpenJSCAD.org project for how to submit bug reports or changes.
|
|
48
|
+
|
|
49
|
+
Small Note: If editing this README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
|
|
50
|
+
|
|
51
|
+
## License
|
|
52
|
+
|
|
53
|
+
[The MIT License (MIT)](./LICENSE)
|
|
54
|
+
(unless specified otherwise)
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jscad/3mf-serializer",
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "3MF serializer for JSCAD project",
|
|
5
|
+
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"coverage": "nyc --reporter=html --reporter=text npm test",
|
|
9
|
+
"test": "ava --concurrency 3 --verbose --timeout 40000 './tests/*.test.js'"
|
|
10
|
+
},
|
|
11
|
+
"contributors": [
|
|
12
|
+
{
|
|
13
|
+
"name": "z3dev",
|
|
14
|
+
"url": "http://www.z3d.jp"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"openjscad",
|
|
19
|
+
"jscad",
|
|
20
|
+
"export",
|
|
21
|
+
"serializer",
|
|
22
|
+
"3mf"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@jscad/array-utils": "2.1.3",
|
|
30
|
+
"@jscad/modeling": "2.9.2",
|
|
31
|
+
"fflate": "0.7.3",
|
|
32
|
+
"onml": "1.2.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"ava": "3.15.0",
|
|
36
|
+
"nyc": "15.1.0"
|
|
37
|
+
},
|
|
38
|
+
"gitHead": "0cebde0166c104e3c08cc05d2c03d9defc7eca26"
|
|
39
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/*
|
|
2
|
+
JSCAD Object to 3MF (XML) Format Serialization
|
|
3
|
+
|
|
4
|
+
## License
|
|
5
|
+
|
|
6
|
+
Copyright (c) 2022 JSCAD Organization https://github.com/jscad
|
|
7
|
+
|
|
8
|
+
All code released under MIT license
|
|
9
|
+
|
|
10
|
+
Notes:
|
|
11
|
+
1) geom2 conversion to:
|
|
12
|
+
none
|
|
13
|
+
2) geom3 conversion to:
|
|
14
|
+
mesh
|
|
15
|
+
3) path2 conversion to:
|
|
16
|
+
none
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Serializer of JSCAD geometries to 3D manufacturing format (XML)
|
|
21
|
+
*
|
|
22
|
+
* The serialization of the following geometries are possible.
|
|
23
|
+
* - serialization of 3D geometry (geom3) to 3MF object (a unique mesh containing both vertices and triangles)
|
|
24
|
+
*
|
|
25
|
+
* Colors are added to base materials when found on the 3D geometry, i.e. attribute color.
|
|
26
|
+
* Names are added to meshs when found on the 3D geometry, i.e. attribute name.
|
|
27
|
+
*
|
|
28
|
+
* @module io/3mf-serializer
|
|
29
|
+
* @example
|
|
30
|
+
* const { serializer, mimeType } = require('@jscad/3mf-serializer')
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
const zipSync = require('fflate').zipSync
|
|
35
|
+
const strToU8 = require('fflate').strToU8
|
|
36
|
+
|
|
37
|
+
const stringify = require('onml/lib/stringify')
|
|
38
|
+
|
|
39
|
+
const { colors, geometries, modifiers } = require('@jscad/modeling')
|
|
40
|
+
const { flatten, toArray } = require('@jscad/array-utils')
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
const mimeType = 'model/3mf'
|
|
44
|
+
const fileExtension = '3mf'
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Serialize the give objects to 3MF contents (XML) or 3MF packaging (OPC).
|
|
48
|
+
* @see https://3mf.io/specification/
|
|
49
|
+
* @param {Object} [options] - options for serialization
|
|
50
|
+
* @param {String} [options.unit='millimeter'] - unit of design; millimeter, inch, feet, meter or micrometer
|
|
51
|
+
* @param {Boolean} [options.metadata=true] - add metadata to 3MF contents, such at CreationDate
|
|
52
|
+
* @param {Array} [options.defaultcolor=[0,0,0,1]] - default color for objects
|
|
53
|
+
* @param {Boolean} [options.compress=true] - package and compress the contents
|
|
54
|
+
* @param {Object|Array} objects - objects to serialize into 3D manufacturing format
|
|
55
|
+
* @returns {Array} serialized contents, 3MF contents (XML) or 3MF packaging (ZIP)
|
|
56
|
+
* @example
|
|
57
|
+
* const geometry = primitives.cube()
|
|
58
|
+
* const package = serializer({unit: 'meter'}, geometry) // 3MF package, ZIP format
|
|
59
|
+
*/
|
|
60
|
+
const serialize = (options, ...objects) => {
|
|
61
|
+
const defaults = {
|
|
62
|
+
unit: 'millimeter', // micron, millimeter, centimeter, inch, foot, meter
|
|
63
|
+
metadata: true,
|
|
64
|
+
defaultcolor: [255/255, 160/255, 0, 1], // JSCAD Orange
|
|
65
|
+
compress: true
|
|
66
|
+
}
|
|
67
|
+
options = Object.assign({}, defaults, options)
|
|
68
|
+
|
|
69
|
+
objects = flatten(objects)
|
|
70
|
+
|
|
71
|
+
// convert only 3D geometries
|
|
72
|
+
let objects3d = objects.filter((object) => geometries.geom3.isA(object))
|
|
73
|
+
|
|
74
|
+
if (objects3d.length === 0) throw new Error('only 3D geometries can be serialized to 3MF')
|
|
75
|
+
if (objects.length !== objects3d.length) console.warn('some objects could not be serialized to 3MF')
|
|
76
|
+
|
|
77
|
+
// convert to triangles
|
|
78
|
+
objects = toArray(modifiers.generalize({ snap: true, triangulate: true }, objects3d))
|
|
79
|
+
|
|
80
|
+
// construct the contents of the 3MF 'model'
|
|
81
|
+
const body = ['model',
|
|
82
|
+
{
|
|
83
|
+
unit: options.unit,
|
|
84
|
+
'xml:lang': 'und'
|
|
85
|
+
},
|
|
86
|
+
['metadata', { name: 'Application' }, 'JSCAD']
|
|
87
|
+
]
|
|
88
|
+
if (options.metadata) {
|
|
89
|
+
body.push(['metadata', { name: 'CreationDate' }, new Date().toISOString()])
|
|
90
|
+
}
|
|
91
|
+
body.push(translateResources(objects, options))
|
|
92
|
+
body.push(translateBuild(objects, options))
|
|
93
|
+
|
|
94
|
+
// convert the contents to 3MF (XML) format
|
|
95
|
+
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
96
|
+
${stringify(body, 2)}`
|
|
97
|
+
|
|
98
|
+
// compress and package the contents if requested
|
|
99
|
+
if (options.compress) {
|
|
100
|
+
const data = {
|
|
101
|
+
'3D': {
|
|
102
|
+
'3dmodel.model': strToU8(xml)
|
|
103
|
+
},
|
|
104
|
+
'_rels': {
|
|
105
|
+
'.rels': strToU8(rels)
|
|
106
|
+
},
|
|
107
|
+
'[Content_Types].xml': strToU8(contenttype)
|
|
108
|
+
}
|
|
109
|
+
const opts = {
|
|
110
|
+
comment: 'created by JSCAD'
|
|
111
|
+
}
|
|
112
|
+
const zipData = zipSync(data, opts)
|
|
113
|
+
return [zipData.buffer]
|
|
114
|
+
}
|
|
115
|
+
return [xml]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const contenttype = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
119
|
+
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
120
|
+
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml">
|
|
121
|
+
</Default>
|
|
122
|
+
<Default Extension="model" ContentType="application/vnd.ms-package.3dmanufacturing-3dmodel+xml">
|
|
123
|
+
</Default>
|
|
124
|
+
</Types>`
|
|
125
|
+
|
|
126
|
+
const rels = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
127
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
128
|
+
<Relationship Target="/3D/3dmodel.model" Id="rel0" Type="http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel">
|
|
129
|
+
</Relationship>
|
|
130
|
+
</Relationships>`
|
|
131
|
+
|
|
132
|
+
const translateResources = (objects, options) => {
|
|
133
|
+
let resources = ['resources', {}, translateMaterials(objects, options)]
|
|
134
|
+
resources = resources.concat(translateObjects(objects, options))
|
|
135
|
+
return resources
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const translateMaterials = (objects, options) => {
|
|
139
|
+
let basematerials = ['basematerials', { id: '0' }]
|
|
140
|
+
|
|
141
|
+
const materials = []
|
|
142
|
+
objects.forEach((object, i) => {
|
|
143
|
+
let srgb = colors.rgbToHex(options.defaultcolor).toUpperCase()
|
|
144
|
+
if (object.color) {
|
|
145
|
+
srgb = colors.rgbToHex(object.color).toUpperCase()
|
|
146
|
+
}
|
|
147
|
+
materials.push(['base', { name: `mat${i}`, displaycolor: srgb }])
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
basematerials = basematerials.concat(materials)
|
|
151
|
+
return basematerials
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const translateObjects = (objects, options) => {
|
|
155
|
+
const contents = []
|
|
156
|
+
objects.forEach((object, i) => {
|
|
157
|
+
if (geometries.geom3.isA(object)) {
|
|
158
|
+
const polygons = geometries.geom3.toPolygons(object)
|
|
159
|
+
if (polygons.length > 0) {
|
|
160
|
+
options.id = i
|
|
161
|
+
contents.push(convertToObject(object, options))
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
return contents
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const translateBuild = (objects, options) => {
|
|
169
|
+
let build = ['build', { }]
|
|
170
|
+
|
|
171
|
+
const items = []
|
|
172
|
+
objects.forEach((object, i) => {
|
|
173
|
+
items.push(['item', { objectid: `${i + 1}` }])
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
build = build.concat(items)
|
|
177
|
+
return build
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/*
|
|
181
|
+
* This section converts each 3D geometry to object / mesh
|
|
182
|
+
*/
|
|
183
|
+
|
|
184
|
+
const convertToObject = (object, options) => {
|
|
185
|
+
const name = object.name ? object.name : `Part ${options.id}`
|
|
186
|
+
const contents = ['object', { id: `${options.id + 1}`, type: 'model', pid: '0', pindex: `${options.id}`, name: name }, convertToMesh(object, options)]
|
|
187
|
+
return contents
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const convertToMesh = (object, options) => {
|
|
191
|
+
const contents = ['mesh', {}, convertToVertices(object, options), convertToVolumes(object, options)]
|
|
192
|
+
return contents
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
* This section converts each 3D geometry to mesh vertices
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
const convertToVertices = (object, options) => {
|
|
200
|
+
const contents = ['vertices', {}]
|
|
201
|
+
|
|
202
|
+
const vertices = []
|
|
203
|
+
const polygons = geometries.geom3.toPolygons(object)
|
|
204
|
+
polygons.forEach((polygon) => {
|
|
205
|
+
for (let i = 0; i < polygon.vertices.length; i++) {
|
|
206
|
+
vertices.push(convertToVertex(polygon.vertices[i], options))
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
return contents.concat(vertices)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const convertToVertex = (vertex, options) => {
|
|
214
|
+
const contents = ['vertex', { x: vertex[0], y: vertex[1], z: vertex[2] }]
|
|
215
|
+
return contents
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/*
|
|
219
|
+
* This section converts each 3D geometry to mesh triangles
|
|
220
|
+
*/
|
|
221
|
+
|
|
222
|
+
const convertToVolumes = (object, options) => {
|
|
223
|
+
let n = 0
|
|
224
|
+
const polygons = geometries.geom3.toPolygons(object)
|
|
225
|
+
|
|
226
|
+
let contents = ['triangles', {}]
|
|
227
|
+
polygons.forEach((polygon) => {
|
|
228
|
+
if (polygon.vertices.length < 3) {
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const triangles = convertToTriangles(polygon, n)
|
|
233
|
+
|
|
234
|
+
contents = contents.concat(triangles)
|
|
235
|
+
|
|
236
|
+
n += polygon.vertices.length
|
|
237
|
+
})
|
|
238
|
+
return contents
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const convertToTriangles = (polygon, index) => {
|
|
242
|
+
const contents = []
|
|
243
|
+
|
|
244
|
+
// making sure they are all triangles (triangular polygons)
|
|
245
|
+
for (let i = 0; i < polygon.vertices.length - 2; i++) {
|
|
246
|
+
const triangle = ['triangle', { v1: index, v2: (index + i + 1), v3: (index + i + 2) }]
|
|
247
|
+
contents.push(triangle)
|
|
248
|
+
}
|
|
249
|
+
return contents
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
module.exports = {
|
|
253
|
+
serialize,
|
|
254
|
+
mimeType,
|
|
255
|
+
fileExtension
|
|
256
|
+
}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
const test = require('ava')
|
|
2
|
+
|
|
3
|
+
const { colors, geometries, primitives } = require('@jscad/modeling')
|
|
4
|
+
|
|
5
|
+
const serializer = require('../src/index.js')
|
|
6
|
+
|
|
7
|
+
test('serialize (empty)', (t) => {
|
|
8
|
+
const emptyShape = geometries.geom3.create()
|
|
9
|
+
const buffer = serializer.serialize({ metadata: false, compress: false }, emptyShape)
|
|
10
|
+
t.deepEqual(buffer, expected1)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('serialize (single)', (t) => {
|
|
14
|
+
const cube1 = primitives.cube()
|
|
15
|
+
const buffer = serializer.serialize({ metadata: false, compress: false }, cube1)
|
|
16
|
+
t.deepEqual(buffer, expected2)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('serialize (single, color)', (t) => {
|
|
20
|
+
let cube1 = primitives.cube()
|
|
21
|
+
cube1 = colors.colorize([1.0, 0.0, 0.5, 0.8], cube1)
|
|
22
|
+
const buffer = serializer.serialize({ metadata: false, compress: false, unit: 'inch' }, cube1)
|
|
23
|
+
t.deepEqual(buffer, expected3)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('serialize (multiple, color)', (t) => {
|
|
27
|
+
let cube1 = primitives.cuboid({ size: [4, 5, 6], center: [5, 5, 5] })
|
|
28
|
+
cube1 = colors.colorize([0.0, 0.0, 1.0, 0.8], cube1)
|
|
29
|
+
cube1.name = "CUBE A"
|
|
30
|
+
const cube2 = primitives.cube()
|
|
31
|
+
cube2.name = "CUBE B"
|
|
32
|
+
const buffer = serializer.serialize({ metadata: false, compress: false, defaultcolor: [1, 0, 0, 1] }, cube1, cube2)
|
|
33
|
+
t.deepEqual(buffer, expected4)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('serialize (multiple, compress)', (t) => {
|
|
37
|
+
const cube1 = colors.colorize([1.0, 0.0, 0.5, 0.8], primitives.cube())
|
|
38
|
+
cube1.name = "CUBE A"
|
|
39
|
+
const cube2 = primitives.cuboid({ size: [4, 5, 6], center: [5, 5, 5] })
|
|
40
|
+
cube2.name = "CUBE B"
|
|
41
|
+
|
|
42
|
+
const results = serializer.serialize({ compress: true }, cube1, cube2)
|
|
43
|
+
t.is(results.length, 1)
|
|
44
|
+
const len = results[0].byteLength
|
|
45
|
+
t.true(len > 1600)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const expected1 = [
|
|
49
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
50
|
+
<model unit="millimeter" xml:lang="und">
|
|
51
|
+
<metadata name="Application">JSCAD</metadata>
|
|
52
|
+
<resources>
|
|
53
|
+
<basematerials id="0">
|
|
54
|
+
<base name="mat0" displaycolor="#FFA000FF"/>
|
|
55
|
+
</basematerials>
|
|
56
|
+
</resources>
|
|
57
|
+
<build>
|
|
58
|
+
<item objectid="1"/>
|
|
59
|
+
</build>
|
|
60
|
+
</model>
|
|
61
|
+
`
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
const expected2 = [
|
|
65
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
66
|
+
<model unit="millimeter" xml:lang="und">
|
|
67
|
+
<metadata name="Application">JSCAD</metadata>
|
|
68
|
+
<resources>
|
|
69
|
+
<basematerials id="0">
|
|
70
|
+
<base name="mat0" displaycolor="#FFA000FF"/>
|
|
71
|
+
</basematerials>
|
|
72
|
+
<object id="1" type="model" pid="0" pindex="0" name="Part 0">
|
|
73
|
+
<mesh>
|
|
74
|
+
<vertices>
|
|
75
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
76
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
77
|
+
<vertex x="-1" y="1" z="1"/>
|
|
78
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
79
|
+
<vertex x="-1" y="1" z="1"/>
|
|
80
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
81
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
82
|
+
<vertex x="1" y="1" z="-1"/>
|
|
83
|
+
<vertex x="1" y="1" z="1"/>
|
|
84
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
85
|
+
<vertex x="1" y="1" z="1"/>
|
|
86
|
+
<vertex x="1" y="-1" z="1"/>
|
|
87
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
88
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
89
|
+
<vertex x="1" y="-1" z="1"/>
|
|
90
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
91
|
+
<vertex x="1" y="-1" z="1"/>
|
|
92
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
93
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
94
|
+
<vertex x="-1" y="1" z="1"/>
|
|
95
|
+
<vertex x="1" y="1" z="1"/>
|
|
96
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
97
|
+
<vertex x="1" y="1" z="1"/>
|
|
98
|
+
<vertex x="1" y="1" z="-1"/>
|
|
99
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
100
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
101
|
+
<vertex x="1" y="1" z="-1"/>
|
|
102
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
103
|
+
<vertex x="1" y="1" z="-1"/>
|
|
104
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
105
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
106
|
+
<vertex x="1" y="-1" z="1"/>
|
|
107
|
+
<vertex x="1" y="1" z="1"/>
|
|
108
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
109
|
+
<vertex x="1" y="1" z="1"/>
|
|
110
|
+
<vertex x="-1" y="1" z="1"/>
|
|
111
|
+
</vertices>
|
|
112
|
+
<triangles>
|
|
113
|
+
<triangle v1="0" v2="1" v3="2"/>
|
|
114
|
+
<triangle v1="3" v2="4" v3="5"/>
|
|
115
|
+
<triangle v1="6" v2="7" v3="8"/>
|
|
116
|
+
<triangle v1="9" v2="10" v3="11"/>
|
|
117
|
+
<triangle v1="12" v2="13" v3="14"/>
|
|
118
|
+
<triangle v1="15" v2="16" v3="17"/>
|
|
119
|
+
<triangle v1="18" v2="19" v3="20"/>
|
|
120
|
+
<triangle v1="21" v2="22" v3="23"/>
|
|
121
|
+
<triangle v1="24" v2="25" v3="26"/>
|
|
122
|
+
<triangle v1="27" v2="28" v3="29"/>
|
|
123
|
+
<triangle v1="30" v2="31" v3="32"/>
|
|
124
|
+
<triangle v1="33" v2="34" v3="35"/>
|
|
125
|
+
</triangles>
|
|
126
|
+
</mesh>
|
|
127
|
+
</object>
|
|
128
|
+
</resources>
|
|
129
|
+
<build>
|
|
130
|
+
<item objectid="1"/>
|
|
131
|
+
</build>
|
|
132
|
+
</model>
|
|
133
|
+
`
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
const expected3 = [
|
|
137
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
138
|
+
<model unit="inch" xml:lang="und">
|
|
139
|
+
<metadata name="Application">JSCAD</metadata>
|
|
140
|
+
<resources>
|
|
141
|
+
<basematerials id="0">
|
|
142
|
+
<base name="mat0" displaycolor="#FF007FCC"/>
|
|
143
|
+
</basematerials>
|
|
144
|
+
<object id="1" type="model" pid="0" pindex="0" name="Part 0">
|
|
145
|
+
<mesh>
|
|
146
|
+
<vertices>
|
|
147
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
148
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
149
|
+
<vertex x="-1" y="1" z="1"/>
|
|
150
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
151
|
+
<vertex x="-1" y="1" z="1"/>
|
|
152
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
153
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
154
|
+
<vertex x="1" y="1" z="-1"/>
|
|
155
|
+
<vertex x="1" y="1" z="1"/>
|
|
156
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
157
|
+
<vertex x="1" y="1" z="1"/>
|
|
158
|
+
<vertex x="1" y="-1" z="1"/>
|
|
159
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
160
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
161
|
+
<vertex x="1" y="-1" z="1"/>
|
|
162
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
163
|
+
<vertex x="1" y="-1" z="1"/>
|
|
164
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
165
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
166
|
+
<vertex x="-1" y="1" z="1"/>
|
|
167
|
+
<vertex x="1" y="1" z="1"/>
|
|
168
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
169
|
+
<vertex x="1" y="1" z="1"/>
|
|
170
|
+
<vertex x="1" y="1" z="-1"/>
|
|
171
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
172
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
173
|
+
<vertex x="1" y="1" z="-1"/>
|
|
174
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
175
|
+
<vertex x="1" y="1" z="-1"/>
|
|
176
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
177
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
178
|
+
<vertex x="1" y="-1" z="1"/>
|
|
179
|
+
<vertex x="1" y="1" z="1"/>
|
|
180
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
181
|
+
<vertex x="1" y="1" z="1"/>
|
|
182
|
+
<vertex x="-1" y="1" z="1"/>
|
|
183
|
+
</vertices>
|
|
184
|
+
<triangles>
|
|
185
|
+
<triangle v1="0" v2="1" v3="2"/>
|
|
186
|
+
<triangle v1="3" v2="4" v3="5"/>
|
|
187
|
+
<triangle v1="6" v2="7" v3="8"/>
|
|
188
|
+
<triangle v1="9" v2="10" v3="11"/>
|
|
189
|
+
<triangle v1="12" v2="13" v3="14"/>
|
|
190
|
+
<triangle v1="15" v2="16" v3="17"/>
|
|
191
|
+
<triangle v1="18" v2="19" v3="20"/>
|
|
192
|
+
<triangle v1="21" v2="22" v3="23"/>
|
|
193
|
+
<triangle v1="24" v2="25" v3="26"/>
|
|
194
|
+
<triangle v1="27" v2="28" v3="29"/>
|
|
195
|
+
<triangle v1="30" v2="31" v3="32"/>
|
|
196
|
+
<triangle v1="33" v2="34" v3="35"/>
|
|
197
|
+
</triangles>
|
|
198
|
+
</mesh>
|
|
199
|
+
</object>
|
|
200
|
+
</resources>
|
|
201
|
+
<build>
|
|
202
|
+
<item objectid="1"/>
|
|
203
|
+
</build>
|
|
204
|
+
</model>
|
|
205
|
+
`
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
const expected4 = [`<?xml version="1.0" encoding="UTF-8"?>
|
|
209
|
+
<model unit="millimeter" xml:lang="und">
|
|
210
|
+
<metadata name="Application">JSCAD</metadata>
|
|
211
|
+
<resources>
|
|
212
|
+
<basematerials id="0">
|
|
213
|
+
<base name="mat0" displaycolor="#0000FFCC"/>
|
|
214
|
+
<base name="mat1" displaycolor="#FF0000FF"/>
|
|
215
|
+
</basematerials>
|
|
216
|
+
<object id="1" type="model" pid="0" pindex="0" name="CUBE A">
|
|
217
|
+
<mesh>
|
|
218
|
+
<vertices>
|
|
219
|
+
<vertex x="3" y="2.5" z="2"/>
|
|
220
|
+
<vertex x="3" y="2.5" z="8"/>
|
|
221
|
+
<vertex x="3" y="7.5" z="8"/>
|
|
222
|
+
<vertex x="3" y="2.5" z="2"/>
|
|
223
|
+
<vertex x="3" y="7.5" z="8"/>
|
|
224
|
+
<vertex x="3" y="7.5" z="2"/>
|
|
225
|
+
<vertex x="7" y="2.5" z="2"/>
|
|
226
|
+
<vertex x="7" y="7.5" z="2"/>
|
|
227
|
+
<vertex x="7" y="7.5" z="8"/>
|
|
228
|
+
<vertex x="7" y="2.5" z="2"/>
|
|
229
|
+
<vertex x="7" y="7.5" z="8"/>
|
|
230
|
+
<vertex x="7" y="2.5" z="8"/>
|
|
231
|
+
<vertex x="3" y="2.5" z="2"/>
|
|
232
|
+
<vertex x="7" y="2.5" z="2"/>
|
|
233
|
+
<vertex x="7" y="2.5" z="8"/>
|
|
234
|
+
<vertex x="3" y="2.5" z="2"/>
|
|
235
|
+
<vertex x="7" y="2.5" z="8"/>
|
|
236
|
+
<vertex x="3" y="2.5" z="8"/>
|
|
237
|
+
<vertex x="3" y="7.5" z="2"/>
|
|
238
|
+
<vertex x="3" y="7.5" z="8"/>
|
|
239
|
+
<vertex x="7" y="7.5" z="8"/>
|
|
240
|
+
<vertex x="3" y="7.5" z="2"/>
|
|
241
|
+
<vertex x="7" y="7.5" z="8"/>
|
|
242
|
+
<vertex x="7" y="7.5" z="2"/>
|
|
243
|
+
<vertex x="3" y="2.5" z="2"/>
|
|
244
|
+
<vertex x="3" y="7.5" z="2"/>
|
|
245
|
+
<vertex x="7" y="7.5" z="2"/>
|
|
246
|
+
<vertex x="3" y="2.5" z="2"/>
|
|
247
|
+
<vertex x="7" y="7.5" z="2"/>
|
|
248
|
+
<vertex x="7" y="2.5" z="2"/>
|
|
249
|
+
<vertex x="3" y="2.5" z="8"/>
|
|
250
|
+
<vertex x="7" y="2.5" z="8"/>
|
|
251
|
+
<vertex x="7" y="7.5" z="8"/>
|
|
252
|
+
<vertex x="3" y="2.5" z="8"/>
|
|
253
|
+
<vertex x="7" y="7.5" z="8"/>
|
|
254
|
+
<vertex x="3" y="7.5" z="8"/>
|
|
255
|
+
</vertices>
|
|
256
|
+
<triangles>
|
|
257
|
+
<triangle v1="0" v2="1" v3="2"/>
|
|
258
|
+
<triangle v1="3" v2="4" v3="5"/>
|
|
259
|
+
<triangle v1="6" v2="7" v3="8"/>
|
|
260
|
+
<triangle v1="9" v2="10" v3="11"/>
|
|
261
|
+
<triangle v1="12" v2="13" v3="14"/>
|
|
262
|
+
<triangle v1="15" v2="16" v3="17"/>
|
|
263
|
+
<triangle v1="18" v2="19" v3="20"/>
|
|
264
|
+
<triangle v1="21" v2="22" v3="23"/>
|
|
265
|
+
<triangle v1="24" v2="25" v3="26"/>
|
|
266
|
+
<triangle v1="27" v2="28" v3="29"/>
|
|
267
|
+
<triangle v1="30" v2="31" v3="32"/>
|
|
268
|
+
<triangle v1="33" v2="34" v3="35"/>
|
|
269
|
+
</triangles>
|
|
270
|
+
</mesh>
|
|
271
|
+
</object>
|
|
272
|
+
<object id="2" type="model" pid="0" pindex="1" name="CUBE B">
|
|
273
|
+
<mesh>
|
|
274
|
+
<vertices>
|
|
275
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
276
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
277
|
+
<vertex x="-1" y="1" z="1"/>
|
|
278
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
279
|
+
<vertex x="-1" y="1" z="1"/>
|
|
280
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
281
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
282
|
+
<vertex x="1" y="1" z="-1"/>
|
|
283
|
+
<vertex x="1" y="1" z="1"/>
|
|
284
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
285
|
+
<vertex x="1" y="1" z="1"/>
|
|
286
|
+
<vertex x="1" y="-1" z="1"/>
|
|
287
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
288
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
289
|
+
<vertex x="1" y="-1" z="1"/>
|
|
290
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
291
|
+
<vertex x="1" y="-1" z="1"/>
|
|
292
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
293
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
294
|
+
<vertex x="-1" y="1" z="1"/>
|
|
295
|
+
<vertex x="1" y="1" z="1"/>
|
|
296
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
297
|
+
<vertex x="1" y="1" z="1"/>
|
|
298
|
+
<vertex x="1" y="1" z="-1"/>
|
|
299
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
300
|
+
<vertex x="-1" y="1" z="-1"/>
|
|
301
|
+
<vertex x="1" y="1" z="-1"/>
|
|
302
|
+
<vertex x="-1" y="-1" z="-1"/>
|
|
303
|
+
<vertex x="1" y="1" z="-1"/>
|
|
304
|
+
<vertex x="1" y="-1" z="-1"/>
|
|
305
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
306
|
+
<vertex x="1" y="-1" z="1"/>
|
|
307
|
+
<vertex x="1" y="1" z="1"/>
|
|
308
|
+
<vertex x="-1" y="-1" z="1"/>
|
|
309
|
+
<vertex x="1" y="1" z="1"/>
|
|
310
|
+
<vertex x="-1" y="1" z="1"/>
|
|
311
|
+
</vertices>
|
|
312
|
+
<triangles>
|
|
313
|
+
<triangle v1="0" v2="1" v3="2"/>
|
|
314
|
+
<triangle v1="3" v2="4" v3="5"/>
|
|
315
|
+
<triangle v1="6" v2="7" v3="8"/>
|
|
316
|
+
<triangle v1="9" v2="10" v3="11"/>
|
|
317
|
+
<triangle v1="12" v2="13" v3="14"/>
|
|
318
|
+
<triangle v1="15" v2="16" v3="17"/>
|
|
319
|
+
<triangle v1="18" v2="19" v3="20"/>
|
|
320
|
+
<triangle v1="21" v2="22" v3="23"/>
|
|
321
|
+
<triangle v1="24" v2="25" v3="26"/>
|
|
322
|
+
<triangle v1="27" v2="28" v3="29"/>
|
|
323
|
+
<triangle v1="30" v2="31" v3="32"/>
|
|
324
|
+
<triangle v1="33" v2="34" v3="35"/>
|
|
325
|
+
</triangles>
|
|
326
|
+
</mesh>
|
|
327
|
+
</object>
|
|
328
|
+
</resources>
|
|
329
|
+
<build>
|
|
330
|
+
<item objectid="1"/>
|
|
331
|
+
<item objectid="2"/>
|
|
332
|
+
</build>
|
|
333
|
+
</model>
|
|
334
|
+
`
|
|
335
|
+
]
|