QGIS API Documentation  3.19.0-Master (ceff950960)
qgsrange.h
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrange.h
3  ----------
4  begin : April 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #ifndef QGSRANGE_H
19 #define QGSRANGE_H
20 
21 #include "qgis_sip.h"
22 #include "qgis_core.h"
23 #include "qgis.h"
24 
25 #include <QDate>
26 #include <QDateTime>
27 
45 template <typename T>
46 class QgsRange
47 {
48  public:
49 
54  QgsRange( T lower, T upper, bool includeLower = true, bool includeUpper = true )
55  : mLower( lower )
56  , mUpper( upper )
59  {}
60 
66  T lower() const { return mLower; }
67 
73  T upper() const { return mUpper; }
74 
81  bool includeLower() const { return mIncludeLower; }
82 
89  bool includeUpper() const { return mIncludeUpper; }
90 
96  bool isEmpty() const { return mLower > mUpper || ( mUpper == mLower && !( mIncludeLower || mIncludeUpper ) ); }
97 
102  bool isSingleton() const { return mLower == mUpper && ( mIncludeLower || mIncludeUpper ); }
103 
108  bool contains( const QgsRange<T> &other ) const
109  {
110  bool lowerOk = ( mIncludeLower && mLower <= other.mLower )
111  || ( !mIncludeLower && mLower < other.mLower )
112  || ( !mIncludeLower && !other.mIncludeLower && mLower <= other.mLower );
113  if ( !lowerOk )
114  return false;
115 
116  bool upperOk = ( mIncludeUpper && mUpper >= other.mUpper )
117  || ( !mIncludeUpper && mUpper > other.mUpper )
118  || ( !mIncludeUpper && !other.mIncludeUpper && mUpper >= other.mUpper );
119  if ( !upperOk )
120  return false;
121 
122  return true;
123  }
124 
128  bool contains( T element ) const
129  {
130  bool lowerOk = ( mIncludeLower && mLower <= element )
131  || ( !mIncludeLower && mLower < element );
132  if ( !lowerOk )
133  return false;
134 
135  bool upperOk = ( mIncludeUpper && mUpper >= element )
136  || ( !mIncludeUpper && mUpper > element );
137  if ( !upperOk )
138  return false;
139 
140  return true;
141  }
142 
147  bool overlaps( const QgsRange<T> &other ) const
148  {
149  if ( ( ( mIncludeLower && mLower <= other.mLower ) || ( !mIncludeLower && mLower < other.mLower ) )
150  && ( ( mIncludeUpper && mUpper >= other.mUpper ) || ( !mIncludeUpper && mUpper > other.mUpper ) ) )
151  return true;
152 
153  if ( ( ( mIncludeLower && mLower <= other.mLower ) || ( !mIncludeLower && mLower < other.mLower ) )
154  && ( ( mIncludeUpper && mUpper >= other.mLower ) || ( !mIncludeUpper && mUpper > other.mLower ) ) )
155  return true;
156 
157  if ( ( ( mIncludeLower && mLower <= other.mUpper ) || ( !mIncludeLower && mLower < other.mUpper ) )
158  && ( ( mIncludeUpper && mUpper >= other.mUpper ) || ( !mIncludeUpper && mUpper > other.mUpper ) ) )
159  return true;
160 
161  if ( ( ( mIncludeLower && mLower >= other.mLower ) || ( !mIncludeLower && mLower > other.mLower ) )
162  && ( ( mIncludeLower && mLower <= other.mUpper ) || ( !mIncludeLower && mLower < other.mUpper ) ) )
163  return true;
164 
165  if ( mLower == other.mLower && mUpper == other.mUpper )
166  return true;
167 
168  return false;
169  }
170 
171  bool operator==( const QgsRange<T> &other ) const
172  {
173  return mLower == other.mLower &&
174  mUpper == other.mUpper &&
175  mIncludeLower == other.includeLower() &&
176  mIncludeUpper == other.includeUpper();
177  }
178 
179  bool operator!=( const QgsRange<T> &other ) const
180  {
181  return ( ! operator==( other ) );
182  }
183 
184  protected:
185 
188  bool mIncludeLower = true;
189  bool mIncludeUpper = true;
190 
191 };
192 
193 
202 class CORE_EXPORT QgsDoubleRange : public QgsRange< double >
203 {
204  public:
205 
206 #ifndef SIP_RUN
207 
216  QgsDoubleRange( double lower = std::numeric_limits< double >::lowest(),
217  double upper = std::numeric_limits< double >::max(),
218  bool includeLower = true, bool includeUpper = true )
219  : QgsRange( lower, upper, includeLower, includeUpper )
220  {}
221 #else
222 
227  QgsDoubleRange( double lower,
228  double upper,
229  bool includeLower = true, bool includeUpper = true )
230  : QgsRange( lower, upper, includeLower, includeUpper )
231  {}
232 
239  : QgsRange( std::numeric_limits< double >::lowest(), std::numeric_limits< double >::max(), true, true )
240  {}
241 #endif
242 
247  bool isInfinite() const
248  {
249  return lower() == std::numeric_limits< double >::lowest() && upper() == std::numeric_limits< double >::max();
250  }
251 
252 #ifdef SIP_RUN
253  SIP_PYOBJECT __repr__();
254  % MethodCode
255  QString str = QStringLiteral( "<QgsDoubleRange: %1%2, %3%4>" ).arg( sipCpp->includeLower() ? QStringLiteral( "[" ) : QStringLiteral( "(" ) )
256  .arg( sipCpp->lower() )
257  .arg( sipCpp->upper() )
258  .arg( sipCpp->includeUpper() ? QStringLiteral( "]" ) : QStringLiteral( ")" ) );
259  sipRes = PyUnicode_FromString( str.toUtf8().constData() );
260  % End
261 #endif
262 
263  bool operator==( const QgsDoubleRange &other ) const
264  {
265  return qgsDoubleNear( mLower, other.mLower ) &&
266  qgsDoubleNear( mUpper, other.mUpper ) &&
267  mIncludeLower == other.includeLower() &&
268  mIncludeUpper == other.includeUpper();
269  }
270 
271  bool operator!=( const QgsDoubleRange &other ) const
272  {
273  return ( ! operator==( other ) );
274  }
275 
276 };
277 
278 
287 class CORE_EXPORT QgsIntRange : public QgsRange< int >
288 {
289  public:
290 
291 #ifndef SIP_RUN
292 
301  QgsIntRange( int lower = std::numeric_limits< int >::lowest(),
302  int upper = std::numeric_limits< int >::max(),
303  bool includeLower = true, bool includeUpper = true )
304  : QgsRange( lower, upper, includeLower, includeUpper )
305  {}
306 #else
307 
312  QgsIntRange( int lower,
313  int upper,
314  bool includeLower = true, bool includeUpper = true )
315  : QgsRange( lower, upper, includeLower, includeUpper )
316  {}
317 
323  QgsIntRange()
324  : QgsRange( std::numeric_limits< int >::lowest(), std::numeric_limits< int >::max(), true, true )
325  {}
326 #endif
327 
332  bool isInfinite() const
333  {
334  return lower() == std::numeric_limits< int >::lowest() && upper() == std::numeric_limits< int >::max();
335  }
336 
337 #ifdef SIP_RUN
338  SIP_PYOBJECT __repr__();
339  % MethodCode
340  QString str = QStringLiteral( "<QgsIntRange: %1%2, %3%4>" ).arg( sipCpp->includeLower() ? QStringLiteral( "[" ) : QStringLiteral( "(" ) )
341  .arg( sipCpp->lower() )
342  .arg( sipCpp->upper() )
343  .arg( sipCpp->includeUpper() ? QStringLiteral( "]" ) : QStringLiteral( ")" ) );
344  sipRes = PyUnicode_FromString( str.toUtf8().constData() );
345  % End
346 #endif
347 
348 };
349 
350 
367 template <typename T>
369 {
370  public:
371 
377 #ifndef SIP_RUN
378  QgsTemporalRange( const T &begin = T(), const T &end = T(), bool includeBeginning = true, bool includeEnd = true )
379  : mLower( begin )
380  , mUpper( end )
381  , mIncludeLower( includeBeginning )
382  , mIncludeUpper( includeEnd )
383  {}
384 #else
385  QgsTemporalRange( const T &begin, const T &end, bool includeBeginning = true, bool includeEnd = true );
386  // default constructor as default value for templates is not handled in SIP
387 #endif
388 
394  T begin() const { return mLower; }
395 
401  T end() const { return mUpper; }
402 
409  bool includeBeginning() const { return mIncludeLower; }
410 
416  bool includeEnd() const { return mIncludeUpper; }
417 
423  bool isInstant() const { return mLower.isValid() && mUpper.isValid() && mLower == mUpper && ( mIncludeLower || mIncludeUpper ); }
424 
430  bool isInfinite() const
431  {
432  return !mLower.isValid() && !mUpper.isValid();
433  }
434 
440  bool isEmpty() const
441  {
442  if ( !mLower.isValid() && !mUpper.isValid() )
443  return false;
444 
445  if ( mLower.isValid() != mUpper.isValid() )
446  return false;
447 
448  if ( mLower > mUpper )
449  return true;
450 
451  if ( mLower == mUpper && !( mIncludeLower || mIncludeUpper ) )
452  return true;
453 
454  return false;
455  }
456 
460  bool contains( const QgsTemporalRange<T> &other ) const
461  {
462  if ( !other.mLower.isValid() && mLower.isValid() )
463  return false;
464 
465  if ( mLower.isValid() )
466  {
467  bool lowerOk = ( mIncludeLower && mLower <= other.mLower )
468  || ( !mIncludeLower && mLower < other.mLower )
469  || ( !mIncludeLower && !other.mIncludeLower && mLower <= other.mLower );
470  if ( !lowerOk )
471  return false;
472  }
473 
474  if ( !other.mUpper.isValid() && mUpper.isValid() )
475  return false;
476 
477  if ( mUpper.isValid() )
478  {
479  bool upperOk = ( mIncludeUpper && mUpper >= other.mUpper )
480  || ( !mIncludeUpper && mUpper > other.mUpper )
481  || ( !mIncludeUpper && !other.mIncludeUpper && mUpper >= other.mUpper );
482  if ( !upperOk )
483  return false;
484  }
485 
486  return true;
487  }
488 
492  bool contains( const T &element ) const
493  {
494  if ( !element.isValid() )
495  return false;
496 
497  if ( mLower.isValid() )
498  {
499  bool lowerOk = ( mIncludeLower && mLower <= element )
500  || ( !mIncludeLower && mLower < element );
501  if ( !lowerOk )
502  return false;
503  }
504 
505  if ( mUpper.isValid() )
506  {
507  bool upperOk = ( mIncludeUpper && mUpper >= element )
508  || ( !mIncludeUpper && mUpper > element );
509  if ( !upperOk )
510  return false;
511  }
512 
513  return true;
514  }
515 
519  bool overlaps( const QgsTemporalRange<T> &other ) const
520  {
521  if ( !mUpper.isValid() && ( ( mIncludeLower && mLower <= other.mUpper ) || ( !mIncludeLower && mLower < other.mUpper ) ) )
522  return true;
523 
524  if ( ( ( mIncludeLower && mLower <= other.mLower ) || ( !mIncludeLower && mLower < other.mLower ) )
525  && ( ( mIncludeUpper && mUpper >= other.mUpper ) || ( !mIncludeUpper && mUpper > other.mUpper ) ) )
526  return true;
527 
528  if ( ( ( mIncludeLower && mLower <= other.mLower ) || ( !mIncludeLower && mLower < other.mLower ) )
529  && ( ( mIncludeUpper && mUpper >= other.mLower ) || ( !mIncludeUpper && mUpper > other.mLower ) ) )
530  return true;
531 
532  if ( ( ( mIncludeLower && mLower <= other.mUpper ) || ( !mIncludeLower && mLower < other.mUpper ) )
533  && ( ( mIncludeUpper && mUpper >= other.mUpper ) || ( !mIncludeUpper && mUpper > other.mUpper ) ) )
534  return true;
535 
536  if ( ( ( mIncludeLower && mLower >= other.mLower ) || ( !mIncludeLower && mLower > other.mLower ) )
537  && ( ( mIncludeLower && mLower <= other.mUpper ) || ( !mIncludeLower && mLower < other.mUpper ) ) )
538  return true;
539 
540  if ( mLower == other.mLower && mUpper == other.mUpper )
541  return true;
542 
543  return false;
544  }
545 
554  bool extend( const QgsTemporalRange<T> &other )
555  {
556  if ( other.isEmpty() )
557  {
558  return false;
559  }
560  else if ( isEmpty() )
561  {
562  mLower = other.begin();
563  mUpper = other.end();
564  mIncludeLower = other.includeBeginning();
565  mIncludeUpper = other.includeEnd();
566  return true;
567  }
568 
569  // Both not empty, do some math
570  bool changed { false };
571 
572  // Lower
573  if ( ! other.begin().isValid()
574  || ( begin().isValid() && other.begin() < mLower ) )
575  {
576  mLower = other.begin();
577  mIncludeLower = other.includeBeginning();
578  changed = true;
579  }
580  else if ( other.begin() == mLower && other.includeBeginning() && ! mIncludeLower )
581  {
582  mIncludeLower = true;
583  changed = true;
584  }
585 
586  // Upper
587  if ( ! other.end().isValid()
588  || ( end().isValid() && other.end() > mUpper ) )
589  {
590  mUpper = other.end();
591  mIncludeUpper = other.includeEnd();
592  changed = true;
593  }
594  else if ( other.end() == mUpper && other.includeEnd() && ! mIncludeUpper )
595  {
596  mIncludeUpper = true;
597  changed = true;
598  }
599  return changed;
600  }
601 
602 #ifndef SIP_RUN
603 
617  static QList< QgsTemporalRange<T> > mergeRanges( const QList< QgsTemporalRange<T> > &ranges )
618  {
619  if ( ranges.empty() )
620  return {};
621 
622  QList< QgsTemporalRange<T > > sortedRanges = ranges;
623  std::sort( sortedRanges.begin(), sortedRanges.end(), []( const QgsTemporalRange< T > &a, const QgsTemporalRange< T > &b ) -> bool { return a.begin() < b.begin(); } );
624  QList< QgsTemporalRange<T>> res;
625  res.reserve( sortedRanges.size() );
626 
627  QgsTemporalRange<T> prevRange;
628  auto it = sortedRanges.constBegin();
629  prevRange = *it++;
630  for ( ; it != sortedRanges.constEnd(); ++it )
631  {
632  if ( prevRange.overlaps( *it ) )
633  {
634  prevRange.extend( *it );
635  }
636  else
637  {
638  res << prevRange;
639  prevRange = *it;
640  }
641  }
642  res << prevRange;
643  return res;
644  }
645 #endif
646 
647  bool operator==( const QgsTemporalRange<T> &other ) const
648  {
649  return mLower == other.mLower &&
650  mUpper == other.mUpper &&
651  mIncludeLower == other.includeBeginning() &&
652  mIncludeUpper == other.includeEnd();
653  }
654 
655  bool operator!=( const QgsTemporalRange<T> &other ) const
656  {
657  return ( ! operator==( other ) );
658  }
659 
660  private:
661 
662  T mLower;
663  T mUpper;
664  bool mIncludeLower = true;
665  bool mIncludeUpper = true;
666 };
667 
668 
680 
681 Q_DECLARE_METATYPE( QgsDateRange )
682 
683 
693 typedef QgsTemporalRange< QDateTime > QgsDateTimeRange SIP_DOC_TEMPLATE;
694 
695 Q_DECLARE_METATYPE( QgsDateTimeRange )
696 
697 #endif // QGSRANGE_H
QgsRange which stores a range of double values.
Definition: qgsrange.h:203
QgsDoubleRange(double lower=std::numeric_limits< double >::lowest(), double upper=std::numeric_limits< double >::max(), bool includeLower=true, bool includeUpper=true)
Constructor for QgsDoubleRange.
Definition: qgsrange.h:216
bool operator==(const QgsDoubleRange &other) const
Definition: qgsrange.h:263
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition: qgsrange.h:247
bool operator!=(const QgsDoubleRange &other) const
Definition: qgsrange.h:271
QgsRange which stores a range of integer values.
Definition: qgsrange.h:288
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition: qgsrange.h:332
QgsIntRange(int lower=std::numeric_limits< int >::lowest(), int upper=std::numeric_limits< int >::max(), bool includeLower=true, bool includeUpper=true)
Constructor for QgsIntRange.
Definition: qgsrange.h:301
A template based class for storing ranges (lower to upper values).
Definition: qgsrange.h:47
bool mIncludeLower
Definition: qgsrange.h:188
bool includeUpper() const
Returns true if the upper bound is inclusive, or false if the upper bound is exclusive.
Definition: qgsrange.h:89
bool overlaps(const QgsRange< T > &other) const
Returns true if this range overlaps another range.
Definition: qgsrange.h:147
QgsRange(T lower, T upper, bool includeLower=true, bool includeUpper=true)
Constructor for QgsRange.
Definition: qgsrange.h:54
bool contains(const QgsRange< T > &other) const
Returns true if this range contains another range.
Definition: qgsrange.h:108
T lower() const
Returns the lower bound of the range.
Definition: qgsrange.h:66
bool includeLower() const
Returns true if the lower bound is inclusive, or false if the lower bound is exclusive.
Definition: qgsrange.h:81
bool mIncludeUpper
Definition: qgsrange.h:189
T upper() const
Returns the upper bound of the range.
Definition: qgsrange.h:73
bool isSingleton() const
Returns true if the range consists only of a single value or instant.
Definition: qgsrange.h:102
T mUpper
Definition: qgsrange.h:187
bool operator!=(const QgsRange< T > &other) const
Definition: qgsrange.h:179
bool contains(T element) const
Returns true if this range contains a specified element.
Definition: qgsrange.h:128
bool operator==(const QgsRange< T > &other) const
Definition: qgsrange.h:171
bool isEmpty() const
Returns true if the range is empty, ie the lower bound equals (or exceeds) the upper bound and either...
Definition: qgsrange.h:96
T mLower
Definition: qgsrange.h:186
A template based class for storing temporal ranges (beginning to end values).
Definition: qgsrange.h:369
static QList< QgsTemporalRange< T > > mergeRanges(const QList< QgsTemporalRange< T > > &ranges)
Merges a list of temporal ranges.
Definition: qgsrange.h:617
bool contains(const T &element) const
Returns true if this range contains a specified element.
Definition: qgsrange.h:492
T begin() const
Returns the beginning of the range.
Definition: qgsrange.h:394
bool contains(const QgsTemporalRange< T > &other) const
Returns true if this range contains another range.
Definition: qgsrange.h:460
bool extend(const QgsTemporalRange< T > &other)
Extends the range in place by extending this range out to include an other range.
Definition: qgsrange.h:554
T end() const
Returns the upper bound of the range.
Definition: qgsrange.h:401
bool isInstant() const
Returns true if the range consists only of a single instant.
Definition: qgsrange.h:423
bool operator!=(const QgsTemporalRange< T > &other) const
Definition: qgsrange.h:655
QgsTemporalRange(const T &begin=T(), const T &end=T(), bool includeBeginning=true, bool includeEnd=true)
Constructor for QgsTemporalRange.
Definition: qgsrange.h:378
bool operator==(const QgsTemporalRange< T > &other) const
Definition: qgsrange.h:647
bool overlaps(const QgsTemporalRange< T > &other) const
Returns true if this range overlaps another range.
Definition: qgsrange.h:519
bool includeEnd() const
Returns true if the end is inclusive, or false if the end is exclusive.
Definition: qgsrange.h:416
bool includeBeginning() const
Returns true if the beginning is inclusive, or false if the beginning is exclusive.
Definition: qgsrange.h:409
bool isEmpty() const
Returns true if the range is empty, ie the beginning equals (or exceeds) the end and either of the bo...
Definition: qgsrange.h:440
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition: qgsrange.h:430
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:407
#define str(x)
Definition: qgis.cpp:37
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:343
Q_DECLARE_METATYPE(QgsMeshTimeSettings)
QgsTemporalRange< QDate > QgsDateRange SIP_DOC_TEMPLATE
QgsRange which stores a range of dates.
Definition: qgsrange.h:679