diff --git a/web/app/3d/modeler-app.js b/web/app/3d/modeler-app.js index 1739589c..986a7362 100644 --- a/web/app/3d/modeler-app.js +++ b/web/app/3d/modeler-app.js @@ -18,6 +18,7 @@ import '../../css/app3d.less' import * as BREPPrimitives from '../brep/brep-primitives' import * as BREPBool from '../brep/operations/boolean' +import {BREPValidator} from '../brep/brep-validator' import {SceneSolid} from '../brep/viz/scene-solid' function App() { @@ -82,6 +83,8 @@ App.prototype.BREPTestImpl = function() { const box1 = BREPPrimitives.box(500, 500, 500); const box2 = BREPPrimitives.box(500, 500, 500, new Matrix3().translate(250, 250, 250)); + BREPValidator.validateToConsole(box1); + //box1.faces = [box1.faces[2]]; //box2.faces = [box2.faces[5]]; diff --git a/web/app/brep/brep-builder.js b/web/app/brep/brep-builder.js index 1a0e3cfd..7b28a622 100644 --- a/web/app/brep/brep-builder.js +++ b/web/app/brep/brep-builder.js @@ -17,18 +17,20 @@ export function createPrism(basePoints, height) { const lidNormal = normal.multiply(-1); const offVector = lidNormal.multiply(height); - const lidSegments = []; - iterateSegments(basePoints.map(p => p.plus(offVector)), (a, b) => lidSegments.push({a, b})); - const lidLoop = new Loop(); + //iterateSegments(basePoints.map(p => new Vertex(p.plus(offVector))), (a, b) => lidSegments.push({a, b})); + const lidPoints = basePoints.map(p => p.plus(offVector)).reverse(); + const lidLoop = createPlaneLoop(lidPoints.map(p => new Vertex(p))); const shell = new Shell(); const n = baseLoop.halfEdges.length; for (let i = 0; i < n; i++) { + let lidIdx = n - 2 - i; + if (lidIdx == -1) { + lidIdx = n - 1; + } const baseHalfEdge = baseLoop.halfEdges[i]; - const lidSegment = lidSegments[i]; - const lidHalfEdge = createHalfEdge(lidLoop, new Vertex(lidSegment.b), new Vertex(lidSegment.a)); - + const lidHalfEdge = lidLoop.halfEdges[lidIdx]; const wallPolygon = [baseHalfEdge.vertexB, baseHalfEdge.vertexA, lidHalfEdge.vertexB, lidHalfEdge.vertexA]; const wallLoop = createPlaneLoop(wallPolygon); diff --git a/web/app/brep/brep-validator.js b/web/app/brep/brep-validator.js new file mode 100644 index 00000000..e4a94750 --- /dev/null +++ b/web/app/brep/brep-validator.js @@ -0,0 +1,146 @@ +import Vector from '../math/vector' +import * as math from '../math/math' + +export class BREPValidator { + + constructor() { + this.errors = []; + } + + validateShell(shell) { + for (let face of shell.faces) { + this.validateFace(face); + } + } + + validateFace(face) { + if (face !== face.outerLoop.face) { + this.addError(new LoopRefersToWrongFace(face.outerLoop, face)); + } + this.validateLoop(face.outerLoop); + } + + validateLoop(loop) { + const halfEdges = loop.halfEdges; + const n = halfEdges.length; + if (n == 0) { + return; + } + + for (let i = 0; i < n; i ++) { + const j = (i + 1) % n; + const curr = halfEdges[i]; + const next = halfEdges[j]; + if (curr.loop !== loop) { + this.addError(new HalfEdgeRefersToWrongLoop(loop, curr)); + } + if (curr.vertexB !== next.vertexA) { + this.addError(new VerticesOfHalfEdgeArentConnected(curr, next)); + } + if (curr.next != next) { + this.addError(new HalfEdgeNextPointerIncorrect(curr, next)); + } + if (next.prev != curr) { + this.addError(new HalfEdgePrevPointerIncorrect(next, curr)); + } + const twin = curr.twin(); + if (twin.vertexB != curr.vertexA) { + this.addError(new TwinStartVertexIncorrect(curr, twin)); + } + if (twin.vertexA != curr.vertexB) { + this.addError(new TwinEndVertexIncorrect(curr, twin)); + } + } + } + + addError(validationError) { + this.errors.push(validationError); + } +} + +BREPValidator.validateToConsole = function(shell) { + const brepValidator = new BREPValidator(); + + brepValidator.validateShell(shell); + for (let brepError of brepValidator.errors) { + console.log(brepError.message()); + } +}; + +class VerticesOfHalfEdgeArentConnected { + constructor(loop, halfEdge1, halfEdge2) { + this.loop = loop; + this.halfEdge1 = halfEdge1; + this.halfEdge2 = halfEdge2; + } + + message() { + return 'starting point of the following half edge should identically the same as ending of a half edge'; + } +} + +class HalfEdgeRefersToWrongLoop { + constructor(loop, face) { + this.loop = loop; + this.face = face; + } + + message() { + return 'half edge refers to different loop it belongs to'; + } +} + +class LoopRefersToWrongFace { + constructor(loop, halfEdge) { + this.loop = loop; + this.halfEdge = halfEdge; + } + + message() { + return 'loop refers to different face it belongs to'; + } +} + +class HalfEdgeNextPointerIncorrect { + constructor(halfEdge, nextHalfEdge) { + this.halfEdge = halfEdge; + this.nextHalfEdge = nextHalfEdge; + } + + message() { + return "half edge's next pointer doesn't refer to real next half edge"; + } +} + +class HalfEdgePrevPointerIncorrect { + constructor(halfEdge, prevHalfEdge) { + this.halfEdge = halfEdge; + this.prevHalfEdge = prevHalfEdge; + } + + message() { + return "half edge's prev pointer doesn't refer to prior half edge"; + } +} + +class TwinStartVertexIncorrect { + constructor(halfEdge, twin) { + this.halfEdge = halfEdge; + this.twin = twin; + } + + message() { + return "a twin has incorrect start vertex, should be identical to the end vertex of the half edge"; + } +} + +class TwinEndVertexIncorrect { + constructor(halfEdge, twin) { + this.halfEdge = halfEdge; + this.twin = twin; + } + + message() { + return "a twin has incorrect end vertex, should be identical to the start vertex of the half edge"; + } +} \ No newline at end of file diff --git a/web/app/brep/operations/boolean.js b/web/app/brep/operations/boolean.js index 24d27ab7..6c281ee3 100644 --- a/web/app/brep/operations/boolean.js +++ b/web/app/brep/operations/boolean.js @@ -30,6 +30,9 @@ export function union( shell1, shell2 ) { //if (shell2.faces.indexOf(face) != -1) { // continue; //} + if (face.debugName == 'lid') { + __DEBUG__.Clear(); + } const edges = face.outerLoop.halfEdges.concat(faceData.newEdges); //edges.forEach(e => __DEBUG__.AddLine(e.vertexA.point, e.vertexB.point)); while (true) {