QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
45template <typename T>
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 const 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 const 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 const bool lowerOk = ( mIncludeLower && mLower <= element )
131 || ( !mIncludeLower && mLower < element );
132 if ( !lowerOk )
133 return false;
134
135 const 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
202class 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
287class 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
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
367template <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 const 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 const 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 const bool lowerOk = ( mIncludeLower && mLower <= element )
500 || ( !mIncludeLower && mLower < element );
501 if ( !lowerOk )
502 return false;
503 }
504
505 if ( mUpper.isValid() )
506 {
507 const 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
681Q_DECLARE_METATYPE( QgsDateRange )
682
683
693typedef QgsTemporalRange< QDateTime > QgsDateTimeRange SIP_DOC_TEMPLATE;
694
695Q_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
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
static QList< QgsTemporalRange< T > > mergeRanges(const QList< QgsTemporalRange< T > > &ranges)
Merges a list of temporal ranges.
Definition: qgsrange.h:617
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:2527
Q_DECLARE_METATYPE(QgsDatabaseQueryLogEntry)
QgsTemporalRange< QDate > QgsDateRange SIP_DOC_TEMPLATE
QgsRange which stores a range of dates.
Definition: qgsrange.h:679