Polygon.class.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. /**
  3. * Polygon: A polygon is a plane figure that is bounded by a closed path,
  4. * composed of a finite sequence of straight line segments
  5. */
  6. class Polygon extends Collection
  7. {
  8. protected $geom_type = 'Polygon';
  9. public function area($exterior_only = FALSE, $signed = FALSE) {
  10. if ($this->isEmpty()) return 0;
  11. if ($this->geos() && $exterior_only == FALSE) {
  12. return $this->geos()->area();
  13. }
  14. $exterior_ring = $this->components[0];
  15. $pts = $exterior_ring->getComponents();
  16. $c = count($pts);
  17. if((int)$c == '0') return NULL;
  18. $a = '0';
  19. foreach($pts as $k => $p){
  20. $j = ($k + 1) % $c;
  21. $a = $a + ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX());
  22. }
  23. if ($signed) $area = ($a / 2);
  24. else $area = abs(($a / 2));
  25. if ($exterior_only == TRUE) {
  26. return $area;
  27. }
  28. foreach ($this->components as $delta => $component) {
  29. if ($delta != 0) {
  30. $inner_poly = new Polygon(array($component));
  31. $area -= $inner_poly->area();
  32. }
  33. }
  34. return $area;
  35. }
  36. public function centroid() {
  37. if ($this->isEmpty()) return NULL;
  38. if ($this->geos()) {
  39. return geoPHP::geosToGeometry($this->geos()->centroid());
  40. }
  41. $exterior_ring = $this->components[0];
  42. $pts = $exterior_ring->getComponents();
  43. $c = count($pts);
  44. if((int)$c == '0') return NULL;
  45. $cn = array('x' => '0', 'y' => '0');
  46. $a = $this->area(TRUE, TRUE);
  47. // If this is a polygon with no area. Just return the first point.
  48. if ($a == 0) {
  49. return $this->exteriorRing()->pointN(1);
  50. }
  51. foreach($pts as $k => $p){
  52. $j = ($k + 1) % $c;
  53. $P = ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX());
  54. $cn['x'] = $cn['x'] + ($p->getX() + $pts[$j]->getX()) * $P;
  55. $cn['y'] = $cn['y'] + ($p->getY() + $pts[$j]->getY()) * $P;
  56. }
  57. $cn['x'] = $cn['x'] / ( 6 * $a);
  58. $cn['y'] = $cn['y'] / ( 6 * $a);
  59. $centroid = new Point($cn['x'], $cn['y']);
  60. return $centroid;
  61. }
  62. /**
  63. * Find the outermost point from the centroid
  64. *
  65. * @returns Point The outermost point
  66. */
  67. public function outermostPoint() {
  68. $centroid = $this->getCentroid();
  69. $max = array('length' => 0, 'point' => null);
  70. foreach($this->getPoints() as $point) {
  71. $lineString = new LineString(array($centroid, $point));
  72. if($lineString->length() > $max['length']) {
  73. $max['length'] = $lineString->length();
  74. $max['point'] = $point;
  75. }
  76. }
  77. return $max['point'];
  78. }
  79. public function exteriorRing() {
  80. if ($this->isEmpty()) return new LineString();
  81. return $this->components[0];
  82. }
  83. public function numInteriorRings() {
  84. if ($this->isEmpty()) return 0;
  85. return $this->numGeometries()-1;
  86. }
  87. public function interiorRingN($n) {
  88. return $this->geometryN($n+1);
  89. }
  90. public function dimension() {
  91. if ($this->isEmpty()) return 0;
  92. return 2;
  93. }
  94. public function isSimple() {
  95. if ($this->geos()) {
  96. return $this->geos()->isSimple();
  97. }
  98. $segments = $this->explode();
  99. foreach ($segments as $i => $segment) {
  100. foreach ($segments as $j => $check_segment) {
  101. if ($i != $j) {
  102. if ($segment->lineSegmentIntersect($check_segment)) {
  103. return FALSE;
  104. }
  105. }
  106. }
  107. }
  108. return TRUE;
  109. }
  110. // Not valid for this geometry type
  111. // --------------------------------
  112. public function length() { return NULL; }
  113. }