zincjs 3.0.0 → 3.0.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/README.md +27 -22
- package/build/zinc.js +2 -2
- package/build/zinc.js.map +1 -1
- package/package.json +4 -1
- package/src/controls.js +1332 -1241
- package/src/geometryCSG.js +111 -115
- package/src/glyphsetCSG.js +51 -55
- package/src/loaders/GLTFToZincJSLoader.js +31 -33
- package/src/loaders/JSONLoader.js +339 -449
- package/src/loaders/OBJLoader.js +654 -851
- package/src/loaders/STLLoader.js +271 -329
- package/src/loaders/niftiReader.js +90 -59
- package/src/loaders/primitivesLoader.js +55 -52
- package/src/minimap.js +63 -43
- package/src/primitives/geometry.js +40 -44
- package/src/primitives/glyph.js +16 -19
- package/src/primitives/glyphset.js +229 -185
- package/src/primitives/label.js +29 -31
- package/src/primitives/lines.js +20 -20
- package/src/primitives/lines2.js +33 -39
- package/src/primitives/lod.js +43 -43
- package/src/primitives/marker.js +31 -32
- package/src/primitives/markerCluster.js +32 -35
- package/src/primitives/pointset.js +86 -83
- package/src/primitives/texturePrimitive.js +9 -10
- package/src/primitives/textureSlides.js +84 -97
- package/src/primitives/textureVolume.js +46 -49
- package/src/primitives/tubeLines.js +108 -108
- package/src/primitives/zincObject.js +176 -184
- package/src/region.js +145 -155
- package/src/renderRequests.js +3 -3
- package/src/renderer.js +635 -620
- package/src/scene.js +479 -419
- package/src/sceneExporter.js +22 -17
- package/src/sceneLoader.js +542 -296
- package/src/shaders/rgbVolumeRender.js +11 -18
- package/src/shaders/textureArray.js +5 -12
- package/src/shaders/textureSlide.js +10 -17
- package/src/shaders/volumeRender.js +11 -18
- package/src/shaders/volumeRender_old.js +11 -18
- package/src/shaders/volumeTexture.js +7 -14
- package/src/textSprite.js +23 -19
- package/src/texture/texture.js +14 -15
- package/src/texture/textureArray.js +14 -16
- package/src/three/InstancedPoints.js +2 -9
- package/src/three/Loader.js +334 -315
- package/src/three/line/Line.js +165 -215
- package/src/three/line/LineSegments.js +40 -55
- package/src/three/line/LineSegments2.js +322 -366
- package/src/three/line/LineSegmentsGeometry.js +239 -280
- package/src/three-js-csg.js +260 -252
- package/src/tsl/glyphRenderMaterial.js +12 -3
- package/src/tsl/glyphTransform.js +51 -29
- package/src/tsl/textureSlides.js +23 -24
- package/src/utilities.js +309 -371
- package/src/videoHandler.js +76 -83
- package/src/workers/geometryCSG.worker.js +33 -36
- package/src/workers/geometryCSGInternal.js +39 -44
- package/src/zinc.js +4 -7
- package/vite.config.js +7 -7
package/src/loaders/STLLoader.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
BufferAttribute,
|
|
3
|
+
BufferGeometry,
|
|
4
|
+
FileLoader,
|
|
5
|
+
Float32BufferAttribute,
|
|
6
|
+
Loader,
|
|
7
|
+
LoaderUtils,
|
|
8
|
+
Vector3,
|
|
9
9
|
} from 'three/webgpu';
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -59,341 +59,283 @@ import {
|
|
|
59
59
|
* const mesh = new THREE.Mesh(geometry, materials);
|
|
60
60
|
*/
|
|
61
61
|
|
|
62
|
-
|
|
63
62
|
class STLLoader extends Loader {
|
|
63
|
+
constructor(manager) {
|
|
64
|
+
super(manager);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
load(url, onLoad, onProgress, onError) {
|
|
68
|
+
const scope = this;
|
|
69
|
+
|
|
70
|
+
const loader = new FileLoader(this.manager);
|
|
71
|
+
loader.setPath(this.path);
|
|
72
|
+
loader.setResponseType('arraybuffer');
|
|
73
|
+
loader.setRequestHeader(this.requestHeader);
|
|
74
|
+
loader.setWithCredentials(this.withCredentials);
|
|
75
|
+
|
|
76
|
+
loader.load(
|
|
77
|
+
url,
|
|
78
|
+
function (text) {
|
|
79
|
+
try {
|
|
80
|
+
onLoad(scope.parse(text));
|
|
81
|
+
} catch (e) {
|
|
82
|
+
if (onError) {
|
|
83
|
+
onError(e);
|
|
84
|
+
} else {
|
|
85
|
+
console.error(e);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
scope.manager.itemError(url);
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
onProgress,
|
|
92
|
+
onError,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
parse(data) {
|
|
97
|
+
function isBinary(data) {
|
|
98
|
+
const reader = new DataView(data);
|
|
99
|
+
const face_size = (32 / 8) * 3 + (32 / 8) * 3 * 3 + 16 / 8;
|
|
100
|
+
const n_faces = reader.getUint32(80, true);
|
|
101
|
+
const expect = 80 + 32 / 8 + n_faces * face_size;
|
|
102
|
+
|
|
103
|
+
if (expect === reader.byteLength) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// An ASCII STL data must begin with 'solid ' as the first six bytes.
|
|
108
|
+
// However, ASCII STLs lacking the SPACE after the 'd' are known to be
|
|
109
|
+
// plentiful. So, check the first 5 bytes for 'solid'.
|
|
110
|
+
|
|
111
|
+
// Several encodings, such as UTF-8, precede the text with up to 5 bytes:
|
|
112
|
+
// https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding
|
|
113
|
+
// Search for "solid" to start anywhere after those prefixes.
|
|
114
|
+
|
|
115
|
+
// US-ASCII ordinal values for 's', 'o', 'l', 'i', 'd'
|
|
116
|
+
|
|
117
|
+
const solid = [115, 111, 108, 105, 100];
|
|
118
|
+
|
|
119
|
+
for (let off = 0; off < 5; off++) {
|
|
120
|
+
// If "solid" text is matched to the current offset, declare it to be an ASCII STL.
|
|
121
|
+
|
|
122
|
+
if (matchDataViewAt(solid, reader, off)) return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Couldn't find "solid" text at the beginning; it is binary STL.
|
|
126
|
+
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function matchDataViewAt(query, reader, offset) {
|
|
131
|
+
// Check if each byte in query matches the corresponding byte from the current offset
|
|
132
|
+
|
|
133
|
+
for (let i = 0, il = query.length; i < il; i++) {
|
|
134
|
+
if (query[i] !== reader.getUint8(offset + i, false)) return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function parseBinary(data) {
|
|
141
|
+
const reader = new DataView(data);
|
|
142
|
+
const faces = reader.getUint32(80, true);
|
|
143
|
+
|
|
144
|
+
let r,
|
|
145
|
+
g,
|
|
146
|
+
b,
|
|
147
|
+
hasColors = false,
|
|
148
|
+
colors;
|
|
149
|
+
let defaultR, defaultG, defaultB, alpha;
|
|
150
|
+
|
|
151
|
+
// process STL header
|
|
152
|
+
// check for default color in header ("COLOR=rgba" sequence).
|
|
153
|
+
|
|
154
|
+
for (let index = 0; index < 80 - 10; index++) {
|
|
155
|
+
if (
|
|
156
|
+
reader.getUint32(index, false) == 0x434f4c4f /*COLO*/ &&
|
|
157
|
+
reader.getUint8(index + 4) == 0x52 /*'R'*/ &&
|
|
158
|
+
reader.getUint8(index + 5) == 0x3d /*'='*/
|
|
159
|
+
) {
|
|
160
|
+
hasColors = true;
|
|
161
|
+
colors = new Float32Array(faces * 3 * 3);
|
|
162
|
+
|
|
163
|
+
defaultR = reader.getUint8(index + 6) / 255;
|
|
164
|
+
defaultG = reader.getUint8(index + 7) / 255;
|
|
165
|
+
defaultB = reader.getUint8(index + 8) / 255;
|
|
166
|
+
alpha = reader.getUint8(index + 9) / 255;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const dataOffset = 84;
|
|
171
|
+
const faceLength = 12 * 4 + 2;
|
|
172
|
+
|
|
173
|
+
const geometry = new BufferGeometry();
|
|
174
|
+
|
|
175
|
+
const vertices = new Float32Array(faces * 3 * 3);
|
|
176
|
+
const normals = new Float32Array(faces * 3 * 3);
|
|
177
|
+
|
|
178
|
+
for (let face = 0; face < faces; face++) {
|
|
179
|
+
const start = dataOffset + face * faceLength;
|
|
180
|
+
const normalX = reader.getFloat32(start, true);
|
|
181
|
+
const normalY = reader.getFloat32(start + 4, true);
|
|
182
|
+
const normalZ = reader.getFloat32(start + 8, true);
|
|
183
|
+
|
|
184
|
+
if (hasColors) {
|
|
185
|
+
const packedColor = reader.getUint16(start + 48, true);
|
|
186
|
+
|
|
187
|
+
if ((packedColor & 0x8000) === 0) {
|
|
188
|
+
// facet has its own unique color
|
|
189
|
+
|
|
190
|
+
r = (packedColor & 0x1f) / 31;
|
|
191
|
+
g = ((packedColor >> 5) & 0x1f) / 31;
|
|
192
|
+
b = ((packedColor >> 10) & 0x1f) / 31;
|
|
193
|
+
} else {
|
|
194
|
+
r = defaultR;
|
|
195
|
+
g = defaultG;
|
|
196
|
+
b = defaultB;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (let i = 1; i <= 3; i++) {
|
|
201
|
+
const vertexstart = start + i * 12;
|
|
202
|
+
const componentIdx = face * 3 * 3 + (i - 1) * 3;
|
|
203
|
+
|
|
204
|
+
vertices[componentIdx] = reader.getFloat32(vertexstart, true);
|
|
205
|
+
vertices[componentIdx + 1] = reader.getFloat32(vertexstart + 4, true);
|
|
206
|
+
vertices[componentIdx + 2] = reader.getFloat32(vertexstart + 8, true);
|
|
207
|
+
|
|
208
|
+
normals[componentIdx] = normalX;
|
|
209
|
+
normals[componentIdx + 1] = normalY;
|
|
210
|
+
normals[componentIdx + 2] = normalZ;
|
|
64
211
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
for ( let i = 0, il = query.length; i < il; i ++ ) {
|
|
153
|
-
|
|
154
|
-
if ( query[ i ] !== reader.getUint8( offset + i, false ) ) return false;
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return true;
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function parseBinary( data ) {
|
|
163
|
-
|
|
164
|
-
const reader = new DataView( data );
|
|
165
|
-
const faces = reader.getUint32( 80, true );
|
|
166
|
-
|
|
167
|
-
let r, g, b, hasColors = false, colors;
|
|
168
|
-
let defaultR, defaultG, defaultB, alpha;
|
|
169
|
-
|
|
170
|
-
// process STL header
|
|
171
|
-
// check for default color in header ("COLOR=rgba" sequence).
|
|
172
|
-
|
|
173
|
-
for ( let index = 0; index < 80 - 10; index ++ ) {
|
|
174
|
-
|
|
175
|
-
if ( ( reader.getUint32( index, false ) == 0x434F4C4F /*COLO*/ ) &&
|
|
176
|
-
( reader.getUint8( index + 4 ) == 0x52 /*'R'*/ ) &&
|
|
177
|
-
( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) {
|
|
178
|
-
|
|
179
|
-
hasColors = true;
|
|
180
|
-
colors = new Float32Array( faces * 3 * 3 );
|
|
181
|
-
|
|
182
|
-
defaultR = reader.getUint8( index + 6 ) / 255;
|
|
183
|
-
defaultG = reader.getUint8( index + 7 ) / 255;
|
|
184
|
-
defaultB = reader.getUint8( index + 8 ) / 255;
|
|
185
|
-
alpha = reader.getUint8( index + 9 ) / 255;
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const dataOffset = 84;
|
|
192
|
-
const faceLength = 12 * 4 + 2;
|
|
193
|
-
|
|
194
|
-
const geometry = new BufferGeometry();
|
|
195
|
-
|
|
196
|
-
const vertices = new Float32Array( faces * 3 * 3 );
|
|
197
|
-
const normals = new Float32Array( faces * 3 * 3 );
|
|
198
|
-
|
|
199
|
-
for ( let face = 0; face < faces; face ++ ) {
|
|
200
|
-
|
|
201
|
-
const start = dataOffset + face * faceLength;
|
|
202
|
-
const normalX = reader.getFloat32( start, true );
|
|
203
|
-
const normalY = reader.getFloat32( start + 4, true );
|
|
204
|
-
const normalZ = reader.getFloat32( start + 8, true );
|
|
205
|
-
|
|
206
|
-
if ( hasColors ) {
|
|
207
|
-
|
|
208
|
-
const packedColor = reader.getUint16( start + 48, true );
|
|
209
|
-
|
|
210
|
-
if ( ( packedColor & 0x8000 ) === 0 ) {
|
|
211
|
-
|
|
212
|
-
// facet has its own unique color
|
|
213
|
-
|
|
214
|
-
r = ( packedColor & 0x1F ) / 31;
|
|
215
|
-
g = ( ( packedColor >> 5 ) & 0x1F ) / 31;
|
|
216
|
-
b = ( ( packedColor >> 10 ) & 0x1F ) / 31;
|
|
217
|
-
|
|
218
|
-
} else {
|
|
219
|
-
|
|
220
|
-
r = defaultR;
|
|
221
|
-
g = defaultG;
|
|
222
|
-
b = defaultB;
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
for ( let i = 1; i <= 3; i ++ ) {
|
|
229
|
-
|
|
230
|
-
const vertexstart = start + i * 12;
|
|
231
|
-
const componentIdx = ( face * 3 * 3 ) + ( ( i - 1 ) * 3 );
|
|
232
|
-
|
|
233
|
-
vertices[ componentIdx ] = reader.getFloat32( vertexstart, true );
|
|
234
|
-
vertices[ componentIdx + 1 ] = reader.getFloat32( vertexstart + 4, true );
|
|
235
|
-
vertices[ componentIdx + 2 ] = reader.getFloat32( vertexstart + 8, true );
|
|
236
|
-
|
|
237
|
-
normals[ componentIdx ] = normalX;
|
|
238
|
-
normals[ componentIdx + 1 ] = normalY;
|
|
239
|
-
normals[ componentIdx + 2 ] = normalZ;
|
|
240
|
-
|
|
241
|
-
if ( hasColors ) {
|
|
242
|
-
|
|
243
|
-
colors[ componentIdx ] = r;
|
|
244
|
-
colors[ componentIdx + 1 ] = g;
|
|
245
|
-
colors[ componentIdx + 2 ] = b;
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
geometry.setAttribute( 'position', new BufferAttribute( vertices, 3 ) );
|
|
254
|
-
geometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
|
|
255
|
-
|
|
256
|
-
if ( hasColors ) {
|
|
257
|
-
|
|
258
|
-
geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
|
|
259
|
-
geometry.hasColors = true;
|
|
260
|
-
geometry.alpha = alpha;
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return geometry;
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function parseASCII( data ) {
|
|
269
|
-
|
|
270
|
-
const geometry = new BufferGeometry();
|
|
271
|
-
const patternSolid = /solid([\s\S]*?)endsolid/g;
|
|
272
|
-
const patternFace = /facet([\s\S]*?)endfacet/g;
|
|
273
|
-
let faceCounter = 0;
|
|
274
|
-
|
|
275
|
-
const patternFloat = /[\s]+([+-]?(?:\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?)/.source;
|
|
276
|
-
const patternVertex = new RegExp( 'vertex' + patternFloat + patternFloat + patternFloat, 'g' );
|
|
277
|
-
const patternNormal = new RegExp( 'normal' + patternFloat + patternFloat + patternFloat, 'g' );
|
|
278
|
-
|
|
279
|
-
const vertices = [];
|
|
280
|
-
const normals = [];
|
|
281
|
-
|
|
282
|
-
const normal = new Vector3();
|
|
283
|
-
|
|
284
|
-
let result;
|
|
285
|
-
|
|
286
|
-
let groupCount = 0;
|
|
287
|
-
let startVertex = 0;
|
|
288
|
-
let endVertex = 0;
|
|
289
|
-
|
|
290
|
-
while ( ( result = patternSolid.exec( data ) ) !== null ) {
|
|
291
|
-
|
|
292
|
-
startVertex = endVertex;
|
|
293
|
-
|
|
294
|
-
const solid = result[ 0 ];
|
|
295
|
-
|
|
296
|
-
while ( ( result = patternFace.exec( solid ) ) !== null ) {
|
|
297
|
-
|
|
298
|
-
let vertexCountPerFace = 0;
|
|
299
|
-
let normalCountPerFace = 0;
|
|
300
|
-
|
|
301
|
-
const text = result[ 0 ];
|
|
302
|
-
|
|
303
|
-
while ( ( result = patternNormal.exec( text ) ) !== null ) {
|
|
304
|
-
|
|
305
|
-
normal.x = parseFloat( result[ 1 ] );
|
|
306
|
-
normal.y = parseFloat( result[ 2 ] );
|
|
307
|
-
normal.z = parseFloat( result[ 3 ] );
|
|
308
|
-
normalCountPerFace ++;
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
while ( ( result = patternVertex.exec( text ) ) !== null ) {
|
|
313
|
-
|
|
314
|
-
vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
|
|
315
|
-
normals.push( normal.x, normal.y, normal.z );
|
|
316
|
-
vertexCountPerFace ++;
|
|
317
|
-
endVertex ++;
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// every face have to own ONE valid normal
|
|
322
|
-
|
|
323
|
-
if ( normalCountPerFace !== 1 ) {
|
|
324
|
-
|
|
325
|
-
console.error( 'THREE.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter );
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// each face have to own THREE valid vertices
|
|
330
|
-
|
|
331
|
-
if ( vertexCountPerFace !== 3 ) {
|
|
332
|
-
|
|
333
|
-
console.error( 'THREE.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter );
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
faceCounter ++;
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const start = startVertex;
|
|
342
|
-
const count = endVertex - startVertex;
|
|
343
|
-
|
|
344
|
-
geometry.addGroup( start, count, groupCount );
|
|
345
|
-
groupCount ++;
|
|
346
|
-
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
|
|
350
|
-
geometry.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
|
|
351
|
-
|
|
352
|
-
return geometry;
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
function ensureString( buffer ) {
|
|
357
|
-
|
|
358
|
-
if ( typeof buffer !== 'string' ) {
|
|
359
|
-
|
|
360
|
-
return LoaderUtils.decodeText( new Uint8Array( buffer ) );
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
return buffer;
|
|
365
|
-
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function ensureBinary( buffer ) {
|
|
369
|
-
|
|
370
|
-
if ( typeof buffer === 'string' ) {
|
|
371
|
-
|
|
372
|
-
const array_buffer = new Uint8Array( buffer.length );
|
|
373
|
-
for ( let i = 0; i < buffer.length; i ++ ) {
|
|
374
|
-
|
|
375
|
-
array_buffer[ i ] = buffer.charCodeAt( i ) & 0xff; // implicitly assumes little-endian
|
|
212
|
+
if (hasColors) {
|
|
213
|
+
colors[componentIdx] = r;
|
|
214
|
+
colors[componentIdx + 1] = g;
|
|
215
|
+
colors[componentIdx + 2] = b;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
geometry.setAttribute('position', new BufferAttribute(vertices, 3));
|
|
221
|
+
geometry.setAttribute('normal', new BufferAttribute(normals, 3));
|
|
222
|
+
|
|
223
|
+
if (hasColors) {
|
|
224
|
+
geometry.setAttribute('color', new BufferAttribute(colors, 3));
|
|
225
|
+
geometry.hasColors = true;
|
|
226
|
+
geometry.alpha = alpha;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return geometry;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function parseASCII(data) {
|
|
233
|
+
const geometry = new BufferGeometry();
|
|
234
|
+
const patternSolid = /solid([\s\S]*?)endsolid/g;
|
|
235
|
+
const patternFace = /facet([\s\S]*?)endfacet/g;
|
|
236
|
+
let faceCounter = 0;
|
|
237
|
+
|
|
238
|
+
const patternFloat = /[\s]+([+-]?(?:\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?)/.source;
|
|
239
|
+
const patternVertex = new RegExp('vertex' + patternFloat + patternFloat + patternFloat, 'g');
|
|
240
|
+
const patternNormal = new RegExp('normal' + patternFloat + patternFloat + patternFloat, 'g');
|
|
241
|
+
|
|
242
|
+
const vertices = [];
|
|
243
|
+
const normals = [];
|
|
244
|
+
|
|
245
|
+
const normal = new Vector3();
|
|
246
|
+
|
|
247
|
+
let result;
|
|
248
|
+
|
|
249
|
+
let groupCount = 0;
|
|
250
|
+
let startVertex = 0;
|
|
251
|
+
let endVertex = 0;
|
|
252
|
+
|
|
253
|
+
while ((result = patternSolid.exec(data)) !== null) {
|
|
254
|
+
startVertex = endVertex;
|
|
255
|
+
|
|
256
|
+
const solid = result[0];
|
|
257
|
+
|
|
258
|
+
while ((result = patternFace.exec(solid)) !== null) {
|
|
259
|
+
let vertexCountPerFace = 0;
|
|
260
|
+
let normalCountPerFace = 0;
|
|
261
|
+
|
|
262
|
+
const text = result[0];
|
|
263
|
+
|
|
264
|
+
while ((result = patternNormal.exec(text)) !== null) {
|
|
265
|
+
normal.x = parseFloat(result[1]);
|
|
266
|
+
normal.y = parseFloat(result[2]);
|
|
267
|
+
normal.z = parseFloat(result[3]);
|
|
268
|
+
normalCountPerFace++;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
while ((result = patternVertex.exec(text)) !== null) {
|
|
272
|
+
vertices.push(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]));
|
|
273
|
+
normals.push(normal.x, normal.y, normal.z);
|
|
274
|
+
vertexCountPerFace++;
|
|
275
|
+
endVertex++;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// every face have to own ONE valid normal
|
|
279
|
+
|
|
280
|
+
if (normalCountPerFace !== 1) {
|
|
281
|
+
console.error(
|
|
282
|
+
"THREE.STLLoader: Something isn't right with the normal of face number " +
|
|
283
|
+
faceCounter,
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// each face have to own THREE valid vertices
|
|
288
|
+
|
|
289
|
+
if (vertexCountPerFace !== 3) {
|
|
290
|
+
console.error(
|
|
291
|
+
"THREE.STLLoader: Something isn't right with the vertices of face number " +
|
|
292
|
+
faceCounter,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
faceCounter++;
|
|
297
|
+
}
|
|
376
298
|
|
|
377
|
-
|
|
299
|
+
const start = startVertex;
|
|
300
|
+
const count = endVertex - startVertex;
|
|
378
301
|
|
|
379
|
-
|
|
302
|
+
geometry.addGroup(start, count, groupCount);
|
|
303
|
+
groupCount++;
|
|
304
|
+
}
|
|
380
305
|
|
|
381
|
-
|
|
306
|
+
geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3));
|
|
307
|
+
geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3));
|
|
382
308
|
|
|
383
|
-
|
|
309
|
+
return geometry;
|
|
310
|
+
}
|
|
384
311
|
|
|
385
|
-
|
|
312
|
+
function ensureString(buffer) {
|
|
313
|
+
if (typeof buffer !== 'string') {
|
|
314
|
+
return LoaderUtils.decodeText(new Uint8Array(buffer));
|
|
315
|
+
}
|
|
386
316
|
|
|
387
|
-
|
|
317
|
+
return buffer;
|
|
318
|
+
}
|
|
388
319
|
|
|
389
|
-
|
|
320
|
+
function ensureBinary(buffer) {
|
|
321
|
+
if (typeof buffer === 'string') {
|
|
322
|
+
const array_buffer = new Uint8Array(buffer.length);
|
|
323
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
324
|
+
array_buffer[i] = buffer.charCodeAt(i) & 0xff; // implicitly assumes little-endian
|
|
325
|
+
}
|
|
390
326
|
|
|
391
|
-
|
|
327
|
+
return array_buffer.buffer || array_buffer;
|
|
328
|
+
} else {
|
|
329
|
+
return buffer;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
392
332
|
|
|
393
|
-
|
|
333
|
+
// start
|
|
394
334
|
|
|
395
|
-
|
|
335
|
+
const binData = ensureBinary(data);
|
|
396
336
|
|
|
337
|
+
return isBinary(binData) ? parseBinary(binData) : parseASCII(ensureString(data));
|
|
338
|
+
}
|
|
397
339
|
}
|
|
398
340
|
|
|
399
341
|
export { STLLoader };
|