1<?php 2 3namespace geoPHP\Geometry; 4 5use geoPHP\geoPHP; 6 7/** 8 * MultiGeometry is an abstract collection of geometries 9 * 10 * @package geoPHP\Geometry 11 */ 12abstract class MultiGeometry extends Collection 13{ 14 15 public function __construct($components = [], $allowEmptyComponents = true, $allowedComponentType = Geometry::class) 16 { 17 parent::__construct($components, $allowEmptyComponents, $allowedComponentType); 18 } 19 20 /** 21 * @return bool|null 22 */ 23 public function isSimple() 24 { 25 if ($this->getGeos()) { 26 // @codeCoverageIgnoreStart 27 /** @noinspection PhpUndefinedMethodInspection */ 28 return $this->getGeos()->isSimple(); 29 // @codeCoverageIgnoreEnd 30 } 31 32 // A collection is simple if all it's components are simple 33 foreach ($this->components as $component) { 34 if (!$component->isSimple()) { 35 return false; 36 } 37 } 38 39 return true; 40 } 41 42 // By default, the boundary of a collection is the boundary of it's components 43 public function boundary() 44 { 45 if ($this->isEmpty()) { 46 return new LineString(); 47 } 48 49 if ($this->getGeos()) { 50 // @codeCoverageIgnoreStart 51 /** @noinspection PhpUndefinedMethodInspection */ 52 return $this->getGeos()->boundary(); 53 // @codeCoverageIgnoreEnd 54 } 55 56 $componentsBoundaries = []; 57 foreach ($this->components as $component) { 58 $componentsBoundaries[] = $component->boundary(); 59 } 60 return geoPHP::buildGeometry($componentsBoundaries); 61 } 62 63 public function area() 64 { 65 if ($this->getGeos()) { 66 // @codeCoverageIgnoreStart 67 /** @noinspection PhpUndefinedMethodInspection */ 68 return $this->getGeos()->area(); 69 // @codeCoverageIgnoreEnd 70 } 71 72 $area = 0; 73 foreach ($this->components as $component) { 74 $area += $component->area(); 75 } 76 return $area; 77 } 78 79 /** 80 * Returns the length of this Collection in its associated spatial reference. 81 * Eg. if Geometry is in geographical coordinate system it returns the length in degrees 82 * @return float|int 83 */ 84 public function length() 85 { 86 $length = 0; 87 foreach ($this->components as $component) { 88 $length += $component->length(); 89 } 90 return $length; 91 } 92 93 public function length3D() 94 { 95 $length = 0; 96 foreach ($this->components as $component) { 97 $length += $component->length3D(); 98 } 99 return $length; 100 } 101 102 /** 103 * Returns the degree based Geometry' length in meters 104 * @param float|null $radius Default is the semi-major axis of WGS84 105 * @return int the length in meters 106 */ 107 public function greatCircleLength($radius = geoPHP::EARTH_WGS84_SEMI_MAJOR_AXIS) 108 { 109 $length = 0; 110 foreach ($this->components as $component) { 111 $length += $component->greatCircleLength($radius); 112 } 113 return $length; 114 } 115 116 public function haversineLength() 117 { 118 $length = 0; 119 foreach ($this->components as $component) { 120 $length += $component->haversineLength(); 121 } 122 return $length; 123 } 124 125 public function minimumZ() 126 { 127 $min = PHP_INT_MAX; 128 foreach ($this->components as $component) { 129 $componentMin = $component->minimumZ(); 130 if ($componentMin < $min) { 131 $min = $componentMin; 132 } 133 } 134 return $min < PHP_INT_MAX ? $min : null; 135 } 136 137 public function maximumZ() 138 { 139 $max = ~PHP_INT_MAX; 140 foreach ($this->components as $component) { 141 $componentMax = $component->maximumZ(); 142 if ($componentMax > $max) { 143 $max = $componentMax; 144 } 145 } 146 return $max > ~PHP_INT_MAX ? $max : null; 147 } 148 149 public function zDifference() 150 { 151 $startPoint = $this->startPoint(); 152 $endPoint = $this->endPoint(); 153 if ($startPoint && $endPoint && $startPoint->hasZ() && $endPoint->hasZ()) { 154 return abs($startPoint->z() - $endPoint->z()); 155 } else { 156 return null; 157 } 158 } 159 160 public function elevationGain($verticalTolerance = 0) 161 { 162 $gain = null; 163 foreach ($this->components as $component) { 164 $gain += $component->elevationGain($verticalTolerance); 165 } 166 return $gain; 167 } 168 169 public function elevationLoss($verticalTolerance = 0) 170 { 171 $loss = null; 172 foreach ($this->components as $component) { 173 $loss += $component->elevationLoss($verticalTolerance); 174 } 175 return $loss; 176 } 177 178 public function minimumM() 179 { 180 $min = PHP_INT_MAX; 181 foreach ($this->components as $component) { 182 $componentMin = $component->minimumM(); 183 if ($componentMin < $min) { 184 $min = $componentMin; 185 } 186 } 187 return $min < PHP_INT_MAX ? $min : null; 188 } 189 190 public function maximumM() 191 { 192 $max = ~PHP_INT_MAX; 193 foreach ($this->components as $component) { 194 $componentMax = $component->maximumM(); 195 if ($componentMax > $max) { 196 $max = $componentMax; 197 } 198 } 199 return $max > ~PHP_INT_MAX ? $max : null; 200 } 201 202 203 204 public function startPoint() 205 { 206 return null; 207 } 208 209 public function endPoint() 210 { 211 return null; 212 } 213 214 public function isRing() 215 { 216 return null; 217 } 218 219 public function isClosed() 220 { 221 return null; 222 } 223 224 public function pointN($n) 225 { 226 return null; 227 } 228 229 public function exteriorRing() 230 { 231 return null; 232 } 233 234 public function numInteriorRings() 235 { 236 return null; 237 } 238 239 public function interiorRingN($n) 240 { 241 return null; 242 } 243} 244