Ergebnisse einer Umkreissuche sortieren
fabx
- php
Hallo Community,
ich habe mit der OpenGeoDB eine Umkreissuche realisiert.
Die Umkreissuche funktioniert auch einwandfrei.
Leider schaffe ich es nicht die Ergebnisse nach der Entfernung zu sortieren.
Der php Code, der die sortierten Ergebnisse liefern soll:
~~~php
<?php
$sql = 'SELECT ' . $Spalten . ',
' . (2 * $this->Erdradius) . ' *
ASIN(
SQRT(
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
) / ' . (2 * $this->Erdradius) . ' ) AS Entfernung
FROM ' . $this->table . '
WHERE
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
<= "' . pow(2 * $this->Erdradius * sin($Radius / (2 * $this->Erdradius)), 2) . '"';
?>
Und der komplette php Code sieht folgender Maßen aus:
~~~php
<?php
class Umkreissuche {
// Erdradius in Kilometern
private $Erdradius = 6371;
// mysql link identifier
private $db;
// Datentabelle
private $table = false;
// Fehler zeigen?
public $zeigeFehler = true;
public function __construct($db, $table = 'vereine') {
if (!is_resource($db) || get_resource_type($db) != 'mysql link') {
trigger_error('Keine MySQL-Ressource übergeben', E_USER_ERROR);
}
$this->db = $db;
$this->table = $table;
// leere Koordinaten in Tabelle füllen
$sql = 'SELECT `ID`, `PLZ`
FROM `' . $this->table . '`
WHERE
`KoordX` = "0"
AND `KoordY` = "0"
AND `KoordZ` = "0"
';
$re = mysql_query($sql, $this->db);
while ($rd = mysql_fetch_object($re)) {
if (!$this->Plz2Koord($rd->PLZ, $lon, $lat)) {
if ($this->zeigeFehler) {
trigger_error('Postleitzahl ' . $rd->PLZ . ' konnte nicht zugeordnet werden', E_USER_NOTICE);
}
continue;
}
$this->Kugel2Kartesisch($lon, $lat, $x, $y, $z);
$sql = 'UPDATE `' . $this->table . '`
SET
`Longitude` = "' . $lon . '",
`Latitude` = "' . $lat . '",
`KoordX` = "' . $x . '",
`KoordY` = "' . $y . '",
`KoordZ` = "' . $z . '"
WHERE
`ID` = "' . (int)$rd->ID . '"
LIMIT 1
';
mysql_query($sql, $this->db);
}
}
public function Kugel2Kartesisch($lon, $lat, &$x, &$y, &$z) {
$lambda = $lon * pi() / 180;
$phi = $lat * pi() / 180;
$x = $this->Erdradius * cos($phi) * cos($lambda);
$y = $this->Erdradius * cos($phi) * sin($lambda);
$z = $this->Erdradius * sin($phi);
return true;
}
public function Plz2Koord($PLZ, &$lon, &$lat) {
$sql = 'SELECT
coo.lon,
coo.lat
FROM geodb_coordinates AS coo
INNER JOIN geodb_textdata AS textdata
ON textdata.loc_id = coo.loc_id
WHERE
textdata.text_val = "' . mysql_real_escape_string($PLZ, $this->db) . '"
AND textdata.text_type = "500300000"
LIMIT 1';
$re = mysql_query($sql, $this->db);
if (mysql_num_rows($re) != 1) {
return false;
}
list($lon, $lat) = mysql_fetch_row($re);
return true;
}
public function Suche($PLZ, $Radius, $Spalten = array(), $Reihenfolge = false, $Richtung = 'ASC') {
if (!is_array($Spalten) || count($Spalten) == 0) {
$Spalten = '*';
} else {
$Spalten = '`' . implode('`, `', $Spalten) . '`';
}
if (!$this->Plz2Koord($PLZ, $lon, $lat)) {
if ($this->zeigeFehler) {
trigger_error('Postleitzahl ' . $PLZ . ' konnte nicht zugeordnet werden', E_USER_NOTICE);
}
return false;
}
$this->Kugel2Kartesisch($lon, $lat, $UrsprungX, $UrsprungY, $UrsprungZ);
$sql = 'SELECT ' . $Spalten . '
FROM `' . $this->table . '`
WHERE
KoordX >= ' . ($UrsprungX - $Radius) . '
AND KoordX <= ' . ($UrsprungX + $Radius) . '
AND KoordY >= ' . ($UrsprungY - $Radius) . '
AND KoordY <= ' . ($UrsprungY + $Radius) . '
AND KoordZ >= ' . ($UrsprungZ - $Radius) . '
AND KoordZ <= ' . ($UrsprungZ + $Radius) . '
AND POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
<= "' . pow(2 * $this->Erdradius * sin($Radius / (2 * $this->Erdradius)), 2) . '"';
if ($Reihenfolge && strpos($Spalten, $Reihenfolge) !== false) {
$Richtung = (strtoupper($Richtung) == 'DESC') ? 'DESC' : 'ASC';
$sql .= "\n" . 'ORDER BY `' . $Reihenfolge . '` ' . $Richtung;
}
$re = mysql_query($sql, $this->db);
$result = array();
while ($rd = mysql_fetch_object($re)) {
$result[] = $rd;
}
return $result;
}
}
?>
Ich bin um jede Hilfe dankbar.
Liebe Grüße
Fabx
Hallo,
ich habe mit der OpenGeoDB eine Umkreissuche realisiert.
Die Umkreissuche funktioniert auch einwandfrei.
ohne jetzt im Einzelnen auf deinen Code einzugehen: Wie groß ist "Umkreis" in deinem Fall typischerweise? Ein paar Kilometer? Hundert Kilometer? Wenn die Entfernungen in der Größenordnung liegen, und der Bezugspunkt nicht gerade in der Polarregion liegt, würde ich die Trigonometrie links liegenlassen und die geographischen Koordinaten einfach wie kartesische Koordinaten betrachten. Okay, mit zunehmender geographischer breite wird der Umkreis dann zur Ellipse, aber auch das kann man kompensieren, indem man die x-Koordinate (geographische Länge) mit B=cos(b) skaliert, wobei b die geographische Breite des Bezugspunkts ist, und somit für einen gegebenen Bezugspunkt konstant.
Die Höhe (z-Koordinate) würde ich aus der betrachtung komplett rauslassen.
Leider schaffe ich es nicht die Ergebnisse nach der Entfernung zu sortieren.
Wie schon erwähnt, nehme ich mal die polaren Koordinaten und tue so, als wären es kartesische. Seien (l0, b0) die Koordinaten des Bezugspunktes, dann sagt der alte Pythagoras, dass für die Entfernung d zu (lx, bx) gilt:
d² = (lx-l0)² + (bx-b0)²
Betrachtet man jetzt noch die mit der Breite zunehmende Verzerrung der Länge, wie ich oben schon angedeutet habe, dann ergibt sich für die Entfernung:
d² = (cos(b0)*(lx-l0))² + (bx-b0)²
Diesen Term müsstest du als Kriterium für eine ORDER-BY-Klausel in dein SQL-Statement ergänzen, dann sortiert das DBMS die Punkte nach Entfernung. Das Wurzelziehen kann man sich sparen, denn wenn man das Quadrat der Entfernung auf- oder absteigend sortiert, ist damit auch die Entfernung selbst entsprechend sortiert.
So long,
Martin
Hallo,
ich habe mit der OpenGeoDB eine Umkreissuche realisiert.
Die Umkreissuche funktioniert auch einwandfrei.ohne jetzt im Einzelnen auf deinen Code einzugehen: Wie groß ist "Umkreis" in deinem Fall typischerweise? Ein paar Kilometer? Hundert Kilometer? Wenn die Entfernungen in der Größenordnung liegen, und der Bezugspunkt nicht gerade in der Polarregion liegt, würde ich die Trigonometrie links liegenlassen und die geographischen Koordinaten einfach wie kartesische Koordinaten betrachten. Okay, mit zunehmender geographischer breite wird der Umkreis dann zur Ellipse, aber auch das kann man kompensieren, indem man die x-Koordinate (geographische Länge) mit B=cos(b) skaliert, wobei b die geographische Breite des Bezugspunkts ist, und somit für einen gegebenen Bezugspunkt konstant.
Die Höhe (z-Koordinate) würde ich aus der betrachtung komplett rauslassen.Leider schaffe ich es nicht die Ergebnisse nach der Entfernung zu sortieren.
Wie schon erwähnt, nehme ich mal die polaren Koordinaten und tue so, als wären es kartesische. Seien (l0, b0) die Koordinaten des Bezugspunktes, dann sagt der alte Pythagoras, dass für die Entfernung d zu (lx, bx) gilt:
d² = (lx-l0)² + (bx-b0)²
Betrachtet man jetzt noch die mit der Breite zunehmende Verzerrung der Länge, wie ich oben schon angedeutet habe, dann ergibt sich für die Entfernung:
d² = (cos(b0)*(lx-l0))² + (bx-b0)²
Diesen Term müsstest du als Kriterium für eine ORDER-BY-Klausel in dein SQL-Statement ergänzen, dann sortiert das DBMS die Punkte nach Entfernung. Das Wurzelziehen kann man sich sparen, denn wenn man das Quadrat der Entfernung auf- oder absteigend sortiert, ist damit auch die Entfernung selbst entsprechend sortiert.
So long,
Martin
Hallo Martin,
vielen Dank für deinen ausführlichen Beitrag.
die Sortierung soll je nach ausgewähltem Radius innerhalb von 10, 15 und 30km erfolgen. Alle Ergebnisse liegen vorerst in Deutschland.
Leider fehlen mir die Kenntnisse um deinen Lösungsweg vollständig zu verstehen und in PHP zu realisieren.
Ich werde nach dem ich aktuell JavaScript lerne auf jeden Fall einen PHP Crashkurs machen und mir dann deinen Beitrag nochmals anschauen.
Den Code was mir die sortierten Ergebnisse liefern sollen habe ich ja schon bereits:
<?php
$sql = 'SELECT ' . $Spalten . ',
' . (2 * $this->Erdradius) . ' *
ASIN(
SQRT(
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
) / ' . (2 * $this->Erdradius) . ' ) AS Entfernung
FROM `' . $this->table . '`
WHERE
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
<= "' . pow(2 * $this->Erdradius * sin($Radius / (2 * $this->Erdradius)), 2) . '"';
?>
Das Problem ist, dass es bei mir nicht funktionieren will..
Meinst du, dass es am Code liegt?
Liebe Grüße
Fabx
Tach!
Leider schaffe ich es nicht die Ergebnisse nach der Entfernung zu sortieren.
<?php
$sql = 'SELECT ' . $Spalten . ',
' . (2 * $this->Erdradius) . ' *
ASIN(
SQRT(
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
) / ' . (2 * $this->Erdradius) . ' ) AS Entfernung
FROM' . $this->table . '
WHERE
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
<= "' . pow(2 * $this->Erdradius * sin($Radius / (2 * $this->Erdradius)), 2) . '"';
?>
Ich sehe da kein "ORDER BY Entfernung". Ohne das wird es schwer, ein sortiertes Ergebnis zu erhalten.
dedlfix.
Tach!
Leider schaffe ich es nicht die Ergebnisse nach der Entfernung zu sortieren.
<?php
$sql = 'SELECT ' . $Spalten . ',
' . (2 * $this->Erdradius) . ' *
ASIN(
SQRT(
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
) / ' . (2 * $this->Erdradius) . ' ) AS Entfernung
FROM' . $this->table . '
WHERE
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
<= "' . pow(2 * $this->Erdradius * sin($Radius / (2 * $this->Erdradius)), 2) . '"';
?>
>
> Ich sehe da kein "ORDER BY Entfernung". Ohne das wird es schwer, ein sortiertes Ergebnis zu erhalten.
>
>
> dedlfix.
Guten Mittag dedlfix
Vielen Dank für deinen Hinweis.
Ich habe das sql statement mit ORDER BY ergänzt, leider ohne Erfolg.
Irgendwie will es einfach nicht. Habe auch mehrer Möglichkeiten versucht doch leider werden die Ergebnisse immernoch nicht sortiert.
Woran liegt das?
Mein Code sieht nun mit ORDER BY so aus:
~~~php
<?php
class Umkreissuche {
// Erdradius in Kilometern
private $Erdradius = 6371;
// mysql link identifier
private $db;
// Datentabelle
private $table = false;
// Fehler zeigen?
public $zeigeFehler = true;
public function __construct($db, $table = 'vereine') {
if (!is_resource($db) || get_resource_type($db) != 'mysql link') {
trigger_error('Keine MySQL-Ressource übergeben', E_USER_ERROR);
}
$this->db = $db;
$this->table = $table;
// leere Koordinaten in Tabelle füllen
$sql = 'SELECT `ID`, `PLZ`
FROM `' . $this->table . '`
WHERE
`KoordX` = "0"
AND `KoordY` = "0"
AND `KoordZ` = "0"
';
$re = mysql_query($sql, $this->db);
while ($rd = mysql_fetch_object($re)) {
if (!$this->Plz2Koord($rd->PLZ, $lon, $lat)) {
if ($this->zeigeFehler) {
trigger_error('Postleitzahl ' . $rd->PLZ . ' konnte nicht zugeordnet werden', E_USER_NOTICE);
}
continue;
}
$this->Kugel2Kartesisch($lon, $lat, $x, $y, $z);
$sql = 'UPDATE `' . $this->table . '`
SET
`Longitude` = "' . $lon . '",
`Latitude` = "' . $lat . '",
`KoordX` = "' . $x . '",
`KoordY` = "' . $y . '",
`KoordZ` = "' . $z . '"
WHERE
`ID` = "' . (int)$rd->ID . '"
LIMIT 1
';
mysql_query($sql, $this->db);
}
}
public function Kugel2Kartesisch($lon, $lat, &$x, &$y, &$z) {
$lambda = $lon * pi() / 180;
$phi = $lat * pi() / 180;
$x = $this->Erdradius * cos($phi) * cos($lambda);
$y = $this->Erdradius * cos($phi) * sin($lambda);
$z = $this->Erdradius * sin($phi);
return true;
}
public function Plz2Koord($PLZ, &$lon, &$lat) {
$sql = 'SELECT
coo.lon,
coo.lat
FROM geodb_coordinates AS coo
INNER JOIN geodb_textdata AS textdata
ON textdata.loc_id = coo.loc_id
WHERE
textdata.text_val = "' . mysql_real_escape_string($PLZ, $this->db) . '"
AND textdata.text_type = "500300000"
LIMIT 1';
$re = mysql_query($sql, $this->db);
if (mysql_num_rows($re) != 1) {
return false;
}
list($lon, $lat) = mysql_fetch_row($re);
return true;
}
public function Suche($PLZ, $Radius, $Spalten = array(), $Reihenfolge = false, $Richtung = 'ASC') {
if (!is_array($Spalten) || count($Spalten) == 0) {
$Spalten = '*';
} else {
$Spalten = '`' . implode('`, `', $Spalten) . '`';
}
if (!$this->Plz2Koord($PLZ, $lon, $lat)) {
if ($this->zeigeFehler) {
trigger_error('Postleitzahl ' . $PLZ . ' konnte nicht zugeordnet werden', E_USER_NOTICE);
}
return false;
}
$this->Kugel2Kartesisch($lon, $lat, $UrsprungX, $UrsprungY, $UrsprungZ);
$sql = 'SELECT ' . $Spalten . '
FROM `' . $this->table . '`
WHERE
KoordX >= ' . ($UrsprungX - $Radius) . '
AND KoordX <= ' . ($UrsprungX + $Radius) . '
AND KoordY >= ' . ($UrsprungY - $Radius) . '
AND KoordY <= ' . ($UrsprungY + $Radius) . '
AND KoordZ >= ' . ($UrsprungZ - $Radius) . '
AND KoordZ <= ' . ($UrsprungZ + $Radius) . '
AND POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
<= "' . pow(2 * $this->Erdradius * sin($Radius / (2 * $this->Erdradius)), 2) . '"';
if ($Reihenfolge && strpos($Spalten, $Reihenfolge) !== false) {
$Richtung = (strtoupper($Richtung) == 'DESC') ? 'DESC' : 'ASC';
$sql .= "\n" . 'ORDER BY `' . $Reihenfolge . '` ' . $Richtung;
}
$re = mysql_query($sql, $this->db);
$result = array();
while ($rd = mysql_fetch_object($re)) {
$result[] = $rd;
}
return $result;
$sql = 'SELECT ' . $Spalten . 'ORDER BY `' . $Entfernung . ',
' . (2 * $this->Erdradius) . ' *
ASIN(
SQRT(
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
) / ' . (2 * $this->Erdradius) . ' ) AS Entfernung
FROM `' . $this->table . '`
WHERE
POWER(' . $UrsprungX .' - KoordX, 2)
+ POWER(' . $UrsprungY .' - KoordY, 2)
+ POWER(' . $UrsprungZ .' - KoordZ, 2)
<= "' . pow(2 * $this->Erdradius * sin($Radius / (2 * $this->Erdradius)), 2) . '"';
}
}
?>
Liebe Grüße
Fabx
Ich sehe da kein "ORDER BY Entfernung". Ohne das wird es schwer, ein sortiertes Ergebnis zu erhalten.
Bitte Helf mir,
das hört sich alles so einfach an.. :(
Kannst du mir Näheres beschreiben?
Ich bin am Verzweifeln
Liebe Grüße
Fabx
Tach!
Ich sehe da kein "ORDER BY Entfernung". Ohne das wird es schwer, ein sortiertes Ergebnis zu erhalten.
Bitte Helf mir, das hört sich alles so einfach an.. :(
Kannst du mir Näheres beschreiben?
Ich hab da erstmal nicht geantwortet, weil ich nicht weiter helfen wonnte (Mischung aus wollen und konnte). Du zeigst eine Mengen Code, aber der ist für mich nicht ausführbar, weil mir eine Menge Voraussetzungen fehlen, die bei dir vorhanden sind. Mir bleibt lediglich, PHP zu simulieren und den Code in meinem Kopf zu interpretieren und auszuführen. Dazu bin ich nur bedingt geeignet. Du musst an dieser Stelle selbst mehr mit Debugging aktiv werden. Lass dir zum Beispiel das fertige SQL-Statement ausgeben. Ist es richtig zusammengesetzt? Wenn nicht, ist der PHP-Code fehlerhaft. Läuft es auch im phpMyAdmin? Ist das Ergebnis ebenso fehlerhaft? Dann ist das Statement verbesserungsbedürftig und der PHP-Code drumherum uninteressant.
dedlfix.