forked from lino/radar-wp
Initial import.
This commit is contained in:
commit
86383280c9
428 changed files with 68738 additions and 0 deletions
96
vendor/phayes/geophp/lib/adapters/EWKB.class.php
vendored
Normal file
96
vendor/phayes/geophp/lib/adapters/EWKB.class.php
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
27
vendor/phayes/geophp/lib/adapters/EWKT.class.php
vendored
Normal file
27
vendor/phayes/geophp/lib/adapters/EWKT.class.php
vendored
Normal 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');
|
||||
}
|
||||
}
|
||||
}
|
180
vendor/phayes/geophp/lib/adapters/GPX.class.php
vendored
Normal file
180
vendor/phayes/geophp/lib/adapters/GPX.class.php
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
31
vendor/phayes/geophp/lib/adapters/GeoAdapter.class.php
vendored
Normal file
31
vendor/phayes/geophp/lib/adapters/GeoAdapter.class.php
vendored
Normal 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);
|
||||
|
||||
}
|
249
vendor/phayes/geophp/lib/adapters/GeoHash.class.php
vendored
Normal file
249
vendor/phayes/geophp/lib/adapters/GeoHash.class.php
vendored
Normal 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)];
|
||||
}
|
||||
}
|
155
vendor/phayes/geophp/lib/adapters/GeoJSON.class.php
vendored
Normal file
155
vendor/phayes/geophp/lib/adapters/GeoJSON.class.php
vendored
Normal 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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
244
vendor/phayes/geophp/lib/adapters/GeoRSS.class.php
vendored
Normal file
244
vendor/phayes/geophp/lib/adapters/GeoRSS.class.php
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
158
vendor/phayes/geophp/lib/adapters/GoogleGeocode.class.php
vendored
Normal file
158
vendor/phayes/geophp/lib/adapters/GoogleGeocode.class.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
272
vendor/phayes/geophp/lib/adapters/KML.class.php
vendored
Normal file
272
vendor/phayes/geophp/lib/adapters/KML.class.php
vendored
Normal 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>';
|
||||
}
|
||||
|
||||
}
|
250
vendor/phayes/geophp/lib/adapters/WKB.class.php
vendored
Normal file
250
vendor/phayes/geophp/lib/adapters/WKB.class.php
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
258
vendor/phayes/geophp/lib/adapters/WKT.class.php
vendored
Normal file
258
vendor/phayes/geophp/lib/adapters/WKT.class.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
294
vendor/phayes/geophp/lib/geometry/Collection.class.php
vendored
Normal file
294
vendor/phayes/geophp/lib/geometry/Collection.class.php
vendored
Normal file
|
@ -0,0 +1,294 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Collection: Abstract class for compound geometries
|
||||
*
|
||||
* A geometry is a collection if it is made up of other
|
||||
* component geometries. Therefore everything but a Point
|
||||
* is a Collection. For example a LingString is a collection
|
||||
* of Points. A Polygon is a collection of LineStrings etc.
|
||||
*/
|
||||
abstract class Collection extends Geometry
|
||||
{
|
||||
public $components = array();
|
||||
|
||||
/**
|
||||
* Constructor: Checks and sets component geometries
|
||||
*
|
||||
* @param array $components array of geometries
|
||||
*/
|
||||
public function __construct($components = array()) {
|
||||
if (!is_array($components)) {
|
||||
throw new Exception("Component geometries must be passed as an array");
|
||||
}
|
||||
foreach ($components as $component) {
|
||||
if ($component instanceof Geometry) {
|
||||
$this->components[] = $component;
|
||||
}
|
||||
else {
|
||||
throw new Exception("Cannot create a collection with non-geometries");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Collection component geometries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getComponents() {
|
||||
return $this->components;
|
||||
}
|
||||
|
||||
public function centroid() {
|
||||
if ($this->isEmpty()) return NULL;
|
||||
|
||||
if ($this->geos()) {
|
||||
$geos_centroid = $this->geos()->centroid();
|
||||
if ($geos_centroid->typeName() == 'Point') {
|
||||
return geoPHP::geosToGeometry($this->geos()->centroid());
|
||||
}
|
||||
}
|
||||
|
||||
// As a rough estimate, we say that the centroid of a colletion is the centroid of it's envelope
|
||||
// @@TODO: Make this the centroid of the convexHull
|
||||
// Note: Outside of polygons, geometryCollections and the trivial case of points, there is no standard on what a "centroid" is
|
||||
$centroid = $this->envelope()->centroid();
|
||||
|
||||
return $centroid;
|
||||
}
|
||||
|
||||
public function getBBox() {
|
||||
if ($this->isEmpty()) return NULL;
|
||||
|
||||
if ($this->geos()) {
|
||||
$envelope = $this->geos()->envelope();
|
||||
if ($envelope->typeName() == 'Point') {
|
||||
return geoPHP::geosToGeometry($envelope)->getBBOX();
|
||||
}
|
||||
|
||||
$geos_ring = $envelope->exteriorRing();
|
||||
return array(
|
||||
'maxy' => $geos_ring->pointN(3)->getY(),
|
||||
'miny' => $geos_ring->pointN(1)->getY(),
|
||||
'maxx' => $geos_ring->pointN(1)->getX(),
|
||||
'minx' => $geos_ring->pointN(3)->getX(),
|
||||
);
|
||||
}
|
||||
|
||||
// Go through each component and get the max and min x and y
|
||||
$i = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$component_bbox = $component->getBBox();
|
||||
|
||||
// On the first run through, set the bbox to the component bbox
|
||||
if ($i == 0) {
|
||||
$maxx = $component_bbox['maxx'];
|
||||
$maxy = $component_bbox['maxy'];
|
||||
$minx = $component_bbox['minx'];
|
||||
$miny = $component_bbox['miny'];
|
||||
}
|
||||
|
||||
// Do a check and replace on each boundary, slowly growing the bbox
|
||||
$maxx = $component_bbox['maxx'] > $maxx ? $component_bbox['maxx'] : $maxx;
|
||||
$maxy = $component_bbox['maxy'] > $maxy ? $component_bbox['maxy'] : $maxy;
|
||||
$minx = $component_bbox['minx'] < $minx ? $component_bbox['minx'] : $minx;
|
||||
$miny = $component_bbox['miny'] < $miny ? $component_bbox['miny'] : $miny;
|
||||
$i++;
|
||||
}
|
||||
|
||||
return array(
|
||||
'maxy' => $maxy,
|
||||
'miny' => $miny,
|
||||
'maxx' => $maxx,
|
||||
'minx' => $minx,
|
||||
);
|
||||
}
|
||||
|
||||
public function asArray() {
|
||||
$array = array();
|
||||
foreach ($this->components as $component) {
|
||||
$array[] = $component->asArray();
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function area() {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->area();
|
||||
}
|
||||
|
||||
$area = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$area += $component->area();
|
||||
}
|
||||
return $area;
|
||||
}
|
||||
|
||||
// By default, the boundary of a collection is the boundary of it's components
|
||||
public function boundary() {
|
||||
if ($this->isEmpty()) return new LineString();
|
||||
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->boundary();
|
||||
}
|
||||
|
||||
$components_boundaries = array();
|
||||
foreach ($this->components as $component) {
|
||||
$components_boundaries[] = $component->boundary();
|
||||
}
|
||||
return geoPHP::geometryReduce($components_boundaries);
|
||||
}
|
||||
|
||||
public function numGeometries() {
|
||||
return count($this->components);
|
||||
}
|
||||
|
||||
// Note that the standard is 1 based indexing
|
||||
public function geometryN($n) {
|
||||
$n = intval($n);
|
||||
if (array_key_exists($n-1, $this->components)) {
|
||||
return $this->components[$n-1];
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public function length() {
|
||||
$length = 0;
|
||||
foreach ($this->components as $delta => $component) {
|
||||
$length += $component->length();
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function greatCircleLength($radius = 6378137) {
|
||||
$length = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$length += $component->greatCircleLength($radius);
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function haversineLength() {
|
||||
$length = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$length += $component->haversineLength();
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function dimension() {
|
||||
$dimension = 0;
|
||||
foreach ($this->components as $component) {
|
||||
if ($component->dimension() > $dimension) {
|
||||
$dimension = $component->dimension();
|
||||
}
|
||||
}
|
||||
return $dimension;
|
||||
}
|
||||
|
||||
// A collection is empty if it has no components OR all it's components are empty
|
||||
public function isEmpty() {
|
||||
if (!count($this->components)) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
foreach ($this->components as $component) {
|
||||
if (!$component->isEmpty()) return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
public function numPoints() {
|
||||
$num = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$num += $component->numPoints();
|
||||
}
|
||||
return $num;
|
||||
}
|
||||
|
||||
public function getPoints() {
|
||||
$points = array();
|
||||
foreach ($this->components as $component) {
|
||||
$points = array_merge($points, $component->getPoints());
|
||||
}
|
||||
return $points;
|
||||
}
|
||||
|
||||
public function equals($geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->equals($geometry->geos());
|
||||
}
|
||||
|
||||
// To test for equality we check to make sure that there is a matching point
|
||||
// in the other geometry for every point in this geometry.
|
||||
// This is slightly more strict than the standard, which
|
||||
// uses Within(A,B) = true and Within(B,A) = true
|
||||
// @@TODO: Eventually we could fix this by using some sort of simplification
|
||||
// method that strips redundant vertices (that are all in a row)
|
||||
|
||||
$this_points = $this->getPoints();
|
||||
$other_points = $geometry->getPoints();
|
||||
|
||||
// First do a check to make sure they have the same number of vertices
|
||||
if (count($this_points) != count($other_points)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
foreach ($this_points as $point) {
|
||||
$found_match = FALSE;
|
||||
foreach ($other_points as $key => $test_point) {
|
||||
if ($point->equals($test_point)) {
|
||||
$found_match = TRUE;
|
||||
unset($other_points[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found_match) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// All points match, return TRUE
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function isSimple() {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->isSimple();
|
||||
}
|
||||
|
||||
// A collection is simple if all it's components are simple
|
||||
foreach ($this->components as $component) {
|
||||
if (!$component->isSimple()) return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function explode() {
|
||||
$parts = array();
|
||||
foreach ($this->components as $component) {
|
||||
$parts = array_merge($parts, $component->explode());
|
||||
}
|
||||
return $parts;
|
||||
}
|
||||
|
||||
// Not valid for this geometry type
|
||||
// --------------------------------
|
||||
public function x() { return NULL; }
|
||||
public function y() { return NULL; }
|
||||
public function startPoint() { return NULL; }
|
||||
public function endPoint() { return NULL; }
|
||||
public function isRing() { return NULL; }
|
||||
public function isClosed() { return NULL; }
|
||||
public function pointN($n) { return NULL; }
|
||||
public function exteriorRing() { return NULL; }
|
||||
public function numInteriorRings() { return NULL; }
|
||||
public function interiorRingN($n) { return NULL; }
|
||||
public function pointOnSurface() { return NULL; }
|
||||
}
|
||||
|
347
vendor/phayes/geophp/lib/geometry/Geometry.class.php
vendored
Normal file
347
vendor/phayes/geophp/lib/geometry/Geometry.class.php
vendored
Normal file
|
@ -0,0 +1,347 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Geometry abstract class
|
||||
*/
|
||||
abstract class Geometry
|
||||
{
|
||||
private $geos = NULL;
|
||||
protected $srid = NULL;
|
||||
protected $geom_type;
|
||||
|
||||
// Abtract: Standard
|
||||
// -----------------
|
||||
abstract public function area();
|
||||
abstract public function boundary();
|
||||
abstract public function centroid();
|
||||
abstract public function length();
|
||||
abstract public function y();
|
||||
abstract public function x();
|
||||
abstract public function numGeometries();
|
||||
abstract public function geometryN($n);
|
||||
abstract public function startPoint();
|
||||
abstract public function endPoint();
|
||||
abstract public function isRing(); // Mssing dependancy
|
||||
abstract public function isClosed(); // Missing dependancy
|
||||
abstract public function numPoints();
|
||||
abstract public function pointN($n);
|
||||
abstract public function exteriorRing();
|
||||
abstract public function numInteriorRings();
|
||||
abstract public function interiorRingN($n);
|
||||
abstract public function dimension();
|
||||
abstract public function equals($geom);
|
||||
abstract public function isEmpty();
|
||||
abstract public function isSimple();
|
||||
|
||||
// Abtract: Non-Standard
|
||||
// ---------------------
|
||||
abstract public function getBBox();
|
||||
abstract public function asArray();
|
||||
abstract public function getPoints();
|
||||
abstract public function explode();
|
||||
abstract public function greatCircleLength(); //meters
|
||||
abstract public function haversineLength(); //degrees
|
||||
|
||||
|
||||
// Public: Standard -- Common to all geometries
|
||||
// --------------------------------------------
|
||||
public function SRID() {
|
||||
return $this->srid;
|
||||
}
|
||||
|
||||
public function setSRID($srid) {
|
||||
if ($this->geos()) {
|
||||
$this->geos()->setSRID($srid);
|
||||
}
|
||||
$this->srid = $srid;
|
||||
}
|
||||
|
||||
public function envelope() {
|
||||
if ($this->isEmpty()) return new Polygon();
|
||||
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->envelope());
|
||||
}
|
||||
|
||||
$bbox = $this->getBBox();
|
||||
$points = array (
|
||||
new Point($bbox['maxx'],$bbox['miny']),
|
||||
new Point($bbox['maxx'],$bbox['maxy']),
|
||||
new Point($bbox['minx'],$bbox['maxy']),
|
||||
new Point($bbox['minx'],$bbox['miny']),
|
||||
new Point($bbox['maxx'],$bbox['miny']),
|
||||
);
|
||||
|
||||
$outer_boundary = new LineString($points);
|
||||
return new Polygon(array($outer_boundary));
|
||||
}
|
||||
|
||||
public function geometryType() {
|
||||
return $this->geom_type;
|
||||
}
|
||||
|
||||
// Public: Non-Standard -- Common to all geometries
|
||||
// ------------------------------------------------
|
||||
|
||||
// $this->out($format, $other_args);
|
||||
public function out() {
|
||||
$args = func_get_args();
|
||||
|
||||
$format = array_shift($args);
|
||||
$type_map = geoPHP::getAdapterMap();
|
||||
$processor_type = $type_map[$format];
|
||||
$processor = new $processor_type();
|
||||
|
||||
array_unshift($args, $this);
|
||||
$result = call_user_func_array(array($processor, 'write'), $args);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
// Public: Aliases
|
||||
// ---------------
|
||||
public function getCentroid() {
|
||||
return $this->centroid();
|
||||
}
|
||||
|
||||
public function getArea() {
|
||||
return $this->area();
|
||||
}
|
||||
|
||||
public function getX() {
|
||||
return $this->x();
|
||||
}
|
||||
|
||||
public function getY() {
|
||||
return $this->y();
|
||||
}
|
||||
|
||||
public function getGeos() {
|
||||
return $this->geos();
|
||||
}
|
||||
|
||||
public function getGeomType() {
|
||||
return $this->geometryType();
|
||||
}
|
||||
|
||||
public function getSRID() {
|
||||
return $this->SRID();
|
||||
}
|
||||
|
||||
public function asText() {
|
||||
return $this->out('wkt');
|
||||
}
|
||||
|
||||
public function asBinary() {
|
||||
return $this->out('wkb');
|
||||
}
|
||||
|
||||
// Public: GEOS Only Functions
|
||||
// ---------------------------
|
||||
public function geos() {
|
||||
// If it's already been set, just return it
|
||||
if ($this->geos && geoPHP::geosInstalled()) {
|
||||
return $this->geos;
|
||||
}
|
||||
// It hasn't been set yet, generate it
|
||||
if (geoPHP::geosInstalled()) {
|
||||
$reader = new GEOSWKBReader();
|
||||
$this->geos = $reader->readHEX($this->out('wkb',TRUE));
|
||||
}
|
||||
else {
|
||||
$this->geos = FALSE;
|
||||
}
|
||||
return $this->geos;
|
||||
}
|
||||
|
||||
public function setGeos($geos) {
|
||||
$this->geos = $geos;
|
||||
}
|
||||
|
||||
public function pointOnSurface() {
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->pointOnSurface());
|
||||
}
|
||||
}
|
||||
|
||||
public function equalsExact(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->equalsExact($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function relate(Geometry $geometry, $pattern = NULL) {
|
||||
if ($this->geos()) {
|
||||
if ($pattern) {
|
||||
return $this->geos()->relate($geometry->geos(), $pattern);
|
||||
}
|
||||
else {
|
||||
return $this->geos()->relate($geometry->geos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function checkValidity() {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->checkValidity();
|
||||
}
|
||||
}
|
||||
|
||||
public function buffer($distance) {
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->buffer($distance));
|
||||
}
|
||||
}
|
||||
|
||||
public function intersection(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->intersection($geometry->geos()));
|
||||
}
|
||||
}
|
||||
|
||||
public function convexHull() {
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->convexHull());
|
||||
}
|
||||
}
|
||||
|
||||
public function difference(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->difference($geometry->geos()));
|
||||
}
|
||||
}
|
||||
|
||||
public function symDifference(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->symDifference($geometry->geos()));
|
||||
}
|
||||
}
|
||||
|
||||
// Can pass in a geometry or an array of geometries
|
||||
public function union(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
if (is_array($geometry)) {
|
||||
$geom = $this->geos();
|
||||
foreach ($geometry as $item) {
|
||||
$geom = $geom->union($item->geos());
|
||||
}
|
||||
return geoPHP::geosToGeometry($geom);
|
||||
}
|
||||
else {
|
||||
return geoPHP::geosToGeometry($this->geos()->union($geometry->geos()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function simplify($tolerance, $preserveTopology = FALSE) {
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->simplify($tolerance, $preserveTopology));
|
||||
}
|
||||
}
|
||||
|
||||
public function disjoint(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->disjoint($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function touches(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->touches($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function intersects(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->intersects($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function crosses(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->crosses($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function within(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->within($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function contains(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->contains($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function overlaps(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->overlaps($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function covers(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->covers($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function coveredBy(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->coveredBy($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function distance(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->distance($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function hausdorffDistance(Geometry $geometry) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->hausdorffDistance($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function project(Geometry $point, $normalized = NULL) {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->project($point->geos(), $normalized);
|
||||
}
|
||||
}
|
||||
|
||||
// Public - Placeholders
|
||||
// ---------------------
|
||||
public function hasZ() {
|
||||
// geoPHP does not support Z values at the moment
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function is3D() {
|
||||
// geoPHP does not support 3D geometries at the moment
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function isMeasured() {
|
||||
// geoPHP does not yet support M values
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function coordinateDimension() {
|
||||
// geoPHP only supports 2-dimensional space
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function z() {
|
||||
// geoPHP only supports 2-dimensional space
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public function m() {
|
||||
// geoPHP only supports 2-dimensional space
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
29
vendor/phayes/geophp/lib/geometry/GeometryCollection.class.php
vendored
Normal file
29
vendor/phayes/geophp/lib/geometry/GeometryCollection.class.php
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* GeometryCollection: A heterogenous collection of geometries
|
||||
*/
|
||||
class GeometryCollection extends Collection
|
||||
{
|
||||
protected $geom_type = 'GeometryCollection';
|
||||
|
||||
// We need to override asArray. Because geometryCollections are heterogeneous
|
||||
// we need to specify which type of geometries they contain. We need to do this
|
||||
// because, for example, there would be no way to tell the difference between a
|
||||
// MultiPoint or a LineString, since they share the same structure (collection
|
||||
// of points). So we need to call out the type explicitly.
|
||||
public function asArray() {
|
||||
$array = array();
|
||||
foreach ($this->components as $component) {
|
||||
$array[] = array(
|
||||
'type' => $component->geometryType(),
|
||||
'components' => $component->asArray(),
|
||||
);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
// Not valid for this geomettry
|
||||
public function boundary() { return NULL; }
|
||||
public function isSimple() { return NULL; }
|
||||
}
|
||||
|
190
vendor/phayes/geophp/lib/geometry/LineString.class.php
vendored
Normal file
190
vendor/phayes/geophp/lib/geometry/LineString.class.php
vendored
Normal file
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
/**
|
||||
* LineString. A collection of Points representing a line.
|
||||
* A line can have more than one segment.
|
||||
*/
|
||||
class LineString extends Collection
|
||||
{
|
||||
protected $geom_type = 'LineString';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $points An array of at least two points with
|
||||
* which to build the LineString
|
||||
*/
|
||||
public function __construct($points = array()) {
|
||||
if (count($points) == 1) {
|
||||
throw new Exception("Cannot construct a LineString with a single point");
|
||||
}
|
||||
|
||||
// Call the Collection constructor to build the LineString
|
||||
parent::__construct($points);
|
||||
}
|
||||
|
||||
// The boundary of a linestring is itself
|
||||
public function boundary() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function startPoint() {
|
||||
return $this->pointN(1);
|
||||
}
|
||||
|
||||
public function endPoint() {
|
||||
$last_n = $this->numPoints();
|
||||
return $this->pointN($last_n);
|
||||
}
|
||||
|
||||
public function isClosed() {
|
||||
return ($this->startPoint()->equals($this->endPoint()));
|
||||
}
|
||||
|
||||
public function isRing() {
|
||||
return ($this->isClosed() && $this->isSimple());
|
||||
}
|
||||
|
||||
public function numPoints() {
|
||||
return $this->numGeometries();
|
||||
}
|
||||
|
||||
public function pointN($n) {
|
||||
return $this->geometryN($n);
|
||||
}
|
||||
|
||||
public function dimension() {
|
||||
if ($this->isEmpty()) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function area() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function length() {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->length();
|
||||
}
|
||||
$length = 0;
|
||||
foreach ($this->getPoints() as $delta => $point) {
|
||||
$previous_point = $this->geometryN($delta);
|
||||
if ($previous_point) {
|
||||
$length += sqrt(pow(($previous_point->getX() - $point->getX()), 2) + pow(($previous_point->getY()- $point->getY()), 2));
|
||||
}
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function greatCircleLength($radius = 6378137) {
|
||||
$length = 0;
|
||||
$points = $this->getPoints();
|
||||
for($i=0; $i<$this->numPoints()-1; $i++) {
|
||||
$point = $points[$i];
|
||||
$next_point = $points[$i+1];
|
||||
if (!is_object($next_point)) {continue;}
|
||||
// Great circle method
|
||||
$lat1 = deg2rad($point->getY());
|
||||
$lat2 = deg2rad($next_point->getY());
|
||||
$lon1 = deg2rad($point->getX());
|
||||
$lon2 = deg2rad($next_point->getX());
|
||||
$dlon = $lon2 - $lon1;
|
||||
$length +=
|
||||
$radius *
|
||||
atan2(
|
||||
sqrt(
|
||||
pow(cos($lat2) * sin($dlon), 2) +
|
||||
pow(cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dlon), 2)
|
||||
)
|
||||
,
|
||||
sin($lat1) * sin($lat2) +
|
||||
cos($lat1) * cos($lat2) * cos($dlon)
|
||||
);
|
||||
}
|
||||
// Returns length in meters.
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function haversineLength() {
|
||||
$degrees = 0;
|
||||
$points = $this->getPoints();
|
||||
for($i=0; $i<$this->numPoints()-1; $i++) {
|
||||
$point = $points[$i];
|
||||
$next_point = $points[$i+1];
|
||||
if (!is_object($next_point)) {continue;}
|
||||
$degree = rad2deg(
|
||||
acos(
|
||||
sin(deg2rad($point->getY())) * sin(deg2rad($next_point->getY())) +
|
||||
cos(deg2rad($point->getY())) * cos(deg2rad($next_point->getY())) *
|
||||
cos(deg2rad(abs($point->getX() - $next_point->getX())))
|
||||
)
|
||||
);
|
||||
$degrees += $degree;
|
||||
}
|
||||
// Returns degrees
|
||||
return $degrees;
|
||||
}
|
||||
|
||||
public function explode() {
|
||||
$parts = array();
|
||||
$points = $this->getPoints();
|
||||
|
||||
foreach ($points as $i => $point) {
|
||||
if (isset($points[$i+1])) {
|
||||
$parts[] = new LineString(array($point, $points[$i+1]));
|
||||
}
|
||||
}
|
||||
return $parts;
|
||||
}
|
||||
|
||||
public function isSimple() {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->isSimple();
|
||||
}
|
||||
|
||||
$segments = $this->explode();
|
||||
|
||||
foreach ($segments as $i => $segment) {
|
||||
foreach ($segments as $j => $check_segment) {
|
||||
if ($i != $j) {
|
||||
if ($segment->lineSegmentIntersect($check_segment)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Utility function to check if any line sigments intersect
|
||||
// Derived from http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
|
||||
public function lineSegmentIntersect($segment) {
|
||||
$p0_x = $this->startPoint()->x();
|
||||
$p0_y = $this->startPoint()->y();
|
||||
$p1_x = $this->endPoint()->x();
|
||||
$p1_y = $this->endPoint()->y();
|
||||
$p2_x = $segment->startPoint()->x();
|
||||
$p2_y = $segment->startPoint()->y();
|
||||
$p3_x = $segment->endPoint()->x();
|
||||
$p3_y = $segment->endPoint()->y();
|
||||
|
||||
$s1_x = $p1_x - $p0_x; $s1_y = $p1_y - $p0_y;
|
||||
$s2_x = $p3_x - $p2_x; $s2_y = $p3_y - $p2_y;
|
||||
|
||||
$fps = (-$s2_x * $s1_y) + ($s1_x * $s2_y);
|
||||
$fpt = (-$s2_x * $s1_y) + ($s1_x * $s2_y);
|
||||
|
||||
if ($fps == 0 || $fpt == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$s = (-$s1_y * ($p0_x - $p2_x) + $s1_x * ($p0_y - $p2_y)) / $fps;
|
||||
$t = ( $s2_x * ($p0_y - $p2_y) - $s2_y * ($p0_x - $p2_x)) / $fpt;
|
||||
|
||||
if ($s > 0 && $s < 1 && $t > 0 && $t < 1) {
|
||||
// Collision detected
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
20
vendor/phayes/geophp/lib/geometry/MultiLineString.class.php
vendored
Normal file
20
vendor/phayes/geophp/lib/geometry/MultiLineString.class.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* MultiLineString: A collection of LineStrings
|
||||
*/
|
||||
class MultiLineString extends Collection
|
||||
{
|
||||
protected $geom_type = 'MultiLineString';
|
||||
|
||||
// MultiLineString is closed if all it's components are closed
|
||||
public function isClosed() {
|
||||
foreach ($this->components as $line) {
|
||||
if (!$line->isClosed()) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
21
vendor/phayes/geophp/lib/geometry/MultiPoint.class.php
vendored
Normal file
21
vendor/phayes/geophp/lib/geometry/MultiPoint.class.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/**
|
||||
* MultiPoint: A collection Points
|
||||
*/
|
||||
class MultiPoint extends Collection
|
||||
{
|
||||
protected $geom_type = 'MultiPoint';
|
||||
|
||||
public function numPoints() {
|
||||
return $this->numGeometries();
|
||||
}
|
||||
|
||||
public function isSimple() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Not valid for this geometry type
|
||||
// --------------------------------
|
||||
public function explode() { return NULL; }
|
||||
}
|
||||
|
8
vendor/phayes/geophp/lib/geometry/MultiPolygon.class.php
vendored
Normal file
8
vendor/phayes/geophp/lib/geometry/MultiPolygon.class.php
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
/**
|
||||
* MultiPolygon: A collection of Polygons
|
||||
*/
|
||||
class MultiPolygon extends Collection
|
||||
{
|
||||
protected $geom_type = 'MultiPolygon';
|
||||
}
|
179
vendor/phayes/geophp/lib/geometry/Point.class.php
vendored
Normal file
179
vendor/phayes/geophp/lib/geometry/Point.class.php
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Point: The most basic geometry type. All other geometries
|
||||
* are built out of Points.
|
||||
*/
|
||||
class Point extends Geometry
|
||||
{
|
||||
public $coords = array(2);
|
||||
protected $geom_type = 'Point';
|
||||
protected $dimension = 2;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param numeric $x The x coordinate (or longitude)
|
||||
* @param numeric $y The y coordinate (or latitude)
|
||||
* @param numeric $z The z coordinate (or altitude) - optional
|
||||
*/
|
||||
public function __construct($x = NULL, $y = NULL, $z = NULL) {
|
||||
|
||||
// Check if it's an empty point
|
||||
if ($x === NULL && $y === NULL) {
|
||||
$this->coords = array(NULL, NULL);
|
||||
$this->dimension = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic validation on x and y
|
||||
if (!is_numeric($x) || !is_numeric($y)) {
|
||||
throw new Exception("Cannot construct Point. x and y should be numeric");
|
||||
}
|
||||
|
||||
// Check to see if this is a 3D point
|
||||
if ($z !== NULL) {
|
||||
if (!is_numeric($z)) {
|
||||
throw new Exception("Cannot construct Point. z should be numeric");
|
||||
}
|
||||
$this->dimension = 3;
|
||||
}
|
||||
|
||||
// Convert to floatval in case they are passed in as a string or integer etc.
|
||||
$x = floatval($x);
|
||||
$y = floatval($y);
|
||||
$z = floatval($z);
|
||||
|
||||
// Add poitional elements
|
||||
if ($this->dimension == 2) {
|
||||
$this->coords = array($x, $y);
|
||||
}
|
||||
if ($this->dimension == 3) {
|
||||
$this->coords = array($x, $y, $z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get X (longitude) coordinate
|
||||
*
|
||||
* @return float The X coordinate
|
||||
*/
|
||||
public function x() {
|
||||
return $this->coords[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Y (latitude) coordinate
|
||||
*
|
||||
* @return float The Y coordinate
|
||||
*/
|
||||
public function y() {
|
||||
return $this->coords[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Z (altitude) coordinate
|
||||
*
|
||||
* @return float The Z coordinate or NULL is not a 3D point
|
||||
*/
|
||||
public function z() {
|
||||
if ($this->dimension == 3) {
|
||||
return $this->coords[2];
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
// A point's centroid is itself
|
||||
public function centroid() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBBox() {
|
||||
return array(
|
||||
'maxy' => $this->getY(),
|
||||
'miny' => $this->getY(),
|
||||
'maxx' => $this->getX(),
|
||||
'minx' => $this->getX(),
|
||||
);
|
||||
}
|
||||
|
||||
public function asArray($assoc = FALSE) {
|
||||
return $this->coords;
|
||||
}
|
||||
|
||||
public function area() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function length() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function greatCircleLength() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function haversineLength() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The boundary of a point is itself
|
||||
public function boundary() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function dimension() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function isEmpty() {
|
||||
if ($this->dimension == 0) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
public function numPoints() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getPoints() {
|
||||
return array($this);
|
||||
}
|
||||
|
||||
public function equals($geometry) {
|
||||
if (get_class($geometry) != 'Point') {
|
||||
return FALSE;
|
||||
}
|
||||
if (!$this->isEmpty() && !$geometry->isEmpty()) {
|
||||
return ($this->x() == $geometry->x() && $this->y() == $geometry->y());
|
||||
}
|
||||
else if ($this->isEmpty() && $geometry->isEmpty()) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
public function isSimple() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Not valid for this geometry type
|
||||
public function numGeometries() { return NULL; }
|
||||
public function geometryN($n) { return NULL; }
|
||||
public function startPoint() { return NULL; }
|
||||
public function endPoint() { return NULL; }
|
||||
public function isRing() { return NULL; }
|
||||
public function isClosed() { return NULL; }
|
||||
public function pointN($n) { return NULL; }
|
||||
public function exteriorRing() { return NULL; }
|
||||
public function numInteriorRings() { return NULL; }
|
||||
public function interiorRingN($n) { return NULL; }
|
||||
public function pointOnSurface() { return NULL; }
|
||||
public function explode() { return NULL; }
|
||||
}
|
||||
|
215
vendor/phayes/geophp/lib/geometry/Polygon.class.php
vendored
Normal file
215
vendor/phayes/geophp/lib/geometry/Polygon.class.php
vendored
Normal file
|
@ -0,0 +1,215 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Polygon: A polygon is a plane figure that is bounded by a closed path,
|
||||
* composed of a finite sequence of straight line segments
|
||||
*/
|
||||
class Polygon extends Collection
|
||||
{
|
||||
protected $geom_type = 'Polygon';
|
||||
|
||||
// The boundary of a polygin is it's outer ring
|
||||
public function boundary() {
|
||||
return $this->exteriorRing();
|
||||
}
|
||||
|
||||
public function area($exterior_only = FALSE, $signed = FALSE) {
|
||||
if ($this->isEmpty()) return 0;
|
||||
|
||||
if ($this->geos() && $exterior_only == FALSE) {
|
||||
return $this->geos()->area();
|
||||
}
|
||||
|
||||
$exterior_ring = $this->components[0];
|
||||
$pts = $exterior_ring->getComponents();
|
||||
|
||||
$c = count($pts);
|
||||
if((int)$c == '0') return NULL;
|
||||
$a = '0';
|
||||
foreach($pts as $k => $p){
|
||||
$j = ($k + 1) % $c;
|
||||
$a = $a + ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX());
|
||||
}
|
||||
|
||||
if ($signed) $area = ($a / 2);
|
||||
else $area = abs(($a / 2));
|
||||
|
||||
if ($exterior_only == TRUE) {
|
||||
return $area;
|
||||
}
|
||||
foreach ($this->components as $delta => $component) {
|
||||
if ($delta != 0) {
|
||||
$inner_poly = new Polygon(array($component));
|
||||
$area -= $inner_poly->area();
|
||||
}
|
||||
}
|
||||
return $area;
|
||||
}
|
||||
|
||||
public function centroid() {
|
||||
if ($this->isEmpty()) return NULL;
|
||||
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->centroid());
|
||||
}
|
||||
|
||||
$exterior_ring = $this->components[0];
|
||||
$pts = $exterior_ring->getComponents();
|
||||
|
||||
$c = count($pts);
|
||||
if((int)$c == '0') return NULL;
|
||||
$cn = array('x' => '0', 'y' => '0');
|
||||
$a = $this->area(TRUE, TRUE);
|
||||
|
||||
// If this is a polygon with no area. Just return the first point.
|
||||
if ($a == 0) {
|
||||
return $this->exteriorRing()->pointN(1);
|
||||
}
|
||||
|
||||
foreach($pts as $k => $p){
|
||||
$j = ($k + 1) % $c;
|
||||
$P = ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX());
|
||||
$cn['x'] = $cn['x'] + ($p->getX() + $pts[$j]->getX()) * $P;
|
||||
$cn['y'] = $cn['y'] + ($p->getY() + $pts[$j]->getY()) * $P;
|
||||
}
|
||||
|
||||
$cn['x'] = $cn['x'] / ( 6 * $a);
|
||||
$cn['y'] = $cn['y'] / ( 6 * $a);
|
||||
|
||||
$centroid = new Point($cn['x'], $cn['y']);
|
||||
return $centroid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the outermost point from the centroid
|
||||
*
|
||||
* @returns Point The outermost point
|
||||
*/
|
||||
public function outermostPoint() {
|
||||
$centroid = $this->getCentroid();
|
||||
|
||||
$max = array('length' => 0, 'point' => null);
|
||||
|
||||
foreach($this->getPoints() as $point) {
|
||||
$lineString = new LineString(array($centroid, $point));
|
||||
|
||||
if($lineString->length() > $max['length']) {
|
||||
$max['length'] = $lineString->length();
|
||||
$max['point'] = $point;
|
||||
}
|
||||
}
|
||||
|
||||
return $max['point'];
|
||||
}
|
||||
|
||||
public function exteriorRing() {
|
||||
if ($this->isEmpty()) return new LineString();
|
||||
return $this->components[0];
|
||||
}
|
||||
|
||||
public function numInteriorRings() {
|
||||
if ($this->isEmpty()) return 0;
|
||||
return $this->numGeometries()-1;
|
||||
}
|
||||
|
||||
public function interiorRingN($n) {
|
||||
return $this->geometryN($n+1);
|
||||
}
|
||||
|
||||
public function dimension() {
|
||||
if ($this->isEmpty()) return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function isSimple() {
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->isSimple();
|
||||
}
|
||||
|
||||
$segments = $this->explode();
|
||||
|
||||
foreach ($segments as $i => $segment) {
|
||||
foreach ($segments as $j => $check_segment) {
|
||||
if ($i != $j) {
|
||||
if ($segment->lineSegmentIntersect($check_segment)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given point, determine whether it's bounded by the given polygon.
|
||||
* Adapted from http://www.assemblysys.com/dataServices/php_pointinpolygon.php
|
||||
* @see http://en.wikipedia.org/wiki/Point%5Fin%5Fpolygon
|
||||
*
|
||||
* @param Point $point
|
||||
* @param boolean $pointOnBoundary - whether a boundary should be considered "in" or not
|
||||
* @param boolean $pointOnVertex - whether a vertex should be considered "in" or not
|
||||
* @return boolean
|
||||
*/
|
||||
public function pointInPolygon($point, $pointOnBoundary = true, $pointOnVertex = true) {
|
||||
$vertices = $this->getPoints();
|
||||
|
||||
// Check if the point sits exactly on a vertex
|
||||
if ($this->pointOnVertex($point, $vertices)) {
|
||||
return $pointOnVertex ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
// Check if the point is inside the polygon or on the boundary
|
||||
$intersections = 0;
|
||||
$vertices_count = count($vertices);
|
||||
|
||||
for ($i=1; $i < $vertices_count; $i++) {
|
||||
$vertex1 = $vertices[$i-1];
|
||||
$vertex2 = $vertices[$i];
|
||||
if ($vertex1->y() == $vertex2->y()
|
||||
&& $vertex1->y() == $point->y()
|
||||
&& $point->x() > min($vertex1->x(), $vertex2->x())
|
||||
&& $point->x() < max($vertex1->x(), $vertex2->x())) {
|
||||
// Check if point is on an horizontal polygon boundary
|
||||
return $pointOnBoundary ? TRUE : FALSE;
|
||||
}
|
||||
if ($point->y() > min($vertex1->y(), $vertex2->y())
|
||||
&& $point->y() <= max($vertex1->y(), $vertex2->y())
|
||||
&& $point->x() <= max($vertex1->x(), $vertex2->x())
|
||||
&& $vertex1->y() != $vertex2->y()) {
|
||||
$xinters =
|
||||
($point->y() - $vertex1->y()) * ($vertex2->x() - $vertex1->x())
|
||||
/ ($vertex2->y() - $vertex1->y())
|
||||
+ $vertex1->x();
|
||||
if ($xinters == $point->x()) {
|
||||
// Check if point is on the polygon boundary (other than horizontal)
|
||||
return $pointOnBoundary ? TRUE : FALSE;
|
||||
}
|
||||
if ($vertex1->x() == $vertex2->x() || $point->x() <= $xinters) {
|
||||
$intersections++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the number of edges we passed through is even, then it's in the polygon.
|
||||
if ($intersections % 2 != 0) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
public function pointOnVertex($point) {
|
||||
foreach($this->getPoints() as $vertex) {
|
||||
if ($point->equals($vertex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Not valid for this geometry type
|
||||
// --------------------------------
|
||||
public function length() { return NULL; }
|
||||
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue