Written by Paul
Geohash๋?
Geohash ์์คํ
์ ๋ค์๊ณผ ๊ฐ์ ์บ๋ฆญํฐ์
์ผ๋ก base32 ์ธ์ฝ๋ฉ์ ์ฌ์ฉํ๋ค
0123456789bcdefghjkmnpqrstuvwxyz
๊ฐ๊ฐ์ ๋ฌธ์๋ค์ ๊ทธ๋ฆฌ๋ ๊ฒฉ์์์ ๋ ์์ ์น์
์ ๋ํ๋ธ๋ค. ๋ฌธ์๋ฅผ ํ๋ ๋ ์ถ๊ฐํ๋ ๊ฒ์ ํด๋น ์์ญ์ precision์ ์ฆ๊ฐ์์ผ์ ์์ญ์ ๋๋๋ ๊ฒ์ ์๋ฏธํ๋ค.
preicision์ ์ฆ๊ฐ์ํค๋ ์์ (python)
import geohash # Initial geohash initial_geohash = "wydm" # Increase precision by one level new_geohash = geohash.encode(geohash.decode(initial_geohash), precision=len(initial_geohash) + 1) print(new_geohash)
ย
4x4 ๊ทธ๋ฆฌ๋ ๊ฒฉ์๋ฅผ ๋ํ๋ด๋ geohash๋ฅผ ๊ตฌํ๋ ์์ (python)
# Base32 character set used in geohashes, arranged for a 4x4 grid selection base32_grid = [ "0123", "4567", "89bc", "defg", "hjk", "mnpq", "rst", "vwxyz" ] # Initial geohash initial_geohash = "wydm" # Function to get a 4x4 grid subset def get_4x4_geohashes(initial_geohash): more_precise_geohashes = [] # Iterate over the rows and columns of the grid for row in range(4): # Adjust the range to get the row block you want (e.g., first 4 rows) for col in range(4): # Adjust the range to get the column block you want (e.g., first 4 columns) more_precise_geohashes.append(initial_geohash + base32_grid[row][col]) return more_precise_geohashes # Get the 4x4 geohashes subset subset_geohashes = get_4x4_geohashes(initial_geohash) # Print the narrowed-down geohashes for geohash in subset_geohashes: print(geohash)
ย
typescript geohash ์์
4x4 ์๋ธ์
๊ตฌํ๊ธฐ
// Base32 character set used in geohashes, arranged for a 4x4 grid selection const base32Grid: string[] = [ "0123", "4567", "89bc", "defg", "hjk", "mnpq", "rst", "vwxyz" ]; // Initial geohash const initialGeohash: string = "wydm"; // Function to get a 4x4 grid subset function get4x4Geohashes(initialGeohash: string): string[] { const morePreciseGeohashes: string[] = []; // Iterate over the rows and columns of the grid for (let row = 0; row < 4; row++) { // Adjust the range to get the row block you want (e.g., first 4 rows) for (let col = 0; col < 4; col++) { // Adjust the range to get the column block you want (e.g., first 4 columns) morePreciseGeohashes.push(initialGeohash + base32Grid[row][col]); } } return morePreciseGeohashes; } // Get the 4x4 geohashes subset const subsetGeohashes: string[] = get4x4Geohashes(initialGeohash); // Print the narrowed-down geohashes subsetGeohashes.forEach(geohash => console.log(geohash));
ย
4x8 ์๋ธ์
๊ตฌํ๊ธฐ
// Base32 character set used in geohashes, arranged for a grid selection const base32Grid: string[] = [ "0123", // Row 1 "4567", // Row 2 "89bc", // Row 3 "defg", // Row 4 "hjk", // Row 5 "mnpq", // Row 6 "rst", // Row 7 "vwxyz" // Row 8 ]; // Initial geohash const initialGeohash: string = "wydm"; // Function to get a 4x8 grid subset function get4x8Geohashes(initialGeohash: string): string[] { const morePreciseGeohashes: string[] = []; // Iterate over 4 rows and 8 columns of the grid for (let row = 0; row < 4; row++) { // First 4 rows for (let col = 0; col < 8; col++) { // All 8 columns morePreciseGeohashes.push(initialGeohash + base32Grid[row][col % 4]); // Use modulus for column wrap } } return morePreciseGeohashes; } // Get the 4x8 geohashes subset const subsetGeohashes: string[] = get4x8Geohashes(initialGeohash); // Print the narrowed-down geohashes subsetGeohashes.forEach(geohash => console.log(geohash));
ย
ย
geohash ๊ด๋ จ ์ ์ฉํ npm library
ngeohash
commonjs ๋ก ์์ฑ๋ pure js ์ฝ๋๋ผ์, ๋
ธ๋์์ ์ฌ์ฉํ๊ธฐ ํธ๋ฆฌํ๋ค
๋ง์ฝ ํ์
์ ์ง์ํ๊ณ ์ถ๋ค๋ฉด,
@types/ngeohash
๋ฅผ ์ธ์คํจ ํ๋ฉด ๋ ๊ฒ์ด๋คย
latlon-geohash
ES6 ๋ฌธ๋ฒ์ผ๋ก ์์ฑ๋์ด ์์ด์, commonjs ๋ก ์ด๋ฃจ์ด์ง ํ๋ก์ ํธ๋ผ๋ฉด ๋ฐ๋ก ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅ ํ๋ค
package.json์์ ๋ฐ๋ก ESM ์ฒ๋ฆฌ๊ฐ ๋์ด์์ง ์๋ค
๋ง์ฐฌ๊ฐ์ง๋ก ํ์
์ง์์ ์ํ๋ค๋ฉด
@types/latlon-geohash
๋ฅผ ์ธ์คํจ ํ๋ฉด ๋ ๊ฒ์ด๋คย
ย
geohash ๊ฐ ๋์ํ๋ ๋ฐฉ์
์ง๊ตฌ๋ฅผ grid cell๋ก ๋๋๋ค
์๋์ ๊ฒฝ๋ (latitude, longitude) ๊ฐ์ ๋ผ์๋ฃ๋๋ค
binary๋ฅผ base32 ๋ก ์ปจ๋ฒํ
ํ๋ค
preicision์ ์กฐ์ ํ๋ค. ๋ ๊ธด hash์ ๋ฌธ์์ด ๊ธธ์ด ๊ฐ์ผ ์๋ก ๋ ์ ํํจ์ ์๋ฏธํ๋ค
ย
typescript geohash ์๊ณ ๋ฆฌ์ฆ
const BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz"; // Geohash base32 map const BITS = [16, 8, 4, 2, 1]; interface LatLngBounds { minLat: number; maxLat: number; minLng: number; maxLng: number; } /** * Encodes latitude and longitude into a Geohash string * @param lat Latitude value * @param lng Longitude value * @param precision The length of the resulting Geohash string (default: 12) * @returns Geohash string */ function encode(lat: number, lng: number, precision: number = 12): string { let idx = 0; // Index in BASE32 map let bit = 0; // Current bit in BITS array let even = true; // Alternating between latitude and longitude let geohash = ''; // Resulting geohash string let latRange = { min: -90.0, max: 90.0 }; let lngRange = { min: -180.0, max: 180.0 }; while (geohash.length < precision) { if (even) { const mid = (lngRange.min + lngRange.max) / 2; if (lng >= mid) { idx = idx | BITS[bit]; lngRange.min = mid; } else { lngRange.max = mid; } } else { const mid = (latRange.min + latRange.max) / 2; if (lat >= mid) { idx = idx | BITS[bit]; latRange.min = mid; } else { latRange.max = mid; } } even = !even; if (bit < 4) { bit++; } else { geohash += BASE32[idx]; bit = 0; idx = 0; } } return geohash; } /** * Decodes a Geohash string back into latitude and longitude * @param geohash Geohash string * @returns An object containing latitude, longitude, and the bounds */ function decode(geohash: string): { lat: number, lng: number, bounds: LatLngBounds } { let even = true; let latRange = { min: -90.0, max: 90.0 }; let lngRange = { min: -180.0, max: 180.0 }; for (let i = 0; i < geohash.length; i++) { const char = geohash[i]; const idx = BASE32.indexOf(char); for (let j = 0; j < 5; j++) { const bit = (idx >> (4 - j)) & 1; if (even) { const mid = (lngRange.min + lngRange.max) / 2; if (bit === 1) { lngRange.min = mid; } else { lngRange.max = mid; } } else { const mid = (latRange.min + latRange.max) / 2; if (bit === 1) { latRange.min = mid; } else { latRange.max = mid; } } even = !even; } } const lat = (latRange.min + latRange.max) / 2; const lng = (lngRange.min + lngRange.max) / 2; return { lat: lat, lng: lng, bounds: { minLat: latRange.min, maxLat: latRange.max, minLng: lngRange.min, maxLng: lngRange.max } }; } // Example usage const geohash = encode(37.7749, -122.4194); // Encode San Francisco coordinates console.log(`Geohash: ${geohash}`); const location = decode(geohash); // Decode the geohash back into coordinates console.log(`Decoded Location: Lat ${location.lat}, Lng ${location.lng}`);
ย
์ฐธ๊ณ ) BITS ๋ณ์๋ base32 ์ ์ฐ๊ด ๋์ด์๋ค
ย
์ ์ฉํ ์น์ฌ์ดํธ
- geohash explorer: https://geohash.softeng.co/wydm6
- geohash visualizer
- geohash converter: http://geohash.co/
- convert geohash by lat, lng, geohash and precision
ย
์ถ์ฒ
- ChatGPT
ย