forked from lino/radar-wp
258 lines
7.3 KiB
PHP
258 lines
7.3 KiB
PHP
<?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);
|
|
}
|
|
}
|
|
}
|