2012-10-11 60 views
20

Estoy trabajando en una aplicación en la que tengo que llegar cerca del lugar, mi servicio web recibirá 2 parámetros (longitud decimal, latitud decimal)Encuentra ubicación más cercana con la longitud y latitud

Tengo una tabla donde las ubicaciones se guardan en la base de datos con campos de longitud y latitud,

Quiero recuperar las ubicaciones más cercanas.

¿Alguien puede ayudar?

Aquí está mi código:

var locations = from l in locations 

    select l 

Aquí están más detalles acerca de esto: tengo un 2 campos (decimal (18, 2) null) 1 latitud, 2 longitud dentro de una tabla de base de datos,

y tengo un método

public List<Locations> GetLocation(decimal? Long, decimal? lat) 
{ 
var Loc = from l in Locations 
    //// now here is how to get nearest location ? how to query? 
    //// i have also tried Math.Abs(l.Lat - lat) its giving error about nullable decimal always hence i have seted decimal to nullable or converted to nullable 
//// also i have tried where (l.lat - Lat) * (l.lon - Long) this is also giving error about can not convert decimal to bool 
return Loc.ToList(); 
} 
+0

Código? Muy breve ... ¿Qué has intentado sofar? – lboshuizen

Respuesta

4

Aquí es la solución

var constValue = 57.2957795130823D 

var constValue2 = 3958.75586574D; 

var searchWithin = 20; 

double latitude = ConversionHelper.SafeConvertToDoubleCultureInd(Latitude, 0), 
        longitude = ConversionHelper.SafeConvertToDoubleCultureInd(Longitude, 0); 
var loc = (from l in DB.locations 
let temp = Math.Sin(Convert.ToDouble(l.Latitude)/constValue) * Math.Sin(Convert.ToDouble(latitude)/constValue) + 
           Math.Cos(Convert.ToDouble(l.Latitude)/constValue) * 
           Math.Cos(Convert.ToDouble(latitude)/constValue) * 
           Math.Cos((Convert.ToDouble(longitude)/constValue) - (Convert.ToDouble(l.Longitude)/constValue)) 
          let calMiles = (constValue2 * Math.Acos(temp > 1 ? 1 : (temp < -1 ? -1 : temp))) 
          where (l.Latitude > 0 && l.Longitude > 0) 
          orderby calMiles 

select new location 
    { 
    Name = l.name 
    }); 
    return loc .ToList(); 
+0

demasiado código – cyclical

+1

¿Cuáles son los valores constantes? –

+0

El nombre 'ConversionHelper' no existe en el contexto actual. ,¿Cómo resolver? –

2

¿tiene un rango válido, fuera de la cual el "éxito" no es realmente relevante? Si es así, use

from l in locations where ((l.lat - point.lat) * (l.lat - point.lat)) + ((l.lng - point.lng) * (l.lng - point.lng)) < (range * range) select l 

luego encuentre el resultado con el menor valor de distancia al cuadrado dentro de un bucle de esos resultados.

+0

No creo que la comparación de distancia euclidiana se aplique a la longitud/latitud. – Fung

+0

Para rangos pequeños (<3 en lat/lng coords), debería estar bien ... –

+0

lat y longs no son cuadrados, cerca de ecuador tal vez, pero no en ningún otro lado ... – sasjaq

44

Primero puede convertir los datos de ubicación en la base de datos a System.Device.Location.GeoCoordinate, luego use LINQ para encontrar el más cercano.

var coord = new GeoCoordinate(latitude, longitude); 
var nearest = locations.Select(x => new GeoCoordinate(x.Latitude, x.Longitude)) 
         .OrderBy(x => x.GetDistanceTo(coord)) 
         .First(); 
+2

+1 ¡Bonito hallazgo! Sin embargo, tuve que agregar una referencia a 'System.Device', ¡pero funciona muy bien! buen código gracias! –

+0

Brillante respuesta, esto. +1. –

+1

¿Las ubicaciones deben estar en la memoria? en otras palabras: ¿es posible hacer esto en Linq-To-Entities puro (traducido a SQL)? – sports

2

Para más detalles sobre el comentario de @Fung, si está utilizando Entity Framework/LINQ a Entidades, si se intenta utilizar el método GeoCoordinate.GetDistanceTo en una consulta LINQ, obtendrá un NotSupportedException tiempo de ejecución con el mensaje:

LINQ a Entidades no reconoce el método de método 'doble GetDistanceTo (System.Device.Location.GeoCoordinate)', y este método no se puede traducir en una expresión tienda.

Con la versión de Entity Framework 5 o 6, una alternativa es utilizar la clase System.Data.Spatial.DbGeography. Por ejemplo:

DbGeography searchLocation = DbGeography.FromText(String.Format("POINT({0} {1})", longitude, latitude)); 

var nearbyLocations = 
    (from location in _context.Locations 
    where // (Additional filtering criteria here...) 
    select new 
    { 
     LocationID = location.ID, 
     Address1 = location.Address1, 
     City = location.City, 
     State = location.State, 
     Zip = location.Zip, 
     Latitude = location.Latitude, 
     Longitude = location.Longitude, 
     Distance = searchLocation.Distance(
      DbGeography.FromText("POINT(" + location.Longitude + " " + location.Latitude + ")")) 
    }) 
    .OrderBy(location => location.Distance) 
    .ToList(); 

_context en este ejemplo es la instancia DbContext instancia previamente.

Aunque actualmente es undocumented in MSDN, las unidades devueltas por el método DbGeography.Distance parecen ser metros. Ver: System.Data.Spatial DbGeography.Distance units?

1
var objAllListing = (from listing in _listingWithLanguageRepository.GetAll().Where(z => z.IsActive == true) 
            let distance = 12742 * SqlFunctions.Asin(SqlFunctions.SquareRoot(SqlFunctions.Sin(((SqlFunctions.Pi()/180) * (listing.Listings.Latitude - sourceLatitude))/2) * SqlFunctions.Sin(((SqlFunctions.Pi()/180) * (listing.Listings.Latitude - sourceLatitude))/2) + 
                 SqlFunctions.Cos((SqlFunctions.Pi()/180) * sourceLatitude) * SqlFunctions.Cos((SqlFunctions.Pi()/180) * (listing.Listings.Latitude)) * 
                 SqlFunctions.Sin(((SqlFunctions.Pi()/180) * (listing.Listings.Longitude - sourceLongitude))/2) * SqlFunctions.Sin(((SqlFunctions.Pi()/180) * (listing.Listings.Longitude - sourceLongitude))/2))) 
            where distance <= input.Distance 

            select new ListingFinalResult { ListingDetail = listing, Distance = distance }).ToList();//.Take(5).OrderBy(x => x.distance).ToList(); 
Cuestiones relacionadas