1
0
Fork 0
forked from lino/radar-wp

Initial import.

This commit is contained in:
ekes 2015-02-24 16:25:12 +01:00
commit 86383280c9
428 changed files with 68738 additions and 0 deletions

View file

@ -0,0 +1,294 @@
<?php
/**
* Collection: Abstract class for compound geometries
*
* A geometry is a collection if it is made up of other
* component geometries. Therefore everything but a Point
* is a Collection. For example a LingString is a collection
* of Points. A Polygon is a collection of LineStrings etc.
*/
abstract class Collection extends Geometry
{
public $components = array();
/**
* Constructor: Checks and sets component geometries
*
* @param array $components array of geometries
*/
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 a collection with non-geometries");
}
}
}
/**
* Returns Collection component geometries
*
* @return array
*/
public function getComponents() {
return $this->components;
}
public function centroid() {
if ($this->isEmpty()) return NULL;
if ($this->geos()) {
$geos_centroid = $this->geos()->centroid();
if ($geos_centroid->typeName() == 'Point') {
return geoPHP::geosToGeometry($this->geos()->centroid());
}
}
// As a rough estimate, we say that the centroid of a colletion is the centroid of it's envelope
// @@TODO: Make this the centroid of the convexHull
// Note: Outside of polygons, geometryCollections and the trivial case of points, there is no standard on what a "centroid" is
$centroid = $this->envelope()->centroid();
return $centroid;
}
public function getBBox() {
if ($this->isEmpty()) return NULL;
if ($this->geos()) {
$envelope = $this->geos()->envelope();
if ($envelope->typeName() == 'Point') {
return geoPHP::geosToGeometry($envelope)->getBBOX();
}
$geos_ring = $envelope->exteriorRing();
return array(
'maxy' => $geos_ring->pointN(3)->getY(),
'miny' => $geos_ring->pointN(1)->getY(),
'maxx' => $geos_ring->pointN(1)->getX(),
'minx' => $geos_ring->pointN(3)->getX(),
);
}
// Go through each component and get the max and min x and y
$i = 0;
foreach ($this->components as $component) {
$component_bbox = $component->getBBox();
// On the first run through, set the bbox to the component bbox
if ($i == 0) {
$maxx = $component_bbox['maxx'];
$maxy = $component_bbox['maxy'];
$minx = $component_bbox['minx'];
$miny = $component_bbox['miny'];
}
// Do a check and replace on each boundary, slowly growing the bbox
$maxx = $component_bbox['maxx'] > $maxx ? $component_bbox['maxx'] : $maxx;
$maxy = $component_bbox['maxy'] > $maxy ? $component_bbox['maxy'] : $maxy;
$minx = $component_bbox['minx'] < $minx ? $component_bbox['minx'] : $minx;
$miny = $component_bbox['miny'] < $miny ? $component_bbox['miny'] : $miny;
$i++;
}
return array(
'maxy' => $maxy,
'miny' => $miny,
'maxx' => $maxx,
'minx' => $minx,
);
}
public function asArray() {
$array = array();
foreach ($this->components as $component) {
$array[] = $component->asArray();
}
return $array;
}
public function area() {
if ($this->geos()) {
return $this->geos()->area();
}
$area = 0;
foreach ($this->components as $component) {
$area += $component->area();
}
return $area;
}
// By default, the boundary of a collection is the boundary of it's components
public function boundary() {
if ($this->isEmpty()) return new LineString();
if ($this->geos()) {
return $this->geos()->boundary();
}
$components_boundaries = array();
foreach ($this->components as $component) {
$components_boundaries[] = $component->boundary();
}
return geoPHP::geometryReduce($components_boundaries);
}
public function numGeometries() {
return count($this->components);
}
// Note that the standard is 1 based indexing
public function geometryN($n) {
$n = intval($n);
if (array_key_exists($n-1, $this->components)) {
return $this->components[$n-1];
}
else {
return NULL;
}
}
public function length() {
$length = 0;
foreach ($this->components as $delta => $component) {
$length += $component->length();
}
return $length;
}
public function greatCircleLength($radius = 6378137) {
$length = 0;
foreach ($this->components as $component) {
$length += $component->greatCircleLength($radius);
}
return $length;
}
public function haversineLength() {
$length = 0;
foreach ($this->components as $component) {
$length += $component->haversineLength();
}
return $length;
}
public function dimension() {
$dimension = 0;
foreach ($this->components as $component) {
if ($component->dimension() > $dimension) {
$dimension = $component->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;
}
}
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; }
public function y() { return NULL; }
public function startPoint() { return NULL; }
public function endPoint() { return NULL; }
public function isRing() { return NULL; }
public function isClosed() { 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; }
}

