-
Notifications
You must be signed in to change notification settings - Fork 0
/
ConvexHullGraham.js
87 lines (74 loc) · 2.21 KB
/
ConvexHullGraham.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
* Author: Arnab Ray
* ConvexHull using Graham Scan
* Wikipedia: https://en.wikipedia.org/wiki/Graham_scan
* Given a set of points in the plane. The Convex hull of the set is the smallest
* convex polygon that contains all the points of it.
*/
function compare (a, b) {
// Compare Function to Sort the points, a and b are points to compare
if (a.x < b.x) return -1
if (a.x === b.x && a.y < b.y) return -1
return 1
}
function orientation (a, b, c) {
// Check orientation of Line(a,b) and Line(b,c)
const alpha = (b.y - a.y) / (b.x - a.x)
const beta = (c.y - b.y) / (c.x - b.x)
// Clockwise
if (alpha > beta) return 1
// Anticlockwise
else if (beta > alpha) return -1
// Colinear
return 0
}
function convexHull (points) {
const pointsLen = points.length
if (pointsLen <= 2) {
throw new Error('Minimum of 3 points is required to form closed polygon!')
}
points.sort(compare)
const p1 = points[0]; const p2 = points[pointsLen - 1]
// Divide Hull in two halves
const upperPoints = []; const lowerPoints = []
upperPoints.push(p1)
lowerPoints.push(p1)
for (let i = 1; i < pointsLen; i++) {
if (i === pointsLen - 1 || orientation(p1, points[i], p2) !== -1) {
let upLen = upperPoints.length
while (upLen >= 2 && orientation(upperPoints[upLen - 2], upperPoints[upLen - 1], points[i]) === -1) {
upperPoints.pop()
upLen = upperPoints.length
}
upperPoints.push(points[i])
}
if (i === pointsLen - 1 || orientation(p1, points[i], p2) !== 1) {
let lowLen = lowerPoints.length
while (lowLen >= 2 && orientation(lowerPoints[lowLen - 2], lowerPoints[lowLen - 1], points[i]) === 1) {
lowerPoints.pop()
lowLen = lowerPoints.length
}
lowerPoints.push(points[i])
}
}
const hull = []
for (let i = 1; i < upperPoints.length - 1; i++) {
hull.push(upperPoints[i])
}
for (let i = lowerPoints.length - 1; i >= 0; i--) {
hull.push(lowerPoints[i])
}
return hull
}
export { convexHull }
// Example
// const points = [
// { x: 0, y: 3 },
// { x: 1, y: 1 },
// { x: 2, y: 2 },
// { x: 4, y: 4 },
// { x: 0, y: 0 },
// { x: 1, y: 2 },
// { x: 3, y: 1 },
// { x: 3, y: 3 }]
// convexHull(points)