|
@@ -48,52 +48,41 @@ abstract Polygon(Array<Point>) from Array<Point> to Array<Point> {
|
|
return b;
|
|
return b;
|
|
}
|
|
}
|
|
|
|
|
|
- //sources : https://fr.wikipedia.org/wiki/Parcours_de_Graham
|
|
|
|
- //step by step demonstration : http://www.algomation.com/algorithm/graham-scan-convex-hull
|
|
|
|
|
|
+ inline function xSort(a : Point, b : Point) {
|
|
|
|
+ if(a.x == b.x)
|
|
|
|
+ return a.y < b.y ? -1 : 1;
|
|
|
|
+ return a.x < b.x ? -1 : 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //see Monotone_chain convex hull algorythm
|
|
public function convexHull() {
|
|
public function convexHull() {
|
|
var len = points.length;
|
|
var len = points.length;
|
|
if( points.length < 3 )
|
|
if( points.length < 3 )
|
|
return points;
|
|
return points;
|
|
|
|
|
|
- //find lowest y points
|
|
|
|
- var p0 = points[0];
|
|
|
|
- for( p in points ) {
|
|
|
|
- if( p.y < p0.y || (p.y == p0.y && p.x < p0.x) )
|
|
|
|
- p0 = p;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- //sort by angle from p0
|
|
|
|
- var pts : Array<{p : h2d.col.Point, a : Float}> = [];
|
|
|
|
- var p1 = new h2d.col.Point(p0.x + 1e5, p0.y);
|
|
|
|
- for(p in points) {
|
|
|
|
- if(p.x == p0.x && p.y == p0.y) continue;
|
|
|
|
- pts.push({p : p, a : side(p0, p1, p)});
|
|
|
|
- }
|
|
|
|
- pts.sort(function(pa, pb) return side(p0, pa.p, pb.p) > 0 ? -1 : 1);
|
|
|
|
-
|
|
|
|
- //remove same angle points (includes duplicated points)
|
|
|
|
- var index = pts.length - 1;
|
|
|
|
- while(index > 0) {
|
|
|
|
- var cur = pts[index];
|
|
|
|
- var prev = pts[index - 1];
|
|
|
|
- if(cur.a == prev.a) {
|
|
|
|
- if(Math.distanceSq(cur.p.x - p0.x, cur.p.y - p0.y) < Math.distanceSq(prev.p.x - p0.x, prev.p.y - p0.y))
|
|
|
|
- pts.remove(cur);
|
|
|
|
- else pts.remove(prev);
|
|
|
|
- }
|
|
|
|
- index--;
|
|
|
|
- }
|
|
|
|
|
|
+ points.sort(xSort);
|
|
|
|
|
|
- //set hull
|
|
|
|
- var hull = [ p0, pts[0].p, pts[1].p ];
|
|
|
|
- for (i in 2...pts.length) {
|
|
|
|
- var pi = pts[i].p;
|
|
|
|
- while (side(hull[hull.length - 2], hull[hull.length - 1], pi) <= 0)
|
|
|
|
- hull.pop();
|
|
|
|
- hull.push(pi);
|
|
|
|
|
|
+ var hull = [];
|
|
|
|
+ var k = 0;
|
|
|
|
+ for (p in points) {
|
|
|
|
+ while (k >= 2 && side(hull[k - 2], hull[k - 1], p) <= 0)
|
|
|
|
+ k--;
|
|
|
|
+ hull[k++] = p;
|
|
}
|
|
}
|
|
|
|
|
|
- return hull;
|
|
|
|
|
|
+ var i = points.length - 2;
|
|
|
|
+ var len = k + 1;
|
|
|
|
+ while(i >= 0) {
|
|
|
|
+ var p = points[i];
|
|
|
|
+ while (k >= len && side(hull[k - 2], hull[k - 1], p) <= 0)
|
|
|
|
+ k--;
|
|
|
|
+ hull[k++] = p;
|
|
|
|
+ i--;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while( hull.length >= k )
|
|
|
|
+ hull.pop();
|
|
|
|
+ return hull;
|
|
}
|
|
}
|
|
|
|
|
|
public function isClockwise() {
|
|
public function isClockwise() {
|