| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- <?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; }
-
- }
|