Umkreissuche Programmieren

Ich habe mir jetz ein kleines bsp. Script erstellt das die Entfernung zwischen zwei Orten berechnet.

// Geodaten Ort1
$B1 = 10.09531;
$L1 = 50.28654;

// Geodaten Ort2
$B2 = 10.080667;
$L2 = 50.265417;

// Kreiszahl Pi
$pi = pi();

// Umrechnung der Gradzahl in RAD:
$breite1 = $B1 / 180 * $pi ;
$länge1 = $L1 / 180 * $pi ;
$breite2 = $B2 / 180 * $pi ;
$länge2 = $L2 / 180 * $pi ;

print " Umrechnung der Gradzahl in RAD: ";

print " Breite1: $B1 = $breite1
";
print " Länge1: $L1 = $länge1
";

print " Breite2: $B2 = $breite2
";
print " Länge2: $L2 = $länge2
";

// Die Formel zur Entfernungsberechnung bedient sich einer Einheitskugel:
// e = ARCCOS[SIN(Breite1)*SIN(Breite2) + COS(Breite1)*COS(Breite2)*COS(Länge2-Länge1)]

$e = acos( sin($breite1)*sin($breite2) + cos($breite1)*cos($breite2)*cos($länge2-$länge1) );

$entfernung = $e * 6378.137;
print " Entfernung (Luftlinie): „.$entfernung.“ km ";

Jetzt möchte ich, dass ganze für eine Umkreissuche erweitern.

Ich habe eine MySQL Datenbank ‚Gemeinden‘ mit PLZ und Geodaten und eine Datenbank Ausflugsiele mit Geodaten.

Ich habe ein Übersichtsliste der Gemeinden erstellt.

Wenn jetzt jemand eine Gemeinde aus der Übersicht auswählt, sollen Informationen über die Gemeinde und die nächsten 10 Ausflugsziele (POI) im Umkreis der Gemeinde angezeigt werden.

Hat da jemand eine Idee wie das programmiert werden muss?

Hallo,

ich versteh dein Problem nicht ganz. Wenn du doch die Entfernung zwischen zwei Orten berechnen kannst, kannst du diese Berechnung doch auch mit beliebig vielen Orten durchführen, von denen du dann die 10 nächsten nimmst. Oder?

Grüße,
Dietmar

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Leider habe ich zu diesem Thema noch keine Bsp. Scripts oder Codeschnipsel im Web gefunden.

Ich werds mal versuchen selber zu programmieren.

Es gibt zwar Projekte wie opengeodb oder die geoclass die sind mir aber zu kompliziert und die Geodaten sind zu viele ca. 25 MB.

Mfg Maffy

Hallo

Ich würde als erstes deine Berechnung in eine Funktion packen:

function entfernung($L1,$B1,$L2,$B2)
 {
 ...
 return $entf;
 }

Dann etwas in der Art:

$mysql\_que="SELECT name,laenge,breite FROM ausflugsziele";
$mysql\_sel=mysql\_query($mysql\_que);

$earr=array('name'=\>array(),'entf'=\>array());

while $mysql\_ftc=$mysql\_fetch\_assoc($mysql\_sel)
 {
 $earr['name'][]=$mysql\_ftc['name'];
 $earr['entf'][]=entfernung($L\_Gemeinde,$B\_Gemeinde,$mysql\_ftc['laenge'],$mysql\_ftc['breite']);
 }

array\_multisort($earr['entf'],$earr['name']);
$earr=array('name'=\>array\_values($earr['name']),'entf'=\>array\_values($earr['entf']));

echo "Die zehn nächsten Ausflugsziele:
\n";
for ($i = 1; $i \n";
 }

$mysql_que=„SELECT name,laenge,breite FROM ausflugsziele“;

der op hat gesagt, dass er 25mb an daten hat, selbst wenn das nur 10000 datensaetze sind, wie lange soll dein script dann laufen? das 1.mal geht er kaputt, wenn er die 10000 datensaetze zieht, das 2.mal wenn du fuer jeden die entfernung berechnest und das 3.mal beim sort…

ok, endlos viele Daten in einer Schleife abzuarbeiten und jeweils die Entfernung auszurechnen, geht natürlich nicht.
Du mußt dir also vor der Abfrage überlegen wie du deine Datenmenge sinnvoll begrenzen kannst und dazu sichere Regeln erstellen. Und solche Regeln hängen sicherlich vom betrachteten Gebiet ab.

Also mal angenommen, es handelt sich um Geodaten von Deutschland. Dann kannst du doch genau bestimmen, welches der kleinste mögliche Abstand zwischen zwei Längengraden ist (irgendwo in Schleswig-Holstein). Und mit diesem Wissen und dem Wissen, um den immer gleichen Abstand der Breitengrade, kannst du bestimmen, in welchem Bereich sich Längen- und Breitengradangaben befinden müssen, damit sie im Suchradius zu einem eingegebenen Punkt liegen.

Wenn du damit dann deine Abfrage einschränkst, sollte eine überschaubare Datensatzanzahl herauskommen, innerhalb derer du die geringsten Abstände errechnen kannst.

Grüße,
Dietmar

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

