ThreeBSP.js源码编译后js文件
官方仓库为CoffeeScript代码编写 也可以自行拉去,根据官方文档进行编译 编译脚本 首先全局下载coffeescript
npm install --global coffeescript
编译脚本(切换到src目录下)
coffee -c .\ThreeBSP.coffee
// Generated by CoffeeScript 2.7.0
(function () {
var BACK, COPLANAR, EPSILON, FRONT, SPANNING, Timelimit, ref, returning,
boundMethodCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } },
hasProp = {}.hasOwnProperty;
EPSILON = 1e-5;
COPLANAR = 0;
FRONT = 1;
BACK = 2;
SPANNING = 3;
// Call the callback with no arguments
// then return the first value.
// Used to construct chainable
// callbacks
returning = function (value, fn) {
fn();
return value;
};
Timelimit = class Timelimit {
constructor(timeout, progress) {
this.check = this.check.bind(this);
this.start = this.start.bind(this);
this.finish = this.finish.bind(this);
this.doTask = this.doTask.bind(this);
this.timeout = timeout;
this.progress = progress;
"NOTHING";
}
check() {
var elapsed;
if (this.started == null) {
return;
}
return returning((elapsed = Date.now() - this.started), () => {
var ref, ref1, ref2;
if ((ref = elapsed >= this.timeout) != null ? ref : 2e308) {
throw new Error(`Timeout reached: ${elapsed}/${this.timeout}, ${(ref1 = this.tasks) != null ? ref1 : 0} tasks unfinished ${(ref2 = this.done) != null ? ref2 : 0} finished.`);
}
});
}
start() {
if (this.started == null) {
this.started = Date.now();
}
if (this.tasks == null) {
this.tasks = 0;
}
if (this.total == null) {
this.total = 0;
}
this.total += 1;
this.tasks += 1;
return this.check();
}
finish() {
var elapsed;
if ((this.tasks != null) && this.tasks < 1) {
throw new Error("Finished more tasks than started");
}
this.tasks -= 1;
elapsed = this.check();
if (this.done == null) {
this.done = 0;
}
this.done += 1;
if (this.progress != null) {
this.progress(this.done, this.total);
}
if (this.tasks === 0) {
`Finished ${this.done} tasks in ${elapsed}/${this.timeout} ms`;
return this.started = this.done = this.total = void 0;
}
}
doTask(block) {
var result;
this.start();
result = block();
this.finish();
return result;
}
};
//#
//# ThreBSP Driver
// Can be instantiated with THREE.Geometry,
// THREE.Mesh or a ThreeBSP.Node
window.ThreeBSP = class ThreeBSP {
constructor(treeIsh, matrix1, options = {}) {
var base, ref, ref1, ref2, ref3;
// Evaluate block after replacing @timer with new_timer
// then put @timer back after block returns
this.withTimer = this.withTimer.bind(this);
this.toTree = this.toTree.bind(this);
// Converters/Exporters
this.toMesh = this.toMesh.bind(this);
this.toGeometry = this.toGeometry.bind(this);
// CSG Operations
this.subtract = this.subtract.bind(this);
this.union = this.union.bind(this);
this.intersect = this.intersect.bind(this);
this.matrix = matrix1;
this.options = options;
if ((this.matrix != null) && !(this.matrix instanceof THREE.Matrix4)) {
this.options = this.matrix;
this.matrix = void 0;
}
if (this.options == null) {
this.options = {};
}
if (this.matrix == null) {
this.matrix = new THREE.Matrix4();
}
// Start a timer if one wasn't passed
if ((base = this.options).timer == null) {
base.timer = new Timelimit((ref = (ref1 = this.options.timer) != null ? ref1.timeout : void 0) != null ? ref : this.options.timeout, (ref2 = (ref3 = this.options.timer) != null ? ref3.progress : void 0) != null ? ref2 : this.options.progress);
}
this.tree = this.toTree(treeIsh);
}
withTimer(new_timer, block) {
var old_timer;
old_timer = this.options.timer;
try {
this.options.timer = new_timer;
return block();
} finally {
this.options.timer = old_timer;
}
}
toTree(treeIsh) {
var face, geometry, i, k, len, polygons, ref;
if (treeIsh instanceof ThreeBSP.Node) {
return treeIsh;
}
polygons = [];
geometry = treeIsh instanceof THREE.Geometry ? treeIsh : treeIsh instanceof THREE.Mesh ? (treeIsh.updateMatrix(), this.matrix = treeIsh.matrix.clone(), treeIsh.geometry) : void 0;
ref = geometry.faces;
for (i = k = 0, len = ref.length; k < len; i = ++k) {
face = ref[i];
((face, i) => {
var faceVertexUvs, idx, l, len1, polygon, ref1, ref2, vIndex, vName, vertex;
faceVertexUvs = (ref1 = geometry.faceVertexUvs) != null ? ref1[0][i] : void 0;
if (faceVertexUvs == null) {
faceVertexUvs = [new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2()];
}
polygon = new ThreeBSP.Polygon();
ref2 = ['a', 'b', 'c', 'd'];
for (vIndex = l = 0, len1 = ref2.length; l < len1; vIndex = ++l) {
vName = ref2[vIndex];
if ((idx = face[vName]) != null) {
vertex = geometry.vertices[idx];
vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2(faceVertexUvs[vIndex].x, faceVertexUvs[vIndex].y));
vertex.applyMatrix4(this.matrix);
polygon.vertices.push(vertex);
}
}
return polygons.push(polygon.calculateProperties());
})(face, i);
}
return new ThreeBSP.Node(polygons, this.options);
}
toMesh(material = new THREE.MeshNormalMaterial()) {
return this.options.timer.doTask(() => {
var geometry, mesh;
geometry = this.toGeometry();
return returning((mesh = new THREE.Mesh(geometry, material)), () => {
mesh.position.getPositionFromMatrix(this.matrix);
return mesh.rotation.setEulerFromRotationMatrix(this.matrix);
});
});
}
toGeometry() {
return this.options.timer.doTask(() => {
var geometry, matrix;
matrix = new THREE.Matrix4().getInverse(this.matrix);
return returning((geometry = new THREE.Geometry()), () => {
var k, len, polygon, ref, results;
ref = this.tree.allPolygons();
results = [];
for (k = 0, len = ref.length; k < len; k++) {
polygon = ref[k];
results.push(this.options.timer.doTask(() => {
var face, idx, l, polyVerts, ref1, results1, v, vertUvs, verts;
polyVerts = (function () {
var l, len1, ref1, results1;
ref1 = polygon.vertices;
results1 = [];
for (l = 0, len1 = ref1.length; l < len1; l++) {
v = ref1[l];
results1.push(v.clone().applyMatrix4(matrix));
}
return results1;
})();
results1 = [];
for (idx = l = 2, ref1 = polyVerts.length; (2 <= ref1 ? l < ref1 : l > ref1); idx = 2 <= ref1 ? ++l : --l) {
verts = [polyVerts[0], polyVerts[idx - 1], polyVerts[idx]];
vertUvs = (function () {
var len1, m, ref2, ref3, results2;
results2 = [];
for (m = 0, len1 = verts.length; m < len1; m++) {
v = verts[m];
results2.push(new THREE.Vector2((ref2 = v.uv) != null ? ref2.x : void 0, (ref3 = v.uv) != null ? ref3.y : void 0));
}
return results2;
})();
face = new THREE.Face3(...((function () {
var len1, m, results2;
results2 = [];
for (m = 0, len1 = verts.length; m < len1; m++) {
v = verts[m];
results2.push(geometry.vertices.push(v) - 1);
}
return results2;
})()), polygon.normal.clone());
geometry.faces.push(face);
results1.push(geometry.faceVertexUvs[0].push(vertUvs));
}
return results1;
}));
}
return results;
});
});
}
subtract(other) {
return this.options.timer.doTask(() => {
return other.withTimer(this.options.timer, () => {
var them, us;
[us, them] = [this.tree.clone(), other.tree.clone()];
us.invert().clipTo(them);
them.clipTo(us).invert().clipTo(us).invert();
return new ThreeBSP(us.build(them.allPolygons()).invert(), this.matrix, this.options);
});
});
}
union(other) {
return this.options.timer.doTask(() => {
return other.withTimer(this.options.timer, () => {
var them, us;
[us, them] = [this.tree.clone(), other.tree.clone()];
us.clipTo(them);
them.clipTo(us).invert().clipTo(us).invert();
return new ThreeBSP(us.build(them.allPolygons()), this.matrix, this.options);
});
});
}
intersect(other) {
return this.options.timer.doTask(() => {
return other.withTimer(this.options.timer, () => {
var them, us;
[us, them] = [this.tree.clone(), other.tree.clone()];
them.clipTo(us.invert()).invert().clipTo(us.clipTo(them));
return new ThreeBSP(us.build(them.allPolygons()).invert(), this.matrix, this.options);
});
});
}
};
//#
//# ThreeBSP.Vertex
ref = ThreeBSP.Vertex = class Vertex extends THREE.Vector3 {
constructor(x, y, z, normal = new THREE.Vector3(), uv = new THREE.Vector2()) {
super(x, y, z);
this.lerp = this.lerp.bind(this);
this.interpolate = this.interpolate.bind(this);
this.normal = normal;
this.uv = uv;
}
clone() {
return new ThreeBSP.Vertex(this.x, this.y, this.z, this.normal.clone(), this.uv.clone());
}
lerp(v, alpha) {
boundMethodCheck(this, ref);
return returning(super.lerp(() => {
this.uv.add(v.uv.clone().sub(this.uv).multiplyScalar(alpha));
return this.normal.lerp(v, alpha);
}));
}
interpolate(...args) {
boundMethodCheck(this, ref);
return this.clone().lerp(...args);
}
};
//#
//# ThreeBSP.Polygon
ThreeBSP.Polygon = class Polygon {
constructor(vertices = [], normal, w) {
this.calculateProperties = this.calculateProperties.bind(this);
this.clone = this.clone.bind(this);
this.invert = this.invert.bind(this);
this.classifyVertex = this.classifyVertex.bind(this);
this.classifySide = this.classifySide.bind(this);
// Return a list of polygons from `poly` such
// that no polygons span the plane defined by
// `this`. Should be a list of one or two Polygons
this.tessellate = this.tessellate.bind(this);
this.subdivide = this.subdivide.bind(this);
this.vertices = vertices;
this.normal = normal;
this.w = w;
if (this.vertices.length) {
this.calculateProperties();
}
}
calculateProperties() {
return returning(this, () => {
var a, b, c;
[a, b, c] = this.vertices;
this.normal = b.clone().sub(a).cross(c.clone().sub(a)).normalize();
return this.w = this.normal.clone().dot(a);
});
}
clone() {
var v;
return new ThreeBSP.Polygon((function () {
var k, len, ref1, results;
ref1 = this.vertices;
results = [];
for (k = 0, len = ref1.length; k < len; k++) {
v = ref1[k];
results.push(v.clone());
}
return results;
}).call(this), this.normal.clone(), this.w);
}
invert() {
return returning(this, () => {
this.normal.multiplyScalar(-1);
this.w *= -1;
return this.vertices.reverse();
});
}
classifyVertex(vertex) {
var side;
side = this.normal.dot(vertex) - this.w;
switch (false) {
case !(side < -EPSILON):
return BACK;
case !(side > EPSILON):
return FRONT;
default:
return COPLANAR;
}
}
classifySide(polygon) {
var back, front, tally, v;
[front, back] = [0, 0];
tally = (v) => {
switch (this.classifyVertex(v)) {
case FRONT:
return front += 1;
case BACK:
return back += 1;
}
};
(function () {
var k, len, ref1, results;
ref1 = polygon.vertices;
results = [];
for (k = 0, len = ref1.length; k < len; k++) {
v = ref1[k];
results.push(tally(v));
}
return results;
})();
if (front > 0 && back === 0) {
return FRONT;
}
if (front === 0 && back > 0) {
return BACK;
}
if ((front === back && back === 0)) {
return COPLANAR;
}
return SPANNING;
}
tessellate(poly) {
var b, count, f, i, j, k, len, polys, ref1, t, ti, tj, v, vi, vj;
({ f, b, count } = {
f: [],
b: [],
count: poly.vertices.length
});
if (this.classifySide(poly) !== SPANNING) {
return [poly];
}
ref1 = poly.vertices;
// vi and vj are the current and next Vertex
// i and j are the indexes of vi and vj
// ti and tj are the classifications of vi and vj
for (i = k = 0, len = ref1.length; k < len; i = ++k) {
vi = ref1[i];
vj = poly.vertices[(j = (i + 1) % count)];
[ti, tj] = (function () {
var l, len1, ref2, results;
ref2 = [vi, vj];
results = [];
for (l = 0, len1 = ref2.length; l < len1; l++) {
v = ref2[l];
results.push(this.classifyVertex(v));
}
return results;
}).call(this);
if (ti !== BACK) {
f.push(vi);
}
if (ti !== FRONT) {
b.push(vi);
}
if ((ti | tj) === SPANNING) {
t = (this.w - this.normal.dot(vi)) / this.normal.dot(vj.clone().sub(vi));
v = vi.interpolate(vj, t);
f.push(v);
b.push(v);
}
}
return returning((polys = []), () => {
if (f.length >= 3) {
polys.push(new ThreeBSP.Polygon(f));
}
if (b.length >= 3) {
return polys.push(new ThreeBSP.Polygon(b));
}
});
}
subdivide(polygon, coplanar_front, coplanar_back, front, back) {
var k, len, poly, ref1, results, side;
ref1 = this.tessellate(polygon);
results = [];
for (k = 0, len = ref1.length; k < len; k++) {
poly = ref1[k];
side = this.classifySide(poly);
switch (side) {
case FRONT:
results.push(front.push(poly));
break;
case BACK:
results.push(back.push(poly));
break;
case COPLANAR:
if (this.normal.dot(poly.normal) > 0) {
results.push(coplanar_front.push(poly));
} else {
results.push(coplanar_back.push(poly));
}
break;
default:
throw new Error(`BUG: Polygon of classification ${side} in subdivision`);
}
}
return results;
}
};
//#
//# ThreeBSP.Node
ThreeBSP.Node = class Node {
clone() {
var node;
return returning((node = new ThreeBSP.Node(this.options)), () => {
var ref1;
node.divider = (ref1 = this.divider) != null ? ref1.clone() : void 0;
node.polygons = this.options.timer.doTask(() => {
var k, len, p, ref2, results;
ref2 = this.polygons;
results = [];
for (k = 0, len = ref2.length; k < len; k++) {
p = ref2[k];
results.push(p.clone());
}
return results;
});
node.front = this.options.timer.doTask(() => {
var ref2;
return (ref2 = this.front) != null ? ref2.clone() : void 0;
});
return node.back = this.options.timer.doTask(() => {
var ref2;
return (ref2 = this.back) != null ? ref2.clone() : void 0;
});
});
}
constructor(polygons, options = {}) {
this.clone = this.clone.bind(this);
this.build = this.build.bind(this);
this.isConvex = this.isConvex.bind(this);
this.allPolygons = this.allPolygons.bind(this);
this.invert = this.invert.bind(this);
this.clipPolygons = this.clipPolygons.bind(this);
this.clipTo = this.clipTo.bind(this);
this.options = options;
if ((polygons != null) && !(polygons instanceof Array)) {
this.options = polygons;
polygons = void 0;
}
this.polygons = [];
this.options.timer.doTask(() => {
if ((polygons != null) && polygons.length) {
return this.build(polygons);
}
});
}
build(polygons) {
return returning(this, () => {
var polys, results, side, sides;
sides = {
front: [],
back: []
};
if (this.divider == null) {
this.divider = polygons[0].clone();
}
this.options.timer.doTask(() => {
var k, len, poly, results;
results = [];
for (k = 0, len = polygons.length; k < len; k++) {
poly = polygons[k];
results.push(this.options.timer.doTask(() => {
return this.divider.subdivide(poly, this.polygons, this.polygons, sides.front, sides.back);
}));
}
return results;
});
results = [];
for (side in sides) {
if (!hasProp.call(sides, side)) continue;
polys = sides[side];
if (polys.length) {
if (this[side] == null) {
this[side] = new ThreeBSP.Node(this.options);
}
results.push(this[side].build(polys));
} else {
results.push(void 0);
}
}
return results;
});
}
isConvex(polys) {
var inner, k, l, len, len1, outer;
for (k = 0, len = polys.length; k < len; k++) {
inner = polys[k];
for (l = 0, len1 = polys.length; l < len1; l++) {
outer = polys[l];
if (inner !== outer && outer.classifySide(inner) !== BACK) {
return false;
}
}
}
return true;
}
allPolygons() {
return this.options.timer.doTask(() => {
var ref1, ref2;
return this.polygons.slice().concat(((ref2 = this.front) != null ? ref2.allPolygons() : void 0) || []).concat(((ref1 = this.back) != null ? ref1.allPolygons() : void 0) || []);
});
}
invert() {
return returning(this, () => {
return this.options.timer.doTask(() => {
var flipper, k, l, len, len1, poly, ref1, ref2;
ref1 = this.polygons;
for (k = 0, len = ref1.length; k < len; k++) {
poly = ref1[k];
this.options.timer.doTask(() => {
return poly.invert();
});
}
ref2 = [this.divider, this.front, this.back];
for (l = 0, len1 = ref2.length; l < len1; l++) {
flipper = ref2[l];
this.options.timer.doTask(() => {
return flipper != null ? flipper.invert() : void 0;
});
}
return [this.front, this.back] = [this.back, this.front];
});
});
}
clipPolygons(polygons) {
return this.options.timer.doTask(() => {
var back, front, k, len, poly;
if (!this.divider) {
return polygons.slice();
}
front = [];
back = [];
for (k = 0, len = polygons.length; k < len; k++) {
poly = polygons[k];
this.options.timer.doTask(() => {
return this.divider.subdivide(poly, front, back, front, back);
});
}
if (this.front) {
front = this.front.clipPolygons(front);
}
if (this.back) {
back = this.back.clipPolygons(back);
}
if (this.back) {
return front.concat(back);
} else {
return front;
}
});
}
clipTo(node) {
return returning(this, () => {
return this.options.timer.doTask(() => {
var ref1, ref2;
this.polygons = node.clipPolygons(this.polygons);
if ((ref1 = this.front) != null) {
ref1.clipTo(node);
}
return (ref2 = this.back) != null ? ref2.clipTo(node) : void 0;
});
});
}
};
}).call(this);