View file

@ -0,0 +1,347 @@
<?php
/**
* Geometry abstract class
*/
abstract class Geometry
{
private $geos = NULL;
protected $srid = NULL;
protected $geom_type;
// Abtract: Standard
// -----------------
abstract public function area();
abstract public function boundary();
abstract public function centroid();
abstract public function length();
abstract public function y();
abstract public function x();
abstract public function numGeometries();
abstract public function geometryN($n);
abstract public function startPoint();
abstract public function endPoint();
abstract public function isRing(); // Mssing dependancy
abstract public function isClosed(); // Missing dependancy
abstract public function numPoints();
abstract public function pointN($n);
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();
abstract public function greatCircleLength(); //meters
abstract public function haversineLength(); //degrees
// Public: Standard -- Common to all geometries
// --------------------------------------------
public function SRID() {
return $this->srid;
}
public function setSRID($srid) {
if ($this->geos()) {
$this->geos()->setSRID($srid);
}
$this->srid = $srid;
}
public function envelope() {
if ($this->isEmpty()) return new Polygon();
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->envelope());
}
$bbox = $this->getBBox();
$points = array (
new Point($bbox['maxx'],$bbox['miny']),
new Point($bbox['maxx'],$bbox['maxy']),
new Point($bbox['minx'],$bbox['maxy']),
new Point($bbox['minx'],$bbox['miny']),
new Point($bbox['maxx'],$bbox['miny']),
);
$outer_boundary = new LineString($points);
return new Polygon(array($outer_boundary));
}
public function geometryType() {
return $this->geom_type;
}
// Public: Non-Standard -- Common to all geometries
// ------------------------------------------------
// $this->out($format, $other_args);
public function out() {
$args = func_get_args();
$format = array_shift($args);
$type_map = geoPHP::getAdapterMap();
$processor_type = $type_map[$format];
$processor = new $processor_type();
array_unshift($args, $this);
$result = call_user_func_array(array($processor, 'write'), $args);
return $result;
}
// Public: Aliases
// ---------------
public function getCentroid() {
return $this->centroid();
}
public function getArea() {
return $this->area();
}
public function getX() {
return $this->x();
}
public function getY() {
return $this->y();
}
public function getGeos() {
return $this->geos();
}
public function getGeomType() {
return $this->geometryType();
}
public function getSRID() {
return $this->SRID();
}
public function asText() {
return $this->out('wkt');
}
public function asBinary() {
return $this->out('wkb');
}
// Public: GEOS Only Functions
// ---------------------------
public function geos() {
// If it's already been set, just return it
if ($this->geos && geoPHP::geosInstalled()) {
return $this->geos;
}
// It hasn't been set yet, generate it
if (geoPHP::geosInstalled()) {
$reader = new GEOSWKBReader();
$this->geos = $reader->readHEX($this->out('wkb',TRUE));
}
else {
$this->geos = FALSE;
}
return $this->geos;
}
public function setGeos($geos) {
$this->geos = $geos;
}
public function pointOnSurface() {
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->pointOnSurface());
}
}
public function equalsExact(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->equalsExact($geometry->geos());
}
}
public function relate(Geometry $geometry, $pattern = NULL) {
if ($this->geos()) {
if ($pattern) {
return $this->geos()->relate($geometry->geos(), $pattern);
}
else {
return $this->geos()->relate($geometry->geos());
}
}
}
public function checkValidity() {
if ($this->geos()) {
return $this->geos()->checkValidity();
}
}
public function buffer($distance) {
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->buffer($distance));
}
}
public function intersection(Geometry $geometry) {
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->intersection($geometry->geos()));
}
}
public function convexHull() {
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->convexHull());
}
}
public function difference(Geometry $geometry) {
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->difference($geometry->geos()));
}
}
public function symDifference(Geometry $geometry) {
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->symDifference($geometry->geos()));
}
}
// Can pass in a geometry or an array of geometries
public function union(Geometry $geometry) {
if ($this->geos()) {
if (is_array($geometry)) {
$geom = $this->geos();
foreach ($geometry as $item) {
$geom = $geom->union($item->geos());
}
return geoPHP::geosToGeometry($geom);
}
else {
return geoPHP::geosToGeometry($this->geos()->union($geometry->geos()));
}
}
}
public function simplify($tolerance, $preserveTopology = FALSE) {
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->simplify($tolerance, $preserveTopology));
}
}
public function disjoint(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->disjoint($geometry->geos());
}
}
public function touches(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->touches($geometry->geos());
}
}
public function intersects(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->intersects($geometry->geos());
}
}
public function crosses(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->crosses($geometry->geos());
}
}
public function within(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->within($geometry->geos());
}
}
public function contains(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->contains($geometry->geos());
}
}
public function overlaps(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->overlaps($geometry->geos());
}
}
public function covers(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->covers($geometry->geos());
}
}
public function coveredBy(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->coveredBy($geometry->geos());
}
}
public function distance(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->distance($geometry->geos());
}
}
public function hausdorffDistance(Geometry $geometry) {
if ($this->geos()) {
return $this->geos()->hausdorffDistance($geometry->geos());
}
}
public function project(Geometry $point, $normalized = NULL) {
if ($this->geos()) {
return $this->geos()->project($point->geos(), $normalized);
}
}
// Public - Placeholders
// ---------------------
public function hasZ() {
// geoPHP does not support Z values at the moment
return FALSE;
}
public function is3D() {
// geoPHP does not support 3D geometries at the moment
return FALSE;
}
public function isMeasured() {
// geoPHP does not yet support M values
return FALSE;
}
public function coordinateDimension() {
// geoPHP only supports 2-dimensional space
return 2;
}
public function z() {
// geoPHP only supports 2-dimensional space
return NULL;
}
public function m() {
// geoPHP only supports 2-dimensional space
return NULL;
}
}

