diff --git a/geoPHP.inc b/geoPHP.inc index b9e413c9..7a4af6cf 100644 --- a/geoPHP.inc +++ b/geoPHP.inc @@ -234,7 +234,8 @@ class geoPHP // First char is a tab, space or carriage-return. trim it and try again if ($bytes[1] == 9 || $bytes[1] == 10 || $bytes[1] == 32) { - return geoPHP::detectFormat(ltrim($input)); + $ltinput = ltrim($input); + return geoPHP::detectFormat($ltinput); } // Detect WKB or EWKB -- first byte is 1 (little endian indicator) diff --git a/lib/adapters/GeoJSON.class.php b/lib/adapters/GeoJSON.class.php index abe8e926..fa0a0e22 100644 --- a/lib/adapters/GeoJSON.class.php +++ b/lib/adapters/GeoJSON.class.php @@ -55,7 +55,12 @@ private function objToGeom($obj) { } private function arrayToPoint($array) { - return new Point($array[0], $array[1]); + if (!empty($array)) { + return new Point($array[0], $array[1]); + } + else { + return new Point(); + } } private function arrayToLineString($array) { diff --git a/lib/adapters/GeoRSS.class.php b/lib/adapters/GeoRSS.class.php index 970b1564..8934b997 100644 --- a/lib/adapters/GeoRSS.class.php +++ b/lib/adapters/GeoRSS.class.php @@ -82,6 +82,11 @@ protected function geomFromXML() { protected function getPointsFromCoords($string) { $coords = array(); + + if (empty($string)) { + return $coords; + } + $latlon = explode(' ',$string); foreach ($latlon as $key => $item) { if (!($key % 2)) { @@ -101,8 +106,15 @@ protected function parsePoints() { $points = array(); $pt_elements = $this->xmlobj->getElementsByTagName('point'); foreach ($pt_elements as $pt) { - $point_array = $this->getPointsFromCoords(trim($pt->firstChild->nodeValue)); - $points[] = $point_array[0]; + if ($pt->hasChildNodes()) { + $point_array = $this->getPointsFromCoords(trim($pt->firstChild->nodeValue)); + } + if (!empty($point_array)) { + $points[] = $point_array[0]; + } + else { + $points[] = new Point(); + } } return $points; } @@ -188,9 +200,13 @@ protected function geometryToGeoRSS($geom) { } private function pointToGeoRSS($geom) { - return '<'.$this->nss.'point>'.$geom->getY().' '.$geom->getX().'nss.'point>'; + $out = '<'.$this->nss.'point>'; + if (!$geom->isEmpty()) { + $out .= $geom->getY().' '.$geom->getX(); + } + $out .= 'nss.'point>'; + return $out; } - private function linestringToGeoRSS($geom) { $output = '<'.$this->nss.'line>'; diff --git a/lib/adapters/KML.class.php b/lib/adapters/KML.class.php index 346ffbff..8be9f680 100644 --- a/lib/adapters/KML.class.php +++ b/lib/adapters/KML.class.php @@ -114,7 +114,12 @@ protected function childElements($xml, $nodename = '') { protected function parsePoint($xml) { $coordinates = $this->_extractCoordinates($xml); - return new Point($coordinates[0][0],$coordinates[0][1]); + if (!empty($coordinates)) { + return new Point($coordinates[0][0],$coordinates[0][1]); + } + else { + return new Point(); + } } protected function parseLineString($xml) { @@ -130,6 +135,9 @@ protected function parsePolygon($xml) { $components = array(); $outer_boundary_element_a = $this->childElements($xml, 'outerboundaryis'); + if (empty($outer_boundary_element_a)) { + return new Polygon(); // It's an empty polygon + } $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]; @@ -205,7 +213,12 @@ private function geometryToKML($geom) { } private function pointToKML($geom) { - return '<'.$this->nss.'Point><'.$this->nss.'coordinates>'.$geom->getX().",".$geom->getY().'nss.'coordinates>nss.'Point>'; + $out = '<'.$this->nss.'Point>'; + if (!$geom->isEmpty()) { + $out .= '<'.$this->nss.'coordinates>'.$geom->getX().",".$geom->getY().'nss.'coordinates>'; + } + $out .= 'nss.'Point>'; + return $out; } private function linestringToKML($geom, $type = FALSE) { diff --git a/lib/adapters/WKB.class.php b/lib/adapters/WKB.class.php index 0a191046..ebaff43a 100644 --- a/lib/adapters/WKB.class.php +++ b/lib/adapters/WKB.class.php @@ -86,7 +86,12 @@ function getGeometry(&$mem) { function getPoint(&$mem) { $point_coords = unpack("d*", fread($mem,$this->dimension*8)); - return new Point($point_coords[1],$point_coords[2]); + if (!empty($point_coords)) { + return new Point($point_coords[1],$point_coords[2]); + } + else { + return new Point(); // EMPTY point + } } function getLinstring(&$mem) { @@ -198,9 +203,12 @@ public function write(Geometry $geometry, $write_as_hex = FALSE) { function writePoint($point) { // Set the coords - $wkb = pack('dd',$point->x(), $point->y()); - - return $wkb; + if (!$point->isEmpty()) { + $wkb = pack('dd',$point->x(), $point->y()); + return $wkb; + } else { + return ''; + } } function writeLineString($line) { diff --git a/lib/geometry/Point.class.php b/lib/geometry/Point.class.php index 420b3e38..d6556cb6 100644 --- a/lib/geometry/Point.class.php +++ b/lib/geometry/Point.class.php @@ -17,7 +17,15 @@ class Point extends Geometry * @param numeric $y The y coordinate (or latitude) * @param numeric $z The z coordinate (or altitude) - optional */ - public function __construct($x, $y, $z = NULL) { + public function __construct($x = NULL, $y = NULL, $z = NULL) { + + // Check if it's an empty point + if ($x === NULL && $y === NULL) { + $this->coords = array(NULL, NULL); + $this->dimension = 0; + return; + } + // Basic validation on x and y if (!is_numeric($x) || !is_numeric($y)) { throw new Exception("Cannot construct Point. x and y should be numeric"); @@ -119,7 +127,12 @@ public function dimension() { } public function isEmpty() { - return FALSE; + if ($this->dimension == 0) { + return TRUE; + } + else { + return FALSE; + } } public function numPoints() { @@ -131,7 +144,18 @@ public function getPoints() { } public function equals($geometry) { - return ($this->x() == $geometry->x() && $this->y() == $geometry->y()); + if (get_class($geometry) != 'Point') { + return FALSE; + } + if (!$this->isEmpty() && !$geometry->isEmpty()) { + return ($this->x() == $geometry->x() && $this->y() == $geometry->y()); + } + else if ($this->isEmpty() && $geometry->isEmpty()) { + return TRUE; + } + else { + return FALSE; + } } public function isSimple() { diff --git a/lib/geometry/Polygon.class.php b/lib/geometry/Polygon.class.php index a2b51033..f930b18a 100644 --- a/lib/geometry/Polygon.class.php +++ b/lib/geometry/Polygon.class.php @@ -8,6 +8,11 @@ class Polygon extends Collection { protected $geom_type = 'Polygon'; + // The boundary of a polygin is it's outer ring + public function boundary() { + return $this->exteriorRing(); + } + public function area($exterior_only = FALSE, $signed = FALSE) { if ($this->isEmpty()) return 0; diff --git a/tests/input/box.georss b/tests/input/box.georss index 4c1bddfc..9dc5a2ff 100644 --- a/tests/input/box.georss +++ b/tests/input/box.georss @@ -1 +1 @@ -42.943 -71.032 43.039 -69.856 \ No newline at end of file +42.943 -71.032 43.039 -69.856 diff --git a/tests/input/circle.georss b/tests/input/circle.georss index 4d7055bf..8f6a18ec 100644 --- a/tests/input/circle.georss +++ b/tests/input/circle.georss @@ -1 +1 @@ -42.943 -71.032 500 \ No newline at end of file +42.943 -71.032 500 diff --git a/tests/input/line.georss b/tests/input/line.georss index 7dbeb12d..3ade523c 100644 --- a/tests/input/line.georss +++ b/tests/input/line.georss @@ -1 +1 @@ -45.256 -110.45 46.46 -109.48 43.84 -109.86 \ No newline at end of file +45.256 -110.45 46.46 -109.48 43.84 -109.86 diff --git a/tests/input/polygon.georss b/tests/input/polygon.georss index 7decd204..14f54d1a 100644 --- a/tests/input/polygon.georss +++ b/tests/input/polygon.georss @@ -1,3 +1,3 @@ - + 45.256 -110.45 46.46 -109.48 43.84 -109.86 45.256 -110.45 - \ No newline at end of file + diff --git a/tests/input/track.gpx b/tests/input/track.gpx index b2306a6f..23fe1d71 100644 --- a/tests/input/track.gpx +++ b/tests/input/track.gpx @@ -14,11 +14,11 @@ 4.46 - + 4.94 - + 6.87 diff --git a/tests/test.php b/tests/test.php index 09670560..ae112bd6 100644 --- a/tests/test.php +++ b/tests/test.php @@ -1,11 +1,18 @@ 'getCentroid'), - array('name' => 'getArea'), - array('name' => 'getX'), - array('name' => 'getY'), - array('name' => 'getGeos'), - array('name' => 'getGeomType'), - array('name' => 'getSRID'), - array('name' => 'asText'), - array('name' => 'asBinary'), - ); - - foreach($aliases as $alias) { - $argument = NULL; - $alias_name = $alias['name']; - if (isset($alias['argument'])) { - $argument = $alias['argument']; - } - - switch ($alias_name) { - case 'getSRID': - if ($geometry->geometryType() == 'Point') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - break; - case 'getGeos': - if ($geometry->geometryType() == 'Point') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - break; - case 'getX': - case 'getY': - if ($geometry->geometryType() == 'Point') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - break; - case 'getArea': - if ($geometry->geometryType() == 'Point') { - $this->assertEquals(0, $geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertEquals(0, $geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - break; - case 'getCentroid': - if ($geometry->geometryType() == 'Point') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - break; - case 'asText': - case 'asBinary': - case 'getGeomType': - $this->assertNotNull($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - break; - default: - $this->assertTrue($geometry->$alias_name($argument), 'Failed on ' . $alias_name .' (test file: ' . $file . ')'); - } - } - - } - } - } - -} diff --git a/tests/tests/geosTest.php b/tests/tests/geosTest.php index 80b7f7f6..e45e212f 100644 --- a/tests/tests/geosTest.php +++ b/tests/tests/geosTest.php @@ -7,6 +7,10 @@ function setUp() { } function testGeos() { + if (!geoPHP::geosInstalled()) { + echo "Skipping GEOS -- not installed"; + return; + } foreach (scandir('./input', SCANDIR_SORT_NONE) as $file) { $parts = explode('.',$file); if ($parts[0]) { diff --git a/tests/tests/methodsTest.php b/tests/tests/methodsTest.php index 097a9378..3129ff3a 100644 --- a/tests/tests/methodsTest.php +++ b/tests/tests/methodsTest.php @@ -67,14 +67,16 @@ function _methods_tester($geometry, $method_name, $argument, $file) { switch ($method_name) { case 'y': case 'x': - if ($geometry->geometryType() == 'Point') { - $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + if (!$geometry->isEmpty()) { + if ($geometry->geometryType() == 'Point') { + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + } + if ($geometry->geometryType() == 'LineString') { + $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + } + if ($geometry->geometryType() == 'MultiLineString') { + $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + } } break; case 'geometryN': @@ -180,33 +182,26 @@ function _methods_tester($geometry, $method_name, $argument, $file) { } break; case 'SRID': - if ($geometry->geometryType() == 'Point') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } break; case 'getBBox': - if ($geometry->geometryType() == 'Point') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + if (!$geometry->isEmpty()) { + if ($geometry->geometryType() == 'Point') { + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + } + if ($geometry->geometryType() == 'LineString') { + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + } + if ($geometry->geometryType() == 'MultiLineString') { + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + } } break; case 'centroid': if ($geometry->geometryType() == 'Point') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'MultiLineString') { $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); @@ -214,13 +209,13 @@ function _methods_tester($geometry, $method_name, $argument, $file) { break; case 'length': if ($geometry->geometryType() == 'Point') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertEquals($geometry->$method_name($argument), 0, 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotEquals($geometry->$method_name($argument), 0, 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotEquals($geometry->$method_name($argument), 0, 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } break; case 'numGeometries': @@ -228,7 +223,7 @@ function _methods_tester($geometry, $method_name, $argument, $file) { $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'MultiLineString') { $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); @@ -236,10 +231,10 @@ function _methods_tester($geometry, $method_name, $argument, $file) { break; case 'numPoints': if ($geometry->geometryType() == 'Point') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'MultiLineString') { $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); @@ -247,10 +242,10 @@ function _methods_tester($geometry, $method_name, $argument, $file) { break; case 'dimension': if ($geometry->geometryType() == 'Point') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'MultiLineString') { $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); @@ -258,10 +253,10 @@ function _methods_tester($geometry, $method_name, $argument, $file) { break; case 'boundary': if ($geometry->geometryType() == 'Point') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'LineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'MultiLineString') { $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); diff --git a/tests/tests/placeholdersTest.php b/tests/tests/placeholdersTest.php index 42e6c5e9..8f50f4dd 100644 --- a/tests/tests/placeholdersTest.php +++ b/tests/tests/placeholdersTest.php @@ -33,8 +33,7 @@ function testPlaceholders() { } switch ($method_name) { - case 'm': - case 'z': + case 'hasZ': if ($geometry->geometryType() == 'Point') { $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } @@ -42,26 +41,15 @@ function testPlaceholders() { $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); + $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } break; + case 'm': + case 'z': case 'coordinateDimension': case 'isEmpty': case 'isMeasured': case 'is3D': - case 'hasZ': - if ($geometry->geometryType() == 'Point') { - $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'LineString') { - $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - if ($geometry->geometryType() == 'MultiLineString') { - $this->assertNotNull($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); - } - break; - default: - $this->assertTrue($geometry->$method_name($argument), 'Failed on ' . $method_name .' (test file: ' . $file . ')'); } }