Skip to content

Commit

Permalink
GeoJSON and KML can now deal with empty geometries
Browse files Browse the repository at this point in the history
  • Loading branch information
phayes committed Aug 27, 2012
1 parent 54eab05 commit 29fd6d9
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 58 deletions.
29 changes: 12 additions & 17 deletions lib/adapters/GeoJSON.class.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* GeoJSON class : a geojson reader/writer.
*
*
* Note that it will always return a GeoJSON geometry. This
* means that if you pass it a feature, it will return the
* geometry of that feature strip everything else.
Expand All @@ -25,7 +25,7 @@ public function read($input) {
if (!is_string($input->type)) {
throw new Exception('Invalid JSON');
}

// Check to see if it's a FeatureCollection
if ($input->type == 'FeatureCollection') {
$geoms = array();
Expand All @@ -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]);
}
Expand Down Expand Up @@ -102,7 +97,7 @@ private function arrayToMultiPolygon($array) {
}
return new MultiPolygon($polys);
}

private function objToGeometryCollection($obj) {
$geoms = array();
if (empty($obj->geometries)) {
Expand All @@ -113,7 +108,7 @@ private function objToGeometryCollection($obj) {
}
return new GeometryCollection($geoms);
}

/**
* Serializes an object into a geojson string
*
Expand All @@ -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();
Expand Down
91 changes: 50 additions & 41 deletions lib/adapters/KML.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,7 +33,7 @@ class KML extends GeoAdapter
public function read($kml) {
return $this->geomFromText($kml);
}

/**
* Serialize geometries into a KML string.
*
Expand All @@ -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('/<!\[cdata\[(.*?)\]\]>/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();
Expand All @@ -73,7 +73,7 @@ public function geomFromText($text) {

return $geom;
}

protected function geomFromXML() {
$geometries = array();
$geom_types = geoPHP::geometryList();
Expand All @@ -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();
Expand All @@ -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) {
Expand All @@ -146,10 +148,10 @@ protected function parsePolygon($xml) {
}
}
}

return new Polygon($components);
}

protected function parseGeometryCollection($xml) {
$components = array();
$geom_types = geoPHP::geometryList();
Expand All @@ -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) {
Expand All @@ -179,10 +178,10 @@ protected function _extractCoordinates($xml) {
}
}
}

return $coordinates;
}

private function geometryToKML($geom) {
$type = strtolower($geom->getGeomType());
switch ($type) {
Expand Down Expand Up @@ -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 .= '</'.$this->nss.'coordinates>';
}

return $str .'</'.$this->nss.'coordinates></'. $this->nss . $type .'>';
$str .= '</'. $this->nss . $type .'>';

return $str;
}

public function polygonToKML($geom) {
$components = $geom->getComponents();
$str = '<'.$this->nss.'outerBoundaryIs>' . $this->linestringToKML($components[0], 'LinearRing') . '</'.$this->nss.'outerBoundaryIs>';
foreach (array_slice($components, 1) as $comp) {
$str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . '</'.$this->nss.'innerBoundaryIs>';
if (!empty($components)) {
$str = '<'.$this->nss.'outerBoundaryIs>' . $this->linestringToKML($components[0], 'LinearRing') . '</'.$this->nss.'outerBoundaryIs>';
foreach (array_slice($components, 1) as $comp) {
$str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . '</'.$this->nss.'innerBoundaryIs>';
}
}

return '<'.$this->nss.'Polygon>'. $str .'</'.$this->nss.'Polygon>';
}

public function collectionToKML($geom) {
$components = $geom->getComponents();
$str = '<'.$this->nss.'MultiGeometry>';
Expand Down

0 comments on commit 29fd6d9

Please sign in to comment.