Initial import.

This commit is contained in:
ekes 2015-02-24 16:25:12 +01:00
commit 86383280c9
428 changed files with 68738 additions and 0 deletions

View file

@ -0,0 +1,96 @@
<?php
/**
* EWKB (Extended Well Known Binary) Adapter
*/
class EWKB extends WKB
{
/**
* Read WKB binary string into geometry objects
*
* @param string $wkb An Extended-WKB binary string
*
* @return Geometry
*/
public function read($wkb, $is_hex_string = FALSE) {
if ($is_hex_string) {
$wkb = pack('H*',$wkb);
}
// Open the wkb up in memory so we can examine the SRID
$mem = fopen('php://memory', 'r+');
fwrite($mem, $wkb);
fseek($mem, 0);
$base_info = unpack("corder/ctype/cz/cm/cs", fread($mem, 5));
if ($base_info['s']) {
$srid = current(unpack("Lsrid", fread($mem, 4)));
}
else {
$srid = NULL;
}
fclose($mem);
// Run the wkb through the normal WKB reader to get the geometry
$wkb_reader = new WKB();
$geom = $wkb_reader->read($wkb);
// If there is an SRID, add it to the geometry
if ($srid) {
$geom->setSRID($srid);
}
return $geom;
}
/**
* Serialize geometries into an EWKB binary string.
*
* @param Geometry $geometry
*
* @return string The Extended-WKB binary string representation of the input geometries
*/
public function write(Geometry $geometry, $write_as_hex = FALSE) {
// We always write into NDR (little endian)
$wkb = pack('c',1);
switch ($geometry->getGeomType()) {
case 'Point';
$wkb .= pack('L',1);
$wkb .= $this->writePoint($geometry);
break;
case 'LineString';
$wkb .= pack('L',2);
$wkb .= $this->writeLineString($geometry);
break;
case 'Polygon';
$wkb .= pack('L',3);
$wkb .= $this->writePolygon($geometry);
break;
case 'MultiPoint';
$wkb .= pack('L',4);
$wkb .= $this->writeMulti($geometry);
break;
case 'MultiLineString';
$wkb .= pack('L',5);
$wkb .= $this->writeMulti($geometry);
break;
case 'MultiPolygon';
$wkb .= pack('L',6);
$wkb .= $this->writeMulti($geometry);
break;
case 'GeometryCollection';
$wkb .= pack('L',7);
$wkb .= $this->writeMulti($geometry);
break;
}
if ($write_as_hex) {
$unpacked = unpack('H*',$wkb);
return $unpacked[1];
}
else {
return $wkb;
}
}
}

View file

@ -0,0 +1,27 @@
<?php
/**
* EWKT (Extended Well Known Text) Adapter
*/
class EWKT extends WKT
{
/**
* Serialize geometries into an EWKT string.
*
* @param Geometry $geometry
*
* @return string The Extended-WKT string representation of the input geometries
*/
public function write(Geometry $geometry) {
$srid = $geometry->SRID();
$wkt = '';
if ($srid) {
$wkt = 'SRID=' . $srid . ';';
$wkt .= $geometry->out('wkt');
return $wkt;
}
else {
return $geometry->out('wkt');
}
}
}

View file

@ -0,0 +1,180 @@
<?php
/*
* Copyright (c) Patrick Hayes
*
* This code is open-source and licenced under the Modified BSD License.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* PHP Geometry/GPX encoder/decoder
*/
class GPX extends GeoAdapter
{
private $namespace = FALSE;
private $nss = ''; // Name-space string. eg 'georss:'
/**
* Read GPX string into geometry objects
*
* @param string $gpx A GPX string
*
* @return Geometry|GeometryCollection
*/
public function read($gpx) {
return $this->geomFromText($gpx);
}
/**
* Serialize geometries into a GPX string.
*
* @param Geometry $geometry
*
* @return string The GPX string representation of the input geometries
*/
public function write(Geometry $geometry, $namespace = FALSE) {
if ($geometry->isEmpty()) return NULL;
if ($namespace) {
$this->namespace = $namespace;
$this->nss = $namespace.':';
}
return '<'.$this->nss.'gpx creator="geoPHP" version="1.0">'.$this->geometryToGPX($geometry).'</'.$this->nss.'gpx>';
}
public function geomFromText($text) {
// Change to lower-case and strip all CDATA
$text = strtolower($text);
$text = preg_replace('/<!\[cdata\[(.*?)\]\]>/s','',$text);
// Load into DOMDocument
$xmlobj = new DOMDocument();
@$xmlobj->loadXML($text);
if ($xmlobj === false) {
throw new Exception("Invalid GPX: ". $text);
}
$this->xmlobj = $xmlobj;
try {
$geom = $this->geomFromXML();
} catch(InvalidText $e) {
throw new Exception("Cannot Read Geometry From GPX: ". $text);
} catch(Exception $e) {
throw $e;
}
return $geom;
}
protected function geomFromXML() {
$geometries = array();
$geometries = array_merge($geometries, $this->parseWaypoints());
$geometries = array_merge($geometries, $this->parseTracks());
$geometries = array_merge($geometries, $this->parseRoutes());
if (empty($geometries)) {
throw new Exception("Invalid / Empty GPX");
}
return geoPHP::geometryReduce($geometries);
}
protected function childElements($xml, $nodename = '') {
$children = array();
foreach ($xml->childNodes as $child) {
if ($child->nodeName == $nodename) {
$children[] = $child;
}
}
return $children;
}
protected function parseWaypoints() {
$points = array();
$wpt_elements = $this->xmlobj->getElementsByTagName('wpt');
foreach ($wpt_elements as $wpt) {
$lat = $wpt->attributes->getNamedItem("lat")->nodeValue;
$lon = $wpt->attributes->getNamedItem("lon")->nodeValue;
$points[] = new Point($lon, $lat);
}
return $points;
}
protected function parseTracks() {
$lines = array();
$trk_elements = $this->xmlobj->getElementsByTagName('trk');
foreach ($trk_elements as $trk) {
$components = array();
foreach ($this->childElements($trk, 'trkseg') as $trkseg) {
foreach ($this->childElements($trkseg, 'trkpt') as $trkpt) {
$lat = $trkpt->attributes->getNamedItem("lat")->nodeValue;
$lon = $trkpt->attributes->getNamedItem("lon")->nodeValue;
$components[] = new Point($lon, $lat);
}
}
if ($components) {$lines[] = new LineString($components);}
}
return $lines;
}
protected function parseRoutes() {
$lines = array();
$rte_elements = $this->xmlobj->getElementsByTagName('rte');
foreach ($rte_elements as $rte) {
$components = array();
foreach ($this->childElements($rte, 'rtept') as $rtept) {
$lat = $rtept->attributes->getNamedItem("lat")->nodeValue;
$lon = $rtept->attributes->getNamedItem("lon")->nodeValue;
$components[] = new Point($lon, $lat);
}
$lines[] = new LineString($components);
}
return $lines;
}
protected function geometryToGPX($geom) {
$type = strtolower($geom->getGeomType());
switch ($type) {
case 'point':
return $this->pointToGPX($geom);
break;
case 'linestring':
return $this->linestringToGPX($geom);
break;
case 'polygon':
case 'multipoint':
case 'multilinestring':
case 'multipolygon':
case 'geometrycollection':
return $this->collectionToGPX($geom);
break;
}
}
private function pointToGPX($geom) {
return '<'.$this->nss.'wpt lat="'.$geom->getY().'" lon="'.$geom->getX().'" />';
}
private function linestringToGPX($geom) {
$gpx = '<'.$this->nss.'trk><'.$this->nss.'trkseg>';
foreach ($geom->getComponents() as $comp) {
$gpx .= '<'.$this->nss.'trkpt lat="'.$comp->getY().'" lon="'.$comp->getX().'" />';
}
$gpx .= '</'.$this->nss.'trkseg></'.$this->nss.'trk>';
return $gpx;
}
public function collectionToGPX($geom) {
$gpx = '';
$components = $geom->getComponents();
foreach ($geom->getComponents() as $comp) {
$gpx .= $this->geometryToGPX($comp);
}
return $gpx;
}
}