View file

@ -0,0 +1,29 @@
<?php
/**
* GeometryCollection: A heterogenous collection of geometries
*/
class GeometryCollection extends Collection
{
protected $geom_type = 'GeometryCollection';
// We need to override asArray. Because geometryCollections are heterogeneous
// we need to specify which type of geometries they contain. We need to do this
// because, for example, there would be no way to tell the difference between a
// MultiPoint or a LineString, since they share the same structure (collection
// of points). So we need to call out the type explicitly.
public function asArray() {
$array = array();
foreach ($this->components as $component) {
$array[] = array(
'type' => $component->geometryType(),
'components' => $component->asArray(),
);
}
return $array;
}
// Not valid for this geomettry
public function boundary() { return NULL; }
public function isSimple() { return NULL; }
}

View file

@ -0,0 +1,190 @@
<?php
/**
* LineString. A collection of Points representing a line.
* A line can have more than one segment.
*/
class LineString extends Collection
{
protected $geom_type = 'LineString';
/**
* Constructor
*
* @param array $points An array of at least two points with
* which to build the LineString
*/
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
parent::__construct($points);
}
// The boundary of a linestring is itself
public function boundary() {
return $this;
}
public function startPoint() {
return $this->pointN(1);
}
public function endPoint() {
$last_n = $this->numPoints();
return $this->pointN($last_n);
}
public function isClosed() {
return ($this->startPoint()->equals($this->endPoint()));
}
public function isRing() {
return ($this->isClosed() && $this->isSimple());
}
public function numPoints() {
return $this->numGeometries();
}
public function pointN($n) {
return $this->geometryN($n);
}
public function dimension() {
if ($this->isEmpty()) return 0;
return 1;
}
public function area() {
return 0;
}
public function length() {
if ($this->geos()) {
return $this->geos()->length();
}
$length = 0;
foreach ($this->getPoints() as $delta => $point) {
$previous_point = $this->geometryN($delta);
if ($previous_point) {
$length += sqrt(pow(($previous_point->getX() - $point->getX()), 2) + pow(($previous_point->getY()- $point->getY()), 2));
}
}
return $length;
}
public function greatCircleLength($radius = 6378137) {
$length = 0;
$points = $this->getPoints();
for($i=0; $i<$this->numPoints()-1; $i++) {
$point = $points[$i];
$next_point = $points[$i+1];
if (!is_object($next_point)) {continue;}
// Great circle method
$lat1 = deg2rad($point->getY());
$lat2 = deg2rad($next_point->getY());
$lon1 = deg2rad($point->getX());
$lon2 = deg2rad($next_point->getX());
$dlon = $lon2 - $lon1;
$length +=
$radius *
atan2(
sqrt(
pow(cos($lat2) * sin($dlon), 2) +
pow(cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dlon), 2)
)
,
sin($lat1) * sin($lat2) +
cos($lat1) * cos($lat2) * cos($dlon)
);
}
// Returns length in meters.
return $length;
}
public function haversineLength() {
$degrees = 0;
$points = $this->getPoints();
for($i=0; $i<$this->numPoints()-1; $i++) {
$point = $points[$i];
$next_point = $points[$i+1];
if (!is_object($next_point)) {continue;}
$degree = rad2deg(
acos(
sin(deg2rad($point->getY())) * sin(deg2rad($next_point->getY())) +
cos(deg2rad($point->getY())) * cos(deg2rad($next_point->getY())) *
cos(deg2rad(abs($point->getX() - $next_point->getX())))
)
);
$degrees += $degree;
}
// Returns degrees
return $degrees;
}
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
public 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;
}
}

