Geocodificación y Geocodificación Inversa en Windows Phone 8

Hola a todos!

En el último artículo hablamos sobre el nuevo control de mapas de Windows Phone 8 y el cálculo y dibujado de rutas e indicaciones. En este artículo vamos a ir un paso más allá. Usaremos el namespace Microsoft.Phone.Maps.Services para acceder a los servicios de geo codificación. Estos nos permitirán “traducir” coordenadas geográficas en direcciones, geo codificación inversa, y direcciones en coordenadas geográficas, geo codificación.

GeocodeQuery

La clase GeocodeQuery nos permite introducir un término de búsqueda y consultar a los servicios cartográficos de Nokia para obtener su representación en coordenadas geográficas. Su uso es muy parecido al RouteQuery que vimos en el artículo anterior. En este caso indicaremos la propiedad SearchTerm con la cadena de texto que deseamos buscar, manejaremos el evento QueryCompleted y llamaremos al método QueryAsync:

GeocodeQuery query = new GeocodeQuery()
{
    GeoCoordinate = new GeoCoordinate(),
    SearchTerm = "Calle Fontecha y Salazar 1, Bilbao"
};

query.QueryCompleted += query_QueryCompleted;
query.QueryAsync();

En el manejador del evento QueryCompleted recibiremos como resultado una lista del tipo MapLocation. Recibimos una lista porque puede que el resultado del término de búsqueda que hemos introducido devuelva más de un resultado:

void query_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
{
    if (e.Error == null)
    {
        Results = new ObservableCollection<MapLocation>(e.Result);
    }
}

Cada objeto MapLocation nos ofrece dos propiedades que nos interesan:

  • GeoCoordinate: Contiene la información geográfica de la coincidencia: Altura, Latitud, Longitud.
  • Information. Contiene información adicional sobre el termino buscado. Principalmente encontraremos información sobre la dirección: Código postal, barrio, país, código ISO de país, ciudad, población…

El resultado de una búsqueda de este tipo podría ser parecido al siguiente (click en la imagen para ampliar):

image

En algunos casos, también obtendremos los valores de la propiedad BoundingBox de MapLocation. Esta propiedad nos indica el centro en coordenadas geográficas y los puntos cardinales como un LocationRectangle con el área que engloba el punto que se nos ha devuelto.

ReverseGeocodeQuery

Ahora que ya hemos visto como obtener una localización geográfica a partir de un término de búsqueda, veamos como obtener una dirección a partir de un punto geográfico. Esta técnica es la que conocemos como geo codificación inversa y nos apoyaremos en la clase ReverseGeocodeQuery para llevar a cabo el trabajo.

Su uso es idéntico a GeocodeQuery, la única diferencia la podemos encontrar en las propiedades que establecemos. Mientras que GeocodeQuery recibe un término de búsqueda y nos devuelve las coordenadas geográficas, ReverseGeocodeQuery recibe coordenadas geográficas y nos devolverá direcciones:

ReverseGeocodeQuery query = new ReverseGeocodeQuery()
{
    GeoCoordinate = new GeoCoordinate(43.26614, -2.92451)
};

query.QueryCompleted += query_QueryCompleted;
query.QueryAsync();

El evento QueryCompleted nos devolverá una lista de MapLocation de la cual podremos obtener toda la información necesaria como la calle, número, código postal… como podemos ver a continuación (click en la imagen para ampliar):

image

MapsSettings

Para concluir este vistazo a los nuevos mapas de Windows Phone 8, vamos a hablar de la clase MapSettings. Esta clase se encuentra en el namespace Microsoft.Phone.Maps y expone dos propiedades: IsMapsDisabled y ApplicationContext.

IsMapsDisabled nos informa si los servicios de mapas están desactivados en el dispositivo.  Estoy investigando que significa esto exactamente, bajo que condiciones pueden estar desactivados y pondré una entrada con las respuestas que obtenga para clarificar el uso de esta propiedad.

ApplicationContext nos permite indicar propiedades que se aplicarán a todo el uso de los mapas o sus servicios. En este caso se trata del ApplicationId y el AuthenticationToken. Podremos obtener estos dos valores cuando vayamos a subir nuestra aplicación a la Windows Phone Store. Después de completar el primer paso con la información general de la aplicación. Se habilitarán las opciones, una de ellas es “Map Services” (click en la imagen para ampliar):

image

