GeoClass.php - Source Code
This is the source code of GeoClass.php
<?php /** GeoClass.php * Author: Stefan Motz (stefan@multimediamotz.de) * Homepage: http://www.multimediamotz.de/GeoClass/ * Version: 0.1.2 * Copyright 2003 multimediamotz, Stefan Motz * * GeoClass.php is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * GeoClass.php is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GeoClass.php; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // Configuration $cfgUnit = "km"; // Possible Values: km = kilometers, miles = miles, in = inch, sm = sea-miles $cgfLanguage = "de"; // Possible Values: de = german, en = english $cgfNimaNative = true; // Wether Nima-Databases output and search for native names only. /** History: * * 2002-08-15 * - added xml-header to rdf-output * 0.1.2 * - extensions for WebService * - two new globals for return-type of WebService * - findGeoObject can hold an array as parameter * * 0.1.1 * - added dms support * - changed instance var databaseFields of GeoObjectDB and GeoObjectDBNima to databaseValues * (even if anyone adopted GeoClass.php by now, it should be no problem to change it) * - databaseValues-array of GeoObjectDBNima get additional entries: country and state * - GeoDBNima has new instance variables: $country: the databases country, $states: array of ADM1-entries * - added config-variable $cgfNimaNative, determines wether only native names are searched * - GeoDBNima->findCloseByGeoObjects searches for native names only, if $cgfNimaNative == true * - GeoObject can be an "empty" Object. Name is set to "" by default, long/lat are set to 0. * BUGFIXES * - an empty queryResult is transformed to an empty array, not to NULL */ /** An external documentation will follow soon(er or later). * But the code is commented, so have a look there. * Following classes and methods are implemented: * * class GeoObject { * var $name; * var $latitude; * var $longitude; * var $latitudeRad; * var $longitudeRad; * var $latitudeDMS; * var $longitudeDMS; * function GeoObject($name, $latitude, $longitude, $degree = false); * function getEarthRadius($unit = GEO_UNIT); * function getDistance(&$geoObject, $unit = GEO_UNIT); * function getDistanceString(&$geoObject, $unit = GEO_UNIT); * function getDistanceNS(&$geoObject, $unit = GEO_UNIT); * function getDistanceWE(&$geoObject, $unit = GEO_UNIT); * function getOrientation(&$geoObject, $form = GEO_ORIENTATION_SHORT, $language = GEO_LANGUAGE); * function getRDFPointEntry($indent=0); * function getRDFDataFile(); * function getInfo(); * function dms2deg($dms); * function deg2dms($degFloat, $decPlaces = 0) * } * * class GeoObjectDB extends GeoObject { * var $databaseValues; * function GeoObjectDB($name, $latitude, $longitude, $databaseValues, $degree=false); * } * * class GeoObjectDBNima extends GeoObjectDB { * var $name; * var $utf8name; * function GeoObjectDBNima($name, $latitude, $longitude, $databaseValues, $degree=false); * function getFeatureClassification($language = GEO_LANGUAGE); * } * * class GeoDB { * var $database; * var $user; * var $password; * var $table; * var $field_name; * var $field_lat; * var $field_long; * var $degree = true; * var $domain = "localhost"; * var $port = "3306"; * function GeoDB($database, $user, $password, $table, $field_name, $field_lat, $field_long, $degree = true); * function findGeoObject($name); * function findCloseByGeoObjects(&$geoObject, $maxRadius = 100, $maxHits = 50); * function getRDFDataFile(&$GeoObjectArray); * } * * class GeoDBNima extends GeoDB { * var $field_name = "FULL_NAME"; * var $field_lat = "DD_LAT"; * var $field_long = "DD_LONG"; * var $degree = true; * function GeoDBNima($database, $user, $password, $table); * function findClassifiedPopulatedPlace($name, $placeClassificationSet = "1,2,3,4,5,0"); * function findGeoObject($name, $featureClassificationSet = "A,P,V,L,U,R,T,H,S", $placeClassificationSet = "0,1,2,3,4,5,6"); * function findCloseByGeoObjects(&$geoObject, $maxRadius = 100, $maxHits = 50, $featureClassificationSet = "A,P,V,L,U,R,T,H,S", $placeClassificationSet = "0,1,2,3,4,5,6"); * function geoObjetDB2geoObjectDBNima(&$geoObjectsDB); * } * */ // Transcribe the configuration values to globals define("GEO_UNIT", $cfgUnit); define("GEO_LANGUAGE", $cgfLanguage); define("GEO_NIMA_NATIVE", $cgfNimaNative); // Radius of the earth in kilometers. // GEO_EARTH_RADIUS is set to the mean value: 6371. km // equatorial radius as of WGS84: 6378.137 km define("GEO_EARTH_RADIUS", 6371.); // Constants for return-type of WebService define("GEO_RETURN_SER", 0); define("GEO_RETURN_RDF", 1); /** All the following stuff is for internationalisation. German and English are provided. * Perhaps I will include an external language file later. */ $stringConstantNumbers = 0; $cfgLanguages = array("de", "en"); // Possible forms of the orientation string define("GEO_ORIENTATION_SHORT", $stringConstantNumbers++); // N, W, E, NE, etc. define("GEO_ORIENTATION_LONG", $stringConstantNumbers++); // north, south west, etc. $cfgStrings[GEO_ORIENTATION_SHORT]["de"] = array("N", "NO", "O", "SO", "S", "SW", "W", "NW"); $cfgStrings[GEO_ORIENTATION_SHORT]["en"] = array("N", "NE", "E", "SE", "S", "SW", "W", "NW"); $cfgStrings[GEO_ORIENTATION_LONG]["de"] = array("Norden", "Nordosten", "Osten", "Südosten", "Süden", "Südwesten", "Westen", "Nordwesten"); $cfgStrings[GEO_ORIENTATION_LONG]["en"] = array("north", "north east", "east", "south east", "south", "south west", "west", "north west"); // Possible Errors define("GEO_ERR_NONAME", $stringConstantNumbers++); // Default Error $cfgStrings[GEO_ERR_ERROR]["de"] = "Fehler"; $cfgStrings[GEO_ERR_ERROR]["en"] = "Error"; define("GEO_ERR_NONAME", $stringConstantNumbers++); // Default value for locations without a proper name $cfgStrings[GEO_ERR_NONAME]["de"] = "Ohne Namen"; $cfgStrings[GEO_ERR_NONAME]["en"] = "unknown"; // Nima Designations (http://gnswww.nima.mil/geonames/GNS/index.jsp) // Will follow // Following globals are for later use. define("GEO_RELATION_EQUAL", "="); define("GEO_RELATION_NOTEQUAL", "!="); define("GEO_RELATION_LESS", "<"); define("GEO_RELATION_GREATER", ">"); define("GEO_RELATION_LESSOREQUAL", "<="); define("GEO_RELATION_GREATEROREQUAL", ">="); define("GEO_RELATION_LIKE", "LIKE"); define("GEO_RELATION_NOTLIKE", "NOT LIKE"); /** Class GeoDBNima * Extension of GeoDB. * Establishes a connection to a mysql-database as provided by NIMA (http://www.nima.mil/gns/html/) * Adds find-methods based on the structure of NIMA-Data. * The labels of the nima-database must be as provided (http://www.nima.mil/gns/html/cntyfile/gis.html) * Yet not fully tested. To be honest: only tested on gm.txt (Germany). But should work ;-) */ class GeoDBNima extends GeoDB { var $field_name = "FULL_NAME"; var $field_lat = "DD_LAT"; var $field_long = "DD_LONG"; var $degree = true; // Extended information about the selected Nima Database var $country = "unknown"; var $states = array(); /** Constructor GeoObject * string $database: name of the database which contains the nima-table * string $user: name of the user * string $password: users password * string $table: the table with the nima-data * Note: Fieldnames are not provided here, because it is assumed that you leave them unchanged (see above). */ function GeoDBNima($database, $user, $password, $table) { GeoDB::GeoDB($database, $user, $password, $table, $this->field_name, $this->field_lat, $this->field_long, $this->degree); $this->initNimaInformation(); } /** The init-function is called by the constructor. It determines further information of the database. * Private. */ function initNimaInformation() { global $cfgStrings; // find GeoObject with native name of the country $countryObjectArray = $this->performQuery("SELECT * FROM ".$this->table." WHERE DSG = 'PCLI' AND NT = 'N'"); if (count($countryObjectArray) == 1) { if ($countryObjectArray[0]->databaseValues[SHORT_FORM] != "") { $this->country = utf8_decode($countryObjectArray[0]->databaseValues[SHORT_FORM]); } else { $this->country = $countryObjectArray[0]->name; } } else { $this->country = $cfgStrings[GEO_ERR_NONAME][GEO_LANGUAGE]; } // find GeoObject with native name of the ADM1 (states) $statesObjectArray = $this->performQuery("SELECT * FROM ".$this->table." WHERE DSG = 'ADM1' AND NT = 'N' ORDER BY ADM1"); if (count($statesObjectArray) != 0) { for ($i = 0; $i < count($statesObjectArray); $i++) { $key = $statesObjectArray[$i]->databaseValues[ADM1]; if ($statesObjectArray[$i]->databaseValues[SHORT_FORM] != "") { $this->states[$key] = utf8_decode($statesObjectArray[$i]->databaseValues[SHORT_FORM]); } else { $this->states[$key] = $statesObjectArray[$i]->name; } } } else { $this->states[] = $cfgStrings[GEO_ERR_NONAME][GEO_LANGUAGE]; } } /** Searches for a populated place (FC = P) which fits the passed $name. You could use MySQL compatible wildcards. * A set or a single place classification could be passed. * By default all classifications (1=big, 5=small, 0=unclassified or very small) are considered. * Returns an array of GeoDBNima-objects which fit the query. */ function findClassifiedPopulatedPlace($name, $placeClassificationSet = "1,2,3,4,5,0") { return $this-> findGeoObject($name, "P", $placeClassificationSet); } /** Searches for a GeoObject which fits the passed name (name could contain MySQL compatible wildcards) and * the given sets of feature classifications and place classifications. * By default all classifications ("A,P,V,L,U,R,T,H,S") respective (1=big, 5=small, 0=unclassified or very small) are considered. * Returns an array of GeoDBNima-objects which fit the query. */ function findGeoObject($name, $featureClassificationSet = "A,P,V,L,U,R,T,H,S", $placeClassificationSet = "0,1,2,3,4,5,6") { $query = "SELECT *"; $query .= " FROM $this->table"; $query .= " WHERE FC IN ('".str_replace(",", "','", $featureClassificationSet)."') AND PC IN ($placeClassificationSet)"; $query .= " AND FULL_NAME LIKE '$name'"; $query .= " ORDER BY SORT_NAME"; $queryResult = $this->queryGeoDB($query); return $this->transformQueryResult($queryResult); } /** Searches for GeoObjects, which are in a specified radius around the passed GeoObject. * Default is radius of 100 (100 of specified unit, see configuration and maxHits of 50. * A set or a single feature classifications and a single or a set of feature classifications place classification could be passed. * By default all classifications ("A,P,V,L,U,R,T,H,S") respective (1=big, 5=small, 0=unclassified or very small) are considered. * Returns an array of GeoDBNima-objects which lie in the area of the passed GeoObject. */ function findCloseByGeoObjects(&$geoObject, $maxRadius = 100, $maxHits = 50, $featureClassificationSet = "A,P,V,L,U,R,T,H,S", $placeClassificationSet = "0,1,2,3,4,5,6") { $query = "SELECT *"; $query .= " , ".$this->getDistanceMysqlFormula($geoObject)." AS e"; $query .= " FROM $this->table"; $query .= " WHERE FC IN ('".str_replace(",", "','", $featureClassificationSet)."') AND PC IN ($placeClassificationSet)"; $query .= " AND ".$this->getDistanceMysqlFormula($geoObject)." < $maxRadius"; if (GEO_NIMA_NATIVE) { $query .= " AND NT = 'N'"; } $query .= " ORDER BY e ASC"; $query .= " LIMIT 0, $maxHits"; $queryResult = $this->queryGeoDB($query); return $this->transformQueryResult($queryResult); } /** Performs a mysql-query on the nima-database. A valid query must be passed. * Primarily used from within the object, so it should be private. * Returns an array of GeoObjectDBNima-objects which fit the query. */ function performQuery($query) { $geoObjectsDB = GeoDB::performQuery($query); return $this->geoObjetDB2geoObjectDBNima($geoObjectsDB); } /** Transforms a mysql-query-result to an array of GeoObjectDBNima-objects. * Should be used private. */ function transformQueryResult($queryResult) { $result = GeoDB::transformQueryResult($queryResult); return $this->geoObjetDB2geoObjectDBNima($result); } /** Transforms a single GeoObjectDB or an array of these to GeoObjectDBNima in order to * get access to additional information of Nima-Databases like Classification etc. */ function geoObjetDB2geoObjectDBNima(&$geoObjectsDB) { if (is_array($geoObjectsDB)) { $geoObjectsDBNima = array(); for ($i = 0; $i < count($geoObjectsDB); $i++) { $geoObjectsDBNima[] = $this->geoObjetDB2geoObjectDBNima($geoObjectsDB[$i]); } return $geoObjectsDBNima; } else { // Add Nima-specific values to the databaseValues-array of the geoObjectDB $geoObjectsDB->databaseValues['country'] = $this->country; $geoObjectsDB->databaseValues['state'] = $this->states[$geoObjectsDB->databaseValues[ADM1]]; $geoObjectDBNima = new GeoObjectDBNima($geoObjectsDB->name, $geoObjectsDB->latitude, $geoObjectsDB->longitude, $geoObjectsDB->databaseValues, $geoObjectsDB->degree); return $geoObjectDBNima; } } } /** Class GeoDB * Establishes a connection to a mysql-database which includes longitude/latitude values and location names. * Certain find-methods return an array of GeoObjectsDB. * GeoObjectDB include an instance-variable $databaseValues with all the fields of the database. * The constructor abandons a domain or port parameter. These must be set by $geoDB->domain = "xyz". * The standard is "localhost" on port "3306". */ class GeoDB { var $database; var $user; var $password; var $table; var $field_name; var $field_lat; var $field_long; var $degree = true; var $domain = "localhost"; var $port = "3306"; /** Constructor GeoObject * string $database: name of the database * string $user: name of the user * string $password: users password * string $table: the table with the georeferenced data * string $field_name: label of the field, which contains the name of the location * string $field_lat: label of the field, which contains the latitude * string $field_long: label of the field, which contains the longitude * boolean $degree: true by default, declares, if database contains degree-values. * false means, that the values are given as radiant. */ function GeoDB($database, $user, $password, $table, $field_name, $field_lat, $field_long, $degree = true) { $this->database = $database; $this->user = $user; $this->password = $password; $this->table = $table; $this->field_name = $field_name; $this->field_lat = $field_lat; $this->field_long = $field_long; $this->degree = $degree; } /** Performs a mysql-query on the database. A valid query must be passed. * Returns a mysql-query-result. * Should be used private, so don't call it like "$geoDB->queryGeoDB('SELECT * FROM $geoDB->table')", because * we have useful functions to do exactly this from within the object ;-) */ function queryGeoDB($query) { $mysqlConnection = mysql_connect($this->domain, $this->user, $this->password); mysql_select_db($this->database); $queryResult = mysql_query($query); mysql_close($mysqlConnection); return $queryResult; } /** Returns an array of GeoObjectDB-objects where $this->field_name fits the passed parameter $name. * You could call it with placeholders like $geoDB->findLocation("%partOfName%"); */ function findGeoObject($searchConditions) { if (is_array($searchConditions)) { foreach($searchConditions AS $key=>$val) { $where[] = $key." = '".$val."'"; $query = "SELECT * FROM $this->table WHERE ".join(" AND", $where)." ORDER BY $this->field_name"; } } else { $query = "SELECT * FROM $this->table WHERE $this->field_name LIKE '".$searchConditions."' ORDER BY $this->field_name"; } $queryResult = $this->queryGeoDB($query); return $this->transformQueryResult($queryResult); } /** Performs a mysql-query on the database. A valid query must be passed. * Primarily used from within the object, so should be private. * Returns an array of GeoObjectDB-objects which fit the query. */ function performQuery($query) { $queryResult = $this->queryGeoDB($query); return $this->transformQueryResult($queryResult); } /** Searches for GeoObjects, which are in a specified radius around the passed GeoBject. * Default is radius of 100 (100 of specified unit, see configuration and maxHits of 50 * Returns an array of GeoDB-objects which lie in ther radius of the passed GeoObject. */ function findCloseByGeoObjects(&$geoObject, $maxRadius = 100, $maxHits = 50) { $query = "SELECT *, "; $query .= $this->getDistanceMysqlFormula($geoObject)." AS e"; $query .= " FROM $this->table"; $query .= " WHERE ".$this->getDistanceMysqlFormula($geoObject)." < $maxRadius"; $query .= " ORDER BY e ASC LIMIT 0, $maxHits"; $queryResult = $this->queryGeoDB($query); return $this->transformQueryResult($queryResult); } /** Returns the mysql formula which evaluates the distance between the passed GeoObject and the * elements in the database. No need to give it out. Private. */ function getDistanceMysqlFormula(&$geoObject) { $formula = "(ACOS((SIN($geoObject->latitudeRad)*SIN(RADIANS($this->field_lat))) + "; $formula .= "(COS($geoObject->latitudeRad)*COS(RADIANS($this->field_lat))*COS(RADIANS($this->field_long)-$geoObject->longitudeRad))) * "; $formula .= $geoObject->getEarthRadius().")"; return $formula; } /** Transforms a mysql-query-result to an array of GeoObjectDB-objects. * Should be used private. */ function transformQueryResult(&$queryResult) { if (mysql_num_rows($queryResult) == 0) { return array(); } $foundGeoObjects = array(); while ($oneGeoObject = mysql_fetch_array($queryResult)) { // Aufbau des assoziativen Arrays mit allen Datenfeldern $databaseValues = array(); foreach ($oneGeoObject as $objektKey=>$objektWert) { if (!is_integer($objektKey)) { $databaseValues[$objektKey] = $objektWert; } } $name = $oneGeoObject[$this->field_name]; $latitude = $oneGeoObject[$this->field_lat]; $longitude = $oneGeoObject[$this->field_long]; $degree = $this->degree; $foundGeoObjects[] = new GeoObjectDB($name, $latitude, $longitude, $databaseValues, $this->$degree); } return $foundGeoObjects; } /** Returns an RDF-Data-File as described here: http://www.w3.org/2003/01/geo/ * respective as shownhere, with label/name: http://www.w3.org/2003/01/geo/test/xplanet/la.rdf * or, with multiple entries, here: http://www.w3.org/2003/01/geo/test/towns.rdf * Requires an array of GeoObjects as parameter. */ function getRDFDataFile(&$GeoObjectArray) { $rdfData .= "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n"; $rdfData .= "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; $rdfData .= "\txmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\"\n"; $rdfData .= "\txmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\">\n\n"; if (is_array($GeoObjectArray)) { for ($i = 0; $i < count($GeoObjectArray); $i++) { $rdfData .= $GeoObjectArray[$i]->getRDFPointEntry(1); $rdfData .= "\n"; } } $rdfData .= "</rdf:RDF>"; return $rdfData; } } /** Class GeoObjectDB * Extension of GeoObject. Data from a database can be passed to the array databaseValues. * Should be used with class GeoDB which returns GeoObjectDB-objects. */ class GeoObjectDB extends GeoObject { var $databaseValues; /** Constructor GeoObjectDB * string $name: name of the location * float $latitude: latitude given as radiant or degree * float $longitude: longitude given as radiant or degree * array $databaseValues: array of any kind of data * boolean $degree: false by default, has to be set to true if * $latitude annd $longitude absolute > Pi/2, otherwise there is an auto-detection */ function GeoObjectDB($name, $latitude, $longitude, $databaseValues, $degree = false) { GeoObject::GeoObject($name, $latitude, $longitude, $degree); $this->databaseValues = $databaseValues; } } /** Class GeoObjectDBNima * Extension of GeoObjectDB respective GeoObject. * Represents georeferenced data as provided by NIMA (http://www.nima.mil/gns/html/) * Handles UTF-8 names and certain getFunctions for accessing the databaseValues and converting * the output to human readable statements (as listed here: http://www.nima.mil/gns/html/cntyfile/gis.html) */ class GeoObjectDBNima extends GeoObjectDB { var $name; var $utf8name; /** Constructor GeoObjectDBNima * string $name: name of the location * float $latitude: latitude given as radiant or degree * float $longitude: longitude given as radiant or degree * array $databaseValues: array of any kind of data */ function GeoObjectDBNima($name, $latitude, $longitude, $databaseValues) { GeoObjectDB::GeoObjectDB($name, $latitude, $longitude, $databaseValues, true); $this->name = utf8_decode($name); $this->utf8name = $name; } function getFeatureClassification($language = GEO_LANGUAGE) { $availableLanguages = array("en", "de"); if (!in_array($language, $availableLanguages)) { $language = "en"; } $featureClassifications["en"] = array( "A" => "Administrative region", "P" => "Populated place", "V" => "Vegetation", "L" => "Locality or area", "U" => "Undersea", "R" => "Streets, highways, roads, or railroad", "T" => "Hypsographic", "H" => "Hydrographic", "S" => "Spot feature" ); $featureClassifications["de"] = array( "A" => "Administrative Region (Kreis, Land, Regierungsbezirk)", "P" => "Ortschaft", "V" => "Vegetation", "L" => "Lokalität / Gegend", "U" => "Gewässer / Unterwasser", "R" => "Straße oder Bahn", "T" => "Hypsografisch", "H" => "Gewässer", "S" => "Besonderer Punkt" ); $fc = $this->databaseValues["FC"]; return $featureClassifications[$language][$fc]; } } /** Class GeoObject * Represents georeferenced data. Latitude, longitude and name of the location are the basic information. */ class GeoObject { var $name; var $latitude; var $longitude; var $latitudeRad; var $longitudeRad; var $latitudeDMS; var $longitudeDMS; /** Constructor GeoObject * string $name: name of the location * float $latitude: latitude given as radiant or degree * float $longitude: longitude given as radiant or degree * boolean $degree: false by default, has to be set to true if * $latitude annd $longitude absolute > PI, otherwise there is an auto-detection */ function GeoObject($name = "", $latitude = 0., $longitude= 0., $degree = false) { global $cfgStrings; $this->name = $name; if (strstr($latitude, " ") && strstr($longitude, " ")) { $this->latitude = $this->dms2deg($latitude); $this->longitude = $this->dms2deg($longitude); $this->latitudeRad = deg2rad($this->latitude); $this->longitudeRad = deg2rad($this->longitude); } else { if ((abs($latitude) > M_PI) || (abs($longitude) > M_PI)) { $degree = true; } if ($degree) { $this->latitude = $latitude; $this->longitude = $longitude; $this->latitudeRad = deg2rad($this->latitude); $this->longitudeRad = deg2rad($this->longitude); } else { $this->latitude = rad2deg($latitude); $this->longitude = rad2deg($longitude); $this->latitudeRad = $latitude; $this->longitudeRad = $longitude; } } $this->latitudeDMS = ($this->latitude > 0?$cfgStrings[GEO_ORIENTATION_SHORT][GEO_LANGUAGE][0]:$cfgStrings[GEO_ORIENTATION_SHORT][GEO_LANGUAGE][3])." ".$this->deg2dms($this->latitude); $this->longitudeDMS = ($this->longitude > 0?$cfgStrings[GEO_ORIENTATION_SHORT][GEO_LANGUAGE][2]:$cfgStrings[GEO_ORIENTATION_SHORT][GEO_LANGUAGE][5])." ".$this->deg2dms($this->longitude); } /** Returns the radius of the earth in the given unit. * GEO_EARTH_RADIUS is set to the mean value: 6371. km * equatorial radius as of WGS84: 6378.137 km */ function getEarthRadius($unit = GEO_UNIT) { switch ($unit) { case "km": // Kilometer return GEO_EARTH_RADIUS; case "miles": // Meilen return GEO_EARTH_RADIUS * 0.621371; case "in": // Zoll/Inch return GEO_EARTH_RADIUS * 39370.08; case "sm": // See-Meilen return GEO_EARTH_RADIUS * 0.5399568; default: return GEO_EARTH_RADIUS; } } /** Returns the distance between an overgiven and this GeoObject in the passed unit as float. */ function getDistance(&$geoObject, $unit = GEO_UNIT) { $erdradius = $this->getEarthRadius($unit); return acos((sin($this->latitudeRad) * sin($geoObject->latitudeRad)) + (cos($this->latitudeRad) * cos($geoObject->latitudeRad) * cos($this->longitudeRad - $geoObject->longitudeRad))) * $erdradius; } /** Returns the distance between an overgiven and this GeoObject * rounded to 2 decimal places. The passed unti is returned at the end of the sting. */ function getDistanceString(&$geoObject, $unit = GEO_UNIT) { return round($this->getDistance($geoObject, $unit), 2)." ".$unit; } /** Returns the north-south distance between this and the passed object in the passed unit as float. */ function getDistanceNS(&$geoObject, $unit = GEO_UNIT) { $erdradius = $this->getEarthRadius($unit); if ($this->latitudeRad > $geoObject->latitudeRad) { $direction = -1; } else { $direction = 1; } return $direction * acos((sin($this->latitudeRad) * sin($geoObject->latitudeRad)) + (cos($this->latitudeRad) * cos($geoObject->latitudeRad))) * $erdradius; } /** Returns the west-east distance between this and the passed object in the passed unit as float. */ function getDistanceWE(&$geoObject, $unit = GEO_UNIT) { $erdradius = $this->getEarthRadius($unit); if ($this->longitudeRad > $geoObject->longitudeRad) { $direction = -1; } else { $direction = 1; } return $direction * acos(pow(sin($this->latitudeRad), 2) + (pow(cos($this->latitudeRad), 2) * cos($this->longitudeRad - $geoObject->longitudeRad))) * $erdradius; } /** Returns the orientation of the parametric GeoObject to this, like "GeoObject lies to the north of this" * Orientation are declared within this function. */ function getOrientation(&$geoObject, $form = GEO_ORIENTATION_SHORT, $language = GEO_LANGUAGE) { global $cfgStrings; global $cfgLanguages; $availableLanguages = array("en", "de"); if (!in_array($language, $availableLanguages)) { $language = "en"; } $availableForms = array(GEO_ORIENTATION_SHORT, GEO_ORIENTATION_LONG); if (!in_array($form, $availableForms)) { $form = GEO_ORIENTATION_SHORT; } $x = $this->getDistanceWE($geoObject); $y = $this->getDistanceNS($geoObject); $winkel = rad2deg(atan2($y, $x)); if (($winkel > 67.5) && ($winkel <= 112.5)) { return $cfgStrings[$form][$language][0]; } elseif (($winkel > 22.5) && ($winkel <= 67.5)) { return $cfgStrings[$form][$language][1]; } elseif (($winkel <= 22.5) && ($winkel > -22.5)) { return $cfgStrings[$form][$language][2]; } elseif (($winkel <= -22.5) && ($winkel > -67.5)) { return $cfgStrings[$form][$language][3]; } elseif (($winkel <= -67.5) && ($winkel > -112.5)) { return $cfgStrings[$form][$language][4]; } elseif (($winkel <= -112.5) && ($winkel > -157.5)) { return $cfgStrings[$form][$language][5]; } elseif (($winkel > 157.5) || ($winkel <= -157.5)) { return $cfgStrings[$form][$language][6]; } elseif (($winkel > 112.5) && ($winkel <= 157.5)) { return $cfgStrings[$form][$language][7]; } else { return ""; } } /** Returns an RDF-point entry as described here: http://www.w3.org/2003/01/geo/ * respective as shownhere, with label/name: http://www.w3.org/2003/01/geo/test/xplanet/la.rdf * or, with multiple entries, here: http://www.w3.org/2003/01/geo/test/towns.rdf * Use getRDFDataFile() for a document with header and footer. * The indent-paramter allows a better structure. */ function getRDFPointEntry($indent=0) { $indentString = ""; for ($i = 0; $i < $indent; $i++) { $indentString .= "\t"; } $rdfEntry = $indentString."<geo:Point>\n"; $rdfEntry .= $indentString."\t<rdfs:label>".utf8_encode($this->name)."</rdfs:label>\n"; $rdfEntry .= $indentString."\t<geo:lat>".$this->latitude."</geo:lat>\n"; $rdfEntry .= $indentString."\t<geo:long>".$this->longitude."</geo:long>\n"; $rdfEntry .= $indentString."</geo:Point>\n"; return $rdfEntry; } /** Returns an RDF-Data-File as described here: http://www.w3.org/2003/01/geo/ * respective as shownhere, with label/name: http://www.w3.org/2003/01/geo/test/xplanet/la.rdf * or, with multiple entries, here: http://www.w3.org/2003/01/geo/test/towns.rdf * The only entry is this Object. */ function getRDFDataFile() { $rdfData = "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; $rdfData .= "\txmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\"\n"; $rdfData .= "\txmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\">\n\n"; $rdfData .= $this->getRDFPointEntry(1); $rdfData .= "\n</rdf:RDF>"; return $rdfData; } /** Returns a short info about the GeoObject */ function getInfo() { return $this->name." (".$this->latitude."/".$this->longitude.")"; } /** Converts a string which represents a latitude/longitude as degree/minutes/seconds * to a float degree value. If no valid string is passed it will return 0. */ function dms2deg($dms) { $searchPattern = "|\s*([NSWOE\-\+]?)\s*(\d{1,3})[\s]*(\d{1,2})[\'\s]*(\d{1,2})[\'\"\s]*|i"; //$searchPattern = "|\d|"; if(preg_match($searchPattern, $dms, $result)) { if (($result[1] == "-") || ($result[1] == "S") || ($result[1] == "W") || ($result[1] == "s") || ($result[1] == "w")) { $algSign = -1.; } else { $algSign = 1.; } return $algSign * ($result[2] +(($result[3] + ($result[4] * 10/6)/100)*10/6)/100); } else { return 0.; } } /** Converts a float value to the degree-minute-second form. The seconds could contain * the number of decimal places one passes to the optional parameter $decPlaces. * The direction (N, S, W, E) must be added manually (e.g. $output = "E ".deg2dms(7.441944); ) */ function deg2dms($degFloat, $decPlaces = 0) { $degree = abs(floor($degFloat)); $minSec = 60 * ($degFloat - $degree); $minutes = floor($minSec); $seconds = round(($minSec - $minutes) * 60, $decPlaces); return $degree."° $minutes' $seconds''"; } } /** Class CreateGeoObjectArrayFromRDF * Creates an array of GeoObjects out of a RDF-file-content/string * RDF-Style as referenced here: http://www.w3.org/2003/01/geo/ * respective as shownhere, with label/name: http://www.w3.org/2003/01/geo/test/xplanet/la.rdf * or, with multiple entries, here: http://www.w3.org/2003/01/geo/test/towns.rdf * It might be useful ti use the extractGeoObjects($rdfContent)-function only. This one returns the array. */ class CreateGeoObjectArrayFromRDF { var $geoObjectArray = array(); /** Constructor CreateGeoObjectArrayFromRDF * string $rdfContent: content of the rdf-file * Note: One could leave the parameter. getGeoObjectArray() will return an empty * array, until setArrayOfGeoObjects($rdfContent) sets a value. * It might be ok to just use the extractGeoObjects($rdfContent)-function. */ function CreateGeoObjectArrayFromRDF($rdfContent = "") { $this->setArrayOfGeoObjects($rdfContent); } /** Sets the instance-variable to the new value. */ function setArrayOfGeoObjects($rdfContent) { $this->geoObjectArray = $this->extractGeoObjects($rdfContent); } /** Returns an array of GeoObjects, which are extracted from the passed string/file-content */ function extractGeoObjects($rdfContent) { global $cfgStrings; // Make the file flat $rdfContent = str_replace(array("\r", "\n"), array("", ""), $rdfContent); $rawPpointArray = explode("</geo:Point>", $rdfContent); $pointArray = array(); foreach ($rawPpointArray as $onePointSetRaw) { $parts = explode("<geo:Point>", $onePointSetRaw); $pointArray[] = $parts[1]; } $returnArray = array(); foreach ($pointArray as $onePoint) { $error = false; $searchName = "|(.*)(<rdfs:label>)(.*)(</rdfs:label>)(.*)|i"; if (preg_match($searchName, $onePoint, $searchResult)) { $name = $searchResult[3]; } else { $name = $cfgStrings[GEO_ERR_NONAME][GEO_LANGUAGE]; } $searchLatitude = "|(.*)(<geo:lat>)(.*)(</geo:lat>)(.*)|i"; if (preg_match($searchLatitude, $onePoint, $searchResult)) { $latitude = $searchResult[3]; } else { $error = true; } $searchLongitude = "|(.*)(<geo:long>)(.*)(</geo:long>)(.*)|i"; if (preg_match($searchLongitude, $onePoint, $searchResult)) { $longitude = $searchResult[3]; } else { $error = true; } if (!$error) { $returnArray[] = new GeoObject($name, $latitude, $longitude); } } return $returnArray; } /** Returns the instance-variable with the array of GeoObjects */ function getGeoObjectArray() { return $this->geoObjectArray; } } ?>
© multimediamotz, Stefan Motz 2003