Brute-force convex hull construction
Jul 16 2016 ยท Graphics and Rendering
I’ve been experimenting a bit with convex hull constructions and below I’ll explain how to do a brute-force construction of a hull.
It’s worth noting up-front that the brute-force method is slow, O(n3) worst case complexity. So why bother? I think there are a few compelling reasons:
- The brute-force method expresses the fundamental solution, which gives you the basic building blocks and understanding to approach more complex solutions
- It’s faster to implement
- It’s still a viable solution when n is small, and n is usually small.
What is a convex hull?
You can find a formal definition on Wikipedia. Informally, and specific to computational geometry, the convex hull is a convex polygon in which all points are either vertices of said polygon or enclosed within the polygon.
Brute-force construction
- Iterate over every pair of points (p,q)
- If all the other points are to the right (or left, depending on implementation) of the line formed by (p,q), the segment (p,q) is part of our result set (i.e. it’s part of the convex hull)
Here’s the top-level code that handles the iteration and construction of resulting line segments:
/**
* Compute convex hull
*/
var computeConvexHull = function() {
console.log("--- ");
for(var i=0; i<points.length; i++) {
for(var j=0; j<points.length; j++) {
if(i === j) {
continue;
}
var ptI = points[i];
var ptJ = points[j];
// Do all other points lie within the half-plane to the right
var allPointsOnTheRight = true;
for(var k=0; k<points.length; k++) {
if(k === i || k === j) {
continue;
}
var d = whichSideOfLine(ptI, ptJ, points[k]);
if(d < 0) {
allPointsOnTheRight = false;
break;
}
}
if(allPointsOnTheRight) {
console.log("segment " + i + " to " + j);
var pointAScreen = cartToScreen(ptI, getDocumentWidth(), getDocumentHeight());
var pointBScreen = cartToScreen(ptJ, getDocumentWidth(), getDocumentHeight());
drawLineSegment(pointAScreen, pointBScreen);
}
}
}
};
The “secret sauce” is the whichSideOfLine() method:
/**
* Determine which side of a line a given point is on
*/
var whichSideOfLine = function(lineEndptA, lineEndptB, ptSubject) {
return (ptSubject.x - lineEndptA.x) * (lineEndptB.y - lineEndptA.y) - (ptSubject.y - lineEndptA.y) * (lineEndptB.x - lineEndptA.x);
};
This is a bit of linear algebra derived from the general equation for a line.
The result represents the side of a line a point is one, based on the sign of the result. We can check if the point is on the left or on the right, it doesn’t matter as long as there is consistency and the same check is done for all points.
How it looks
I made a few diagrams to show the first few steps in the algorithm, as segments constituting the convex hull are found. The shaded area represents our success case, where all other points are to the right of the line formed by the points under consideration. Not shown are the failure cases (i.e. one or more points are on the left of the line formed by the points under consideration).
Code and Demo
You can play around with constructing a hull below by double-clicking to add vertices.
You can find the code on GitHub.