GEOS 3.12.0
CoordinateSequence.h
1/**********************************************************************
2 *
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
5 *
6 * Copyright (C) 2022 ISciences LLC
7 * Copyright (C) 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#pragma once
17
18#include <geos/export.h>
19
20#include <geos/geom/Coordinate.h> // for applyCoordinateFilter
21#include <geos/geom/CoordinateSequenceIterator.h>
22
23#include <cassert>
24#include <vector>
25#include <iostream>
26#include <iosfwd> // ostream
27#include <memory> // for unique_ptr typedef
28
29// Forward declarations
30namespace geos {
31namespace geom {
32class Envelope;
33class CoordinateFilter;
34}
35}
36
37namespace geos {
38namespace geom { // geos::geom
39
56class GEOS_DLL CoordinateSequence {
57
58public:
59
61 enum { X, Y, Z, M };
62
63 using iterator = CoordinateSequenceIterator<CoordinateSequence, Coordinate>;
64 using const_iterator = CoordinateSequenceIterator<const CoordinateSequence, const Coordinate>;
65
66 typedef std::unique_ptr<CoordinateSequence> Ptr;
67
70
75
83 CoordinateSequence(std::size_t size, std::size_t dim = 0);
84
96 CoordinateSequence(std::size_t size, bool hasz, bool hasm, bool initialize = true);
97
103 CoordinateSequence(const std::initializer_list<Coordinate>&);
104
109 CoordinateSequence(const std::initializer_list<CoordinateXY>&);
110
116 CoordinateSequence(const std::initializer_list<CoordinateXYM>&);
117
121 CoordinateSequence(const std::initializer_list<CoordinateXYZM>&);
122
128 static CoordinateSequence XY(std::size_t size) {
129 return CoordinateSequence(size, false, false);
130 }
131
137 static CoordinateSequence XYZ(std::size_t size) {
138 return CoordinateSequence(size, true, false);
139 }
140
146 static CoordinateSequence XYZM(std::size_t size) {
147 return CoordinateSequence(size, true, true);
148 }
149
155 static CoordinateSequence XYM(std::size_t size) {
156 return CoordinateSequence(size, false, true);
157 }
158
162 std::unique_ptr<CoordinateSequence> clone() const;
163
167
174
178 std::size_t getSize() const {
179 return size();
180 }
181
185 size_t size() const
186 {
187 assert(stride() == 2 || stride() == 3 || stride() == 4);
188 switch(stride()) {
189 case 2: return m_vect.size() / 2;
190 case 4: return m_vect.size() / 4;
191 default : return m_vect.size() / 3;
192 }
193 }
194
196 bool isEmpty() const {
197 return m_vect.empty();
198 }
199
201 bool isNullPoint() const {
202 if (size() != 1) {
203 return false;
204 }
205 switch(getCoordinateType()) {
206 case CoordinateType::XY: return getAt<CoordinateXY>(0).isNull();
207 case CoordinateType::XYZ: return getAt<Coordinate>(0).isNull();
208 case CoordinateType::XYZM: return getAt<CoordinateXYZM>(0).isNull();
209 case CoordinateType::XYM: return getAt<CoordinateXYM>(0).isNull();
210 default: return false;
211 }
212 }
213
220 bool isRing() const;
221
228 std::size_t getDimension() const;
229
230 bool hasZ() const {
231 return m_hasdim ? m_hasz : (m_vect.empty() || !std::isnan(m_vect[2]));
232 }
233
234 bool hasM() const {
235 return m_hasm;
236 }
237
239 bool hasRepeatedPoints() const;
240
243
247 CoordinateType getCoordinateType() const {
248 switch(stride()) {
249 case 4: return CoordinateType::XYZM;
250 case 2: return CoordinateType::XY;
251 default: return hasM() ? CoordinateType::XYM : CoordinateType::XYZ;
252 }
253 }
254
258
262 template<typename T=Coordinate>
263 const T& getAt(std::size_t i) const {
264 static_assert(std::is_base_of<CoordinateXY, T>::value, "Must be a Coordinate class");
265 assert(sizeof(T) <= sizeof(double) * stride());
266 assert(i*stride() < m_vect.size());
267 const T* orig = reinterpret_cast<const T*>(&m_vect[i*stride()]);
268 return *orig;
269 }
270
274 template<typename T=Coordinate>
275 T& getAt(std::size_t i) {
276 static_assert(std::is_base_of<CoordinateXY, T>::value, "Must be a Coordinate class");
277 assert(sizeof(T) <= sizeof(double) * stride());
278 assert(i*stride() < m_vect.size());
279 T* orig = reinterpret_cast<T*>(&m_vect[i*stride()]);
280 return *orig;
281 }
282
286 template<typename T>
287 void getAt(std::size_t i, T& c) const {
288 switch(getCoordinateType()) {
289 case CoordinateType::XY: c = getAt<CoordinateXY>(i); break;
290 case CoordinateType::XYZ: c = getAt<Coordinate>(i); break;
291 case CoordinateType::XYZM: c = getAt<CoordinateXYZM>(i); break;
292 case CoordinateType::XYM: c = getAt<CoordinateXYM>(i); break;
293 default: getAt<Coordinate>(i);
294 }
295 }
296
297 void getAt(std::size_t i, CoordinateXY& c) const {
298 c = getAt<CoordinateXY>(i);
299 }
300
301 // TODO: change to return CoordinateXY
305 const Coordinate& operator[](std::size_t i) const
306 {
307 return getAt(i);
308 }
309
310 // TODO: change to return CoordinateXY
315 operator[](std::size_t i)
316 {
317 return getAt(i);
318 }
319
330 double getOrdinate(std::size_t index, std::size_t ordinateIndex) const;
331
338 double getX(std::size_t index) const
339 {
340 return m_vect[index * stride()];
341 }
342
349 double getY(std::size_t index) const
350 {
351 return m_vect[index * stride() + 1];
352 }
353
355 template<typename T=Coordinate>
356 const T& back() const
357 {
358 return getAt<T>(size() - 1);
359 }
360
362 template<typename T=Coordinate>
363 T& back()
364 {
365 return getAt<T>(size() - 1);
366 }
367
369 template<typename T=Coordinate>
370 const T& front() const
371 {
372 return *(reinterpret_cast<const T*>(m_vect.data()));
373 }
374
376 template<typename T=Coordinate>
377 T& front()
378 {
379 return *(reinterpret_cast<T*>(m_vect.data()));
380 }
381
383 void toVector(std::vector<Coordinate>& coords) const;
384
385 void toVector(std::vector<CoordinateXY>& coords) const;
386
387
391
393 template<typename T>
394 void setAt(const T& c, std::size_t pos) {
395 switch(getCoordinateType()) {
396 case CoordinateType::XY: setAtImpl<CoordinateXY>(c, pos); break;
397 case CoordinateType::XYZ: setAtImpl<Coordinate>(c, pos); break;
398 case CoordinateType::XYZM: setAtImpl<CoordinateXYZM>(c, pos); break;
399 case CoordinateType::XYM: setAtImpl<CoordinateXYM>(c, pos); break;
400 default: setAtImpl<Coordinate>(c, pos);
401 }
402 }
403
412 void setOrdinate(std::size_t index, std::size_t ordinateIndex, double value);
413
415 void setPoints(const std::vector<Coordinate>& v);
416
420
425 template<typename T=Coordinate>
426 void add(const T& c) {
427 add(c, size());
428 }
429
436 template<typename T>
437 void add(const T& c, bool allowRepeated)
438 {
439 if(!allowRepeated && !isEmpty()) {
440 const CoordinateXY& last = back<CoordinateXY>();
441 if(last.equals2D(c)) {
442 return;
443 }
444 }
445
446 add(c);
447 }
448
457 template<typename T>
458 void add(const T& c, std::size_t pos)
459 {
460 static_assert(std::is_base_of<CoordinateXY, T>::value, "Must be a Coordinate class");
461
462 // c may be a reference inside m_vect, so we make sure it will not
463 // grow before adding it
464 if (m_vect.size() + stride() <= m_vect.capacity()) {
465 make_space(pos, 1);
466 setAt(c, static_cast<std::size_t>(pos));
467 } else {
468 T tmp{c};
469 make_space(pos, 1);
470 setAt(tmp, static_cast<std::size_t>(pos));
471 }
472 }
473
483 template<typename T>
484 void add(std::size_t i, const T& coord, bool allowRepeated)
485 {
486 // don't add duplicate coordinates
487 if(! allowRepeated) {
488 std::size_t sz = size();
489 if(sz > 0) {
490 if(i > 0) {
491 const CoordinateXY& prev = getAt<CoordinateXY>(i - 1);
492 if(prev.equals2D(coord)) {
493 return;
494 }
495 }
496 if(i < sz) {
497 const CoordinateXY& next = getAt<CoordinateXY>(i);
498 if(next.equals2D(coord)) {
499 return;
500 }
501 }
502 }
503 }
504
505 add(coord, i);
506 }
507
508 void add(double x, double y) {
509 CoordinateXY c(x, y);
510 add(c);
511 }
512
513 void add(const CoordinateSequence& cs);
514
515 void add(const CoordinateSequence& cs, bool allowRepeated);
516
517 void add(const CoordinateSequence& cl, bool allowRepeated, bool forwardDirection);
518
519 void add(const CoordinateSequence& cs, std::size_t from, std::size_t to);
520
521 void add(const CoordinateSequence& cs, std::size_t from, std::size_t to, bool allowRepeated);
522
523 template<typename T, typename... Args>
524 void add(T begin, T end, Args... args) {
525 for (auto it = begin; it != end; ++it) {
526 add(*it, args...);
527 }
528 }
529
530 template<typename T>
531 void add(std::size_t i, T from, T to) {
532 auto npts = static_cast<std::size_t>(std::distance(from, to));
533 make_space(i, npts);
534
535 for (auto it = from; it != to; ++it) {
536 setAt(*it, i);
537 i++;
538 }
539 }
540
544
545 void clear() {
546 m_vect.clear();
547 }
548
549 void reserve(std::size_t capacity) {
550 m_vect.reserve(capacity * stride());
551 }
552
553 void resize(std::size_t capacity) {
554 m_vect.resize(capacity * stride());
555 }
556
557 void pop_back();
558
560 std::string toString() const;
561
563 const CoordinateXY* minCoordinate() const;
564
571
573 //
576 static std::size_t indexOf(const CoordinateXY* coordinate,
577 const CoordinateSequence* cl);
578
584 static bool equals(const CoordinateSequence* cl1,
585 const CoordinateSequence* cl2);
586
592 bool equalsIdentical(const CoordinateSequence& other) const;
593
595 static void scroll(CoordinateSequence* cl, const CoordinateXY* firstCoordinate);
596
615
617 void reverse();
618
619 void sort();
620
621
627 void expandEnvelope(Envelope& env) const;
628
629 void closeRing(bool allowRepeated = false);
630
634
635 template<typename Filter>
636 void apply_rw(const Filter* filter) {
637 switch(getCoordinateType()) {
638 case CoordinateType::XY: for (auto& c : items<CoordinateXY>()) { filter->filter_rw(&c); } break;
639 case CoordinateType::XYZ: for (auto& c : items<Coordinate>()) { filter->filter_rw(&c); } break;
640 case CoordinateType::XYM: for (auto& c : items<CoordinateXYM>()) { filter->filter_rw(&c); } break;
641 case CoordinateType::XYZM: for (auto& c : items<CoordinateXYZM>()) { filter->filter_rw(&c); } break;
642 }
643 m_hasdim = m_hasz = false; // re-check (see http://trac.osgeo.org/geos/ticket/435)
644 }
645
646 template<typename Filter>
647 void apply_ro(Filter* filter) const {
648 switch(getCoordinateType()) {
649 case CoordinateType::XY: for (const auto& c : items<CoordinateXY>()) { filter->filter_ro(&c); } break;
650 case CoordinateType::XYZ: for (const auto& c : items<Coordinate>()) { filter->filter_ro(&c); } break;
651 case CoordinateType::XYM: for (const auto& c : items<CoordinateXYM>()) { filter->filter_ro(&c); } break;
652 case CoordinateType::XYZM: for (const auto& c : items<CoordinateXYZM>()) { filter->filter_ro(&c); } break;
653 }
654 }
655
656 template<typename F>
657 void forEach(F&& fun) const {
658 switch(getCoordinateType()) {
659 case CoordinateType::XY: for (const auto& c : items<CoordinateXY>()) { fun(c); } break;
660 case CoordinateType::XYZ: for (const auto& c : items<Coordinate>()) { fun(c); } break;
661 case CoordinateType::XYM: for (const auto& c : items<CoordinateXYM>()) { fun(c); } break;
662 case CoordinateType::XYZM: for (const auto& c : items<CoordinateXYZM>()) { fun(c); } break;
663 }
664 }
665
666 template<typename T, typename F>
667 void forEach(F&& fun) const
668 {
669 for (std::size_t i = 0; i < size(); i++) {
670 fun(getAt<T>(i));
671 }
672 }
673
674 template<typename T, typename F>
675 void forEach(std::size_t from, std::size_t to, F&& fun) const
676 {
677 for (std::size_t i = from; i <= to; i++) {
678 fun(getAt<T>(i));
679 }
680 }
681
682 template<typename T>
683 class Coordinates {
684 public:
685 using SequenceType = typename std::conditional<std::is_const<T>::value, const CoordinateSequence, CoordinateSequence>::type;
686
687 explicit Coordinates(SequenceType* seq) : m_seq(seq) {}
688
689 CoordinateSequenceIterator<SequenceType, T> begin() {
690 return {m_seq};
691 }
692
693 CoordinateSequenceIterator<SequenceType, T> end() {
694 return {m_seq, m_seq->getSize()};
695 }
696
697 CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>
698 begin() const {
699 return CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>{m_seq};
700 }
701
702 CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>
703 end() const {
704 return CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>{m_seq, m_seq->getSize()};
705 }
706
707 CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>
708 cbegin() const {
709 return CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>{m_seq};
710 }
711
712 CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>
713 cend() const {
714 return CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>{m_seq, m_seq->getSize()};
715 }
716
717 private:
718 SequenceType* m_seq;
719 };
720
721 template<typename T>
722 Coordinates<typename std::add_const<T>::type> items() const {
723 return Coordinates<typename std::add_const<T>::type>(this);
724 }
725
726 template<typename T>
727 Coordinates<T> items() {
728 return Coordinates<T>(this);
729 }
730
731
733
734 double* data() {
735 return m_vect.data();
736 }
737
738 const double* data() const {
739 return m_vect.data();
740 }
741
742private:
743 std::vector<double> m_vect; // Vector to store values
744
745 uint8_t m_stride; // Stride of stored values, corresponding to underlying type
746
747 mutable bool m_hasdim; // Has the dimension of this sequence been determined? Or was it created with no
748 // explicit dimensionality, and we're waiting for getDimension() to be called
749 // after some coordinates have been added?
750 mutable bool m_hasz;
751 bool m_hasm;
752
753 void initialize();
754
755 template<typename T1, typename T2>
756 void setAtImpl(const T2& c, std::size_t pos) {
757 auto& orig = getAt<T1>(pos);
758 orig = c;
759 }
760
761 void make_space(std::size_t pos, std::size_t n) {
762 m_vect.insert(std::next(m_vect.begin(), static_cast<std::ptrdiff_t>(pos * stride())),
763 m_stride * n,
764 DoubleNotANumber);
765 }
766
767 std::uint8_t stride() const {
768 return m_stride;
769 }
770
771};
772
773GEOS_DLL std::ostream& operator<< (std::ostream& os, const CoordinateSequence& cs);
774
775GEOS_DLL bool operator== (const CoordinateSequence& s1, const CoordinateSequence& s2);
776
777GEOS_DLL bool operator!= (const CoordinateSequence& s1, const CoordinateSequence& s2);
778
779} // namespace geos::geom
780} // namespace geos
781
The internal representation of a list of coordinates inside a Geometry.
Definition CoordinateSequence.h:56
Coordinate is the lightweight class used to store coordinates.
Definition Coordinate.h:216
An Envelope defines a rectangulare region of the 2D coordinate plane.
Definition Envelope.h:58
T & getAt(std::size_t i)
Returns a reference to Coordinate at position i.
Definition CoordinateSequence.h:275
Coordinate & operator[](std::size_t i)
Definition CoordinateSequence.h:315
void toVector(std::vector< Coordinate > &coords) const
Pushes all Coordinates of this sequence into the provided vector.
double getOrdinate(std::size_t index, std::size_t ordinateIndex) const
const T & front() const
Return first Coordinate in the sequence.
Definition CoordinateSequence.h:370
T & back()
Return last Coordinate in the sequence.
Definition CoordinateSequence.h:363
void getAt(std::size_t i, T &c) const
Write Coordinate at position i to given Coordinate.
Definition CoordinateSequence.h:287
const T & getAt(std::size_t i) const
Returns a read-only reference to Coordinate at position i.
Definition CoordinateSequence.h:263
T & front()
Return first Coordinate in the sequence.
Definition CoordinateSequence.h:377
double getX(std::size_t index) const
Definition CoordinateSequence.h:338
double getY(std::size_t index) const
Definition CoordinateSequence.h:349
const Coordinate & operator[](std::size_t i) const
Definition CoordinateSequence.h:305
const T & back() const
Return last Coordinate in the sequence.
Definition CoordinateSequence.h:356
void add(const T &c, bool allowRepeated)
Definition CoordinateSequence.h:437
void add(std::size_t i, const T &coord, bool allowRepeated)
Inserts the specified coordinate at the specified position in this list.
Definition CoordinateSequence.h:484
void add(const T &c)
Definition CoordinateSequence.h:426
void add(const T &c, std::size_t pos)
Inserts the specified coordinate at the specified position in this sequence. If multiple coordinates ...
Definition CoordinateSequence.h:458
CoordinateSequence(const std::initializer_list< CoordinateXYZM > &)
static CoordinateSequence XYM(std::size_t size)
Definition CoordinateSequence.h:155
CoordinateSequence(const std::initializer_list< CoordinateXY > &)
std::unique_ptr< CoordinateSequence > clone() const
Returns a heap-allocated deep copy of this CoordinateSequence.
CoordinateSequence(std::size_t size, bool hasz, bool hasm, bool initialize=true)
static CoordinateSequence XYZM(std::size_t size)
Definition CoordinateSequence.h:146
static CoordinateSequence XYZ(std::size_t size)
Definition CoordinateSequence.h:137
static CoordinateSequence XY(std::size_t size)
Definition CoordinateSequence.h:128
CoordinateSequence(std::size_t size, std::size_t dim=0)
CoordinateSequence(const std::initializer_list< CoordinateXYM > &)
CoordinateSequence(const std::initializer_list< Coordinate > &)
void setOrdinate(std::size_t index, std::size_t ordinateIndex, double value)
void setPoints(const std::vector< Coordinate > &v)
Substitute Coordinate list with a copy of the given vector.
void setAt(const T &c, std::size_t pos)
Copy Coordinate c to position pos.
Definition CoordinateSequence.h:394
std::size_t getSize() const
Returns the number of Coordinates.
Definition CoordinateSequence.h:178
bool hasRepeatedOrInvalidPoints() const
Returns true if contains any NaN/Inf coordinates.
size_t size() const
Returns the number of Coordinates.
Definition CoordinateSequence.h:185
bool isNullPoint() const
Returns true if there is 1 coordinate and if it is null.
Definition CoordinateSequence.h:201
bool hasRepeatedPoints() const
Returns true if contains any two consecutive points.
CoordinateType getCoordinateType() const
Definition CoordinateSequence.h:247
bool isEmpty() const
Returns true if list contains no coordinates.
Definition CoordinateSequence.h:196
bool isRing() const
Tests whether an a CoordinateSequence forms a ring, by checking length and closure....
std::size_t getDimension() const
bool equalsIdentical(const CoordinateSequence &other) const
Returns true if the two sequences are identical (pointwise equal in all dimensions,...
void reverse()
Reverse Coordinate order in given CoordinateSequence.
static void scroll(CoordinateSequence *cl, const CoordinateXY *firstCoordinate)
Scroll given CoordinateSequence so to start with given Coordinate.
const CoordinateXY * minCoordinate() const
Returns lower-left Coordinate in list.
static int increasingDirection(const CoordinateSequence &pts)
Determines which orientation of the Coordinate array is (overall) increasing.
void expandEnvelope(Envelope &env) const
static CoordinateSequence * atLeastNCoordinatesOrNothing(std::size_t n, CoordinateSequence *c)
Returns either the given CoordinateSequence if its length is greater than the given amount,...
std::string toString() const
Get a string representation of CoordinateSequence.
static std::size_t indexOf(const CoordinateXY *coordinate, const CoordinateSequence *cl)
Return position of a Coordinate.
static bool equals(const CoordinateSequence *cl1, const CoordinateSequence *cl2)
Returns true if the two arrays are identical, both null, or pointwise equal in two dimensions.
Basic namespace for all GEOS functionalities.
Definition geos.h:39