Skip to content

Commit

Permalink
Adding support for empty geometries
Browse files Browse the repository at this point in the history
  • Loading branch information
phayes committed Apr 12, 2012
1 parent 532a6a4 commit 920edec
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 18 deletions.
1 change: 1 addition & 0 deletions lib/adapters/GPX.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function read($gpx) {
* @return string The GPX string representation of the input geometries
*/
public function write(Geometry $geometry) {
if ($geometry->isEmpty()) return NULL;
return '<gpx creator="geoPHP" version="1.0">'.$this->geometryToGPX($geometry).'</gpx>';
}

Expand Down
20 changes: 18 additions & 2 deletions lib/adapters/WKB.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
class WKB extends GeoAdapter
{

private $dimension = 2;
private $z = FALSE;
private $m = FALSE;

/**
* Read WKB into geometry objects
*
Expand Down Expand Up @@ -44,6 +48,15 @@ function getGeometry(&$mem) {
throw new Exception('Only NDR (little endian) SKB format is supported at the moment');
}

if ($base_info['z']) {
$this->dimension++;
$this->z = TRUE;
}
if ($base_info['m']) {
$this->dimension++;
$this->m = TRUE;
}

// If there is SRID information, ignore it - use EWKB Adapter to get SRID support
if ($base_info['s']) {
fread($mem, 4);
Expand All @@ -68,16 +81,19 @@ function getGeometry(&$mem) {
}

function getPoint(&$mem) {
$point_coords = unpack("d*", fread($mem,16));
$point_coords = unpack("d*", fread($mem,$this->dimension*8));
return new Point($point_coords[1],$point_coords[2]);
}

function getLinstring(&$mem) {
// Get the number of points expected in this string out of the first 4 bytes
$line_length = unpack('L',fread($mem,4));

// Return an empty linestring if there is no line-length
if (!$line_length[1]) return new LineString();

// Read the nubmer of points x2 (each point is two coords) into decimal-floats
$line_coords = unpack('d'.$line_length[1]*2, fread($mem,$line_length[1]*16));
$line_coords = unpack('d*', fread($mem,$line_length[1]*$this->dimension*8));

// We have our coords, build up the linestring
$components = array();
Expand Down
29 changes: 28 additions & 1 deletion lib/adapters/WKT.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ private function parsePoint($data_string) {

private function parseLineString($data_string) {
$data_string = $this->trimParens($data_string);

// If it's marked as empty, then return an empty line
if ($data_string == 'EMPTY') return new LineString();

$parts = explode(',',$data_string);
$points = array();
foreach ($parts as $part) {
Expand All @@ -79,6 +83,10 @@ private function parseLineString($data_string) {

private function parsePolygon($data_string) {
$data_string = $this->trimParens($data_string);

// If it's marked as empty, then return an empty polygon
if ($data_string == 'EMPTY') return new Polygon();

$parts = explode('),(',$data_string);
$lines = array();
foreach ($parts as $part) {
Expand All @@ -91,6 +99,10 @@ private function parsePolygon($data_string) {

private function parseMultiPoint($data_string) {
$data_string = $this->trimParens($data_string);

// If it's marked as empty, then return an empty MutiPoint
if ($data_string == 'EMPTY') return new MultiPoint();

$parts = explode(',',$data_string);
$points = array();
foreach ($parts as $part) {
Expand All @@ -101,6 +113,10 @@ private function parseMultiPoint($data_string) {

private function parseMultiLineString($data_string) {
$data_string = $this->trimParens($data_string);

// If it's marked as empty, then return an empty multi-linestring
if ($data_string == 'EMPTY') return new MultiLineString();

$parts = explode('),(',$data_string);
$lines = array();
foreach ($parts as $part) {
Expand All @@ -114,6 +130,10 @@ private function parseMultiLineString($data_string) {

private function parseMultiPolygon($data_string) {
$data_string = $this->trimParens($data_string);

// If it's marked as empty, then return an empty multi-polygon
if ($data_string == 'EMPTY') return new MultiPolygon();

$parts = explode(')),((',$data_string);
$polys = array();
foreach ($parts as $part) {
Expand All @@ -127,6 +147,10 @@ private function parseMultiPolygon($data_string) {

private function parseGeometryCollection($data_string) {
$data_string = $this->trimParens($data_string);

// If it's marked as empty, then return an empty geom-collection
if ($data_string == 'EMPTY') return new GeometryCollection();

$geometries = array();
$matches = array();
$str = preg_replace('/,\s*([A-Za-z])/', '|$1', $data_string);
Expand Down Expand Up @@ -179,7 +203,10 @@ public function write(Geometry $geometry) {
return $writer->write($geometry->geos());
}

if ($data = $this->extractData($geometry)) {
if ($geometry->isEmpty()) {
return strtoupper($geometry->geometryType()).' EMPTY';
}
else if ($data = $this->extractData($geometry)) {
return strtoupper($geometry->geometryType()).' ('.$data.')';
}
}
Expand Down
23 changes: 17 additions & 6 deletions lib/geometry/Collection.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,18 @@ abstract class Collection extends Geometry
*
* @param array $components array of geometries
*/
public function __construct(array $components) {
public function __construct($components = array()) {
if (!is_array($components)) {
throw new Exception("Component geometries must be passed as an array");
}
foreach ($components as $component) {
if ($component instanceof Geometry) {
$this->components[] = $component;
}
else {
throw new Exception("Cannot create empty collection");
throw new Exception("Cannot create a collection with non-geometries");
}
}

if (empty($this->components)) {
throw new Exception("Cannot create empty ".get_called_class());
}
}

/**
Expand Down Expand Up @@ -177,6 +176,18 @@ public function dimension() {
return $dimension;
}

// A collection is empty if it has no components OR all it's components are empty
public function isEmpty() {
if (!count($this->components)) {
return TRUE;
}
else {
foreach ($this->components as $component) {
if (!$component->isEmpty()) return FALSE;
}
return TRUE;
}
}

// Not valid for this geometry type
// --------------------------------
Expand Down
7 changes: 1 addition & 6 deletions lib/geometry/Geometry.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ abstract public function exteriorRing();
abstract public function numInteriorRings();
abstract public function interiorRingN($n);
abstract public function dimension();

abstract public function isEmpty();

// Abtract: Non-Standard
// ---------------------
Expand Down Expand Up @@ -315,11 +315,6 @@ public function isMeasured() {
return FALSE;
}

public function isEmpty() {
// geoPHP does not yet support empty geometries
return FALSE;
}

public function coordinateDimension() {
// geoPHP only supports 2-dimentional space
return 2;
Expand Down
6 changes: 3 additions & 3 deletions lib/geometry/LineString.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class LineString extends Collection
* @param array $points An array of at least two points with
* which to build the LineString
*/
public function __construct(array $points) {
if (count($points) < 2) {
throw new Exception("Cannot construct LineString with less than two points");
public function __construct($points = array()) {
if (count($points) == 1) {
throw new Exception("Cannot construct a LineString with a single point");
}

// Call the Collection constructor to build the LineString
Expand Down
4 changes: 4 additions & 0 deletions lib/geometry/Point.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ public function dimension() {
return 0;
}

public function isEmpty() {
return FALSE;
}

// Not valid for this geometry type
public function numGeometries() { return NULL; }
public function geometryN($n) { return NULL; }
Expand Down

0 comments on commit 920edec

Please sign in to comment.