martes, 9 de octubre de 2012

API Google Maps y Visual Basic.NET. Parte III. Codificación geográfica

En el tutorial de hoy vamos a ver cómo obtener la latitud y longitud a partir de una determinada dirección, por ejemplo, le indicaremos a nuestra aplicación que nos muestre las coordenadas de "Puerta del Sol, Madrid" y nos mostrará las coordenadas (40.4168762,-3.7033046). A este proceso se le llama codificación geográfica, según la definición de la documentación oficial es, "el proceso de transformar direcciones (como "1600 Amphitheatre Parkway, Mountain View, CA") en coordenadas geográficas (como 37.423021 de latitud y -122.083739 de longitud), que se pueden utilizar para colocar marcadores o situar el mapa".
Vamos a ver que es un poco más complejo que las partes anteriores (I y II), pero es fácilmente entendible. Primeramente explicaremos cómo hacer nuestra petición mediante un solicitud HTTP, es decir, cómo tenemos que crear nuestra URL para que nos devuelva la información.
Un ejemplo sería:
Con esto vemos que debemos incluir primeramente "http://maps.googleapis.com/maps/api/geocode/xml?" y después los parámetro que los vamos a explicar a continuación.

PARÁMETROS
  • Address  (obligatorio) (dirección): se trata de la dirección a partir de la cuál queremos obtener la latitud/longitud. Es aconsejable indicar las unidades geográficas separadas por comas (por ejemplo, "Puerta del Sol, Madrid, España") y también se debe (aunque no es obligatorio) eliminar los espacios y sustituirlos por "+". Es decir, una dirección correcta sería, Puerta+de+Sol,+Madrid,+España. Todo esto debe aparece acompañado de "address=", en resumen, quedaría: address=Puerta+de+Sol,+Madrid,+España.

  • Region: este es un parámetro opcional y hace que al realizar la búsqueda dé prioridad a resultados de la región seleccionada, es decir, si buscamos la ciudad de León habiendo puesto como región España, el primer resultado será de León (España), en cambio, si ponemos como región México, nos aparece como primer resultado la ciudad de León (México). Para establecer la región hay que incluir la sentencia "region=" y la región que queremos, por ejemplo para España sería, "region=es". Entra aquí para más información sobre los códigos.

  • Language (idioma): es el idioma en el que se devuelven los resultados, aquí podemos ver los idiomas disponibles. Para seleccionar español la sentencia sería, "language=es"

  • Sensor (obligatorio): determina si la petición procede de un dispositivo con sensor (por ejemplo un receptor GNSS (GPS) de un teléfono móvil). Se puede seleccionar entre true o false. Un ejemplo sería, "sensor=false".

Estos serían los parámetros que vamos a usar, hay otro parámetro más "bound" pero por ahora no lo utilizaremos. Para separar los parámetros hay que utilizar el carácter "&", es decir, si por ejemplo sólo utilizamos "address" y "sensor" (puesto que son obligatorios) habría que separar las sentencias con "&", "address=Puerta+de+Sol,+Madrid,+España&sensor=false". 

Un ejemplo completo sería:
Si hacemos clic sobre el enlace anterior vamos a ver que el navegador nos muestra un archivo xml.


Y lo que tenemos que hacer con Visual Basic es recuperar la información para mostrarla al usuario.
Ahora que sabemos la teoría, vamos a programarlo:
Abrimos Visual Basic y creamos un nuevo proyecto y añadimos simplemente 3 TextBox (txtdireccion, txtlatitud, txtlongitud) y un Button, quedaría algo así:


Primero vamos a realizar unas declaraciones:

Imports System.Net
Imports System.IO
Imports System.Xml.XPath


A continuación vamos a crear es una función con la que gestionaremos la petición y devolveremos la latitud/longitud encontrada:

