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
30 namespace geos {
31 namespace geom {
32 class Envelope;
33 class CoordinateFilter;
34 }
35 }
36 
37 namespace geos {
38 namespace geom { // geos::geom
39 
56 class GEOS_DLL CoordinateSequence {
57 
58 public:
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 
173  Envelope getEnvelope() const;
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 
242  bool hasRepeatedOrInvalidPoints() const;
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
314  Coordinate&
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 
569  static CoordinateSequence* atLeastNCoordinatesOrNothing(std::size_t n,
570  CoordinateSequence* c);
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 
614  static int increasingDirection(const CoordinateSequence& pts);
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 
742 private:
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 
773 GEOS_DLL std::ostream& operator<< (std::ostream& os, const CoordinateSequence& cs);
774 
775 GEOS_DLL bool operator== (const CoordinateSequence& s1, const CoordinateSequence& s2);
776 
777 GEOS_DLL bool operator!= (const CoordinateSequence& s1, const CoordinateSequence& s2);
778 
779 } // namespace geos::geom
780 } // namespace geos
781 
static CoordinateSequence XYM(std::size_t size)
Definition: CoordinateSequence.h:155
size_t size() const
Returns the number of Coordinates.
Definition: CoordinateSequence.h:185
An Envelope defines a rectangulare region of the 2D coordinate plane.
Definition: Envelope.h:58
static CoordinateSequence XYZM(std::size_t size)
Definition: CoordinateSequence.h:146
bool isEmpty() const
Returns true if list contains no coordinates.
Definition: CoordinateSequence.h:196
double getY(std::size_t index) const
Definition: CoordinateSequence.h:349
CoordinateType getCoordinateType() const
Definition: CoordinateSequence.h:247
bool isNullPoint() const
Returns true if there is 1 coordinate and if it is null.
Definition: CoordinateSequence.h:201
Coordinate is the lightweight class used to store coordinates.
Definition: Coordinate.h:216
T & getAt(std::size_t i)
Returns a reference to Coordinate at position i.
Definition: CoordinateSequence.h:275
const T & front() const
Return first Coordinate in the sequence.
Definition: CoordinateSequence.h:370
double getX(std::size_t index) const
Definition: CoordinateSequence.h:338
void add(const T &c, bool allowRepeated)
Definition: CoordinateSequence.h:437
std::size_t getSize() const
Returns the number of Coordinates.
Definition: CoordinateSequence.h:178
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
Basic namespace for all GEOS functionalities.
Definition: Angle.h:25
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
void add(const T &c)
Definition: CoordinateSequence.h:426
T & back()
Return last Coordinate in the sequence.
Definition: CoordinateSequence.h:363
static CoordinateSequence XY(std::size_t size)
Definition: CoordinateSequence.h:128
void setAt(const T &c, std::size_t pos)
Copy Coordinate c to position pos.
Definition: CoordinateSequence.h:394
void getAt(std::size_t i, T &c) const
Write Coordinate at position i to given Coordinate.
Definition: CoordinateSequence.h:287
The internal representation of a list of coordinates inside a Geometry.
Definition: CoordinateSequence.h:56
const Coordinate & operator[](std::size_t i) const
Definition: CoordinateSequence.h:305
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
Coordinate & operator[](std::size_t i)
Definition: CoordinateSequence.h:315
const T & back() const
Return last Coordinate in the sequence.
Definition: CoordinateSequence.h:356
static CoordinateSequence XYZ(std::size_t size)
Definition: CoordinateSequence.h:137