From 788f74f6c2f2ed61ebdb2a717e38aab6add743f3 Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Sun, 15 Jun 2025 10:36:00 -0400 Subject: [PATCH 1/2] Add hole support for polygons --- Sources/SwiftH3/H3Index.swift | 70 +++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/Sources/SwiftH3/H3Index.swift b/Sources/SwiftH3/H3Index.swift index a759453..47ef9a8 100644 --- a/Sources/SwiftH3/H3Index.swift +++ b/Sources/SwiftH3/H3Index.swift @@ -202,24 +202,36 @@ extension H3Index { public class H3Polygon { private var loop: [Ch3.LatLng] - // TODO: Add holes - - var geoPolygon: GeoPolygon { - let numVerts = Int32(loop.count) - return loop.withUnsafeMutableBufferPointer { ptr in - GeoPolygon( - geoloop: GeoLoop( - numVerts: numVerts, - verts: ptr.baseAddress - ), - numHoles: 0, - holes: nil - ) + private var holes: [[Ch3.LatLng]] + + internal func withGeoPolygon(_ body: (inout GeoPolygon) -> T) -> T { + return loop.withUnsafeMutableBufferPointer { loopPtr in + var holeLoops: [GeoLoop] = [] + holeLoops.reserveCapacity(holes.count) + for hole in holes { + let loop = hole.withUnsafeMutableBufferPointer { ptr in + GeoLoop(numVerts: Int32(ptr.count), verts: ptr.baseAddress) + } + holeLoops.append(loop) + } + + return holeLoops.withUnsafeMutableBufferPointer { holesPtr in + var polygon = GeoPolygon( + geoloop: GeoLoop( + numVerts: Int32(loopPtr.count), + verts: loopPtr.baseAddress + ), + numHoles: Int32(holeLoops.count), + holes: holesPtr.baseAddress + ) + return body(&polygon) + } } } - public init(loop: [H3Coordinate]) { + public init(loop: [H3Coordinate], holes: [[H3Coordinate]] = []) { self.loop = loop.map(\.latLng) + self.holes = holes.map { $0.map(\.latLng) } } } @@ -240,21 +252,23 @@ extension Array where Element == H3Coordinate { extension H3Index { public static func polygonToCells(polygon: H3Polygon, resolution: Int) -> [H3Index] { - var geoPolygon = polygon.geoPolygon - - var maxCellsSize: Int64 = 0 - let sizeError = maxPolygonToCellsSize(&geoPolygon, Int32(resolution), 0, &maxCellsSize) - if sizeError.code != .success { - return [] - } - - var cells = [UInt64](repeating: 0, count: Int(maxCellsSize)) - let error = Ch3.polygonToCells(&geoPolygon, Int32(resolution), 0, &cells) - if error.code != .success { - return [] + return polygon.withGeoPolygon { geoPolygon in + var polygon = geoPolygon + + var maxCellsSize: Int64 = 0 + let sizeError = maxPolygonToCellsSize(&polygon, Int32(resolution), 0, &maxCellsSize) + if sizeError.code != .success { + return [] + } + + var cells = [UInt64](repeating: 0, count: Int(maxCellsSize)) + let error = Ch3.polygonToCells(&polygon, Int32(resolution), 0, &cells) + if error.code != .success { + return [] + } + + return cells.map(H3Index.init).filter(\.isValid) } - - return cells.map(H3Index.init).filter(\.isValid) } } From 6b1c304d8caba92e8c6f89c2a6be03582926540e Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Sun, 15 Jun 2025 12:29:08 -0400 Subject: [PATCH 2/2] Fix var access issues --- Sources/SwiftH3/H3Index.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftH3/H3Index.swift b/Sources/SwiftH3/H3Index.swift index 47ef9a8..13eaa57 100644 --- a/Sources/SwiftH3/H3Index.swift +++ b/Sources/SwiftH3/H3Index.swift @@ -208,14 +208,15 @@ public class H3Polygon { return loop.withUnsafeMutableBufferPointer { loopPtr in var holeLoops: [GeoLoop] = [] holeLoops.reserveCapacity(holes.count) - for hole in holes { + for var hole in holes { let loop = hole.withUnsafeMutableBufferPointer { ptr in GeoLoop(numVerts: Int32(ptr.count), verts: ptr.baseAddress) } holeLoops.append(loop) } - return holeLoops.withUnsafeMutableBufferPointer { holesPtr in + var holeLoopsCopy = holeLoops + return holeLoopsCopy.withUnsafeMutableBufferPointer { holesPtr in var polygon = GeoPolygon( geoloop: GeoLoop( numVerts: Int32(loopPtr.count),