123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- <?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
- // beggining 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, $wkt_geom);
- $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);
- $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, $type) {
- return substr($wkt, strlen($type));
- }
-
- /**
- * 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);
- }
- }
- }
|