Benutzer:Erik/Extension:Häfen in der Nähe

aus SkipperGuide, dem Online-Revierführer über die Segelreviere der Welt.
Version vom 3. März 2007, 00:12 Uhr von Erik (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Nach dem Erstellen der Navigationsleisten, habe ich überlegt, wie man sinnvolle Navigationsleisten auch automatisch erstellen kann. Eine Möglichkeit habe ich einmal in der folgenden Extension ausprobiert. Sie arbeitet als Parser Hook und listet alle Häfen in der Nähe einer gegebenen geografischen Position auf. Die Position, sowie die maximale Distanz und die maximale Anzahl der anzuzeigenden Häfen kann als Parameter übergeben werden. Die bekannten Häfen werden auf das Zutreffen der Bedingungen untersucht und dann nach Entfernung und Alphabet geordnet angezeigt. Die Extension greift auf das kml-File zurück, welches von der GoogleEarthExport Extension erzeugt wird.

Beispiel

Im folgenden ein Beispiel, wie man die Extension in Verbindung mit der Vorlage Navigationsleiste nutzen kann:

{{Navigationsleiste
|TITEL=Häfen in der Umgebung
|INHALT=
<nearbyplaces lat="54.333333" lon="10.133333" dist="100" max="10"/>
}}

Das Ergebnis des oben aufgeführten Codes

Bedienung

Das Aufrufen der Orte geschieht mit dem Tag <nearbyplaces/> oder auch <nearbyplaces></nearbyplaces>. Ohne die Angabe weiterer Parameter werden die zehn am nächsten an Kiel gelegenen Häfen, die maximal 100sm von Kiel entfernt sein dürfen. Diese Darstellung kann durch die folgenden Parameter verändert werden:

lon
Angabe der geografischen Länge des Ausgangspunkts
lat
Angabe der geografischen Breit des Ausgsngspunkts
dist
Der maximal Abstand vom Ausgangspunkt, den ein Hafen haben darf
max
Die maximale Anzahl von angezeigten Häfen

Diese Werte werden als Attribute des Tags gesetzt. Beispiel:

<nearbyplaces lat="54.333333" lon="10.133333" dist="100" max="10"/>

Die Reihenfolge der Parameter ist dabei egal. Der Wert sollte immer in Anführungsstriche gesetzt sein. Wird ein Parameter ausgelassen, so wird der Default-Wert (s.o.) genommen.

Eine lauffähige Installation des Scripts gibt es hier. Dort kann auch mit den Einstellungen experimentiert werden.

Installation

Das folgende Script (NearbyPlacesExtension.php) muss im Extensions-Verzeichnis abgelegt und die Zeile require_once("./extensions/NearbyPlacesExtension.php"); muss zu der LocalSettings.php hinzugefügt werden.

<?php 

// register the extension
$wgExtensionFunctions[] = "wfNearbyPlacesExtension";

// set the credit information
$wgExtensionCredits['parserhook'][] = array(

        'name' => 'Nearby Places',
        'author' => 'Erik Hansen',
        'url' => 'http://www.skipperguide.de/wiki/Benutzer:Erik',
        'description' => 'Shows a list of places near a given place', 

);

// initialize this extension
// register nearbyplaces as parser hook.
function wfNearbyPlacesExtension() { 

        global $wgParser;
        $wgParser->setHook( "nearbyplaces", "npeShowNearbyPlaces" ); 

}

// the comparation function for sorting the places array
// this sort all places first by distance then by their name
function npeCmpPlacesByDist($a, $b) {

	if ($a["dist"] == $b["dist"]) {
		return strcmp($a["name"], $b["name"]);
	}
	return ($a["dist"] < $b["dist"]) ? -1 : 1;

}

// this function 
function npeShowNearbyPlaces( $input, $argv, &$parser ) {

	// this is needed to use wiki syntax in the output
	global $wgOut;

	// get the supplied arguments
	if (isset($argv["lat"])) {
		$req_lat = $argv["lat"];
	} else {
		$req_lat = 54.333333;
	}

	if (isset($argv["lon"])) {
		$req_lon = $argv["lon"];
	} else {
		$req_lon = 10.133333;
	}

	if (isset($argv["dist"])) {
		$max_dist = $argv["dist"];
	} else {
		$max_dist = 100;
	}

	if (isset($argv["max"])) {
		$max_cnt = $argv["max"];
	} else {
		$max_cnt = 10;
	}

	// initialize the array for the found places
	$nearby_places = array();

	// create a new dom instance and load the kml file into it
	$xml = file_get_contents("http://www.skipperguide.de/extension/GoogleEarthExport.php");
	$dom = new DomDocument;
	$dom->loadXML($xml);

	// pick all placemarks from the kml-File
	// In case none is found we are done already.
	$places = $dom->getElementsByTagName('Placemark');
	if ($places->length == 0)
		return ("Es wurden leider keine Häfen gefunden.");

	// parse through all palces from the kml file
	foreach ($places as $place) {

		// in case the difference in nm between the latitudes is 
	        // lager than the distance, we do not hat to proceed any
	        // further with this place
		$lat = $place->getElementsByTagName('latitude')->item(0)->nodeValue;
		if (abs($lat - $req_lat) >> ($max_dist / 3600.0)) {
			continue;
		}

		// calculate the distance between the two places
		// this is done by calculating the loxodromic distance
		// using the (Besteckrechnung nach Mittelbreite).
		// This should be sufficient for distances shorter than
		// 500nm.
		// In case the distance is larger than max_dist,
		// this place will be discarded.
		$lon = $place->getElementsByTagName('longitude')->item(0)->nodeValue;
		$b = $lat - $req_lat;
		$l = $lon - $req_lon;
		$pm = ($lat + $req_lat) / 2;
		$a = $l * cos($pm);
		$al = atan ($a / $b);
		$dist = abs(60 * $b / cos ($al));
		if ($dist > $max_dist) {
			continue;
		}

		// in case we have come that far, the place will be added
		// to the list of places within the requested range
		$description = $place->getElementsByTagName('description')->item(0)->nodeValue;
		$name = $place->getElementsByTagName('name')->item(0)->nodeValue;
		list($link) = sscanf($description, "http://www.skipperguide.de/wiki/%s");
 		$nearby_places[] = array ("lat" => $lat, "lon" => $lon, "dist" => $dist, "name" => $name, "link" => $link); 

	}

	// check wether any places have been found.
	if (count($nearby_places) == 0)
		return ("Es wurden leider keine Häfen gefunden."); 

	// sort all places using npeCmpPlacesByDist for comparation
	// this sorts all places by distance. Places with the same
	// distancs are sorted by their name
	usort($nearby_places, "npeCmpPlacesByDist");

	// initialize the output string
	$output = "";

	// output all places up to max_cnt places ordered by distance an name
	$cnt = 0;
	foreach ($nearby_places as $place) {
	
		$output .= "[[" . $place["link"] . "|" . $place["name"] . "]] (" . number_format($place["dist"], 0) . "sm) |\n";

		$cnt++;
		if ($cnt >= $max_cnt) {
			break;
		}
	}

	// parse the output with the wiki parser, then return the result
	return ($wgOut->parse($output));

}

?>