mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-23 17:04:00 +01:00
BREP / union / intersect / subtract
This commit is contained in:
parent
19181e6135
commit
e66f7f7126
6 changed files with 68 additions and 6 deletions
|
|
@ -91,7 +91,7 @@ App.prototype.BREPTestImpl = function() {
|
|||
//addToScene(box1);
|
||||
//addToScene(box2);
|
||||
|
||||
const result = BREPBool.union(box1, box2);
|
||||
const result = BREPBool.subtract(box1, box2);
|
||||
addToScene(result);
|
||||
|
||||
this.viewer.render()
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ export function createPrism(basePoints, height) {
|
|||
lidFace.debugName = 'lid';
|
||||
|
||||
shell.faces.push(baseFace, lidFace);
|
||||
shell.faces.forEach(f => f.shell = shell);
|
||||
return shell;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ export class BREPValidator {
|
|||
|
||||
validateShell(shell) {
|
||||
for (let face of shell.faces) {
|
||||
if (face.shell !== shell) {
|
||||
this.addError(new FaceRefersToWrongShell(face, shell))
|
||||
}
|
||||
this.validateFace(face);
|
||||
}
|
||||
}
|
||||
|
|
@ -77,6 +80,17 @@ BREPValidator.validateToConsole = function(shell) {
|
|||
}
|
||||
};
|
||||
|
||||
class FaceRefersToWrongShell {
|
||||
constructor(face, shell) {
|
||||
this.face = face;
|
||||
this.shell = shell;
|
||||
}
|
||||
|
||||
message() {
|
||||
return "face refers to a shell it doesn't belong to";
|
||||
}
|
||||
}
|
||||
|
||||
class VerticesOfHalfEdgeArentConnected {
|
||||
constructor(loop, halfEdge1, halfEdge2) {
|
||||
this.loop = loop;
|
||||
|
|
|
|||
|
|
@ -30,4 +30,7 @@ export class Plane extends Surface {
|
|||
return super.intersect();
|
||||
}
|
||||
|
||||
invert() {
|
||||
return new Plane(this.normal.multiply(-1), - this.w);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,22 +12,62 @@ import {Matrix3} from '../../math/l3space';
|
|||
|
||||
export const TOLERANCE = 1e-8;
|
||||
|
||||
const TYPE = {
|
||||
UNION: 0,
|
||||
INTERSECT: 1,
|
||||
SUBTRACT: 2
|
||||
};
|
||||
|
||||
export function union( shell1, shell2 ) {
|
||||
return BooleanAlgorithm(shell1, shell2, TYPE.UNION);
|
||||
}
|
||||
|
||||
export function intersect( shell1, shell2 ) {
|
||||
return BooleanAlgorithm(shell1, shell2, TYPE.INTERSECT);
|
||||
}
|
||||
|
||||
export function subtract( shell1, shell2 ) {
|
||||
invert(shell2);
|
||||
return BooleanAlgorithm(shell1, shell2, TYPE.SUBTRACT);
|
||||
}
|
||||
|
||||
export function invert( shell ) {
|
||||
for (let face of shell.faces) {
|
||||
face.surface = face.surface.invert();
|
||||
invertLoop(face.outerLoop);
|
||||
}
|
||||
BREPValidator.validateToConsole(shell);
|
||||
}
|
||||
|
||||
function invertLoop(loop) {
|
||||
for (let halfEdge of loop.halfEdges) {
|
||||
const t = halfEdge.vertexA;
|
||||
halfEdge.vertexA = halfEdge.vertexB;
|
||||
halfEdge.vertexB = t;
|
||||
}
|
||||
loop.halfEdges.reverse();
|
||||
BREPBuilder.linkSegments(loop.halfEdges);
|
||||
}
|
||||
|
||||
export function BooleanAlgorithm( shell1, shell2, type ) {
|
||||
|
||||
const facesData = [];
|
||||
|
||||
initSolveData(shell1, facesData);
|
||||
initSolveData(shell2, facesData);
|
||||
|
||||
intersectFaces(shell1, shell2);
|
||||
intersectFaces(shell1, shell2, type !== TYPE.UNION);
|
||||
|
||||
const result = new Shell();
|
||||
//__DEBUG__.AddSegment(shell2.faces[0].outerLoop.halfEdges[0].vertexA.point, shell2.faces[0].outerLoop.halfEdges[0].vertexB.point)
|
||||
|
||||
for (let faceData of facesData) {
|
||||
|
||||
const seen = new Set();
|
||||
const face = faceData.face;
|
||||
if (faceData.newEdges.length == 0) {
|
||||
if (type === TYPE.INTERSECT) continue;
|
||||
if (type === TYPE.SUBTRACT && face.shell == shell2) continue;
|
||||
}
|
||||
const seen = new Set();
|
||||
const edges = face.outerLoop.halfEdges.concat(faceData.newEdges);
|
||||
while (true) {
|
||||
let edge = edges.pop();
|
||||
|
|
@ -61,6 +101,7 @@ export function union( shell1, shell2 ) {
|
|||
const newFace = new Face(face.surface);
|
||||
newFace.outerLoop = loop;
|
||||
newFace.outerLoop.face = newFace;
|
||||
newFace.shell = result;
|
||||
result.faces.push(newFace);
|
||||
}
|
||||
}
|
||||
|
|
@ -101,7 +142,7 @@ function findMaxTurningLeft(edge, edges) {
|
|||
return edges[0];
|
||||
}
|
||||
|
||||
function intersectFaces(shell1, shell2) {
|
||||
function intersectFaces(shell1, shell2, inverseCrossEdgeDirection) {
|
||||
for (let i = 0; i < shell1.faces.length; i++) {
|
||||
for (let j = 0; j < shell2.faces.length; j++) {
|
||||
const face1 = shell1.faces[i];
|
||||
|
|
@ -115,11 +156,13 @@ function intersectFaces(shell1, shell2) {
|
|||
|
||||
const newEdges = [];
|
||||
const direction = face1.surface.normal.cross(face2.surface.normal);
|
||||
if (inverseCrossEdgeDirection) {
|
||||
direction._multiply(-1);
|
||||
}
|
||||
split(nodes, newEdges, curve, direction);
|
||||
|
||||
newEdges.forEach(e => {
|
||||
//__DEBUG__.AddHalfEdge(e.halfEdge1);
|
||||
console.log("new edge");
|
||||
face1.__faceSolveData.newEdges.push(e.halfEdge1);
|
||||
face2.__faceSolveData.newEdges.push(e.halfEdge2);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ export class Face {
|
|||
|
||||
constructor(surface) {
|
||||
this.surface = surface;
|
||||
this.shell = null;
|
||||
this.outerLoop = null;
|
||||
this.innerLoops = [];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue