GPX.class.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <?php
  2. /*
  3. * Copyright (c) Patrick Hayes
  4. *
  5. * This code is open-source and licenced under the Modified BSD License.
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * PHP Geometry/GPX encoder/decoder
  11. */
  12. class GPX extends GeoAdapter
  13. {
  14. private $namespace = FALSE;
  15. private $nss = ''; // Name-space string. eg 'georss:'
  16. /**
  17. * Read GPX string into geometry objects
  18. *
  19. * @param string $gpx A GPX string
  20. *
  21. * @return Geometry|GeometryCollection
  22. */
  23. public function read($gpx) {
  24. return $this->geomFromText($gpx);
  25. }
  26. /**
  27. * Serialize geometries into a GPX string.
  28. *
  29. * @param Geometry $geometry
  30. *
  31. * @return string The GPX string representation of the input geometries
  32. */
  33. public function write(Geometry $geometry, $namespace = FALSE) {
  34. if ($geometry->isEmpty()) return NULL;
  35. if ($namespace) {
  36. $this->namespace = $namespace;
  37. $this->nss = $namespace.':';
  38. }
  39. return '<'.$this->nss.'gpx creator="geoPHP" version="1.0">'.$this->geometryToGPX($geometry).'</'.$this->nss.'gpx>';
  40. }
  41. public function geomFromText($text) {
  42. // Change to lower-case and strip all CDATA
  43. $text = strtolower($text);
  44. $text = preg_replace('/<!\[cdata\[(.*?)\]\]>/s','',$text);
  45. // Load into DOMDocument
  46. $xmlobj = new DOMDocument();
  47. @$xmlobj->loadXML($text);
  48. if ($xmlobj === false) {
  49. throw new Exception("Invalid GPX: ". $text);
  50. }
  51. $this->xmlobj = $xmlobj;
  52. try {
  53. $geom = $this->geomFromXML();
  54. } catch(InvalidText $e) {
  55. throw new Exception("Cannot Read Geometry From GPX: ". $text);
  56. } catch(Exception $e) {
  57. throw $e;
  58. }
  59. return $geom;
  60. }
  61. protected function geomFromXML() {
  62. $geometries = array();
  63. $geometries = array_merge($geometries, $this->parseWaypoints());
  64. $geometries = array_merge($geometries, $this->parseTracks());
  65. $geometries = array_merge($geometries, $this->parseRoutes());
  66. if (empty($geometries)) {
  67. throw new Exception("Invalid / Empty GPX");
  68. }
  69. return geoPHP::geometryReduce($geometries);
  70. }
  71. protected function childElements($xml, $nodename = '') {
  72. $children = array();
  73. foreach ($xml->childNodes as $child) {
  74. if ($child->nodeName == $nodename) {
  75. $children[] = $child;
  76. }
  77. }
  78. return $children;
  79. }
  80. protected function parseWaypoints() {
  81. $points = array();
  82. $wpt_elements = $this->xmlobj->getElementsByTagName('wpt');
  83. foreach ($wpt_elements as $wpt) {
  84. $lat = $wpt->attributes->getNamedItem("lat")->nodeValue;
  85. $lon = $wpt->attributes->getNamedItem("lon")->nodeValue;
  86. $points[] = new Point($lon, $lat);
  87. }
  88. return $points;
  89. }
  90. protected function parseTracks() {
  91. $lines = array();
  92. $trk_elements = $this->xmlobj->getElementsByTagName('trk');
  93. foreach ($trk_elements as $trk) {
  94. $components = array();
  95. foreach ($this->childElements($trk, 'trkseg') as $trkseg) {
  96. foreach ($this->childElements($trkseg, 'trkpt') as $trkpt) {
  97. $lat = $trkpt->attributes->getNamedItem("lat")->nodeValue;
  98. $lon = $trkpt->attributes->getNamedItem("lon")->nodeValue;
  99. $components[] = new Point($lon, $lat);
  100. }
  101. }
  102. if ($components) {$lines[] = new LineString($components);}
  103. }
  104. return $lines;
  105. }
  106. protected function parseRoutes() {
  107. $lines = array();
  108. $rte_elements = $this->xmlobj->getElementsByTagName('rte');
  109. foreach ($rte_elements as $rte) {
  110. $components = array();
  111. foreach ($this->childElements($rte, 'rtept') as $rtept) {
  112. $lat = $rtept->attributes->getNamedItem("lat")->nodeValue;
  113. $lon = $rtept->attributes->getNamedItem("lon")->nodeValue;
  114. $components[] = new Point($lon, $lat);
  115. }
  116. $lines[] = new LineString($components);
  117. }
  118. return $lines;
  119. }
  120. protected function geometryToGPX($geom) {
  121. $type = strtolower($geom->getGeomType());
  122. switch ($type) {
  123. case 'point':
  124. return $this->pointToGPX($geom);
  125. break;
  126. case 'linestring':
  127. return $this->linestringToGPX($geom);
  128. break;
  129. case 'polygon':
  130. case 'multipoint':
  131. case 'multilinestring':
  132. case 'multipolygon':
  133. case 'geometrycollection':
  134. return $this->collectionToGPX($geom);
  135. break;
  136. }
  137. }
  138. private function pointToGPX($geom) {
  139. return '<'.$this->nss.'wpt lat="'.$geom->getY().'" lon="'.$geom->getX().'" />';
  140. }
  141. private function linestringToGPX($geom) {
  142. $gpx = '<'.$this->nss.'trk><'.$this->nss.'trkseg>';
  143. foreach ($geom->getComponents() as $comp) {
  144. $gpx .= '<'.$this->nss.'trkpt lat="'.$comp->getY().'" lon="'.$comp->getX().'" />';
  145. }
  146. $gpx .= '</'.$this->nss.'trkseg></'.$this->nss.'trk>';
  147. return $gpx;
  148. }
  149. public function collectionToGPX($geom) {
  150. $gpx = '';
  151. $components = $geom->getComponents();
  152. foreach ($geom->getComponents() as $comp) {
  153. $gpx .= $this->geometryToGPX($comp);
  154. }
  155. return $gpx;
  156. }
  157. }