mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-12 03:13:24 +01:00
90 lines
2.3 KiB
TypeScript
90 lines
2.3 KiB
TypeScript
import {TopoObject} from './topo-object'
|
|
import {Face} from "./face";
|
|
import {BrepSurface} from "geom/surfaces/brepSurface";
|
|
import {HalfEdge} from "./edge";
|
|
import {findLowestLeftPoint} from "geom/euclidean";
|
|
import {Vertex} from "brep/topo/vertex";
|
|
|
|
export class Loop extends TopoObject {
|
|
|
|
face: Face;
|
|
halfEdges: HalfEdge[];
|
|
|
|
encloses = {
|
|
[Symbol.iterator]: () => enclosesGenerator(this.halfEdges)
|
|
};
|
|
|
|
constructor(face: Face) {
|
|
super();
|
|
this.face = face;
|
|
this.halfEdges = [];
|
|
}
|
|
|
|
isCCW(surface: BrepSurface) {
|
|
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;
|
|
}
|
|
|
|
private static isPolygonCCWOnSurface(polygon: any[], surface: BrepSurface) {
|
|
const tr = surface.simpleSurface.get2DTransformation();
|
|
const polygon2d = polygon.map(p => tr.apply(p));
|
|
const lowestLeftIdx = 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;
|
|
}
|
|
}
|
|
|
|
export function* enclosesGenerator(halfEdges): Generator<[HalfEdge, HalfEdge, Vertex]> {
|
|
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) {
|
|
// @ts-ignore
|
|
__DEBUG__.AddHalfEdge(curr, 0xff1199);
|
|
// @ts-ignore
|
|
__DEBUG__.AddHalfEdge(next, 0x99ff11);
|
|
throw 'using enclose generator on invalid Loop';
|
|
}
|
|
yield [curr, next, curr.vertexB];
|
|
}
|
|
}
|
|
|
|
|