Dentro de esta opción podremos pulsar un enlace “Get Token” que nos dará un token y application id válido. Solo tendremos que incluirlo en nuestra aplicación y volver a compilarla para subir el paquete a la Store. Sin este paso, nuestra aplicación no se certificará.

Conclusión

Con lo que vimos en el artículo anterior sobre rutas y este articulo, tenemos toda la información necesaria para realizar cualquier tipo de aplicación que haga uso de los mapas, localización y direcciones. Desde luego se ha simplificado mucho su funcionamiento, ya no dependemos de otros servicios externos y todas las consultas, tanto de rutas como de geo codificación se usan de una manera muy similar.

Espero que disfrutéis y hagáis grandes aplicaciones con esta información. Un saludo y Happy Coding!

Nuevo control de Mapas y calculo de rutas en Windows Phone 8

Hola a todos!

Ya había pasado un tiempo sin escribir, es lo que tiene llegar a la fase final de un libro. De pronto el 5% del trabajo te ocupa el 100% del tiempo. Pero ya estamos aquí otra vez. Hoy quería hablar sobre más novedades y funcionalidades que podemos encontrar en los mapas de Windows Phone 8.

Soy un verdadero enamorado de los nuevos mapas incluidos con el sistema. Si has visto los ejemplos y slides de mis charlas o as acudido a alguna, habrás comprobado lo fácil que es crear mapas visualmente increíbles: con representación de edificios en tres dimensiones, controlando el ángulo de cámara, la inclinación del terreno, el tipo de información para peatones a mostrar… Pero lo realmente increíble de los mapas es que no son solo unos mapas sin más. Alrededor de ellos se encuentra toda una infraestructura que podemos usar en nuestras aplicaciones. En concreto hoy me quiero centrar en el cálculo de rutas y en la geo codificación inversa.

Microsoft.Phone.Maps.Services

Este namespace contiene todas las clases que usaremos para realizar consultas al sistema de mapas de Windows Phone 8. En particular nos centraremos en tres tipos: RouteQuery, que nos permitirá crear rutas con indicaciones, GeocodeQuery, que nos ayudará a resolver direcciones para obtener coordenadas geográficas y ReverseGeocodeQuery, que nos permitirá obtener direcciones a partir de coordenadas geográficas. En este primer artículo de la serie vamos a examinar en profundidad las rutas con RouteQuery.

RouteQuery

En Windows Phone 7.X la única forma, sencilla y mínimamente automatizada, de crear rutas A-B era usar el lanzador BingMapsDirectionsTask. Este lanzador recibía un punto inicial, un punto final y abría la aplicación de mapas del teléfono para mostrarlos. En Windows Phone 8 conservamos este lanzador, al que se ha añadido el MapsDirectionsTask, pero también tenemos la posibilidad de mostrar rutas dentro de un mapa en nuestra aplicación. Una ventaja de usar la clase RouteQuery es que podemos indicar más de dos puntos, inicial y final, y crear rutas con múltiples puntos intermedios.

En primer lugar tendremos que crear una nueva instancia de RouteQuery. Debemos indicar el modo de viaje mediante la propiedad TravelMode. Para ello usaremos el enumerado TravelMode, que nos ofrece dos opciones: Walking o Driving. A continuación también tendremos que indicar los puntos que compondrán al menos el inicio y final de la ruta mediante la propiedad Waypoints. Como mínimo debemos indicar dos puntos, pero podemos añadir n puntos intermedios que deseemos:

RouteQuery query = new RouteQuery()
{
    TravelMode = TravelMode.Walking,
    Waypoints = new List<GeoCoordinate>()
    {
        new GeoCoordinate(43.26614, -2.92451),
        new GeoCoordinate(43.26308, -2.94296)
    }
};

En el ejemplo anterior indicamos solo dos coordenadas y nuestro modo de viaje lo establecemos en “Walking”. Con esto ya hemos creado nuestro objeto RouteQuery. Ahora usaremos el método QueryAsync y manejaremos el evento QueryCompleted para obtener los resultados:

    ...
    query.QueryCompleted += query_QueryCompleted;
    query.QueryAsync();
}

void query_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
    if (e.Error == null)
    {
        if (GetRouteCompleted != null)
            GetRouteCompleted(e.Result, null);
    }
}

En el manejador recibimos los resultados en el parámetro QueryCompletedEventArgs<Route>, en la propiedad Result. Es importante que comprobemos que no se ha producido ningún error. A continuación, como nos encontramos en una ViewModel y tenemos que añadir la ruta al mapa, lanzamos un evento que hemos definido en nuestra ViewModel llamado GetRouteCompleted.

