none
Ayuda con geolocalizacion! RRS feed

  • Pregunta

  • Hola gente!

    Tengo una Base de Datos en la Nube que contiene coordenada de ciertos lugares que meti en ella, como puedo hacer para que una aplicacion que estoy haciendo en WP7 me muestre los lugares que estan cerca mio dependiendo de mi ubicacion, osea la que me da el telefono? Ya tengo la ubicacion que me da el telefono, sin embargo no se como hacer para que me traiga los lugares que estan cerca, no todos los que estan en la Base de Datos.

    Esto lo pregunto porque soy bastante nuevo con lo que es servicios de geolocalizacion en WP7, etc...

    Alguna idea, alguien ha hecho algo similar?

     

    Saludos!!


    Salas
    • Editado ERIC SALAS miércoles, 30 de noviembre de 2011 22:48
    miércoles, 30 de noviembre de 2011 22:46

Respuestas

  • Hola Eric,

    Yo estoy trabajando en una aplicación que hace exactamente eso que pides. Yo lo he hecho ordenando mis localizaciones en función de la formula Haversine (http://es.wikipedia.org/wiki/F%C3%B3rmula_del_Haversine) que es la que permite medir la distancia real entre dos posiciones en el globo. Y por último haciendo un top por si quiero obtener un número limitado o en la cláusula WHERE incluir una condición en función de dicha fórmula.

    Te copio dos implementaciones de la fórmula Haversine, una en C# y otra en SQL (MS SQL Server):

    C#:

        /// <summary>
        /// The distance type to return the results in.
        /// </summary>
        public enum DistanceType { Miles, Kilometers };
     
        /// <summary>
        /// Specifies a Latitude / Longitude point.
        /// </summary>
        public struct Position
        {
            public double Latitude;
            public double Longitude;
        }
     
        class Haversine
        {
            /// <summary>
            /// Returns the distance in miles or kilometers of any two
            /// latitude / longitude points.
            /// </summary>
            /// <param name=”pos1″></param>
            /// <param name=”pos2″></param>
            /// <param name=”type”></param>
            /// <returns></returns>
            public double Distance(Position pos1, Position pos2,DistanceType type)
            {
                double R = (type == DistanceType.Miles) ? 3960 : 6371;
     
                double dLat = this.toRadian(pos2.Latitude – pos1.Latitude);
                double dLon = this.toRadian(pos2.Longitude – pos1.Longitude);
     
                double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
                    Math.Cos(this.toRadian(pos1.Latitude)) *Math.Cos(this.toRadian(pos2.Latitude)) *
                    Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
                double c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
                double d = R * c;
     
                return d;
            }
     
            /// <summary>
            /// Convert to Radians.
            /// </summary>
            /// <param name=”val”></param>
            /// <returns></returns>
            private double toRadian(double val)
            {
                return (Math.PI / 180) * val;
            }
        }
    

    SQL:

    CREATE FUNCTION [dbo].[GetDistance]
    
    (
          @lat1 Float(8),
          @long1 Float(8),
          @lat2 Float(8),
          @long2 Float(8)
    )
    RETURNS Float(8)
    AS
    BEGIN
     
          DECLARE @R Float(8);
          DECLARE @dLat Float(8);
          DECLARE @dLon Float(8);
          DECLARE @a Float(8);
          DECLARE @c Float(8);
          DECLARE @d Float(8);
     
          SET @R = 3960;
          SET @dLat = RADIANS(@lat2 - @lat1);
          SET @dLon = RADIANS(@long2 - @long1);
     
          SET @a = SIN(@dLat / 2) * SIN(@dLat / 2) + COS(RADIANS(@lat1))
                            * COS(RADIANS(@lat2)) * SIN(@dLon / 2) *SIN(@dLon / 2);
          SET @c = 2 * ASIN(MIN(SQRT(@a)));
          SET @d = @R * @c;
     
          RETURN @d;
     
    END
    GO
    

    Si te sirve marca la respuesta como correcta por favor :)


    Eugenio Estrada @eugenioestrada mail@eugenioestrada.es
    • Marcado como respuesta ERIC SALAS jueves, 1 de diciembre de 2011 3:15
    miércoles, 30 de noviembre de 2011 23:37

