threeBSP.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. // Generated by CoffeeScript 1.6.3
  2. (function() {
  3. var BACK, COPLANAR, EPSILON, FRONT, SPANNING, returning,
  4. __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  5. __slice = [].slice,
  6. __hasProp = {}.hasOwnProperty,
  7. __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
  8. EPSILON = 1e-5;
  9. COPLANAR = 0;
  10. FRONT = 1;
  11. BACK = 2;
  12. SPANNING = 3;
  13. returning = function(value, fn) {
  14. fn();
  15. return value;
  16. };
  17. window.ThreeBSP = (function() {
  18. function ThreeBSP(treeIsh, matrix) {
  19. this.matrix = matrix;
  20. this.intersect = __bind(this.intersect, this);
  21. this.union = __bind(this.union, this);
  22. this.subtract = __bind(this.subtract, this);
  23. this.toGeometry = __bind(this.toGeometry, this);
  24. this.toMesh = __bind(this.toMesh, this);
  25. this.toTree = __bind(this.toTree, this);
  26. if (this.matrix == null) {
  27. this.matrix = new THREE.Matrix4();
  28. }
  29. this.tree = this.toTree(treeIsh);
  30. }
  31. ThreeBSP.prototype.toTree = function(treeIsh) {
  32. var face, geometry, i, polygons, _fn, _i, _len, _ref,
  33. _this = this;
  34. if (treeIsh instanceof ThreeBSP.Node) {
  35. return treeIsh;
  36. }
  37. polygons = [];
  38. geometry = treeIsh instanceof THREE.Geometry ? treeIsh : treeIsh instanceof THREE.Mesh ? (treeIsh.updateMatrix(), this.matrix = treeIsh.matrix.clone(), treeIsh.geometry) : void 0;
  39. _ref = geometry.faces;
  40. _fn = function(face, i) {
  41. var faceVertexUvs, idx, polygon, vIndex, vName, vertex, _j, _len1, _ref1, _ref2;
  42. faceVertexUvs = (_ref1 = geometry.faceVertexUvs) != null ? _ref1[0][i] : void 0;
  43. if (faceVertexUvs == null) {
  44. faceVertexUvs = [new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2()];
  45. }
  46. polygon = new ThreeBSP.Polygon();
  47. _ref2 = ['a', 'b', 'c', 'd'];
  48. for (vIndex = _j = 0, _len1 = _ref2.length; _j < _len1; vIndex = ++_j) {
  49. vName = _ref2[vIndex];
  50. if ((idx = face[vName]) != null) {
  51. vertex = geometry.vertices[idx];
  52. vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2(faceVertexUvs[vIndex].x, faceVertexUvs[vIndex].y));
  53. vertex.applyMatrix4(_this.matrix);
  54. polygon.vertices.push(vertex);
  55. }
  56. }
  57. return polygons.push(polygon.calculateProperties());
  58. };
  59. for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
  60. face = _ref[i];
  61. _fn(face, i);
  62. }
  63. return new ThreeBSP.Node(polygons);
  64. };
  65. ThreeBSP.prototype.toMesh = function(material) {
  66. var geometry, mesh,
  67. _this = this;
  68. if (material == null) {
  69. material = new THREE.MeshNormalMaterial();
  70. }
  71. geometry = this.toGeometry();
  72. return returning((mesh = new THREE.Mesh(geometry, material)), function() {
  73. mesh.position.getPositionFromMatrix(_this.matrix);
  74. return mesh.rotation.setFromRotationMatrix(_this.matrix);
  75. });
  76. };
  77. ThreeBSP.prototype.toGeometry = function() {
  78. var geometry, matrix,
  79. _this = this;
  80. matrix = new THREE.Matrix4().getInverse(this.matrix);
  81. return returning((geometry = new THREE.Geometry()), function() {
  82. var face, idx, polyVerts, polygon, v, vertUvs, verts, _i, _len, _ref, _results;
  83. _ref = _this.tree.allPolygons();
  84. _results = [];
  85. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  86. polygon = _ref[_i];
  87. polyVerts = (function() {
  88. var _j, _len1, _ref1, _results1;
  89. _ref1 = polygon.vertices;
  90. _results1 = [];
  91. for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
  92. v = _ref1[_j];
  93. _results1.push(v.clone().applyMatrix4(matrix));
  94. }
  95. return _results1;
  96. })();
  97. _results.push((function() {
  98. var _j, _ref1, _results1;
  99. _results1 = [];
  100. for (idx = _j = 2, _ref1 = polyVerts.length; 2 <= _ref1 ? _j < _ref1 : _j > _ref1; idx = 2 <= _ref1 ? ++_j : --_j) {
  101. verts = [polyVerts[0], polyVerts[idx - 1], polyVerts[idx]];
  102. vertUvs = (function() {
  103. var _k, _len1, _ref2, _ref3, _results2;
  104. _results2 = [];
  105. for (_k = 0, _len1 = verts.length; _k < _len1; _k++) {
  106. v = verts[_k];
  107. _results2.push(new THREE.Vector2((_ref2 = v.uv) != null ? _ref2.x : void 0, (_ref3 = v.uv) != null ? _ref3.y : void 0));
  108. }
  109. return _results2;
  110. })();
  111. face = (function(func, args, ctor) {
  112. ctor.prototype = func.prototype;
  113. var child = new ctor, result = func.apply(child, args);
  114. return Object(result) === result ? result : child;
  115. })(THREE.Face3, __slice.call((function() {
  116. var _k, _len1, _results2;
  117. _results2 = [];
  118. for (_k = 0, _len1 = verts.length; _k < _len1; _k++) {
  119. v = verts[_k];
  120. _results2.push(geometry.vertices.push(v) - 1);
  121. }
  122. return _results2;
  123. })()).concat([polygon.normal.clone()]), function(){});
  124. geometry.faces.push(face);
  125. _results1.push(geometry.faceVertexUvs[0].push(vertUvs));
  126. }
  127. return _results1;
  128. })());
  129. }
  130. return _results;
  131. });
  132. };
  133. ThreeBSP.prototype.subtract = function(other) {
  134. var them, us, _ref;
  135. _ref = [this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1];
  136. us.invert().clipTo(them);
  137. them.clipTo(us).invert().clipTo(us).invert();
  138. return new ThreeBSP(us.build(them.allPolygons()).invert(), this.matrix);
  139. };
  140. ThreeBSP.prototype.union = function(other) {
  141. var them, us, _ref;
  142. _ref = [this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1];
  143. us.clipTo(them);
  144. them.clipTo(us).invert().clipTo(us).invert();
  145. return new ThreeBSP(us.build(them.allPolygons()), this.matrix);
  146. };
  147. ThreeBSP.prototype.intersect = function(other) {
  148. var them, us, _ref;
  149. _ref = [this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1];
  150. them.clipTo(us.invert()).invert().clipTo(us.clipTo(them));
  151. return new ThreeBSP(us.build(them.allPolygons()).invert(), this.matrix);
  152. };
  153. return ThreeBSP;
  154. })();
  155. ThreeBSP.Vertex = (function(_super) {
  156. __extends(Vertex, _super);
  157. function Vertex(x, y, z, normal, uv) {
  158. this.normal = normal != null ? normal : new THREE.Vector3();
  159. this.uv = uv != null ? uv : new THREE.Vector2();
  160. this.interpolate = __bind(this.interpolate, this);
  161. this.lerp = __bind(this.lerp, this);
  162. Vertex.__super__.constructor.call(this, x, y, z);
  163. }
  164. Vertex.prototype.clone = function() {
  165. return new ThreeBSP.Vertex(this.x, this.y, this.z, this.normal.clone(), this.uv.clone());
  166. };
  167. Vertex.prototype.lerp = function(v, alpha) {
  168. var _this = this;
  169. return returning(Vertex.__super__.lerp.apply(this, arguments), function() {
  170. _this.uv.add(v.uv.clone().sub(_this.uv).multiplyScalar(alpha));
  171. return _this.normal.lerp(v, alpha);
  172. });
  173. };
  174. Vertex.prototype.interpolate = function() {
  175. var args, _ref;
  176. args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  177. return (_ref = this.clone()).lerp.apply(_ref, args);
  178. };
  179. return Vertex;
  180. })(THREE.Vector3);
  181. ThreeBSP.Polygon = (function() {
  182. function Polygon(vertices, normal, w) {
  183. this.vertices = vertices != null ? vertices : [];
  184. this.normal = normal;
  185. this.w = w;
  186. this.subdivide = __bind(this.subdivide, this);
  187. this.tessellate = __bind(this.tessellate, this);
  188. this.classifySide = __bind(this.classifySide, this);
  189. this.classifyVertex = __bind(this.classifyVertex, this);
  190. this.invert = __bind(this.invert, this);
  191. this.clone = __bind(this.clone, this);
  192. this.calculateProperties = __bind(this.calculateProperties, this);
  193. if (this.vertices.length) {
  194. this.calculateProperties();
  195. }
  196. }
  197. Polygon.prototype.calculateProperties = function() {
  198. var _this = this;
  199. return returning(this, function() {
  200. var a, b, c, _ref;
  201. _ref = _this.vertices, a = _ref[0], b = _ref[1], c = _ref[2];
  202. _this.normal = b.clone().sub(a).cross(c.clone().sub(a)).normalize();
  203. return _this.w = _this.normal.clone().dot(a);
  204. });
  205. };
  206. Polygon.prototype.clone = function() {
  207. var v;
  208. return new ThreeBSP.Polygon((function() {
  209. var _i, _len, _ref, _results;
  210. _ref = this.vertices;
  211. _results = [];
  212. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  213. v = _ref[_i];
  214. _results.push(v.clone());
  215. }
  216. return _results;
  217. }).call(this), this.normal.clone(), this.w);
  218. };
  219. Polygon.prototype.invert = function() {
  220. var _this = this;
  221. return returning(this, function() {
  222. _this.normal.multiplyScalar(-1);
  223. _this.w *= -1;
  224. return _this.vertices.reverse();
  225. });
  226. };
  227. Polygon.prototype.classifyVertex = function(vertex) {
  228. var side;
  229. side = this.normal.dot(vertex) - this.w;
  230. switch (false) {
  231. case !(side < -EPSILON):
  232. return BACK;
  233. case !(side > EPSILON):
  234. return FRONT;
  235. default:
  236. return COPLANAR;
  237. }
  238. };
  239. Polygon.prototype.classifySide = function(polygon) {
  240. var back, front, tally, v, _i, _len, _ref, _ref1,
  241. _this = this;
  242. _ref = [0, 0], front = _ref[0], back = _ref[1];
  243. tally = function(v) {
  244. switch (_this.classifyVertex(v)) {
  245. case FRONT:
  246. return front += 1;
  247. case BACK:
  248. return back += 1;
  249. }
  250. };
  251. _ref1 = polygon.vertices;
  252. for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
  253. v = _ref1[_i];
  254. tally(v);
  255. }
  256. if (front > 0 && back === 0) {
  257. return FRONT;
  258. }
  259. if (front === 0 && back > 0) {
  260. return BACK;
  261. }
  262. if ((front === back && back === 0)) {
  263. return COPLANAR;
  264. }
  265. return SPANNING;
  266. };
  267. Polygon.prototype.tessellate = function(poly) {
  268. var b, count, f, i, j, polys, t, ti, tj, v, vi, vj, _i, _len, _ref, _ref1, _ref2,
  269. _this = this;
  270. _ref = {
  271. f: [],
  272. b: [],
  273. count: poly.vertices.length
  274. }, f = _ref.f, b = _ref.b, count = _ref.count;
  275. if (this.classifySide(poly) !== SPANNING) {
  276. return [poly];
  277. }
  278. _ref1 = poly.vertices;
  279. for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
  280. vi = _ref1[i];
  281. vj = poly.vertices[(j = (i + 1) % count)];
  282. _ref2 = (function() {
  283. var _j, _len1, _ref2, _results;
  284. _ref2 = [vi, vj];
  285. _results = [];
  286. for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
  287. v = _ref2[_j];
  288. _results.push(this.classifyVertex(v));
  289. }
  290. return _results;
  291. }).call(this), ti = _ref2[0], tj = _ref2[1];
  292. if (ti !== BACK) {
  293. f.push(vi);
  294. }
  295. if (ti !== FRONT) {
  296. b.push(vi);
  297. }
  298. if ((ti | tj) === SPANNING) {
  299. t = (this.w - this.normal.dot(vi)) / this.normal.dot(vj.clone().sub(vi));
  300. v = vi.interpolate(vj, t);
  301. f.push(v);
  302. b.push(v);
  303. }
  304. }
  305. return returning((polys = []), function() {
  306. if (f.length >= 3) {
  307. polys.push(new ThreeBSP.Polygon(f));
  308. }
  309. if (b.length >= 3) {
  310. return polys.push(new ThreeBSP.Polygon(b));
  311. }
  312. });
  313. };
  314. Polygon.prototype.subdivide = function(polygon, coplanar_front, coplanar_back, front, back) {
  315. var poly, side, _i, _len, _ref, _results;
  316. _ref = this.tessellate(polygon);
  317. _results = [];
  318. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  319. poly = _ref[_i];
  320. side = this.classifySide(poly);
  321. switch (side) {
  322. case FRONT:
  323. _results.push(front.push(poly));
  324. break;
  325. case BACK:
  326. _results.push(back.push(poly));
  327. break;
  328. case COPLANAR:
  329. if (this.normal.dot(poly.normal) > 0) {
  330. _results.push(coplanar_front.push(poly));
  331. } else {
  332. _results.push(coplanar_back.push(poly));
  333. }
  334. break;
  335. default:
  336. throw new Error("BUG: Polygon of classification " + side + " in subdivision");
  337. }
  338. }
  339. return _results;
  340. };
  341. return Polygon;
  342. })();
  343. ThreeBSP.Node = (function() {
  344. Node.prototype.clone = function() {
  345. var node,
  346. _this = this;
  347. return returning((node = new ThreeBSP.Node()), function() {
  348. var p, _ref, _ref1, _ref2;
  349. node.divider = (_ref = _this.divider) != null ? _ref.clone() : void 0;
  350. node.polygons = (function() {
  351. var _i, _len, _ref1, _results;
  352. _ref1 = this.polygons;
  353. _results = [];
  354. for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
  355. p = _ref1[_i];
  356. _results.push(p.clone());
  357. }
  358. return _results;
  359. }).call(_this);
  360. node.front = (_ref1 = _this.front) != null ? _ref1.clone() : void 0;
  361. return node.back = (_ref2 = _this.back) != null ? _ref2.clone() : void 0;
  362. });
  363. };
  364. function Node(polygons) {
  365. this.clipTo = __bind(this.clipTo, this);
  366. this.clipPolygons = __bind(this.clipPolygons, this);
  367. this.invert = __bind(this.invert, this);
  368. this.allPolygons = __bind(this.allPolygons, this);
  369. this.isConvex = __bind(this.isConvex, this);
  370. this.build = __bind(this.build, this);
  371. this.clone = __bind(this.clone, this);
  372. this.polygons = [];
  373. if ((polygons != null) && polygons.length) {
  374. this.build(polygons);
  375. }
  376. }
  377. Node.prototype.build = function(polygons) {
  378. var _this = this;
  379. return returning(this, function() {
  380. var poly, polys, side, sides, _i, _len, _results;
  381. sides = {
  382. front: [],
  383. back: []
  384. };
  385. if (_this.divider == null) {
  386. _this.divider = polygons[0].clone();
  387. }
  388. for (_i = 0, _len = polygons.length; _i < _len; _i++) {
  389. poly = polygons[_i];
  390. _this.divider.subdivide(poly, _this.polygons, _this.polygons, sides.front, sides.back);
  391. }
  392. _results = [];
  393. for (side in sides) {
  394. if (!__hasProp.call(sides, side)) continue;
  395. polys = sides[side];
  396. if (polys.length) {
  397. if (_this[side] == null) {
  398. _this[side] = new ThreeBSP.Node();
  399. }
  400. _results.push(_this[side].build(polys));
  401. } else {
  402. _results.push(void 0);
  403. }
  404. }
  405. return _results;
  406. });
  407. };
  408. Node.prototype.isConvex = function(polys) {
  409. var inner, outer, _i, _j, _len, _len1;
  410. for (_i = 0, _len = polys.length; _i < _len; _i++) {
  411. inner = polys[_i];
  412. for (_j = 0, _len1 = polys.length; _j < _len1; _j++) {
  413. outer = polys[_j];
  414. if (inner !== outer && outer.classifySide(inner) !== BACK) {
  415. return false;
  416. }
  417. }
  418. }
  419. return true;
  420. };
  421. Node.prototype.allPolygons = function() {
  422. var _ref, _ref1;
  423. return this.polygons.slice().concat(((_ref1 = this.front) != null ? _ref1.allPolygons() : void 0) || []).concat(((_ref = this.back) != null ? _ref.allPolygons() : void 0) || []);
  424. };
  425. Node.prototype.invert = function() {
  426. var _this = this;
  427. return returning(this, function() {
  428. var flipper, poly, _i, _j, _len, _len1, _ref, _ref1, _ref2;
  429. _ref = _this.polygons;
  430. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  431. poly = _ref[_i];
  432. poly.invert();
  433. }
  434. _ref1 = [_this.divider, _this.front, _this.back];
  435. for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
  436. flipper = _ref1[_j];
  437. if (flipper != null) {
  438. flipper.invert();
  439. }
  440. }
  441. return _ref2 = [_this.back, _this.front], _this.front = _ref2[0], _this.back = _ref2[1], _ref2;
  442. });
  443. };
  444. Node.prototype.clipPolygons = function(polygons) {
  445. var back, front, poly, _i, _len;
  446. if (!this.divider) {
  447. return polygons.slice();
  448. }
  449. front = [];
  450. back = [];
  451. for (_i = 0, _len = polygons.length; _i < _len; _i++) {
  452. poly = polygons[_i];
  453. this.divider.subdivide(poly, front, back, front, back);
  454. }
  455. if (this.front) {
  456. front = this.front.clipPolygons(front);
  457. }
  458. if (this.back) {
  459. back = this.back.clipPolygons(back);
  460. }
  461. return front.concat(this.back ? back : []);
  462. };
  463. Node.prototype.clipTo = function(node) {
  464. var _this = this;
  465. return returning(this, function() {
  466. var _ref, _ref1;
  467. _this.polygons = node.clipPolygons(_this.polygons);
  468. if ((_ref = _this.front) != null) {
  469. _ref.clipTo(node);
  470. }
  471. return (_ref1 = _this.back) != null ? _ref1.clipTo(node) : void 0;
  472. });
  473. };
  474. return Node;
  475. })();
  476. }).call(this);