/src/geos/src/geom/GeometryCollection.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2001-2002 Vivid Solutions Inc. |
7 | | * Copyright (C) 2005 2006 Refractions Research Inc. |
8 | | * |
9 | | * This is free software; you can redistribute and/or modify it under |
10 | | * the terms of the GNU Lesser General Public Licence as published |
11 | | * by the Free Software Foundation. |
12 | | * See the COPYING file for more information. |
13 | | * |
14 | | ********************************************************************** |
15 | | * |
16 | | * Last port: geom/GeometryCollection.java rev. 1.41 |
17 | | * |
18 | | **********************************************************************/ |
19 | | |
20 | | #include <geos/geom/GeometryCollection.h> |
21 | | #include <geos/util/IllegalArgumentException.h> |
22 | | #include <geos/geom/CoordinateSequence.h> |
23 | | #include <geos/geom/CoordinateSequenceFilter.h> |
24 | | #include <geos/geom/GeometryFactory.h> |
25 | | #include <geos/geom/GeometryFilter.h> |
26 | | #include <geos/geom/GeometryComponentFilter.h> |
27 | | #include <geos/util.h> |
28 | | |
29 | | |
30 | | #include <algorithm> |
31 | | #include <vector> |
32 | | #include <memory> |
33 | | |
34 | | namespace geos { |
35 | | namespace geom { // geos::geom |
36 | | |
37 | | /*protected*/ |
38 | | GeometryCollection::GeometryCollection(const GeometryCollection& gc) |
39 | | : |
40 | 20.7k | Geometry(gc), |
41 | 20.7k | geometries(gc.geometries.size()), |
42 | 20.7k | flags(gc.flags), |
43 | 20.7k | envelope(gc.envelope) |
44 | 20.7k | { |
45 | 93.8k | for(std::size_t i = 0; i < geometries.size(); ++i) { |
46 | 73.1k | geometries[i] = gc.geometries[i]->clone(); |
47 | 73.1k | } |
48 | 20.7k | } |
49 | | |
50 | | GeometryCollection& |
51 | | GeometryCollection::operator=(const GeometryCollection& gc) |
52 | 0 | { |
53 | 0 | geometries.resize(gc.geometries.size()); |
54 | 0 | envelope = gc.envelope; |
55 | 0 | flags = gc.flags; |
56 | |
|
57 | 0 | for (std::size_t i = 0; i < geometries.size(); i++) { |
58 | 0 | geometries[i] = gc.geometries[i]->clone(); |
59 | 0 | } |
60 | |
|
61 | 0 | return *this; |
62 | 0 | } |
63 | | |
64 | | GeometryCollection::GeometryCollection(std::vector<std::unique_ptr<Geometry>> && newGeoms, const GeometryFactory& factory) : |
65 | 328k | Geometry(&factory), |
66 | 328k | geometries(std::move(newGeoms)), |
67 | 328k | flags{}, // set all flags to zero |
68 | 328k | envelope(computeEnvelopeInternal()) |
69 | 328k | { |
70 | | |
71 | 328k | if (hasNullElements(&geometries)) { |
72 | 0 | throw util::IllegalArgumentException("geometries must not contain null elements\n"); |
73 | 0 | } |
74 | | |
75 | 328k | setSRID(getSRID()); |
76 | 328k | } |
77 | | |
78 | | void |
79 | | GeometryCollection::setSRID(int newSRID) |
80 | 942k | { |
81 | 942k | Geometry::setSRID(newSRID); |
82 | 60.3M | for(auto& g : geometries) { |
83 | 60.3M | g->setSRID(newSRID); |
84 | 60.3M | } |
85 | 942k | } |
86 | | |
87 | | /* |
88 | | * Collects all coordinates of all subgeometries into a CoordinateSequence. |
89 | | * |
90 | | * Returns a newly the collected coordinates |
91 | | * |
92 | | */ |
93 | | std::unique_ptr<CoordinateSequence> |
94 | | GeometryCollection::getCoordinates() const |
95 | 0 | { |
96 | 0 | auto coordinates = detail::make_unique<CoordinateSequence>(getNumPoints()); |
97 | |
|
98 | 0 | std::size_t k = 0; |
99 | 0 | for(const auto& g : geometries) { |
100 | 0 | auto childCoordinates = g->getCoordinates(); // TODO avoid this copy where getCoordinateRO() exists |
101 | 0 | std::size_t npts = childCoordinates->getSize(); |
102 | 0 | for(std::size_t j = 0; j < npts; ++j) { |
103 | 0 | coordinates->setAt(childCoordinates->getAt(j), k); |
104 | 0 | k++; |
105 | 0 | } |
106 | 0 | } |
107 | 0 | return coordinates; |
108 | 0 | } |
109 | | |
110 | | bool |
111 | | GeometryCollection::isEmpty() const |
112 | 19.7M | { |
113 | 19.7M | for(const auto& g : geometries) { |
114 | 660k | if(!g->isEmpty()) { |
115 | 507k | return false; |
116 | 507k | } |
117 | 660k | } |
118 | 19.1M | return true; |
119 | 19.7M | } |
120 | | |
121 | | void |
122 | 3.79M | GeometryCollection::setFlags() const { |
123 | 3.79M | if (flags.flagsCalculated) { |
124 | 3.62M | return; |
125 | 3.62M | } |
126 | | |
127 | 28.6M | for (const auto& geom : geometries) { |
128 | 28.6M | flags.hasPoints |= geom->hasDimension(Dimension::P); |
129 | 28.6M | flags.hasLines |= geom->hasDimension(Dimension::L); |
130 | 28.6M | flags.hasPolygons |= geom->hasDimension(Dimension::A); |
131 | 28.6M | flags.hasM |= geom->hasM(); |
132 | 28.6M | flags.hasZ |= geom->hasZ(); |
133 | 28.6M | flags.hasCurves |= geom->hasCurvedComponents(); |
134 | 28.6M | } |
135 | | |
136 | 165k | flags.flagsCalculated = true; |
137 | 165k | } |
138 | | |
139 | | Dimension::DimensionType |
140 | | GeometryCollection::getDimension() const |
141 | 3.33M | { |
142 | 3.33M | setFlags(); |
143 | | |
144 | 3.33M | if (flags.hasPolygons) { |
145 | 342 | return Dimension::A; |
146 | 342 | } |
147 | 3.33M | if (flags.hasLines) { |
148 | 85.7k | return Dimension::L; |
149 | 85.7k | } |
150 | 3.24M | if (flags.hasPoints) { |
151 | 4.33k | return Dimension::P; |
152 | 4.33k | } |
153 | 3.24M | return Dimension::False; |
154 | 3.24M | } |
155 | | |
156 | | bool |
157 | 58.3k | GeometryCollection::isDimensionStrict(Dimension::DimensionType d) const { |
158 | 58.3k | setFlags(); |
159 | | |
160 | 58.3k | if (isEmpty()) { |
161 | 37.7k | return true; |
162 | 37.7k | } |
163 | | |
164 | 20.5k | switch(d) { |
165 | 20.5k | case Dimension::A: return flags.hasPolygons && !flags.hasLines && !flags.hasPoints; |
166 | 0 | case Dimension::L: return !flags.hasPolygons && flags.hasLines && !flags.hasPoints; |
167 | 0 | case Dimension::P: return !flags.hasPolygons && !flags.hasLines && flags.hasPoints; |
168 | 0 | default: |
169 | 0 | return false; |
170 | 20.5k | } |
171 | 20.5k | } |
172 | | |
173 | | bool |
174 | 5.14k | GeometryCollection::hasDimension(Dimension::DimensionType d) const { |
175 | 5.14k | setFlags(); |
176 | | |
177 | 5.14k | switch (d) { |
178 | 1.71k | case Dimension:: A: return flags.hasPolygons; |
179 | 1.71k | case Dimension:: L: return flags.hasLines; |
180 | 1.71k | case Dimension:: P: return flags.hasPoints; |
181 | 0 | default: |
182 | 0 | return false; |
183 | 5.14k | } |
184 | 5.14k | } |
185 | | |
186 | | int |
187 | | GeometryCollection::getBoundaryDimension() const |
188 | 0 | { |
189 | 0 | int dimension = Dimension::False; |
190 | 0 | for(const auto& g : geometries) { |
191 | 0 | dimension = std::max(dimension, g->getBoundaryDimension()); |
192 | 0 | } |
193 | 0 | return dimension; |
194 | 0 | } |
195 | | |
196 | | uint8_t |
197 | | GeometryCollection::getCoordinateDimension() const |
198 | 123k | { |
199 | 123k | uint8_t dimension = 2; |
200 | | |
201 | 3.83M | for(const auto& g : geometries) { |
202 | 3.83M | dimension = std::max(dimension, g->getCoordinateDimension()); |
203 | 3.83M | } |
204 | 123k | return dimension; |
205 | 123k | } |
206 | | |
207 | | bool |
208 | | GeometryCollection::hasM() const |
209 | 149k | { |
210 | 149k | setFlags(); |
211 | 149k | return flags.hasM; |
212 | 149k | } |
213 | | |
214 | | bool |
215 | | GeometryCollection::hasZ() const |
216 | 150k | { |
217 | 150k | setFlags(); |
218 | 150k | return flags.hasZ; |
219 | 150k | } |
220 | | |
221 | | size_t |
222 | | GeometryCollection::getNumGeometries() const |
223 | 41.0M | { |
224 | 41.0M | return geometries.size(); |
225 | 41.0M | } |
226 | | |
227 | | const Geometry* |
228 | | GeometryCollection::getGeometryN(std::size_t n) const |
229 | 221k | { |
230 | 221k | return geometries[n].get(); |
231 | 221k | } |
232 | | |
233 | | std::vector<std::unique_ptr<Geometry>> |
234 | | GeometryCollection::releaseGeometries() |
235 | 35.0k | { |
236 | 35.0k | auto ret = std::move(geometries); |
237 | 35.0k | geometryChanged(); |
238 | 35.0k | flags.flagsCalculated = false; |
239 | 35.0k | return ret; |
240 | 35.0k | } |
241 | | |
242 | | size_t |
243 | | GeometryCollection::getNumPoints() const |
244 | 16.5k | { |
245 | 16.5k | std::size_t numPoints = 0; |
246 | 21.8M | for(const auto& g : geometries) { |
247 | 21.8M | numPoints += g->getNumPoints(); |
248 | 21.8M | } |
249 | 16.5k | return numPoints; |
250 | 16.5k | } |
251 | | |
252 | | std::string |
253 | | GeometryCollection::getGeometryType() const |
254 | 9 | { |
255 | 9 | return "GeometryCollection"; |
256 | 9 | } |
257 | | |
258 | | std::unique_ptr<Geometry> |
259 | | GeometryCollection::getBoundary() const |
260 | 0 | { |
261 | 0 | throw util::IllegalArgumentException("Operation not supported by GeometryCollection\n"); |
262 | 0 | } |
263 | | |
264 | | bool |
265 | | GeometryCollection::equalsExact(const Geometry* other, double tolerance) const |
266 | 0 | { |
267 | 0 | if(!isEquivalentClass(other)) { |
268 | 0 | return false; |
269 | 0 | } |
270 | | |
271 | 0 | const GeometryCollection* otherCollection = detail::down_cast<const GeometryCollection*>(other); |
272 | 0 | if(geometries.size() != otherCollection->geometries.size()) { |
273 | 0 | return false; |
274 | 0 | } |
275 | 0 | for(std::size_t i = 0; i < geometries.size(); ++i) { |
276 | 0 | if(!(geometries[i]->equalsExact(otherCollection->geometries[i].get(), tolerance))) { |
277 | 0 | return false; |
278 | 0 | } |
279 | 0 | } |
280 | 0 | return true; |
281 | 0 | } |
282 | | |
283 | | bool |
284 | | GeometryCollection::equalsIdentical(const Geometry* other_g) const |
285 | 0 | { |
286 | 0 | if(!isEquivalentClass(other_g)) { |
287 | 0 | return false; |
288 | 0 | } |
289 | | |
290 | 0 | const auto& other = static_cast<const GeometryCollection&>(*other_g); |
291 | 0 | if(getNumGeometries() != other.getNumGeometries()) { |
292 | 0 | return false; |
293 | 0 | } |
294 | | |
295 | 0 | if (envelope != other.envelope) { |
296 | 0 | return false; |
297 | 0 | } |
298 | | |
299 | 0 | for(std::size_t i = 0; i < getNumGeometries(); i++) { |
300 | 0 | if(!(getGeometryN(i)->equalsIdentical(other.getGeometryN(i)))) { |
301 | 0 | return false; |
302 | 0 | } |
303 | 0 | } |
304 | | |
305 | 0 | return true; |
306 | 0 | } |
307 | | |
308 | | void |
309 | | GeometryCollection::apply_rw(const CoordinateFilter* filter) |
310 | 12.1k | { |
311 | 1.11M | for(auto& g : geometries) { |
312 | 1.11M | g->apply_rw(filter); |
313 | 1.11M | } |
314 | 12.1k | } |
315 | | |
316 | | void |
317 | | GeometryCollection::apply_ro(CoordinateFilter* filter) const |
318 | 16.5k | { |
319 | 21.8M | for(const auto& g : geometries) { |
320 | 21.8M | g->apply_ro(filter); |
321 | 21.8M | } |
322 | 16.5k | } |
323 | | |
324 | | void |
325 | | GeometryCollection::apply_ro(GeometryFilter* filter) const |
326 | 194k | { |
327 | 194k | filter->filter_ro(this); |
328 | 52.9M | for(const auto& g : geometries) { |
329 | 52.9M | g->apply_ro(filter); |
330 | 52.9M | } |
331 | 194k | } |
332 | | |
333 | | void |
334 | | GeometryCollection::apply_rw(GeometryFilter* filter) |
335 | 0 | { |
336 | 0 | filter->filter_rw(this); |
337 | 0 | for(auto& g : geometries) { |
338 | 0 | g->apply_rw(filter); |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | | void |
343 | | GeometryCollection::normalize() |
344 | 0 | { |
345 | 0 | for(auto& g : geometries) { |
346 | 0 | g->normalize(); |
347 | 0 | } |
348 | 0 | std::sort(geometries.begin(), geometries.end(), [](const std::unique_ptr<Geometry> & a, const std::unique_ptr<Geometry> & b) { |
349 | 0 | return a->compareTo(b.get()) > 0; |
350 | 0 | }); |
351 | 0 | } |
352 | | |
353 | | Envelope |
354 | | GeometryCollection::computeEnvelopeInternal() const |
355 | 431k | { |
356 | 431k | Envelope p_envelope; |
357 | 53.5M | for(const auto& g : geometries) { |
358 | 53.5M | const Envelope* env = g->getEnvelopeInternal(); |
359 | 53.5M | p_envelope.expandToInclude(env); |
360 | 53.5M | } |
361 | 431k | return p_envelope; |
362 | 431k | } |
363 | | |
364 | | int |
365 | | GeometryCollection::compareToSameClass(const Geometry* g) const |
366 | 0 | { |
367 | 0 | const GeometryCollection* gc = detail::down_cast<const GeometryCollection*>(g); |
368 | 0 | return compare(geometries, gc->geometries); |
369 | 0 | } |
370 | | |
371 | 96.9k | bool GeometryCollection::hasCurvedComponents() const { |
372 | 96.9k | setFlags(); |
373 | 96.9k | return flags.hasCurves; |
374 | 96.9k | } |
375 | | |
376 | | const CoordinateXY* |
377 | | GeometryCollection::getCoordinate() const |
378 | 0 | { |
379 | 0 | for(const auto& g : geometries) { |
380 | 0 | if(!g->isEmpty()) { |
381 | 0 | return g->getCoordinate(); |
382 | 0 | } |
383 | 0 | } |
384 | 0 | return nullptr; |
385 | 0 | } |
386 | | |
387 | | /** |
388 | | * @return the area of this collection |
389 | | */ |
390 | | double |
391 | | GeometryCollection::getArea() const |
392 | 117k | { |
393 | 117k | double area = 0.0; |
394 | 4.76M | for(const auto& g : geometries) { |
395 | 4.76M | area += g->getArea(); |
396 | 4.76M | } |
397 | 117k | return area; |
398 | 117k | } |
399 | | |
400 | | /** |
401 | | * @return the total length of this collection |
402 | | */ |
403 | | double |
404 | | GeometryCollection::getLength() const |
405 | 0 | { |
406 | 0 | double sum = 0.0; |
407 | 0 | for(const auto& g : geometries) { |
408 | 0 | sum += g->getLength(); |
409 | 0 | } |
410 | 0 | return sum; |
411 | 0 | } |
412 | | |
413 | | void |
414 | | GeometryCollection::apply_rw(GeometryComponentFilter* filter) |
415 | 35.0k | { |
416 | 35.0k | filter->filter_rw(this); |
417 | 35.0k | for(auto& g : geometries) { |
418 | 0 | if (filter->isDone()) { |
419 | 0 | return; |
420 | 0 | } |
421 | 0 | g->apply_rw(filter); |
422 | 0 | } |
423 | 35.0k | } |
424 | | |
425 | | void |
426 | | GeometryCollection::apply_ro(GeometryComponentFilter* filter) const |
427 | 7.15k | { |
428 | 7.15k | filter->filter_ro(this); |
429 | 140k | for(const auto& g : geometries) { |
430 | 140k | if (filter->isDone()) { |
431 | 0 | return; |
432 | 0 | } |
433 | 140k | g->apply_ro(filter); |
434 | 140k | } |
435 | 7.15k | } |
436 | | |
437 | | void |
438 | | GeometryCollection::apply_rw(CoordinateSequenceFilter& filter) |
439 | 0 | { |
440 | 0 | for(auto& g : geometries) { |
441 | 0 | g->apply_rw(filter); |
442 | 0 | if(filter.isDone()) { |
443 | 0 | break; |
444 | 0 | } |
445 | 0 | } |
446 | 0 | if(filter.isGeometryChanged()) { |
447 | 0 | geometryChanged(); |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | | void |
452 | | GeometryCollection::apply_ro(CoordinateSequenceFilter& filter) const |
453 | 82.5k | { |
454 | 1.07M | for(const auto& g : geometries) { |
455 | 1.07M | g->apply_ro(filter); |
456 | 1.07M | if(filter.isDone()) { |
457 | 66.2k | break; |
458 | 66.2k | } |
459 | 1.07M | } |
460 | | |
461 | 82.5k | assert(!filter.isGeometryChanged()); // read-only filter... |
462 | | //if (filter.isGeometryChanged()) geometryChanged(); |
463 | 82.5k | } |
464 | | |
465 | | GeometryTypeId |
466 | | GeometryCollection::getGeometryTypeId() const |
467 | 93.1k | { |
468 | 93.1k | return GEOS_GEOMETRYCOLLECTION; |
469 | 93.1k | } |
470 | | |
471 | | GeometryCollection* |
472 | | GeometryCollection::reverseImpl() const |
473 | 0 | { |
474 | 0 | if(isEmpty()) { |
475 | 0 | return clone().release(); |
476 | 0 | } |
477 | | |
478 | 0 | std::vector<std::unique_ptr<Geometry>> reversed(geometries.size()); |
479 | |
|
480 | 0 | std::transform(geometries.begin(), |
481 | 0 | geometries.end(), |
482 | 0 | reversed.begin(), |
483 | 0 | [](const std::unique_ptr<Geometry> & g) { |
484 | 0 | return g->reverse(); |
485 | 0 | }); |
486 | |
|
487 | 0 | return getFactory()->createGeometryCollection(std::move(reversed)).release(); |
488 | 0 | } |
489 | | |
490 | | |
491 | | |
492 | | } // namespace geos::geom |
493 | | } // namespace geos |