'ConvexHull' 'Swift'でぐぐってみたら、なんだか物足りなかったので、なんとなく。
import simd public struct Graham { var target: [SIMD2<Float>] = [] public func scan() -> [SIMD2<Float>] { guard let lowestPoint = target.most(in: lower) else { return [] } return scanLeftTurn(startPoint: lowestPoint, angleOrder: target .filter({ $0 != lowestPoint }) .sorted{ lowBiasedAngle(with: lowestPoint)($0,$1) }) } func scanLeftTurn(startPoint head: SIMD2<Float>, angleOrder tail: [SIMD2<Float>]) -> [SIMD2<Float>] { var stack: [SIMD2<Float>] = [] stack.push(head); stack.push(tail[0]) for vertex in tail[1..<tail.count] { while ( !left( stack.top(1) , stack.top(0), vertex ) ) { _ = stack.pop() } stack.push(vertex) } return stack } } func lowBiasedAngle(with h: SIMD2<Float>) -> (_ pi: SIMD2<Float>,_ pj: SIMD2<Float>) -> Bool { { (pi, pj) in areaSign( h, pi, pj ) != .negative } } func left(_ a: SIMD2<Float>,_ b: SIMD2<Float>,_ c: SIMD2<Float> ) -> Bool { areaSign( a, b, c ) == .positive } func lower<Scalar: Comparable>(_ lhs: SIMD2<Scalar>, _ rhs: SIMD2<Scalar> ) -> Bool { lhs.y < rhs.y || (lhs.y == rhs.y && lhs.x > rhs.x) } enum Compare { case negative case even case positive } func areaSign(_ a: SIMD2<Float>,_ b: SIMD2<Float>,_ c: SIMD2<Float>) -> Compare { let area2 = cross(b - a, c - a).z if abs(area2) < .ulpOfOne { return .even } else if area2 > 0 { return .positive } return .negative } extension Array { func most(in condition: (Element, Element) -> Bool) -> Element? { reduce(nil) { lhs, rhs in guard let lhs = lhs else { return rhs } return condition(lhs, rhs) ? lhs : rhs } } } extension Array { mutating func push(_ element: Element) { append(element) } mutating func pop() -> Element { removeLast() } func top(_ i: Int) -> Element { self[count - 1 - i] } }
Reference
O'Rourke,J. (1998). Computational Geometry in C, 2nd edn, Cambridge: Cambridge University Press.