Public Function CodificacionGeografica(ByVal direccion As String, Optional ByVal regionBusqueda As String = "es", Optional ByVal idioma As String = "es", Optional ByVal sensor As Boolean = False) 'busca latitud/longitud a partir de dirección

        'La función recibe 4 parámetros. La región, idioma y sensor son opcionales.

        'Creamos la dirección
        Dim direccion1 As String
        direccion1 = "address=" & direccion

        'Creamos la region
        Dim region1 As String
        region1 = "region=" & regionBusqueda

        'Creamos el idioma
        Dim idioma1 As String
        idioma1 = "language=" & idioma

        'Creamos el sensor
        Dim sensor1 As String
        sensor1 = "sensor=" & sensor.ToString.ToLower

        'Creamos la URL con los datos
        Dim url = "http://maps.googleapis.com/maps/api/geocode/xml?" + direccion1 + "&" + region1 + "&" + idioma1 + "&" + sensor1

        Dim LatLong As New ArrayList() 'Creamos un arraylist en el que almacenaremos toda la información

        'Creamos una petición http y asignamos un tiempo máximo de espera de 3000 milisegundos
        Dim req As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
        req.Timeout = 3000
        'Preparamos el archivo xml
        Dim res As System.Net.WebResponse = req.GetResponse()
        Dim responseStream As Stream = res.GetResponseStream()
        Dim NodeIter As XPathNodeIterator
        Dim docNav As New XPathDocument(responseStream)
        Dim nav = docNav.CreateNavigator

        Dim ExLatitud, ExLongitud As String 'Variables para buscar dentro del archivo xml

        'Creamos los paths
        ExLatitud = "GeocodeResponse/result/geometry/location/lat"
        ExLongitud = "GeocodeResponse/result/geometry/location/lng"

        'Recorremos el xml
        NodeIter = nav.Select(ExLatitud)
        While (NodeIter.MoveNext())
            LatLong.Add(NodeIter.Current.Value)
            Exit While
        End While

        NodeIter = nav.Select(ExLongitud)
        While (NodeIter.MoveNext())
            LatLong.Add(NodeIter.Current.Value)
            Exit While
        End While

        responseStream.Close() 'Cerramos la conexión
        Return LatLong 'Devolvemos el arraylist con los datos
    End Function


Ahora hacemos doble clic sobre el botón y hacemos la llamada a la función:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 If txtdireccion.Text <> "" Then 'Si hay escrito algo en el texbox dirección
            Dim datos As New ArrayList 'Creamos arraylist en el que almacenamos la información       
            datos = CodificacionGeografica(txtdireccion.Text.ToString.Replace(" ", "+"), , , )
        If datos.Count > 1 Then 'Si se ha almacenado al menos dos datos
                txtlatitud.Text = datos(0)  'Mostramos el primer resultado almacenado
                txtlongitud.Text = datos(1)  'Mostramos el segundo resultado almacenado
            Else
                txtlatitud.Text = "No encontrado"
                txtlongitud.Text = "No encontrado"
            End If
        End If
    End Sub





Como vemos es una proceso bastante sencillo, se podrían mejorar muchas cosas, por ejemplo, el archivo xml tiene un campo status que nos proporciona información sobre posibles errores, o mostrar la dirección encontrada. Esto lo veremos en próximos artículos.
Podéis descargar el código fuente aquí.
Documentación oficial sobre codificación geográfica:
https://developers.google.com/maps/documentation/geocoding/?hl=es-AR




9 comentarios:

  1. Ok, Buen aporte!!! funciona correctamente
    Saludos

    ResponderEliminar
  2. Te Agradezco de Gran Ayuda compartir tus conocimientos, un saludo desde Viña del Mar, Chile

    ResponderEliminar
  3. Me alegro que os sirva de ayuda ;)

    ResponderEliminar
  4. Muchas gracias por la ayuda.

    ResponderEliminar
  5. Te falto poner en el post el .ToLower despues del .ToString, porque si no lo pongo siempre me sale "No encontrado":

    Dim sensor1 As String
    sensor1 = "sensor=" & sensor.ToString

    Saludos desde Perú

    ResponderEliminar
    Respuestas
    1. Gracias por el aviso ;), ya lo he modificado.

      Eliminar
  6. muy buen aporte el problema que te consulto yo tengo un proxy y me da un error 407. se requiere autorizacion, pero yo tengo lña autorizacion...
    Dim res As System.Net.WebResponse = req.GetResponse() en esta linea me sale el error 407.
    gracias

    ResponderEliminar
  7. Luis, me ha servido mucho tu información, he estado tratando de agregar marcadores al mapa pero no he podido, la idea es dejar una señal en el mapa y obtener las coordenadas de un punto especifico al hacer clic sobre el, me puedes ayudar por favor?

    ResponderEliminar
    Respuestas
    1. Hola!
      Para eso tendrás que utilizar el API de Javascript para Google Maps
      https://developers.google.com/maps/documentation/javascript/overlays?hl=es#Icons

      Eliminar