添加实体差集
This commit is contained in:
parent
ba3e5cabfd
commit
1e40bb624f
702
src/ThreeCSG.ts
Normal file
702
src/ThreeCSG.ts
Normal file
@ -0,0 +1,702 @@
|
|||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
|
const EPSILON = 1e-5,
|
||||||
|
COPLANAR = 0, //共面
|
||||||
|
FRONT = 1, //前
|
||||||
|
BACK = 2,
|
||||||
|
SPANNING = 3;
|
||||||
|
|
||||||
|
export class ThreeBSP
|
||||||
|
{
|
||||||
|
tree: Node;
|
||||||
|
matrix: THREE.Matrix4;
|
||||||
|
Node: typeof Node;
|
||||||
|
Vertex: typeof Vertex;
|
||||||
|
Polygon: typeof Polygon;
|
||||||
|
constructor(geometry)
|
||||||
|
{
|
||||||
|
// Convert THREE.Geometry to ThreeBSP
|
||||||
|
let i, _length_i,
|
||||||
|
face, vertex, faceVertexUvs, uvs,
|
||||||
|
polygon,
|
||||||
|
polygons = [],
|
||||||
|
tree;
|
||||||
|
|
||||||
|
this.Polygon = Polygon;
|
||||||
|
this.Vertex = Vertex;
|
||||||
|
this.Node = Node;
|
||||||
|
if (geometry instanceof THREE.Geometry)
|
||||||
|
{
|
||||||
|
this.matrix = new THREE.Matrix4();
|
||||||
|
} else if (geometry instanceof THREE.Mesh)
|
||||||
|
{
|
||||||
|
// #todo: add hierarchy support
|
||||||
|
geometry.updateMatrix();
|
||||||
|
this.matrix = geometry.matrix.clone();
|
||||||
|
geometry = geometry.geometry;
|
||||||
|
} else if (geometry instanceof Node)
|
||||||
|
{
|
||||||
|
this.tree = geometry;
|
||||||
|
this.matrix = new THREE.Matrix4();
|
||||||
|
return this;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw 'ThreeBSP: Given geometry is unsupported';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, _length_i = geometry.faces.length; i < _length_i; i++)
|
||||||
|
{
|
||||||
|
face = geometry.faces[i];
|
||||||
|
faceVertexUvs = geometry.faceVertexUvs[0][i];
|
||||||
|
polygon = new Polygon();
|
||||||
|
|
||||||
|
if (face instanceof THREE.Face3)
|
||||||
|
{
|
||||||
|
vertex = geometry.vertices[face.a];
|
||||||
|
uvs = faceVertexUvs ? new THREE.Vector2(faceVertexUvs[0].x, faceVertexUvs[0].y) : null;
|
||||||
|
vertex = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], uvs);
|
||||||
|
vertex.applyMatrix4(this.matrix);
|
||||||
|
polygon.vertices.push(vertex);
|
||||||
|
|
||||||
|
vertex = geometry.vertices[face.b];
|
||||||
|
uvs = faceVertexUvs ? new THREE.Vector2(faceVertexUvs[1].x, faceVertexUvs[1].y) : null;
|
||||||
|
vertex = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[1], uvs);
|
||||||
|
vertex.applyMatrix4(this.matrix);
|
||||||
|
polygon.vertices.push(vertex);
|
||||||
|
|
||||||
|
vertex = geometry.vertices[face.c];
|
||||||
|
uvs = faceVertexUvs ? new THREE.Vector2(faceVertexUvs[2].x, faceVertexUvs[2].y) : null;
|
||||||
|
vertex = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[2], uvs);
|
||||||
|
vertex.applyMatrix4(this.matrix);
|
||||||
|
polygon.vertices.push(vertex);
|
||||||
|
} else if (typeof THREE.Face4)
|
||||||
|
{
|
||||||
|
vertex = geometry.vertices[face.a];
|
||||||
|
uvs = faceVertexUvs ? new THREE.Vector2(faceVertexUvs[0].x, faceVertexUvs[0].y) : null;
|
||||||
|
vertex = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], uvs);
|
||||||
|
vertex.applyMatrix4(this.matrix);
|
||||||
|
polygon.vertices.push(vertex);
|
||||||
|
|
||||||
|
vertex = geometry.vertices[face.b];
|
||||||
|
uvs = faceVertexUvs ? new THREE.Vector2(faceVertexUvs[1].x, faceVertexUvs[1].y) : null;
|
||||||
|
vertex = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[1], uvs);
|
||||||
|
vertex.applyMatrix4(this.matrix);
|
||||||
|
polygon.vertices.push(vertex);
|
||||||
|
|
||||||
|
vertex = geometry.vertices[face.c];
|
||||||
|
uvs = faceVertexUvs ? new THREE.Vector2(faceVertexUvs[2].x, faceVertexUvs[2].y) : null;
|
||||||
|
vertex = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[2], uvs);
|
||||||
|
vertex.applyMatrix4(this.matrix);
|
||||||
|
polygon.vertices.push(vertex);
|
||||||
|
|
||||||
|
vertex = geometry.vertices[face.d];
|
||||||
|
uvs = faceVertexUvs ? new THREE.Vector2(faceVertexUvs[3].x, faceVertexUvs[3].y) : null;
|
||||||
|
vertex = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[3], uvs);
|
||||||
|
vertex.applyMatrix4(this.matrix);
|
||||||
|
polygon.vertices.push(vertex);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw 'Invalid face type at index ' + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
polygon.calculateProperties();
|
||||||
|
polygons.push(polygon);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tree = new Node(polygons);
|
||||||
|
}
|
||||||
|
|
||||||
|
//减
|
||||||
|
subtract(other_tree)
|
||||||
|
{
|
||||||
|
let a = this.tree.clone(),
|
||||||
|
b = other_tree.tree.clone();
|
||||||
|
|
||||||
|
a.invert();
|
||||||
|
a.clipTo(b);
|
||||||
|
b.clipTo(a);
|
||||||
|
b.invert();
|
||||||
|
b.clipTo(a);
|
||||||
|
b.invert();
|
||||||
|
a.build(b.allPolygons());
|
||||||
|
a.invert();
|
||||||
|
let bsp = new ThreeBSP(a);
|
||||||
|
bsp.matrix = this.matrix;
|
||||||
|
return bsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//结合
|
||||||
|
union(other_tree)
|
||||||
|
{
|
||||||
|
let a = this.tree.clone(),
|
||||||
|
b = other_tree.tree.clone();
|
||||||
|
|
||||||
|
a.clipTo(b);
|
||||||
|
b.clipTo(a);
|
||||||
|
b.invert();
|
||||||
|
b.clipTo(a);
|
||||||
|
b.invert();
|
||||||
|
a.build(b.allPolygons());
|
||||||
|
let bsp = new ThreeBSP(a);
|
||||||
|
bsp.matrix = this.matrix;
|
||||||
|
return bsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//相交
|
||||||
|
intersect(other_tree)
|
||||||
|
{
|
||||||
|
let a = this.tree.clone(),
|
||||||
|
b = other_tree.tree.clone();
|
||||||
|
|
||||||
|
a.invert();
|
||||||
|
b.clipTo(a);
|
||||||
|
b.invert();
|
||||||
|
a.clipTo(b);
|
||||||
|
b.clipTo(a);
|
||||||
|
a.build(b.allPolygons());
|
||||||
|
a.invert();
|
||||||
|
let bsp = new ThreeBSP(a);
|
||||||
|
bsp.matrix = this.matrix;
|
||||||
|
return bsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
toGeometry()
|
||||||
|
{
|
||||||
|
let i, j,
|
||||||
|
matrix = new THREE.Matrix4().getInverse(this.matrix),
|
||||||
|
geometry = new THREE.Geometry(),
|
||||||
|
polygons = this.tree.allPolygons(),
|
||||||
|
polygon_count = polygons.length,
|
||||||
|
polygon, polygon_vertice_count,
|
||||||
|
vertice_dict = {},
|
||||||
|
vertex_idx_a, vertex_idx_b, vertex_idx_c,
|
||||||
|
vertex, face,
|
||||||
|
verticeUvs;
|
||||||
|
|
||||||
|
for (i = 0; i < polygon_count; i++)
|
||||||
|
{
|
||||||
|
polygon = polygons[i];
|
||||||
|
polygon_vertice_count = polygon.vertices.length;
|
||||||
|
|
||||||
|
for (j = 2; j < polygon_vertice_count; j++)
|
||||||
|
{
|
||||||
|
verticeUvs = [];
|
||||||
|
|
||||||
|
vertex = polygon.vertices[0];
|
||||||
|
verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));
|
||||||
|
vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);
|
||||||
|
vertex.applyMatrix4(matrix);
|
||||||
|
|
||||||
|
if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined')
|
||||||
|
{
|
||||||
|
vertex_idx_a = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
geometry.vertices.push(vertex);
|
||||||
|
vertex_idx_a = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex = polygon.vertices[j - 1];
|
||||||
|
verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));
|
||||||
|
vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);
|
||||||
|
vertex.applyMatrix4(matrix);
|
||||||
|
if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined')
|
||||||
|
{
|
||||||
|
vertex_idx_b = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
geometry.vertices.push(vertex);
|
||||||
|
vertex_idx_b = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex = polygon.vertices[j];
|
||||||
|
verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));
|
||||||
|
vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);
|
||||||
|
vertex.applyMatrix4(matrix);
|
||||||
|
if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined')
|
||||||
|
{
|
||||||
|
vertex_idx_c = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
geometry.vertices.push(vertex);
|
||||||
|
vertex_idx_c = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
face = new THREE.Face3(
|
||||||
|
vertex_idx_a,
|
||||||
|
vertex_idx_b,
|
||||||
|
vertex_idx_c,
|
||||||
|
new THREE.Vector3(polygon.normal.x, polygon.normal.y, polygon.normal.z)
|
||||||
|
);
|
||||||
|
|
||||||
|
geometry.faces.push(face);
|
||||||
|
geometry.faceVertexUvs[0].push(verticeUvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
toMesh(material)
|
||||||
|
{
|
||||||
|
let geometry = this.toGeometry(),
|
||||||
|
mesh = new THREE.Mesh(geometry, material);
|
||||||
|
|
||||||
|
mesh.position.setFromMatrixPosition(this.matrix);
|
||||||
|
mesh.rotation.setFromRotationMatrix(this.matrix);
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//多边形
|
||||||
|
export class Polygon
|
||||||
|
{
|
||||||
|
w: any;
|
||||||
|
normal: any;
|
||||||
|
vertices: any;
|
||||||
|
constructor(vertices?, normal?, w?)
|
||||||
|
{
|
||||||
|
if (!(vertices instanceof Array))
|
||||||
|
{
|
||||||
|
vertices = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vertices = vertices;
|
||||||
|
if (vertices.length > 0)
|
||||||
|
{
|
||||||
|
this.calculateProperties();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.normal = this.w = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateProperties()
|
||||||
|
{
|
||||||
|
let a = this.vertices[0],
|
||||||
|
b = this.vertices[1],
|
||||||
|
c = this.vertices[2];
|
||||||
|
|
||||||
|
this.normal = b.clone().subtract(a).cross(
|
||||||
|
c.clone().subtract(a)
|
||||||
|
).normalize();
|
||||||
|
|
||||||
|
this.w = this.normal.clone().dot(a);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone()
|
||||||
|
{
|
||||||
|
let i, vertice_count,
|
||||||
|
polygon = new Polygon();
|
||||||
|
|
||||||
|
for (i = 0, vertice_count = this.vertices.length; i < vertice_count; i++)
|
||||||
|
{
|
||||||
|
polygon.vertices.push(this.vertices[i].clone());
|
||||||
|
}
|
||||||
|
polygon.calculateProperties();
|
||||||
|
|
||||||
|
return polygon;
|
||||||
|
}
|
||||||
|
|
||||||
|
flip()
|
||||||
|
{
|
||||||
|
let i, vertices = [];
|
||||||
|
|
||||||
|
this.normal.multiplyScalar(-1);
|
||||||
|
this.w *= -1;
|
||||||
|
|
||||||
|
for (i = this.vertices.length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
vertices.push(this.vertices[i]);
|
||||||
|
}
|
||||||
|
this.vertices = vertices;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//划分?
|
||||||
|
classifyVertex(vertex)
|
||||||
|
{
|
||||||
|
let side_value = this.normal.dot(vertex) - this.w;
|
||||||
|
|
||||||
|
if (side_value < -EPSILON)
|
||||||
|
{
|
||||||
|
return BACK;
|
||||||
|
} else if (side_value > EPSILON)
|
||||||
|
{
|
||||||
|
return FRONT;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return COPLANAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//划分边?
|
||||||
|
classifySide(polygon)
|
||||||
|
{
|
||||||
|
let i, vertex, classification,
|
||||||
|
num_positive = 0,
|
||||||
|
num_negative = 0,
|
||||||
|
vertice_count = polygon.vertices.length;
|
||||||
|
|
||||||
|
for (i = 0; i < vertice_count; i++)
|
||||||
|
{
|
||||||
|
vertex = polygon.vertices[i];
|
||||||
|
classification = this.classifyVertex(vertex);
|
||||||
|
if (classification === FRONT)
|
||||||
|
{
|
||||||
|
num_positive++;
|
||||||
|
} else if (classification === BACK)
|
||||||
|
{
|
||||||
|
num_negative++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_positive > 0 && num_negative === 0)
|
||||||
|
{
|
||||||
|
return FRONT;
|
||||||
|
} else if (num_positive === 0 && num_negative > 0)
|
||||||
|
{
|
||||||
|
return BACK;
|
||||||
|
} else if (num_positive === 0 && num_negative === 0)
|
||||||
|
{
|
||||||
|
return COPLANAR;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return SPANNING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//分解 分离 区域?
|
||||||
|
splitPolygon(polygon, coplanar_front, coplanar_back, front, back)
|
||||||
|
{
|
||||||
|
let classification = this.classifySide(polygon);
|
||||||
|
|
||||||
|
if (classification === COPLANAR)
|
||||||
|
{
|
||||||
|
|
||||||
|
(this.normal.dot(polygon.normal) > 0 ? coplanar_front : coplanar_back).push(polygon);
|
||||||
|
|
||||||
|
} else if (classification === FRONT)
|
||||||
|
{
|
||||||
|
|
||||||
|
front.push(polygon);
|
||||||
|
|
||||||
|
} else if (classification === BACK)
|
||||||
|
{
|
||||||
|
|
||||||
|
back.push(polygon);
|
||||||
|
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
|
||||||
|
let vertice_count,
|
||||||
|
i, j, ti, tj, vi, vj,
|
||||||
|
t, v,
|
||||||
|
f = [],
|
||||||
|
b = [];
|
||||||
|
|
||||||
|
for (i = 0, vertice_count = polygon.vertices.length; i < vertice_count; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
j = (i + 1) % vertice_count;
|
||||||
|
vi = polygon.vertices[i];
|
||||||
|
vj = polygon.vertices[j];
|
||||||
|
ti = this.classifyVertex(vi);
|
||||||
|
tj = this.classifyVertex(vj);
|
||||||
|
|
||||||
|
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().subtract(vi));
|
||||||
|
v = vi.interpolate(vj, t);
|
||||||
|
f.push(v);
|
||||||
|
b.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (f.length >= 3) front.push(new Polygon(f).calculateProperties());
|
||||||
|
if (b.length >= 3) back.push(new Polygon(b).calculateProperties());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Vertex
|
||||||
|
{
|
||||||
|
uv: any;
|
||||||
|
normal: any;
|
||||||
|
z: any;
|
||||||
|
y: any;
|
||||||
|
x: any;
|
||||||
|
constructor(x: number, y: number, z: number, normal: THREE.Vector3, uv: THREE.Vector2)
|
||||||
|
{
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.normal = normal || new THREE.Vector3();
|
||||||
|
this.uv = uv || new THREE.Vector2();
|
||||||
|
}
|
||||||
|
|
||||||
|
clone()
|
||||||
|
{
|
||||||
|
return new Vertex(this.x, this.y, this.z, this.normal.clone(), this.uv.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
add(vertex)
|
||||||
|
{
|
||||||
|
this.x += vertex.x;
|
||||||
|
this.y += vertex.y;
|
||||||
|
this.z += vertex.z;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
subtract(vertex)
|
||||||
|
{
|
||||||
|
this.x -= vertex.x;
|
||||||
|
this.y -= vertex.y;
|
||||||
|
this.z -= vertex.z;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
multiplyScalar(scalar)
|
||||||
|
{
|
||||||
|
this.x *= scalar;
|
||||||
|
this.y *= scalar;
|
||||||
|
this.z *= scalar;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//×乘
|
||||||
|
cross(vertex)
|
||||||
|
{
|
||||||
|
let x = this.x,
|
||||||
|
y = this.y,
|
||||||
|
z = this.z;
|
||||||
|
|
||||||
|
this.x = y * vertex.z - z * vertex.y;
|
||||||
|
this.y = z * vertex.x - x * vertex.z;
|
||||||
|
this.z = x * vertex.y - y * vertex.x;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize()
|
||||||
|
{
|
||||||
|
let length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||||
|
|
||||||
|
this.x /= length;
|
||||||
|
this.y /= length;
|
||||||
|
this.z /= length;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//点乘
|
||||||
|
dot(vertex)
|
||||||
|
{
|
||||||
|
return this.x * vertex.x + this.y * vertex.y + this.z * vertex.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
//线性插值
|
||||||
|
lerp(a, t)
|
||||||
|
{
|
||||||
|
this.add(
|
||||||
|
a.clone().subtract(this).multiplyScalar(t)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.normal.add(
|
||||||
|
a.normal.clone().sub(this.normal).multiplyScalar(t)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.uv.add(
|
||||||
|
a.uv.clone().sub(this.uv).multiplyScalar(t)
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//插值
|
||||||
|
interpolate(other, t)
|
||||||
|
{
|
||||||
|
return this.clone().lerp(other, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyMatrix4(m)
|
||||||
|
{
|
||||||
|
|
||||||
|
// input: THREE.Matrix4 affine matrix
|
||||||
|
|
||||||
|
let x = this.x, y = this.y, z = this.z;
|
||||||
|
|
||||||
|
let e = m.elements;
|
||||||
|
|
||||||
|
this.x = e[0] * x + e[4] * y + e[8] * z + e[12];
|
||||||
|
this.y = e[1] * x + e[5] * y + e[9] * z + e[13];
|
||||||
|
this.z = e[2] * x + e[6] * y + e[10] * z + e[14];
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class Node
|
||||||
|
{
|
||||||
|
divider: any;
|
||||||
|
back: any;
|
||||||
|
front: any;
|
||||||
|
polygons: any[];
|
||||||
|
constructor(polygons?)
|
||||||
|
{
|
||||||
|
let i, polygon_count,
|
||||||
|
front = [],
|
||||||
|
back = [];
|
||||||
|
|
||||||
|
this.polygons = [];
|
||||||
|
this.front = this.back = undefined;
|
||||||
|
|
||||||
|
if (!(polygons instanceof Array) || polygons.length === 0) return;
|
||||||
|
|
||||||
|
this.divider = polygons[0].clone();
|
||||||
|
|
||||||
|
for (i = 0, polygon_count = polygons.length; i < polygon_count; i++)
|
||||||
|
{
|
||||||
|
this.divider.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (front.length > 0)
|
||||||
|
{
|
||||||
|
this.front = new Node(front);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (back.length > 0)
|
||||||
|
{
|
||||||
|
this.back = new Node(back);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//是凸的? 凸包?
|
||||||
|
isConvex(polygons)
|
||||||
|
{
|
||||||
|
let i, j;
|
||||||
|
for (i = 0; i < polygons.length; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < polygons.length; j++)
|
||||||
|
{
|
||||||
|
if (i !== j && polygons[i].classifySide(polygons[j]) !== BACK)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
build(polygons)
|
||||||
|
{
|
||||||
|
let i, polygon_count,
|
||||||
|
front = [],
|
||||||
|
back = [];
|
||||||
|
|
||||||
|
if (!this.divider)
|
||||||
|
{
|
||||||
|
this.divider = polygons[0].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, polygon_count = polygons.length; i < polygon_count; i++)
|
||||||
|
{
|
||||||
|
this.divider.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (front.length > 0)
|
||||||
|
{
|
||||||
|
if (!this.front) this.front = new Node();
|
||||||
|
this.front.build(front);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (back.length > 0)
|
||||||
|
{
|
||||||
|
if (!this.back) this.back = new Node();
|
||||||
|
this.back.build(back);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allPolygons()
|
||||||
|
{
|
||||||
|
let polygons = this.polygons.slice();
|
||||||
|
if (this.front) polygons = polygons.concat(this.front.allPolygons());
|
||||||
|
if (this.back) polygons = polygons.concat(this.back.allPolygons());
|
||||||
|
return polygons;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone()
|
||||||
|
{
|
||||||
|
let node = new Node();
|
||||||
|
|
||||||
|
node.divider = this.divider.clone();
|
||||||
|
node.polygons = this.polygons.map(function (polygon)
|
||||||
|
{
|
||||||
|
return polygon.clone();
|
||||||
|
});
|
||||||
|
node.front = this.front && this.front.clone();
|
||||||
|
node.back = this.back && this.back.clone();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
//反转
|
||||||
|
invert()
|
||||||
|
{
|
||||||
|
let i, polygon_count, temp;
|
||||||
|
|
||||||
|
for (i = 0, polygon_count = this.polygons.length; i < polygon_count; i++)
|
||||||
|
{
|
||||||
|
this.polygons[i].flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.divider.flip();
|
||||||
|
if (this.front) this.front.invert();
|
||||||
|
if (this.back) this.back.invert();
|
||||||
|
|
||||||
|
temp = this.front;
|
||||||
|
this.front = this.back;
|
||||||
|
this.back = temp;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
clipPolygons(polygons)
|
||||||
|
{
|
||||||
|
let i, polygon_count,
|
||||||
|
front, back;
|
||||||
|
|
||||||
|
if (!this.divider) return polygons.slice();
|
||||||
|
|
||||||
|
front = [];
|
||||||
|
back = [];
|
||||||
|
|
||||||
|
for (i = 0, polygon_count = polygons.length; i < polygon_count; i++)
|
||||||
|
{
|
||||||
|
this.divider.splitPolygon(polygons[i], front, back, front, back);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.front) front = this.front.clipPolygons(front);
|
||||||
|
if (this.back) back = this.back.clipPolygons(back);
|
||||||
|
else back = [];
|
||||||
|
|
||||||
|
return front.concat(back);
|
||||||
|
}
|
||||||
|
|
||||||
|
clipTo(node)
|
||||||
|
{
|
||||||
|
this.polygons = node.clipPolygons(this.polygons);
|
||||||
|
if (this.front) this.front.clipTo(node);
|
||||||
|
if (this.back) this.back.clipTo(node);
|
||||||
|
}
|
||||||
|
}
|
10
src/Utils.ts
10
src/Utils.ts
@ -11,14 +11,12 @@ export function LoadBoard(view: Viewer, data: any[])
|
|||||||
view.m_Scene.children.length = 0;
|
view.m_Scene.children.length = 0;
|
||||||
|
|
||||||
//加板
|
//加板
|
||||||
let brList = createTemplateBoard(data);
|
let { meshs, edgesa } = createTemplateBoard(data);
|
||||||
//线框
|
|
||||||
let edgeList = brList.map(br => createEdge(br));
|
|
||||||
//加标注
|
//加标注
|
||||||
let dims = DrawDimension(brList);
|
let dims = DrawDimension(meshs);
|
||||||
|
|
||||||
view.m_Scene.add(...brList);
|
view.m_Scene.add(...meshs);
|
||||||
view.m_Scene.add(...edgeList);
|
view.m_Scene.add(...edgesa);
|
||||||
view.m_Scene.add(...dims);
|
view.m_Scene.add(...dims);
|
||||||
|
|
||||||
view.ViewToSwiso();
|
view.ViewToSwiso();
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { LineSegments, Mesh } from 'three';
|
import { Geometry, LineSegments } from 'three';
|
||||||
import { polar } from './GeUtils';
|
import { polar } from './GeUtils';
|
||||||
import { boardMaterial, edgeMaterial } from './Material';
|
import { boardMaterial, edgeMaterial } from './Material';
|
||||||
import { RotateUVs } from './RotateUV';
|
import { RotateUVs } from './RotateUV';
|
||||||
|
import { ThreeBSP } from './ThreeCSG';
|
||||||
//解析二维圆弧类.
|
//解析二维圆弧类.
|
||||||
export class Arc2d
|
export class Arc2d
|
||||||
{
|
{
|
||||||
@ -115,28 +116,51 @@ export function createBoard(boardData: object)
|
|||||||
amount: boardHeight
|
amount: boardHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
let ext = new THREE.ExtrudeGeometry(sp, extrudeSettings);
|
let ext = new THREE.ExtrudeGeometry(sp, extrudeSettings) as Geometry;
|
||||||
ext.computeBoundingSphere();
|
ext.computeBoundingSphere();
|
||||||
ext.computeBoundingBox();
|
ext.computeBoundingBox();
|
||||||
ext.translate(0, 0, -boardHeight)
|
ext.translate(0, 0, -boardHeight)
|
||||||
ext.applyMatrix(boardMat);
|
ext.applyMatrix(boardMat);
|
||||||
|
|
||||||
if (boardData["BoardName"] === "地脚线")
|
//外边.
|
||||||
|
let edges = [createEdge(ext)];
|
||||||
|
//差集
|
||||||
|
if (boardData["SubBoardLocal"].length > 0)
|
||||||
{
|
{
|
||||||
RotateUVs(ext);
|
let subBoardList = boardData["SubBoardLocal"].map(d => createBoard(d));
|
||||||
|
let thisCsg = new ThreeBSP(ext);
|
||||||
|
|
||||||
|
for (let br of subBoardList)
|
||||||
|
{
|
||||||
|
edges.push(...br.edges);
|
||||||
|
let subCsg = new ThreeBSP(br.mesh);
|
||||||
|
thisCsg = thisCsg.subtract(subCsg);
|
||||||
|
}
|
||||||
|
ext = thisCsg.toGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (boardData["BoardName"] === "地脚线")
|
||||||
|
RotateUVs(ext);
|
||||||
|
|
||||||
let mesh = new THREE.Mesh(ext, boardMaterial);
|
let mesh = new THREE.Mesh(ext, boardMaterial);
|
||||||
return mesh;
|
return { mesh, edges };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTemplateBoard(brDataList: any[])
|
export function createTemplateBoard(brDataList: any[])
|
||||||
{
|
{
|
||||||
return brDataList.map(brData => createBoard(brData));
|
let meshs = [];
|
||||||
|
let edgesa = [];
|
||||||
|
for (let d of brDataList)
|
||||||
|
{
|
||||||
|
let { mesh, edges } = createBoard(d);
|
||||||
|
meshs.push(mesh);
|
||||||
|
edgesa.push(...edges);
|
||||||
|
}
|
||||||
|
return { meshs, edgesa };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createEdge(board: Mesh): LineSegments
|
export function createEdge(geo: Geometry): LineSegments
|
||||||
{
|
{
|
||||||
let edge = new THREE.EdgesGeometry(board.geometry, 1);
|
let edge = new THREE.EdgesGeometry(geo, 1);
|
||||||
return new LineSegments(edge, edgeMaterial);
|
return new LineSegments(edge, edgeMaterial);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"compileOnSave": true,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"sourceMap": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
|
Loading…
Reference in New Issue
Block a user