otsdaq_utilities  v2_05_02_indev
ThreeCSG.js
1 (function( factory ) {
2  if ( typeof define === "function" && define.amd ) {
3  define( [ 'threejs' ], factory );
4  } else if (typeof exports === 'object' && typeof module !== 'undefined') {
5  factory(require("three"), exports);
6  } else {
7  if (typeof THREE == 'undefined')
8  throw new Error('THREE is not defined', 'ThreeCSG.js');
9  ThreeBSP = factory(THREE);
10  }
11 } (function(THREE, ThreeBSP) {
12 
13  "use strict";
14 
15  if (!ThreeBSP) ThreeBSP = {};
16 
17  var EPSILON = 1e-5,
18  COPLANAR = 0,
19  FRONT = 1,
20  BACK = 2,
21  SPANNING = 3;
22 
23  ThreeBSP.Geometry = function( geometry, transfer_matrix, nodeid, flippedMesh ) {
24  // Convert THREE.Geometry to ThreeBSP
25 
26  if ( geometry instanceof THREE.Geometry ) {
27  this.matrix = null; // new THREE.Matrix4; not create matrix when do not needed
28  } else if ( geometry instanceof THREE.Mesh ) {
29  // #todo: add hierarchy support
30  geometry.updateMatrix();
31  transfer_matrix = this.matrix = geometry.matrix.clone();
32  geometry = geometry.geometry;
33  } else if ( geometry instanceof ThreeBSP.Node ) {
34  this.tree = geometry;
35  this.matrix = null; // new THREE.Matrix4;
36  return this;
37  } else if ( geometry instanceof THREE.BufferGeometry ) {
38  var pos_buf = geometry.getAttribute('position').array,
39  norm_buf = geometry.getAttribute('normal').array,
40  polygons = [], polygon, vert1, vert2, vert3;
41 
42  for (var i=0; i < pos_buf.length; i+=9) {
43  polygon = new ThreeBSP.Polygon;
44 
45  vert1 = new ThreeBSP.Vertex( pos_buf[i], pos_buf[i+1], pos_buf[i+2], norm_buf[i], norm_buf[i+1], norm_buf[i+2]);
46  if (transfer_matrix) vert1.applyMatrix4(transfer_matrix);
47 
48  vert2 = new ThreeBSP.Vertex( pos_buf[i+3], pos_buf[i+4], pos_buf[i+5], norm_buf[i+3], norm_buf[i+4], norm_buf[i+5]);
49  if (transfer_matrix) vert2.applyMatrix4(transfer_matrix);
50 
51  vert3 = new ThreeBSP.Vertex( pos_buf[i+6], pos_buf[i+7], pos_buf[i+8], norm_buf[i+6], norm_buf[i+7], norm_buf[i+8]);
52  if (transfer_matrix) vert3.applyMatrix4(transfer_matrix);
53 
54  if (flippedMesh) polygon.vertices.push( vert1, vert3, vert2 );
55  else polygon.vertices.push( vert1, vert2, vert3 );
56 
57  polygon.calculateProperties();
58  polygons.push( polygon );
59  }
60 
61  this.tree = new ThreeBSP.Node( polygons, nodeid );
62  if (nodeid!==undefined) this.maxid = this.tree.maxnodeid;
63  return this;
64 
65  } else if (geometry.polygons && (geometry.polygons[0] instanceof ThreeBSP.Polygon)) {
66  var polygons = geometry.polygons;
67 
68  for (var i=0;i<polygons.length;++i) {
69  var polygon = polygons[i];
70  if (transfer_matrix) {
71  for (var n=0;n<polygon.vertices.length;++n)
72  polygon.vertices[n].applyMatrix4(transfer_matrix);
73  }
74 
75  polygon.calculateProperties();
76  }
77 
78  this.tree = new ThreeBSP.Node( polygons, nodeid );
79  if (nodeid!==undefined) this.maxid = this.tree.maxnodeid;
80  return this;
81 
82  } else {
83  throw 'ThreeBSP: Given geometry is unsupported';
84  }
85 
86  var polygons = [],
87  nfaces = geometry.faces.length,
88  face, polygon, vertex, normal, useVertexNormals;
89 
90  for (var i = 0; i < nfaces; ++i ) {
91  face = geometry.faces[i];
92  normal = face.normal;
93  // faceVertexUvs = geometry.faceVertexUvs[0][i];
94  polygon = new ThreeBSP.Polygon;
95 
96  if ( face instanceof THREE.Face3 ) {
97  useVertexNormals = face.vertexNormals && (face.vertexNormals.length==3);
98 
99  vertex = geometry.vertices[ face.a ];
100  if (useVertexNormals) normal = face.vertexNormals[0];
101  // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[0].x, faceVertexUvs[0].y ) : null;
102  vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z /*face.normal , uvs */ );
103  if (transfer_matrix) vertex.applyMatrix4(transfer_matrix);
104  polygon.vertices.push( vertex );
105 
106  vertex = geometry.vertices[ face.b ];
107  if (useVertexNormals) normal = face.vertexNormals[1];
108  //uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[1].x, faceVertexUvs[1].y ) : null;
109  vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z /*face.normal , uvs */ );
110  if (transfer_matrix) vertex.applyMatrix4(transfer_matrix);
111  polygon.vertices.push( vertex );
112 
113  vertex = geometry.vertices[ face.c ];
114  if (useVertexNormals) normal = face.vertexNormals[2];
115  // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[2].x, faceVertexUvs[2].y ) : null;
116  vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z /*face.normal, uvs */ );
117  if (transfer_matrix) vertex.applyMatrix4(transfer_matrix);
118  polygon.vertices.push( vertex );
119  } else if ( typeof THREE.Face4 ) {
120  useVertexNormals = face.vertexNormals && (face.vertexNormals.length==4);
121 
122  vertex = geometry.vertices[ face.a ];
123  if (useVertexNormals) normal = face.vertexNormals[0];
124  // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[0].x, faceVertexUvs[0].y ) : null;
125  vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z /*, uvs */ );
126  if (transfer_matrix) vertex.applyMatrix4(transfer_matrix);
127  polygon.vertices.push( vertex );
128 
129  vertex = geometry.vertices[ face.b ];
130  if (useVertexNormals) normal = face.vertexNormals[1];
131  // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[1].x, faceVertexUvs[1].y ) : null;
132  vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z /*, uvs */ );
133  if (transfer_matrix) vertex.applyMatrix4(transfer_matrix);
134  polygon.vertices.push( vertex );
135 
136  vertex = geometry.vertices[ face.c ];
137  if (useVertexNormals) normal = face.vertexNormals[2];
138  // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[2].x, faceVertexUvs[2].y ) : null;
139  vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z /*, uvs */ );
140  if (transfer_matrix) vertex.applyMatrix4(transfer_matrix);
141  polygon.vertices.push( vertex );
142 
143  vertex = geometry.vertices[ face.d ];
144  if (useVertexNormals) normal = face.vertexNormals[3];
145  // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[3].x, faceVertexUvs[3].y ) : null;
146  vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z /*, uvs */ );
147  if (transfer_matrix) vertex.applyMatrix4(transfer_matrix);
148  polygon.vertices.push( vertex );
149  } else {
150  throw 'Invalid face type at index ' + i;
151  }
152 
153  polygon.calculateProperties();
154  polygons.push( polygon );
155  }
156 
157  this.tree = new ThreeBSP.Node( polygons, nodeid );
158  if (nodeid!==undefined) this.maxid = this.tree.maxnodeid;
159  }
160 
161  ThreeBSP.Geometry.prototype.subtract = function( other_tree ) {
162  var a = this.tree.clone(),
163  b = other_tree.tree.clone();
164 
165  a.invert();
166  a.clipTo( b );
167  b.clipTo( a );
168  b.invert();
169  b.clipTo( a );
170  b.invert();
171  a.build( b.allPolygons() );
172  a.invert();
173  a = new ThreeBSP.Geometry( a );
174  a.matrix = this.matrix;
175  return a;
176  }
177 
178  ThreeBSP.Geometry.prototype.union = function( other_tree ) {
179  var a = this.tree.clone(),
180  b = other_tree.tree.clone();
181 
182  a.clipTo( b );
183  b.clipTo( a );
184  b.invert();
185  b.clipTo( a );
186  b.invert();
187  a.build( b.allPolygons() );
188  a = new ThreeBSP.Geometry( a );
189  a.matrix = this.matrix;
190  return a;
191  }
192 
193  ThreeBSP.Geometry.prototype.intersect = function( other_tree ) {
194  var a = this.tree.clone(),
195  b = other_tree.tree.clone();
196 
197  a.invert();
198  b.clipTo( a );
199  b.invert();
200  a.clipTo( b );
201  b.clipTo( a );
202  a.build( b.allPolygons() );
203  a.invert();
204  a = new ThreeBSP.Geometry( a );
205  a.matrix = this.matrix;
206  return a;
207  }
208 
209  ThreeBSP.Geometry.prototype.tryToCompress = function(polygons) {
210 
211  if (this.maxid === undefined) return;
212 
213  var arr = [], parts, foundpair,
214  nreduce = 0, n, len = polygons.length,
215  p, p1, p2, i1, i2;
216 
217  // sort out polygons
218  for (n=0;n<len;++n) {
219  p = polygons[n];
220  if (p.id === undefined) continue;
221  if (arr[p.id] === undefined) arr[p.id] = [];
222 
223  arr[p.id].push(p);
224  }
225 
226  for(n=0; n<arr.length; ++n) {
227  parts = arr[n];
228  if (parts===undefined) continue;
229 
230  len = parts.length;
231 
232  foundpair = (len > 1);
233 
234  while (foundpair) {
235  foundpair = false;
236 
237  for (i1 = 0; i1<len-1; ++i1) {
238  p1 = parts[i1];
239  if (!p1 || !p1.parent) continue;
240  for (i2 = i1+1; i2 < len; ++i2) {
241  p2 = parts[i2];
242  if (p2 && (p1.parent === p2.parent) && (p1.nsign === p2.nsign)) {
243 
244  if (p1.nsign !== p1.parent.nsign) p1.parent.flip();
245 
246  nreduce++;
247  parts[i1] = p1.parent;
248  parts[i2] = null;
249  if (p1.parent.vertices.length < 3) console.log('something wrong with parent');
250  foundpair = true;
251  break;
252  }
253  }
254  }
255  }
256  }
257 
258  if (nreduce>0) {
259  polygons.splice(0, polygons.length);
260 
261  for(n=0;n<arr.length;++n) {
262  parts = arr[n];
263  if (parts !== undefined)
264  for (i1=0,len=parts.length; i1<len;++i1)
265  if (parts[i1]) polygons.push(parts[i1]);
266  }
267 
268  }
269  }
270 
271  ThreeBSP.Geometry.prototype.direct_subtract = function( other_tree ) {
272  var a = this.tree,
273  b = other_tree.tree;
274  a.invert();
275  a.clipTo( b );
276  b.clipTo( a );
277  b.invert();
278  b.clipTo( a );
279  b.invert();
280  a.build( b.collectPolygons([]) );
281  a.invert();
282  return this;
283  }
284 
285  ThreeBSP.Geometry.prototype.direct_union = function( other_tree ) {
286  var a = this.tree,
287  b = other_tree.tree;
288 
289  a.clipTo( b );
290  b.clipTo( a );
291  b.invert();
292  b.clipTo( a );
293  b.invert();
294  a.build( b.collectPolygons([]) );
295  return this;
296  }
297 
298  ThreeBSP.Geometry.prototype.direct_intersect = function( other_tree ) {
299  var a = this.tree,
300  b = other_tree.tree;
301 
302  a.invert();
303  b.clipTo( a );
304  b.invert();
305  a.clipTo( b );
306  b.clipTo( a );
307  a.build( b.collectPolygons([]) );
308  a.invert();
309  return this;
310  }
311 
312  ThreeBSP.CreateNormal = function(axis_name, pos, size) {
313  // create geometry to make cut on specified axis
314 
315  var vert1, vert2, vert3;
316 
317  if (!size || (size<10000)) size = 10000;
318 
319  switch(axis_name) {
320  case "x":
321  vert1 = new ThreeBSP.Vertex(pos, -3*size, size, 1, 0, 0),
322  vert3 = new ThreeBSP.Vertex(pos, size, size, 1, 0, 0),
323  vert2 = new ThreeBSP.Vertex(pos, size, -3*size, 1, 0, 0);
324  break;
325  case "y":
326  vert1 = new ThreeBSP.Vertex(-3*size, pos, size, 0, 1, 0),
327  vert2 = new ThreeBSP.Vertex( size, pos, size, 0, 1, 0),
328  vert3 = new ThreeBSP.Vertex( size, pos, -3*size, 0, 1, 0);
329  break;
330  case "z":
331  vert1 = new ThreeBSP.Vertex(-3*size, size, pos, 0, 0, 1),
332  vert3 = new ThreeBSP.Vertex( size, size, pos, 0, 0, 1),
333  vert2 = new ThreeBSP.Vertex( size, -3*size, pos, 0, 0, 1);
334  break;
335  }
336 
337  var polygon = new ThreeBSP.Polygon([vert1, vert2, vert3]);
338  polygon.calculateProperties();
339 
340  var node = new ThreeBSP.Node([polygon]);
341 
342  return new ThreeBSP.Geometry(node);
343  }
344 
345 
346  ThreeBSP.Geometry.prototype.cut_from_plane = function( other_tree) {
347  // just cut peaces from second geometry, which just simple plane
348 
349  var a = this.tree,
350  b = other_tree.tree;
351 
352  a.invert();
353  b.clipTo( a );
354 
355  return this;
356  }
357 
358 
359  ThreeBSP.Geometry.prototype.toGeometry = function() {
360  var i, j,
361  matrix = this.matrix ? new THREE.Matrix4().getInverse( this.matrix ) : null,
362  geometry = new THREE.Geometry(),
363  polygons = this.tree.collectPolygons([]),
364  polygon_count = polygons.length,
365  polygon, polygon_vertice_count,
366  vertice_dict = {},
367  vertex_idx_a, vertex_idx_b, vertex_idx_c,
368  vertex, face;
369 
370  for ( i = 0; i < polygon_count; ++i ) {
371  polygon = polygons[i];
372  polygon_vertice_count = polygon.vertices.length;
373 
374  for ( j = 2; j < polygon_vertice_count; ++j ) {
375  // verticeUvs = [];
376 
377  vertex = polygon.vertices[0];
378  // verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) );
379  vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z );
380  if (matrix) vertex.applyMatrix4(matrix);
381 
382  if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) {
383  vertex_idx_a = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ];
384  } else {
385  geometry.vertices.push( vertex );
386  vertex_idx_a = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1;
387  }
388 
389  vertex = polygon.vertices[j-1];
390  // verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) );
391  vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z );
392  if (matrix) vertex.applyMatrix4(matrix);
393  if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) {
394  vertex_idx_b = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ];
395  } else {
396  geometry.vertices.push( vertex );
397  vertex_idx_b = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1;
398  }
399 
400  vertex = polygon.vertices[j];
401  // verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) );
402  vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z );
403  if (matrix) vertex.applyMatrix4(matrix);
404  if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) {
405  vertex_idx_c = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ];
406  } else {
407  geometry.vertices.push( vertex );
408  vertex_idx_c = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1;
409  }
410 
411  face = new THREE.Face3(
412  vertex_idx_a,
413  vertex_idx_b,
414  vertex_idx_c,
415  new THREE.Vector3( polygon.normal.x, polygon.normal.y, polygon.normal.z )
416  );
417 
418  geometry.faces.push( face );
419  // geometry.faceVertexUvs[0].push( verticeUvs );
420  }
421 
422  }
423  return geometry;
424  }
425 
426  ThreeBSP.Geometry.prototype.scale = function(x,y,z) {
427  // try to scale as THREE.BufferGeometry
428  var polygons = this.tree.collectPolygons([]);
429 
430  for (var i = 0; i < polygons.length; ++i) {
431  var polygon = polygons[i];
432  for (var k=0; k < polygon.vertices.length; ++k) {
433  var v = polygon.vertices[k];
434  v.x *= x;
435  v.y *= y;
436  v.z *= z;
437  }
438  delete polygon.normal;
439  polygon.calculateProperties();
440  }
441  }
442 
443  ThreeBSP.Geometry.prototype.toPolygons = function() {
444  var polygons = this.tree.collectPolygons([]);
445 
446  this.tryToCompress(polygons);
447 
448  for (var i = 0; i < polygons.length; ++i ) {
449  delete polygons[i].id;
450  delete polygons[i].parent;
451  }
452 
453  return polygons;
454  }
455 
456  ThreeBSP.Geometry.prototype.toBufferGeometry = function() {
457  return ThreeBSP.CreateBufferGeometry(this.toPolygons());
458  }
459 
460  ThreeBSP.CreateBufferGeometry = function(polygons) {
461  var i, j, polygon_count = polygons.length, buf_size = 0;
462 
463  for ( i = 0; i < polygon_count; ++i )
464  buf_size += (polygons[i].vertices.length - 2) * 9;
465 
466  var positions_buf = new Float32Array(buf_size),
467  normals_buf = new Float32Array(buf_size),
468  iii = 0, polygon;
469 
470  function CopyVertex(vertex) {
471 
472  positions_buf[iii] = vertex.x;
473  positions_buf[iii+1] = vertex.y;
474  positions_buf[iii+2] = vertex.z;
475 
476  normals_buf[iii] = polygon.nsign * vertex.nx;
477  normals_buf[iii+1] = polygon.nsign * vertex.ny;
478  normals_buf[iii+2] = polygon.nsign * vertex.nz;
479  iii+=3;
480  }
481 
482  for ( i = 0; i < polygon_count; ++i ) {
483  polygon = polygons[i];
484  for ( j = 2; j < polygon.vertices.length; ++j ) {
485  CopyVertex(polygon.vertices[0]);
486  CopyVertex(polygon.vertices[j-1]);
487  CopyVertex(polygon.vertices[j]);
488  }
489  }
490 
491  var geometry = new THREE.BufferGeometry();
492  geometry.addAttribute( 'position', new THREE.BufferAttribute( positions_buf, 3 ) );
493  geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals_buf, 3 ) );
494 
495  // geometry.computeVertexNormals();
496  return geometry;
497  }
498 
499  ThreeBSP.Geometry.prototype.toMesh = function( material ) {
500  var geometry = this.toGeometry(),
501  mesh = new THREE.Mesh( geometry, material );
502 
503  if (this.matrix) {
504  mesh.position.setFromMatrixPosition( this.matrix );
505  mesh.rotation.setFromRotationMatrix( this.matrix );
506  }
507 
508  return mesh;
509  }
510 
511  ThreeBSP.Polygon = function( vertices, normal, w ) {
512  if ( !( vertices instanceof Array ) ) {
513  vertices = [];
514  }
515 
516  this.vertices = vertices;
517  this.nsign = 1;
518  if ( vertices.length > 0 ) {
519  this.calculateProperties();
520  } else {
521  this.normal = this.w = undefined;
522  }
523  }
524 
525  ThreeBSP.Polygon.prototype.copyProperties = function(parent, more) {
526  this.normal = parent.normal; // .clone();
527  this.w = parent.w;
528  this.nsign = parent.nsign;
529  if (more && (parent.id !== undefined)) {
530  this.id = parent.id;
531  this.parent = parent;
532  }
533  return this;
534  }
535 
536  ThreeBSP.Polygon.prototype.calculateProperties = function() {
537  if (this.normal) return;
538 
539  var a = this.vertices[0],
540  b = this.vertices[1],
541  c = this.vertices[2];
542 
543  this.nsign = 1;
544 
545  this.normal = b.clone().subtract( a ).cross(
546  c.clone().subtract( a )
547  ).normalize();
548 
549  this.w = this.normal.clone().dot( a );
550  return this;
551  }
552 
553  ThreeBSP.Polygon.prototype.clone = function() {
554  var vertice_count = this.vertices.length,
555  polygon = new ThreeBSP.Polygon;
556 
557  for (var i = 0; i < vertice_count; ++i )
558  polygon.vertices.push( this.vertices[i].clone() );
559 
560  return polygon.copyProperties(this);
561  }
562 
563  ThreeBSP.Polygon.prototype.flip = function() {
564 
566  //this.normal.multiplyScalar( -1 );
567  //this.w *= -1;
568 
569  this.nsign *= -1;
570 
571  this.vertices.reverse();
572 
573  return this;
574  }
575 
576  ThreeBSP.Polygon.prototype.classifyVertex = function( vertex ) {
577  var side_value = this.nsign * (this.normal.dot( vertex ) - this.w);
578 
579  if ( side_value < -EPSILON ) return BACK;
580  if ( side_value > EPSILON ) return FRONT;
581  return COPLANAR;
582  }
583 
584  ThreeBSP.Polygon.prototype.classifySide = function( polygon ) {
585  var i, classification,
586  num_positive = 0, num_negative = 0,
587  vertice_count = polygon.vertices.length;
588 
589  for ( i = 0; i < vertice_count; ++i ) {
590  classification = this.classifyVertex( polygon.vertices[i] );
591  if ( classification === FRONT ) {
592  ++num_positive;
593  } else if ( classification === BACK ) {
594  ++num_negative;
595  }
596  }
597 
598  if ( num_positive > 0 && num_negative === 0 ) return FRONT;
599  if ( num_positive === 0 && num_negative > 0 ) return BACK;
600  if ( num_positive === 0 && num_negative === 0 ) return COPLANAR;
601  return SPANNING;
602  }
603 
604  ThreeBSP.Polygon.prototype.splitPolygon = function( polygon, coplanar_front, coplanar_back, front, back ) {
605  var classification = this.classifySide( polygon );
606 
607  if ( classification === COPLANAR ) {
608 
609  ( (this.nsign * polygon.nsign * this.normal.dot( polygon.normal ) > 0) ? coplanar_front : coplanar_back ).push( polygon );
610 
611  } else if ( classification === FRONT ) {
612 
613  front.push( polygon );
614 
615  } else if ( classification === BACK ) {
616 
617  back.push( polygon );
618 
619  } else {
620 
621  var vertice_count = polygon.vertices.length,
622  nnx = this.normal.x,
623  nny = this.normal.y,
624  nnz = this.normal.z,
625  i, j, ti, tj, vi, vj,
626  t, v,
627  f = [], b = [];
628 
629  for ( i = 0; i < vertice_count; ++i ) {
630 
631  j = (i + 1) % vertice_count;
632  vi = polygon.vertices[i];
633  vj = polygon.vertices[j];
634  ti = this.classifyVertex( vi );
635  tj = this.classifyVertex( vj );
636 
637  if ( ti != BACK ) f.push( vi );
638  if ( ti != FRONT ) b.push( vi );
639  if ( (ti | tj) === SPANNING ) {
640  // t = ( this.w - this.normal.dot( vi ) ) / this.normal.dot( vj.clone().subtract( vi ) );
641  //v = vi.clone().lerp( vj, t );
642 
643  t = (this.w - (nnx*vi.x + nny*vi.y + nnz*vi.z)) / (nnx*(vj.x-vi.x) + nny*(vj.y-vi.y) + nnz*(vj.z-vi.z));
644 
645  v = vi.interpolate( vj, t );
646  f.push( v );
647  b.push( v );
648  }
649  }
650 
651  //if ( f.length >= 3 ) front.push( new ThreeBSP.Polygon( f ).calculateProperties() );
652  //if ( b.length >= 3 ) back.push( new ThreeBSP.Polygon( b ).calculateProperties() );
653  if ( f.length >= 3 ) front.push( new ThreeBSP.Polygon( f ).copyProperties(polygon, true) );
654  if ( b.length >= 3 ) back.push( new ThreeBSP.Polygon( b ).copyProperties(polygon, true) );
655  }
656  }
657 
658  ThreeBSP.Vertex = function(x, y, z, nx, ny, nz) {
659  this.x = x;
660  this.y = y;
661  this.z = z;
662  this.nx = nx;
663  this.ny = ny;
664  this.nz = nz;
665  }
666 
667  ThreeBSP.Vertex.prototype.setnormal = function ( nx, ny, nz ) {
668  this.nx = nx;
669  this.ny = ny;
670  this.nz = nz;
671  }
672 
673  ThreeBSP.Vertex.prototype.clone = function() {
674  return new ThreeBSP.Vertex( this.x, this.y, this.z, this.nx, this.ny, this.nz);
675  }
676 
677  ThreeBSP.Vertex.prototype.add = function( vertex ) {
678  this.x += vertex.x;
679  this.y += vertex.y;
680  this.z += vertex.z;
681  return this;
682  }
683 
684  ThreeBSP.Vertex.prototype.subtract = function( vertex ) {
685  this.x -= vertex.x;
686  this.y -= vertex.y;
687  this.z -= vertex.z;
688  return this;
689  }
690 
691  ThreeBSP.Vertex.prototype.multiplyScalar = function( scalar ) {
692  this.x *= scalar;
693  this.y *= scalar;
694  this.z *= scalar;
695  return this;
696  }
697 
698  ThreeBSP.Vertex.prototype.cross = function( vertex ) {
699  var x = this.x,
700  y = this.y,
701  z = this.z;
702 
703  this.x = y * vertex.z - z * vertex.y;
704  this.y = z * vertex.x - x * vertex.z;
705  this.z = x * vertex.y - y * vertex.x;
706 
707  return this;
708  }
709 
710  ThreeBSP.Vertex.prototype.normalize = function() {
711  var length = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
712 
713  this.x /= length;
714  this.y /= length;
715  this.z /= length;
716 
717  return this;
718  }
719 
720  ThreeBSP.Vertex.prototype.dot = function( vertex ) {
721  return this.x*vertex.x + this.y*vertex.y + this.z*vertex.z;
722  }
723 
724  ThreeBSP.Vertex.prototype.diff = function( vertex ) {
725  var dx = (this.x - vertex.x),
726  dy = (this.y - vertex.y),
727  dz = (this.z - vertex.z),
728  len2 = this.x*this.x + this.y*this.y + this.z*this.z;
729 
730  return (dx*dx + dy*dy + dz*dz) / (len2>0 ? len2 : 1e-10);
731  }
732 
733 /*
734  ThreeBSP.Vertex.prototype.lerp = function( a, t ) {
735  this.add(
736  a.clone().subtract( this ).multiplyScalar( t )
737  );
738 
739  this.normal.add(
740  a.normal.clone().sub( this.normal ).multiplyScalar( t )
741  );
742 
743  //this.uv.add(
744  // a.uv.clone().sub( this.uv ).multiplyScalar( t )
745  //);
746 
747  return this;
748  };
749  ThreeBSP.Vertex.prototype.interpolate = function( other, t ) {
750  return this.clone().lerp( other, t );
751  };
752 */
753 
754  ThreeBSP.Vertex.prototype.interpolate = function( a, t ) {
755  var t1 = 1-t;
756  return new ThreeBSP.Vertex(this.x*t1 + a.x*t, this.y*t1 + a.y*t, this.z*t1 + a.z*t,
757  this.nx*t1 + a.nx*t, this.ny*t1 + a.ny*t, this.nz*t1 + a.nz*t);
758  }
759 
760  ThreeBSP.Vertex.prototype.applyMatrix4 = function ( m ) {
761 
762  // input: THREE.Matrix4 affine matrix
763 
764  var x = this.x, y = this.y, z = this.z, e = m.elements;
765 
766  this.x = e[0] * x + e[4] * y + e[8] * z + e[12];
767  this.y = e[1] * x + e[5] * y + e[9] * z + e[13];
768  this.z = e[2] * x + e[6] * y + e[10] * z + e[14];
769 
770  x = this.nx; y = this.ny; z = this.nz;
771 
772  this.nx = e[0] * x + e[4] * y + e[8] * z;
773  this.ny = e[1] * x + e[5] * y + e[9] * z;
774  this.nz = e[2] * x + e[6] * y + e[10] * z;
775 
776  return this;
777  }
778 
779  // ================================================================================================
780 
781  ThreeBSP.Node = function( polygons, nodeid ) {
782  this.polygons = [];
783  this.front = this.back = undefined;
784 
785  if ( !(polygons instanceof Array) || polygons.length === 0 ) return;
786 
787  this.divider = polygons[0].clone();
788 
789  var polygon_count = polygons.length,
790  front = [], back = [];
791 
792  for (var i = 0; i < polygon_count; ++i ) {
793  if (nodeid!==undefined) {
794  polygons[i].id = nodeid++;
795  delete polygons[i].parent;
796  }
797 
798  this.divider.splitPolygon( polygons[i], this.polygons, this.polygons, front, back );
799  }
800 
801  if (nodeid !== undefined) this.maxnodeid = nodeid;
802 
803  if ( front.length > 0 )
804  this.front = new ThreeBSP.Node( front );
805 
806  if ( back.length > 0 )
807  this.back = new ThreeBSP.Node( back );
808  }
809 
810  ThreeBSP.Node.isConvex = function( polygons ) {
811  var i, j, len = polygons.length;
812  for ( i = 0; i < len; ++i )
813  for ( j = 0; j < len; ++j )
814  if ( i !== j && polygons[i].classifySide( polygons[j] ) !== BACK ) return false;
815  return true;
816  }
817 
818  ThreeBSP.Node.prototype.build = function( polygons ) {
819  var polygon_count = polygons.length,
820  front = [], back = [];
821 
822  if ( !this.divider )
823  this.divider = polygons[0].clone();
824 
825  for (var i = 0; i < polygon_count; ++i )
826  this.divider.splitPolygon( polygons[i], this.polygons, this.polygons, front, back );
827 
828  if ( front.length > 0 ) {
829  if ( !this.front ) this.front = new ThreeBSP.Node();
830  this.front.build( front );
831  }
832 
833  if ( back.length > 0 ) {
834  if ( !this.back ) this.back = new ThreeBSP.Node();
835  this.back.build( back );
836  }
837  }
838 
839  ThreeBSP.Node.prototype.collectPolygons = function(arr) {
840  var len = this.polygons.length;
841  for (var i=0;i<len;++i) arr.push(this.polygons[i]);
842  if ( this.front ) this.front.collectPolygons(arr);
843  if ( this.back ) this.back.collectPolygons(arr);
844  return arr;
845  }
846 
847  ThreeBSP.Node.prototype.allPolygons = function() {
848  var polygons = this.polygons.slice();
849  if ( this.front ) polygons = polygons.concat( this.front.allPolygons() );
850  if ( this.back ) polygons = polygons.concat( this.back.allPolygons() );
851  return polygons;
852  }
853 
854  ThreeBSP.Node.prototype.numPolygons = function() {
855  var res = this.polygons.length;
856  if ( this.front ) res += this.front.numPolygons();
857  if ( this.back ) res += this.back.numPolygons();
858  return res;
859  }
860 
861  ThreeBSP.Node.prototype.clone = function() {
862  var node = new ThreeBSP.Node();
863 
864  node.divider = this.divider.clone();
865  node.polygons = this.polygons.map( function( polygon ) { return polygon.clone(); } );
866  node.front = this.front && this.front.clone();
867  node.back = this.back && this.back.clone();
868 
869  return node;
870  }
871 
872  ThreeBSP.Node.prototype.invert = function() {
873  var polygon_count = this.polygons.length;
874 
875  for (var i = 0; i < polygon_count; ++i )
876  this.polygons[i].flip();
877 
878  this.divider.flip();
879  if ( this.front ) this.front.invert();
880  if ( this.back ) this.back.invert();
881 
882  var temp = this.front;
883  this.front = this.back;
884  this.back = temp;
885 
886  return this;
887  }
888 
889  ThreeBSP.Node.prototype.clipPolygons = function( polygons ) {
890 
891  if ( !this.divider ) return polygons.slice();
892 
893  var polygon_count = polygons.length, front = [], back = [];
894 
895  for (var i = 0; i < polygon_count; ++i )
896  this.divider.splitPolygon( polygons[i], front, back, front, back );
897 
898  if ( this.front ) front = this.front.clipPolygons( front );
899  if ( this.back ) back = this.back.clipPolygons( back );
900  else back = [];
901 
902  return front.concat( back );
903  }
904 
905  ThreeBSP.Node.prototype.clipTo = function( node ) {
906  this.polygons = node.clipPolygons( this.polygons );
907  if ( this.front ) this.front.clipTo( node );
908  if ( this.back ) this.back.clipTo( node );
909  }
910 
911  return ThreeBSP;
912 
913 }));
914