Thu, 06 Apr 2017 19:00:07 +0200
ht is not PVC....
16 | 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 THREE.STLLoader(); | |
20 | * loader.load( './models/stl/slotted_disk.stl', function ( geometry ) { | |
21 | * scene.add( new THREE.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 THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: THREE.VertexColors }); | |
28 | * } else { .... } | |
29 | * var mesh = new THREE.Mesh( geometry, material ); | |
30 | */ | |
31 | ||
32 | ||
33 | THREE.STLLoader = function ( manager ) { | |
34 | ||
35 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; | |
36 | ||
37 | }; | |
38 | ||
39 | THREE.STLLoader.prototype = { | |
40 | ||
41 | constructor: THREE.STLLoader, | |
42 | ||
43 | load: function ( url, onLoad, onProgress, onError ) { | |
44 | ||
45 | var scope = this; | |
46 | ||
47 | var loader = new THREE.FileLoader( scope.manager ); | |
48 | loader.setResponseType( 'arraybuffer' ); | |
49 | loader.load( url, function ( text ) { | |
50 | ||
51 | onLoad( scope.parse( text ) ); | |
52 | ||
53 | }, onProgress, onError ); | |
54 | ||
55 | }, | |
56 | ||
57 | parse: function ( data ) { | |
58 | ||
59 | var isBinary = function () { | |
60 | ||
61 | var expect, face_size, n_faces, reader; | |
62 | reader = new DataView( binData ); | |
63 | face_size = ( 32 / 8 * 3 ) + ( ( 32 / 8 * 3 ) * 3 ) + ( 16 / 8 ); | |
64 | n_faces = reader.getUint32( 80, true ); | |
65 | expect = 80 + ( 32 / 8 ) + ( n_faces * face_size ); | |
66 | ||
67 | if ( expect === reader.byteLength ) { | |
68 | ||
69 | return true; | |
70 | ||
71 | } | |
72 | ||
73 | // some binary files will have different size from expected, | |
74 | // checking characters higher than ASCII to confirm is binary | |
75 | var fileLength = reader.byteLength; | |
76 | for ( var index = 0; index < fileLength; index ++ ) { | |
77 | ||
78 | if ( reader.getUint8( index, false ) > 127 ) { | |
79 | ||
80 | return true; | |
81 | ||
82 | } | |
83 | ||
84 | } | |
85 | ||
86 | return false; | |
87 | ||
88 | }; | |
89 | ||
90 | var binData = this.ensureBinary( data ); | |
91 | ||
92 | return isBinary() ? this.parseBinary( binData ) : this.parseASCII( this.ensureString( data ) ); | |
93 | ||
94 | }, | |
95 | ||
96 | parseBinary: function ( data ) { | |
97 | ||
98 | var reader = new DataView( data ); | |
99 | var faces = reader.getUint32( 80, true ); | |
100 | ||
101 | var r, g, b, hasColors = false, colors; | |
102 | var defaultR, defaultG, defaultB, alpha; | |
103 | ||
104 | // process STL header | |
105 | // check for default color in header ("COLOR=rgba" sequence). | |
106 | ||
107 | for ( var index = 0; index < 80 - 10; index ++ ) { | |
108 | ||
109 | if ( ( reader.getUint32( index, false ) == 0x434F4C4F /*COLO*/ ) && | |
110 | ( reader.getUint8( index + 4 ) == 0x52 /*'R'*/ ) && | |
111 | ( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) { | |
112 | ||
113 | hasColors = true; | |
114 | colors = []; | |
115 | ||
116 | defaultR = reader.getUint8( index + 6 ) / 255; | |
117 | defaultG = reader.getUint8( index + 7 ) / 255; | |
118 | defaultB = reader.getUint8( index + 8 ) / 255; | |
119 | alpha = reader.getUint8( index + 9 ) / 255; | |
120 | ||
121 | } | |
122 | ||
123 | } | |
124 | ||
125 | var dataOffset = 84; | |
126 | var faceLength = 12 * 4 + 2; | |
127 | ||
128 | var geometry = new THREE.BufferGeometry(); | |
129 | ||
130 | var vertices = []; | |
131 | var normals = []; | |
132 | ||
133 | for ( var face = 0; face < faces; face ++ ) { | |
134 | ||
135 | var start = dataOffset + face * faceLength; | |
136 | var normalX = reader.getFloat32( start, true ); | |
137 | var normalY = reader.getFloat32( start + 4, true ); | |
138 | var normalZ = reader.getFloat32( start + 8, true ); | |
139 | ||
140 | if ( hasColors ) { | |
141 | ||
142 | var packedColor = reader.getUint16( start + 48, true ); | |
143 | ||
144 | if ( ( packedColor & 0x8000 ) === 0 ) { | |
145 | ||
146 | // facet has its own unique color | |
147 | ||
148 | r = ( packedColor & 0x1F ) / 31; | |
149 | g = ( ( packedColor >> 5 ) & 0x1F ) / 31; | |
150 | b = ( ( packedColor >> 10 ) & 0x1F ) / 31; | |
151 | ||
152 | } else { | |
153 | ||
154 | r = defaultR; | |
155 | g = defaultG; | |
156 | b = defaultB; | |
157 | ||
158 | } | |
159 | ||
160 | } | |
161 | ||
162 | for ( var i = 1; i <= 3; i ++ ) { | |
163 | ||
164 | var vertexstart = start + i * 12; | |
165 | ||
166 | vertices.push( reader.getFloat32( vertexstart, true ) ); | |
167 | vertices.push( reader.getFloat32( vertexstart + 4, true ) ); | |
168 | vertices.push( reader.getFloat32( vertexstart + 8, true ) ); | |
169 | ||
170 | normals.push( normalX, normalY, normalZ ); | |
171 | ||
172 | if ( hasColors ) { | |
173 | ||
174 | colors.push( r, g, b ); | |
175 | ||
176 | } | |
177 | ||
178 | } | |
179 | ||
180 | } | |
181 | ||
182 | geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) ); | |
183 | geometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) ); | |
184 | ||
185 | if ( hasColors ) { | |
186 | ||
187 | geometry.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) ); | |
188 | geometry.hasColors = true; | |
189 | geometry.alpha = alpha; | |
190 | ||
191 | } | |
192 | ||
193 | return geometry; | |
194 | ||
195 | }, | |
196 | ||
197 | parseASCII: function ( data ) { | |
198 | ||
199 | var geometry, length, patternFace, patternNormal, patternVertex, result, text; | |
200 | geometry = new THREE.BufferGeometry(); | |
201 | patternFace = /facet([\s\S]*?)endfacet/g; | |
202 | ||
203 | var vertices = []; | |
204 | var normals = []; | |
205 | ||
206 | var normal = new THREE.Vector3(); | |
207 | ||
208 | while ( ( result = patternFace.exec( data ) ) !== null ) { | |
209 | ||
210 | text = result[ 0 ]; | |
211 | patternNormal = /normal[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g; | |
212 | ||
213 | while ( ( result = patternNormal.exec( text ) ) !== null ) { | |
214 | ||
215 | normal.x = parseFloat( result[ 1 ] ); | |
216 | normal.y = parseFloat( result[ 3 ] ); | |
217 | normal.z = parseFloat( result[ 5 ] ); | |
218 | ||
219 | } | |
220 | ||
221 | patternVertex = /vertex[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g; | |
222 | ||
223 | while ( ( result = patternVertex.exec( text ) ) !== null ) { | |
224 | ||
225 | vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 3 ] ), parseFloat( result[ 5 ] ) ); | |
226 | normals.push( normal.x, normal.y, normal.z ); | |
227 | ||
228 | } | |
229 | ||
230 | } | |
231 | ||
232 | geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) ); | |
233 | geometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) ); | |
234 | ||
235 | return geometry; | |
236 | ||
237 | }, | |
238 | ||
239 | ensureString: function ( buf ) { | |
240 | ||
241 | if ( typeof buf !== "string" ) { | |
242 | ||
243 | var array_buffer = new Uint8Array( buf ); | |
244 | var strArray = []; | |
245 | for ( var i = 0; i < buf.byteLength; i ++ ) { | |
246 | ||
247 | strArray.push(String.fromCharCode( array_buffer[ i ] )); // implicitly assumes little-endian | |
248 | ||
249 | } | |
250 | return strArray.join(''); | |
251 | ||
252 | } else { | |
253 | ||
254 | return buf; | |
255 | ||
256 | } | |
257 | ||
258 | }, | |
259 | ||
260 | ensureBinary: function ( buf ) { | |
261 | ||
262 | if ( typeof buf === "string" ) { | |
263 | ||
264 | var array_buffer = new Uint8Array( buf.length ); | |
265 | for ( var i = 0; i < buf.length; i ++ ) { | |
266 | ||
267 | array_buffer[ i ] = buf.charCodeAt( i ) & 0xff; // implicitly assumes little-endian | |
268 | ||
269 | } | |
270 | return array_buffer.buffer || array_buffer; | |
271 | ||
272 | } else { | |
273 | ||
274 | return buf; | |
275 | ||
276 | } | |
277 | ||
278 | } | |
279 | ||
280 | }; |