Skip to content

Instantly share code, notes, and snippets.

@saifuddin778
Last active June 8, 2019 02:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save saifuddin778/35b03529078e0dfba5476d13f7bcea40 to your computer and use it in GitHub Desktop.
Save saifuddin778/35b03529078e0dfba5476d13f7bcea40 to your computer and use it in GitHub Desktop.
Convex Hull (Jarvis's March)

Visual representation of the process of finding convex hull for a set of random 2D points (implementation known as the Gift Wrapping or Jarvis's March algorithm).

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
text-align: center;
}
.dots {
fill: #50ff50;
fill-opacity: 0.6;
stroke: #383838;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
//saif, a. (2k19)
function genSpace(width, height, points){
var space = d3.select("body").append("svg").attr("width", width).attr("height", height).style("background", "snow").append("g");
space.selectAll()
.data(points)
.enter()
.append("g")
.append("circle")
.attr("cx", function(d){return d.x})
.attr("cy", function(d){return d.y})
.attr("r", function(d){return 3})
.attr("class", "dots");
return space
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function getOrientation(origin, p1, p2){
/**
-- returns orientation of point p1 wrt p2 using origin as the center point. -ve if p2 is clockwise wrt p1, else +ve.
**/
const orient = ((p2.x - origin.x) * (p1.y - origin.y)) - ((p1.x - origin.x) * (p2.y - origin.y));
return orient;
}
function distance(p1, p2){
/**
-- standard distance function
**/
var dist = 0;
for (var i=0; i<p1.length; i++){
dist += Math.pow(Math.abs(p1[i]-p2[i]), 2);
}
return dist;
}
async function run(){
/**
-- entry point
*/
const width = 500;
const height = 500;
const n = 2000;
const points = d3.range(n).map(function(d){
const r = 10 + (200 * Math.random()) * Math.random();
const theta = Math.random() * 2 * Math.PI;
return {
x: Math.round((width/2) + r * Math.cos(theta), 2),
y: Math.round((height/2) + r * Math.sin(theta), 2)
}
});
var space = genSpace(width, height, points);
//now run over the points and find the left most
let left_most = points[0];
let left_most_idx = 0;
for (var i=0; i<n; i++){
if (points[i].x < left_most.x){
left_most = points[i];
left_most_idx = i;
}
}
var hulls = [];
//now begin from the left most
var l = left_most_idx;
hulls.push(points[l]);
var connect_from = 0;
while(true){
var q = (l + 1) % points.length;
for (var i=0; i<n; i++){
if (i == l){
continue
}
var d = getOrientation(points[l], points[i], points[q]);
if ((d > 0) || ((d==0) && (distance(points[i], points[l]) > distance(points[q], points[l])))) {
q = i;
}
}
l = q;
if (l == left_most_idx){
space.append("line").attr("x1", hulls[0].x).attr("y1", hulls[0].y).attr("x2", hulls[hulls.length-1].x).attr("y2", hulls[hulls.length-1].y).style("fill", "none").style("stroke", "tomato").style("stroke-width", 2).style("stroke-dasharray", ("3, 3"));
break;
}
hulls.push(points[q]);
space.append("line").attr("x1", hulls[connect_from].x).attr("y1", hulls[connect_from].y).attr("x2", hulls[hulls.length-1].x).attr("y2", hulls[hulls.length-1].y).style("fill", "none").style("stroke", "tomato").style("stroke-width", 2).style("stroke-dasharray", ("3, 3"));
if (connect_from == 0){
d3.select(space.selectAll("circle")[0][left_most_idx]).style("fill", "red").attr("r", 4);
}
d3.select(space.selectAll("circle")[0][q]).style("fill", "red").attr("r", 4);
await sleep(500);
connect_from += 1;
}
}
run();
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment