Skip to content

Instantly share code, notes, and snippets.

@aslushnikov
Created May 1, 2012 18:14
Show Gist options
  • Save aslushnikov/2570185 to your computer and use it in GitHub Desktop.
Save aslushnikov/2570185 to your computer and use it in GitHub Desktop.
convex shell on JS
function Point(x, y) {
this.x = x;
this.y = y;
return this;
}
var a = [
new Point(0, 3)
, new Point(1, 1)
, new Point(1, 3)
, new Point(2, 4)
, new Point(3, 1)
, new Point(3, 2)
, new Point(4, 2)
];
function convexShell(points) {
var n = points.length;
if (n == 0) {
throw new Error("Zero length array of points is not allowed");
}
var p = points[0];
for(var i = 1; i < n; i++) {
if (points[i].y > p.y) continue;
if (points[i].y < p.y || points[i].x < p.x) {
p = points[i];
}
}
function atan(point) {
return Math.atan2(point.y - p.y, point.x - p.x);
}
function dist(p1, p2) {
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
function cmp(p1, p2) {
var d = atan(p1) - atan(p2);
if (Math.abs(d) > 1e-8) return d;
return dist(p1, p) - dist(p2, p);
}
function qsort(points, l, r) {
var i = l, j = r;
var m = Math.round((i + j)/2);
var x = points[m];
do{
while(cmp(points[i], x) < 0) {
++i;
}
while(cmp(points[j], x) > 0) {
--j;
}
if (i <= j) {
var t = points[i];
points[i] = points[j];
points[j] = t;
++i;--j;
}
} while(i <= j);
if (i < r) qsort(points, i, r);
if (l < j) qsort(points, l, j);
}
qsort(points, 0, n-1);
if (n < 3) {
return points;
}
var shell = [];
shell.push(points[0]);
shell.push(points[1]);
for(var i = 2; i < n; i++) {
var sp3 = points[i];
var sp2 = shell.pop();
var sp1 = shell.pop();
var x1 = sp1.x - sp2.x;
var y1 = sp1.y - sp2.y;
var x2 = sp3.x - sp2.x;
var y2 = sp3.y - sp2.y;
if (x1 * y2 - x2 * y1 < 0) {
shell.push(sp1);
shell.push(sp2);
shell.push(sp3);
} else {
shell.push(sp1);
shell.push(sp3);
}
}
return shell;
}
for(var i = 0; i < a.length; i++) {
console.log(a[i].x + " " + a[i].y);
}
convexShell(a);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment