|
import cross from "./cross.js"; |
|
|
|
function lexicographicOrder(a, b) { |
|
return a[0] - b[0] || a[1] - b[1]; |
|
} |
|
|
|
|
|
|
|
|
|
function computeUpperHullIndexes(points) { |
|
const n = points.length, |
|
indexes = [0, 1]; |
|
let size = 2, i; |
|
|
|
for (i = 2; i < n; ++i) { |
|
while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size; |
|
indexes[size++] = i; |
|
} |
|
|
|
return indexes.slice(0, size); |
|
} |
|
|
|
export default function(points) { |
|
if ((n = points.length) < 3) return null; |
|
|
|
var i, |
|
n, |
|
sortedPoints = new Array(n), |
|
flippedPoints = new Array(n); |
|
|
|
for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i]; |
|
sortedPoints.sort(lexicographicOrder); |
|
for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]]; |
|
|
|
var upperIndexes = computeUpperHullIndexes(sortedPoints), |
|
lowerIndexes = computeUpperHullIndexes(flippedPoints); |
|
|
|
|
|
var skipLeft = lowerIndexes[0] === upperIndexes[0], |
|
skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1], |
|
hull = []; |
|
|
|
|
|
|
|
for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]); |
|
for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]); |
|
|
|
return hull; |
|
} |
|
|