NURBS suport for BREP boolean / adjusting the API

This commit is contained in:
Val Erastov 2017-09-08 20:36:17 -07:00
parent a2da7e348d
commit 60e1455bb1
10 changed files with 306 additions and 1119 deletions

View file

@ -24,6 +24,8 @@ import * as BREPBool from '../brep/operations/boolean'
import {BREPValidator} from '../brep/brep-validator'
import {BREPSceneSolid} from './scene/brep-scene-object'
import TPI from './tpi'
import {createBox, createSphere, createCylinder} from "../hds/hds-builder";
// import {createSphere, rayMarchOntoCanvas, sdfIntersection, sdfSolid, sdfSubtract, sdfTransform, sdfUnion} from "../hds/sdf";
function App() {
this.id = this.processHints();
@ -83,27 +85,51 @@ App.prototype.addShellOnScene = function(shell, skin) {
};
App.prototype.scratchCode = function() {
const a = BREPBuilder.createPrism(ap.map(p => new this.TPI.brep.geom.Point().set3(p)), 500);
const b = BREPBuilder.createPrism(bp.map(p => new this.TPI.brep.geom.Point().set3(p)), 500);
this.addShellOnScene(a, {
color: 0x800080,
transparent: true,
opacity: 0.5,
});
this.addShellOnScene(b, {
color: 0xfff44f,
transparent: true,
opacity: 0.5,
});
//this.addShellOnScene(a);
//this.addShellOnScene(b);
const result = BREPBool.subtract(a, b);
this.addShellOnScene(result);
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();
};
App.prototype.raytracing = function() {
let box = createBox(800, 800, 800);
this.viewer.workGroup.add(box.toThreeMesh());
let win = $('<div><canvas width="1000" height="1000" /></div>')
.css({
'position': 'absolute',
'width': '800px',
'height': '800px',
'left': '20px',
'top': '20px',
'z-order': 999999
});
win.appendTo($('body'));
const canvas = win.find('canvas')[0];
console.log(canvas);
const ctx = canvas.getContext('2d');
// ctx.fillStyle = 'green';
// ctx.fillRect(10, 10, 100, 100);
let sphere = createSphere(new Vector(), 600);
let sphere2 = sdfTransform(sphere, new Matrix3().translate(-150, 300, 0));
let solid = sdfSolid(box);
let solid2 = sdfTransform(sphere, new Matrix3().translate(-150, 300, 0));
let result = sdfSubtract(sphere, sphere2);
let solid3 = sdfSubtract(solid, solid2);
let width = this.viewer.container.clientWidth;
let height = this.viewer.container.clientHeight;
rayMarchOntoCanvas(solid3, this.viewer.camera, width, height, canvas, 2000, 10);
this.viewer.render();
}
App.prototype.processHints = function() {
let id = window.location.hash.substring(1);
if (!id) {

View file

@ -6,6 +6,7 @@ import {SelectionManager, SketchSelectionManager, EdgeSelectionManager} from './
function Viewer(bus, container) {
this.bus = bus;
this.container = container;
function aspect() {
return container.clientWidth / container.clientHeight;
}

View file

@ -4,6 +4,7 @@ export class Line extends Curve {
constructor(p0, v) {
super();
throw 'only nurbs for now'
this.p0 = p0;
this.v = v;
this._pointsCache = new Map();

View file

@ -2,10 +2,14 @@ import verb from 'verb-nurbs'
import {Matrix3} from '../../../math/l3space'
import * as math from '../../../math/math'
import {Point} from '../point'
import {Surface} from "../surface";
import Vector from "../../../math/vector";
import {Curve} from "../curve";
export class NurbsCurve {
export class NurbsCurve extends Curve {
constructor(verbCurve) {
super();
this.verb = verbCurve;
}
@ -50,18 +54,30 @@ export class NurbsCurve {
tangentAtPoint(point) {
return new Point().set3(this.verb.tangent(this.verb.closestParam(point.data())));
}
tangentAtParam(param) {
return new Point().set3(this.verb.tangent(param ));
}
closestDistanceToPoint(point) {
const closest = this.verb.closestPoint(point.data());
return math.distance3(point.x, point.y, point.z, closest[0], closest[1], closest[2]);
}
tangent(point) {
return new Point().set3(this.verb.tangent( this.verb.closestParam(point.data() )));
split(point) {
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());
}
intersect(other, tolerance) {
return verb.geom.Intersect.curves(this.verb, other.verb, tolerance).map(i => new Point().set3(i.point0));
point(u) {
return new Point().set3(this.verb.point(u));
}
static createByPoints(points, degeree) {
@ -78,37 +94,36 @@ NurbsCurve.prototype.createLinearNurbs = function(a, b) {
return NurbsCurve.createLinearNurbs(a, b);
};
export class NurbsSurface {
export class NurbsSurface extends Surface {
constructor(verbSurface) {
super();
this.verb = verbSurface;
}
isCognateCurve(curve) {
return curve.constructor.name == 'NurbsCurve';
this.inverted = false;
}
toNurbs() {
return this;
}
coplanarUnsignedForSameClass(other, tol) {
//throw 'not implemented'
return false;
normal(point) {
let uv = this.verb.closestParam(point.data());
let normal = new Vector().set3(this.verb.normal(uv[0], uv[1]));
if (this.inverted) {
normal._negate();
}
return normal;
}
intersectForSameClass(other, tol) {
const curves = verb.geom.Intersect.surfaces(this.verb, other.verb, tol);
return curves.map(curve => new NurbsCurve(curve));
let inverted = this.inverted !== other.inverted;
return curves.map(curve => new NurbsCurve(inverted ? curve.reverse() : curve));
}
classifyCognateCurve(line, tol) {
const parallel = math.areEqual(line.v.dot(this.normal), 0, tol);
const pointOnPlane = math.areEqual(this.normal.dot(line.p0), this.w, tol);
return {
hit: !parallel || pointOnPlane,
parallel
}
invert() {
let inverted = new NurbsSurface(this.verb);
inverted.inverted = !this.inverted;
return inverted;
}
}

View file

@ -8,6 +8,7 @@ export class Plane extends Surface {
constructor(normal, w) {
super();
throw 'only nurbs for now'
this.normal = normal;
this.w = w;
}

View file

@ -5,19 +5,6 @@ export class Surface {
}
//--------------------------------------------------------------------------------------------------------------------
classifyCognateCurve(curve, tol) {
throw 'not implemented';
}
classifyCurve(curve, tol) {
if (this.isCognateCurve(curve)) {
return this.classifyCognateCurve(curve, tol)
}
return this.toNurbs().classifyCognateCurve(curve.toNurbs(), tol);
};
//--------------------------------------------------------------------------------------------------------------------
intersectForSameClass() {
@ -33,19 +20,6 @@ export class Surface {
//--------------------------------------------------------------------------------------------------------------------
coplanarUnsignedForSameClass(other, tol) {
throw 'not implemented';
}
coplanarUnsigned(other, tol) {
if (this.isSameClass(other)) {
return this.coplanarUnsignedForSameClass(other, tol)
}
return this.toNurbs().coplanarUnsignedForSameClass(other.toNurbs());
}
//--------------------------------------------------------------------------------------------------------------------
equalsForSameClass(other, tol) {
throw 'not implemented';
}
@ -59,16 +33,16 @@ export class Surface {
//--------------------------------------------------------------------------------------------------------------------
normal(point) {
throw 'not implemented';
}
toNurbs() {
throw 'not implemented';
}
isSameClass(other) {
return this.constructor.name == other.constructor.name;
}
isCognateCurve(curve) {
return false;
return this.constructor.name === other.constructor.name;
}
}
Surface.prototype.isPlane = false;

File diff suppressed because it is too large Load diff

View file

@ -2,106 +2,46 @@ import {TopoObject} from './topo-object'
export class Edge extends TopoObject {
constructor(curve) {
constructor(curve, a, b) {
super();
this.curve = curve;
this.halfEdge1 = null;
this.halfEdge2 = null;
this.halfEdge1 = new HalfEdge(this, false, a, b);
this.halfEdge2 = new HalfEdge(this, true, b, a);
}
link(halfEdge1, halfEdge2) {
halfEdge1.edge = this;
halfEdge2.edge = this;
this.halfEdge1 = halfEdge1;
this.halfEdge2 = halfEdge2;
invert() {
const t = this.halfEdge1;
this.halfEdge1 = this.halfEdge2;
this.halfEdge2 = t;
this.halfEdge1.inverted = false;
this.halfEdge2.inverted = true;
this.curve = this.curve.invert();
}
}
export class HalfEdge extends TopoObject {
class HalfEdge extends TopoObject {
constructor() {
constructor(edge, inverted, a, b) {
super();
this.edge = null;
this.vertexA = null;
this.vertexB = null;
this.edge = edge;
this.inverted = inverted;
this.vertexA = a;
this.vertexB = b;
this.loop = null;
this.next = null;
this.prev = null;
}
static create(a, b, loop, edge) {
const e = new HalfEdge().setAB(a, b);
e.loop = loop;
e.edge = edge;
return e;
}
setAB(a, b) {
this.vertexA = a;
this.vertexB = b;
return this;
}
twin() {
return this.edge.halfEdge1 == this ? this.edge.halfEdge2 : this.edge.halfEdge1;
return this.edge.halfEdge1 === this ? this.edge.halfEdge2 : this.edge.halfEdge1;
}
splitHalfEdge(vertex) {
const h = this;
const newEdge = new HalfEdge();
newEdge.vertexA = vertex;
newEdge.vertexB = h.vertexB;
h.vertexB = newEdge.vertexA;
h.vertexA.edges.add(newEdge);
h.vertexA.edges.delete(h);
vertex.edges.add(newEdge);
return newEdge;
}
split(vertex) {
const orig = this;
const twin = orig.twin();
if (orig.vertexA == vertex || orig.vertexB == vertex) {
return;
tangent(point) {
let tangent = this.edge.curve.tangentAtPoint(point);
tangent._normalize();
if (this.inverted) {
tangent._negate();
}
const newOrig = orig.splitHalfEdge(vertex);
const newTwin = twin.splitHalfEdge(vertex);
orig.edge.link(orig, newTwin);
new Edge(orig.edge.curve).link(twin, newOrig);
orig.loop.halfEdges.splice(orig.loop.halfEdges.indexOf(orig) + 1, 0, newOrig);
twin.loop.halfEdges.splice(twin.loop.halfEdges.indexOf(twin) + 1, 0, newTwin);
function insertToLL(orig, newOrig) {
orig.next.prev = newOrig
newOrig.next = orig.next;
orig.next = newOrig;
newOrig.prev = orig;
}
insertToLL(orig, newOrig);
insertToLL(twin, newTwin);
newOrig.loop = orig.loop;
newTwin.loop = twin.loop;
return tangent;
}
}
HalfEdge.fromVertices = function(a, b, curve) {
const halfEdge1 = new HalfEdge();
const halfEdge2 = new HalfEdge();
halfEdge1.setAB(a, b);
halfEdge2.setAB(b, a);
new Edge(curve).link(halfEdge1, halfEdge2);
return halfEdge1;
};

View file

@ -15,7 +15,7 @@ export class Face extends TopoObject {
}
export function* loopsGenerator(face) {
if (face.outerLoop != null) {
if (face.outerLoop !== null) {
yield face.outerLoop;
}
for (let innerLoop of face.innerLoops) {

View file

@ -16,7 +16,28 @@ const CASE = {
app.addShellOnScene(result);
env.done();
}));
},
/**
* https://github.com/xibyte/jsketcher/issues/47
*/
testFacesAreInSamePlane_BUG_47: function(env) {
test.modeller(env.test((win, app) => {
const mat = new Matrix3();
const m = mat.translate(0, 0, 10);
const box1 = app.TPI.brep.primitives.box(100, 100, 100, undefined);
const box2 = app.TPI.brep.primitives.box(100, 100, 100, mat);
const shell = app.TPI.brep.bool.union(box1, box2);
// app.addShellOnScene(box1);
// app.addShellOnScene(box2);
app.addShellOnScene(shell);
env.done();
}));
}
};
def('simple.union');