En el code behind de nuestra vista, nos suscribiremos al evento cuando naveguemos a la página y lo eliminaremos al navegar fuera de ella:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    vm.GetRouteCompleted += vm_GetRouteCompleted;
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    vm.GetRouteCompleted -= vm_GetRouteCompleted;
}

En el manejador vm_GetRouteCompleted solo tendremos que usar el método AddRoute del elemento Map para añadir la ruta y que este la dibuje. Adicionalmente, para situar la cámara en el primer punto del recorrido obtenemos las geometrías que componen la ruta. En particular la primera de ellas, que indica el punto de inicio:

private void vm_GetRouteCompleted(object sender, EventArgs e)
{
    var route = new MapRoute((Route)sender);
    GeoCoordinate firstPoint = route.Route.Geometry.First();

    mapElement.Center = firstPoint;
    mapElement.AddRoute(route);
}

Y con esto ya tenemos completado el trabajo para mostrar nuestra ruta en pantalla. Antes de continuar, tenemos que añadir al manifiesto de nuestra aplicación dos capacidades: ID_CAP_MAP e ID_CAP_LOCATION para que funcione correctamente. Una vez añadidas, ejecuta la aplicación y el resultado debería ser algo parecido a lo siguiente:

image

Ya tenemos nuestra ruta calculada y dibujada en el mapa. Además con la posibilidad de poner el mapa en 3D y los edificios queda muy bien. Quizás hechas de menos algo: Indicaciones. Ya que tenemos la ruta, estaría muy bien tener también las indicaciones. Pues las tenemos! Están contenidas en una propiedad llamada Legs dentro de nuestra ruta. En nuestra ViewModel vamos a exponer una colección de RouteManeuvers, el objeto que indica una maniobra. y la vamos a rellenar de la siguiente forma:

void query_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
    if (e.Error == null)
    {
        Maneuvers = new ObservableCollection<RouteManeuver>(e.Result.Legs.SelectMany(l => l.Maneuvers));

        if (GetRouteCompleted != null)
            GetRouteCompleted(e.Result, null);
    }
}

¿Por qué usar un SelectMany? La propiedad Legs es una colección. Esta comprende las instrucciones para ir de un punto hasta el siguiente. Si al realizar la consulta de nuestra ruta hemos indicado tres puntos (A,B,C) tendremos dos Legs: uno con las indicaciones de A-B y otro de B-C. Por lo tanto usamos SelectMany para obtener todas las indicaciones de todos los segmentos de la ruta. A continuación solo nos queda añadir a nuestra interfaz de usuario una lista que muestre los puntos:

<ListBox Grid.Column="1" ItemsSource="{Binding Maneuvers}"
         Background="#66000000">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Margin="0,0,2,5">
                <TextBlock Text="{Binding InstructionKind}"
                           Foreground="{StaticResource PhoneAccentBrush}">
                </TextBlock>
                <TextBlock Text="{Binding InstructionText}"
                           TextWrapping="Wrap">
                </TextBlock>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Principalmente cada objeto Maneuver nos expondrá dos propiedades: InstructionKind e InstructionText. InstructionKind indica el tipo de maniobra: TurnRight, TurnLeft, Start, End… mientras que InstructionText nos dará una descripción más detallada de la misma. Si ejecutamos ahora nuestra aplicación de ejemplo veremos el siguiente resultado:

image

Voila! de una forma rápida y sencilla tenemos nuestra ruta dibujada e indicaciones añadidas en la pantalla. Además del tipo de maniobra y la descripción, cada objeto Maneuver nos ofrece la longitud hasta el siguiente paso en metros y su posición geográfica, con lo que podríamos comprobar cuando nos acercamos al siguiente punto para usar la sintetización de voz de Windows Phone 8 y leer las instrucciones al usuario.

Conclusión

Esta vez, Microsoft ha hecho un gran trabajo con los mapas de Windows Phone 8. Con el apoyo de Nokia nos han dado la oportunidad de crear aplicaciones que hagan un uso intensivo de la cartografía y la localización. A continuación tenéis el ejemplo de este artículo para que le deis un repaso y juguéis con el aprovechando las vacaciones navideñas. Incluye uso de MVVM, Autofac, VMLocator, los mapas y las rutas!

Un saludo y Happy Coding!