mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-08 01:13:27 +01:00
support nurbs / vertex factory for boolean
This commit is contained in:
parent
e3859bdebc
commit
3c910e4838
11 changed files with 203 additions and 401 deletions
|
|
@ -64,11 +64,10 @@ function addGlobalDebugActions(app) {
|
||||||
app.viewer.render();
|
app.viewer.render();
|
||||||
},
|
},
|
||||||
AddHalfEdge: (he, color) => {
|
AddHalfEdge: (he, color) => {
|
||||||
const points = [he.vertexA.point];
|
const points = he.edge.curve.verb.tessellate().map(p => new Vector().set3(p));
|
||||||
if (he.edge && he.edge.curve) {
|
if (he.inverted) {
|
||||||
he.edge.curve.approximate(10, he.vertexA.point, he.vertexB.point, points);
|
points.reverse();
|
||||||
}
|
}
|
||||||
points.push(he.vertexB.point);
|
|
||||||
window.__DEBUG__.AddPolyLine(points, color);
|
window.__DEBUG__.AddPolyLine(points, color);
|
||||||
},
|
},
|
||||||
AddFace: (face, color) => {
|
AddFace: (face, color) => {
|
||||||
|
|
|
||||||
|
|
@ -88,11 +88,11 @@ App.prototype.scratchCode = function() {
|
||||||
const box1 = app.TPI.brep.primitives.box(500, 500, 500);
|
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 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));
|
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.union(box1, box2);
|
||||||
// let result = app.TPI.brep.bool.subtract(box1, box2);
|
let result = app.TPI.brep.bool.subtract(box1, box2);
|
||||||
// result = app.TPI.brep.bool.subtract(result, box3);
|
result = app.TPI.brep.bool.subtract(result, box3);
|
||||||
app.addShellOnScene(box1);
|
// app.addShellOnScene(box1);
|
||||||
app.addShellOnScene(box2);
|
app.addShellOnScene(result);
|
||||||
app.viewer.render();
|
app.viewer.render();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,24 +41,18 @@ export class BREPSceneSolid extends SceneSolid {
|
||||||
|
|
||||||
createEdges() {
|
createEdges() {
|
||||||
const visited = new Set();
|
const visited = new Set();
|
||||||
for (let face of this.shell.faces) {
|
for (let edge of this.shell.edges) {
|
||||||
for (let halfEdge of face.outerLoop.halfEdges) {
|
if (edge.data[EDGE_AUX] === undefined) {
|
||||||
if (!visited.has(halfEdge.edge)) {
|
const line = new THREE.Line(undefined, WIREFRAME_MATERIAL);
|
||||||
visited.add(halfEdge.edge);
|
const contour = edge.curve.verb.tessellate();
|
||||||
if (halfEdge.edge.data[EDGE_AUX] === undefined) {
|
for (let p of contour) {
|
||||||
const line = new THREE.Line(undefined, WIREFRAME_MATERIAL);
|
line.geometry.vertices.push(new THREE.Vector3().fromArray(p));
|
||||||
const contour = [halfEdge.vertexA.point];
|
|
||||||
halfEdge.edge.curve.approximate(10, halfEdge.vertexA.point, halfEdge.vertexB.point, contour);
|
|
||||||
contour.push(halfEdge.vertexB.point);
|
|
||||||
for (let p of contour) {
|
|
||||||
line.geometry.vertices.push(p.three());
|
|
||||||
}
|
|
||||||
this.wireframeGroup.add(line);
|
|
||||||
line.__TCAD_EDGE = halfEdge.edge;
|
|
||||||
halfEdge.edge.data['scene.edge'] = line;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
this.wireframeGroup.add(line);
|
||||||
|
line.__TCAD_EDGE = edge;
|
||||||
|
edge.data['scene.edge'] = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,13 +55,7 @@ export default function(face) {
|
||||||
}
|
}
|
||||||
analyzeCurvature(face.surface.verb, triangles);
|
analyzeCurvature(face.surface.verb, triangles);
|
||||||
|
|
||||||
if (face.surface.inverted) {
|
|
||||||
triangles.forEach(t => t.reverse());
|
|
||||||
}
|
|
||||||
|
|
||||||
return triangles.map(t => t.map(p => face.surface.point(p[0], p[1])));
|
return triangles.map(t => t.map(p => face.surface.point(p[0], p[1])));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function analyzeCurvature(nurbs, triangles) {
|
function analyzeCurvature(nurbs, triangles) {
|
||||||
|
|
|
||||||
|
|
@ -112,193 +112,6 @@ function assemble(walls, basePlane, lidPlane) {
|
||||||
return shell;
|
return shell;
|
||||||
}
|
}
|
||||||
|
|
||||||
function assembleRevolved(walls, baseSurface, lidSurface) {
|
|
||||||
const baseLoop = new Loop();
|
|
||||||
const lidLoop = new Loop();
|
|
||||||
const shell = new Shell();
|
|
||||||
|
|
||||||
// walls.reverse();
|
|
||||||
iterateSegments(walls, (wall, next) => {
|
|
||||||
|
|
||||||
const nullFace = new Face();
|
|
||||||
nullFace.outerLoop = new Loop();
|
|
||||||
function addEdge(he) {
|
|
||||||
he.edge = new Edge(Line.fromSegment(he.vertexA.point, he.vertexB.point))
|
|
||||||
const twin = new HalfEdge().setAB(he.vertexB, he.vertexA);
|
|
||||||
twin.loop = nullFace.outerLoop;
|
|
||||||
nullFace.outerLoop.halfEdges.push(twin);
|
|
||||||
he.edge.link(twin, he);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let he of wall.topEdges) {
|
|
||||||
addEdge(he);
|
|
||||||
// __DEBUG__.AddHalfEdge(he);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = next.bottomEdges.length - 1; i >= 0; i--) {
|
|
||||||
let he = next.bottomEdges[i];
|
|
||||||
addEdge(he);
|
|
||||||
// __DEBUG__.AddHalfEdge(he, 0xffffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
linkSegments(nullFace.outerLoop.halfEdges);
|
|
||||||
nullFace.data.NULL_FACE = {
|
|
||||||
curve: vertIsoCurve(wall.surface, 1, true),
|
|
||||||
start: wall.topEdges[0].twin()
|
|
||||||
};
|
|
||||||
// __DEBUG__.AddPoint.apply(null, nullFace.data.NULL_FACE.curve.point(0.0))
|
|
||||||
// __DEBUG__.AddPoint.apply(null, nullFace.data.NULL_FACE.curve.point(0.1))
|
|
||||||
// __DEBUG__.AddPoint.apply(null, nullFace.data.NULL_FACE.curve.point(0.2))
|
|
||||||
// __DEBUG__.AddPoint.apply(null, nullFace.data.NULL_FACE.curve.point(0.3))
|
|
||||||
// __DEBUG__.AddPoint.apply(null, nullFace.data.NULL_FACE.curve.point(0.4))
|
|
||||||
// __DEBUG__.AddPoint.apply(null, nullFace.data.NULL_FACE.curve.point(0.5))
|
|
||||||
mergeNullFace(nullFace.data.NULL_FACE);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
for (let wall of walls) {
|
|
||||||
|
|
||||||
function addHalfEdges(loop, edges) {
|
|
||||||
// for (let i = edges.length - 1; i >= 0; i--) {
|
|
||||||
// let he = edges[i];
|
|
||||||
for (let he of edges) {
|
|
||||||
he.edge = new Edge(Line.fromSegment(he.vertexA.point, he.vertexB.point))
|
|
||||||
const twin = new HalfEdge().setAB(he.vertexB, he.vertexA);
|
|
||||||
__DEBUG__.AddHalfEdge(twin)
|
|
||||||
twin.loop = loop;
|
|
||||||
loop.halfEdges.push(twin);
|
|
||||||
he.edge.link(twin, he);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addHalfEdges(baseLoop, wall.leftEdges);
|
|
||||||
addHalfEdges(lidLoop, wall.rightEdges);
|
|
||||||
|
|
||||||
for (let wallFace of wall.faces) {
|
|
||||||
shell.faces.push(wallFace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// walls.reverse();
|
|
||||||
|
|
||||||
lidLoop.halfEdges.reverse();
|
|
||||||
linkSegments(baseLoop.halfEdges);
|
|
||||||
linkSegments(lidLoop.halfEdges);
|
|
||||||
|
|
||||||
const baseFace = createFace(baseSurface, baseLoop);
|
|
||||||
const lidFace = createFace(lidSurface, lidLoop);
|
|
||||||
|
|
||||||
shell.faces.push(baseFace, lidFace);
|
|
||||||
shell.faces.forEach(f => f.shell = shell);
|
|
||||||
return shell;
|
|
||||||
}
|
|
||||||
|
|
||||||
function connectWalls(walls) {
|
|
||||||
|
|
||||||
iterateSegments(walls, (a, b) => {
|
|
||||||
|
|
||||||
function connect(halfEdgeA, halfEdgeB) {
|
|
||||||
const curve = Line.fromSegment(halfEdgeA.vertexA.point, halfEdgeA.vertexB.point);
|
|
||||||
new Edge(curve).link(halfEdgeA, halfEdgeB);
|
|
||||||
}
|
|
||||||
|
|
||||||
let aEdges = a.leftEdges;
|
|
||||||
let bEdges = b.rightEdges;
|
|
||||||
|
|
||||||
if (aEdges.length == 1 && bEdges.length == 1) {
|
|
||||||
connect(aEdges[0], bEdges[0])
|
|
||||||
} else {
|
|
||||||
throw "unsupported: use 'null-face' like it's done for the revolve and then merge it";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function revolveToWallNurbs(basePath, surface, p0, v, angle) {
|
|
||||||
const nurbses = [];
|
|
||||||
const n = basePath.points.length;
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
const curve = basePath.groups[i].toNurbs(surface);
|
|
||||||
const nurbs = new verb.geom.RevolvedSurface(curve.verb, p0.data(), v.data(), -angle);
|
|
||||||
nurbses.push(nurbs);
|
|
||||||
}
|
|
||||||
return nurbses;
|
|
||||||
}
|
|
||||||
|
|
||||||
function swap(obj, prop1, prop2) {
|
|
||||||
const tmp = obj[prop1];
|
|
||||||
obj[prop1] = obj[prop2];
|
|
||||||
obj[prop2] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function revolve(basePath, baseSurface, p0, v, angle) {
|
|
||||||
|
|
||||||
angle = -angle;
|
|
||||||
|
|
||||||
const baseLoop = new Loop();
|
|
||||||
|
|
||||||
const shell = new Shell();
|
|
||||||
const walls = [];
|
|
||||||
|
|
||||||
const n = basePath.points.length;
|
|
||||||
|
|
||||||
const baseVertices = [];
|
|
||||||
const lidVertices = [];
|
|
||||||
|
|
||||||
const nurbses = revolveToWallNurbs(basePath, baseSurface, p0, v, -angle);
|
|
||||||
|
|
||||||
for (let nurbs of nurbses) {
|
|
||||||
const domU = nurbs.domainU();
|
|
||||||
const domV = nurbs.domainV();
|
|
||||||
// profile of revolving becomes V direction
|
|
||||||
baseVertices.push(new Vertex(new Point().set3(nurbs.point(domU.min, domV.min))));
|
|
||||||
lidVertices.push(new Vertex(new Point().set3(nurbs.point(domU.max, domV.min))));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
let j = (i + 1) % n;
|
|
||||||
const nurbs = nurbses[i];
|
|
||||||
const wall = wallFromNUBRS(nurbs, false, baseVertices[i], lidVertices[i], lidVertices[j], baseVertices[j]);
|
|
||||||
walls.push(wall);
|
|
||||||
}
|
|
||||||
|
|
||||||
const normal = cad_utils.normalOfCCWSeq([lidVertices[2].point, lidVertices[1].point, lidVertices[0].point]);
|
|
||||||
const w = lidVertices[0].point.dot(normal);
|
|
||||||
const planeLid = new Plane(normal, w);
|
|
||||||
|
|
||||||
let revolved = assembleRevolved(walls, baseSurface, planeLid);
|
|
||||||
if (angle < 0) {
|
|
||||||
invert(revolved);
|
|
||||||
}
|
|
||||||
return revolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTwin(halfEdge) {
|
|
||||||
const twin = new HalfEdge();
|
|
||||||
twin.vertexA = halfEdge.vertexB;
|
|
||||||
twin.vertexB = halfEdge.vertexA;
|
|
||||||
twin.edge = halfEdge.edge;
|
|
||||||
if (halfEdge.edge.halfEdge1 == halfEdge) {
|
|
||||||
halfEdge.edge.halfEdge2 = twin;
|
|
||||||
} else {
|
|
||||||
halfEdge.edge.halfEdge1 = twin;
|
|
||||||
}
|
|
||||||
return twin;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFace(surface, loop) {
|
|
||||||
const face = new Face(surface);
|
|
||||||
face.outerLoop = loop;
|
|
||||||
loop.face = face;
|
|
||||||
return face;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function createPlaneForLoop(normal, loop) {
|
|
||||||
const w = loop.halfEdges[0].vertexA.point.dot(normal);
|
|
||||||
const plane = new Plane(normal, w);
|
|
||||||
return plane;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createBoundingNurbs(points, plane) {
|
function createBoundingNurbs(points, plane) {
|
||||||
if (!plane) {
|
if (!plane) {
|
||||||
const normal = cad_utils.normalOfCCWSeq(points);
|
const normal = cad_utils.normalOfCCWSeq(points);
|
||||||
|
|
@ -322,55 +135,6 @@ function createBoundingNurbs(points, plane) {
|
||||||
return nurbs;
|
return nurbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function linkHalfEdges(edge, halfEdge1, halfEdge2) {
|
|
||||||
halfEdge1.edge = edge;
|
|
||||||
halfEdge2.edge = edge;
|
|
||||||
edge.halfEdge1 = halfEdge1;
|
|
||||||
edge.halfEdge2 = halfEdge2;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createHalfEdge(loop, vertexA, vertexB) {
|
|
||||||
const halfEdge = new HalfEdge();
|
|
||||||
halfEdge.loop = loop;
|
|
||||||
halfEdge.vertexA = vertexA;
|
|
||||||
halfEdge.vertexB = vertexB;
|
|
||||||
loop.halfEdges.push(halfEdge);
|
|
||||||
return halfEdge;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function linkSegments(halfEdges) {
|
|
||||||
iterateSegments(halfEdges, (prev, next) => {
|
|
||||||
prev.next = next;
|
|
||||||
next.prev = prev;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function point(x, y, z) {
|
|
||||||
return new Point(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function iterateSegments(items, callback) {
|
|
||||||
let length = items.length;
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
let j = (i + 1) % length;
|
|
||||||
callback(items[i], items[j], i, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createPlaneLoop(vertices, curves) {
|
|
||||||
|
|
||||||
const loop = new Loop();
|
|
||||||
|
|
||||||
iterateSegments(vertices, (a, b, i) => {
|
|
||||||
const halfEdge = createHalfEdge(loop, a, b);
|
|
||||||
halfEdge.edge = new Edge(curves[i] ? curves[i] : Line.fromSegment(a.point, b.point));
|
|
||||||
return halfEdge;
|
|
||||||
});
|
|
||||||
|
|
||||||
linkSegments(loop.halfEdges);
|
|
||||||
return loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
function bothClassOf(o1, o2, className) {
|
function bothClassOf(o1, o2, className) {
|
||||||
return o1.constructor.name === className && o2.constructor.name === className;
|
return o1.constructor.name === className && o2.constructor.name === className;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import * as BREPBuilder from './brep-builder'
|
import {Point} from './geom/point'
|
||||||
|
import {createPrism} from './brep-builder'
|
||||||
import {Matrix3} from '../math/l3space'
|
import {Matrix3} from '../math/l3space'
|
||||||
|
|
||||||
export function box(w, h, d, tr) {
|
export function box(w, h, d, tr) {
|
||||||
|
|
@ -8,11 +9,11 @@ export function box(w, h, d, tr) {
|
||||||
if (!tr) {
|
if (!tr) {
|
||||||
tr = IDENTITY;
|
tr = IDENTITY;
|
||||||
}
|
}
|
||||||
return BREPBuilder.createPrism([
|
return createPrism([
|
||||||
tr._apply(BREPBuilder.point(-wh, -hh, dh)),
|
tr._apply(new Point(-wh, -hh, dh)),
|
||||||
tr._apply(BREPBuilder.point( wh, -hh, dh)),
|
tr._apply(new Point( wh, -hh, dh)),
|
||||||
tr._apply(BREPBuilder.point( wh, hh, dh)),
|
tr._apply(new Point( wh, hh, dh)),
|
||||||
tr._apply(BREPBuilder.point(-wh, hh, dh))
|
tr._apply(new Point(-wh, hh, dh))
|
||||||
], d);
|
], d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,45 +17,12 @@ export class NurbsCurve extends Curve {
|
||||||
return new NurbsCurve(this.verb.transform(tr));
|
return new NurbsCurve(this.verb.transform(tr));
|
||||||
}
|
}
|
||||||
|
|
||||||
approximate(resolution, from, to, out) {
|
|
||||||
const chunks = this.verb.divideByArcLength(10);
|
|
||||||
let startU = this.verb.closestParam(from.toArray());
|
|
||||||
let endU = this.verb.closestParam(to.toArray());
|
|
||||||
const reverse = startU > endU;
|
|
||||||
if (reverse) {
|
|
||||||
const tmp = startU;
|
|
||||||
startU = endU;
|
|
||||||
endU = tmp;
|
|
||||||
chunks.reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let sample of chunks) {
|
|
||||||
const u = sample.u;
|
|
||||||
if (u > startU + math.TOLERANCE && u < endU - math.TOLERANCE) {
|
|
||||||
out.push(new Point().set3(this.verb.point(u)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
approximateU(resolution, paramFrom, paramTo, consumer) {
|
|
||||||
let u = paramFrom;
|
|
||||||
let endU = paramTo;
|
|
||||||
let step = this.verb.paramAtLength(resolution);
|
|
||||||
if (u > endU) {
|
|
||||||
step *= -1;
|
|
||||||
}
|
|
||||||
u += step;
|
|
||||||
for (;step > 0 ? u < endU : u > endU; u += step) {
|
|
||||||
consumer(u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tangentAtPoint(point) {
|
tangentAtPoint(point) {
|
||||||
return new Point().set3(this.verb.tangent(this.verb.closestParam(point.data())))._normalize();
|
return pt(this.verb.tangent(this.verb.closestParam(point.data())))._normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
tangentAtParam(param) {
|
tangentAtParam(param) {
|
||||||
return new Point().set3(this.verb.tangent(param ))._normalize();
|
return pt(this.verb.tangent(param ))._normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
closestDistanceToPoint(point) {
|
closestDistanceToPoint(point) {
|
||||||
|
|
@ -64,7 +31,7 @@ export class NurbsCurve extends Curve {
|
||||||
}
|
}
|
||||||
|
|
||||||
split(point) {
|
split(point) {
|
||||||
return this.verb.split(this.verb.closestParam(point.data)).map(v => new NurbsCurve(v));
|
return this.verb.split(this.verb.closestParam(point.data())).map(v => new NurbsCurve(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
invert() {
|
invert() {
|
||||||
|
|
@ -72,17 +39,55 @@ export class NurbsCurve extends Curve {
|
||||||
}
|
}
|
||||||
|
|
||||||
point(u) {
|
point(u) {
|
||||||
return new Point().set3(this.verb.point(u));
|
return pt(this.verb.point(u));
|
||||||
}
|
}
|
||||||
|
|
||||||
intersectCurve(other, tol) {
|
intersectCurve(other, tol) {
|
||||||
return verb.geom.Intersect.curves(this.verb, other.verb, tol).map( i => ({
|
let isecs = [];
|
||||||
|
tol = tol || 1e-6;
|
||||||
|
|
||||||
|
const eq = (v1, v2) => math.areVectorsEqual3(v1, v2, tol);
|
||||||
|
|
||||||
|
function add(i0) {
|
||||||
|
for (let i1 of isecs) {
|
||||||
|
if (eq(i0.p0, i1.p0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isecs.push(i0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isecOn(c0, c1, u0) {
|
||||||
|
const p0 = c0.verb.point(u0);
|
||||||
|
const u1 = c1.verb.closestParam(p0);
|
||||||
|
const p1 = c1.verb.point(u1);
|
||||||
|
if (eq(p0, p1)) {
|
||||||
|
if (c0 === other) {
|
||||||
|
add({u0: u1, u1: u0, p0: p1, p1: p0});
|
||||||
|
} else {
|
||||||
|
add({u0, u1, p0, p1});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isecOn(this, other, 0);
|
||||||
|
isecOn(this, other, 1);
|
||||||
|
isecOn(other, this, 0);
|
||||||
|
isecOn(other, this, 1);
|
||||||
|
|
||||||
|
verb.geom.Intersect.curves(this.verb, other.verb, tol).forEach( i => add({
|
||||||
u0: i.u0,
|
u0: i.u0,
|
||||||
u1: i.u1,
|
u1: i.u1,
|
||||||
p0: new Vector().set3(i.point0),
|
p0: i.point0,
|
||||||
p1: new Vector().set3(i.point1)
|
p1: i.point1
|
||||||
}));
|
}));
|
||||||
}
|
isecs.forEach(i => {
|
||||||
|
i.p0 = pt(i.p0);
|
||||||
|
i.p1 = pt(i.p1);
|
||||||
|
})
|
||||||
|
return isecs;
|
||||||
|
}
|
||||||
|
|
||||||
static createByPoints(points, degeree) {
|
static createByPoints(points, degeree) {
|
||||||
points = points.map(p => p.data());
|
points = points.map(p => p.data());
|
||||||
|
|
@ -112,7 +117,7 @@ export class NurbsSurface extends Surface {
|
||||||
|
|
||||||
normal(point) {
|
normal(point) {
|
||||||
let uv = this.verb.closestParam(point.data());
|
let uv = this.verb.closestParam(point.data());
|
||||||
let normal = new Vector().set3(this.verb.normal(uv[0], uv[1]));
|
let normal = pt(this.verb.normal(uv[0], uv[1]));
|
||||||
if (this.inverted) {
|
if (this.inverted) {
|
||||||
normal._negate();
|
normal._negate();
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +126,7 @@ export class NurbsSurface extends Surface {
|
||||||
}
|
}
|
||||||
|
|
||||||
normalUV(u, v) {
|
normalUV(u, v) {
|
||||||
let normal = new Vector().set3(this.verb.normal(u, v));
|
let normal = pt(this.verb.normal(u, v));
|
||||||
if (this.inverted) {
|
if (this.inverted) {
|
||||||
normal._negate();
|
normal._negate();
|
||||||
}
|
}
|
||||||
|
|
@ -134,11 +139,11 @@ export class NurbsSurface extends Surface {
|
||||||
}
|
}
|
||||||
|
|
||||||
point(u, v) {
|
point(u, v) {
|
||||||
return new Point().set3(this.verb.point(u, v));
|
return pt(this.verb.point(u, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
intersectSurfaceForSameClass(other, tol) {
|
intersectSurfaceForSameClass(other, tol) {
|
||||||
const curves = verb.geom.Intersect.surfaces(this.verb, other.verb, tol);
|
const curves = verb_isec(this.verb, other.verb);
|
||||||
let inverted = this.inverted !== other.inverted;
|
let inverted = this.inverted !== other.inverted;
|
||||||
return curves.map(curve => new NurbsCurve(inverted ? curve.reverse() : curve));
|
return curves.map(curve => new NurbsCurve(inverted ? curve.reverse() : curve));
|
||||||
}
|
}
|
||||||
|
|
@ -162,4 +167,32 @@ export class NurbsSurface extends Surface {
|
||||||
isoCurveAlignV(param) {
|
isoCurveAlignV(param) {
|
||||||
return this.isoCurve(param, false);
|
return this.isoCurve(param, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dist(p1, p2) {
|
||||||
|
return math.distance3(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pt(data) {
|
||||||
|
return new Point().set3(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function verb_isec(nurbs1, nurbs2) {
|
||||||
|
const tol = 1e-3
|
||||||
|
const surface0 = nurbs1.asNurbs();
|
||||||
|
const surface1 = nurbs2.asNurbs();
|
||||||
|
var tess1 = verb.eval.Tess.rationalSurfaceAdaptive(surface0);
|
||||||
|
var tess2 = verb.eval.Tess.rationalSurfaceAdaptive(surface1);
|
||||||
|
var resApprox = verb.eval.Intersect.meshes(tess1,tess2);
|
||||||
|
var exactPls = resApprox.map(function(pl) {
|
||||||
|
return pl.map(function(inter) {
|
||||||
|
return verb.eval.Intersect.surfacesAtPointWithEstimate(surface0,surface1,inter.uv0,inter.uv1,tol);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return exactPls.map(function(x) {
|
||||||
|
return verb.eval.Make.rationalInterpCurve(x.map(function(y) {
|
||||||
|
return y.point;
|
||||||
|
}), x.length - 1);
|
||||||
|
}).map(cd => new verb.geom.NurbsCurve(cd));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import * as BREPBuilder from '../brep-builder';
|
|
||||||
import {BREPValidator} from '../brep-validator';
|
import {BREPValidator} from '../brep-validator';
|
||||||
import {Edge} from '../topo/edge';
|
import {Edge} from '../topo/edge';
|
||||||
import {Loop} from '../topo/loop';
|
import {Loop} from '../topo/loop';
|
||||||
|
|
@ -15,10 +14,7 @@ export const TOLERANCE_HALF = TOLERANCE * 0.5;
|
||||||
const DEBUG = {
|
const DEBUG = {
|
||||||
OPERANDS_MODE: false,
|
OPERANDS_MODE: false,
|
||||||
LOOP_DETECTION: true,
|
LOOP_DETECTION: true,
|
||||||
FACE_FACE_INTERSECTION: false,
|
FACE_FACE_INTERSECTION: true,
|
||||||
FACE_EDGE_INTERSECTION: false,
|
|
||||||
SEWING: false,
|
|
||||||
EDGE_MERGING: true,
|
|
||||||
NOOP: () => {}
|
NOOP: () => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -62,11 +58,11 @@ export function invert( shell ) {
|
||||||
|
|
||||||
export function BooleanAlgorithm( shell1, shell2, type ) {
|
export function BooleanAlgorithm( shell1, shell2, type ) {
|
||||||
|
|
||||||
POINT_TO_VERT.clear();
|
|
||||||
|
|
||||||
let facesData = [];
|
let facesData = [];
|
||||||
|
|
||||||
mergeVertices(shell1, shell2);
|
mergeVertices(shell1, shell2);
|
||||||
|
initVertexFactory(shell1, shell2)
|
||||||
|
|
||||||
intersectEdges(shell1, shell2);
|
intersectEdges(shell1, shell2);
|
||||||
|
|
||||||
initSolveData(shell1, facesData);
|
initSolveData(shell1, facesData);
|
||||||
|
|
@ -75,7 +71,7 @@ export function BooleanAlgorithm( shell1, shell2, type ) {
|
||||||
intersectFaces(shell1, shell2, type);
|
intersectFaces(shell1, shell2, type);
|
||||||
|
|
||||||
for (let faceData of facesData) {
|
for (let faceData of facesData) {
|
||||||
initGraph(faceData);
|
faceData.initGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
const allFaces = [];
|
const allFaces = [];
|
||||||
|
|
@ -119,6 +115,7 @@ function detectLoops(face) {
|
||||||
const seen = new Set();
|
const seen = new Set();
|
||||||
let edges = [];
|
let edges = [];
|
||||||
for (let e of face.edges) edges.push(e);
|
for (let e of face.edges) edges.push(e);
|
||||||
|
for (let e of faceData.loopOfNew.halfEdges) edges.push(e);
|
||||||
while (true) {
|
while (true) {
|
||||||
let edge = edges.pop();
|
let edge = edges.pop();
|
||||||
if (!edge) {
|
if (!edge) {
|
||||||
|
|
@ -127,8 +124,7 @@ function detectLoops(face) {
|
||||||
if (seen.has(edge)) {
|
if (seen.has(edge)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const loop = new Loop();
|
const loop = new Loop(null);
|
||||||
loop.face = face;
|
|
||||||
let surface = face.surface;
|
let surface = face.surface;
|
||||||
while (edge) {
|
while (edge) {
|
||||||
if (DEBUG.LOOP_DETECTION) {
|
if (DEBUG.LOOP_DETECTION) {
|
||||||
|
|
@ -147,24 +143,13 @@ function detectLoops(face) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loop.halfEdges[0].vertexA === loop.halfEdges[loop.halfEdges.length - 1].vertexB) {
|
if (loop.halfEdges[0].vertexA === loop.halfEdges[loop.halfEdges.length - 1].vertexB) {
|
||||||
for (let halfEdge of loop.halfEdges) {
|
loop.link();
|
||||||
halfEdge.loop = loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
BREPBuilder.linkSegments(loop.halfEdges);
|
|
||||||
loops.push(loop);
|
loops.push(loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return loops;
|
return loops;
|
||||||
}
|
}
|
||||||
|
|
||||||
function initGraph(faceData) {
|
|
||||||
faceData.vertexToEdge.clear();
|
|
||||||
for (let he of faceData.face.edges) {
|
|
||||||
addToListInMap(faceData.vertexToEdge, he.vertexA, he);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function edgeV(edge) {
|
function edgeV(edge) {
|
||||||
return edge.vertexB.point.minus(edge.vertexA.point)._normalize();
|
return edge.vertexB.point.minus(edge.vertexA.point)._normalize();
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +158,7 @@ export function mergeVertices(shell1, shell2) {
|
||||||
const toSwap = new Map();
|
const toSwap = new Map();
|
||||||
for (let v1 of shell1.vertices) {
|
for (let v1 of shell1.vertices) {
|
||||||
for (let v2 of shell2.vertices) {
|
for (let v2 of shell2.vertices) {
|
||||||
if (math.areVectorsEqual(v1.point, v2.point, TOLERANCE)) {
|
if (veq(v1.point, v2.point)) {
|
||||||
toSwap.set(v2, v1);
|
toSwap.set(v2, v1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -193,13 +178,6 @@ export function mergeVertices(shell1, shell2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function squash(face, edges) {
|
|
||||||
face.outerLoop = new Loop();
|
|
||||||
face.outerLoop.face = face;
|
|
||||||
edges.forEach(he => face.outerLoop.halfEdges.push(he));
|
|
||||||
face.innerLoops = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterFaces(faces, newLoops) {
|
function filterFaces(faces, newLoops) {
|
||||||
const validFaces = new Set(faces);
|
const validFaces = new Set(faces);
|
||||||
const result = new Set();
|
const result = new Set();
|
||||||
|
|
@ -248,6 +226,7 @@ function traverseFaces(face, validFaces, callback) {
|
||||||
export function loopsToFaces(originFace, loops, out) {
|
export function loopsToFaces(originFace, loops, out) {
|
||||||
const face = new Face(originFace.surface);
|
const face = new Face(originFace.surface);
|
||||||
face.innerLoops = loops;
|
face.innerLoops = loops;
|
||||||
|
loops.forEach(loop => loop.face = face);
|
||||||
out.push(face);
|
out.push(face);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -321,16 +300,16 @@ function intersectEdges(shell1, shell2) {
|
||||||
for (let point of points) {
|
for (let point of points) {
|
||||||
const {u0, u1} = point;
|
const {u0, u1} = point;
|
||||||
let vertex;
|
let vertex;
|
||||||
if (equal(u0, 0)) {
|
if (eq(u0, 0)) {
|
||||||
vertex = e1.halfEdge1.vertexA;
|
vertex = e1.halfEdge1.vertexA;
|
||||||
} else if (equal(u0, 1)) {
|
} else if (eq(u0, 1)) {
|
||||||
vertex = e1.halfEdge1.vertexB;
|
vertex = e1.halfEdge1.vertexB;
|
||||||
} else if (equal(u1, 0)) {
|
} else if (eq(u1, 0)) {
|
||||||
vertex = e2.halfEdge1.vertexA;
|
vertex = e2.halfEdge1.vertexA;
|
||||||
} else if (equal(u1, 1)) {
|
} else if (eq(u1, 1)) {
|
||||||
vertex = e2.halfEdge1.vertexB;
|
vertex = e2.halfEdge1.vertexB;
|
||||||
} else {
|
} else {
|
||||||
vertex = newVertex(e1.curve.point(u0));
|
vertex = vertexFactory.create(e1.curve.point(u0));
|
||||||
}
|
}
|
||||||
const new1 = splitEdgeByVertex(e1, vertex);
|
const new1 = splitEdgeByVertex(e1, vertex);
|
||||||
const new2 = splitEdgeByVertex(e2, vertex);
|
const new2 = splitEdgeByVertex(e2, vertex);
|
||||||
|
|
@ -362,7 +341,7 @@ function fixCurveDirection(curve, surface1, surface2, operationType) {
|
||||||
expectedDirection._negate();
|
expectedDirection._negate();
|
||||||
}
|
}
|
||||||
let sameAsExpected = expectedDirection.dot(tangent) > 0;
|
let sameAsExpected = expectedDirection.dot(tangent) > 0;
|
||||||
if (sameAsExpected) {
|
if (!sameAsExpected) {
|
||||||
curve = curve.invert();
|
curve = curve.invert();
|
||||||
}
|
}
|
||||||
return curve;
|
return curve;
|
||||||
|
|
@ -373,7 +352,7 @@ function newEdgeDirectionValidityTest(e, curve) {
|
||||||
let point = e.halfEdge1.vertexA.point;
|
let point = e.halfEdge1.vertexA.point;
|
||||||
let tangent = curve.tangentAtPoint(point);
|
let tangent = curve.tangentAtPoint(point);
|
||||||
assert('tangent of originated curve and first halfEdge should be the same', math.vectorsEqual(tangent, e.halfEdge1.tangent(point)));
|
assert('tangent of originated curve and first halfEdge should be the same', math.vectorsEqual(tangent, e.halfEdge1.tangent(point)));
|
||||||
assert('tangent of originated curve and second halfEdge should be the opposite', math.vectorsEqual(tangent, e.halfEdge2.tangent(point)));
|
assert('tangent of originated curve and second halfEdge should be the opposite', math.vectorsEqual(tangent._negate(), e.halfEdge2.tangent(point)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function intersectFaces(shell1, shell2, operationType) {
|
function intersectFaces(shell1, shell2, operationType) {
|
||||||
|
|
@ -381,13 +360,15 @@ function intersectFaces(shell1, shell2, operationType) {
|
||||||
for (let i = 0; i < shell1.faces.length; i++) {
|
for (let i = 0; i < shell1.faces.length; i++) {
|
||||||
const face1 = shell1.faces[i];
|
const face1 = shell1.faces[i];
|
||||||
if (DEBUG.FACE_FACE_INTERSECTION) {
|
if (DEBUG.FACE_FACE_INTERSECTION) {
|
||||||
__DEBUG__.Clear(); __DEBUG__.AddFace(face1, 0x00ff00);
|
__DEBUG__.Clear();
|
||||||
|
__DEBUG__.AddFace(face1, 0x00ff00);
|
||||||
DEBUG.NOOP();
|
DEBUG.NOOP();
|
||||||
}
|
}
|
||||||
for (let j = 0; j < shell2.faces.length; j++) {
|
for (let j = 0; j < shell2.faces.length; j++) {
|
||||||
const face2 = shell2.faces[j];
|
const face2 = shell2.faces[j];
|
||||||
if (DEBUG.FACE_FACE_INTERSECTION) {
|
if (DEBUG.FACE_FACE_INTERSECTION) {
|
||||||
__DEBUG__.Clear(); __DEBUG__.AddFace(face1, 0x00ff00);
|
__DEBUG__.Clear();
|
||||||
|
__DEBUG__.AddFace(face1, 0x00ff00);
|
||||||
__DEBUG__.AddFace(face2, 0x0000ff);
|
__DEBUG__.AddFace(face2, 0x0000ff);
|
||||||
if (face1.refId === 0 && face2.refId === 0) {
|
if (face1.refId === 0 && face2.refId === 0) {
|
||||||
DEBUG.NOOP();
|
DEBUG.NOOP();
|
||||||
|
|
@ -419,7 +400,7 @@ function intersectFaces(shell1, shell2, operationType) {
|
||||||
|
|
||||||
function addNewEdge(face, halfEdge) {
|
function addNewEdge(face, halfEdge) {
|
||||||
const data = face.data[MY];
|
const data = face.data[MY];
|
||||||
data.newEdges.push(halfEdge);
|
data.loopOfNew.halfEdges.push(halfEdge);
|
||||||
halfEdge.loop = data.loopOfNew;
|
halfEdge.loop = data.loopOfNew;
|
||||||
EdgeSolveData.createIfEmpty(halfEdge).newEdgeFlag = true;
|
EdgeSolveData.createIfEmpty(halfEdge).newEdgeFlag = true;
|
||||||
//addToListInMap(data.vertexToEdge, halfEdge.vertexA, halfEdge);
|
//addToListInMap(data.vertexToEdge, halfEdge.vertexA, halfEdge);
|
||||||
|
|
@ -445,7 +426,7 @@ function filterNodes(nodes) {
|
||||||
if (i === j) continue;
|
if (i === j) continue;
|
||||||
const node2 = nodes[j];
|
const node2 = nodes[j];
|
||||||
if (node2 !== null) {
|
if (node2 !== null) {
|
||||||
if (equal(node2.u, node1.u)) {
|
if (eq(node2.u, node1.u)) {
|
||||||
if (node1.normal + node2.normal === 0) {
|
if (node1.normal + node2.normal === 0) {
|
||||||
nodes[i] = null
|
nodes[i] = null
|
||||||
}
|
}
|
||||||
|
|
@ -474,12 +455,12 @@ function intersectCurveWithEdge(curve, edge, result) {
|
||||||
const {u0, u1} = point;
|
const {u0, u1} = point;
|
||||||
|
|
||||||
let vertex;
|
let vertex;
|
||||||
if (equal(u0, 0)) {
|
if (eq(u0, 0)) {
|
||||||
vertex = edge.edge.halfEdge1.vertexA;
|
vertex = edge.edge.halfEdge1.vertexA;
|
||||||
} else if (equal(u0, 1)) {
|
} else if (eq(u0, 1)) {
|
||||||
vertex = edge.edge.halfEdge1.vertexB;
|
vertex = edge.edge.halfEdge1.vertexB;
|
||||||
} else {
|
} else {
|
||||||
vertex = new Vertex(edge.edge.curve.point(u0));
|
vertex = vertexFactory.create(point.p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push(new Node(vertex, edge, curve, u1));
|
result.push(new Node(vertex, edge, curve, u1));
|
||||||
|
|
@ -498,8 +479,8 @@ function split(nodes, curve, result) {
|
||||||
|
|
||||||
const edge = new Edge(curve, inNode.vertex, outNode.vertex);
|
const edge = new Edge(curve, inNode.vertex, outNode.vertex);
|
||||||
|
|
||||||
splitEdgeByVertex(inNode.edge, edge.halfEdge1.vertexA);
|
splitEdgeByVertex(inNode.edge.edge, edge.halfEdge1.vertexA);
|
||||||
splitEdgeByVertex(outNode.edge, edge.halfEdge1.vertexB);
|
splitEdgeByVertex(outNode.edge.edge, edge.halfEdge1.vertexB);
|
||||||
|
|
||||||
result.push(edge);
|
result.push(edge);
|
||||||
}
|
}
|
||||||
|
|
@ -533,23 +514,15 @@ function splitEdgeByVertex(edge, vertex) {
|
||||||
return [edge1, edge2];
|
return [edge1, edge2];
|
||||||
}
|
}
|
||||||
|
|
||||||
const POINT_TO_VERT = new Map();
|
|
||||||
function newVertex(point) {
|
|
||||||
let vertex = POINT_TO_VERT.get(point);
|
|
||||||
if (!vertex) {
|
|
||||||
vertex = new Vertex(point);
|
|
||||||
duplicatePointTest(point);
|
|
||||||
POINT_TO_VERT.set(point, vertex);
|
|
||||||
}
|
|
||||||
return vertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
function nodeNormal(point, edge, curve) {
|
function nodeNormal(point, edge, curve) {
|
||||||
|
const normal = edge.loop.face.surface.normal(point);
|
||||||
const edgeTangent = edge.tangent(point);
|
const edgeTangent = edge.tangent(point);
|
||||||
const curveTangent = curve.tangentAtPoint(point);
|
const curveTangent = curve.tangentAtPoint(point);
|
||||||
|
|
||||||
let dot = edgeTangent.dot(curveTangent);
|
|
||||||
if (equal(dot, 0)) {
|
let cross = normal.cross(edgeTangent);
|
||||||
|
let dot = cross.dot(curveTangent);
|
||||||
|
if (eq(dot, 0)) {
|
||||||
dot = 0;
|
dot = 0;
|
||||||
} else {
|
} else {
|
||||||
if (dot < 0)
|
if (dot < 0)
|
||||||
|
|
@ -597,23 +570,44 @@ function Node(vertex, edge, curve, u) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let __DEBUG_POINT_DUPS = [];
|
let vertexFactory = null;
|
||||||
function duplicatePointTest(point, data) {
|
function initVertexFactory(shell1, shell2) {
|
||||||
data = data || {};
|
vertexFactory = new VertexFactory();
|
||||||
let res = false;
|
vertexFactory.addVertices(shell1.vertices);
|
||||||
for (let entry of __DEBUG_POINT_DUPS) {
|
vertexFactory.addVertices(shell2.vertices);
|
||||||
let other = entry[0];
|
}
|
||||||
if (math.areVectorsEqual(point, other, TOLERANCE)) {
|
|
||||||
res = true;
|
class VertexFactory {
|
||||||
break;
|
|
||||||
|
constructor() {
|
||||||
|
this.vertices = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
addVertices(vertices) {
|
||||||
|
for (let v of vertices) {
|
||||||
|
this.vertices.push(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__DEBUG_POINT_DUPS.push([point, data]);
|
|
||||||
if (res) {
|
find(point) {
|
||||||
__DEBUG__.AddPoint(point);
|
for (let vertex of this.vertices) {
|
||||||
console.error('DUPLICATE DETECTED: ' + point)
|
if (veq(point, vertex.point)) {
|
||||||
|
return vertex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
create(point) {
|
||||||
|
|
||||||
|
let vertex = this.find(point);
|
||||||
|
if (vertex === null) {
|
||||||
|
vertex = new Vertex(point);
|
||||||
|
this.vertices.push(vertex);
|
||||||
|
console.log("DUPLICATE DETECTED: " + vertex);
|
||||||
|
}
|
||||||
|
return vertex;
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SolveData {
|
class SolveData {
|
||||||
|
|
@ -625,11 +619,22 @@ class SolveData {
|
||||||
class FaceSolveData {
|
class FaceSolveData {
|
||||||
constructor(face) {
|
constructor(face) {
|
||||||
this.face = face;
|
this.face = face;
|
||||||
this.loopOfNew = new Loop();
|
this.loopOfNew = new Loop(face);
|
||||||
this.newEdges = this.loopOfNew.halfEdges;
|
|
||||||
this.vertexToEdge = new Map();
|
this.vertexToEdge = new Map();
|
||||||
this.overlaps = new Set();
|
}
|
||||||
this.loopOfNew.face = face;
|
|
||||||
|
initGraph() {
|
||||||
|
this.vertexToEdge.clear();
|
||||||
|
for (let he of this.face.edges) {
|
||||||
|
this.addToGraph(he);
|
||||||
|
}
|
||||||
|
for (let he of this.loopOfNew.halfEdges) {
|
||||||
|
this.addToGraph(he);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addToGraph(he) {
|
||||||
|
addToListInMap(this.vertexToEdge, he.vertexA, he);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -660,10 +665,14 @@ function __DEBUG_OPERANDS(shell1, shell2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function equal(v1, v2) {
|
function eq(v1, v2) {
|
||||||
return math.areEqual(v1, v2, TOLERANCE);
|
return math.areEqual(v1, v2, TOLERANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function veq(v1, v2) {
|
||||||
|
return math.areVectorsEqual(v1, v2, TOLERANCE);
|
||||||
|
}
|
||||||
|
|
||||||
function assert(name, cond) {
|
function assert(name, cond) {
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
throw 'ASSERTION FAILED: ' + name;
|
throw 'ASSERTION FAILED: ' + name;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export class Face extends TopoObject {
|
||||||
this.id = undefined;
|
this.id = undefined;
|
||||||
this.surface = surface;
|
this.surface = surface;
|
||||||
this.shell = null;
|
this.shell = null;
|
||||||
this.outerLoop = new Loop();
|
this.outerLoop = new Loop(this);
|
||||||
this.innerLoops = [];
|
this.innerLoops = [];
|
||||||
this.defineIterable('loops', () => loopsGenerator(this));
|
this.defineIterable('loops', () => loopsGenerator(this));
|
||||||
this.defineIterable('edges', () => halfEdgesGenerator(this))
|
this.defineIterable('edges', () => halfEdgesGenerator(this))
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ import * as math from '../../math/math'
|
||||||
|
|
||||||
export class Loop extends TopoObject {
|
export class Loop extends TopoObject {
|
||||||
|
|
||||||
constructor() {
|
constructor(face) {
|
||||||
super();
|
super();
|
||||||
this.face = null;
|
this.face = face;
|
||||||
this.halfEdges = [];
|
this.halfEdges = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,6 +26,8 @@ export class Loop extends TopoObject {
|
||||||
const next = this.halfEdges[j];
|
const next = this.halfEdges[j];
|
||||||
curr.next = next;
|
curr.next = next;
|
||||||
next.prev = curr;
|
next.prev = curr;
|
||||||
|
|
||||||
|
curr.loop = this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,12 @@ export function areVectorsEqual(v1, v2, tolerance) {
|
||||||
areEqual(v1.z, v2.z, tolerance);
|
areEqual(v1.z, v2.z, tolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function areVectorsEqual3(v1, v2, tolerance) {
|
||||||
|
return areEqual(v1[0], v2[0], tolerance) &&
|
||||||
|
areEqual(v1[1], v2[1], tolerance) &&
|
||||||
|
areEqual(v1[2], v2[2], tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
export function vectorsEqual(v1, v2) {
|
export function vectorsEqual(v1, v2) {
|
||||||
return areVectorsEqual(v1, v2, TOLERANCE);
|
return areVectorsEqual(v1, v2, TOLERANCE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue