ACF $AcfVersion:0$
TRanges.h
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-2.1-or-later OR GPL-2.0-or-later OR GPL-3.0-or-later OR LicenseRef-ACF-Commercial
2#pragma once
3
4
5// STL includes
6#include <set>
7#include <vector>
8
9// Qt includes
10#include <QtCore/QList>
11
12// ACF includes
13#include <istd/TRange.h>
14
15
16namespace istd
17{
18
19
25template <typename ValueType>
27{
28public:
29 typedef QList< TRange<ValueType> > RangeList;
30 typedef std::vector< TRange<ValueType> > RangeVector;
31 typedef std::set<ValueType> SwitchPoints;
32
36 TRanges();
37
41 explicit TRanges(const istd::TRange<ValueType>& range);
42
46 void Reset();
47
52 bool IsEmpty() const;
53
57 const SwitchPoints& GetSwitchPoints() const;
62
68 void InsertSwitchPoint(ValueType point);
69
74 bool GetBeginState() const;
80 void SetBeginState(bool state);
81
85 bool IsInside(ValueType point) const;
86
90 bool IsInside(const TRange<ValueType>& range) const;
91
95 bool IsInside(const TRanges<ValueType>& rangesList) const;
96
100 void GetInverted(TRanges<ValueType>& result, const TRange<ValueType>* clipRangePtr) const;
101
105 void Invert(const TRange<ValueType>* clipRangePtr);
106
110 TRanges<ValueType> GetUnion(const TRanges<ValueType>& rangesList) const;
111
116 void GetUnion(const TRanges<ValueType>& rangesList, TRanges<ValueType>& result) const;
117
122 void Union(const TRanges<ValueType>& rangesList);
123
128 void Union(const TRange<ValueType>& range, bool isInverted = false);
129
134
139 void GetIntersection(const TRanges<ValueType>& rangesList, TRanges<ValueType>& result) const;
140
145 void Intersection(const TRanges<ValueType>& rangesList);
146
151 void Intersection(const TRange<ValueType>& range, bool isInverted = false);
152
158 void Erode(ValueType leftValue, ValueType rightValue);
159
165 void Dilate(ValueType leftValue, ValueType rightValue);
172 void RemoveGaps(ValueType value, bool gapState = false);
173
177 void ShiftRanges(ValueType offset);
178
184 void GetAsList(const TRange<ValueType>& range, RangeList& result) const;
185
186 bool operator==(const TRanges<ValueType>& ranges) const;
187 bool operator!=(const TRanges<ValueType>& ranges) const;
188
189 uint GetHashValue(uint seed = 0) const;
190
191private:
192 SwitchPoints m_switchPoints;
193
194 bool m_beginState;
195};
196
197
198template <typename ValueType>
200: m_beginState(false)
201{
202}
203
204
205template <typename ValueType>
207: m_beginState(false)
208{
209 if (!range.IsEmpty()){
210 m_switchPoints.insert(range.GetMinValue());
211 m_switchPoints.insert(range.GetMaxValue());
212 }
213}
214
215
216template <typename ValueType>
218{
219 m_switchPoints.clear();
220 m_beginState = false;
221}
222
223
224template <typename ValueType>
226{
227 return m_switchPoints.empty() && (m_beginState == false);
228}
229
230
231template <typename ValueType>
233{
234 return m_switchPoints;
235}
236
237
238template <typename ValueType>
240{
241 return m_switchPoints;
242}
243
244
245template <typename ValueType>
247{
248 std::pair<typename SwitchPoints::iterator, bool> insertionStatus = m_switchPoints.insert(point);
249 if (!insertionStatus.second){
250 m_switchPoints.erase(insertionStatus.first);
251 }
252}
253
254
255template <typename ValueType>
257{
258 return m_beginState;
259}
260
261
262template <typename ValueType>
264{
265 m_beginState = state;
266}
267
268
269template <typename ValueType>
270bool TRanges<ValueType>::IsInside(ValueType point) const
271{
272 bool state = m_beginState;
273 for ( typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
274 iter != m_switchPoints.end();
275 ++iter){
276 if (*iter > point){
277 break;
278 }
279
280 state = !state;
281 }
282
283 return state;
284}
285
286
287template <typename ValueType>
289{
290 bool state = m_beginState;
291 for ( typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
292 iter != m_switchPoints.end();
293 ++iter){
294 if (*iter > range.GetMinValue()){
295 if (state){
296 ++iter;
297
298 // is the next switch out of checked range?
299 return (iter == m_switchPoints.end()) || (*iter >= range.GetMaxValue());
300 }
301 else{
302 return false;
303 }
304 }
305
306 state = !state;
307 }
308
309 return state;
310}
311
312
313template <typename ValueType>
315{
316 typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
317 typename SwitchPoints::const_iterator listIter = rangesList.m_switchPoints.begin();
318
319 bool state = m_beginState;
320 bool listState = rangesList.m_beginState;
321
322 for (;;){
323 bool isListCovered = state || !listState;
324 if (!isListCovered){
325 return false;
326 }
327
328 if (iter != m_switchPoints.end()){
329 ValueType point = *iter;
330
331 if (listIter != rangesList.m_switchPoints.end()){
332 ValueType listPoint = *listIter;
333
334 if (point <= listPoint){
335 ++iter;
336 state = !state;
337 }
338
339 if (listPoint <= point){
340 ++listIter;
341 listState = !listState;
342 }
343 }
344 else{
345 return true;
346 }
347 }
348 else{
349 // if no more segments in this list, check if no more switch is inside
350 return listIter == rangesList.m_switchPoints.end();
351 }
352 }
353}
354
355
356template <typename ValueType>
358{
359 if (clipRangePtr != NULL){
360 result.Reset();
361 result.m_beginState = false;
362
363 int prevPosition = clipRangePtr->GetMinValue();
364
365 bool state = m_beginState;
366
367 for ( typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
368 iter != m_switchPoints.end();
369 ++iter){
370 ValueType position = *iter;
371 if (position >= clipRangePtr->GetMaxValue()){
372 break;
373 }
374
375 if (position > prevPosition){
376 if (!state){
377 result.m_switchPoints.insert(prevPosition);
378 result.m_switchPoints.insert(position);
379 }
380
381 prevPosition = position;
382 }
383
384 state = !state;
385 }
386
387 if (!state){
388 result.m_switchPoints.insert(prevPosition);
389 result.m_switchPoints.insert(clipRangePtr->GetMaxValue());
390 }
391 }
392 else{
393 result.m_switchPoints = m_switchPoints;
394 result.m_beginState = !m_beginState;
395 }
396}
397
398
399template <typename ValueType>
401{
402 if (clipRangePtr != NULL){
403 int prevPosition = clipRangePtr->GetMinValue();
404
405 bool state = m_beginState;
406
407 // remove all points before
408 for ( typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
409 (iter != m_switchPoints.end()) && (*iter < prevPosition);
410 m_switchPoints.erase(iter++)){
411 state = !state;
412 }
413
414 typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
415
416 if (!state){
417 if ((iter != m_switchPoints.end()) && (*iter > prevPosition)){ // no first element? add it!
418 m_switchPoints.insert(prevPosition);
419 }
420 }
421
422 for (; iter != m_switchPoints.end(); ++iter){
423 ValueType position = *iter;
424 if (position >= clipRangePtr->GetMaxValue()){ // remove all points after
425 m_switchPoints.erase(iter, m_switchPoints.end());
426
427 break;
428 }
429
430 state = !state;
431 }
432
433 if (!state){
434 m_switchPoints.insert(clipRangePtr->GetMaxValue());
435 }
436
437 m_beginState = false;
438 }
439 else{
440 m_beginState = !m_beginState;
441 }
442}
443
444
445template <typename ValueType>
447{
448 TRanges<ValueType> retVal;
449
450 GetUnion(rangesList, retVal);
451
452 return retVal;
453}
454
455
456template <typename ValueType>
458{
459 typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
460 typename SwitchPoints::const_iterator listIter = rangesList.m_switchPoints.begin();
461
462 bool state = m_beginState;
463 bool listState = rangesList.m_beginState;
464
465 bool resultState = state || listState;
466
467 result.m_beginState = resultState;
468 result.m_switchPoints.clear();
469
470 for (;;){
471 if (iter != m_switchPoints.end()){
472 ValueType point = *iter;
473
474 if (listIter != rangesList.m_switchPoints.end()){
475 ValueType listPoint = *listIter;
476
477 if (point <= listPoint){
478 ++iter;
479 state = !state;
480 }
481
482 if (listPoint <= point){
483 ++listIter;
484 listState = !listState;
485 }
486
487 bool unitedStateAfter = state || listState;
488 if (unitedStateAfter != resultState){
489 result.m_switchPoints.insert(qMin(point, listPoint));
490
491 resultState = unitedStateAfter;
492 }
493 }
494 else{
495 if (!listState){
496 result.m_switchPoints.insert(iter, m_switchPoints.end());
497 }
498
499 return;
500 }
501 }
502 else{
503 if (!state && (listIter != rangesList.m_switchPoints.end())){
504 result.m_switchPoints.insert(listIter, rangesList.m_switchPoints.end());
505 }
506
507 return;
508 }
509 }
510}
511
512
513template <typename ValueType>
515{
516 typename SwitchPoints::iterator iter = m_switchPoints.begin();
517 typename SwitchPoints::const_iterator listIter = rangesList.m_switchPoints.begin();
518
519 bool state = m_beginState;
520 bool listState = rangesList.m_beginState;
521
522 m_beginState = state || listState;
523
524 for (;;){
525 if (iter != m_switchPoints.end()){
526 ValueType point = *iter;
527
528 if (listIter != rangesList.m_switchPoints.end()){
529 ValueType listPoint = *listIter;
530
531 if (point == listPoint){
532 ++iter;
533 state = !state;
534 ++listIter;
535 listState = !listState;
536 }
537 else if (point < listPoint){
538 if (listState){
539 iter = m_switchPoints.erase(iter);
540 }
541 else{
542 ++iter;
543 }
544 state = !state;
545 }
546 else{
547 if (!state){
548 iter = m_switchPoints.insert(iter, listPoint);
549 }
550 ++listIter;
551 listState = !listState;
552 }
553 }
554 else{
555 if (listState){
556 m_switchPoints.erase(iter, m_switchPoints.end());
557 }
558
559 return;
560 }
561 }
562 else{
563 if (!state && (listIter != rangesList.m_switchPoints.end())){
564 m_switchPoints.insert(listIter, rangesList.m_switchPoints.end());
565 }
566
567 return;
568 }
569 }
570}
571
572
573template <typename ValueType>
574void TRanges<ValueType>::Union(const TRange<ValueType>& range, bool isInverted)
575{
576 if (range.IsEmpty()){
577 return;
578 }
579
580 bool firstPointState = m_beginState;
581 typename SwitchPoints::const_iterator firstIter = m_switchPoints.begin();
582 for (;firstIter != m_switchPoints.end(); ++firstIter){
583 if (*firstIter >= range.GetMinValue()){
584 break;
585 }
586
587 firstPointState = !firstPointState;
588 }
589
590 bool secondPointState = firstPointState;
591 typename SwitchPoints::const_iterator secondIter = firstIter;
592 for (;secondIter != m_switchPoints.end(); ++secondIter){
593 if (*secondIter >= range.GetMaxValue()){
594 break;
595 }
596
597 secondPointState = !secondPointState;
598 }
599
600 if (firstIter != secondIter){
601 // if there are some points in range...
602 if (isInverted){
603 m_switchPoints.erase(m_switchPoints.begin(), firstIter); // remove all points before
604 m_switchPoints.erase(m_switchPoints.begin(), secondIter); // remove all points after
605 }
606 else{
607 m_switchPoints.erase(firstIter, secondIter); // remove all points before
608 }
609 }
610 else{
611 if (isInverted){
612 m_switchPoints.clear();
613 }
614 }
615
616 m_beginState = m_beginState || isInverted;
617
618 if (firstPointState == isInverted){
619 m_switchPoints.insert(range.GetMinValue());
620 }
621
622 if (secondPointState == isInverted){
623 m_switchPoints.insert(range.GetMaxValue());
624 }
625}
626
627
628template <typename ValueType>
630{
631 TRanges<ValueType> retVal;
632
633 GetIntersection(rangesList, retVal);
634
635 return retVal;
636}
637
638
639template <typename ValueType>
641{
642 typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
643 typename SwitchPoints::const_iterator listIter = rangesList.m_switchPoints.begin();
644
645 bool state = m_beginState;
646 bool listState = rangesList.m_beginState;
647
648 bool resultState = state && listState;
649
650 result.m_beginState = resultState;
651 result.m_switchPoints.clear();
652
653 for (;;){
654 if (iter != m_switchPoints.end()){
655 ValueType point = *iter;
656
657 if (listIter != rangesList.m_switchPoints.end()){
658 ValueType listPoint = *listIter;
659
660 if (point <= listPoint){
661 ++iter;
662 state = !state;
663 }
664
665 if (listPoint <= point){
666 ++listIter;
667 listState = !listState;
668 }
669
670 bool unitedStateAfter = state && listState;
671 if (unitedStateAfter != resultState){
672 result.m_switchPoints.insert(qMin(point, listPoint));
673
674 resultState = unitedStateAfter;
675 }
676 }
677 else{
678 if (listState){
679 result.m_switchPoints.insert(iter, m_switchPoints.end());
680 }
681
682 return;
683 }
684 }
685 else{
686 if (state && (listIter != rangesList.m_switchPoints.end())){
687 result.m_switchPoints.insert(listIter, rangesList.m_switchPoints.end());
688 }
689
690 return;
691 }
692 }
693}
694
695
696template <typename ValueType>
698{
699 typename SwitchPoints::iterator iter = m_switchPoints.begin();
700 typename SwitchPoints::const_iterator listIter = rangesList.m_switchPoints.begin();
701
702 bool state = m_beginState;
703 bool listState = rangesList.m_beginState;
704
705 m_beginState = state && listState;
706
707 for (;;){
708 if (iter != m_switchPoints.end()){
709 ValueType point = *iter;
710
711 if (listIter != rangesList.m_switchPoints.end()){
712 ValueType listPoint = *listIter;
713
714 if (point == listPoint){
715 ++iter;
716 state = !state;
717 ++listIter;
718 listState = !listState;
719 }
720 else if (point < listPoint){
721 if (!listState){
722 iter = m_switchPoints.erase(iter);
723 }
724 else{
725 ++iter;
726 }
727 state = !state;
728 }
729 else{
730 if (state){
731 iter = m_switchPoints.insert(iter, listPoint);
732 }
733 ++listIter;
734 listState = !listState;
735 }
736 }
737 else{
738 if (!listState){
739 m_switchPoints.erase(iter, m_switchPoints.end());
740 }
741
742 return;
743 }
744 }
745 else{
746 if (state && (listIter != rangesList.m_switchPoints.end())){
747 m_switchPoints.insert(listIter, rangesList.m_switchPoints.end());
748 }
749
750 return;
751 }
752 }
753}
754
755
756template <typename ValueType>
757void TRanges<ValueType>::Intersection(const TRange<ValueType>& range, bool isInverted)
758{
759 m_beginState = !m_beginState;
760
761 Union(range, !isInverted);
762
763 m_beginState = !m_beginState;
764}
765
766
767template <typename ValueType>
768void TRanges<ValueType>::Erode(ValueType leftValue, ValueType rightValue)
769{
770 TRanges<ValueType>::Dilate(-leftValue, -rightValue);
771}
772
773
774template <typename ValueType>
775void TRanges<ValueType>::Dilate(ValueType leftValue, ValueType rightValue)
776{
777 if (leftValue * rightValue < 0){ // do 2 steps for complex dilatation
778 Dilate(leftValue, 0);
779 Dilate(0, rightValue);
780
781 return;
782 }
783
784 ValueType absoluteSum = std::abs(leftValue + rightValue);
785 if (absoluteSum <= 0){
786 return; // nothing to do
787 }
788
789 bool isErosion = (leftValue + rightValue < 0);
790 ValueType leftValueAbs = std::abs(leftValue);
791 ValueType rightValueAbs = std::abs(rightValue);
792
793 typename SwitchPoints::iterator iter = m_switchPoints.begin();
794 while (iter != m_switchPoints.end()){
795 ValueType point = *iter;
796
797 const bool state = std::distance(m_switchPoints.begin(), iter) % 2 > 0 ? m_beginState : !m_beginState;
798 if (!state == isErosion){
799 // move point back
800 if (iter != m_switchPoints.begin()){
801 auto prevIter = std::prev(iter);
802
803 if (*prevIter > point - absoluteSum){
804 // previous range should be removed - is smaller than the erosion kernel
805 m_switchPoints.erase(prevIter);
806 m_switchPoints.erase(iter++);
807
808 continue;
809 }
810 }
811
812 // range can be moved using kernel size
813 m_switchPoints.erase(iter++);
814 iter = m_switchPoints.insert(iter, point - leftValueAbs);
815 }
816 else{
817 // move point forward
818 auto nextIter = std::next(iter);
819
820 if (nextIter != m_switchPoints.end()){
821 if (*nextIter < point + absoluteSum){
822 // following range should be removed - is smaller than the erosion kernel
823 m_switchPoints.erase(nextIter);
824 m_switchPoints.erase(iter++);
825
826 continue;
827 }
828 }
829
830 // range can be moved using kernel size
831 m_switchPoints.erase(iter++);
832 iter = m_switchPoints.insert(iter, point + rightValueAbs);
833 }
834
835 ++iter;
836 }
837}
838
839
840template <typename ValueType>
841void TRanges<ValueType>::RemoveGaps(ValueType value, bool gapState)
842{
843 if (!gapState){
844 Dilate(value, value);
845 Erode(value, value);
846 }
847 else{
848 Erode(value, value);
849 Dilate(value, value);
850 }
851}
852
853
854template <typename ValueType>
856{
857 SwitchPoints newSwitchPoints;
858 for ( typename SwitchPoints::iterator iter = m_switchPoints.begin();
859 iter != m_switchPoints.end();
860 ++iter){
861 newSwitchPoints.insert(*iter + offset);
862 }
863
864 m_switchPoints.swap(newSwitchPoints);
865}
866
867
868template <typename ValueType>
870{
871 int prevPosition = range.GetMinValue();
872
873 bool state = m_beginState;
874
875 for ( typename SwitchPoints::const_iterator iter = m_switchPoints.begin();
876 iter != m_switchPoints.end();
877 ++iter){
878 ValueType position = *iter;
879 if (position >= range.GetMaxValue()){
880 break;
881 }
882
883 if (position > prevPosition){
884 if (state){
885 result.push_back(TRange<ValueType>(prevPosition, position));
886 }
887
888 prevPosition = position;
889 }
890
891 state = !state;
892 }
893
894 if (state){
895 result.push_back(TRange<ValueType>(prevPosition, range.GetMaxValue()));
896 }
897}
898
899
900template <typename ValueType>
902{
903 return (m_beginState == ranges.m_beginState) && (m_switchPoints == ranges.m_switchPoints);
904}
905
906
907template <typename ValueType>
909{
910 return (m_beginState != ranges.m_beginState) || (m_switchPoints != ranges.m_switchPoints);
911}
912
913
914template <typename ValueType>
916{
917 uint retVal = seed;
918
919 if (m_beginState){
920 retVal++;
921 }
922
923 for ( typename TRanges<ValueType>::SwitchPoints::const_iterator iter = m_switchPoints.begin();
924 iter != m_switchPoints.end();
925 ++iter){
926 const ValueType& pos = *iter;
927
928 retVal = retVal ^ uint(pos);
929 }
930
931 return retVal;
932}
933
934
935// related global functions
936
937template <typename ValueType>
938inline uint qHash(const istd::TRanges<ValueType>& key, uint seed = 0)
939{
940 return key.GetHashValue(seed);
941}
942
943
944// typedefs
945
948
949
950} // namespace istd
951
952
953
954
Implementation of a abstract range defined by two values - minimum and maximum.
Definition TRange.h:22
ValueType GetMaxValue() const
Get the top value.
Definition TRange.h:382
ValueType GetMinValue() const
Get the bottom value.
Definition TRange.h:341
bool IsEmpty() const
Return true if the bottom value is equal to the top value.
Definition TRange.h:327
Set of ranges.
Definition TRanges.h:27
void Invert(const TRange< ValueType > *clipRangePtr)
Invert this range in place.
Definition TRanges.h:400
bool IsInside(ValueType point) const
Check if some point belongs to set.
Definition TRanges.h:270
std::vector< TRange< ValueType > > RangeVector
Definition TRanges.h:30
void Dilate(ValueType leftValue, ValueType rightValue)
Calculate dilatation of this range list.
Definition TRanges.h:775
SwitchPoints & GetSwitchPointsRef()
Allows access to stored switch points.
Definition TRanges.h:239
void SetBeginState(bool state)
Set begin state.
Definition TRanges.h:263
void InsertSwitchPoint(ValueType point)
Insert new switch point.
Definition TRanges.h:246
bool IsEmpty() const
Check if this set is empty.
Definition TRanges.h:225
void Erode(ValueType leftValue, ValueType rightValue)
Calculate erosion of this range list.
Definition TRanges.h:768
std::set< ValueType > SwitchPoints
Definition TRanges.h:31
bool operator==(const TRanges< ValueType > &ranges) const
Definition TRanges.h:901
bool GetBeginState() const
Get begin state.
Definition TRanges.h:256
uint GetHashValue(uint seed=0) const
Definition TRanges.h:915
TRanges< ValueType > GetUnion(const TRanges< ValueType > &rangesList) const
Get union of two range list.
Definition TRanges.h:446
void ShiftRanges(ValueType offset)
ShiftRanges all points in this set using specified offset.
Definition TRanges.h:855
bool operator!=(const TRanges< ValueType > &ranges) const
Definition TRanges.h:908
const SwitchPoints & GetSwitchPoints() const
Get stored switch points.
Definition TRanges.h:232
void RemoveGaps(ValueType value, bool gapState=false)
Remove gaps with some length.
Definition TRanges.h:841
TRanges()
Default constructor initializing this set to be empty.
Definition TRanges.h:199
void Union(const TRanges< ValueType > &rangesList)
Calculate union of this range list and the other one.
Definition TRanges.h:514
void Intersection(const TRanges< ValueType > &rangesList)
Calculate intersection of this range list and the other one.
Definition TRanges.h:697
void Reset()
Set this set to be empty.
Definition TRanges.h:217
void GetInverted(TRanges< ValueType > &result, const TRange< ValueType > *clipRangePtr) const
Get inverted range.
Definition TRanges.h:357
void GetAsList(const TRange< ValueType > &range, RangeList &result) const
Get this set as list of istd::TRange objects.
Definition TRanges.h:869
QList< TRange< ValueType > > RangeList
Definition TRanges.h:29
TRanges< ValueType > GetIntersection(const TRanges< ValueType > &rangesList) const
Get intersection of two range list.
Definition TRanges.h:629
#define NULL
Definition istd.h:74
Standard library.
Definition IComponent.h:17
TRanges< double > CRanges
Definition TRanges.h:946
uint qHash(const CVarIndex &index, uint seed=0)
TRanges< int > CIntRanges
Definition TRanges.h:947