mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-07 17:04:58 +01:00
PIP for NURBS
This commit is contained in:
parent
cad474b100
commit
13f2f8f6ee
11 changed files with 415 additions and 78 deletions
|
|
@ -24,9 +24,14 @@ function addGlobalDebugActions(app) {
|
||||||
app.viewer.render();
|
app.viewer.render();
|
||||||
},
|
},
|
||||||
AddSegment: (a, b, color) => {
|
AddSegment: (a, b, color) => {
|
||||||
debugGroup.add(createLine(a, b, color));
|
__DEBUG__.AddPolyLine([a, b], color);
|
||||||
debugGroup.add(createPoint(a, 0x000088));
|
},
|
||||||
debugGroup.add(createPoint(b, 0x880000));
|
AddPolyLine: (points, color) => {
|
||||||
|
for (let i = 1; i < points.length; ++i) {
|
||||||
|
debugGroup.add(createLine(points[i - 1], points[i], color));
|
||||||
|
}
|
||||||
|
debugGroup.add(createPoint(points[0], 0x000088));
|
||||||
|
debugGroup.add(createPoint(points[points.length - 1], 0x880000));
|
||||||
app.viewer.render();
|
app.viewer.render();
|
||||||
},
|
},
|
||||||
AddPoint: (coordinates, or, vector, andColorAtTheEnd) => {
|
AddPoint: (coordinates, or, vector, andColorAtTheEnd) => {
|
||||||
|
|
@ -55,7 +60,12 @@ function addGlobalDebugActions(app) {
|
||||||
app.viewer.render();
|
app.viewer.render();
|
||||||
},
|
},
|
||||||
AddHalfEdge: (he, color) => {
|
AddHalfEdge: (he, color) => {
|
||||||
window.__DEBUG__.AddSegment(he.vertexA.point, he.vertexB.point, color);
|
const points = [he.vertexA.point];
|
||||||
|
if (he.edge && he.edge.curve) {
|
||||||
|
he.edge.curve.approximate(10, he.vertexA.point, he.vertexB.point, points);
|
||||||
|
}
|
||||||
|
points.push(he.vertexB.point);
|
||||||
|
window.__DEBUG__.AddPolyLine(points, color);
|
||||||
},
|
},
|
||||||
AddFace: (face, color) => {
|
AddFace: (face, color) => {
|
||||||
for (let e of face.edges) __DEBUG__.AddHalfEdge(e, color);
|
for (let e of face.edges) __DEBUG__.AddHalfEdge(e, color);
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,30 @@ export function triangulateToThree(shell, geom) {
|
||||||
}
|
}
|
||||||
//view.setFaceColor(sceneFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null);
|
//view.setFaceColor(sceneFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null);
|
||||||
}
|
}
|
||||||
|
} else if (brepFace.surface.constructor.name == 'NurbsSurface1') {
|
||||||
|
const off = geom.vertices.length;
|
||||||
|
const contours = [];
|
||||||
|
|
||||||
|
for (let loop of brepFace.loops) {
|
||||||
|
const points = [];
|
||||||
|
for (let he of loop.halfEdges) {
|
||||||
|
points.push(he.vertexA.point);
|
||||||
|
he.edge.curve.approximate(10, he.vertexA.point, he.vertexB.point, points);
|
||||||
|
}
|
||||||
|
const verb = brepFace.surface.verb;
|
||||||
|
const uvs = points.map(point => verb.closestParam(point.data()));
|
||||||
|
uvs.forEach(uv => uv.push(0)); // add z coord
|
||||||
|
contours.push(uvs);
|
||||||
|
//....TODO
|
||||||
|
for (let i = 0; i < tessedUVs.length; i += 3 ) {
|
||||||
|
var a = new Vector().set3(tessedUVs[i]);
|
||||||
|
var b = new Vector().set3(tessedUVs[i + 1]);
|
||||||
|
var c = new Vector().set3(tessedUVs[i + 2]);
|
||||||
|
const normalOrNormals = normalOfCCWSeq([a, b, c]).three();
|
||||||
|
const face = new THREE.Face3(off, off + 1, off + 2, normalOrNormals);
|
||||||
|
addFace(face);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (brepFace.surface.constructor.name == 'NurbsSurface') {
|
} else if (brepFace.surface.constructor.name == 'NurbsSurface') {
|
||||||
const off = geom.vertices.length;
|
const off = geom.vertices.length;
|
||||||
const tess = brepFace.surface.verb.tessellate({maxDepth: 3});
|
const tess = brepFace.surface.verb.tessellate({maxDepth: 3});
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import {Face} from '../brep/topo/face';
|
||||||
import {Shell} from '../brep/topo/shell';
|
import {Shell} from '../brep/topo/shell';
|
||||||
import {Vertex} from '../brep/topo/vertex';
|
import {Vertex} from '../brep/topo/vertex';
|
||||||
import {Point} from '../brep/geom/point';
|
import {Point} from '../brep/geom/point';
|
||||||
|
import {NurbsCurve} from '../brep/geom/impl/nurbs';
|
||||||
|
import {Plane} from '../brep/geom/impl/plane';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
brep: {
|
brep: {
|
||||||
|
|
@ -17,7 +19,7 @@ export default {
|
||||||
bool: BREPBool,
|
bool: BREPBool,
|
||||||
validator: BREPValidator,
|
validator: BREPValidator,
|
||||||
geom: {
|
geom: {
|
||||||
Point
|
Point, NurbsCurve, Plane
|
||||||
},
|
},
|
||||||
topo: {
|
topo: {
|
||||||
HalfEdge, Edge, Loop, Face, Shell, Vertex
|
HalfEdge, Edge, Loop, Face, Shell, Vertex
|
||||||
|
|
|
||||||
|
|
@ -186,12 +186,14 @@ export function invertLoop(loop) {
|
||||||
linkSegments(loop.halfEdges);
|
linkSegments(loop.halfEdges);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createPlaneLoop(vertices) {
|
export function createPlaneLoop(vertices, curves) {
|
||||||
|
|
||||||
const loop = new Loop();
|
const loop = new Loop();
|
||||||
|
|
||||||
iterateSegments(vertices, (a, b) => {
|
iterateSegments(vertices, (a, b, i) => {
|
||||||
createHalfEdge(loop, a, b)
|
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);
|
linkSegments(loop.halfEdges);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
export class Curve {
|
export class Curve {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isLine = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intersectCurve(curve) {
|
intersectCurve(curve) {
|
||||||
|
|
@ -20,7 +19,7 @@ export class Curve {
|
||||||
approximate(resolution, from, to, path) {
|
approximate(resolution, from, to, path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Curve.prototype.isLine = false;
|
||||||
|
|
||||||
export class CompositeCurve {
|
export class CompositeCurve {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ export class Line extends Curve {
|
||||||
|
|
||||||
constructor(p0, v) {
|
constructor(p0, v) {
|
||||||
super();
|
super();
|
||||||
this.isLine = true;
|
|
||||||
this.p0 = p0;
|
this.p0 = p0;
|
||||||
this.v = v;
|
this.v = v;
|
||||||
this._pointsCache = new Map();
|
this._pointsCache = new Map();
|
||||||
|
|
@ -56,6 +55,8 @@ export class Line extends Curve {
|
||||||
offset() {};
|
offset() {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Line.prototype.isLine = true;
|
||||||
|
|
||||||
Line.fromTwoPlanesIntersection = function(plane1, plane2) {
|
Line.fromTwoPlanesIntersection = function(plane1, plane2) {
|
||||||
const n1 = plane1.normal;
|
const n1 = plane1.normal;
|
||||||
const n2 = plane2.normal;
|
const n2 = plane2.normal;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import verb from 'verb-nurbs'
|
import verb from 'verb-nurbs'
|
||||||
import {Matrix3} from '../../../math/l3space'
|
import {Matrix3} from '../../../math/l3space'
|
||||||
import Vector from '../../../math/vector'
|
import * as math from '../../../math/math'
|
||||||
|
import {Point} from '../point'
|
||||||
|
|
||||||
export class NurbsCurve {
|
export class NurbsCurve {
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ export class NurbsCurve {
|
||||||
const step = this.verb.paramAtLength(length / resolution);
|
const step = this.verb.paramAtLength(length / resolution);
|
||||||
u += step;
|
u += step;
|
||||||
for (;u < endU; u += step) {
|
for (;u < endU; u += step) {
|
||||||
out.push(new Vector().set3(this.verb.point(u)));
|
out.push(new Point().set3(this.verb.point(u)));
|
||||||
}
|
}
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
for (let i = off, j = out.length - 1; i != j; ++i, --j) {
|
for (let i = off, j = out.length - 1; i != j; ++i, --j) {
|
||||||
|
|
@ -41,8 +42,48 @@ export class NurbsCurve {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return new Point().set3(this.verb.tangent(this.verb.closestParam(point.data())));
|
||||||
|
}
|
||||||
|
|
||||||
|
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() )));
|
||||||
|
}
|
||||||
|
|
||||||
|
intersect(other, tolerance) {
|
||||||
|
return verb.geom.Intersect.curves(this.verb, other.verb, tolerance).map(i => new Point().set3(i.point0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static createByPoints(points, degeree) {
|
||||||
|
points = points.map(p => p.data());
|
||||||
|
return new NurbsCurve(new verb.geom.NurbsCurve.byPoints(points, degeree));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NurbsCurve.prototype.createLinearNurbs = function(a, b) {
|
||||||
|
return new NurbsCurve(new verb.geom.Line(a.data(), b.data()));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export class NurbsSurface {
|
export class NurbsSurface {
|
||||||
|
|
||||||
constructor(verbSurface) {
|
constructor(verbSurface) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import {Surface} from '../surface'
|
import {Surface} from '../surface'
|
||||||
|
import {Point} from '../point'
|
||||||
import {Line} from './line'
|
import {Line} from './line'
|
||||||
import {Matrix3, AXIS, BasisForPlane} from '../../../math/l3space'
|
import {Matrix3, AXIS, BasisForPlane} from '../../../math/l3space'
|
||||||
import * as math from '../../../math/math'
|
import * as math from '../../../math/math'
|
||||||
|
|
@ -38,11 +39,17 @@ export class Plane extends Surface {
|
||||||
}
|
}
|
||||||
|
|
||||||
get2DTransformation() {
|
get2DTransformation() {
|
||||||
return this.get3DTransformation().invert();
|
if (!this.__2dTr) {
|
||||||
|
this.__2dTr = this.get3DTransformation().invert();
|
||||||
|
}
|
||||||
|
return this.__2dTr;
|
||||||
}
|
}
|
||||||
|
|
||||||
get3DTransformation() {
|
get3DTransformation() {
|
||||||
return new Matrix3().setBasis(this.basis());
|
if (!this.__3dTr) {
|
||||||
|
this.__3dTr = new Matrix3().setBasis(this.basis());
|
||||||
|
}
|
||||||
|
return this.__3dTr;
|
||||||
}
|
}
|
||||||
|
|
||||||
coplanarUnsigned(other, tol) {
|
coplanarUnsigned(other, tol) {
|
||||||
|
|
@ -58,8 +65,27 @@ export class Plane extends Surface {
|
||||||
}
|
}
|
||||||
|
|
||||||
toParametricForm() {
|
toParametricForm() {
|
||||||
const basis = BasisForPlane(this.normal);
|
if (!this.__parametricForm) {
|
||||||
return new ParametricPlane(this.normal.multiply(this.w), basis.x, basis.y);
|
const basis = BasisForPlane(this.normal);
|
||||||
|
this.__parametricForm = new ParametricPlane(this.normal.multiply(this.w), basis.x, basis.y);
|
||||||
|
}
|
||||||
|
return this.__parametricForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
toUV(point) {
|
||||||
|
return this.get2DTransformation().apply(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
fromUV(u, v) {
|
||||||
|
return this.get3DTransformation()._apply(new Point(u, v, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
domainU() {
|
||||||
|
return [Number.MIN_VALUE, Number.MAX_VALUE];
|
||||||
|
}
|
||||||
|
|
||||||
|
domainV() {
|
||||||
|
return [Number.MIN_VALUE, Number.MAX_VALUE];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -667,7 +667,6 @@ export function loopsToFaces(originFace, loops, out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNestedLoops(face, brepLoops) {
|
function getNestedLoops(face, brepLoops) {
|
||||||
const tr = face.surface.get2DTransformation();
|
|
||||||
function NestedLoop(loop) {
|
function NestedLoop(loop) {
|
||||||
this.loop = loop;
|
this.loop = loop;
|
||||||
this.nesting = [];
|
this.nesting = [];
|
||||||
|
|
@ -677,7 +676,7 @@ function getNestedLoops(face, brepLoops) {
|
||||||
const loops = brepLoops.map(loop => new NestedLoop(loop));
|
const loops = brepLoops.map(loop => new NestedLoop(loop));
|
||||||
function contains(loop, other) {
|
function contains(loop, other) {
|
||||||
for (let point of other.asPolygon()) {
|
for (let point of other.asPolygon()) {
|
||||||
if (!classifyPointInsideLoop(tr.apply(point), loop, tr).inside) {
|
if (!classifyPointInsideLoop(point, loop, face.surface).inside) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1076,9 +1075,9 @@ function classifyPointToFace(point, face) {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const tr = face.surface.get2DTransformation();
|
|
||||||
const point2d = tr.apply(point);
|
const uvPt = face.surface.toUV(point);
|
||||||
const outer = classifyPointInsideLoop(point2d, face.outerLoop, tr);
|
const outer = classifyPointInsideLoop(point, face.outerLoop, face.surface, uvPt);
|
||||||
|
|
||||||
if (outer.inside) {
|
if (outer.inside) {
|
||||||
if (outer.vertex || outer.edge) {
|
if (outer.vertex || outer.edge) {
|
||||||
|
|
@ -1087,7 +1086,7 @@ function classifyPointToFace(point, face) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let innerLoop of face.innerLoops) {
|
for (let innerLoop of face.innerLoops) {
|
||||||
const inner = classifyPointInsideLoop(point2d, innerLoop, tr);
|
const inner = classifyPointInsideLoop(point, innerLoop, face.surface, uvPt);
|
||||||
if (inner.vertex || inner.edge) {
|
if (inner.vertex || inner.edge) {
|
||||||
return inner;
|
return inner;
|
||||||
}
|
}
|
||||||
|
|
@ -1209,7 +1208,7 @@ class FaceSolveData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function classifyPointInsideLoop( inPt, loop, tr ) {
|
export function classifyPointInsideLoop( pt, loop, surface, uvPt ) {
|
||||||
|
|
||||||
function VertexResult(vertex) {
|
function VertexResult(vertex) {
|
||||||
this.inside = true;
|
this.inside = true;
|
||||||
|
|
@ -1221,20 +1220,37 @@ export function classifyPointInsideLoop( inPt, loop, tr ) {
|
||||||
this.edge = edge;
|
this.edge = edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
const _2dCoords = new Map();
|
if (!uvPt) {
|
||||||
|
uvPt = surface.toUV(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLine(edge) {
|
||||||
|
return !edge.edge || !edge.edge.curve || edge.edge.curve.isLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uvCoords = new Map();
|
||||||
for( let edge of loop.halfEdges ) {
|
for( let edge of loop.halfEdges ) {
|
||||||
const p = tr.apply(edge.vertexA.point);
|
const uv = surface.toUV(edge.vertexA.point);
|
||||||
if (math.areEqual(inPt.y, p.y, TOLERANCE) && math.areEqual(inPt.x, p.x, TOLERANCE)) {
|
if (math.areEqual(uvPt.y, uv.y, TOLERANCE) && math.areEqual(uvPt.x, uv.x, TOLERANCE)) {
|
||||||
return new VertexResult(edge.vertexA);
|
return new VertexResult(edge.vertexA);
|
||||||
}
|
}
|
||||||
_2dCoords.set(edge.vertexA, p);
|
uvCoords.set(edge.vertexA, uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
const grads = [];
|
const grads = [];
|
||||||
for( let edge of loop.halfEdges ) {
|
for( let edge of loop.halfEdges ) {
|
||||||
const a = _2dCoords.get(edge.vertexA);
|
const a = uvCoords.get(edge.vertexA);
|
||||||
const b = _2dCoords.get(edge.vertexB);
|
const b = uvCoords.get(edge.vertexB);
|
||||||
const dy = b.y - a.y;
|
let dy;
|
||||||
|
if (isLine(edge)) {
|
||||||
|
dy = b.y - a.y;
|
||||||
|
} else {
|
||||||
|
const tangent = edge.edge.curve.tangent(edge.vertexA.point);
|
||||||
|
dy = surface.toUV(tangent).y;
|
||||||
|
if (edge.edge.invertedToCurve) {
|
||||||
|
dy *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (math.areEqual(dy, 0, TOLERANCE)) {
|
if (math.areEqual(dy, 0, TOLERANCE)) {
|
||||||
grads.push(0)
|
grads.push(0)
|
||||||
} else if (dy > 0) {
|
} else if (dy > 0) {
|
||||||
|
|
@ -1264,6 +1280,7 @@ export function classifyPointInsideLoop( inPt, loop, tr ) {
|
||||||
|
|
||||||
const skip = new Set();
|
const skip = new Set();
|
||||||
|
|
||||||
|
let ray = null;
|
||||||
let inside = false;
|
let inside = false;
|
||||||
for( let i = 0; i < loop.halfEdges.length; ++i) {
|
for( let i = 0; i < loop.halfEdges.length; ++i) {
|
||||||
|
|
||||||
|
|
@ -1271,11 +1288,11 @@ export function classifyPointInsideLoop( inPt, loop, tr ) {
|
||||||
|
|
||||||
var shouldBeSkipped = skip.has(edge.vertexA) || skip.has(edge.vertexB);
|
var shouldBeSkipped = skip.has(edge.vertexA) || skip.has(edge.vertexB);
|
||||||
|
|
||||||
const a = _2dCoords.get(edge.vertexA);
|
const a = uvCoords.get(edge.vertexA);
|
||||||
const b = _2dCoords.get(edge.vertexB);
|
const b = uvCoords.get(edge.vertexB);
|
||||||
|
|
||||||
const aEq = math.areEqual(inPt.y, a.y, TOLERANCE);
|
const aEq = math.areEqual(uvPt.y, a.y, TOLERANCE);
|
||||||
const bEq = math.areEqual(inPt.y, b.y, TOLERANCE);
|
const bEq = math.areEqual(uvPt.y, b.y, TOLERANCE);
|
||||||
|
|
||||||
if (aEq) {
|
if (aEq) {
|
||||||
skip.add(edge.vertexA);
|
skip.add(edge.vertexA);
|
||||||
|
|
@ -1287,50 +1304,98 @@ export function classifyPointInsideLoop( inPt, loop, tr ) {
|
||||||
if (math.areVectorsEqual(a, b, TOLERANCE)) {
|
if (math.areVectorsEqual(a, b, TOLERANCE)) {
|
||||||
console.error('unable to classify invalid polygon');
|
console.error('unable to classify invalid polygon');
|
||||||
}
|
}
|
||||||
|
|
||||||
var edgeLowPt = a;
|
|
||||||
var edgeHighPt = b;
|
|
||||||
|
|
||||||
var edgeDx = edgeHighPt.x - edgeLowPt.x;
|
if (isLine(edge)) {
|
||||||
var edgeDy = edgeHighPt.y - edgeLowPt.y;
|
let edgeLowPt = a;
|
||||||
|
let edgeHighPt = b;
|
||||||
if (aEq && bEq) {
|
|
||||||
if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
|
let edgeDx = edgeHighPt.x - edgeLowPt.x;
|
||||||
( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) {
|
let edgeDy = edgeHighPt.y - edgeLowPt.y;
|
||||||
return new EdgeResult(edge);
|
|
||||||
} else {
|
if (aEq && bEq) {
|
||||||
|
if ( ( ( edgeHighPt.x <= uvPt.x ) && ( uvPt.x <= edgeLowPt.x ) ) ||
|
||||||
|
( ( edgeLowPt.x <= uvPt.x ) && ( uvPt.x <= edgeHighPt.x ) ) ) {
|
||||||
|
return new EdgeResult(edge);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldBeSkipped) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if ( edgeDy < 0 ) {
|
||||||
if (shouldBeSkipped) {
|
edgeLowPt = b; edgeDx = - edgeDx;
|
||||||
continue;
|
edgeHighPt = a; edgeDy = - edgeDy;
|
||||||
}
|
}
|
||||||
|
if (!aEq && !bEq && ( uvPt.y < edgeLowPt.y || uvPt.y > edgeHighPt.y ) ) {
|
||||||
if ( edgeDy < 0 ) {
|
|
||||||
edgeLowPt = b; edgeDx = - edgeDx;
|
|
||||||
edgeHighPt = a; edgeDy = - edgeDy;
|
|
||||||
}
|
|
||||||
if (!aEq && !bEq && ( inPt.y < edgeLowPt.y || inPt.y > edgeHighPt.y ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bEq) {
|
|
||||||
if (grads[i] * nextGrad(i) < 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (aEq) {
|
|
||||||
if (grads[i] * prevGrad(i) < 0) {
|
if (bEq) {
|
||||||
|
if (grads[i] * nextGrad(i) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (aEq) {
|
||||||
|
if (grads[i] * prevGrad(i) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let perpEdge = edgeDx * (uvPt.y - edgeLowPt.y) - edgeDy * (uvPt.x - edgeLowPt.x);
|
||||||
|
if ( math.areEqual(perpEdge, 0, TOLERANCE) ) return new EdgeResult(edge); // uvPt is on contour ?
|
||||||
|
if ( perpEdge < 0 ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
inside = ! inside; // true intersection left of uvPt
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (aEq && bEq) {
|
||||||
|
if (math.areEqual(edge.edge.curve.closestDistanceToPoint(pt), 0, TOLERANCE)) {
|
||||||
|
return new EdgeResult(edge);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let perpEdge = edgeDx * (inPt.y - edgeLowPt.y) - edgeDy * (inPt.x - edgeLowPt.x);
|
if (shouldBeSkipped) {
|
||||||
if ( math.areEqual(perpEdge, 0, TOLERANCE) ) return new EdgeResult(edge); // inPt is on contour ?
|
continue;
|
||||||
if ( perpEdge < 0 ) {
|
}
|
||||||
continue;
|
|
||||||
|
if (bEq) {
|
||||||
|
if (grads[i] * nextGrad(i) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (aEq) {
|
||||||
|
if (grads[i] * prevGrad(i) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (math.areEqual(edge.edge.curve.closestDistanceToPoint(pt), 0, TOLERANCE)) {
|
||||||
|
return new EdgeResult(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ray == null) {
|
||||||
|
|
||||||
|
let rayEnd = pt.copy();
|
||||||
|
//fixme!!
|
||||||
|
rayEnd.x = 1000000;//surface.fromUV(surface.domainU()[1]).x;
|
||||||
|
ray = edge.edge.curve.createLinearNurbs(pt, rayEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hits = edge.edge.curve.intersect(ray);
|
||||||
|
|
||||||
|
for (let hit of hits) {
|
||||||
|
//if ray just touches
|
||||||
|
const onlyTouches = math.areEqual(edge.edge.curve.tangent(hit).normalize().y, 0, TOLERANCE);
|
||||||
|
if (!onlyTouches) {
|
||||||
|
inside = ! inside;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
inside = ! inside; // true intersection left of inPt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {inside};
|
return {inside};
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ Vector.prototype.set = function(x, y, z) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector.prototype.set3 = function(data) {
|
Vector.prototype.set3 = function(data) {
|
||||||
this.x = data[0];
|
this.x = data[0] || 0;
|
||||||
this.y = data[1];
|
this.y = data[1] || 0;
|
||||||
this.z = data[2];
|
this.z = data[2] || 0;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import * as test from '../test'
|
import * as test from '../test'
|
||||||
import {Matrix3} from '../../app/math/l3space'
|
import {AXIS} from '../../app/math/l3space'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
|
|
@ -639,6 +639,167 @@ export default {
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* o--------o
|
||||||
|
* | \
|
||||||
|
* *--> | )
|
||||||
|
* | /
|
||||||
|
* o--------o
|
||||||
|
*/
|
||||||
|
testPIPClassification1NurbsOut: function (env) {
|
||||||
|
test.modeller(env.test((win, app) => {
|
||||||
|
const loop = createLoop(app.TPI,[
|
||||||
|
[100, 100],
|
||||||
|
[500, 100],
|
||||||
|
[500, 500],
|
||||||
|
[100, 500]
|
||||||
|
], [,['nurbs', [500, 100], [700, 250], [500, 500] ]]);
|
||||||
|
const result = classify(app, win, loop, [-300, 300]);
|
||||||
|
env.assertFalse(result.inside);
|
||||||
|
env.done();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* o--------o
|
||||||
|
* | \
|
||||||
|
* *--> | )
|
||||||
|
* | /
|
||||||
|
* o--------o
|
||||||
|
*/
|
||||||
|
testPIPClassification1NurbsIn: function (env) {
|
||||||
|
test.modeller(env.test((win, app) => {
|
||||||
|
const loop = createLoop(app.TPI,[
|
||||||
|
[100, 100],
|
||||||
|
[500, 100],
|
||||||
|
[500, 500],
|
||||||
|
[100, 500]
|
||||||
|
], [,['nurbs', [500, 100], [700, 250], [500, 500] ]]);
|
||||||
|
const result = classify(app, win, loop, [300, 300]);
|
||||||
|
env.assertTrue(result.inside);
|
||||||
|
env.done();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* *-->
|
||||||
|
*
|
||||||
|
* . ' .
|
||||||
|
* / \
|
||||||
|
* o o
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* o--------o
|
||||||
|
*/
|
||||||
|
testPIPClassificationCloseToNurbsOut: function (env) {
|
||||||
|
test.modeller(env.test((win, app) => {
|
||||||
|
const loop = createLoop(app.TPI,[
|
||||||
|
[100, 100],
|
||||||
|
[500, 100],
|
||||||
|
[500, 500],
|
||||||
|
[100, 500]
|
||||||
|
], [,,['nurbs', [500, 500], [250, 750], [100, 500] ]]);
|
||||||
|
const result = classify(app, win, loop, [-300, 780]);
|
||||||
|
env.assertFalse(result.inside);
|
||||||
|
env.done();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* *-->
|
||||||
|
* . ' .
|
||||||
|
* / \
|
||||||
|
* o o
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* o--------o
|
||||||
|
*/
|
||||||
|
testPIPClassificationTouchesNurbsOut: function (env) {
|
||||||
|
test.modeller(env.test((win, app) => {
|
||||||
|
const loop = createLoop(app.TPI,[
|
||||||
|
[100, 100],
|
||||||
|
[500, 100],
|
||||||
|
[500, 500],
|
||||||
|
[100, 500]
|
||||||
|
], [,,['nurbs', [500, 500], [250, 750], [100, 500] ]]);
|
||||||
|
const result = classify(app, win, loop, [-300, 750]);
|
||||||
|
env.assertFalse(result.inside);
|
||||||
|
env.done();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* *--> . ' .
|
||||||
|
* / \
|
||||||
|
* o o
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* o--------o
|
||||||
|
*/
|
||||||
|
testPIPClassificationThroughNurbsOut: function (env) {
|
||||||
|
test.modeller(env.test((win, app) => {
|
||||||
|
const loop = createLoop(app.TPI,[
|
||||||
|
[100, 100],
|
||||||
|
[500, 100],
|
||||||
|
[500, 500],
|
||||||
|
[100, 500]
|
||||||
|
], [,,['nurbs', [500, 500], [250, 750], [100, 500] ]]);
|
||||||
|
const result = classify(app, win, loop, [-300, 650]);
|
||||||
|
env.assertFalse(result.inside);
|
||||||
|
env.done();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* . ' .
|
||||||
|
* / *-> \
|
||||||
|
* o o
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* o--------o
|
||||||
|
*/
|
||||||
|
testPIPClassificationCrossesNurbsIn: function (env) {
|
||||||
|
test.modeller(env.test((win, app) => {
|
||||||
|
const loop = createLoop(app.TPI,[
|
||||||
|
[100, 100],
|
||||||
|
[500, 100],
|
||||||
|
[500, 500],
|
||||||
|
[100, 500]
|
||||||
|
], [,,['nurbs', [500, 500], [250, 750], [100, 500] ]]);
|
||||||
|
const result = classify(app, win, loop, [300, 650]);
|
||||||
|
env.assertTrue(result.inside);
|
||||||
|
env.done();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* o--------o
|
||||||
|
* \ \
|
||||||
|
* *--> ) )
|
||||||
|
* / /
|
||||||
|
* o--------o
|
||||||
|
*/
|
||||||
|
testPIPClassification2NurbsOut: function (env) {
|
||||||
|
test.modeller(env.test((win, app) => {
|
||||||
|
const loop = createLoop(app.TPI,[
|
||||||
|
[100, 100],
|
||||||
|
[500, 100],
|
||||||
|
[500, 500],
|
||||||
|
[100, 500]
|
||||||
|
], [,['nurbs', [500, 100], [700, 250], [500, 500]], , ['nurbs', [100, 500], [250, 250], [100, 100]]]);
|
||||||
|
const result = classify(app, win, loop, [-300, 300]);
|
||||||
|
env.assertFalse(result.inside);
|
||||||
|
env.done();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
testPIPClassification_TR_OUT_TR_INNER: function (env) {
|
testPIPClassification_TR_OUT_TR_INNER: function (env) {
|
||||||
test.modeller(env.test((win, app) => {
|
test.modeller(env.test((win, app) => {
|
||||||
const loop = createLoop(app.TPI,[
|
const loop = createLoop(app.TPI,[
|
||||||
|
|
@ -660,14 +821,13 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
function classify(app, win, loop, p) {
|
function classify(app, win, loop, p) {
|
||||||
const IDENTITY = new Matrix3();
|
|
||||||
loop.halfEdges.forEach(e => win.__DEBUG__.AddHalfEdge(e, 0xffff00));
|
loop.halfEdges.forEach(e => win.__DEBUG__.AddHalfEdge(e, 0xffff00));
|
||||||
const pnt = point(app.TPI, p[0], p[1], 0);
|
const pnt = point(app.TPI, p[0], p[1], 0);
|
||||||
const beam = pnt.copy();
|
const beam = pnt.copy();
|
||||||
beam.x += 1700;
|
beam.x += 1700;
|
||||||
win.__DEBUG__.AddLine(pnt, beam);
|
win.__DEBUG__.AddLine(pnt, beam);
|
||||||
win.__DEBUG__.AddPoint(pnt, 0xffffff);
|
win.__DEBUG__.AddPoint(pnt, 0xffffff);
|
||||||
const result = app.TPI.brep.bool.classifyPointInsideLoop(pnt, loop, IDENTITY);
|
const result = app.TPI.brep.bool.classifyPointInsideLoop(pnt, loop, new app.TPI.brep.geom.Plane(AXIS.Z, 0));
|
||||||
win.__DEBUG__.AddPoint(pnt, result.inside ? 0x00ff00 : 0xff0000);
|
win.__DEBUG__.AddPoint(pnt, result.inside ? 0x00ff00 : 0xff0000);
|
||||||
if (result.edge) {
|
if (result.edge) {
|
||||||
win.__DEBUG__.AddHalfEdge(result.edge, 0xffffff)
|
win.__DEBUG__.AddHalfEdge(result.edge, 0xffffff)
|
||||||
|
|
@ -676,9 +836,16 @@ function classify(app, win, loop, p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function createLoop(tpi, points) {
|
function createLoop(tpi, points, curves) {
|
||||||
|
curves = curves || [];
|
||||||
const vertices = points.map(p => vertex(tpi, p[0], p[1], 0));
|
const vertices = points.map(p => vertex(tpi, p[0], p[1], 0));
|
||||||
return tpi.brep.builder.createPlaneLoop(vertices);
|
return tpi.brep.builder.createPlaneLoop(vertices, curves.map(c => {
|
||||||
|
if (c && c[0] == 'nurbs') {
|
||||||
|
const points = c.slice(1).map(p => new tpi.brep.geom.Point().set3(p) );
|
||||||
|
return tpi.brep.geom.NurbsCurve.createByPoints(points, 2);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function vertex(tpi, x, y, z) {
|
function vertex(tpi, x, y, z) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue