WKT.class.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. /**
  3. * WKT (Well Known Text) Adapter
  4. */
  5. class WKT extends GeoAdapter
  6. {
  7. /**
  8. * Read WKT string into geometry objects
  9. *
  10. * @param string $WKT A WKT string
  11. *
  12. * @return Geometry
  13. */
  14. public function read($wkt) {
  15. $wkt = trim($wkt);
  16. // If it contains a ';', then it contains additional SRID data
  17. if (strpos($wkt,';')) {
  18. $parts = explode(';', $wkt);
  19. $wkt = $parts[1];
  20. $eparts = explode('=',$parts[0]);
  21. $srid = $eparts[1];
  22. }
  23. else {
  24. $srid = NULL;
  25. }
  26. // If geos is installed, then we take a shortcut and let it parse the WKT
  27. if (geoPHP::geosInstalled()) {
  28. $reader = new GEOSWKTReader();
  29. if ($srid) {
  30. $geom = geoPHP::geosToGeometry($reader->read($wkt));
  31. $geom->setSRID($srid);
  32. return $geom;
  33. }
  34. else {
  35. return geoPHP::geosToGeometry($reader->read($wkt));
  36. }
  37. }
  38. $wkt = str_replace(', ', ',', $wkt);
  39. // For each geometry type, check to see if we have a match at the
  40. // beginning of the string. If we do, then parse using that type
  41. foreach (geoPHP::geometryList() as $geom_type) {
  42. $wkt_geom = strtoupper($geom_type);
  43. if (strtoupper(substr($wkt, 0, strlen($wkt_geom))) == $wkt_geom) {
  44. $data_string = $this->getDataString($wkt);
  45. $method = 'parse'.$geom_type;
  46. if ($srid) {
  47. $geom = $this->$method($data_string);
  48. $geom->setSRID($srid);
  49. return $geom;
  50. }
  51. else {
  52. return $this->$method($data_string);
  53. }
  54. }
  55. }
  56. }
  57. private function parsePoint($data_string) {
  58. $data_string = $this->trimParens($data_string);
  59. // If it's marked as empty, then return an empty point
  60. if ($data_string == 'EMPTY') return new Point();
  61. $parts = explode(' ',$data_string);
  62. return new Point($parts[0], $parts[1]);
  63. }
  64. private function parseLineString($data_string) {
  65. $data_string = $this->trimParens($data_string);
  66. // If it's marked as empty, then return an empty line
  67. if ($data_string == 'EMPTY') return new LineString();
  68. $parts = explode(',',$data_string);
  69. $points = array();
  70. foreach ($parts as $part) {
  71. $points[] = $this->parsePoint($part);
  72. }
  73. return new LineString($points);
  74. }
  75. private function parsePolygon($data_string) {
  76. $data_string = $this->trimParens($data_string);
  77. // If it's marked as empty, then return an empty polygon
  78. if ($data_string == 'EMPTY') return new Polygon();
  79. $parts = explode('),(',$data_string);
  80. $lines = array();
  81. foreach ($parts as $part) {
  82. if (!$this->beginsWith($part,'(')) $part = '(' . $part;
  83. if (!$this->endsWith($part,')')) $part = $part . ')';
  84. $lines[] = $this->parseLineString($part);
  85. }
  86. return new Polygon($lines);
  87. }
  88. private function parseMultiPoint($data_string) {
  89. $data_string = $this->trimParens($data_string);
  90. // If it's marked as empty, then return an empty MutiPoint
  91. if ($data_string == 'EMPTY') return new MultiPoint();
  92. $parts = explode(',',$data_string);
  93. $points = array();
  94. foreach ($parts as $part) {
  95. $points[] = $this->parsePoint($part);
  96. }
  97. return new MultiPoint($points);
  98. }
  99. private function parseMultiLineString($data_string) {
  100. $data_string = $this->trimParens($data_string);
  101. // If it's marked as empty, then return an empty multi-linestring
  102. if ($data_string == 'EMPTY') return new MultiLineString();
  103. $parts = explode('),(',$data_string);
  104. $lines = array();
  105. foreach ($parts as $part) {
  106. // Repair the string if the explode broke it
  107. if (!$this->beginsWith($part,'(')) $part = '(' . $part;
  108. if (!$this->endsWith($part,')')) $part = $part . ')';
  109. $lines[] = $this->parseLineString($part);
  110. }
  111. return new MultiLineString($lines);
  112. }
  113. private function parseMultiPolygon($data_string) {
  114. $data_string = $this->trimParens($data_string);
  115. // If it's marked as empty, then return an empty multi-polygon
  116. if ($data_string == 'EMPTY') return new MultiPolygon();
  117. $parts = explode(')),((',$data_string);
  118. $polys = array();
  119. foreach ($parts as $part) {
  120. // Repair the string if the explode broke it
  121. if (!$this->beginsWith($part,'((')) $part = '((' . $part;
  122. if (!$this->endsWith($part,'))')) $part = $part . '))';
  123. $polys[] = $this->parsePolygon($part);
  124. }
  125. return new MultiPolygon($polys);
  126. }
  127. private function parseGeometryCollection($data_string) {
  128. $data_string = $this->trimParens($data_string);
  129. // If it's marked as empty, then return an empty geom-collection
  130. if ($data_string == 'EMPTY') return new GeometryCollection();
  131. $geometries = array();
  132. $matches = array();
  133. $str = preg_replace('/,\s*([A-Za-z])/', '|$1', $data_string);
  134. $components = explode('|', trim($str));
  135. foreach ($components as $component) {
  136. $geometries[] = $this->read($component);
  137. }
  138. return new GeometryCollection($geometries);
  139. }
  140. protected function getDataString($wkt) {
  141. $first_paren = strpos($wkt, '(');
  142. if ($first_paren !== FALSE) {
  143. return substr($wkt, $first_paren);
  144. } elseif (strstr($wkt,'EMPTY')) {
  145. return 'EMPTY';
  146. } else
  147. return FALSE;
  148. }
  149. /**
  150. * Trim the parenthesis and spaces
  151. */
  152. protected function trimParens($str) {
  153. $str = trim($str);
  154. // We want to only strip off one set of parenthesis
  155. if ($this->beginsWith($str, '(')) {
  156. return substr($str,1,-1);
  157. }
  158. else return $str;
  159. }
  160. protected function beginsWith($str, $char) {
  161. if (substr($str,0,strlen($char)) == $char) return TRUE;
  162. else return FALSE;
  163. }
  164. protected function endsWith($str, $char) {
  165. if (substr($str,(0 - strlen($char))) == $char) return TRUE;
  166. else return FALSE;
  167. }
  168. /**
  169. * Serialize geometries into a WKT string.
  170. *
  171. * @param Geometry $geometry
  172. *
  173. * @return string The WKT string representation of the input geometries
  174. */
  175. public function write(Geometry $geometry) {
  176. // If geos is installed, then we take a shortcut and let it write the WKT
  177. if (geoPHP::geosInstalled()) {
  178. $writer = new GEOSWKTWriter();
  179. $writer->setTrim(TRUE);
  180. return $writer->write($geometry->geos());
  181. }
  182. if ($geometry->isEmpty()) {
  183. return strtoupper($geometry->geometryType()).' EMPTY';
  184. }
  185. else if ($data = $this->extractData($geometry)) {
  186. return strtoupper($geometry->geometryType()).' ('.$data.')';
  187. }
  188. }
  189. /**
  190. * Extract geometry to a WKT string
  191. *
  192. * @param Geometry $geometry A Geometry object
  193. *
  194. * @return string
  195. */
  196. public function extractData($geometry) {
  197. $parts = array();
  198. switch ($geometry->geometryType()) {
  199. case 'Point':
  200. return $geometry->getX().' '.$geometry->getY();
  201. case 'LineString':
  202. foreach ($geometry->getComponents() as $component) {
  203. $parts[] = $this->extractData($component);
  204. }
  205. return implode(', ', $parts);
  206. case 'Polygon':
  207. case 'MultiPoint':
  208. case 'MultiLineString':
  209. case 'MultiPolygon':
  210. foreach ($geometry->getComponents() as $component) {
  211. $parts[] = '('.$this->extractData($component).')';
  212. }
  213. return implode(', ', $parts);
  214. case 'GeometryCollection':
  215. foreach ($geometry->getComponents() as $component) {
  216. $parts[] = strtoupper($component->geometryType()).' ('.$this->extractData($component).')';
  217. }
  218. return implode(', ', $parts);
  219. }
  220. }
  221. }