View file

@ -0,0 +1,31 @@
<?php
/*
* (c) Patrick Hayes 2011
*
* This code is open-source and licenced under the Modified BSD License.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* GeoAdapter : abstract class which represents an adapter
* for reading and writing to and from Geomtry objects
*
*/
abstract class GeoAdapter
{
/**
* Read input and return a Geomtry or GeometryCollection
*
* @return Geometry|GeometryCollection
*/
abstract public function read($input);
/**
* Write out a Geomtry or GeometryCollection in the adapter's format
*
* @return mixed
*/
abstract public function write(Geometry $geometry);
}

View file

@ -0,0 +1,249 @@
<?php
/**
* PHP Geometry GeoHash encoder/decoder.
*
* @author prinsmc
* @see http://en.wikipedia.org/wiki/Geohash
*
*/
class GeoHash extends GeoAdapter{
/**
* base32 encoding character map.
*/
private $table = "0123456789bcdefghjkmnpqrstuvwxyz";
/**
* array of neighbouring hash character maps.
*/
private $neighbours = array (
// north
'top' => array (
'even' => 'p0r21436x8zb9dcf5h7kjnmqesgutwvy',
'odd' => 'bc01fg45238967deuvhjyznpkmstqrwx'
),
// east
'right' => array (
'even' => 'bc01fg45238967deuvhjyznpkmstqrwx',
'odd' => 'p0r21436x8zb9dcf5h7kjnmqesgutwvy'
),
// west
'left' => array (
'even' => '238967debc01fg45kmstqrwxuvhjyznp',
'odd' => '14365h7k9dcfesgujnmqp0r2twvyx8zb'
),
// south
'bottom' => array (
'even' => '14365h7k9dcfesgujnmqp0r2twvyx8zb',
'odd' => '238967debc01fg45kmstqrwxuvhjyznp'
)
);
/**
* array of bordering hash character maps.
*/
private $borders = array (
// north
'top' => array (
'even' => 'prxz',
'odd' => 'bcfguvyz'
),
// east
'right' => array (
'even' => 'bcfguvyz',
'odd' => 'prxz'
),
// west
'left' => array (
'even' => '0145hjnp',
'odd' => '028b'
),
// south
'bottom' => array (
'even' => '028b',
'odd' => '0145hjnp'
)
);
/**
* Convert the geohash to a Point. The point is 2-dimensional.
* @return Point the converted geohash
* @param string $hash a geohash
* @see GeoAdapter::read()
*/
public function read($hash, $as_grid = FALSE) {
$ll = $this->decode($hash);
if (!$as_grid) {
return new Point($ll['medlon'], $ll['medlat']);
}
else {
return new Polygon(array(
new LineString(array(
new Point($ll['minlon'], $ll['maxlat']),
new Point($ll['maxlon'], $ll['maxlat']),
new Point($ll['maxlon'], $ll['minlat']),
new Point($ll['minlon'], $ll['minlat']),
new Point($ll['minlon'], $ll['maxlat']),
))
));
}
}
/**
* Convert the geometry to geohash.
* @return string the geohash or null when the $geometry is not a Point
* @param Point $geometry
* @see GeoAdapter::write()
*/
public function write(Geometry $geometry, $precision = NULL){
if ($geometry->isEmpty()) return '';
if($geometry->geometryType() === 'Point'){
return $this->encodePoint($geometry, $precision);
}
else {
// The geohash is the hash grid ID that fits the envelope
$envelope = $geometry->envelope();
$geohashes = array();
$geohash = '';
foreach ($envelope->getPoints() as $point) {
$geohashes[] = $this->encodePoint($point, 0.0000001);
}
$i = 0;
while ($i < strlen($geohashes[0])) {
$char = $geohashes[0][$i];
foreach ($geohashes as $hash) {
if ($hash[$i] != $char) {
return $geohash;
}
}
$geohash .= $char;
$i++;
}
return $geohash;
}
}
/**
* @return string geohash
* @param Point $point
* @author algorithm based on code by Alexander Songe <a@songe.me>
* @see https://github.com/asonge/php-geohash/issues/1
*/
private function encodePoint($point, $precision = NULL){
if ($precision === NULL) {
$lap = strlen($point->y())-strpos($point->y(),".");
$lop = strlen($point->x())-strpos($point->x(),".");
$precision = pow(10,-max($lap-1,$lop-1,0))/2;
}
$minlat = -90;
$maxlat = 90;
$minlon = -180;
$maxlon = 180;
$latE = 90;
$lonE = 180;
$i = 0;
$error = 180;
$hash='';
while($error>=$precision) {
$chr = 0;
for($b=4;$b>=0;--$b) {
if((1&$b) == (1&$i)) {
// even char, even bit OR odd char, odd bit...a lon
$next = ($minlon+$maxlon)/2;
if($point->x()>$next) {
$chr |= pow(2,$b);
$minlon = $next;
} else {
$maxlon = $next;
}
$lonE /= 2;
} else {
// odd char, even bit OR even char, odd bit...a lat
$next = ($minlat+$maxlat)/2;
if($point->y()>$next) {
$chr |= pow(2,$b);
$minlat = $next;
} else {
$maxlat = $next;
}
$latE /= 2;
}
}
$hash .= $this->table[$chr];
$i++;
$error = min($latE,$lonE);
}
return $hash;
}
/**
* @param string $hash a geohash
* @author algorithm based on code by Alexander Songe <a@songe.me>
* @see https://github.com/asonge/php-geohash/issues/1
*/
private function decode($hash){
$ll = array();
$minlat = -90;
$maxlat = 90;
$minlon = -180;
$maxlon = 180;
$latE = 90;
$lonE = 180;
for($i=0,$c=strlen($hash);$i<$c;$i++) {
$v = strpos($this->table,$hash[$i]);
if(1&$i) {
if(16&$v)$minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
if(8&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
if(4&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
if(2&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
if(1&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
$latE /= 8;
$lonE /= 4;
} else {
if(16&$v)$minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
if(8&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
if(4&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
if(2&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
if(1&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
$latE /= 4;
$lonE /= 8;
}
}
$ll['minlat'] = $minlat;
$ll['minlon'] = $minlon;
$ll['maxlat'] = $maxlat;
$ll['maxlon'] = $maxlon;
$ll['medlat'] = round(($minlat+$maxlat)/2, max(1, -round(log10($latE)))-1);
$ll['medlon'] = round(($minlon+$maxlon)/2, max(1, -round(log10($lonE)))-1);
return $ll;
}
/**
* Calculates the adjacent geohash of the geohash in the specified direction.
* This algorithm is available in various ports that seem to point back to
* geohash-js by David Troy under MIT notice.
*
*
* @see https://github.com/davetroy/geohash-js
* @see https://github.com/lyokato/objc-geohash
* @see https://github.com/lyokato/libgeohash
* @see https://github.com/masuidrive/pr_geohash
* @see https://github.com/sunng87/node-geohash
* @see https://github.com/davidmoten/geo
*
* @param string $hash the geohash (lowercase)
* @param string $direction the direction of the neighbor (top, bottom, left or right)
* @return string the geohash of the adjacent cell
*/
public function adjacent($hash, $direction){
$last = substr($hash, -1);
$type = (strlen($hash) % 2)? 'odd': 'even';
$base = substr($hash, 0, strlen($hash) - 1);
if(strpos(($this->borders[$direction][$type]), $last) !== false){
$base = $this->adjacent($base, $direction);
}
return $base.$this->table[strpos($this->neighbours[$direction][$type], $last)];
}
}

View file

@ -0,0 +1,155 @@
<?php
/**
* GeoJSON class : a geojson reader/writer.
*
* Note that it will always return a GeoJSON geometry. This
* means that if you pass it a feature, it will return the
* geometry of that feature strip everything else.
*/
class GeoJSON extends GeoAdapter
{
/**
* Given an object or a string, return a Geometry
*
* @param mixed $input The GeoJSON string or object
*
* @return object Geometry
*/
public function read($input) {
if (is_string($input)) {
$input = json_decode($input);
}
if (!is_object($input)) {
throw new Exception('Invalid JSON');
}
if (!is_string($input->type)) {
throw new Exception('Invalid JSON');
}
// Check to see if it's a FeatureCollection
if ($input->type == 'FeatureCollection') {
$geoms = array();
foreach ($input->features as $feature) {
$geoms[] = $this->read($feature);
}
return geoPHP::geometryReduce($geoms);
}
// Check to see if it's a Feature
if ($input->type == 'Feature') {
return $this->read($input->geometry);
}
// It's a geometry - process it
return $this->objToGeom($input);
}
private function objToGeom($obj) {
$type = $obj->type;
if ($type == 'GeometryCollection') {
return $this->objToGeometryCollection($obj);
}
$method = 'arrayTo' . $type;
return $this->$method($obj->coordinates);
}
private function arrayToPoint($array) {
if (!empty($array)) {
return new Point($array[0], $array[1]);
}
else {
return new Point();
}
}
private function arrayToLineString($array) {
$points = array();
foreach ($array as $comp_array) {
$points[] = $this->arrayToPoint($comp_array);
}
return new LineString($points);
}
private function arrayToPolygon($array) {
$lines = array();
foreach ($array as $comp_array) {
$lines[] = $this->arrayToLineString($comp_array);
}
return new Polygon($lines);
}
private function arrayToMultiPoint($array) {
$points = array();
foreach ($array as $comp_array) {
$points[] = $this->arrayToPoint($comp_array);
}
return new MultiPoint($points);
}
private function arrayToMultiLineString($array) {
$lines = array();
foreach ($array as $comp_array) {
$lines[] = $this->arrayToLineString($comp_array);
}
return new MultiLineString($lines);
}
private function arrayToMultiPolygon($array) {
$polys = array();
foreach ($array as $comp_array) {
$polys[] = $this->arrayToPolygon($comp_array);
}
return new MultiPolygon($polys);
}
private function objToGeometryCollection($obj) {
$geoms = array();
if (empty($obj->geometries)) {
throw new Exception('Invalid GeoJSON: GeometryCollection with no component geometries');
}
foreach ($obj->geometries as $comp_object) {
$geoms[] = $this->objToGeom($comp_object);
}
return new GeometryCollection($geoms);
}
/**
* Serializes an object into a geojson string
*
*
* @param Geometry $obj The object to serialize
*
* @return string The GeoJSON string
*/
public function write(Geometry $geometry, $return_array = FALSE) {
if ($return_array) {
return $this->getArray($geometry);
}
else {
return json_encode($this->getArray($geometry));
}
}
public function getArray($geometry) {
if ($geometry->getGeomType() == 'GeometryCollection') {
$component_array = array();
foreach ($geometry->components as $component) {
$component_array[] = array(
'type' => $component->geometryType(),
'coordinates' => $component->asArray(),
);
}
return array(
'type'=> 'GeometryCollection',
'geometries'=> $component_array,
);
}
else return array(
'type'=> $geometry->getGeomType(),
'coordinates'=> $geometry->asArray(),
);
}
}

View file

@ -0,0 +1,244 @@
<?php
/*
* Copyright (c) Patrick Hayes
*
* This code is open-source and licenced under the Modified BSD License.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* PHP Geometry/GeoRSS encoder/decoder
*/
class GeoRSS extends GeoAdapter
{
private $namespace = FALSE;
private $nss = ''; // Name-space string. eg 'georss:'
/**
* Read GeoRSS string into geometry objects
*
* @param string $georss - an XML feed containing geoRSS
*
* @return Geometry|GeometryCollection
*/
public function read($gpx) {
return $this->geomFromText($gpx);
}
/**
* Serialize geometries into a GeoRSS string.
*
* @param Geometry $geometry
*
* @return string The georss string representation of the input geometries
*/
public function write(Geometry $geometry, $namespace = FALSE) {
if ($namespace) {
$this->namespace = $namespace;
$this->nss = $namespace.':';
}
return $this->geometryToGeoRSS($geometry);
}
public function geomFromText($text) {
// Change to lower-case, strip all CDATA, and de-namespace
$text = strtolower($text);
$text = preg_replace('/<!\[cdata\[(.*?)\]\]>/s','',$text);
// Load into DOMDOcument
$xmlobj = new DOMDocument();
@$xmlobj->loadXML($text);
if ($xmlobj === false) {
throw new Exception("Invalid GeoRSS: ". $text);
}
$this->xmlobj = $xmlobj;
try {
$geom = $this->geomFromXML();
} catch(InvalidText $e) {
throw new Exception("Cannot Read Geometry From GeoRSS: ". $text);
} catch(Exception $e) {
throw $e;
}
return $geom;
}
protected function geomFromXML() {
$geometries = array();
$geometries = array_merge($geometries, $this->parsePoints());
$geometries = array_merge($geometries, $this->parseLines());
$geometries = array_merge($geometries, $this->parsePolygons());
$geometries = array_merge($geometries, $this->parseBoxes());
$geometries = array_merge($geometries, $this->parseCircles());
if (empty($geometries)) {
throw new Exception("Invalid / Empty GeoRSS");
}
return geoPHP::geometryReduce($geometries);
}
protected function getPointsFromCoords($string) {
$coords = array();
if (empty($string)) {
return $coords;
}
$latlon = explode(' ',$string);
foreach ($latlon as $key => $item) {
if (!($key % 2)) {
// It's a latitude
$lat = $item;
}
else {
// It's a longitude
$lon = $item;
$coords[] = new Point($lon, $lat);
}
}
return $coords;
}
protected function parsePoints() {
$points = array();
$pt_elements = $this->xmlobj->getElementsByTagName('point');
foreach ($pt_elements as $pt) {
if ($pt->hasChildNodes()) {
$point_array = $this->getPointsFromCoords(trim($pt->firstChild->nodeValue));
}
if (!empty($point_array)) {
$points[] = $point_array[0];
}
else {
$points[] = new Point();
}
}
return $points;
}
protected function parseLines() {
$lines = array();
$line_elements = $this->xmlobj->getElementsByTagName('line');
foreach ($line_elements as $line) {
$components = $this->getPointsFromCoords(trim($line->firstChild->nodeValue));
$lines[] = new LineString($components);
}
return $lines;
}
protected function parsePolygons() {
$polygons = array();
$poly_elements = $this->xmlobj->getElementsByTagName('polygon');
foreach ($poly_elements as $poly) {
if ($poly->hasChildNodes()) {
$points = $this->getPointsFromCoords(trim($poly->firstChild->nodeValue));
$exterior_ring = new LineString($points);
$polygons[] = new Polygon(array($exterior_ring));
}
else {
// It's an EMPTY polygon
$polygons[] = new Polygon();
}
}
return $polygons;
}
// Boxes are rendered into polygons
protected function parseBoxes() {
$polygons = array();
$box_elements = $this->xmlobj->getElementsByTagName('box');
foreach ($box_elements as $box) {
$parts = explode(' ',trim($box->firstChild->nodeValue));
$components = array(
new Point($parts[3], $parts[2]),
new Point($parts[3], $parts[0]),
new Point($parts[1], $parts[0]),
new Point($parts[1], $parts[2]),
new Point($parts[3], $parts[2]),
);
$exterior_ring = new LineString($components);
$polygons[] = new Polygon(array($exterior_ring));
}
return $polygons;
}
// Circles are rendered into points
// @@TODO: Add good support once we have circular-string geometry support
protected function parseCircles() {
$points = array();
$circle_elements = $this->xmlobj->getElementsByTagName('circle');
foreach ($circle_elements as $circle) {
$parts = explode(' ',trim($circle->firstChild->nodeValue));
$points[] = new Point($parts[1], $parts[0]);
}
return $points;
}
protected function geometryToGeoRSS($geom) {
$type = strtolower($geom->getGeomType());
switch ($type) {
case 'point':
return $this->pointToGeoRSS($geom);
break;
case 'linestring':
return $this->linestringToGeoRSS($geom);
break;
case 'polygon':
return $this->PolygonToGeoRSS($geom);
break;
case 'multipoint':
case 'multilinestring':
case 'multipolygon':
case 'geometrycollection':
return $this->collectionToGeoRSS($geom);
break;
}
return $output;
}
private function pointToGeoRSS($geom) {
$out = '<'.$this->nss.'point>';
if (!$geom->isEmpty()) {
$out .= $geom->getY().' '.$geom->getX();
}
$out .= '</'.$this->nss.'point>';
return $out;
}
private function linestringToGeoRSS($geom) {
$output = '<'.$this->nss.'line>';
foreach ($geom->getComponents() as $k => $point) {
$output .= $point->getY().' '.$point->getX();
if ($k < ($geom->numGeometries() -1)) $output .= ' ';
}
$output .= '</'.$this->nss.'line>';
return $output;
}
private function polygonToGeoRSS($geom) {
$output = '<'.$this->nss.'polygon>';
$exterior_ring = $geom->exteriorRing();
foreach ($exterior_ring->getComponents() as $k => $point) {
$output .= $point->getY().' '.$point->getX();
if ($k < ($exterior_ring->numGeometries() -1)) $output .= ' ';
}
$output .= '</'.$this->nss.'polygon>';
return $output;
}
public function collectionToGeoRSS($geom) {
$georss = '<'.$this->nss.'where>';
$components = $geom->getComponents();
foreach ($geom->getComponents() as $comp) {
$georss .= $this->geometryToGeoRSS($comp);
}
$georss .= '</'.$this->nss.'where>';
return $georss;
}
}

View file

@ -0,0 +1,158 @@
<?php
/*
* (c) Camptocamp <info@camptocamp.com>
* (c) Patrick Hayes
*
* This code is open-source and licenced under the Modified BSD License.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* PHP Google Geocoder Adapter
*
*
* @package geoPHP
* @author Patrick Hayes <patrick.d.hayes@gmail.com>
*/
class GoogleGeocode extends GeoAdapter
{
/**
* Read an address string or array geometry objects
*
* @param string - Address to geocode
* @param string - Type of Geometry to return. Can either be 'points' or 'bounds' (polygon)
* @param Geometry|bounds-array - Limit the search area to within this region. For example
* by default geocoding "Cairo" will return the location of Cairo Egypt.
* If you pass a polygon of illinois, it will return Cairo IL.
* @param return_multiple - Return all results in a multipoint or multipolygon
* @return Geometry|GeometryCollection
*/
public function read($address, $return_type = 'point', $bounds = FALSE, $return_multiple = FALSE) {
if (is_array($address)) $address = join(',', $address);
if (gettype($bounds) == 'object') {
$bounds = $bounds->getBBox();
}
if (gettype($bounds) == 'array') {
$bounds_string = '&bounds='.$bounds['miny'].','.$bounds['minx'].'|'.$bounds['maxy'].','.$bounds['maxx'];
}
else {
$bounds_string = '';
}
$url = "http://maps.googleapis.com/maps/api/geocode/json";
$url .= '?address='. urlencode($address);
$url .= $bounds_string;
$url .= '&sensor=false';
$this->result = json_decode(@file_get_contents($url));
if ($this->result->status == 'OK') {
if ($return_multiple == FALSE) {
if ($return_type == 'point') {
return $this->getPoint();
}
if ($return_type == 'bounds' || $return_type == 'polygon') {
return $this->getPolygon();
}
}
if ($return_multiple == TRUE) {
if ($return_type == 'point') {
$points = array();
foreach ($this->result->results as $delta => $item) {
$points[] = $this->getPoint($delta);
}
return new MultiPoint($points);
}
if ($return_type == 'bounds' || $return_type == 'polygon') {
$polygons = array();
foreach ($this->result->results as $delta => $item) {
$polygons[] = $this->getPolygon($delta);
}
return new MultiPolygon($polygons);
}
}
}
else {
if ($this->result->status) throw new Exception('Error in Google Geocoder: '.$this->result->status);
else throw new Exception('Unknown error in Google Geocoder');
return FALSE;
}
}
/**
* Serialize geometries into a WKT string.
*
* @param Geometry $geometry
* @param string $return_type Should be either 'string' or 'array'
*
* @return string Does a reverse geocode of the geometry
*/
public function write(Geometry $geometry, $return_type = 'string') {
$centroid = $geometry->getCentroid();
$lat = $centroid->getY();
$lon = $centroid->getX();
$url = "http://maps.googleapis.com/maps/api/geocode/json";
$url .= '?latlng='.$lat.','.$lon;
$url .= '&sensor=false';
$this->result = json_decode(@file_get_contents($url));
if ($this->result->status == 'OK') {
if ($return_type == 'string') {
return $this->result->results[0]->formatted_address;
}
if ($return_type == 'array') {
return $this->result->results[0]->address_components;
}
}
else {
if ($this->result->status) throw new Exception('Error in Google Reverse Geocoder: '.$this->result->status);
else throw new Exception('Unknown error in Google Reverse Geocoder');
return FALSE;
}
}
private function getPoint($delta = 0) {
$lat = $this->result->results[$delta]->geometry->location->lat;
$lon = $this->result->results[$delta]->geometry->location->lng;
return new Point($lon, $lat);
}
private function getPolygon($delta = 0) {
$points = array (
$this->getTopLeft($delta),
$this->getTopRight($delta),
$this->getBottomRight($delta),
$this->getBottomLeft($delta),
$this->getTopLeft($delta),
);
$outer_ring = new LineString($points);
return new Polygon(array($outer_ring));
}
private function getTopLeft($delta = 0) {
$lat = $this->result->results[$delta]->geometry->bounds->northeast->lat;
$lon = $this->result->results[$delta]->geometry->bounds->southwest->lng;
return new Point($lon, $lat);
}
private function getTopRight($delta = 0) {
$lat = $this->result->results[$delta]->geometry->bounds->northeast->lat;
$lon = $this->result->results[$delta]->geometry->bounds->northeast->lng;
return new Point($lon, $lat);
}
private function getBottomLeft($delta = 0) {
$lat = $this->result->results[$delta]->geometry->bounds->southwest->lat;
$lon = $this->result->results[$delta]->geometry->bounds->southwest->lng;
return new Point($lon, $lat);
}
private function getBottomRight($delta = 0) {
$lat = $this->result->results[$delta]->geometry->bounds->southwest->lat;
$lon = $this->result->results[$delta]->geometry->bounds->northeast->lng;
return new Point($lon, $lat);
}
}

View file

@ -0,0 +1,272 @@
<?php
/*
* Copyright (c) Patrick Hayes
* Copyright (c) 2010-2011, Arnaud Renevier
*
* This code is open-source and licenced under the Modified BSD License.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* PHP Geometry/KML encoder/decoder
*
* Mainly inspired/adapted from OpenLayers( http://www.openlayers.org )
* Openlayers/format/WKT.js
*
* @package sfMapFishPlugin
* @subpackage GeoJSON
* @author Camptocamp <info@camptocamp.com>
*/
class KML extends GeoAdapter
{
private $namespace = FALSE;
private $nss = ''; // Name-space string. eg 'georss:'
/**
* Read KML string into geometry objects
*
* @param string $kml A KML string
*
* @return Geometry|GeometryCollection
*/
public function read($kml) {
return $this->geomFromText($kml);
}
/**
* Serialize geometries into a KML string.
*
* @param Geometry $geometry
*
* @return string The KML string representation of the input geometries
*/
public function write(Geometry $geometry, $namespace = FALSE) {
if ($namespace) {
$this->namespace = $namespace;
$this->nss = $namespace.':';
}
return $this->geometryToKML($geometry);
}
public function geomFromText($text) {
// Change to lower-case and strip all CDATA
$text = mb_strtolower($text, mb_detect_encoding($text));
$text = preg_replace('/<!\[cdata\[(.*?)\]\]>/s','',$text);
// Load into DOMDocument
$xmlobj = new DOMDocument();
@$xmlobj->loadXML($text);
if ($xmlobj === false) {
throw new Exception("Invalid KML: ". $text);
}
$this->xmlobj = $xmlobj;
try {
$geom = $this->geomFromXML();
} catch(InvalidText $e) {
throw new Exception("Cannot Read Geometry From KML: ". $text);
} catch(Exception $e) {
throw $e;
}
return $geom;
}
protected function geomFromXML() {
$geometries = array();
$geom_types = geoPHP::geometryList();
$placemark_elements = $this->xmlobj->getElementsByTagName('placemark');
if ($placemark_elements->length) {
foreach ($placemark_elements as $placemark) {
foreach ($placemark->childNodes as $child) {
// Node names are all the same, except for MultiGeometry, which maps to GeometryCollection
$node_name = $child->nodeName == 'multigeometry' ? 'geometrycollection' : $child->nodeName;
if (array_key_exists($node_name, $geom_types)) {
$function = 'parse'.$geom_types[$node_name];
$geometries[] = $this->$function($child);
}
}
}
}
else {
// The document does not have a placemark, try to create a valid geometry from the root element
$node_name = $this->xmlobj->documentElement->nodeName == 'multigeometry' ? 'geometrycollection' : $this->xmlobj->documentElement->nodeName;
if (array_key_exists($node_name, $geom_types)) {
$function = 'parse'.$geom_types[$node_name];
$geometries[] = $this->$function($this->xmlobj->documentElement);
}
}
return geoPHP::geometryReduce($geometries);
}
protected function childElements($xml, $nodename = '') {
$children = array();
if ($xml->childNodes) {
foreach ($xml->childNodes as $child) {
if ($child->nodeName == $nodename) {
$children[] = $child;
}
}
}
return $children;
}
protected function parsePoint($xml) {
$coordinates = $this->_extractCoordinates($xml);
if (!empty($coordinates)) {
return new Point($coordinates[0][0],$coordinates[0][1]);
}
else {
return new Point();
}
}
protected function parseLineString($xml) {
$coordinates = $this->_extractCoordinates($xml);
$point_array = array();
foreach ($coordinates as $set) {
$point_array[] = new Point($set[0],$set[1]);
}
return new LineString($point_array);
}
protected function parsePolygon($xml) {
$components = array();
$outer_boundary_element_a = $this->childElements($xml, 'outerboundaryis');
if (empty($outer_boundary_element_a)) {
return new Polygon(); // It's an empty polygon
}
$outer_boundary_element = $outer_boundary_element_a[0];
$outer_ring_element_a = $this->childElements($outer_boundary_element, 'linearring');
$outer_ring_element = $outer_ring_element_a[0];
$components[] = $this->parseLineString($outer_ring_element);
if (count($components) != 1) {
throw new Exception("Invalid KML");
}
$inner_boundary_element_a = $this->childElements($xml, 'innerboundaryis');
if (count($inner_boundary_element_a)) {
foreach ($inner_boundary_element_a as $inner_boundary_element) {
foreach ($this->childElements($inner_boundary_element, 'linearring') as $inner_ring_element) {
$components[] = $this->parseLineString($inner_ring_element);
}
}
}
return new Polygon($components);
}
protected function parseGeometryCollection($xml) {
$components = array();
$geom_types = geoPHP::geometryList();
foreach ($xml->childNodes as $child) {
$nodeName = ($child->nodeName == 'linearring') ? 'linestring' : $child->nodeName;
if (array_key_exists($nodeName, $geom_types)) {
$function = 'parse'.$geom_types[$nodeName];
$components[] = $this->$function($child);
}
}
return new GeometryCollection($components);
}
protected function _extractCoordinates($xml) {
$coord_elements = $this->childElements($xml, 'coordinates');
$coordinates = array();
if (count($coord_elements)) {
$coord_sets = explode(' ', preg_replace('/[\r\n]+/', ' ', $coord_elements[0]->nodeValue));
foreach ($coord_sets as $set_string) {
$set_string = trim($set_string);
if ($set_string) {
$set_array = explode(',',$set_string);
if (count($set_array) >= 2) {
$coordinates[] = $set_array;
}
}
}
}
return $coordinates;
}
private function geometryToKML($geom) {
$type = strtolower($geom->getGeomType());
switch ($type) {
case 'point':
return $this->pointToKML($geom);
break;
case 'linestring':
return $this->linestringToKML($geom);
break;
case 'polygon':
return $this->polygonToKML($geom);
break;
case 'multipoint':
case 'multilinestring':
case 'multipolygon':
case 'geometrycollection':
return $this->collectionToKML($geom);
break;
}
}
private function pointToKML($geom) {
$out = '<'.$this->nss.'Point>';
if (!$geom->isEmpty()) {
$out .= '<'.$this->nss.'coordinates>'.$geom->getX().",".$geom->getY().'</'.$this->nss.'coordinates>';
}
$out .= '</'.$this->nss.'Point>';
return $out;
}
private function linestringToKML($geom, $type = FALSE) {
if (!$type) {
$type = $geom->getGeomType();
}
$str = '<'.$this->nss . $type .'>';
if (!$geom->isEmpty()) {
$str .= '<'.$this->nss.'coordinates>';
$i=0;
foreach ($geom->getComponents() as $comp) {
if ($i != 0) $str .= ' ';
$str .= $comp->getX() .','. $comp->getY();
$i++;
}
$str .= '</'.$this->nss.'coordinates>';
}
$str .= '</'. $this->nss . $type .'>';
return $str;
}
public function polygonToKML($geom) {
$components = $geom->getComponents();
$str = '';
if (!empty($components)) {
$str = '<'.$this->nss.'outerBoundaryIs>' . $this->linestringToKML($components[0], 'LinearRing') . '</'.$this->nss.'outerBoundaryIs>';
foreach (array_slice($components, 1) as $comp) {
$str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . '</'.$this->nss.'innerBoundaryIs>';
}
}
return '<'.$this->nss.'Polygon>'. $str .'</'.$this->nss.'Polygon>';
}
public function collectionToKML($geom) {
$components = $geom->getComponents();
$str = '<'.$this->nss.'MultiGeometry>';
foreach ($geom->getComponents() as $comp) {
$sub_adapter = new KML();
$str .= $sub_adapter->write($comp);
}
return $str .'</'.$this->nss.'MultiGeometry>';
}
}

View file

@ -0,0 +1,250 @@
<?php
/*
* (c) Patrick Hayes
*
* This code is open-source and licenced under the Modified BSD License.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* PHP Geometry/WKB encoder/decoder
*
*/
class WKB extends GeoAdapter
{
private $dimension = 2;
private $z = FALSE;
private $m = FALSE;
/**
* Read WKB into geometry objects
*
* @param string $wkb
* Well-known-binary string
* @param bool $is_hex_string
* If this is a hexedecimal string that is in need of packing
*
* @return Geometry
*/
public function read($wkb, $is_hex_string = FALSE) {
if ($is_hex_string) {
$wkb = pack('H*',$wkb);
}
if (empty($wkb)) {
throw new Exception('Cannot read empty WKB geometry. Found ' . gettype($wkb));
}
$mem = fopen('php://memory', 'r+');
fwrite($mem, $wkb);
fseek($mem, 0);
$geometry = $this->getGeometry($mem);
fclose($mem);
return $geometry;
}
function getGeometry(&$mem) {
$base_info = unpack("corder/ctype/cz/cm/cs", fread($mem, 5));
if ($base_info['order'] !== 1) {
throw new Exception('Only NDR (little endian) SKB format is supported at the moment');
}
if ($base_info['z']) {
$this->dimension++;
$this->z = TRUE;
}
if ($base_info['m']) {
$this->dimension++;
$this->m = TRUE;
}
// If there is SRID information, ignore it - use EWKB Adapter to get SRID support
if ($base_info['s']) {
fread($mem, 4);
}
switch ($base_info['type']) {
case 1:
return $this->getPoint($mem);
case 2:
return $this->getLinstring($mem);
case 3:
return $this->getPolygon($mem);
case 4:
return $this->getMulti($mem,'point');
case 5:
return $this->getMulti($mem,'line');
case 6:
return $this->getMulti($mem,'polygon');
case 7:
return $this->getMulti($mem,'geometry');
}
}
function getPoint(&$mem) {
$point_coords = unpack("d*", fread($mem,$this->dimension*8));
if (!empty($point_coords)) {
return new Point($point_coords[1],$point_coords[2]);
}
else {
return new Point(); // EMPTY point
}
}
function getLinstring(&$mem) {
// Get the number of points expected in this string out of the first 4 bytes
$line_length = unpack('L',fread($mem,4));
// Return an empty linestring if there is no line-length
if (!$line_length[1]) return new LineString();
// Read the nubmer of points x2 (each point is two coords) into decimal-floats
$line_coords = unpack('d*', fread($mem,$line_length[1]*$this->dimension*8));
// We have our coords, build up the linestring
$components = array();
$i = 1;
$num_coords = count($line_coords);
while ($i <= $num_coords) {
$components[] = new Point($line_coords[$i],$line_coords[$i+1]);
$i += 2;
}
return new LineString($components);
}
function getPolygon(&$mem) {
// Get the number of linestring expected in this poly out of the first 4 bytes
$poly_length = unpack('L',fread($mem,4));
$components = array();
$i = 1;
while ($i <= $poly_length[1]) {
$components[] = $this->getLinstring($mem);
$i++;
}
return new Polygon($components);
}
function getMulti(&$mem, $type) {
// Get the number of items expected in this multi out of the first 4 bytes
$multi_length = unpack('L',fread($mem,4));
$components = array();
$i = 1;
while ($i <= $multi_length[1]) {
$components[] = $this->getGeometry($mem);
$i++;
}
switch ($type) {
case 'point':
return new MultiPoint($components);
case 'line':
return new MultiLineString($components);
case 'polygon':
return new MultiPolygon($components);
case 'geometry':
return new GeometryCollection($components);
}
}
/**
* Serialize geometries into WKB string.
*
* @param Geometry $geometry
*
* @return string The WKB string representation of the input geometries
*/
public function write(Geometry $geometry, $write_as_hex = FALSE) {
// We always write into NDR (little endian)
$wkb = pack('c',1);
switch ($geometry->getGeomType()) {
case 'Point';
$wkb .= pack('L',1);
$wkb .= $this->writePoint($geometry);
break;
case 'LineString';
$wkb .= pack('L',2);
$wkb .= $this->writeLineString($geometry);
break;
case 'Polygon';
$wkb .= pack('L',3);
$wkb .= $this->writePolygon($geometry);
break;
case 'MultiPoint';
$wkb .= pack('L',4);
$wkb .= $this->writeMulti($geometry);
break;
case 'MultiLineString';
$wkb .= pack('L',5);
$wkb .= $this->writeMulti($geometry);
break;
case 'MultiPolygon';
$wkb .= pack('L',6);
$wkb .= $this->writeMulti($geometry);
break;
case 'GeometryCollection';
$wkb .= pack('L',7);
$wkb .= $this->writeMulti($geometry);
break;
}
if ($write_as_hex) {
$unpacked = unpack('H*',$wkb);
return $unpacked[1];
}
else {
return $wkb;
}
}
function writePoint($point) {
// Set the coords
if (!$point->isEmpty()) {
$wkb = pack('dd',$point->x(), $point->y());
return $wkb;
} else {
return '';
}
}
function writeLineString($line) {
// Set the number of points in this line
$wkb = pack('L',$line->numPoints());
// Set the coords
foreach ($line->getComponents() as $point) {
$wkb .= pack('dd',$point->x(), $point->y());
}
return $wkb;
}
function writePolygon($poly) {
// Set the number of lines in this poly
$wkb = pack('L',$poly->numGeometries());
// Write the lines
foreach ($poly->getComponents() as $line) {
$wkb .= $this->writeLineString($line);
}
return $wkb;
}
function writeMulti($geometry) {
// Set the number of components
$wkb = pack('L',$geometry->numGeometries());
// Write the components
foreach ($geometry->getComponents() as $component) {
$wkb .= $this->write($component);
}
return $wkb;
}
}

View file

@ -0,0 +1,258 @@
<?php
/**
* WKT (Well Known Text) Adapter
*/
class WKT extends GeoAdapter
{
/**
* Read WKT string into geometry objects
*
* @param string $WKT A WKT string
*
* @return Geometry
*/
public function read($wkt) {
$wkt = trim($wkt);
// If it contains a ';', then it contains additional SRID data
if (strpos($wkt,';')) {
$parts = explode(';', $wkt);
$wkt = $parts[1];
$eparts = explode('=',$parts[0]);
$srid = $eparts[1];
}
else {
$srid = NULL;
}
// If geos is installed, then we take a shortcut and let it parse the WKT
if (geoPHP::geosInstalled()) {
$reader = new GEOSWKTReader();
if ($srid) {
$geom = geoPHP::geosToGeometry($reader->read($wkt));
$geom->setSRID($srid);
return $geom;
}
else {
return geoPHP::geosToGeometry($reader->read($wkt));
}
}
$wkt = str_replace(', ', ',', $wkt);
// For each geometry type, check to see if we have a match at the
// beginning of the string. If we do, then parse using that type
foreach (geoPHP::geometryList() as $geom_type) {
$wkt_geom = strtoupper($geom_type);
if (strtoupper(substr($wkt, 0, strlen($wkt_geom))) == $wkt_geom) {
$data_string = $this->getDataString($wkt);
$method = 'parse'.$geom_type;
if ($srid) {
$geom = $this->$method($data_string);
$geom->setSRID($srid);
return $geom;
}
else {
return $this->$method($data_string);
}
}
}
}
private function parsePoint($data_string) {
$data_string = $this->trimParens($data_string);
// If it's marked as empty, then return an empty point
if ($data_string == 'EMPTY') return new Point();
$parts = explode(' ',$data_string);
return new Point($parts[0], $parts[1]);
}
private function parseLineString($data_string) {
$data_string = $this->trimParens($data_string);
// If it's marked as empty, then return an empty line
if ($data_string == 'EMPTY') return new LineString();
$parts = explode(',',$data_string);
$points = array();
foreach ($parts as $part) {
$points[] = $this->parsePoint($part);
}
return new LineString($points);
}
private function parsePolygon($data_string) {
$data_string = $this->trimParens($data_string);
// If it's marked as empty, then return an empty polygon
if ($data_string == 'EMPTY') return new Polygon();
$parts = explode('),(',$data_string);
$lines = array();
foreach ($parts as $part) {
if (!$this->beginsWith($part,'(')) $part = '(' . $part;
if (!$this->endsWith($part,')')) $part = $part . ')';
$lines[] = $this->parseLineString($part);
}
return new Polygon($lines);
}
private function parseMultiPoint($data_string) {
$data_string = $this->trimParens($data_string);
// If it's marked as empty, then return an empty MutiPoint
if ($data_string == 'EMPTY') return new MultiPoint();
$parts = explode(',',$data_string);
$points = array();
foreach ($parts as $part) {
$points[] = $this->parsePoint($part);
}
return new MultiPoint($points);
}
private function parseMultiLineString($data_string) {
$data_string = $this->trimParens($data_string);
// If it's marked as empty, then return an empty multi-linestring
if ($data_string == 'EMPTY') return new MultiLineString();
$parts = explode('),(',$data_string);
$lines = array();
foreach ($parts as $part) {
// Repair the string if the explode broke it
if (!$this->beginsWith($part,'(')) $part = '(' . $part;
if (!$this->endsWith($part,')')) $part = $part . ')';
$lines[] = $this->parseLineString($part);
}
return new MultiLineString($lines);
}
private function parseMultiPolygon($data_string) {
$data_string = $this->trimParens($data_string);
// If it's marked as empty, then return an empty multi-polygon
if ($data_string == 'EMPTY') return new MultiPolygon();
$parts = explode(')),((',$data_string);
$polys = array();
foreach ($parts as $part) {
// Repair the string if the explode broke it
if (!$this->beginsWith($part,'((')) $part = '((' . $part;
if (!$this->endsWith($part,'))')) $part = $part . '))';
$polys[] = $this->parsePolygon($part);
}
return new MultiPolygon($polys);
}
private function parseGeometryCollection($data_string) {
$data_string = $this->trimParens($data_string);
// If it's marked as empty, then return an empty geom-collection
if ($data_string == 'EMPTY') return new GeometryCollection();
$geometries = array();
$matches = array();
$str = preg_replace('/,\s*([A-Za-z])/', '|$1', $data_string);
$components = explode('|', trim($str));
foreach ($components as $component) {
$geometries[] = $this->read($component);
}
return new GeometryCollection($geometries);
}
protected function getDataString($wkt) {
$first_paren = strpos($wkt, '(');
if ($first_paren !== FALSE) {
return substr($wkt, $first_paren);
} elseif (strstr($wkt,'EMPTY')) {
return 'EMPTY';
} else
return FALSE;
}
/**
* Trim the parenthesis and spaces
*/
protected function trimParens($str) {
$str = trim($str);
// We want to only strip off one set of parenthesis
if ($this->beginsWith($str, '(')) {
return substr($str,1,-1);
}
else return $str;
}
protected function beginsWith($str, $char) {
if (substr($str,0,strlen($char)) == $char) return TRUE;
else return FALSE;
}
protected function endsWith($str, $char) {
if (substr($str,(0 - strlen($char))) == $char) return TRUE;
else return FALSE;
}
/**
* Serialize geometries into a WKT string.
*
* @param Geometry $geometry
*
* @return string The WKT string representation of the input geometries
*/
public function write(Geometry $geometry) {
// If geos is installed, then we take a shortcut and let it write the WKT
if (geoPHP::geosInstalled()) {
$writer = new GEOSWKTWriter();
$writer->setTrim(TRUE);
return $writer->write($geometry->geos());
}
if ($geometry->isEmpty()) {
return strtoupper($geometry->geometryType()).' EMPTY';
}
else if ($data = $this->extractData($geometry)) {
return strtoupper($geometry->geometryType()).' ('.$data.')';
}
}
/**
* Extract geometry to a WKT string
*
* @param Geometry $geometry A Geometry object
*
* @return string
*/
public function extractData($geometry) {
$parts = array();
switch ($geometry->geometryType()) {
case 'Point':
return $geometry->getX().' '.$geometry->getY();
case 'LineString':
foreach ($geometry->getComponents() as $component) {
$parts[] = $this->extractData($component);
}
return implode(', ', $parts);
case 'Polygon':
case 'MultiPoint':
case 'MultiLineString':
case 'MultiPolygon':
foreach ($geometry->getComponents() as $component) {
$parts[] = '('.$this->extractData($component).')';
}
return implode(', ', $parts);
case 'GeometryCollection':
foreach ($geometry->getComponents() as $component) {
$parts[] = strtoupper($component->geometryType()).' ('.$this->extractData($component).')';
}
return implode(', ', $parts);
}
}
}