2009-05-21 15 views
8

En PHP, tengo el siguiente código para calcular la distancia entre dos lugares:PHP/MySQL: Seleccione en los alrededores de un lugar determinado de DB

<?php 
function distance($lat1, $long1, $lat2, $long2) { 
    // DEGREE TO RADIAN 
    $latitude1 = $lat1/180*pi(); 
    $longitude1 = $long1/180*pi(); 
    $latitude2 = $lat2/180*pi(); 
    $longitude2 = $long2/180*pi(); 
    // FORMULA: e = ARCCOS (SIN(Latitude1) * SIN(Latitude2) + COS(Latitude1) * COS(Latitude2) * COS(Longitude2-Longitude1)) * EARTH_RADIUS 
    $distance = acos(sin($latitude1)*sin($latitude2)+cos($latitude1)*cos($latitude2)*cos($longitude2-$longitude1))*6371; 
    return $distance; 
} 
echo distance(9.9921962, 53.5534074, 9.1807688, 48.7771056); // Hamburg, DE - Stuttgart, DE 
?> 

Pero ahora, quiero seleccionar los alrededores de una dada la ubicación a través de PHP de mi base de datos MySQL:

  • el usuario entra en su ciudad natal
  • mi script obtiene los valores de latitud/longitud a través de la API de Google
  • En mi base de datos, tengo alrededor de 200 lugares con un campo para el valor de latitud y un campo para el valor de longitud
  • Necesito un código para PHP y MySQL para seleccionar los 10 lugares que están más próximas a la ciudad natal del usuario

Espero que puedas ayudarme. ¡Gracias por adelantado!

Respuesta

7

MySQL Great Circle Distance (Haversine formula) hace exactamente lo que necesita.

Con sólo 200 registros sin embargo es posible que también acaba de cargar a todos y comprobarlos con el código. El conjunto de datos es realmente demasiado pequeño para preocuparse demasiado por el código de base de datos o cualquier otra optimización de este tipo.

Calculating distance between zip codes in PHP tiene un par de implementaciones de PHP de este algoritmo.

Geo Proximity Search es más o menos el mismo problema que tiene.

+0

Gracias, como dijo nOw2, es la fórmula de Haversine. Tengo la implementación de PHP todavía, veo el código en mi pregunta. – caw

0

MySQL tiene la capacidad de filas de índice geoespacialmente. Puede que no necesites hacer estas operaciones tú solo (puedes pedirle a MySQL que calcule la distancia entre dos objetos geo y ordenar por eso ...).

Ver: http://forums.mysql.com/read.php?23,159205,159205

+0

Gracias, pero no puedo usar las funciones geoespaciales de MySQL. – caw

-1

¿Por qué no utilizar las funciones geoespaciales de MySQL ...? No, solo bromeo.

Si los 200 registros son lugares reales, como las ciudades, etc. entonces como una alternativa podría utilizar la API GeoNames'?

La siguiente servicio web proporcionará a los 10 lugares más cercanos al lat y lng proporcionado:

http://ws.geonames.org/findNearby?lat=47.3&lng=9

Fuente: http://www.geonames.org/export/web-services.html#findNearbyPlaceName

Lista completa: http://www.geonames.org/export/ws-overview.html

+0

¡Gracias! Tengo los datos en mi base de datos, así que no necesito usar la API de GeoNames. – caw

+0

Sí, lo entiendo, pero podría hacer coincidir esos 200 registros con las respuestas de Geonames y de ahí tener las 10 coincidencias más cercanas. Esto supone nuevamente que sus 200 registros son lugares conocidos de alguna manera y no algunas posiciones aleatorias. –

1

Esa es la fórmula Haversine. Puede traducir el PHP directamente a SQL para poder consultar la base de datos espacialmente (la alternativa es extraer cada registro del DB y ejecutar los datos a través de PHP). MySQL proporciona todas las funciones matemáticas que necesita.

Hice esto para un sitio web comercial que proporciona búsquedas de distancia basada poste/código postal, por lo que es ciertamente posible sin funciones específicas SIG.

+0

¡Gracias, funciona bien! :) No sabía que MySQL tiene todas las funciones matemáticas. – caw

3

tal vez algo como

SELECT field1, field2, ..., 
    ACOS(SIN(latitude/180 * PI()) * SIN(:1) + COS(latitude/180 * PI()) * COS(:2) * COS(:2 - longtidude)) * 6371 AS distance 
    ORDER BY distance ASC; 

o

SELECT field1, field2, ..., 
    ACOS(SIN(RADIANS(latitude)) * SIN(:1) + COS(RADIANS(latitude)) * COS(:2) * COS(:2 - longtidude)) * 6371 AS distance 
    ORDER BY distance ASC; 

(traducido directamente desde el código PHP)

:1 y :2 es $lat2/180*pi() y $long2/180*pi() respectivamente.

+0

Gracias, es lo mismo que la respuesta de nOw2, ¿no es así? Usted escribe "$ lat2/180 * pi()". ¿Por qué no simplemente "RADIANS ($ lat2)"? Lo usaste en el resto de la consulta, ¿por qué no aquí también? – caw

+0

: 1 y: 2 proviene de PHP, que no tiene RADIANS. http://us2.php.net/deg2rad podría ser usado. – itsbth

Cuestiones relacionadas