View file

@ -0,0 +1,20 @@
<?php
/**
* MultiLineString: A collection of LineStrings
*/
class MultiLineString extends Collection
{
protected $geom_type = 'MultiLineString';
// MultiLineString is closed if all it's components are closed
public function isClosed() {
foreach ($this->components as $line) {
if (!$line->isClosed()) {
return FALSE;
}
}
return TRUE;
}
}

View file

@ -0,0 +1,21 @@
<?php
/**
* MultiPoint: A collection Points
*/
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; }
}

View file

@ -0,0 +1,8 @@
<?php
/**
* MultiPolygon: A collection of Polygons
*/
class MultiPolygon extends Collection
{
protected $geom_type = 'MultiPolygon';
}

View file

@ -0,0 +1,179 @@
<?php
/**
* Point: The most basic geometry type. All other geometries
* are built out of Points.
*/
class Point extends Geometry
{
public $coords = array(2);
protected $geom_type = 'Point';
protected $dimension = 2;
/**
* Constructor
*
* @param numeric $x The x coordinate (or longitude)
* @param numeric $y The y coordinate (or latitude)
* @param numeric $z The z coordinate (or altitude) - optional
*/
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");
}
// Check to see if this is a 3D point
if ($z !== NULL) {
if (!is_numeric($z)) {
throw new Exception("Cannot construct Point. z should be numeric");
}
$this->dimension = 3;
}
// Convert to floatval in case they are passed in as a string or integer etc.
$x = floatval($x);
$y = floatval($y);
$z = floatval($z);
// Add poitional elements
if ($this->dimension == 2) {
$this->coords = array($x, $y);
}
if ($this->dimension == 3) {
$this->coords = array($x, $y, $z);
}
}
/**
* Get X (longitude) coordinate
*
* @return float The X coordinate
*/
public function x() {
return $this->coords[0];
}
/**
* Returns Y (latitude) coordinate
*
* @return float The Y coordinate
*/
public function y() {
return $this->coords[1];
}
/**
* Returns Z (altitude) coordinate
*
* @return float The Z coordinate or NULL is not a 3D point
*/
public function z() {
if ($this->dimension == 3) {
return $this->coords[2];
}
else return NULL;
}
// A point's centroid is itself
public function centroid() {
return $this;
}
public function getBBox() {
return array(
'maxy' => $this->getY(),
'miny' => $this->getY(),
'maxx' => $this->getX(),
'minx' => $this->getX(),
);
}
public function asArray($assoc = FALSE) {
return $this->coords;
}
public function area() {
return 0;
}
public function length() {
return 0;
}
public function greatCircleLength() {
return 0;
}
public function haversineLength() {
return 0;
}
// The boundary of a point is itself
public function boundary() {
return $this;
}
public function dimension() {
return 0;
}
public function isEmpty() {
if ($this->dimension == 0) {
return TRUE;
}
else {
return FALSE;
}
}
public function numPoints() {
return 1;
}
public function getPoints() {
return array($this);
}
public function equals($geometry) {
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() {
return TRUE;
}
// Not valid for this geometry type
public function numGeometries() { return NULL; }
public function geometryN($n) { return NULL; }
public function startPoint() { return NULL; }
public function endPoint() { return NULL; }
public function isRing() { return NULL; }
public function isClosed() { 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; }
}

View file

