GEOS 3.15.0dev
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
206 bool isRing() const;
207
214 std::size_t getDimension() const;
215
216 bool hasZ() const {
217 return m_hasdim ? m_hasz : (m_vect.empty() || !std::isnan(m_vect[2]));
218 }
219
220 bool hasM() const {
221 return m_hasm;
222 }
223
229 void setZM(bool hasZ, bool hasM);
230
232 bool hasRepeatedPoints() const;
233
236
240 CoordinateType getCoordinateType() const {
241 switch(stride()) {
242 case 4: return CoordinateType::XYZM;
243 case 2: return CoordinateType::XY;
244 default: return hasM() ? CoordinateType::XYM : CoordinateType::XYZ;
245 }
246 }
247
251
255 template<typename T=Coordinate>
256 const T& getAt(std::size_t i) const {
257 static_assert(std::is_base_of<CoordinateXY, T>::value, "Must be a Coordinate class");
258 assert(sizeof(T) <= sizeof(double) * stride());
259 assert(i*stride() < m_vect.size());
260 const T* orig = reinterpret_cast<const T*>(&m_vect[i*stride()]);
261 return *orig;
262 }
263
267 template<typename T=Coordinate>
268 T& getAt(std::size_t i) {
269 static_assert(std::is_base_of<CoordinateXY, T>::value, "Must be a Coordinate class");
270 assert(sizeof(T) <= sizeof(double) * stride());
271 assert(i*stride() < m_vect.size());
272 T* orig = reinterpret_cast<T*>(&m_vect[i*stride()]);
273 return *orig;
274 }
275
279 template<typename T>
280 void getAt(std::size_t i, T& c) const {
281 switch(getCoordinateType()) {
282 case CoordinateType::XY: c = getAt<CoordinateXY>(i); break;
283 case CoordinateType::XYZ: c = getAt<Coordinate>(i); break;
284 case CoordinateType::XYZM: c = getAt<CoordinateXYZM>(i); break;
285 case CoordinateType::XYM: c = getAt<CoordinateXYM>(i); break;
286 default: getAt<Coordinate>(i);
287 }
288 }
289
290 void getAt(std::size_t i, CoordinateXY& c) const {
291 c = getAt<CoordinateXY>(i);
292 }
293
294 // TODO: change to return CoordinateXY
298 const Coordinate& operator[](std::size_t i) const
299 {
300 return getAt(i);
301 }
302
303 // TODO: change to return CoordinateXY
308 operator[](std::size_t i)
309 {
310 return getAt(i);
311 }
312
323 double getOrdinate(std::size_t index, std::size_t ordinateIndex) const;
324
331 double getX(std::size_t index) const
332 {
333 return m_vect[index * stride()];
334 }
335
342 double getY(std::size_t index) const
343 {
344 return m_vect[index * stride() + 1];
345 }
346
354 double getZ(std::size_t index) const
355 {
356 return getOrdinate(index, Z);
357 }
358
366 double getM(std::size_t index) const
367 {
368 return getOrdinate(index, M);
369 }
370
377 void setX(std::size_t index, double x)
378 {
379 m_vect[index * stride()] = x;
380 }
381
388 void setY(std::size_t index, double y)
389 {
390 m_vect[index * stride() + 1] = y;
391 }
392
401 void setZ(std::size_t index, double z)
402 {
403 if (hasZ())
404 setOrdinate(index, Z, z);
405 }
406
415 void setM(std::size_t index, double m)
416 {
417 if (hasM())
418 setOrdinate(index, M, m);
419 }
420
422 template<typename T=Coordinate>
423 const T& back() const
424 {
425 return getAt<T>(size() - 1);
426 }
427
429 template<typename T=Coordinate>
430 T& back()
431 {
432 return getAt<T>(size() - 1);
433 }
434
436 template<typename T=Coordinate>
437 const T& front() const
438 {
439 return *(reinterpret_cast<const T*>(m_vect.data()));
440 }
441
443 template<typename T=Coordinate>
444 T& front()
445 {
446 return *(reinterpret_cast<T*>(m_vect.data()));
447 }
448
450 void toVector(std::vector<Coordinate>& coords) const;
451
452 void toVector(std::vector<CoordinateXY>& coords) const;
453
454
458
460 template<typename T>
461 void setAt(const T& c, std::size_t pos) {
462 switch(getCoordinateType()) {
463 case CoordinateType::XY: setAtImpl<CoordinateXY>(c, pos); break;
464 case CoordinateType::XYZ: setAtImpl<Coordinate>(c, pos); break;
465 case CoordinateType::XYZM: setAtImpl<CoordinateXYZM>(c, pos); break;
466 case CoordinateType::XYM: setAtImpl<CoordinateXYM>(c, pos); break;
467 default: setAtImpl<Coordinate>(c, pos);
468 }
469 }
470
479 void setOrdinate(std::size_t index, std::size_t ordinateIndex, double value);
480
482 void setPoints(const std::vector<Coordinate>& v);
483
485 void setPoints(const std::vector<CoordinateXY>& v);
486
490
495 template<typename T=Coordinate>
496 void add(const T& c) {
497 add(c, size());
498 }
499
506 template<typename T>
507 void add(const T& c, bool allowRepeated)
508 {
509 if(!allowRepeated && !isEmpty()) {
510 const CoordinateXY& last = back<CoordinateXY>();
511 if(last.equals2D(c)) {
512 return;
513 }
514 }
515
516 add(c);
517 }
518
527 template<typename T>
528 void add(const T& c, std::size_t pos)
529 {
530 static_assert(std::is_base_of<CoordinateXY, T>::value, "Must be a Coordinate class");
531
532 // c may be a reference inside m_vect, so we make sure it will not
533 // grow before adding it
534 if (m_vect.size() + stride() <= m_vect.capacity()) {
535 make_space(pos, 1);
536 setAt(c, static_cast<std::size_t>(pos));
537 } else {
538 T tmp{c};
539 make_space(pos, 1);
540 setAt(tmp, static_cast<std::size_t>(pos));
541 }
542 }
543
553 template<typename T>
554 void add(std::size_t i, const T& coord, bool allowRepeated)
555 {
556 // don't add duplicate coordinates
557 if(! allowRepeated) {
558 std::size_t sz = size();
559 if(sz > 0) {
560 if(i > 0) {
561 const CoordinateXY& prev = getAt<CoordinateXY>(i - 1);
562 if(prev.equals2D(coord)) {
563 return;
564 }
565 }
566 if(i < sz) {
567 const CoordinateXY& next = getAt<CoordinateXY>(i);
568 if(next.equals2D(coord)) {
569 return;
570 }
571 }
572 }
573 }
574
575 add(coord, i);
576 }
577
578 void add(double x, double y) {
579 CoordinateXY c(x, y);
580 add(c);
581 }
582
583 void add(const CoordinateSequence& cs);
584
585 void add(const CoordinateSequence& cs, bool allowRepeated);
586
587 void add(const CoordinateSequence& cl, bool allowRepeated, bool forwardDirection);
588
590 void add(const CoordinateSequence& cs, std::size_t from, std::size_t to);
591
593 void add(const CoordinateSequence& cs, std::size_t from, std::size_t to, bool allowRepeated);
594
595 template<typename T, typename... Args>
596 void add(T begin, T end, Args... args) {
597 for (auto it = begin; it != end; ++it) {
598 add(*it, args...);
599 }
600 }
601
602 template<typename T>
603 void add(std::size_t i, T from, T to) {
604 auto npts = static_cast<std::size_t>(std::distance(from, to));
605 make_space(i, npts);
606
607 for (auto it = from; it != to; ++it) {
608 setAt(*it, i);
609 i++;
610 }
611 }
612
616
617 void clear() {
618 m_vect.clear();
619 }
620
621 void reserve(std::size_t capacity) {
622 m_vect.reserve(capacity * stride());
623 }
624
625 void resize(std::size_t capacity) {
626 m_vect.resize(capacity * stride());
627 }
628
629 void pop_back();
630
632 std::string toString() const;
633
636 const CoordinateXY* minCoordinate() const;
637
640 std::size_t minCoordinateIndex() const;
641
648
650 //
653 static std::size_t indexOf(const CoordinateXY* coordinate,
654 const CoordinateSequence* cl);
655
661 static bool equals(const CoordinateSequence* cl1,
662 const CoordinateSequence* cl2);
663
669 bool equalsIdentical(const CoordinateSequence& other) const;
670
672 static void scroll(CoordinateSequence* cl, const CoordinateXY* firstCoordinate);
673 void scroll(const CoordinateXY* firstCoordinate);
674 void scroll(std::size_t firstCoordinateIndex);
675
694
696 void reverse();
697
698 void sort();
699
701 void swap(std::size_t i, std::size_t j);
702
708 void expandEnvelope(Envelope& env) const;
709
710 void closeRing(bool allowRepeated = false);
711
715
716 template<typename Filter>
717 void apply_rw(const Filter* filter) {
718 switch(getCoordinateType()) {
719 case CoordinateType::XY:
720 for (auto& c : items<CoordinateXY>()) {
721 if (filter->isDone()) break;
722 filter->filter_rw(&c);
723 }
724 break;
725 case CoordinateType::XYZ:
726 for (auto& c : items<Coordinate>()) {
727 if (filter->isDone()) break;
728 filter->filter_rw(&c);
729 }
730 break;
731 case CoordinateType::XYM:
732 for (auto& c : items<CoordinateXYM>()) {
733 if (filter->isDone()) break;
734 filter->filter_rw(&c);
735 }
736 break;
737 case CoordinateType::XYZM:
738 for (auto& c : items<CoordinateXYZM>()) {
739 if (filter->isDone()) break;
740 filter->filter_rw(&c);
741 }
742 break;
743 }
744 m_hasdim = m_hasz = false; // re-check (see http://trac.osgeo.org/geos/ticket/435)
745 }
746
747 template<typename Filter>
748 void apply_ro(Filter* filter) const {
749 switch(getCoordinateType()) {
750 case CoordinateType::XY:
751 for (const auto& c : items<CoordinateXY>()) {
752 if (filter->isDone()) break;
753 filter->filter_ro(&c);
754 }
755 break;
756 case CoordinateType::XYZ:
757 for (const auto& c : items<Coordinate>()) {
758 if (filter->isDone()) break;
759 filter->filter_ro(&c);
760 }
761 break;
762 case CoordinateType::XYM:
763 for (const auto& c : items<CoordinateXYM>()) {
764 if (filter->isDone()) break;
765 filter->filter_ro(&c);
766 }
767 break;
768 case CoordinateType::XYZM:
769 for (const auto& c : items<CoordinateXYZM>()) {
770 if (filter->isDone()) break;
771 filter->filter_ro(&c);
772 }
773 break;
774 }
775 }
776
777 template<typename F>
778 auto applyAt(size_t i, F&& fun) const {
779 switch(getCoordinateType()) {
780 case CoordinateType::XYZ: return fun(getAt<Coordinate>(i));
781 case CoordinateType::XYM: return fun(getAt<CoordinateXYM>(i));
782 case CoordinateType::XYZM: return fun(getAt<CoordinateXYZM>(i));
783 default: return fun(getAt<CoordinateXY>(i));
784 }
785 }
786
787 template<typename F>
788 void forEach(F&& fun) const {
789 switch(getCoordinateType()) {
790 case CoordinateType::XY: for (const auto& c : items<CoordinateXY>()) { fun(c); } break;
791 case CoordinateType::XYZ: for (const auto& c : items<Coordinate>()) { fun(c); } break;
792 case CoordinateType::XYM: for (const auto& c : items<CoordinateXYM>()) { fun(c); } break;
793 case CoordinateType::XYZM: for (const auto& c : items<CoordinateXYZM>()) { fun(c); } break;
794 }
795 }
796
797 template<typename T, typename F>
798 void forEach(F&& fun) const
799 {
800 for (std::size_t i = 0; i < size(); i++) {
801 fun(getAt<T>(i));
802 }
803 }
804
805 template<typename F>
806 void forEachSegment(F&& fun) const {
807 switch(getCoordinateType()) {
808 case CoordinateType::XY: forEachSegmentImpl<CoordinateXY, F>(std::move(fun)); break;
809 case CoordinateType::XYZ: forEachSegmentImpl<Coordinate, F>(std::move(fun)); break;
810 case CoordinateType::XYM: forEachSegmentImpl<CoordinateXYM, F>(std::move(fun)); break;
811 case CoordinateType::XYZM: forEachSegmentImpl<CoordinateXYZM, F>(std::move(fun)); break;
812 }
813 }
814
815 template<typename T, typename F>
816 void forEach(std::size_t from, std::size_t to, F&& fun) const
817 {
818 for (std::size_t i = from; i <= to; i++) {
819 fun(getAt<T>(i));
820 }
821 }
822
823 template<typename T>
824 class Coordinates {
825 public:
826 using SequenceType = typename std::conditional<std::is_const<T>::value, const CoordinateSequence, CoordinateSequence>::type;
827
828 explicit Coordinates(SequenceType* seq) : m_seq(seq) {}
829
830 CoordinateSequenceIterator<SequenceType, T> begin() {
831 return {m_seq};
832 }
833
834 CoordinateSequenceIterator<SequenceType, T> end() {
835 return {m_seq, m_seq->getSize()};
836 }
837
838 CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>
839 begin() const {
840 return CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>{m_seq};
841 }
842
843 CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>
844 end() const {
845 return CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>{m_seq, m_seq->getSize()};
846 }
847
848 CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>
849 cbegin() const {
850 return CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>{m_seq};
851 }
852
853 CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>
854 cend() const {
855 return CoordinateSequenceIterator<const SequenceType, typename std::add_const<T>::type>{m_seq, m_seq->getSize()};
856 }
857
858 private:
859 SequenceType* m_seq;
860 };
861
862 template<typename T>
863 Coordinates<typename std::add_const<T>::type> items() const {
864 return Coordinates<typename std::add_const<T>::type>(this);
865 }
866
867 template<typename T>
868 Coordinates<T> items() {
869 return Coordinates<T>(this);
870 }
871
872
874
875 double* data() {
876 return m_vect.data();
877 }
878
879 const double* data() const {
880 return m_vect.data();
881 }
882
883private:
884 std::vector<double> m_vect; // Vector to store values
885
886 uint8_t m_stride; // Stride of stored values, corresponding to underlying type
887
888 mutable bool m_hasdim; // Has the dimension of this sequence been determined? Or was it created with no
889 // explicit dimensionality, and we're waiting for getDimension() to be called
890 // after some coordinates have been added?
891 mutable bool m_hasz;
892 bool m_hasm;
893
894 void initialize();
895
896 template<typename T1, typename T2>
897 void setAtImpl(const T2& c, std::size_t pos) {
898 auto& orig = getAt<T1>(pos);
899 orig = c;
900 }
901
902 template<typename CoordType, typename F>
903 void forEachSegmentImpl(F&& fun) const {
904 auto p0it = items<CoordType>().cbegin();
905 const auto end = items<CoordType>().end();
906
907 if (p0it == end) {
908 return;
909 }
910
911 auto p1it = std::next(p0it);
912
913 while (p1it != end) {
914 fun(*p0it, *p1it);
915 ++p0it;
916 ++p1it;
917 }
918 }
919
920 void make_space(std::size_t pos, std::size_t n) {
921 m_vect.insert(std::next(m_vect.begin(), static_cast<std::ptrdiff_t>(pos * stride())),
922 m_stride * n,
923 DoubleNotANumber);
924 }
925
926 std::uint8_t stride() const {
927 return m_stride;
928 }
929
930};
931
932GEOS_DLL std::ostream& operator<< (std::ostream& os, const CoordinateSequence& cs);
933
934GEOS_DLL bool operator== (const CoordinateSequence& s1, const CoordinateSequence& s2);
935
936GEOS_DLL bool operator!= (const CoordinateSequence& s1, const CoordinateSequence& s2);
937
938} // namespace geos::geom
939} // namespace geos
940
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:220
An Envelope defines a rectangulare region of the 2D coordinate plane.
Definition Envelope.h:59
T & getAt(std::size_t i)
Returns a reference to Coordinate at position i.
Definition CoordinateSequence.h:268
Coordinate & operator[](std::size_t i)
Definition CoordinateSequence.h:308
void setM(std::size_t index, double m)
Definition CoordinateSequence.h:415
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:437
void setX(std::size_t index, double x)
Definition CoordinateSequence.h:377
T & back()
Return last Coordinate in the sequence.
Definition CoordinateSequence.h:430
void getAt(std::size_t i, T &c) const
Write Coordinate at position i to given Coordinate.
Definition CoordinateSequence.h:280
const T & getAt(std::size_t i) const
Returns a read-only reference to Coordinate at position i.
Definition CoordinateSequence.h:256
T & front()
Return first Coordinate in the sequence.
Definition CoordinateSequence.h:444
double getZ(std::size_t index) const
Definition CoordinateSequence.h:354
double getX(std::size_t index) const
Definition CoordinateSequence.h:331
void setY(std::size_t index, double y)
Definition CoordinateSequence.h:388
double getY(std::size_t index) const
Definition CoordinateSequence.h:342
void setZ(std::size_t index, double z)
Definition CoordinateSequence.h:401
const Coordinate & operator[](std::size_t i) const
Definition CoordinateSequence.h:298
const T & back() const
Return last Coordinate in the sequence.
Definition CoordinateSequence.h:423
double getM(std::size_t index) const
Definition CoordinateSequence.h:366
void add(const CoordinateSequence &cs, std::size_t from, std::size_t to)
Add the portion of a CoordinateSequence between the specified indices (inclusive)
void add(const T &c, bool allowRepeated)
Definition CoordinateSequence.h:507
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:554
void add(const T &c)
Definition CoordinateSequence.h:496
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:528
void add(const CoordinateSequence &cs, std::size_t from, std::size_t to, bool allowRepeated)
Add the portion of a CoordinateSequence between the specified indices (inclusive)
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:461
void setPoints(const std::vector< CoordinateXY > &v)
Substitute Coordinate list with a copy of the given vector.
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 hasRepeatedPoints() const
Returns true if contains any two consecutive points.
void setZM(bool hasZ, bool hasM)
CoordinateType getCoordinateType() const
Definition CoordinateSequence.h:240
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
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::size_t minCoordinateIndex() const
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.
void swap(std::size_t i, std::size_t j)
Swap the coordinates at two indices.
Basic namespace for all GEOS functionalities.
Definition geos.h:38