Aufgabenstellung: Ich weiß, wo ich mich befinde (Lat / Long, ist ja aus den Smartphones easy herauszubekommen) und habe einen Radius in km, in dem ich POI’s mit der Open Streemap API suchen möchte.
Problem: Die OSM API bietet keine (mir bekannte) Möglichkeit, um meinen aktuellen Standort herum eine Radius-Suche in km auszuführen, sondern hätte gern eine Bounding Box angegeben, die die Ecken der Box als Geo-Koordinaten angibt – siehe hier:
http://www.overpass-api.de/api/xapi?node[bbox=8.62,49.85,8.68,49.89][amenity=fast_food|pub][@meta]
Dabei spezifiziert der Parameter bbox die Lat/Long-Koordinaten in der Reihenfolge links, oben, rechts, unten.
Dazu erstmal zum Verständnis:
- Der Breitengrad (Latitude) gibt die Nord-Südachse an, „50“ ist nördlicher als „49“
- Der Längengrad (Longitude) gibt die Ost-Westachse an, „5“ ist westlicher als „6“
Berechnung
Nun haben wir also den eigenen Standort, wissen über Lat/Long Bescheid und wollen die Eckpunkte für die oben angesprochene Bounding Box errechnen. Aufbauend auf diesem Artikel habe ich folgende PHP-Funktion gebaut:
$lat = 49.869059;
$lon = 8.645318;
$radius = 1.5;
/**
* lat (breitengrad = nord -> sued): 50 ist noerdlicher als 49
* lon (längengrad = west -> ost): 5 ist westlicher als 6
*/
function getBoundingBox($lat, $lon, $radius)
{
$earth_radius = 6371;
$maxLat = $lat + rad2deg($radius/$earth_radius);
$minLat = $lat - rad2deg($radius/$earth_radius);
$maxLon = $lon + rad2deg($radius/$earth_radius/cos(deg2rad($lat)));
$minLon = $lon - rad2deg($radius/$earth_radius/cos(deg2rad($lat)));
return array
(
"center" => array("lat" => $lat, "lon" => $lon),
"nw" => array("lat" => $maxLat, "lon" => $minLon),
"ne" => array("lat" => $maxLat, "lon" => $maxLon),
"sw" => array("lat" => $minLat, "lon" => $minLon),
"se" => array("lat" => $minLat, "lon" => $maxLon)
);
}
$coords = getBoundingBox($lat, $lon, $radius);
print_r($coords);
/*
Array
(
[center] => Array
(
[lat] => 49.869059
[lon] => 8.645318
)
[nw] => Array
(
[lat] => 49.882548824089
[lon] => 8.6243885076019
)
[ne] => Array
(
[lat] => 49.882548824089
[lon] => 8.6662474923981
)
[sw] => Array
(
[lat] => 49.855569175911
[lon] => 8.6243885076019
)
[se] => Array
(
[lat] => 49.855569175911
[lon] => 8.6662474923981
)
)
*/
Somit haben wir schonmal die Eckpunkte für den Radius 1,5km um unseren Mittelpunkt ausgerechnet.
Darstellen der Eckpunkte auf einer Google Map
Zur Verifikation der errechneten Eckpunkte muss Quick&Dirty eine googlemap herhalten (inspiriert von hier).
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://code.google.com/apis/maps/documentation/javascript/examples/default.css" />
<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script>
function init()
{
var markers = [];
<?php
foreach ($coords as $desc => $latlong)
{
?>
markers.push({
'lat' : <?php echo $latlong['lat']; ?>,
'lon' : <?php echo $latlong['lon']; ?>,
'desc' : "<?php echo $desc; ?>"
});
<?php
}
?>
var map = new google.maps.Map(document.getElementById("map_canvas"), {
zoom: 11,
center: new google.maps.LatLng(<?php echo $coords['center']['lat'] . "," . $coords['center']['lon']; ?>),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
for (var i = 0; i < markers.length; i++) {
new google.maps.Marker({
position: new google.maps.LatLng(markers[i].lat, markers[i].lon),
map: map,
title: markers[i].desc
});
}
}
window.onload = init;
</script>
</head>
<body>
<div id="map_canvas"></div>
</body>
</html>
Sieht doch gut aus. Somit haben wir unsere Bounding Box Koordinaten auch visuell dargestellt und können die OSM API damit füttern.
Und hier nochmal der komplette Code:
<?php
$lat = 49.869059;
$lon = 8.645318;
$radius = 1.5;
/**
* lat (breitengrad = nord -> sued): 50 ist noerdlicher als 49
* lon (längengrad = west -> ost): 5 ist westlicher als 6
*/
function getBoundingBox($lat, $lon, $radius)
{
$earth_radius = 6371;
$maxLat = $lat + rad2deg($radius/$earth_radius);
$minLat = $lat - rad2deg($radius/$earth_radius);
$maxLon = $lon + rad2deg($radius/$earth_radius/cos(deg2rad($lat)));
$minLon = $lon - rad2deg($radius/$earth_radius/cos(deg2rad($lat)));
return array
(
"center" => array("lat" => $lat, "lon" => $lon),
"nw" => array("lat" => $maxLat, "lon" => $minLon),
"ne" => array("lat" => $maxLat, "lon" => $maxLon),
"sw" => array("lat" => $minLat, "lon" => $minLon),
"se" => array("lat" => $minLat, "lon" => $maxLon)
);
}
$coords = getBoundingBox($lat, $lon, $radius);
?>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://code.google.com/apis/maps/documentation/javascript/examples/default.css" />
<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script>
function init()
{
var markers = [];
<?php
foreach ($coords as $desc => $latlong)
{
?>
markers.push({
'lat' : <?php echo $latlong['lat']; ?>,
'lon' : <?php echo $latlong['lon']; ?>,
'desc' : "<?php echo $desc; ?>"
});
<?php
}
?>
var map = new google.maps.Map(document.getElementById("map_canvas"), {
zoom: 11,
center: new google.maps.LatLng(<?php echo $coords['center']['lat'] . "," . $coords['center']['lon']; ?>),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
for (var i = 0; i < markers.length; i++) {
new google.maps.Marker({
position: new google.maps.LatLng(markers[i].lat, markers[i].lon),
map: map,
title: markers[i].desc
});
}
}
window.onload = init;
</script>
</head>
<body>
<div id="map_canvas"></div>
</body>
</html>

Eine Antwort auf Umkreissuche: Lat/Long und der Radius