From 29fd6d9ff6cf350b1c4fe1dd448b2231b45fd38d Mon Sep 17 00:00:00 2001 From: Patrick Hayes Date: Mon, 27 Aug 2012 13:03:01 -0700 Subject: [PATCH] GeoJSON and KML can now deal with empty geometries --- lib/adapters/GeoJSON.class.php | 29 +++++------ lib/adapters/KML.class.php | 91 +++++++++++++++++++--------------- 2 files changed, 62 insertions(+), 58 deletions(-) diff --git a/lib/adapters/GeoJSON.class.php b/lib/adapters/GeoJSON.class.php index 27f869c3..abe8e926 100644 --- a/lib/adapters/GeoJSON.class.php +++ b/lib/adapters/GeoJSON.class.php @@ -1,7 +1,7 @@ type)) { throw new Exception('Invalid JSON'); } - + // Check to see if it's a FeatureCollection if ($input->type == 'FeatureCollection') { $geoms = array(); @@ -34,31 +34,26 @@ public function read($input) { } 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); } - else { - if (empty($obj->coordinates)) { - throw new Exception ('Invalid GeoJSON: missing coordinates'); - } - $method = 'arrayTo' . $type; - return $this->$method($obj->coordinates); - } + $method = 'arrayTo' . $type; + return $this->$method($obj->coordinates); } - + private function arrayToPoint($array) { return new Point($array[0], $array[1]); } @@ -102,7 +97,7 @@ private function arrayToMultiPolygon($array) { } return new MultiPolygon($polys); } - + private function objToGeometryCollection($obj) { $geoms = array(); if (empty($obj->geometries)) { @@ -113,7 +108,7 @@ private function objToGeometryCollection($obj) { } return new GeometryCollection($geoms); } - + /** * Serializes an object into a geojson string * @@ -130,7 +125,7 @@ public function write(Geometry $geometry, $return_array = FALSE) { return json_encode($this->getArray($geometry)); } } - + public function getArray($geometry) { if ($geometry->getGeomType() == 'GeometryCollection') { $component_array = array(); diff --git a/lib/adapters/KML.class.php b/lib/adapters/KML.class.php index 4d76d767..b3e270f9 100644 --- a/lib/adapters/KML.class.php +++ b/lib/adapters/KML.class.php @@ -11,7 +11,7 @@ /** * PHP Geometry/KML encoder/decoder * - * Mainly inspired/adapted from OpenLayers( http://www.openlayers.org ) + * Mainly inspired/adapted from OpenLayers( http://www.openlayers.org ) * Openlayers/format/WKT.js * * @package sfMapFishPlugin @@ -33,7 +33,7 @@ class KML extends GeoAdapter public function read($kml) { return $this->geomFromText($kml); } - + /** * Serialize geometries into a KML string. * @@ -44,24 +44,24 @@ public function read($kml) { public function write(Geometry $geometry, $namespace = FALSE) { if ($namespace) { $this->namespace = $namespace; - $this->nss = $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('//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(); @@ -73,7 +73,7 @@ public function geomFromText($text) { return $geom; } - + protected function geomFromXML() { $geometries = array(); $geom_types = geoPHP::geometryList(); @@ -98,24 +98,26 @@ protected function geomFromXML() { $geometries[] = $this->$function($this->xmlobj->documentElement); } } - return geoPHP::geometryReduce($geometries); + return geoPHP::geometryReduce($geometries); } - + protected function childElements($xml, $nodename = '') { $children = array(); - foreach ($xml->childNodes as $child) { - if ($child->nodeName == $nodename) { - $children[] = $child; + if ($xml->childNodes) { + foreach ($xml->childNodes as $child) { + if ($child->nodeName == $nodename) { + $children[] = $child; + } } } return $children; } - + protected function parsePoint($xml) { $coordinates = $this->_extractCoordinates($xml); return new Point($coordinates[0][0],$coordinates[0][1]); } - + protected function parseLineString($xml) { $coordinates = $this->_extractCoordinates($xml); $point_array = array(); @@ -124,20 +126,20 @@ protected function parseLineString($xml) { } return new LineString($point_array); } - + protected function parsePolygon($xml) { $components = array(); - + $outer_boundary_element_a = $this->childElements($xml, 'outerboundaryis'); $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) { @@ -146,10 +148,10 @@ protected function parsePolygon($xml) { } } } - + return new Polygon($components); } - + protected function parseGeometryCollection($xml) { $components = array(); $geom_types = geoPHP::geometryList(); @@ -162,14 +164,11 @@ protected function parseGeometryCollection($xml) { } return new GeometryCollection($components); } - + protected function _extractCoordinates($xml) { $coord_elements = $this->childElements($xml, 'coordinates'); - if (!count($coord_elements)) { - throw new Exception('Bad KML: Missing coordinate element'); - } $coordinates = array(); - $coord_sets = explode(' ',$coord_elements[0]->nodeValue); + $coord_sets = explode(' ', $coord_elements[0]->nodeValue); foreach ($coord_sets as $set_string) { $set_string = trim($set_string); if ($set_string) { @@ -179,10 +178,10 @@ protected function _extractCoordinates($xml) { } } } - + return $coordinates; } - + private function geometryToKML($geom) { $type = strtolower($geom->getGeomType()); switch ($type) { @@ -212,28 +211,38 @@ private function linestringToKML($geom, $type = FALSE) { if (!$type) { $type = $geom->getGeomType(); } - - $str = '<'.$this->nss . $type .'><'.$this->nss.'coordinates>'; - $i=0; - foreach ($geom->getComponents() as $comp) { - if ($i != 0) $str .= ' '; - $str .= $comp->getX() .','. $comp->getY(); - $i++; + + $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 .= 'nss.'coordinates>'; } - return $str .'nss.'coordinates>nss . $type .'>'; + $str .= 'nss . $type .'>'; + + return $str; } public function polygonToKML($geom) { $components = $geom->getComponents(); - $str = '<'.$this->nss.'outerBoundaryIs>' . $this->linestringToKML($components[0], 'LinearRing') . 'nss.'outerBoundaryIs>'; - foreach (array_slice($components, 1) as $comp) { - $str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . 'nss.'innerBoundaryIs>'; + if (!empty($components)) { + $str = '<'.$this->nss.'outerBoundaryIs>' . $this->linestringToKML($components[0], 'LinearRing') . 'nss.'outerBoundaryIs>'; + foreach (array_slice($components, 1) as $comp) { + $str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . 'nss.'innerBoundaryIs>'; + } } - + return '<'.$this->nss.'Polygon>'. $str .'nss.'Polygon>'; } - + public function collectionToKML($geom) { $components = $geom->getComponents(); $str = '<'.$this->nss.'MultiGeometry>';