```/* <![CDATA[ */
function get_sym_list(){return [["Variable","xv",[["components",13]]],["Class","xc",[["Collection",11]]],["Function","xf",[["__construct",20],["area",134],["asArray",126],["boundary",147],["centroid",61],["dimension",200],["endPoint",303],["equals",239],["explode",290],["exteriorRing",307],["geometryN",166],["getBBox",79],["getComponents",39],["getPoints",231],["greatCircleLength",184],["haversineLength",192],["interiorRingN",309],["invertxy",52],["isClosed",305],["isEmpty",211],["isRing",304],["isSimple",277],["length",176],["numGeometries",161],["numInteriorRings",308],["numPoints",223],["pointN",306],["pointOnSurface",310],["startPoint",302],["x",300],["y",301]]]];} /* ]]> */1<?php
2
3/**
4 * Collection: Abstract class for compound geometries
5 *
6 * A geometry is a collection if it is made up of other
7 * component geometries. Therefore everything but a Point
8 * is a Collection. For example a LingString is a collection
9 * of Points. A Polygon is a collection of LineStrings etc.
10 */
11abstract class Collection extends Geometry
12{
13  public \$components = array();
14
15  /**
16   * Constructor: Checks and sets component geometries
17   *
18   * @param array \$components array of geometries
19   */
20  public function __construct(\$components = array()) {
21    if (!is_array(\$components)) {
22      throw new Exception("Component geometries must be passed as an array");
23    }
24    foreach (\$components as \$component) {
25      if (\$component instanceof Geometry) {
26        \$this->components[] = \$component;
27      }
28      else {
29        throw new Exception("Cannot create a collection with non-geometries");
30      }
31    }
32  }
33
34  /**
35   * Returns Collection component geometries
36   *
37   * @return array
38   */
39  public function getComponents() {
40    return \$this->components;
41  }
42
43  /*
44   * Author : Adam Cherti
45   *
46   * inverts x and y coordinates
47   * Useful for old data still using lng lat
48   *
49   * @return void
50   *
51   * */
52  public function invertxy()
53  {
54	for(\$i=0;\$i<count(\$this->components);\$i++)
55	{
56		if( method_exists(\$this->components[\$i], 'invertxy' ) )
57			\$this->components[\$i]->invertxy();
58	}
59  }
60
61  public function centroid() {
62    if (\$this->isEmpty()) return NULL;
63
64    if (\$this->geos()) {
65      \$geos_centroid = \$this->geos()->centroid();
66      if (\$geos_centroid->typeName() == 'Point') {
67        return geoPHP::geosToGeometry(\$this->geos()->centroid());
68      }
69    }
70
71    // As a rough estimate, we say that the centroid of a colletion is the centroid of it's envelope
72    // @@TODO: Make this the centroid of the convexHull
73    // Note: Outside of polygons, geometryCollections and the trivial case of points, there is no standard on what a "centroid" is
74    \$centroid = \$this->envelope()->centroid();
75
76    return \$centroid;
77  }
78
79  public function getBBox() {
80    if (\$this->isEmpty()) return NULL;
81
82    if (\$this->geos()) {
83      \$envelope = \$this->geos()->envelope();
84      if (\$envelope->typeName() == 'Point') {
85        return geoPHP::geosToGeometry(\$envelope)->getBBOX();
86      }
87
88      \$geos_ring = \$envelope->exteriorRing();
89      return array(
90        'maxy' => \$geos_ring->pointN(3)->getY(),
91        'miny' => \$geos_ring->pointN(1)->getY(),
92        'maxx' => \$geos_ring->pointN(1)->getX(),
93        'minx' => \$geos_ring->pointN(3)->getX(),
94      );
95    }
96
97    // Go through each component and get the max and min x and y
98    \$i = 0;
99    foreach (\$this->components as \$component) {
100      \$component_bbox = \$component->getBBox();
101
102      // On the first run through, set the bbox to the component bbox
103      if (\$i == 0) {
104        \$maxx = \$component_bbox['maxx'];
105        \$maxy = \$component_bbox['maxy'];
106        \$minx = \$component_bbox['minx'];
107        \$miny = \$component_bbox['miny'];
108      }
109
110      // Do a check and replace on each boundary, slowly growing the bbox
111      \$maxx = \$component_bbox['maxx'] > \$maxx ? \$component_bbox['maxx'] : \$maxx;
112      \$maxy = \$component_bbox['maxy'] > \$maxy ? \$component_bbox['maxy'] : \$maxy;
113      \$minx = \$component_bbox['minx'] < \$minx ? \$component_bbox['minx'] : \$minx;
114      \$miny = \$component_bbox['miny'] < \$miny ? \$component_bbox['miny'] : \$miny;
115      \$i++;
116    }
117
118    return array(
119      'maxy' => \$maxy,
120      'miny' => \$miny,
121      'maxx' => \$maxx,
122      'minx' => \$minx,
123    );
124  }
125
126  public function asArray() {
127    \$array = array();
128    foreach (\$this->components as \$component) {
129      \$array[] = \$component->asArray();
130    }
131    return \$array;
132  }
133
134  public function area() {
135    if (\$this->geos()) {
136      return \$this->geos()->area();
137    }
138
139    \$area = 0;
140    foreach (\$this->components as \$component) {
141      \$area += \$component->area();
142    }
143    return \$area;
144  }
145
146  // By default, the boundary of a collection is the boundary of it's components
147  public function boundary() {
148    if (\$this->isEmpty()) return new LineString();
149
150    if (\$this->geos()) {
151      return \$this->geos()->boundary();
152    }
153
154    \$components_boundaries = array();
155    foreach (\$this->components as \$component) {
156      \$components_boundaries[] = \$component->boundary();
157    }
158    return geoPHP::geometryReduce(\$components_boundaries);
159  }
160
161  public function numGeometries() {
162    return count(\$this->components);
163  }
164
165  // Note that the standard is 1 based indexing
166  public function geometryN(\$n) {
167    \$n = intval(\$n);
168    if (array_key_exists(\$n-1, \$this->components)) {
169      return \$this->components[\$n-1];
170    }
171    else {
172      return NULL;
173    }
174  }
175
176  public function length() {
177    \$length = 0;
178    foreach (\$this->components as \$delta => \$component) {
179      \$length += \$component->length();
180    }
181    return \$length;
182  }
183
184  public function greatCircleLength(\$radius = 6378137) {
185    \$length = 0;
186    foreach (\$this->components as \$component) {
188    }
189    return \$length;
190  }
191
192  public function haversineLength() {
193    \$length = 0;
194    foreach (\$this->components as \$component) {
195      \$length += \$component->haversineLength();
196    }
197    return \$length;
198  }
199
200  public function dimension() {
201    \$dimension = 0;
202    foreach (\$this->components as \$component) {
203      if (\$component->dimension() > \$dimension) {
204        \$dimension = \$component->dimension();
205      }
206    }
207    return \$dimension;
208  }
209
210  // A collection is empty if it has no components OR all it's components are empty
211  public function isEmpty() {
212    if (!count(\$this->components)) {
213      return TRUE;
214    }
215    else {
216      foreach (\$this->components as \$component) {
217        if (!\$component->isEmpty()) return FALSE;
218      }
219      return TRUE;
220    }
221  }
222
223  public function numPoints() {
224    \$num = 0;
225    foreach (\$this->components as \$component) {
226      \$num += \$component->numPoints();
227    }
228    return \$num;
229  }
230
231  public function getPoints() {
232    \$points = array();
233    foreach (\$this->components as \$component) {
234      \$points = array_merge(\$points, \$component->getPoints());
235    }
236    return \$points;
237  }
238
239  public function equals(\$geometry) {
240    if (\$this->geos()) {
241      return \$this->geos()->equals(\$geometry->geos());
242    }
243
244    // To test for equality we check to make sure that there is a matching point
245    // in the other geometry for every point in this geometry.
246    // This is slightly more strict than the standard, which
247    // uses Within(A,B) = true and Within(B,A) = true
248    // @@TODO: Eventually we could fix this by using some sort of simplification
249    // method that strips redundant vertices (that are all in a row)
250
251    \$this_points = \$this->getPoints();
252    \$other_points = \$geometry->getPoints();
253
254    // First do a check to make sure they have the same number of vertices
255    if (count(\$this_points) != count(\$other_points)) {
256      return FALSE;
257    }
258
259    foreach (\$this_points as \$point) {
260      \$found_match = FALSE;
261      foreach (\$other_points as \$key => \$test_point) {
262        if (\$point->equals(\$test_point)) {
263          \$found_match = TRUE;
264          unset(\$other_points[\$key]);
265          break;
266        }
267      }
268      if (!\$found_match) {
269        return FALSE;
270      }
271    }
272
273    // All points match, return TRUE
274    return TRUE;
275  }
276
277  public function isSimple() {
278    if (\$this->geos()) {
279      return \$this->geos()->isSimple();
280    }
281
282    // A collection is simple if all it's components are simple
283    foreach (\$this->components as \$component) {
284      if (!\$component->isSimple()) return FALSE;
285    }
286
287    return TRUE;
288  }
289
290  public function explode() {
291    \$parts = array();
292    foreach (\$this->components as \$component) {
293      \$parts = array_merge(\$parts, \$component->explode());
294    }
295    return \$parts;
296  }
297
298  // Not valid for this geometry type
299  // --------------------------------
300  public function x()                { return NULL; }
301  public function y()                { return NULL; }
302  public function startPoint()       { return NULL; }
303  public function endPoint()         { return NULL; }
304  public function isRing()           { return NULL; }
305  public function isClosed()         { return NULL; }
306  public function pointN(\$n)         { return NULL; }
307  public function exteriorRing()     { return NULL; }
308  public function numInteriorRings() { return NULL; }
309  public function interiorRingN(\$n)  { return NULL; }
310  public function pointOnSurface()   { return NULL; }
311}
312
313```