Geohash

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 ์™€ ์—ฐ๊ด€ ๋˜์–ด์žˆ๋‹ค
ย 

์œ ์šฉํ•œ ์›น์‚ฌ์ดํŠธ

  1. geohash explorer: https://geohash.softeng.co/wydm6
    1. geohash visualizer
  1. geohash converter: http://geohash.co/
    1. convert geohash by lat, lng, geohash and precision
ย 
์ถœ์ฒ˜
  • ChatGPT
ย 
โ† Go home