2010-07-02 35 views
9

Dada una base de datos que contiene tres campos:consulta SQL para consultar próximo a puntos basado en latitud/longitud - SQLite

Latitud Longitud proximidad

Dónde Lat y Long son las coordenadas de GPS y de proximidad es (alguna unidad - pies segundos Minutos???)

Y dada GPS actual del usuario latitud/longitud ...

Quiero escribir una consulta SQL que va a recuperar todas las filas donde el usuario es withi n "Proximidad" de esas filas.

Y el truco: esto tiene que funcionar en SQLite, que solo admite tipos de datos bastante primitivos. Sin engaños y confiando en SQL Server (u otro producto que proporcione mejores funciones de geoespacio).

¿Alguna sugerencia?

+0

Cant utiliza un SQL sencilla para calcular la distancia de dos puntos y luego ver si esto es menos que la distancia? ¿Geometría simple de Euclydian? – Thomas

+2

@Thomas: la distancia * Euclidiana * entre dos puntos es a lo largo de una línea recta * a través * de la Tierra. Eso podría no ser lo que quieres. – dan04

+2

@ dan04 la circunferencia de la Tierra es de una magnitud tan grande que cualquier radio de búsqueda es insignificante. 100 millas a 99.88 millas, eso es aproximadamente 630 pies, menos que un campo de fútbol. – Gallonallen

Respuesta

7

Aquí hay una función personalizada basada en C para sqlite [copiada de los enlaces indicados a continuación]. Esto se puede usar dentro de una aplicación de iOS. Supone que tiene columnas denominadas latitud y longitud, y calcula la diferencia entre ellas y cualquier latitud/longitud que proporcione. Excelente redacción, funciona tal como está.

#define DEG2RAD(degrees) (degrees * 0.01745327) // degrees * pi over 180 

static void distanceFunc(sqlite3_context *context, int argc, sqlite3_value **argv) 
{ 
    // check that we have four arguments (lat1, lon1, lat2, lon2) 
    assert(argc == 4); 
    // check that all four arguments are non-null 
    if (sqlite3_value_type(argv[0]) == SQLITE_NULL || sqlite3_value_type(argv[1]) == SQLITE_NULL || 
    sqlite3_value_type(argv[2]) == SQLITE_NULL || 
    sqlite3_value_type(argv[3]) == SQLITE_NULL) { 
    sqlite3_result_null(context); 
    return; 
} 

// get the four argument values 
double lat1 = sqlite3_value_double(argv[0]); 
double lon1 = sqlite3_value_double(argv[1]); 
double lat2 = sqlite3_value_double(argv[2]); 
double lon2 = sqlite3_value_double(argv[3]); 

// convert lat1 and lat2 into radians now, to avoid doing it twice below 
double lat1rad = DEG2RAD(lat1); 
double lat2rad = DEG2RAD(lat2); 

// apply the spherical law of cosines to our latitudes and longitudes, and set the result appropriately 

// 6378.1 is the approximate radius of the earth in kilometres 
sqlite3_result_double(context, acos(sin(lat1rad) * sin(lat2rad) + cos(lat1rad) * cos(lat2rad) * cos(DEG2RAD(lon2) - DEG2RAD(lon1))) * 
6378.1); 
} 

Esto define una distancia función SQL (Latitud1, longitut1, Latitude2, longitude2), que devuelve la distancia (en kilómetros) entre dos puntos.

Para utilizar esta función, agregue el código anterior ... y continuación, agregue esta línea inmediatamente después de llamar sqlite3_open:

sqlite3_create_function(sqliteDatabasePtr, "distance", 4, SQLITE_UTF8, NULL, &distanceFunc, NULL, NULL); 

... donde sqliteDatabasePtr es el puntero de base de datos devuelto por la llamada a sqlite3_open.

Asumiendo que tiene una tabla llamada por ubicación, con columnas llamados latitud y longitud (tanto de tipo double) que contiene los valores de grados, a continuación, puede utilizar esta función en su SQL como esto:

SELECT * FROM Locations ORDER BY distance(Latitude, Longitude, 51.503357, -0.1199) 

Este ejemplo ordena las ubicaciones en su base de datos en función de qué tan lejos estén del London Eye, que se encuentra en 51.503357, -0.1199.

EDIT:

enlace original http://www.thismuchiknow.co.uk/?p=71 está muerto, así como alguien ha mencionado en el comentario, puede utilizar este enlace: https://web.archive.org/web/20160808122817/http://www.thismuchiknow.co.uk/?p=71 para conseguir que la página web

+0

La respuesta más votada, pero el enlace está muerto – yash

+1

Siempre está la [máquina de retorno] (https://web.archive.org/web/20160808122817/http://www.thismuchiknow.co.uk/?p=71) – mvandillen

3

El Haversine formula es lo que desea. Usar la fórmula de distancia Euclidiana simple no es suficiente, porque la curvatura de la Tierra afecta la distancia entre dos puntos.

Creating a Store Locator with PHP, MySQL & Google Maps es un artículo sobre la implementación de esta solución con MySQL, pero SQLite no admite funciones trigonométricas.

Consulte las respuestas en Calculating Great-Circle Distance with SQLite aquí en Stack Overflow para obtener más consejos sobre cómo extender las funciones de SQLite para que pueda resolverlo.

2

También sabe que hay un complemento para SQLite llamado Spatialite que tiene todas las mismas funciones que PostGIS y SQLServer. Supongo que está intentando usar SQLLite en el iPhone o en el navegador o algo así. Si no, RECOMIENDO ALTAMENTE spatialite.

+0

Ya, haciendo iPhone. Encontré http://www.thismuchiknow.co.uk/?p=71, que voy a probar. –

Cuestiones relacionadas