Skip to content

Commit

Permalink
Merge pull request #6 from fummicc1/fix-bug
Browse files Browse the repository at this point in the history
Fix bug in obtaining coordinate from geohash
  • Loading branch information
fummicc1 authored Nov 24, 2024
2 parents 2b6be6d + 942e01a commit caee0dc
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 54 deletions.
26 changes: 20 additions & 6 deletions Sources/GeoHashFramework/GeoHash.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,26 @@ extension GeoHash {
let southWest = combineBits(latitude: south, longitude: west)

return [
GeoHash(binary: combineBits(latitude: north, longitude: longitudeBits), precision: precision),
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: combineBits(latitude: latitudeBits, longitude: east),
precision: precision
),
GeoHash(binary: southEast, precision: precision),
GeoHash(binary: combineBits(latitude: south, longitude: longitudeBits), 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)
GeoHash(
binary: combineBits(latitude: latitudeBits, longitude: west),
precision: precision
),
GeoHash(binary: northWest, precision: precision),
]
}

Expand All @@ -240,7 +252,9 @@ extension GeoHash {
if let decimal = Int(bits, radix: 2) {
let moved = decimal + delta
// 11 -> 1110
return String(moved, radix: 2)
// keep bits length
let binary = String(moved, radix: 2)
return binary.padding(toLength: bits.count, withPad: "0", startingAt: 0)
}
return bits
}
Expand Down
1 change: 0 additions & 1 deletion Sources/GeoHashFramework/GeoHashBitsPrecision.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public enum GeoHashBitsPrecision: Sendable, Hashable {
case .mid: return 8 * 5
case .high: return 10 * 5
case .exact(let digits):
precondition(digits % 5 == 0)
return digits
}
}
Expand Down
65 changes: 31 additions & 34 deletions Sources/GeoHashFramework/GeoHashCoordinate2D.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,41 @@ import Foundation
public struct GeoHashCoordinate2D: Sendable, Hashable {
public var latitude: Double
public var longitude: Double

public init(latitude: Double, longitude: Double) {
self.latitude = latitude
self.longitude = longitude
}

public init(binary: String, precision: GeoHashBitsPrecision) {
// 010101010 --> 1111
let latitudeBits = binary.enumerated().filter { $0.offset % 2 == 1 }.map { String($0.element) }
// 010101010 --> 00000
let longitudeBits = binary.enumerated().filter { $0.offset % 2 == 0 }.map { String($0.element) }

// 1111 -> 15
let latitudePrecision = pow(2, Double(latitudeBits.count))
let latitudeDelta = 180.0 / latitudePrecision
// 01000 -> 8/15
let latitudeIndex = latitudeBits.enumerated().reduce(into: 0.0, { partialResult, value in
let (index, bits) = value
if bits == "1" {
partialResult += Double(1 << index)
}
}) / latitudePrecision
self.latitude = latitudeDelta * latitudeIndex - 90.0

// 00000 -> 32
let longitudePrecision = pow(2, Double(longitudeBits.count))
let longitudeDelta = 360.0 / longitudePrecision
// 01000 -> 8/15
let longitudeIndex = Double(
longitudeBits.enumerated().reduce(into: 0.0, { partialResult, value in
let (index, bits) = value
if bits == "1" {
partialResult += Double(1 << index)

}
})
) / longitudePrecision

self.longitude = longitudeDelta * longitudeIndex - 180.0
let latitudeBits = binary.enumerated().filter { $0.offset % 2 == 1 }.map {
String($0.element)
}
let longitudeBits = binary.enumerated().filter { $0.offset % 2 == 0 }.map {
String($0.element)
}

// referring to: https://github.com/nh7a/Geohash/blob/927b1f402650ab18ee0714cf099122606390646c/Sources/Geohash/Geohash.swift#L45-L54
// latitude
let latitudeRange = latitudeBits.enumerated().reduce((-90.0, 90.0)) { result, value in
let (min, max) = result
let mean = Decimal(min + max) / Decimal(2)
let (_, bit) = value
return bit == "1"
? (NSDecimalNumber(decimal: mean).doubleValue, max)
: (min, NSDecimalNumber(decimal: mean).doubleValue)
}
self.latitude = (latitudeRange.0 + latitudeRange.1) / 2.0

// longitude
let longitudeRange = longitudeBits.enumerated().reduce((-180.0, 180.0)) { result, value in
let (min, max) = result
let mean = Decimal(min + max) / Decimal(2)
let (_, bit) = value
return bit == "1"
? (NSDecimalNumber(decimal: mean).doubleValue, max)
: (min, NSDecimalNumber(decimal: mean).doubleValue)
}
self.longitude = (longitudeRange.0 + longitudeRange.1) / 2.0
}
}
33 changes: 20 additions & 13 deletions Tests/GeoHashFrameworkTests/GeoHashTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,27 +55,34 @@ struct GeoHashTests {

@Test
func getBound() async throws {
let precision = GeoHashBitsPrecision.exact(digits: 0)
let actual = GeoHash(
binary: String(repeating: "0", count: precision.rawValue),
// Tokyo Station
let coordinate = GeoHashCoordinate2D(
latitude: 35.681382,
longitude: 139.766084
)
let precision = GeoHashBitsPrecision.low
let geoHash = GeoHash(
latitude: coordinate.latitude,
longitude: coordinate.longitude,
precision: precision
).getBound()
)
let actual = geoHash.getBound()
let expected = [
GeoHashCoordinate2D(
latitude: 90.0,
longitude: -180.0
latitude: 35.68634033203124,
longitude: 139.76257324218756
),
GeoHashCoordinate2D(
latitude: 90.0,
longitude: 180.0
latitude: 35.68634033203124,
longitude: 139.77355957031256
),
GeoHashCoordinate2D(
latitude: -90.0,
longitude: 180.0
latitude: 35.68084716796874,
longitude: 139.77355957031256
),
GeoHashCoordinate2D(
latitude: -90.0,
longitude: -180.0
latitude: 35.68084716796874,
longitude: 139.76257324218756
),
]
#expect(actual == expected)
Expand Down Expand Up @@ -104,7 +111,7 @@ struct GeoHashTests {
"xn76urwd",
"xn76urw6",
"xn76urw7",
"xn76urwk"
"xn76urwk",
]

let geoHash = GeoHash(latitude: lat, longitude: lng)
Expand Down

0 comments on commit caee0dc

Please sign in to comment.