jsketcher/web/app/brep/topo/loop.js
2018-01-03 01:52:35 -08:00

80 lines
No EOL
2 KiB
JavaScript

import {TopoObject} from './topo-object'
import {Point} from '../geom/point'
import * as math from '../../math/math'
export class Loop extends TopoObject {
constructor(face) {
super();
this.face = face;
this.halfEdges = [];
this.encloses = undefined;
this.defineIterable('encloses', () => enclosesGenerator(this.halfEdges));
}
isCCW(surface) {
return Loop.isPolygonCCWOnSurface(this.asPolygon(), surface);
}
asPolygon() {
return this.halfEdges.map(e => e.vertexA.point);
}
link() {
let length = this.halfEdges.length;
for (let i = 0; i < length; i++) {
let j = (i + 1) % length;
const curr = this.halfEdges[i];
const next = this.halfEdges[j];
curr.next = next;
next.prev = curr;
curr.loop = this;
}
}
tess() {
let out = [];
for (let e of this.halfEdges) {
let curvePoints = e.edge.curve.tessellate();
if (e.inverted) {
curvePoints.reverse();
}
curvePoints.pop();
for (let point of curvePoints) {
out.push(point);
}
}
return out;
}
}
export function* enclosesGenerator(halfEdges) {
let length = halfEdges.length;
for (let i = 0; i < halfEdges.length; i++) {
let j = (i + 1) % length;
const curr = halfEdges[i];
const next = halfEdges[j];
if (curr.vertexB !== next.vertexA) {
__DEBUG__.AddHalfEdge(curr, 0xff1199);
__DEBUG__.AddHalfEdge(next, 0x99ff11);
throw 'using enclose generator on invalid Loop';
}
yield [curr, next, curr.vertexB];
}
}
Loop.isPolygonCCWOnSurface = function(polygon, surface) {
const tr = surface.get2DTransformation();
const polygon2d = polygon.map(p => tr.apply(p));
const lowestLeftIdx = math.findLowestLeftPoint(polygon2d);
const n = polygon.length;
const nextIdx = ((lowestLeftIdx + 1) % n);
const prevIdx = ((n + lowestLeftIdx - 1) % n);
const o = polygon[lowestLeftIdx];
const first = polygon[nextIdx].minus(o);
const last = o.minus(polygon[prevIdx]);
return last.cross(first).dot(surface.normal) >= 0;
};