PageSourceSearch

https://www.asor.org/wp-content/plugins/woo-3d-viewer/includes/ext/threejs/js/loaders/STLLoader.js?ver=1.8.5.3

js asor.org collected 2026-10-01 10:27:58 UTC 8,483 bytes, 347 lines download raw bytes

1/**
2 * @author aleeper / http://adamleeper.com/
3 * @author mrdoob / http://mrdoob.com/
4 * @author gero3 / https://github.com/gero3
5 * @author Mugen87 / https://github.com/Mugen87
6 *
7 * Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs.
8 *
9 * Supports both binary and ASCII encoded files, with automatic detection of type.
10 *
11 * The loader returns a non-indexed buffer geometry.
12 *
13 * Limitations:
14 *  Binary decoding supports "Magics" color format (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL).
15 *  There is perhaps some question as to how valid it is to always assume little-endian-ness.
16 *  ASCII decoding assumes file is UTF-8.
17 *
18 * Usage:
19 *  var loader = new THREEW.STLLoader();
20 *  loader.load( './models/stl/slotted_disk.stl', function ( geometry ) {
21 *    scene.add( new THREEW.Mesh( geometry ) );
22 *  });
23 *
24 * For binary STLs geometry might contain colors for vertices. To use it:
25 *  // use the same code to load STL as above
26 *  if (geometry.hasColors) {
27 *    material = new THREEW.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: THREEW.VertexColors });
28 *  } else { .... }
29 *  var mesh = new THREEW.Mesh( geometry, material );
30 */
31
32
33THREEW.STLLoader = function ( manager ) {
34
35	this.manager = ( manager !== undefined ) ? manager : THREEW.DefaultLoadingManager;
36
37};
38
39THREEW.STLLoader.prototype = {
40
41	constructor: THREEW.STLLoader,
42
43	load: function ( url, onLoad, onProgress, onError ) {
44
45		var scope = this;
46
47		var loader = new THREEW.FileLoader( scope.manager );
48		loader.setPath( scope.path );
49		loader.setResponseType( 'arraybuffer' );
50		loader.load( url, function ( text ) {
51
52			try {
53
54				onLoad( scope.parse( text ) );
55
56			} catch ( exception ) {
57
58				if ( onError ) {
59
60					onError( exception );
61
62				}
63
64			}
65
66		}, onProgress, onError );
67
68	},
69
70	setPath: function ( value ) {
71
72		this.path = value;
73		return this;
74
75	},
76
77	parse: function ( data ) {
78
79		function isBinary( data ) {
80
81			var expect, face_size, n_faces, reader;
82			reader = new DataView( data );
83			face_size = ( 32 / 8 * 3 ) + ( ( 32 / 8 * 3 ) * 3 ) + ( 16 / 8 );
84			n_faces = reader.getUint32( 80, true );
85			expect = 80 + ( 32 / 8 ) + ( n_faces * face_size );
86
87			if ( expect === reader.byteLength ) {
88
89				return true;
90
91			}
92
93			// An ASCII STL data must begin with 'solid ' as the first six bytes.
94			// However, ASCII STLs lacking the SPACE after the 'd' are known to be
95			// plentiful.  So, check the first 5 bytes for 'solid'.
96
97			// Several encodings, such as UTF-8, precede the text with up to 5 bytes:
98			// https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding
99			// Search for "solid" to start anywhere after those prefixes.
100
101			// US-ASCII ordinal values for 's', 'o', 'l', 'i', 'd'
102
103			var solid = [ 115, 111, 108, 105, 100 ];
104
105			for ( var off = 0; off < 5; off ++ ) {
106
107				// If "solid" text is matched to the current offset, declare it to be an ASCII STL.
108
109				if ( matchDataViewAt ( solid, reader, off ) ) return false;
110
111			}
112
113			// Couldn't find "solid" text at the beginning; it is binary STL.
114
115			return true;
116
117		}
118
119		function matchDataViewAt( query, reader, offset ) {
120
121			// Check if each byte in query matches the corresponding byte from the current offset
122
123			for ( var i = 0, il = query.length; i < il; i ++ ) {
124
125				if ( query[ i ] !== reader.getUint8( offset + i, false ) ) return false;
126
127			}
128
129			return true;
130
131		}
132
133		function parseBinary( data ) {
134
135			var reader = new DataView( data );
136			var faces = reader.getUint32( 80, true );
137
138			var r, g, b, hasColors = false, colors;
139			var defaultR, defaultG, defaultB, alpha;
140
141			// process STL header
142			// check for default color in header ("COLOR=rgba" sequence).
143
144			for ( var index = 0; index < 80 - 10; index ++ ) {
145
146				if ( ( reader.getUint32( index, false ) == 0x434F4C4F /*COLO*/ ) &&
147					( reader.getUint8( index + 4 ) == 0x52 /*'R'*/ ) &&
148					( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) {
149
150					hasColors = true;
151					colors = [];
152
153					defaultR = reader.getUint8( index + 6 ) / 255;
154					defaultG = reader.getUint8( index + 7 ) / 255;
155					defaultB = reader.getUint8( index + 8 ) / 255;
156					alpha = reader.getUint8( index + 9 ) / 255;
157
158				}
159
160			}
161
162			var dataOffset = 84;
163			var faceLength = 12 * 4 + 2;
164
165			var geometry = new THREEW.BufferGeometry();
166
167			var vertices = [];
168			var normals = [];
169
170			for ( var face = 0; face < faces; face ++ ) {
171
172				var start = dataOffset + face * faceLength;
173				var normalX = reader.getFloat32( start, true );
174				var normalY = reader.getFloat32( start + 4, true );
175				var normalZ = reader.getFloat32( start + 8, true );
176
177				if ( hasColors ) {
178
179					var packedColor = reader.getUint16( start + 48, true );
180
181					if ( ( packedColor & 0x8000 ) === 0 ) {
182
183						// facet has its own unique color
184
185						r = ( packedColor & 0x1F ) / 31;
186						g = ( ( packedColor >> 5 ) & 0x1F ) / 31;
187						b = ( ( packedColor >> 10 ) & 0x1F ) / 31;
188
189					} else {
190
191						r = defaultR;
192						g = defaultG;
193						b = defaultB;
194
195					}
196
197				}
198
199				for ( var i = 1; i <= 3; i ++ ) {
200
201					var vertexstart = start + i * 12;
202
203					vertices.push( reader.getFloat32( vertexstart, true ) );
204					vertices.push( reader.getFloat32( vertexstart + 4, true ) );
205					vertices.push( reader.getFloat32( vertexstart + 8, true ) );
206
207					normals.push( normalX, normalY, normalZ );
208
209					if ( hasColors ) {
210
211						colors.push( r, g, b );
212
213					}
214
215				}
216
217			}
218
219			geometry.addAttribute( 'position', new THREEW.BufferAttribute( new Float32Array( vertices ), 3 ) );
220			geometry.addAttribute( 'normal', new THREEW.BufferAttribute( new Float32Array( normals ), 3 ) );
221
222			if ( hasColors ) {
223
224				geometry.addAttribute( 'color', new THREEW.BufferAttribute( new Float32Array( colors ), 3 ) );
225				geometry.hasColors = true;
226				geometry.alpha = alpha;
227
228			}
229
230			return geometry;
231
232		}
233
234		function parseASCII( data ) {
235
236			var geometry = new THREEW.BufferGeometry();
237			var patternFace = /facet([\s\S]*?)endfacet/g;
238			var faceCounter = 0;
239
240			var patternFloat = /[\s]+([+-]?(?:\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?)/.source;
241			var patternVertex = new RegExp( 'vertex' + patternFloat + patternFloat + patternFloat, 'g' );
242			var patternNormal = new RegExp( 'normal' + patternFloat + patternFloat + patternFloat, 'g' );
243
244			var vertices = [];
245			var normals = [];
246
247			var normal = new THREEW.Vector3();
248
249			var result;
250
251			while ( ( result = patternFace.exec( data ) ) !== null ) {
252
253				var vertexCountPerFace = 0;
254				var normalCountPerFace = 0;
255
256				var text = result[ 0 ];
257
258				while ( ( result = patternNormal.exec( text ) ) !== null ) {
259
260					normal.x = parseFloat( result[ 1 ] );
261					normal.y = parseFloat( result[ 2 ] );
262					normal.z = parseFloat( result[ 3 ] );
263					normalCountPerFace ++;
264
265				}
266
267				while ( ( result = patternVertex.exec( text ) ) !== null ) {
268
269					vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
270					normals.push( normal.x, normal.y, normal.z );
271					vertexCountPerFace ++;
272
273				}
274
275				// every face have to own ONE valid normal
276
277				if ( normalCountPerFace !== 1 ) {
278
279					console.error( 'THREEW.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter );
280
281				}
282
283				// each face have to own THREE valid vertices
284
285				if ( vertexCountPerFace !== 3 ) {
286
287					console.error( 'THREEW.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter );
288
289				}
290
291				faceCounter ++;
292
293			}
294
295			geometry.addAttribute( 'position', new THREEW.Float32BufferAttribute( vertices, 3 ) );
296			geometry.addAttribute( 'normal', new THREEW.Float32BufferAttribute( normals, 3 ) );
297
298			return geometry;
299
300		}
301
302		function ensureString( buffer ) {
303
304			if ( typeof buffer !== 'string' ) {
305
306				return THREEW.LoaderUtils.decodeText( new Uint8Array( buffer ) );
307
308			}
309
310			return buffer;
311
312		}
313
314		function ensureBinary( buffer ) {
315
316			if ( typeof buffer === 'string' ) {
317
318				var array_buffer = new Uint8Array( buffer.length );
319				for ( var i = 0; i < buffer.length; i ++ ) {
320
321					array_buffer[ i ] = buffer.charCodeAt( i ) & 0xff; // implicitly assumes little-endian
322
323				}
324				return array_buffer.buffer || array_buffer;
325
326			} else {
327
328				return buffer;
329
330			}
331
332		}
333
334		// start
335
336		var binData = ensureBinary( data );
337
338
339		//fuzzoid mod
340		var myreader = new DataView( data );
341		this.byteLength = myreader.byteLength;
342
343		return isBinary( binData ) ? parseBinary( binData ) : parseASCII( ensureString( data ) );
344
345	}
346
347};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.