清理CSG代码

pull/247/MERGE
ChenX 6 years ago
parent 3353bdbdee
commit 1958fb22d3

@ -2,7 +2,7 @@ import * as THREE from 'three';
import { app } from '../ApplicationServices/Application';
import { Command } from '../Editor/CommandMachine';
import { PromptSsgetResult, PromptStatus } from '../Editor/PromptResult';
import ThreeBSP from '../Geometry/ThreeCSG';
import { CSG } from '../Geometry/ThreeCSG';
import { RenderType } from '../GraphicsSystem/RenderType';
async function GetEntity(msg: string)
@ -28,8 +28,8 @@ abstract class CSGOperation implements Command
let mesh1 = en1.Draw(RenderType.Wireframe) as THREE.Mesh;
let mesh2 = en2.Draw(RenderType.Wireframe) as THREE.Mesh;
let csg1 = new ThreeBSP(mesh1);
let csg2 = new ThreeBSP(mesh2);
let csg1 = new CSG(mesh1);
let csg2 = new CSG(mesh2);
let csg3 = this.Operate(csg1, csg2);
@ -38,7 +38,7 @@ abstract class CSGOperation implements Command
en1.Erase();
en2.Erase();
}
protected Operate(csg1: ThreeBSP, csg2: ThreeBSP): ThreeBSP
protected Operate(csg1: CSG, csg2: CSG): CSG
{
return undefined;
}
@ -46,7 +46,7 @@ abstract class CSGOperation implements Command
export class CSGUnion extends CSGOperation
{
protected Operate(csg1: ThreeBSP, csg2: ThreeBSP)
protected Operate(csg1: CSG, csg2: CSG)
{
return csg1.union(csg2);
}
@ -54,7 +54,7 @@ export class CSGUnion extends CSGOperation
export class CSGSubtraction extends CSGOperation
{
protected Operate(csg1: ThreeBSP, csg2: ThreeBSP)
protected Operate(csg1: CSG, csg2: CSG)
{
return csg1.subtract(csg2);
}

@ -5,7 +5,7 @@ import { ObjectSnapMode } from "../Editor/ObjectSnapMode";
import { BoardUVGenerator } from "../Geometry/BoardUVGenerator";
import { BSPGroupParse } from "../Geometry/BSPGroupParse";
import { cZeroVec, equaln, equalv3, isParallelTo, MoveMatrix } from "../Geometry/GeUtils";
import ThreeBSP from "../Geometry/ThreeCSG";
import { CSG } from "../Geometry/ThreeCSG";
import { RenderType } from "../GraphicsSystem/RenderType";
import { BlockTableRecord } from "./BlockTableRecord";
import { Factory } from "./CADFactory";
@ -143,7 +143,7 @@ export class ExtureSolid extends Entity
g.ApplyMatrix(m);
//由于修改矩阵会导致矩阵错误
this.bsp = undefined;
this.csg = undefined;
return this;
}
@ -161,7 +161,7 @@ export class ExtureSolid extends Entity
g.ApplyMatrix(m);
//由于修改矩阵会导致bsp错误
this.bsp = undefined;
this.csg = undefined;
}
get Width()
@ -597,16 +597,16 @@ export class ExtureSolid extends Entity
/**
* Draw,bsp
*/
private bsp: ThreeBSP;
private get BSP()
private csg: CSG;
private get CSG()
{
if (this.bsp)
return this.bsp;
if (this.csg)
return this.csg;
this.Draw();
if (!this.bsp)
if (!this.csg)
this.Update(UpdateDraw.Geometry);
return this.bsp;
return this.csg;
}
/**
@ -632,7 +632,7 @@ export class ExtureSolid extends Entity
let m = new Matrix4().makeBasis(xv, yv, zv).copyPosition(this.OCS);
let mi = new Matrix4().getInverse(m);
let interBSP = this.BSP.intersect(target.BSP);
let interBSP = this.CSG.intersect(target.CSG);
let topology = new BSPGroupParse(interBSP);
let grooves: ExtureSolid[] = [];
for (let pts of topology.Parse())
@ -921,9 +921,7 @@ export class ExtureSolid extends Entity
let geo = new ExtrudeGeometry(this.ContourCurve.Shape, extrudeSettings);
geo.applyMatrix(this.contourCurve.OCS);
let mesh = new Mesh(geo);
mesh.matrix = this.m_Matrix;
this.bsp = new ThreeBSP(mesh);
this.csg = new CSG(geo, this.m_Matrix);
this.ChangeUV(geo);
if (this.grooves.length === 0)
@ -932,10 +930,10 @@ export class ExtureSolid extends Entity
for (let g of this.grooves)
{
if (g.thickness > 0)
this.bsp = this.bsp.subtract(g.BSP);
this.csg = this.csg.subtract(g.CSG);
}
let bgeo = this.bsp.toGeometry();
let bgeo = this.csg.toGeometry();
this.ChangeUV(bgeo);
return bgeo;
}

@ -1,6 +1,6 @@
import { Vector3 } from "three";
import { ToFixed } from "../Common/Utils";
import ThreeBSP, { Polygon } from "./ThreeCSG";
import { Polygon, CSG } from "./ThreeCSG";
interface Vec3
{
x: number;
@ -20,7 +20,7 @@ interface Vec3
*/
export class BSPGroupParse
{
constructor(bsp?: ThreeBSP, public fractionDigits = 1)
constructor(bsp?: CSG, public fractionDigits = 1)
{
if (bsp)
for (let poly of bsp.tree.allPolygons())

@ -1,25 +1,29 @@
import { BufferGeometry, Face3, Geometry, Material, Matrix4, Mesh, Vector2, Vector3 } from "three";
const EPSILON = 1e-5,
COPLANAR = 0, //共面
FRONT = 1, //前
BACK = 2,
SPANNING = 3;
//ref: https://github.com/chandlerprall/ThreeCSG/blob/master/threeCSG.es6
export default class ThreeBSP
const EPSILON = 1e-5;
enum Side
{
Coplanar = 0,
Front = 1,
Back = 2,
Spanning = 3
}
export class CSG
{
tree: Node;
matrix: Matrix4;
Node: Node;
Vertex: Vertex[];
Polygon: Polygon[] = [];
constructor(obj: Geometry | Mesh | Node)
constructor(obj: Geometry | Mesh | Node, matrix?: Matrix4)
{
let geometry: Geometry;
if (obj instanceof Geometry)
{
geometry = obj;
this.matrix = new Matrix4();
this.matrix = matrix || new Matrix4();
}
else if (obj instanceof Mesh)
{
@ -34,15 +38,16 @@ export default class ThreeBSP
else if (obj instanceof Node)
{
this.tree = obj;
this.matrix = new Matrix4();
this.matrix = matrix || new Matrix4();
return this;
}
else
{
throw 'ThreeBSP: Given geometry is unsupported';
throw '未支持的类型';
}
let polgons: Polygon[] = [];
for (let i = 0; i < geometry.faces.length; i++)
{
let face = geometry.faces[i];
@ -51,33 +56,30 @@ export default class ThreeBSP
if (face instanceof Face3)
{
let vertex = geometry.vertices[face.a];
let uvs = faceVertexUvs ? new Vector2(faceVertexUvs[0].x, faceVertexUvs[0].y) : null;
let vertex1 = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], uvs);
let uvs = faceVertexUvs ? faceVertexUvs[0].clone() : null;
let vertex1 = new Vertex(geometry.vertices[face.a], face.vertexNormals[0], uvs);
vertex1.applyMatrix4(this.matrix);
polygon.vertices.push(vertex1);
vertex = geometry.vertices[face.b];
uvs = faceVertexUvs ? new Vector2(faceVertexUvs[1].x, faceVertexUvs[1].y) : null;
let vertex2 = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[1], uvs);
uvs = faceVertexUvs ? faceVertexUvs[1].clone() : null;
let vertex2 = new Vertex(geometry.vertices[face.b], face.vertexNormals[1], uvs);
vertex2.applyMatrix4(this.matrix);
polygon.vertices.push(vertex2);
vertex = geometry.vertices[face.c];
uvs = faceVertexUvs ? new Vector2(faceVertexUvs[2].x, faceVertexUvs[2].y) : null;
let vertex3 = new Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[2], uvs);
uvs = faceVertexUvs ? faceVertexUvs[2].clone() : null;
let vertex3 = new Vertex(geometry.vertices[face.c], face.vertexNormals[2], uvs);
vertex3.applyMatrix4(this.matrix);
polygon.vertices.push(vertex3);
}
polygon.calculateProperties();
this.Polygon.push(polygon);
polgons.push(polygon);
}
this.tree = new Node(this.Polygon);
this.tree = new Node(polgons);
}
subtract(other_tree: ThreeBSP)
subtract(other_tree: CSG)
{
let a = this.tree.clone(),
b = other_tree.tree.clone();
@ -90,12 +92,10 @@ export default class ThreeBSP
b.invert();
a.build(b.allPolygons());
a.invert();
let bsp = new ThreeBSP(a);
bsp.matrix = this.matrix;
return bsp;
return new CSG(a, this.matrix);
}
union(other_tree: ThreeBSP)
union(other_tree: CSG)
{
let a = this.tree.clone(),
b = other_tree.tree.clone();
@ -106,12 +106,10 @@ export default class ThreeBSP
b.clipTo(a);
b.invert();
a.build(b.allPolygons());
let bsp = new ThreeBSP(a);
bsp.matrix = this.matrix;
return bsp;
return new CSG(a, this.matrix);
}
intersect(other_tree: ThreeBSP)
intersect(other_tree: CSG)
{
let a = this.tree.clone(),
b = other_tree.tree.clone();
@ -123,15 +121,12 @@ export default class ThreeBSP
b.clipTo(a);
a.build(b.allPolygons());
a.invert();
let bsp = new ThreeBSP(a);
bsp.matrix = this.matrix;
return bsp;
return new CSG(a, this.matrix);
}
toGeometry()
{
let
matrix = new Matrix4().getInverse(this.matrix),
let matrix = new Matrix4().getInverse(this.matrix),
geometry = new Geometry(),
polygons = this.tree.allPolygons(),
polygon_count = polygons.length,
@ -215,25 +210,13 @@ export default class ThreeBSP
export class Polygon
{
w: number;
normal: Vertex;
vertices: Vertex[]
constructor(vertices?: Vertex[], normal?: Vertex, w?: number)
constructor(
public vertices: Vertex[] = [],
public normal?: Vector3,
public w?: number)
{
if (!(vertices instanceof Array))
{
vertices = [];
}
this.vertices = vertices;
if (vertices.length > 0)
{
if (vertices.length > 0 && !normal)
this.calculateProperties();
}
else
{
this.normal = this.w = undefined;
}
}
calculateProperties()
@ -242,62 +225,51 @@ export class Polygon
b = this.vertices[1],
c = this.vertices[2];
this.normal = b.clone().subtract(a).cross(
c.clone().subtract(a)
).normalize();
this.normal = b.clone().sub(a)
.cross(c.clone().sub(a))
.normalize();
this.w = this.normal.clone().dot(a);
this.w = this.normal.dot(a);
return this;
}
clone()
{
let polygon = new Polygon();
for (let i = 0, vertice_count = this.vertices.length; i < vertice_count; i++)
{
polygon.vertices.push(this.vertices[i].clone());
}
polygon.calculateProperties();
return polygon;
return new Polygon(
this.vertices.map(v => v.clone()),
this.normal.clone(),
this.w
);
}
flip()
{
let vertices = [];
this.normal.multiplyScalar(-1);
this.w *= -1;
for (let i = this.vertices.length - 1; i >= 0; i--)
{
vertices.push(this.vertices[i]);
}
this.vertices = vertices;
this.vertices.reverse();
return this;
}
//划分?
classifyVertex(vertex: Vector3 | Vertex)
classifyVertex(vertex: Vector3 | Vertex): Side
{
let side_value = this.normal.dot(vertex) - this.w;
if (side_value < -EPSILON)
{
return BACK;
} else if (side_value > EPSILON)
return Side.Back;
}
else if (side_value > EPSILON)
{
return FRONT;
} else
return Side.Front;
}
else
{
return COPLANAR;
return Side.Coplanar;
}
}
//划分边?
classifySide(polygon: Polygon)
classifySide(polygon: Polygon): Side
{
let num_positive = 0,
num_negative = 0,
@ -307,36 +279,35 @@ export class Polygon
{
let vertex = polygon.vertices[i];
let classification = this.classifyVertex(vertex);
if (classification === FRONT)
if (classification === Side.Front)
num_positive++;
else if (classification === BACK)
else if (classification === Side.Back)
num_negative++;
}
if (num_positive > 0 && num_negative === 0)
return FRONT;
return Side.Front;
else if (num_positive === 0 && num_negative > 0)
return BACK;
return Side.Back;
else if (num_positive === 0 && num_negative === 0)
return COPLANAR;
return Side.Coplanar;
else
return SPANNING;
return Side.Spanning;
}
//分解 分离 区域?
splitPolygon(polygon: Polygon, coplanar_front: Polygon[], coplanar_back: Polygon[], front: Polygon[], back: Polygon[])
{
let classification = this.classifySide(polygon);
if (classification === COPLANAR)
if (classification === Side.Coplanar)
{
(this.normal.dot(polygon.normal) > 0 ? coplanar_front : coplanar_back).push(polygon);
}
else if (classification === FRONT)
else if (classification === Side.Front)
{
front.push(polygon);
}
else if (classification === BACK)
else if (classification === Side.Back)
{
back.push(polygon);
}
@ -353,12 +324,12 @@ export class Polygon
let ti = this.classifyVertex(vi);
let tj = this.classifyVertex(vj);
if (ti != BACK) f.push(vi);
if (ti != FRONT) b.push(vi);
if ((ti | tj) === SPANNING)
if (ti != Side.Back) f.push(vi);
if (ti != Side.Front) b.push(vi);
if ((ti | tj) === Side.Spanning)
{
let t = (this.w - this.normal.dot(vi)) / this.normal.dot(vj.clone().subtract(vi));
let v = vi.interpolate(vj, t);
let t = (this.w - this.normal.dot(vi)) / this.normal.dot(vj.clone().sub(vi));
let v = vi.clone().lerp(vj, t);
f.push(v);
b.push(v);
}
@ -370,139 +341,43 @@ export class Polygon
}
}
type v3 = Vector3 | Vertex;
class Vertex
class Vertex extends Vector3
{
uv: Vector2;
normal: Vector3;
z: number;
y: number;
x: number;
constructor(x: number, y: number, z: number, normal: Vector3, uv: Vector2)
{
this.x = x;
this.y = y;
this.z = z;
this.normal = normal || new Vector3();
this.uv = uv || new Vector2();
}
clone()
constructor(
pos: Vector3,
public normal = new Vector3(),
public uv = new Vector2())
{
return new Vertex(this.x, this.y, this.z, this.normal.clone(), this.uv.clone());
}
add(vertex: v3)
{
this.x += vertex.x;
this.y += vertex.y;
this.z += vertex.z;
return this;
super(pos.x, pos.y, pos.z);
}
subtract(vertex: v3)
clone(): Vertex
{
this.x -= vertex.x;
this.y -= vertex.y;
this.z -= vertex.z;
return this;
return new Vertex(this, this.normal.clone(), this.uv.clone());
}
multiplyScalar(scalar)
lerp(v: Vertex, alpha: number)
{
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
super.lerp(v, alpha);
this.normal.lerp(v.normal, alpha);
this.uv.lerp(v.uv, alpha);
return this;
}
//×乘
cross(vertex: v3)
{
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: v3)
{
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: 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;
}
}
class Node
{
divider: Polygon;
back: Node;
front: Node;
polygons: Polygon[];
constructor(polygons?: Polygon[])
constructor(public polygons: Polygon[] = [])
{
let front = [],
back = [];
let front: Polygon[] = [],
back: Polygon[] = [];
this.polygons = [];
this.front = this.back = undefined;
if (!(polygons instanceof Array) || polygons.length === 0) return;
if (polygons.length === 0) return;
this.divider = polygons[0].clone();
@ -528,7 +403,7 @@ class Node
{
for (let j = 0; j < polygons.length; j++)
{
if (i !== j && polygons[i].classifySide(polygons[j]) !== BACK)
if (i !== j && polygons[i].classifySide(polygons[j]) !== Side.Back)
{
return false;
}
@ -539,8 +414,8 @@ class Node
build(polygons: Polygon[])
{
let front = [],
back = [];
let front: Polygon[] = [],
back: Polygon[] = [];
if (!this.divider)
{
@ -578,23 +453,17 @@ class Node
let node = new Node();
node.divider = this.divider.clone();
node.polygons = this.polygons.map(function (polygon)
{
return polygon.clone();
});
node.polygons = this.polygons.map(p => p.clone());
node.front = this.front && this.front.clone();
node.back = this.back && this.back.clone();
return node;
}
//反转
invert()
{
for (let i = 0, polygon_count = this.polygons.length; i < polygon_count; i++)
{
this.polygons[i].flip();
}
for (let p of this.polygons)
p.flip();
this.divider.flip();
if (this.front) this.front.invert();
@ -607,18 +476,15 @@ class Node
return this;
}
//
clipPolygons(polygons: Polygon[])
{
if (!this.divider) return polygons.slice();
let front = [];
let back = [];
let front: Polygon[] = [];
let back: Polygon[] = [];
for (let i = 0, polygon_count = polygons.length; i < polygon_count; i++)
{
this.divider.splitPolygon(polygons[i], front, back, front, back);
}
for (let polygon of polygons)
this.divider.splitPolygon(polygon, front, back, front, back);
if (this.front) front = this.front.clipPolygons(front);
if (this.back) back = this.back.clipPolygons(back);

Loading…
Cancel
Save