2009-05-21 16 views
8

In PHP, ich habe den folgenden Code, um den Abstand zwischen zwei Standorten für die Berechnung:PHP/MySQL: Wählen Standorten in der Nähe einer bestimmten Stelle von 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 
?> 

Aber jetzt möchte ich Standorte auszuwählen nahe an ein Standort via PHP aus meiner MySQL-Datenbank gegeben:

  • der Benutzer gibt seine Heimatstadt
  • Mein Skript die Breiten-/Längenwerte über die Google API
  • wird in meinem Datenbank habe ich über 200 Standorte mit einem Feld für den Breitenwert und ein Feld für den Längenwert
  • ich einen Code für PHP und MySQL benötigen, um die 10 Standorte auszuwählen, die zu der Heimatstadt des Benutzers am nächsten sind

Ich hoffe ihr könnt mir helfen. Danke im Voraus!

Antwort

7

MySQL Great Circle Distance (Haversine formula) macht genau das, was Sie brauchen.

Mit nur 200 Datensätzen können Sie sie aber auch einfach alle laden und mit Code überprüfen. Der Datensatz ist wirklich viel zu klein, um sich zu viele Gedanken über Datenbank oder Code oder andere Optimierungen zu machen.

Calculating distance between zip codes in PHP hat ein paar PHP-Implementierungen dieses Algorithmus.

Geo Proximity Search ist ziemlich genau das gleiche Problem, das Sie haben.

+0

Danke, wie NOW2 gesagt hat, es ist die Haversine-Formel. Ich habe die PHP-Implementierung noch, siehe den Code in meiner Frage. – caw

0

MySQL hat die Fähigkeit, georäumlich zu Indexzeilen. Sie müssen diese Mathematik vielleicht nicht selbst machen (Sie können MySQL einfach bitten, den Abstand zwischen zwei Geo-Objekten zu berechnen und danach zu sortieren ...).

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

+0

Vielen Dank, aber ich kann die geospatialen Features von MySQL nicht verwenden. – caw

-1

Warum Sie nicht verwenden geospatial Funktionen von MySQL ...? Nein, hab nur Spaß gemacht.

Wenn die 200 Datensätze tatsächliche Orte wie Städte usw. sind, könnten Sie als Alternative die API von GeoNames verwenden?

Die folgenden WebService werden die 10 am nächsten Stellen mit dem lat und lng bereitgestellt bieten:

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

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

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

+0

Danke! Ich habe die Daten in meiner Datenbank, daher brauche ich die API von GeoNames nicht. – caw

+0

Ja, ich verstehe, aber Sie könnten diese 200 Datensätze mit den Antworten von Geonames abgleichen und daraus die 10 engsten Übereinstimmungen haben. Dies ist wiederum davon ausgegangen, dass Ihre 200 Datensätze sind irgendwie bekannte Orte und nicht einige zufällige Positionen. –

1

, dass die Formel Haversine ist. Sie können das PHP direkt in SQL übersetzen, so dass Sie die Datenbank räumlich abfragen können (die Alternative besteht darin, jeden Datensatz aus der DB zu holen und die Daten über PHP laufen zu lassen). MySQL bietet alle mathematischen Funktionen, die Sie benötigen.

Ich tat dies für eine kommerzielle Website, die post/zipcode basierte Entfernungssuche lieferte, also ist es sicherlich ohne spezifische GIS-Funktionen möglich.

+0

Danke, es funktioniert gut! :) Ich wusste nicht, dass MySQL alle mathematischen Funktionen hat. – caw

3

Vielleicht so etwas wie

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; 

oder

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

(direkt aus dem PHP-Code übersetzt) ​​

:1 und :2 ist $lat2/180*pi() und $long2/180*pi() sind.

+0

Danke, es ist das gleiche wie NoW2's Antwort, oder? Sie schreiben "$ lat2/180 * pi()". Warum nicht einfach "RADIANS ($ lat2)"? Sie haben es im Rest der Abfrage verwendet, also warum nicht auch hier? – caw

+0

: 1 und: 2 kommt von PHP, das keine RADIANS hat. http://us2.php.net/deg2rad könnte jedoch verwendet werden. – itsbth