Todas las respuestas

  • Hola Eric,

    Yo estoy trabajando en una aplicación que hace exactamente eso que pides. Yo lo he hecho ordenando mis localizaciones en función de la formula Haversine (http://es.wikipedia.org/wiki/F%C3%B3rmula_del_Haversine) que es la que permite medir la distancia real entre dos posiciones en el globo. Y por último haciendo un top por si quiero obtener un número limitado o en la cláusula WHERE incluir una condición en función de dicha fórmula.

    Te copio dos implementaciones de la fórmula Haversine, una en C# y otra en SQL (MS SQL Server):

    C#:

        /// <summary>
        /// The distance type to return the results in.
        /// </summary>
        public enum DistanceType { Miles, Kilometers };
     
        /// <summary>
        /// Specifies a Latitude / Longitude point.
        /// </summary>
        public struct Position
        {
            public double Latitude;
            public double Longitude;
        }
     
        class Haversine
        {
            /// <summary>
            /// Returns the distance in miles or kilometers of any two
            /// latitude / longitude points.
            /// </summary>
            /// <param name=”pos1″></param>
            /// <param name=”pos2″></param>
            /// <param name=”type”></param>
            /// <returns></returns>
            public double Distance(Position pos1, Position pos2,DistanceType type)
            {
                double R = (type == DistanceType.Miles) ? 3960 : 6371;
     
                double dLat = this.toRadian(pos2.Latitude – pos1.Latitude);
                double dLon = this.toRadian(pos2.Longitude – pos1.Longitude);
     
                double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
                    Math.Cos(this.toRadian(pos1.Latitude)) *Math.Cos(this.toRadian(pos2.Latitude)) *
                    Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
                double c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
                double d = R * c;
     
                return d;
            }
     
            /// <summary>
            /// Convert to Radians.
            /// </summary>
            /// <param name=”val”></param>
            /// <returns></returns>
            private double toRadian(double val)
            {
                return (Math.PI / 180) * val;
            }
        }
    

    SQL:

    CREATE FUNCTION [dbo].[GetDistance]
    
    (
          @lat1 Float(8),
          @long1 Float(8),
          @lat2 Float(8),
          @long2 Float(8)
    )
    RETURNS Float(8)
    AS
    BEGIN
     
          DECLARE @R Float(8);
          DECLARE @dLat Float(8);
          DECLARE @dLon Float(8);
          DECLARE @a Float(8);
          DECLARE @c Float(8);
          DECLARE @d Float(8);
     
          SET @R = 3960;
          SET @dLat = RADIANS(@lat2 - @lat1);
          SET @dLon = RADIANS(@long2 - @long1);
     
          SET @a = SIN(@dLat / 2) * SIN(@dLat / 2) + COS(RADIANS(@lat1))
                            * COS(RADIANS(@lat2)) * SIN(@dLon / 2) *SIN(@dLon / 2);
          SET @c = 2 * ASIN(MIN(SQRT(@a)));
          SET @d = @R * @c;
     
          RETURN @d;
     
    END
    GO
    

    Si te sirve marca la respuesta como correcta por favor :)


    Eugenio Estrada @eugenioestrada mail@eugenioestrada.es
    • Marcado como respuesta ERIC SALAS jueves, 1 de diciembre de 2011 3:15
    miércoles, 30 de noviembre de 2011 23:37
  • Hola gracias!

    Me podrias enseñar un ejemplo con valores reales? Sobre todo en los parametros que recibe el metodo Distance!

    Sin duda me puede ayudar, pero como aun soy novato comprendo a medias!


    Salas
    miércoles, 30 de noviembre de 2011 23:45
  • La función Haversine lo único que optiene son una longitud y latitud de origen y una longitud y latitud de destino y en función de eso te calcula una distancia, la implementación de C# que te puse además tiene un parámetro extra que es si quieres la distancia en kilómetros o en millas. Una llamada podría ser:

    // La posición del móvil
    Position posicionUsuario = new Position();
    posicionUsuario.Latitude = -84.572060585022;
    posicionUsuario.Longitude = 39.2226533889771;
    
    // La posición de lo otro que quieras calcular
    Position posicionLocal = new Position();
    posicionUsuario.Latitude = -84.172060585022;
    posicionUsuario.Longitude = 40.2226533889771;
    
    // Distancia real entre los dos puntos geográficos
    Double distancia = Distance(posicionUsuario, posicionLocal, DistanceType.Kilometers);
    
    Haciendo esto para cada uno de los puntos que tienes en tu base de datos puedes saber cuales son los más cercanos al punto "posicionUsuario"


    Eugenio Estrada @eugenioestrada mail@eugenioestrada.es
    miércoles, 30 de noviembre de 2011 23:51
  • Un detalle a tener en cuenta, al usar las distintas ecuaciones (como la indicada) es el ELIPSOIDE de referencia...caso contrario, la fórmula hará cálculos considerando una esfera...lo que obviamente no es real.

    En el caso de WP7, la posición que indica la API, está referenciada al elipsoide WGS84.

    Fijense, que no en vano, la mayoría de los GPS trae en los settings, la posibilidad de elegir el elipsoide de referencia.


    Gus
    jueves, 1 de diciembre de 2011 2:51
  • Saludos Gus! Podrias explicarme un poco mas eso que dijiste?

    Mi idea es que con el GeoCoordinateWatcher tomar la latitud y longitud de mi telefono segun donde este, y despues aplicarle el algoritmo que me indicaron mas arriba, pero no se si hay algun tipo de problema segun lo que dijiste?


    Salas
    jueves, 1 de diciembre de 2011 3:15
  • Oye gracias! Lo he probado en el emulador, metiendo un par de coordenadas y haciendo el calculo de la distancia y me ha servido!

    Ahora bien: me puedes explicar mas sobre esta linea de codigo?

      public enum DistanceType { Miles, Kilometers };


    Salas
    jueves, 1 de diciembre de 2011 3:18
  • Saludos Gus! Podrias explicarme un poco mas eso que dijiste?

    Mi idea es que con el GeoCoordinateWatcher tomar la latitud y longitud de mi telefono segun donde este, y despues aplicarle el algoritmo que me indicaron mas arriba, pero no se si hay algun tipo de problema segun lo que dijiste?


    Salas


    Hola Eric,

    El tema es complejo y largo, como para este foro. Pero tené en cuenta que hay 72 elipsoides (definidos en el EPSG Dataset) que se usan en forma regular.

    Si tu app, no requiere de gran precisión en los cálculos ( o rigurosidad ) no me preocuparía por el tema y lo dejaría como está.

    Como decía antes, la API de WP7 genera valores para el WGS84, que es el más usado. Igual aclaro que este dato NO está documentado por MSFT.

    Lo importante, es saber que si te importa, deberías hacer las correcciones correspondientes. Saludos!


    Gus
    jueves, 1 de diciembre de 2011 11:36