mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2025-07-04 15:39:42 +08:00

* chore: Switch to Node 20 + Vitest * chore: migrate to vitest mock functions * chore: code style (switch to prettier) * test: re-enable long-running test Seems the switch to Node 20 and Vitest has vastly improved the code's and / or the test's runtime! see #1193 * chore: code style * chore: fix failing tests * Updated Documentation in README.md * Update contribution guidelines to state usage of Prettier * fix: set prettier printWidth back to 80 * chore: apply updated code style automatically * fix: set prettier line endings to lf again * chore: apply updated code style automatically --------- Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com>
104 lines
2.3 KiB
JavaScript
104 lines
2.3 KiB
JavaScript
/**
|
|
* 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)
|