UNPKG

@thi.ng/quad-edge

Version:

Quadedge data structure after Guibas & Stolfi

161 lines (160 loc) 3.54 kB
import { assert } from "@thi.ng/errors/assert"; function defEdge(id, src, dest) { assert((id & 3) === 0, `id must be multiple of 4`); const quad = new Array(4); const a = quad[0] = new Edge(quad, id); const b = quad[1] = new Edge(quad, id + 1); const c = quad[2] = new Edge(quad, id + 2); const d = quad[3] = new Edge(quad, id + 3); a.onext = a; c.onext = c; b.onext = d; d.onext = b; src && dest && a.setEnds(src, dest); return a; } class Edge { id; parent; origin; constructor(parent, id) { this.parent = parent; this.id = id; } /** * Next CCW edge from this edge's origin. */ onext; /** * Next CW edge from this edge's origin. */ get oprev() { return this.rot.onext.rot; } /** * Dual of this edge, right -> left. */ get rot() { return this.parent[this.id + 1 & 3]; } /** * Dual of this edge, left -> right. * I.e same as `this.rot.sym` */ get invrot() { return this.parent[this.id + 3 & 3]; } /** * Symmetric partner edge of this edge, from dest -> src. * I.e. `this === this.sym.sym` */ get sym() { return this.parent[this.id + 2 & 3]; } /** * Next CCW edge to this edge's dest. */ get dnext() { return this.sym.onext.sym; } /** * Next CW edge to this edge's dest. */ get dprev() { return this.invrot.onext.invrot; } /** * Next CCW edge around the left face (dual vertex) from this edge's * dest. */ get lnext() { return this.invrot.onext.rot; } /** * Next CCW edge around the left face (dual vertex) to this edge's * origin. */ get lprev() { return this.onext.sym; } /** * Next CCW edge around the right face (dual vertex) to this edge's * dest. */ get rnext() { return this.rot.onext.invrot; } /** * Next CCW edge around the right face (dual vertex) to this edge's * origin. */ get rprev() { return this.sym.onext; } /** * Returns this edge's dest vertex. I.e. `this.sym.origin` */ get dest() { return this.sym.origin; } /** * Sets the origin & dest vertices of this edge (in other words, the * origins of this edge and `this.sym`). * * @param o - * @param d - */ setEnds(o, d) { this.origin = o; this.sym.origin = d; } connect(e, id) { const n = defEdge(id); n.splice(this.lnext); n.sym.splice(e); n.setEnds(this.dest, e.origin); return n; } swap() { const a = this.oprev; const b = this.sym.oprev; this.splice(a); this.sym.splice(b); this.splice(a.lnext); this.sym.splice(b.lnext); this.setEnds(a.dest, b.dest); } remove() { this.splice(this.oprev); this.sym.splice(this.sym.oprev); delete this.parent; } /** * Modifies the edge rings around the origins of this edge and `e`, * as well as, independently, the edge rings of both edges' left * dual vertex. In each case, if the rings are separate, this * operator will join them and if both rings are the same ring, they * will be split / separated. Therefore, splice` is it's own reverse * operator and the only operator needed to edit quad edge * topologies. * * @param e - */ splice(e) { const alpha = this.onext.rot; const beta = e.onext.rot; const t1 = e.onext; const t2 = this.onext; const t3 = beta.onext; const t4 = alpha.onext; this.onext = t1; e.onext = t2; alpha.onext = t3; beta.onext = t4; return this; } } export { Edge, defEdge };