From 56d8635847a1ec0da64bb11138072404ce7fa07f Mon Sep 17 00:00:00 2001 From: Fumiya Tanaka Date: Sun, 24 Nov 2024 16:31:42 +0900 Subject: [PATCH] Add `getNeighbors` method (#4) --- .vscode/launch.json | 22 ++++++++ .vscode/settings.json | 10 ++++ Sources/GeoHashFramework/GeoHash.swift | 56 ++++++++++++++++++- .../GeoHashFrameworkTests/GeoHashTests.swift | 22 ++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..db88274 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "type": "lldb", + "request": "launch", + "args": [], + "cwd": "${workspaceFolder:GeoHashSwift}", + "name": "Debug geohash", + "program": "${workspaceFolder:GeoHashSwift}/.build/debug/geohash", + "preLaunchTask": "swift: Build Debug geohash" + }, + { + "type": "lldb", + "request": "launch", + "args": [], + "cwd": "${workspaceFolder:GeoHashSwift}", + "name": "Release geohash", + "program": "${workspaceFolder:GeoHashSwift}/.build/release/geohash", + "preLaunchTask": "swift: Build Release geohash" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 06588eb..29a77a6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,4 +13,14 @@ "editor.defaultFormatter": "vknabel.vscode-apple-swift-format", "cSpell.words": [], "makefile.configureOnOpen": false, + "swift.sourcekit-lsp.serverArguments": [ + "-Xswiftc", + "-sdk", + "-Xswiftc", + "/Applications/Xcode-16.1.0.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneOS.sdk", + "-Xswiftc", + "-target", + "-Xswiftc", + "arm64-apple-ios18.1-simulator", + ] } diff --git a/Sources/GeoHashFramework/GeoHash.swift b/Sources/GeoHashFramework/GeoHash.swift index e92ca47..e685b06 100644 --- a/Sources/GeoHashFramework/GeoHash.swift +++ b/Sources/GeoHashFramework/GeoHash.swift @@ -154,7 +154,7 @@ extension GeoHash { } } -// MARK: Public getter +// MARK: Public properties and methods extension GeoHash { public var latitudeBits: String { var lat: String = "" @@ -209,6 +209,60 @@ extension GeoHash { return hash } + public func getNeighbors() -> [GeoHash] { + let latitudeBits = self.latitudeBits + let longitudeBits = self.longitudeBits + + let north = add(bits: latitudeBits, by: 1) + let south = add(bits: latitudeBits, by: -1) + let east = add(bits: longitudeBits, by: 1) + let west = add(bits: longitudeBits, by: -1) + + let northEast = combineBits(latitude: north, longitude: east) + let northWest = combineBits(latitude: north, longitude: west) + let southEast = combineBits(latitude: south, longitude: east) + let southWest = combineBits(latitude: south, longitude: west) + + return [ + GeoHash(binary: combineBits(latitude: north, longitude: longitudeBits), precision: precision), + GeoHash(binary: northEast, precision: precision), + GeoHash(binary: combineBits(latitude: latitudeBits, longitude: east), precision: precision), + GeoHash(binary: southEast, precision: precision), + GeoHash(binary: combineBits(latitude: south, longitude: longitudeBits), precision: precision), + GeoHash(binary: southWest, precision: precision), + GeoHash(binary: combineBits(latitude: latitudeBits, longitude: west), precision: precision), + GeoHash(binary: northWest, precision: precision) + ] + } + + /// Add `delta` to `bits` + private func add(bits: String, by delta: Int) -> String { + if let decimal = Int(bits, radix: 2) { + let moved = decimal + delta + // 11 -> 1110 + return String(moved, radix: 2) + } + return bits + } + + /// Combine `latitude` and `longitude` in bits. + private func combineBits(latitude: String, longitude: String) -> String { + var result = "" + let latArray = Array(latitude) + let lngArray = Array(longitude) + let maxLength = max(latArray.count, lngArray.count) + + for i in 0.. [GeoHashCoordinate2D] { // Initial: BottomLeft in zoom-level 0 let baseGeoCoordinate = GeoHash( diff --git a/Tests/GeoHashFrameworkTests/GeoHashTests.swift b/Tests/GeoHashFrameworkTests/GeoHashTests.swift index e62153a..5939cb0 100644 --- a/Tests/GeoHashFrameworkTests/GeoHashTests.swift +++ b/Tests/GeoHashFrameworkTests/GeoHashTests.swift @@ -85,4 +85,26 @@ struct GeoHashTests { } print(count == 131072) // 2^15 * 4 } + + @Test + func getNeighbors() async throws { + // Tokyo Station + let lat = 35.681382 + let lng = 139.766084 + + let expected = [ + "xn76urws", + "xn76urwu", + "xn76urwg", + "xn76urwf", + "xn76urwd", + "xn76urw6", + "xn76urw7", + "xn76urwk" + ] + + let geoHash = GeoHash(latitude: lat, longitude: lng) + let neighbors = geoHash.getNeighbors() + #expect(neighbors.map(\.geoHash) == expected) + } }