@thi.ng/quad-edge
Version:
Quadedge data structure after Guibas & Stolfi
161 lines (160 loc) • 3.54 kB
JavaScript
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
};