Skip to content

Commit

Permalink
Various clean-up, finishing basic geometric methods
Browse files Browse the repository at this point in the history
  • Loading branch information
phayes committed Apr 19, 2012
1 parent 851606d commit be0ce05
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 31 deletions.
3 changes: 1 addition & 2 deletions geoPHP.inc
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ class geoPHP
}
$wkb_writer = new GEOSWKBWriter();
$wkb = $wkb_writer->writeHEX($geos);
$geometry = geoPHP::load($wkb,'wkb',TRUE);
//@@TODO: We no longer need to check this once we have Empty geometries
$geometry = geoPHP::load($wkb, 'wkb', TRUE);
if ($geometry) {
$geometry->setGeos($geos);
return $geometry;
Expand Down
3 changes: 0 additions & 3 deletions lib/adapters/WKB.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@ function getMulti(&$mem, $type) {
// Get the number of items expected in this multi out of the first 4 bytes
$multi_length = unpack('L',fread($mem,4));

//@@TODO: create an EMPTY geometry instead of returning null
if (!$multi_length[1]) return NULL;

$components = array();
$i = 1;
while ($i <= $multi_length[1]) {
Expand Down
76 changes: 75 additions & 1 deletion lib/geometry/Collection.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,81 @@ public function isEmpty() {
}
}

public function numPoints() {
$num = 0;
foreach ($this->components as $component) {
$num += $component->numPoints();
}
return $num;
}

public function getPoints() {
$points = array();
foreach ($this->components as $component) {
$points = array_merge($points, $component->getPoints());
}
return $points;
}

public function equals($geometry) {
if ($this->geos()) {
return $this->geos()->equals($geometry->geos());
}

// To test for equality we check to make sure that there is a matching point
// in the other geometry for every point in this geometry.
// This is slightly more strict than the standard, which
// uses Within(A,B) = true and Within(B,A) = true
// @@TODO: Eventually we could fix this by using some sort of simplification
// method that strips redundant vertices (that are all in a row)

$this_points = $this->getPoints();
$other_points = $geometry->getPoints();

// First do a check to make sure they have the same number of vertices
if (count($this_points) != count($other_points)) {
return FALSE;
}

foreach ($this_points as $point) {
$found_match = FALSE;
foreach ($other_points as $key => $test_point) {
if ($point->equals($test_point)) {
$found_match = TRUE;
unset($other_points[$key]);
break;
}
}
if (!$found_match) {
return FALSE;
}
}

// All points match, return TRUE
return TRUE;
}

public function isSimple() {
if ($this->geos()) {
return $this->geos()->isSimple();
}

// A collection is simple if all it's components are simple
foreach ($this->components as $component) {
if (!$component->isSimple()) return FALSE;
}

return TRUE;
}

public function explode() {
$parts = array();
foreach ($this->components as $component) {
$parts = array_merge($parts, $component->explode());
}
return $parts;
}

// Not valid for this geometry type
// --------------------------------
public function x() { return NULL; }
Expand All @@ -203,7 +278,6 @@ public function startPoint() { return NULL; }
public function endPoint() { return NULL; }
public function isRing() { return NULL; }
public function isClosed() { return NULL; }
public function numPoints() { return NULL; }
public function pointN($n) { return NULL; }
public function exteriorRing() { return NULL; }
public function numInteriorRings() { return NULL; }
Expand Down
43 changes: 24 additions & 19 deletions lib/geometry/Geometry.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ abstract public function y();
abstract public function x();
abstract public function numGeometries();
abstract public function geometryN($n);
abstract public function startPoint();
abstract public function startPoint();
abstract public function endPoint();
abstract public function isRing(); // Mssing dependancy
abstract public function isClosed(); // Missing dependancy
Expand All @@ -29,12 +29,16 @@ abstract public function exteriorRing();
abstract public function numInteriorRings();
abstract public function interiorRingN($n);
abstract public function dimension();
abstract public function equals($geom);
abstract public function isEmpty();
abstract public function isSimple();

// Abtract: Non-Standard
// ---------------------
abstract public function getBBox();
abstract public function asArray();
abstract public function getPoints();
abstract public function explode();


// Public: Standard -- Common to all geometries
Expand Down Expand Up @@ -127,7 +131,7 @@ public function asText() {
return $this->out('wkt');
}

public function asBinary() {
public function asBinary() {
return $this->out('wkb');
}

Expand Down Expand Up @@ -159,22 +163,20 @@ public function pointOnSurface() {
}
}

public function equals($geometry) {
if ($this->geos()) {
return $this->geos()->equals($geometry->geos());
}
}

public function equalsExact($geometry) {
if ($this->geos()) {
return $this->geos()->equalsExact($geometry->geos());
}
}

public function relate($geometry) {
//@@TODO: Deal with second "pattern" parameter
public function relate($geometry, $pattern = NULL) {
if ($this->geos()) {
return $this->geos()->relate($geometry->geos());
if ($pattern) {
return $this->geos()->relate($geometry->geos(), $pattern);
}
else {
return $this->geos()->relate($geometry->geos());
}
}
}

Expand All @@ -183,12 +185,6 @@ public function checkValidity() {
return $this->geos()->checkValidity();
}
}

public function isSimple() {
if ($this->geos()) {
return $this->geos()->isSimple();
}
}

public function buffer($distance) {
if ($this->geos()) {
Expand Down Expand Up @@ -220,10 +216,19 @@ public function symDifference($geometry) {
}
}

// Can pass in a geometry or an array of geometries
public function union($geometry) {
//@@TODO: also does union cascade
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->union($geometry->geos()));
if (is_array($geometry)) {
$geom = $this->geos();
foreach ($geometry as $item) {
$geom = $geom->union($item->geos());
}
return geoPHP::geosToGeometry($geos);
}
else {
return geoPHP::geosToGeometry($this->geos()->union($geometry->geos()));
}
}
}

Expand Down
68 changes: 64 additions & 4 deletions lib/geometry/LineString.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,11 @@ public function endPoint() {
}

public function isClosed() {
//@@TODO: Need to complete equal() first;
#return ($this->startPoint->equal($this->endPoint()));
return ($this->startPoint()->equals($this->endPoint()));
}

public function isRing() {
//@@TODO: need to complete isSimple first
#return ($this->isClosed() && $this->isSimple());
return ($this->isClosed() && $this->isSimple());
}

public function numPoints() {
Expand All @@ -62,6 +60,68 @@ public function dimension() {
public function area() {
return 0;
}

public function explode() {
$parts = array();
$points = $this->getPoints();

foreach ($points as $i => $point) {
if (isset($points[$i+1])) {
$parts[] = new LineString(array($point, $points[$i+1]));
}
}
return $parts;
}

public function isSimple() {
if ($this->geos()) {
return $this->geos()->isSimple();
}

$segments = $this->explode();

foreach ($segments as $i => $segment) {
foreach ($segments as $j => $check_segment) {
if ($i != $j) {
if ($segment->lineSegmentIntersect($check_segment)) {
return FALSE;
}
}
}
}
return TRUE;
}

// Utility function to check if any line sigments intersect
// Derived from http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
private function lineSegmentIntersect($segment) {
$p0_x = $this->startPoint()->x();
$p0_y = $this->startPoint()->y();
$p1_x = $this->endPoint()->x();
$p1_y = $this->endPoint()->y();
$p2_x = $segment->startPoint()->x();
$p2_y = $segment->startPoint()->y();
$p3_x = $segment->endPoint()->x();
$p3_y = $segment->endPoint()->y();

$s1_x = $p1_x - $p0_x; $s1_y = $p1_y - $p0_y;
$s2_x = $p3_x - $p2_x; $s2_y = $p3_y - $p2_y;

$fps = (-$s2_x * $s1_y) + ($s1_x * $s2_y);
$fpt = (-$s2_x * $s1_y) + ($s1_x * $s2_y);

if ($fps == 0 || $fpt == 0) {
return FALSE;
}

$s = (-$s1_y * ($p0_x - $p2_x) + $s1_x * ($p0_y - $p2_y)) / $fps;
$t = ( $s2_x * ($p0_y - $p2_y) - $s2_y * ($p0_x - $p2_x)) / $fpt;

if ($s > 0 && $s < 1 && $t > 0 && $t < 1) {
// Collision detected
return TRUE;
}
return FALSE;
}
}

12 changes: 12 additions & 0 deletions lib/geometry/MultiPoint.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,17 @@
class MultiPoint extends Collection
{
protected $geom_type = 'MultiPoint';

public function numPoints() {
return $this->numGeometries();
}

public function isSimple() {
return TRUE;
}

// Not valid for this geometry type
// --------------------------------
public function explode() { return NULL; }
}

19 changes: 17 additions & 2 deletions lib/geometry/Point.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,22 @@ public function dimension() {
public function isEmpty() {
return FALSE;
}

public function numPoints() {
return 1;
}

public function getPoints() {
return array($this);
}

public function equals($geometry) {
return ($this->x() == $geometry->x() && $this->y() == $geometry->y());
}

public function isSimple() {
return TRUE;
}

// Not valid for this geometry type
public function numGeometries() { return NULL; }
Expand All @@ -121,12 +137,11 @@ public function startPoint() { return NULL; }
public function endPoint() { return NULL; }
public function isRing() { return NULL; }
public function isClosed() { return NULL; }
public function numPoints() { return NULL; }
public function pointN($n) { return NULL; }
public function exteriorRing() { return NULL; }
public function numInteriorRings() { return NULL; }
public function interiorRingN($n) { return NULL; }
public function pointOnSurface() { return NULL; }

public function explode() { return NULL; }
}

19 changes: 19 additions & 0 deletions lib/geometry/Polygon.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ public function dimension() {
return 2;
}

public function isSimple() {
if ($this->geos()) {
return $this->geos()->isSimple();
}

$segments = $this->explode();

foreach ($segments as $i => $segment) {
foreach ($segments as $j => $check_segment) {
if ($i != $j) {
if ($segment->lineSegmentIntersect($check_segment)) {
return FALSE;
}
}
}
}
return TRUE;
}

// Not valid for this geometry type
// --------------------------------
public function length() { return NULL; }
Expand Down

0 comments on commit be0ce05

Please sign in to comment.