@ -0,0 +1,215 @@
<?php
/**
* Polygon: A polygon is a plane figure that is bounded by a closed path,
* composed of a finite sequence of straight line segments
*/
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;
if ($this->geos() && $exterior_only == FALSE) {
return $this->geos()->area();
}
$exterior_ring = $this->components[0];
$pts = $exterior_ring->getComponents();
$c = count($pts);
if((int)$c == '0') return NULL;
$a = '0';
foreach($pts as $k => $p){
$j = ($k + 1) % $c;
$a = $a + ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX());
}
if ($signed) $area = ($a / 2);
else $area = abs(($a / 2));
if ($exterior_only == TRUE) {
return $area;
}
foreach ($this->components as $delta => $component) {
if ($delta != 0) {
$inner_poly = new Polygon(array($component));
$area -= $inner_poly->area();
}
}
return $area;
}
public function centroid() {
if ($this->isEmpty()) return NULL;
if ($this->geos()) {
return geoPHP::geosToGeometry($this->geos()->centroid());
}
$exterior_ring = $this->components[0];
$pts = $exterior_ring->getComponents();
$c = count($pts);
if((int)$c == '0') return NULL;
$cn = array('x' => '0', 'y' => '0');
$a = $this->area(TRUE, TRUE);
// If this is a polygon with no area. Just return the first point.
if ($a == 0) {
return $this->exteriorRing()->pointN(1);
}
foreach($pts as $k => $p){
$j = ($k + 1) % $c;
$P = ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX());
$cn['x'] = $cn['x'] + ($p->getX() + $pts[$j]->getX()) * $P;
$cn['y'] = $cn['y'] + ($p->getY() + $pts[$j]->getY()) * $P;
}
$cn['x'] = $cn['x'] / ( 6 * $a);
$cn['y'] = $cn['y'] / ( 6 * $a);
$centroid = new Point($cn['x'], $cn['y']);
return $centroid;
}
/**
* Find the outermost point from the centroid
*
* @returns Point The outermost point
*/
public function outermostPoint() {
$centroid = $this->getCentroid();
$max = array('length' => 0, 'point' => null);
foreach($this->getPoints() as $point) {
$lineString = new LineString(array($centroid, $point));
if($lineString->length() > $max['length']) {
$max['length'] = $lineString->length();
$max['point'] = $point;
}
}
return $max['point'];
}
public function exteriorRing() {
if ($this->isEmpty()) return new LineString();
return $this->components[0];
}
public function numInteriorRings() {
if ($this->isEmpty()) return 0;
return $this->numGeometries()-1;
}
public function interiorRingN($n) {
return $this->geometryN($n+1);
}
public function dimension() {
if ($this->isEmpty()) return 0;
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;
}
/**
* For a given point, determine whether it's bounded by the given polygon.
* Adapted from http://www.assemblysys.com/dataServices/php_pointinpolygon.php
* @see http://en.wikipedia.org/wiki/Point%5Fin%5Fpolygon
*
* @param Point $point
* @param boolean $pointOnBoundary - whether a boundary should be considered "in" or not
* @param boolean $pointOnVertex - whether a vertex should be considered "in" or not
* @return boolean
*/
public function pointInPolygon($point, $pointOnBoundary = true, $pointOnVertex = true) {
$vertices = $this->getPoints();
// Check if the point sits exactly on a vertex
if ($this->pointOnVertex($point, $vertices)) {
return $pointOnVertex ? TRUE : FALSE;
}
// Check if the point is inside the polygon or on the boundary
$intersections = 0;
$vertices_count = count($vertices);
for ($i=1; $i < $vertices_count; $i++) {
$vertex1 = $vertices[$i-1];
$vertex2 = $vertices[$i];
if ($vertex1->y() == $vertex2->y()
&& $vertex1->y() == $point->y()
&& $point->x() > min($vertex1->x(), $vertex2->x())
&& $point->x() < max($vertex1->x(), $vertex2->x())) {
// Check if point is on an horizontal polygon boundary
return $pointOnBoundary ? TRUE : FALSE;
}
if ($point->y() > min($vertex1->y(), $vertex2->y())
&& $point->y() <= max($vertex1->y(), $vertex2->y())
&& $point->x() <= max($vertex1->x(), $vertex2->x())
&& $vertex1->y() != $vertex2->y()) {
$xinters =
($point->y() - $vertex1->y()) * ($vertex2->x() - $vertex1->x())
/ ($vertex2->y() - $vertex1->y())
+ $vertex1->x();
if ($xinters == $point->x()) {
// Check if point is on the polygon boundary (other than horizontal)
return $pointOnBoundary ? TRUE : FALSE;
}
if ($vertex1->x() == $vertex2->x() || $point->x() <= $xinters) {
$intersections++;
}
}
}
// If the number of edges we passed through is even, then it's in the polygon.
if ($intersections % 2 != 0) {
return TRUE;
}
else {
return FALSE;
}
}
public function pointOnVertex($point) {
foreach($this->getPoints() as $vertex) {
if ($point->equals($vertex)) {
return true;
}
}
}
// Not valid for this geometry type
// --------------------------------
public function length() { return NULL; }
}