实现几何计算,然后实现凸包、Delaunay三角和Voronoi多边形。使用node运行。
几何计算实现点,直线一般式方程、两点式方程、点截式方程、直线交点、点与直线关系,三角形、矩形外接三角形,矩形,圆、三角形外接圆、点与圆关系计算。
凸包算法
graham() {
let vs = this.children.filter(e=>e.getClass() == "Vertex");
// find p0-y vectex
let p0 = vs[0];
for (let v of vs) {
if ( (v.y < p0.y) || (v.y==p0.y && v.x<p0.x))
p0 = v;
}
vs.sort(function(a,b) {
let d1 = Math.atan2( a.y-p0.y , a.x-p0.x ) * (180 / Math.PI);
if (d1 < 0) d1 += 180;
let d2 = Math.atan2( b.y-p0.y , b.x-p0.x ) * (180 / Math.PI);
if (d2 < 0) d2 += 180;
if (d1 < d2)
return -1;
else if (d1 > d2)
return 1;
else {
p0.getDistance(a) - p0.getDistance(b) > 0 ? 1 : -1;
}
});
let ps = [].concat(vs);
let stack = new Array(ps.shift(), ps.shift());
for (let current of ps) {
let d;
do {
let top = stack.peek();
let sec = stack[stack.length-2];
let line = Line.TwoPoint(sec,top);
d = line.position(current);
if (d>0)
top = stack.pop();
} while (d > 0);
stack.push(current);
}
}
显示如下:
德洛内三角
DelaunayBowyer() {
let indices = this.children
.filter(e=>e.getClass() == "Vertex")
.sort((a,b)=>{
return a.x == b.x ? 0 : (a.x < b.x ? -1 : 1);
});
let maxx = 0, maxy = 0, minx = Number.MAX_SAFE_INTEGER, miny = Number.MAX_SAFE_INTEGER;
indices.forEach(v=>{
if (v.x < minx) minx = v.x;
if (v.x > maxx) maxx = v.x;
if (v.y < miny) miny = v.y;
if (v.y > maxy) maxy = v.y;
});
let r = new Rectangle(new Point(minx, miny), new Point(maxx, maxy));
let supert = Triangle.ExternalTriangleFromRectangle(r);
let vs = indices.concat([ supert.p0, supert.p1, supert.p2 ]);
let ts =[ supert ];
for (let v of vs) {
let edge = new CountArray();
let i = ts.length - 1;
while (i>=0) {
let t = ts[i--];
let c = Circle.Circumcircle(t);
let position = c.test(v);
if (position == "out") {
continue ;
}
else {
edge.push(new Pair(t.p0, t.p1));
edge.push(new Pair(t.p1, t.p2));
edge.push(new Pair(t.p2, t.p0));
ts.remove(t);
}
}
let nedge = edge.getArray();
for (let i=0; i<nedge.length; i++) {
if (v.equals(nedge[i].v1) || v.equals(nedge[i].v2) || nedge[i].v1.equals(nedge[i].v2)) {
continue ;
}
let t = new Triangular(v, nedge[i].v1, nedge[i].v2);
ts.push(t);
}
}
for (let i=ts.length-1; i>=0; i--) {
let t = ts[i];
if (t.p0.getClass() == "Point" || t.p1.getClass() == "Point" || t.p2.getClass() == "Point") {
ts.remove(t);
continue ;
}
this.children.push(t);
}
return ts;
}
显示如下,未上色和和上色的:
泰森多边形:
Voronoi() {
let vs = this.children.filter(e=>e.getClass() == "Vertex");
let ts = this.children.filter(e=>e.getClass() == "Triangular");
let gl = [];
for (let v of vs) {
let bounds = [];
for (let t of ts)
if (t.p0 == v || t.p1 == v || t.p2 == v)
bounds.push(t);
let sort = [];
let e = bounds[0].exclude(v)[0];
let t;
while (bounds.length > 0) {
let bFound = false;
for (t of bounds) {
if (t.hasEdge(v, e)) {
e = t.exclude(v, e)[0];
bFound = true;
break;
}
}
if (bFound) {
bounds.remove(t);
sort.push(t);
}
else {
break ;
}
}
if (bounds.length == 0)
gl.push(sort);
}
for (let g of gl) {
let cps = [];
for (let s of g) {
let c = Circle.Circumcircle(s);
if (c.x <= 0 && c.y <= 0)
return ;
cps.push(c.p);
}
let p = new Path(cps);
this.children.push(p);
}
}
显示如下,带背景和去掉背景的: