El sistema de geolocalización Geohash

Geohash

Recientemente mirando el soporte de elasticsearch para el tratamiento de puntos geográficos vimos su soporte para este sistema de geolocalización.

No es muy conocido por lo que no viene mal hacer un pequeño resumen de en qué consiste.

Geohash como hemos dicho un sistema de geolocalización.

Consiste en dividir el globo en cuadrículas de 32 celdas, formadas por 4 filas y 8 columnas. Cada una de las celdas puede ser a su vez dividida de nuevo en otras 32 celdas, igualmente en 4 filas y 8 columnas, y así sucesivamente.

La primera división de celdas sería algo similar a la siguiente imagen.

Geohash

Cuando más veces dividamos las celdas la precisión de la geolocalización será mayor.

La primera cuadrícula de todas tiene una precisión de unos 5000kms x 5000kms, y si vamos dividiendo cada cuadricula en otras 32 celdas iríamos obteniendo cuadriculas de 1,250kms x 625kms, 156kms x 156kms etc.

Con este sistema de geolocalización conseguimos representar un punto del globo mediante una cadena de texto en vez de mediante el sistema de coordenadas habitual (latitud, longitud).

Así por ejemplo, el Museo nacional de Ciencias Naturales de Madrid, situado cerca de Paseo de la Castellana 80, lo podemos representar como:

  • Sistema de coordenadas tradicional (latitud, longitud): 40.44045 -3.69031
  • Sistema de geolocalización geohash: ezjqh1by9w3

Como vemos ezjqh1by9w3 es la cadena que representa ese punto geográfico. Y en este caso hemos dividido las celdas hasta 11 veces.

El mismo punto pero con menos precisión lo podemos representar en diferentes niveles o distintos número de veces en los que dividimos las celdas.

Así por ejemplo el punto ezjqh1by9w3 lo podemos representar como:

  • ezjqh1by9w
  • ezjqh1by9
  • ezjqh1by
  • y así sucesivamente

Cuando más corto sea esta cadena, menos celdas hemos dividido y la precisión será por tanto menor.

Visualizadores y conversores de puntos geohash

El proceso de división de las celdas en cuadrículas sigue un algoritmo. Existen varios sitios online y librerías donde tenemos la implementación de dicho algoritmos. Vamos a mencionar un sitio online donde podemos hacer estas conversiones.

Convertir coordenadas en grados, minutos y segundos a su valor en grados decimales en Java

Java

Existen varias formas de convertir las coordenadas representadas en grados, minutos y segundos a su representación en grados decimales.

El objetivo es pasar de

  • latitud: 40° 20.2′ 55.68
  • longitud: 3° 21′ 3.29

a

  • latitud: 40.352133333333335
  • longitud: 3.350913888888889

Ejemplo de clase Java

public class LatLongUtils {

    public static Double[] toDecimal(String latitude, String longitude) {
        try {
            String[] lat = latitude.replaceAll("[^0-9.\\s-]", "").split(" ");
            String[] lng = longitude.replaceAll("[^0-9.\\s-]", "").split(" ");
            Double dlat = toDecimal(lat); 
            Double dlng = toDecimal(lng);
            return new Double[]{dlat, dlng};
        } catch(Exception ex) {
            log.error(String.format("Error en el formato de las coordenadas: %s %s", new Object[]{latitude, longitude}), ex);
            return null;
        }
    }

    public static Double toDecimal(String latOrLng) {
        try {
            String[] latlng = latOrLng.replaceAll("[^0-9.\\s-]", "").split(" ");
            Double dlatlng = toDecimal(latlng); 
            return dlatlng;
        } catch(Exception ex) {
            log.error(String.format("Error en el formato de las coordenadas: %s ", new Object[]{latOrLng}), ex);
            return null;
        }
    }

    public static Double toDecimal(String[] coord) {
        double d = Double.parseDouble(coord[0]);
        double m = Double.parseDouble(coord[1]);
        double s = Double.parseDouble(coord[2]);
        double signo = 1;
        if (coord[0].startsWith("-"))
            signo = -1;
        return signo * (Math.abs(d) + (m / 60.0) + (s / 3600.0));
    }

    public static void main(String[] args) {
        Double[] coord = toDecimal("40° 20.2' 55.68\"", "3° 21' 3.29\"");
        System.out.println(coord[0] + " " + coord[1]);
    }

}