// Die Formel zur Entfernungsberechnung bedient sich einer Einheitskugel:
// e = ARCCOS[SIN(Breite1)*SIN(Breite2) + COS(Breite1)*COS(Breite2)*COS(Länge2-Länge1)]

$mysql_que=„SELECT name,laenge,breite FROM ausflugsziele ORDER BY
(ACOS(SIN(“.$B_Gemeinde.")*SIN(breite) +
COS(".$B_Gemeinde.")*COS(breite)*COS(laenge-".$L_Gemeinde."))) LIMIT 10";

Da hast du dann gleich die nächsten 10 in der richtigen Ordnung.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

schon mal viel besser, wenn du jetzt sin($B_Gemeinde) und cos($B_Gemeinde) in php berechnest und als const in die query schreibst, sparst du dir 20.000 winkelfunktionen. wenn ich fuer den aufruf von einer winkelfunktion 1/1000 sec brauche, wieviel sec. laufzeit habe ich mir gespart und wieviel kosten mich die verbliebenen 3 aufrufe?

ich denke es loest das problem nicht grundsaetzlich. weil: du musst bei jeder anfrage einen full table scan machen und noch dazu fuer jede zeile 3 winkelfunktionen, 2 produkte und 1 summe bilden, das ergebnis wird in ein temp ausgelagert, soertiert und dir dann die 10 ergebnisse zurueckgegeben. beruecksichtige, dass dein server noch was anderes zu tun haben koennte, und du das vielleicht 10x gleichzeitig machen musst.

was haelst du von folgender variante:
ich lege einen mittelpunkt fest. berechne 1x fuer jeden ort winkel und entfernung zum mittelpunkt und lege die neben breite und laenge in der db ab. die spalten kann ich indizieren.
wenn jetzt eine anfrage kommt berechne ich winkel und entfernung des zielortes zum mittelpunkt und kann auf die indizierte spalten ein select machen (punkte mit aehnlichen winkel und entfernung). das wird mir erst mal ein recht unscharfes ergebnis bringen, dass ich aber mit vergleichsweise geringerem aufwand nachbearbeiten kann.

noch nciht beruecksichtigt haben wir, dass es wenn ich mich recht entsinne ab mysql 4.x erweiterungen fuer genau das problem gibt - damit habe ich mich aber noch nicht beschaeftigt.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Ich habe mir jetzt mal die Arbeit gemacht und die OpenGeoDatenbank in Excel geladen und mir nur die Geodaten (Gemeinden) von den umliegenden Landkreisen rausgepickt und als csv Datei abgespeichert.

Diese CSV Daten konnte ich dann recht einfach in die Datenbank einspielen und weiter verarbeiten.

Ich habe das jetzt so gemacht. Das geht sicher auch noch besser aber soweit scheint es zu funktionieren.

$gemeinde = $_GET[‚ort‘];

$sql = 'SELECT * FROM ’ . GEMEINDE_TABLE . ’ WHERE ID = ‚.$gemeinde.‘ ';
$result = mysql_query($sql);

$nr = mysql_num_rows( $result );

// Gemeindedaten anzeigen
while( $gemeinde = mysql_fetch_array($result)){

$ID = $gemeinde[‚ID‘];
$ST = $gemeinde[‚ST‘];
$BL = $gemeinde[‚BL‘];
$RB = $gemeinde[‚RB‘];
$LK = $gemeinde[‚LK‘];
$GEMEINDE = $gemeinde[‚ORT‘];
$PLZ = $gemeinde[‚PLZ‘];
$LAT = $gemeinde[‚LAT‘];
$LON = $gemeinde[‚LON‘];

// Bundesland
if($BL == „HE“){
$BL = „Hessen“;
} else if ($BL == „BY“){
$BL = „Bayern“;
} else if ($BL == „TH“){
$BL = „Thüringen“;
}

print " $GEMEINDE ";

print " Bundesland: $BL ";
print " Regierungsbezirk: $RB ";
print " Landkreis: $LK ";
print " Postleitzahl: $PLZ ";
print " Längengrad: $LAT Breitengrad: $LON ";

print "
Ausflugsziele im Umkreis von 10 km: ";

// Geodaten auswaehlen
$res2 = mysql_query("SELECT ID,LAT,LON,OBJKET,GS FROM „.ZIELE_TABLE.“ WHERE GS = „.$_GET[‚ort‘].“ ");

while (list($id, $lat, $lon, $objekt, $gs) = mysql_fetch_array($res2)) {

// Kreiszahl Pi
$pi = pi();

$p1x = $LAT;
$p1y = $LON;
$p2x = $lat;
$p2y = $lon;

// Umrechnung der Gradzahl in RAD:
$b1 = $p1x / 180 * $pi ;
$l1 = $p1y / 180 * $pi ;
$b2 = $p2x / 180 * $pi ;
$l2 = $p2y / 180 * $pi ;

$e = acos( sin($b1)*sin($b2) + cos($b1)*cos($b2)*cos($l2-$l1) );
$entfernung = $e * 6378.137;

$radius = 10.0;

// Alle IDs, die innerhalb meines Suchradius ($radius) liegen in $data schreiben
if (round($entfernung,1) Keine Daten vorhanden! ";

} else {

while( $row = mysql_fetch_array($final_result)){

print " - „.$row[‚OBJKET‘].“ ";

}

}

print "    «« zurück   
";