diff --git a/web/app/3d/debug.js b/web/app/3d/debug.js index 289c5407..2c1a9889 100644 --- a/web/app/3d/debug.js +++ b/web/app/3d/debug.js @@ -122,6 +122,11 @@ function addGlobalDebugActions(app) { __DEBUG__.AddPoint(nurbs.point(1, 1), 0x0000ff); __DEBUG__.AddPoint(nurbs.point(0, 1), 0x00ffff); }, + AddNormal: (atPoint, normal, color, scale) => { + scale = scale || 100; + __DEBUG__.AddSegment(atPoint, atPoint.plus(normal.multiply(scale)), color); + }, + HideSolids: () => { app.findAllSolidsOnScene().forEach(s => s.cadGroup.traverse(o => o.visible = false)); app.viewer.render(); diff --git a/web/app/3d/modeler-app.js b/web/app/3d/modeler-app.js index ee6a0982..d0cc52f5 100644 --- a/web/app/3d/modeler-app.js +++ b/web/app/3d/modeler-app.js @@ -84,14 +84,16 @@ App.prototype.addShellOnScene = function(shell, skin) { }; App.prototype.scratchCode = function() { - let box = createBox(500, 500, 500); - let sphere = createSphere([0, 200, 0], 300); - let clylinder = createCylinder(150, 500); - - this.viewer.workGroup.add(box.toThreeMesh()); - // this.viewer.workGroup.add(sphere.toThreeMesh()); - this.viewer.workGroup.add(clylinder.toThreeMesh()); - this.viewer.render(); + const app = this; + const box1 = app.TPI.brep.primitives.box(500, 500, 500); + const box2 = app.TPI.brep.primitives.box(250, 250, 750, new Matrix3().translate(25, 25, 0)); + const box3 = app.TPI.brep.primitives.box(150, 600, 350, new Matrix3().translate(25, 25, -250)); + let result = app.TPI.brep.bool.union(box1, box2); + // let result = app.TPI.brep.bool.subtract(box1, box2); + // result = app.TPI.brep.bool.subtract(result, box3); + app.addShellOnScene(box1); + app.addShellOnScene(box2); + app.viewer.render(); }; diff --git a/web/app/brep/brep-builder.js b/web/app/brep/brep-builder.js index 5fd224b7..ae9caf43 100644 --- a/web/app/brep/brep-builder.js +++ b/web/app/brep/brep-builder.js @@ -357,16 +357,6 @@ export function iterateSegments(items, callback) { } } -export function invertLoop(loop) { - for (let halfEdge of loop.halfEdges) { - const t = halfEdge.vertexA; - halfEdge.vertexA = halfEdge.vertexB; - halfEdge.vertexB = t; - } - loop.halfEdges.reverse(); - linkSegments(loop.halfEdges); -} - export function createPlaneLoop(vertices, curves) { const loop = new Loop(); diff --git a/web/app/brep/geom/impl/nurbs.js b/web/app/brep/geom/impl/nurbs.js index 235e4218..66506736 100644 --- a/web/app/brep/geom/impl/nurbs.js +++ b/web/app/brep/geom/impl/nurbs.js @@ -51,11 +51,11 @@ export class NurbsCurve extends Curve { } tangentAtPoint(point) { - return new Point().set3(this.verb.tangent(this.verb.closestParam(point.data()))); + return new Point().set3(this.verb.tangent(this.verb.closestParam(point.data())))._normalize(); } tangentAtParam(param) { - return new Point().set3(this.verb.tangent(param )); + return new Point().set3(this.verb.tangent(param ))._normalize(); } closestDistanceToPoint(point) { @@ -67,10 +67,6 @@ export class NurbsCurve extends Curve { return this.verb.split(this.verb.closestParam(point.data)).map(v => new NurbsCurve(v)); } - intersect(other, tolerance) { - return verb.geom.Intersect.curves(this.verb, other.verb, tolerance); - } - invert() { return new NurbsCurve(this.verb.reverse()); } @@ -78,7 +74,16 @@ export class NurbsCurve extends Curve { point(u) { return new Point().set3(this.verb.point(u)); } - + + intersectCurve(other, tol) { + return verb.geom.Intersect.curves(this.verb, other.verb, tol).map( i => ({ + u0: i.u0, + u1: i.u1, + p0: new Vector().set3(i.point0), + p1: new Vector().set3(i.point1) + })); + } + static createByPoints(points, degeree) { points = points.map(p => p.data()); return new NurbsCurve(new verb.geom.NurbsCurve.byPoints(points, degeree)); @@ -111,6 +116,7 @@ export class NurbsSurface extends Surface { if (this.inverted) { normal._negate(); } + normal._normalize(); return normal; } @@ -119,22 +125,19 @@ export class NurbsSurface extends Surface { if (this.inverted) { normal._negate(); } + normal._normalize(); return normal; } - normalInMiddle(point) { - let normal = new Vector().set3(this.verb.normal(0.5, 0.5)); - if (this.inverted) { - normal._negate(); - } - return normal; + normalInMiddle() { + return this.normalUV(0.5, 0.5); } point(u, v) { return new Point().set3(this.verb.point(u, v)); } - intersectForSameClass(other, tol) { + intersectSurfaceForSameClass(other, tol) { const curves = verb.geom.Intersect.surfaces(this.verb, other.verb, tol); let inverted = this.inverted !== other.inverted; return curves.map(curve => new NurbsCurve(inverted ? curve.reverse() : curve)); diff --git a/web/app/brep/geom/surface.js b/web/app/brep/geom/surface.js index 29cc7501..83531616 100644 --- a/web/app/brep/geom/surface.js +++ b/web/app/brep/geom/surface.js @@ -7,15 +7,15 @@ export class Surface { //-------------------------------------------------------------------------------------------------------------------- - intersectForSameClass() { + intersectSurfaceForSameClass() { throw 'not implemented'; } - intersect(other, tol) { + intersectSurface(other, tol) { if (this.isSameClass(other)) { - return this.intersectForSameClass(other, tol) + return this.intersectSurfaceForSameClass(other, tol) } - return this.toNurbs().intersectForSameClass(other.toNurbs(), tol); + return this.toNurbs().intersectSurfaceForSameClass(other.toNurbs(), tol); }; //-------------------------------------------------------------------------------------------------------------------- diff --git a/web/app/brep/operations/boolean.js b/web/app/brep/operations/boolean.js index 8dbe8bf9..4d3b5ca5 100644 --- a/web/app/brep/operations/boolean.js +++ b/web/app/brep/operations/boolean.js @@ -46,20 +46,20 @@ export function subtract( shell1, shell2 ) { export function invert( shell ) { for (let face of shell.faces) { face.surface = face.surface.invert(); - for (let loop of face.loops) { - invertLoop(loop); - } for (let edge of shell.edges) { edge.invert(); } + for (let loop of face.loops) { + for (let i = 0; i < loop.halfEdges.length; i++) { + loop.halfEdges[i] = loop.halfEdges[i].twin(); + } + loop.halfEdges.reverse(); + loop.link(); + } } BREPValidator.validateToConsole(shell); } -function invertLoop(loop) { - BREPBuilder.invertLoop(loop); -} - export function BooleanAlgorithm( shell1, shell2, type ) { POINT_TO_VERT.clear(); @@ -297,11 +297,16 @@ function leftTurningMeasure(v1, v2, normal) { } function intersectEdges(shell1, shell2) { - const tuples1 = []; - const tuples2 = []; + function collectTuples(shell) { + const tuples = []; + for (let edge of shell.edges) { + tuples.push([edge]); + } + return tuples; + } - shell1.edges.forEach(e => tuples1.push([e])); - shell2.edges.forEach(e => tuples2.push([e])); + const tuples1 = collectTuples(shell1); + const tuples2 = collectTuples(shell2); for (let i = 0; i < tuples1.length; i++) { const edges1 = tuples1[i]; @@ -311,7 +316,7 @@ function intersectEdges(shell1, shell2) { const e1 = edges1[k]; for (let l = edges2.length - 1; l >= 0 ; l--) { const e2 = edges2[l]; - let points = e1.curve.intersect(e2.curve, TOLERANCE); + let points = e1.curve.intersectCurve(e2.curve, TOLERANCE); for (let point of points) { const {u0, u1} = point; @@ -344,26 +349,23 @@ function intersectEdges(shell1, shell2) { } } -//TODO: extract to a unit test -function curveDirectionValidityTest(curve, surface1, surface2, operationType) { + +function fixCurveDirection(curve, surface1, surface2, operationType) { let point = curve.point(0.5); let tangent = curve.tangentAtPoint(point); - assert('tangent should be normalized', eq(tangent.length, 1)); - let normal1 = surface1.normal(point); - assert('normal should be normalized', eq(normal1.length, 1)); - let normal2 = surface2.normal(point); - assert('normal should be normalized', eq(normal2.length, 1)); let expectedDirection = normal1.cross(normal2); if (operationType === TYPE.UNION) { expectedDirection._negate(); } - let sameAsExpected = expectedDirection.dot(tangent) > 0; - assert('wrong intersection curve direction', sameAsExpected); + if (sameAsExpected) { + curve = curve.invert(); + } + return curve; } //TODO: extract to a unit test @@ -392,13 +394,10 @@ function intersectFaces(shell1, shell2, operationType) { } } - let curves = face1.surface.intersect(face2.surface, TOLERANCE); + let curves = face1.surface.intersectSurface(face2.surface, TOLERANCE); for (let curve of curves) { - if (invert) { - curve = curve.invert(); - } - curveDirectionValidityTest(curve, face1.surface, face2.surface, invert); + curve = fixCurveDirection(curve, face1.surface, face2.surface, operationType); const nodes = []; collectNodesOfIntersectionOfFace(curve, face1, nodes); collectNodesOfIntersectionOfFace(curve, face2, nodes); @@ -409,7 +408,7 @@ function intersectFaces(shell1, shell2, operationType) { split(nodes, curve, newEdges); newEdges.forEach(e => { - newEdgeDirectionValidityTest(e, curve) + newEdgeDirectionValidityTest(e, curve); addNewEdge(face1, e.halfEdge1); addNewEdge(face2, e.halfEdge2); }); @@ -465,33 +464,31 @@ function collectNodesOfIntersectionOfFace(curve, face, nodes) { function collectNodesOfIntersection(curve, loop, nodes) { for (let edge of loop.halfEdges) { - intersectCurveWithEdge(curves, edge, nodes); + intersectCurveWithEdge(curve, edge, nodes); } } function intersectCurveWithEdge(curve, edge, result) { - for (let i = 0; i < curves.length; ++i) { - const points = edge.edge.curve.intersectCurve(curve); - for (let point of points) { - const {u0, u1} = point; + const points = edge.edge.curve.intersectCurve(curve, TOLERANCE); + for (let point of points) { + const {u0, u1} = point; - let vertex; - if (equal(u0, 0)) { - vertex = edge.edge.halfEdge1.vertexA; - } else if (equal(u0, 1)) { - vertex = edge.edge.halfEdge1.vertexB; - } else { - vertex = new Vertex(edge.edge.curve.point(u0)); - } - - result.push(new Node(vertex, edge, curve, u1)); + let vertex; + if (equal(u0, 0)) { + vertex = edge.edge.halfEdge1.vertexA; + } else if (equal(u0, 1)) { + vertex = edge.edge.halfEdge1.vertexB; + } else { + vertex = new Vertex(edge.edge.curve.point(u0)); } + + result.push(new Node(vertex, edge, curve, u1)); } } function split(nodes, curve, result) { - nodes.sort((n1, n2) => n1.u - n2.u); nodes = nodes.filter(n => n !== null); + nodes.sort((n1, n2) => n1.u - n2.u); for (let i = 0; i < nodes.length - 1; i++) { let inNode = nodes[i]; let outNode = nodes[i + 1];