vigra - vigra/multi_iterator_coupled.hxx Source File

[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

multi_iterator_coupled.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 2011-2012 by Stefan Schmidt and Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35
36 #ifndef MULTI_ITERATOR_COUPLED_HXX
37 #define MULTI_ITERATOR_COUPLED_HXX
38
39 #include "metaprogramming.hxx"
40 #include "multi_shape.hxx"
41
42 namespace vigra {
43
44 /** \addtogroup MultiIteratorGroup
45 */
46 //@{
47
48 /**
49 Handle class, used by CoupledScanOrderIterator as the value type to simultaneously itearate over multiple images.
50 */
51 template <class T, class NEXT>
52 class CoupledHandle
53 : public NEXT
54 {
55 public:
56 typedef NEXT base_type;
57 typedef CoupledHandle<T, NEXT> self_type;
58
59 static const int index = NEXT::index + 1; // index of this member of the chain
60 static const unsigned int dimensions = NEXT::dimensions;
61
62 typedef T value_type;
63 typedef T * pointer;
64 typedef T const * const_pointer;
65 typedef T & reference;
66 typedef T const & const_reference;
67 typedef typename base_type::shape_type shape_type;
68
69 CoupledHandle()
70 : base_type(),
71 pointer_(),
72 strides_()
73 {}
74
75 CoupledHandle(const_pointer p, shape_type const & strides, NEXT const & next)
76 : base_type(next),
77 pointer_(const_cast<pointer>(p)),
78 strides_(strides)
79 {}
80
81 template <class Stride>
82 CoupledHandle(MultiArrayView<dimensions, T, Stride> const & v, NEXT const & next)
83 : base_type(next),
84 pointer_(const_cast<pointer>(v.data())),
85 strides_(v.stride())
86 {
87 vigra_precondition(v.shape() == this->shape(), "createCoupledIterator(): shape mismatch.");
88 }
89
90 template<int DIMENSION>
91 inline void increment()
92 {
93 pointer_ += strides_[DIMENSION];
94 base_type::template increment<DIMENSION>();
95 }
96
97 template<int DIMENSION>
98 inline void decrement()
99 {
100 pointer_ -= strides_[DIMENSION];
101 base_type::template decrement<DIMENSION>();
102 }
103
104 // TODO: test if making the above a default case of the this hurts performance
105 template<int DIMENSION>
106 inline void increment(MultiArrayIndex offset)
107 {
108 pointer_ += offset*strides_[DIMENSION];
109 base_type::template increment<DIMENSION>(offset);
110 }
111
112 template<int DIMENSION>
113 inline void decrement(MultiArrayIndex offset)
114 {
115 pointer_ -= offset*strides_[DIMENSION];
116 base_type::template decrement<DIMENSION>(offset);
117 }
118
119 void restrictToSubarray(shape_type const & start, shape_type const & end)
120 {
121 pointer_ += dot(start, strides_);
122 base_type::restrictToSubarray(start, end);
123 }
124
125 // ptr access
126 reference operator*()
127 {
128 return *pointer_;
129 }
130
131 const_reference operator*() const
132 {
133 return *pointer_;
134 }
135
136 pointer operator->()
137 {
138 return pointer_;
139 }
140
141 const_pointer operator->() const
142 {
143 return pointer_;
144 }
145
146 pointer ptr()
147 {
148 return pointer_;
149 }
150
151 const_pointer ptr() const
152 {
153 return pointer_;
154 }
155
156 shape_type const & strides() const
157 {
158 return strides_;
159 }
160
161 pointer pointer_;
162 shape_type strides_;
163 };
164
165
166 template <int N>
167 class CoupledHandle<TinyVector<MultiArrayIndex, N>, void>
168 {
169 public:
170 static const int index = 0; // index of this member of the chain
171 static const unsigned int dimensions = N;
172
173 typedef typename MultiArrayShape<N>::type value_type;
174 typedef value_type const * pointer;
175 typedef value_type const * const_pointer;
176 typedef value_type const & reference;
177 typedef value_type const & const_reference;
178 typedef value_type shape_type;
179 typedef CoupledHandle<value_type, void> self_type;
180
181 CoupledHandle()
182 : point_(),
183 shape_(),
184 scanOrderIndex_()
185 {}
186
187 CoupledHandle(value_type const & shape)
188 : point_(),
189 shape_(shape),
190 scanOrderIndex_()
191 {}
192
193 CoupledHandle(typename MultiArrayShape<N+1>::type const & shape)
194 : point_(),
195 shape_(shape.begin()),
196 scanOrderIndex_()
197 {}
198
199 template<int DIMENSION>
200 inline void increment()
201 {
202 ++point_[DIMENSION];
203 }
204
205 template<int DIMENSION>
206 inline void decrement()
207 {
208 --point_[DIMENSION];
209 }
210
211 // TODO: test if making the above a default case of the this hurts performance
212 template<int DIMENSION>
213 inline void increment(MultiArrayIndex offset)
214 {
215 point_[DIMENSION] += offset;
216 }
217
218 template<int DIMENSION>
219 inline void decrement(MultiArrayIndex offset)
220 {
221 point_[DIMENSION] -= offset;
222 }
223
224 void restrictToSubarray(shape_type const & start, shape_type const & end)
225 {
226 point_ = shape_type();
227 shape_ = end - start;
228 scanOrderIndex_ = 0;
229 }
230
231 inline void incrementIndex()
232 {
233 ++scanOrderIndex_;
234 }
235
236 inline void decrementIndex()
237 {
238 --scanOrderIndex_;
239 }
240
241 inline void incrementIndex(MultiArrayIndex offset)
242 {
243 scanOrderIndex_ += offset;
244 }
245
246 inline void decrementIndex(MultiArrayIndex offset)
247 {
248 scanOrderIndex_ -= offset;
249 }
250
251 // access
252 MultiArrayIndex scanOrderIndex() const
253 {
254 return scanOrderIndex_;
255 }
256
257 // access
258 const_reference point() const
259 {
260 return point_;
261 }
262
263 // access
264 const_reference shape() const
265 {
266 return shape_;
267 }
268
269 const_reference operator*() const
270 {
271 return point_;
272 }
273
274 const_pointer operator->() const
275 {
276 return &point_;
277 }
278
279 const_pointer ptr() const
280 {
281 return &point_;
282 }
283
284 unsigned int borderType() const
285 {
286 return detail::BorderTypeImpl<N>::exec(point_, shape_);
287 }
288
289 value_type point_, shape_;
290 MultiArrayIndex scanOrderIndex_;
291 };
292
293 template <unsigned int N, class T, class StrideTag>
294 class MultiArrayView<N, Multiband<T>, StrideTag>
295 : public MultiArrayView<N, T, StrideTag>
296 {
297 public:
298 MultiArrayView(MultiArrayView<N, T, StrideTag> const & v)
299 : MultiArrayView<N, T, StrideTag>(v)
300 {}
301 };
302
303 template <class T, class NEXT>
304 class CoupledHandle<Multiband<T>, NEXT>
305 : public NEXT
306 {
307 public:
308 typedef NEXT base_type;
309 typedef CoupledHandle<Multiband<T>, NEXT> self_type;
310
311 static const int index = NEXT::index + 1; // index of this member of the chain
312 static const unsigned int dimensions = NEXT::dimensions;
313
314 typedef MultiArrayView<1, T, StridedArrayTag> value_type;
315 typedef value_type * pointer;
316 typedef value_type const * const_pointer;
317 typedef value_type & reference;
318 typedef value_type const & const_reference;
319 typedef typename base_type::shape_type shape_type;
320
321 CoupledHandle()
322 : base_type(),
323 view_(),
324 strides_()
325 {}
326
327 CoupledHandle(const_reference p, shape_type const & strides, NEXT const & next)
328 : base_type(next),
329 view_(p),
330 strides_(strides)
331 {}
332
333 template <class Stride>
334 CoupledHandle(MultiArrayView<dimensions+1, Multiband<T>, Stride> const & v, NEXT const & next)
335 : base_type(next),
336 view_(v.bindInner(shape_type())),
337 strides_(v.bindOuter(0).stride())
338 {
339 vigra_precondition(v.bindOuter(0).shape() == this->shape(), "createCoupledIterator(): shape mismatch.");
340 }
341
342 template<int DIMENSION>
343 inline void increment()
344 {
345 view_.unsafePtr() += strides_[DIMENSION];
346 base_type::template increment<DIMENSION>();
347 }
348
349 template<int DIMENSION>
350 inline void decrement()
351 {
352 view_.unsafePtr() -= strides_[DIMENSION];
353 base_type::template decrement<DIMENSION>();
354 }
355
356 // TODO: test if making the above a default case of the this hurts performance
357 template<int DIMENSION>
358 inline void increment(MultiArrayIndex offset)
359 {
360 view_.unsafePtr() += offset*strides_[DIMENSION];
361 base_type::template increment<DIMENSION>(offset);
362 }
363
364 template<int DIMENSION>
365 inline void decrement(MultiArrayIndex offset)
366 {
367 view_.unsafePtr() -= offset*strides_[DIMENSION];
368 base_type::template decrement<DIMENSION>(offset);
369 }
370
371 void restrictToSubarray(shape_type const & start, shape_type const & end)
372 {
373 view_.unsafePtr() += dot(start, strides_);
374 base_type::restrictToSubarray(start, end);
375 }
376
377 // ptr access
378 reference operator*()
379 {
380 return view_;
381 }
382
383 const_reference operator*() const
384 {
385 return view_;
386 }
387
388 pointer operator->()
389 {
390 return &view_;
391 }
392
393 const_pointer operator->() const
394 {
395 return &view_;
396 }
397
398 pointer ptr()
399 {
400 return &view_;
401 }
402
403 const_pointer ptr() const
404 {
405 return &view_;
406 }
407
408 shape_type const & strides() const
409 {
410 return strides_;
411 }
412
413 value_type view_;
414 shape_type strides_;
415 };
416
417 template <unsigned TARGET_INDEX>
418 struct Error__CoupledHandle_index_out_of_range;
419
420 namespace detail {
421
422 template <unsigned TARGET_INDEX, class Handle, bool isValid, unsigned int INDEX=Handle::index>
423 struct CoupledHandleCastImpl
424 {
425 typedef typename CoupledHandleCastImpl<TARGET_INDEX, typename Handle::base_type, isValid>::type type;
426 };
427
428 template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX>
429 struct CoupledHandleCastImpl<TARGET_INDEX, Handle, false, INDEX>
430 {
431 typedef Error__CoupledHandle_index_out_of_range<TARGET_INDEX> type;
432 };
433
434 template <unsigned TARGET_INDEX, class Handle>
435 struct CoupledHandleCastImpl<TARGET_INDEX, Handle, true, TARGET_INDEX>
436 {
437 typedef Handle type;
438 };
439
440 } // namespace detail
441
442 template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX=Handle::index>
443 struct CoupledHandleCast
444 : public detail::CoupledHandleCastImpl<TARGET_INDEX, Handle, (TARGET_INDEX <= INDEX), INDEX>
445 {};
446
447 template <unsigned int TARGET_INDEX, class Handle>
448 typename CoupledHandleCast<TARGET_INDEX, Handle>::type &
449 cast(Handle & handle)
450 {
451 return handle;
452 };
453
454 template <unsigned int TARGET_INDEX, class Handle>
455 typename CoupledHandleCast<TARGET_INDEX, Handle>::type const &
456 cast(Handle const & handle)
457 {
458 return handle;
459 };
460
461 /** Returns reference to the element in the band of the handle with index TARGET_INDEX.
462 */
463 template <unsigned int TARGET_INDEX, class Handle>
464 typename CoupledHandleCast<TARGET_INDEX, Handle>::type::reference
465 get(Handle & handle)
466 {
467 return *cast<TARGET_INDEX>(handle);
468 };
469
470 /** Returns a constant reference to the element in the band of the handle with index TARGET_INDEX.
471 */
472 template <unsigned int TARGET_INDEX, class Handle>
473 typename CoupledHandleCast<TARGET_INDEX, Handle>::type::const_reference
474 get(Handle const & handle)
475 {
476 return *cast<TARGET_INDEX>(handle);
477 };
478
479 /********************************************************/
480 /* */
481 /* CoupledScanOrderIterator<N> */
482 /* */
483 /********************************************************/
484
485 /** \brief Iterate over multiple images simultaneously in scan order.
486
487 The value type of this iterator is an instance of the handle class CoupledHandle. This allows to iterate over multiple arrays simultaneously. The coordinates can be accessed as a special band (index 0) in the handle. The scan-order is defined such that dimensions are iterated from front to back (first to last).
488
489 Instances of this class are usually constructed by calling createCoupledIterator() .
490
491 To get the type of a CoupledScanOrderIterator for arrays of a certain dimension and element types use CoupledIteratorType::type.
492
493 The iterator supports all functions listed in the STL documentation for
494 <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access Iterators</a>.
495
496 Example of use:
497 \code
498 using namespace vigra;
499 MultiArray<2, double> image1(Shape2(5, 5));
500 MultiArray<2, double> image2(Shape2(5, 5));
501 // fill image with data ...
502
503 typedef CoupledIteratorType<2, double, double>::type Iterator; // the type of the CoupledScanOrderIterator
504
505 Iterator start = createCoupledIterator(image1, image2); // create coupled iterator for simultaneous iteration over image1, image2 and their coordinates
506 Iterator end = start.getEndIterator();
507
508 for (Iterator it = start; it < end; ++it) {
509 std::cout << "coordinates: " << it.get<0>() << std::endl;
510 std::cout << "image1: " << it.get<1>() << std::endl;
511 std::cout << "image2: " << it.get<2>() << std::endl;
512 }
513
514 //random access:
515 Iterator::value_type handle = start[15];
516 std::cout << "image1: " << get<1>(handle) << std::endl;
517 \endcode
518
519 <b>\#include</b> <vigra/multi_iterator_coupled.hxx> <br/>
520 Namespace: vigra
521 */
522
523 template <unsigned int N,
524 class HANDLES=CoupledHandle<TinyVector<MultiArrayIndex, N>, void>,
525 int DIMENSION = N-1>
526 class CoupledScanOrderIterator
527 #ifndef DOXYGEN // doxygen doesn't understand this inheritance
528 : protected CoupledScanOrderIterator<N, HANDLES, DIMENSION-1>
529 #endif
530 {
531 typedef CoupledScanOrderIterator<N, HANDLES, DIMENSION-1> base_type;
532 static const int dimension = DIMENSION;
533
534 public:
535
536 typedef typename MultiArrayShape<dimension+1>::type shape_type;
537 typedef MultiArrayIndex difference_type;
538 typedef CoupledScanOrderIterator iterator;
539 typedef std::random_access_iterator_tag iterator_category;
540
541 typedef typename base_type::value_type value_type;
542
543 #ifdef DOXYGEN
544 /** The type of the CoupledHandle.
545 */
546 typedef HANDLES value_type;
547 #endif
548
549 typedef typename base_type::reference reference;
550 typedef typename base_type::const_reference const_reference; // FIXME: do we need both?
551 typedef typename base_type::pointer pointer;
552
553 explicit CoupledScanOrderIterator(value_type const & handles = value_type())
554 : base_type(handles)
555 {}
556
557 value_type operator[](MultiArrayIndex i) const
558 {
559 return *(CoupledScanOrderIterator(*this) += i);
560 }
561
562 CoupledScanOrderIterator & operator++()
563 {
564 base_type::operator++();
565 if(this->point()[dimension-1] == this->shape()[dimension-1])
566 {
567 base_type::reset();
568 this->handles_.template increment<dimension>();
569 }
570 return *this;
571 }
572
573 CoupledScanOrderIterator operator++(int)
574 {
575 CoupledScanOrderIterator res(*this);
576 ++*this;
577 return res;
578 }
579
580 CoupledScanOrderIterator & operator+=(MultiArrayIndex i)
581 {
582 // FIXME: this looks very expensive
583 shape_type coordOffset;
584 detail::ScanOrderToCoordinate<N>::exec(i+scanOrderIndex(), this->shape(), coordOffset);
585 coordOffset -= point();
586 moveRelative(coordOffset);
587 this->handles_.scanOrderIndex_ += i;
588 return *this;
589 }
590
591 CoupledScanOrderIterator & operator+=(const shape_type &coordOffset)
592 {
593 moveRelative(coordOffset);
594 this->handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec(this->shape(), coordOffset);
595 return *this;
596 }
597
598 CoupledScanOrderIterator & operator--()
599 {
600 base_type::operator--();
601 if(this->point()[dimension-1] == -1)
602 {
603 base_type::inverseReset();
604 this->handles_.template decrement<dimension>();
605 }
606 return *this;
607 }
608
609 CoupledScanOrderIterator operator--(int)
610 {
611 CoupledScanOrderIterator res(*this);
612 --*this;
613 return res;
614 }
615
616 CoupledScanOrderIterator & operator-=(MultiArrayIndex i)
617 {
618 return operator+=(-i);
619 }
620
621 CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
622 {
623 return operator+=(-coordOffset);
624 }
625
626 /** Returns CoupledScanOrderIterator pointing beyond the last element.
627 */
628 CoupledScanOrderIterator getEndIterator() const
629 {
630 return operator+(prod(this->shape()) - this->scanOrderIndex());
631 }
632
633 CoupledScanOrderIterator operator+(MultiArrayIndex d) const
634 {
635 return CoupledScanOrderIterator(*this) += d;
636 }
637
638 CoupledScanOrderIterator operator-(MultiArrayIndex d) const
639 {
640 return CoupledScanOrderIterator(*this) -= d;
641 }
642
643 CoupledScanOrderIterator operator+(const shape_type &coordOffset) const
644 {
645 return CoupledScanOrderIterator(*this) += coordOffset;
646 }
647
648 CoupledScanOrderIterator operator-(const shape_type &coordOffset) const
649 {
650 return CoupledScanOrderIterator(*this) -= coordOffset;
651 }
652
653 MultiArrayIndex operator-(CoupledScanOrderIterator const & r) const
654 {
655 return base_type::operator-(r);
656 }
657
658 bool operator==(CoupledScanOrderIterator const & r) const
659 {
660 return base_type::operator==(r);
661 }
662
663 bool operator!=(CoupledScanOrderIterator const & r) const
664 {
665 return base_type::operator!=(r);
666 }
667
668 bool operator<(CoupledScanOrderIterator const & r) const
669 {
670 return base_type::operator<(r);
671 }
672
673 bool operator<=(CoupledScanOrderIterator const & r) const
674 {
675 return base_type::operator<=(r);
676 }
677
678 bool operator>(CoupledScanOrderIterator const & r) const
679 {
680 return base_type::operator>(r);
681 }
682
683 bool operator>=(CoupledScanOrderIterator const & r) const
684 {
685 return base_type::operator>=(r);
686 }
687
688 CoupledScanOrderIterator & restrictToSubarray(shape_type const & start, shape_type const & end)
689 {
690 this->operator+=(-point());
691 this->handles_.restrictToSubarray(start, end);
692 return *this;
693 }
694
695 using base_type::operator*;
696 using base_type::point;
697 using base_type::shape;
698 using base_type::scanOrderIndex;
699 using base_type::atBorder;
700 using base_type::borderType;
701 using base_type::get;
702 using base_type::isValid;
703 using base_type::atEnd;
704
705 #ifdef DOXYGEN
706
707 /** Returns reference to the element in the band with index TARGET_INDEX.
708 */
709 template<unsigned int TARGET_INDEX>
710 typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference
711 get();
712
713 /** Returns constant reference to the element in the band with index TARGET_INDEX.
714 */
715 template<unsigned int TARGET_INDEX>
716 typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_reference
717 get() const;
718
719 #endif
720
721 protected:
722 void reset()
723 {
724 this->handles_.template decrement<dimension>(this->shape()[dimension]);
725 }
726
727 void inverseReset()
728 {
729 this->handles_.template increment<dimension>(this->shape()[dimension]);
730 }
731
732 void moveRelative(typename value_type::shape_type const & coordOffset)
733 {
734 base_type::moveRelative(coordOffset);
735 this->handles_.template increment<dimension>(coordOffset[dimension]);
736 }
737 };
738
739
740
741 template <unsigned int N, class HANDLES>
742 class CoupledScanOrderIterator<N, HANDLES, 0>
743 {
744 static const int dimension = 0;
745
746 public:
747
748 typedef CoupledScanOrderIterator<N, HANDLES, 0> self_type;
749 typedef HANDLES value_type;
750 typedef MultiArrayIndex difference_type;
751 typedef value_type & reference;
752 typedef value_type const & const_reference;
753 typedef value_type * pointer;
754 typedef typename MultiArrayShape<1>::type shape_type;
755 typedef CoupledScanOrderIterator iterator;
756 typedef std::random_access_iterator_tag iterator_category;
757
758 explicit CoupledScanOrderIterator(value_type const & handles = value_type())
759 : handles_(handles)
760 {}
761
762 CoupledScanOrderIterator & operator++()
763 {
764 handles_.template increment<dimension>();
765 handles_.incrementIndex();
766 return *this;
767 }
768
769 CoupledScanOrderIterator operator++(int)
770 {
771 CoupledScanOrderIterator res(*this);
772 ++*this;
773 return res;
774 }
775
776 CoupledScanOrderIterator & operator+=(MultiArrayIndex i)
777 {
778 shape_type coordOffset;
779 detail::ScanOrderToCoordinate<N>::exec(i, shape(), coordOffset);
780 moveRelative(coordOffset);
781 handles_.scanOrderIndex_ += i;
782 return *this;
783 }
784
785 CoupledScanOrderIterator & operator+=(const shape_type &coordOffset)
786 {
787 moveRelative(coordOffset);
788 handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec(shape(), coordOffset);
789 return *this;
790 }
791
792 CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
793 {
794 return operator+=(-coordOffset);
795 }
796
797 CoupledScanOrderIterator & operator--()
798 {
799 handles_.template decrement<dimension>();
800 handles_.decrementIndex();
801 return *this;
802 }
803
804 CoupledScanOrderIterator operator--(int)
805 {
806 CoupledScanOrderIterator res(*this);
807 --this;
808 return res;
809 }
810
811 CoupledScanOrderIterator & operator-=(MultiArrayIndex i)
812 {
813 return operator+=(-i);
814 }
815
816 value_type operator[](MultiArrayIndex i) const
817 {
818 return *(CoupledScanOrderIterator(*this) += i);
819 }
820
821 CoupledScanOrderIterator
822 operator+(MultiArrayIndex d) const
823 {
824 return CoupledScanOrderIterator(*this) += d;
825 }
826
827 CoupledScanOrderIterator
828 operator-(MultiArrayIndex d) const
829 {
830 return CoupledScanOrderIterator(*this) -= d;
831 }
832
833 CoupledScanOrderIterator operator+(const shape_type &coordOffset) const
834 {
835 return CoupledScanOrderIterator(*this) += coordOffset;
836 }
837
838 CoupledScanOrderIterator operator-(const shape_type &coordOffset) const
839 {
840 return CoupledScanOrderIterator(*this) -= coordOffset;
841 }
842
843 MultiArrayIndex
844 operator-(CoupledScanOrderIterator const & r) const
845 {
846 return scanOrderIndex() - r.scanOrderIndex();
847 }
848
849 bool operator==(CoupledScanOrderIterator const & r) const
850 {
851 return scanOrderIndex() == r.scanOrderIndex();
852 }
853
854 bool operator!=(CoupledScanOrderIterator const & r) const
855 {
856 return scanOrderIndex() != r.scanOrderIndex();
857 }
858
859 bool operator<(CoupledScanOrderIterator const & r) const
860 {
861 return scanOrderIndex() < r.scanOrderIndex();
862 }
863
864 bool operator<=(CoupledScanOrderIterator const & r) const
865 {
866 return scanOrderIndex() <= r.scanOrderIndex();
867 }
868
869 bool operator>(CoupledScanOrderIterator const & r) const
870 {
871 return scanOrderIndex() > r.scanOrderIndex();
872 }
873
874 bool operator>=(CoupledScanOrderIterator const & r) const
875 {
876 return scanOrderIndex() >= r.scanOrderIndex();
877 }
878
879 bool isValid() const
880 {
881 return handles_.scanOrderIndex() < prod(shape());
882 }
883
884 bool atEnd() const
885 {
886 return handles_.scanOrderIndex() >= prod(shape());
887 }
888
889 MultiArrayIndex scanOrderIndex() const
890 {
891 return handles_.scanOrderIndex();
892 }
893
894 typename value_type::shape_type const & point() const
895 {
896 return handles_.point();
897 }
898
899 typename value_type::shape_type const & shape() const
900 {
901 return handles_.shape();
902 }
903
904 reference operator*()
905 {
906 return handles_;
907 }
908
909 const_reference operator*() const
910 {
911 return handles_;
912 }
913
914 CoupledScanOrderIterator & restrictToSubarray(shape_type const & start, shape_type const & end)
915 {
916 operator+=(-point());
917 handles_.restrictToSubarray(start, end);
918 return *this;
919 }
920
921 CoupledScanOrderIterator getEndIterator() const
922 {
923 return operator+(prod(shape())-scanOrderIndex());
924 }
925
926 bool atBorder() const
927 {
928 return (handles_.borderType() != 0);
929 }
930
931 unsigned int borderType() const
932 {
933 return handles_.borderType();
934 }
935
936 template<unsigned int TARGET_INDEX>
937 typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference
938 get()
939 {
940 return vigra::get<TARGET_INDEX>(handles_);
941 }
942
943 template<unsigned int TARGET_INDEX>
944 typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_reference
945 get() const
946 {
947 return vigra::get<TARGET_INDEX>(handles_);
948 }
949
950 protected:
951 void reset()
952 {
953 handles_.template decrement<dimension>(shape()[dimension]);
954 }
955
956 void inverseReset()
957 {
958 handles_.template increment<dimension>(shape()[dimension]);
959 }
960
961 void moveRelative(typename value_type::shape_type const & coordOffset)
962 {
963 handles_.template increment<dimension>(coordOffset[dimension]);
964 }
965
966 value_type handles_;
967 };
968
969
970 template <unsigned int N, class List>
971 struct ComposeCoupledHandle;
972
973 template <unsigned int N, class T, class TAIL>
974 struct ComposeCoupledHandle<N, TypeList<T, TAIL> >
975 {
976 typedef typename ComposeCoupledHandle<N, TAIL>::type BaseType;
977 typedef typename MultiArrayShape<N>::type shape_type;
978 typedef CoupledHandle<T, BaseType> type;
979
980 template <class S>
981 type exec(MultiArrayView<N, T, S> const & m,
982 shape_type const & start, shape_type const & end,
983 BaseType const & base)
984 {
985 return type(m.subarray(start, end).data(), m.stride(), base);
986 }
987
988 template <class S>
989 type exec(MultiArrayView<N, T, S> const & m, BaseType const & base)
990 {
991 return type(m.data(), m.stride(), base);
992 }
993 };
994
995 template <unsigned int N>
996 struct ComposeCoupledHandle<N, void>
997 {
998 typedef typename MultiArrayShape<N>::type shape_type;
999 typedef CoupledHandle<shape_type, void> type;
1000
1001 type exec(shape_type const & shape)
1002 {
1003 return type(shape);
1004 }
1005
1006 type exec(shape_type const & start, shape_type const & end)
1007 {
1008 return type(end-start);
1009 }
1010 };
1011
1012 template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
1013 struct CoupledHandleType
1014 {
1015 // reverse the order to get the desired index order
1016 typedef typename MakeTypeList<T5, T4, T3, T2, T1>::type TypeList;
1017 typedef typename ComposeCoupledHandle<N, TypeList>::type type;
1018 };
1019
1020 template <unsigned int N, class T1, class T2, class T3, class T4, class T5>
1021 struct CoupledHandleType<N, Multiband<T1>, T2, T3, T4, T5>
1022 {
1023 // reverse the order to get the desired index order
1024 typedef typename MakeTypeList<T5, T4, T3, T2, Multiband<T1> >::type TypeList;
1025 typedef typename ComposeCoupledHandle<N-1, TypeList>::type type;
1026 };
1027
1028 /** Helper class to easliy get the type of a CoupledScanOrderIterator (and corresponding CoupledHandle) for up to five arrays of dimension N with element types T1,...,T5.
1029 */
1030 template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
1031 struct CoupledIteratorType
1032 {
1033 /** Type of the CoupledHandle.*/
1034 typedef typename CoupledHandleType<N, T1, T2, T3, T4, T5>::type HandleType;
1035
1036 /** Type of the CoupledScanOrderIterator.*/
1037 typedef CoupledScanOrderIterator<HandleType::dimensions, HandleType> IteratorType;
1038 typedef IteratorType type;
1039 };
1040
1041 /** Alias for \ref vigra::CoupledIteratorType (maybe easier to remember).
1042 */
1043 template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
1044 struct CoupledArrays
1045 : public CoupledIteratorType<N, T1, T2, T3, T4, T5>
1046 {};
1047
1048 /** Returns a CoupledScanOrderIterator from shape to iterate over coordinates.
1049 */
1050 template <int N>
1051 typename CoupledIteratorType<N>::type
1052 createCoupledIterator(TinyVector<MultiArrayIndex, N> const & shape)
1053 {
1054 typedef typename CoupledHandleType<N>::type P0;
1055 typedef CoupledScanOrderIterator<N, P0> IteratorType;
1056
1057 return IteratorType(P0(shape));
1058 }
1059
1060 /** Returns a CoupledScanOrderIterator to simultaneously iterate over image m1 and its coordinates.
1061 */
1062 template <unsigned int N1, class T1, class S1>
1063 typename CoupledIteratorType<N1, T1>::type
1064 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1)
1065 {
1066 typedef typename CoupledHandleType<N1, T1>::type P1;
1067 typedef typename P1::base_type P0;
1068 typedef CoupledScanOrderIterator<P1::dimensions, P1> IteratorType;
1069
1070 return IteratorType(P1(m1,
1071 P0(m1.shape())));
1072 }
1073
1074 /** Returns a CoupledScanOrderIterator to simultaneously iterate over images m1, m2 and their coordinates.
1075 */
1076 template <unsigned int N1, class T1, class S1,
1077 unsigned int N2, class T2, class S2>
1078 typename CoupledIteratorType<N1, T1, T2>::type
1079 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
1080 MultiArrayView<N2, T2, S2> const & m2)
1081 {
1082 typedef typename CoupledHandleType<N1, T1, T2>::type P2;
1083 typedef typename P2::base_type P1;
1084 typedef typename P1::base_type P0;
1085 typedef CoupledScanOrderIterator<P2::dimensions, P2> IteratorType;
1086
1087 return IteratorType(P2(m2,
1088 P1(m1,
1089 P0(m1.shape()))));
1090 }
1091
1092 /** Returns a CoupledScanOrderIterator to simultaneously iterate over images m1, m2, m3 and their coordinates.
1093 */
1094 template <unsigned int N1, class T1, class S1,
1095 unsigned int N2, class T2, class S2,
1096 unsigned int N3, class T3, class S3>
1097 typename CoupledIteratorType<N1, T1, T2, T3>::type
1098 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
1099 MultiArrayView<N2, T2, S2> const & m2,
1100 MultiArrayView<N3, T3, S3> const & m3)
1101 {
1102 typedef typename CoupledHandleType<N1, T1, T2, T3>::type P3;
1103 typedef typename P3::base_type P2;
1104 typedef typename P2::base_type P1;
1105 typedef typename P1::base_type P0;
1106 typedef CoupledScanOrderIterator<P3::dimensions, P3> IteratorType;
1107
1108 return IteratorType(P3(m3,
1109 P2(m2,
1110 P1(m1,
1111 P0(m1.shape())))));
1112 }
1113
1114 /** Returns a CoupledScanOrderIterator to simultaneously iterate over images m1, m2, m3, m4 and their coordinates.
1115 */
1116 template <unsigned int N1, class T1, class S1,
1117 unsigned int N2, class T2, class S2,
1118 unsigned int N3, class T3, class S3,
1119 unsigned int N4, class T4, class S4>
1120 typename CoupledIteratorType<N1, T1, T2, T3, T4>::type
1121 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
1122 MultiArrayView<N2, T2, S2> const & m2,
1123 MultiArrayView<N3, T3, S3> const & m3,
1124 MultiArrayView<N4, T4, S4> const & m4)
1125 {
1126 typedef typename CoupledHandleType<N1, T1, T2, T3, T4>::type P4;
1127 typedef typename P4::base_type P3;
1128 typedef typename P3::base_type P2;
1129 typedef typename P2::base_type P1;
1130 typedef typename P1::base_type P0;
1131 typedef CoupledScanOrderIterator<P4::dimensions, P4> IteratorType;
1132
1133 return IteratorType(P4(m4,
1134 P3(m3,
1135 P2(m2,
1136 P1(m1,
1137 P0(m1.shape()))))));
1138 }
1139
1140 /** Returns a CoupledScanOrderIterator to simultaneously iterate over images m1, m2, m3, m4, m5 and their coordinates.
1141 */
1142 template <unsigned int N1, class T1, class S1,
1143 unsigned int N2, class T2, class S2,
1144 unsigned int N3, class T3, class S3,
1145 unsigned int N4, class T4, class S4,
1146 unsigned int N5, class T5, class S5>
1147 typename CoupledIteratorType<N1, T1, T2, T3, T4, T5>::type
1148 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
1149 MultiArrayView<N2, T2, S2> const & m2,
1150 MultiArrayView<N3, T3, S3> const & m3,
1151 MultiArrayView<N4, T4, S4> const & m4,
1152 MultiArrayView<N5, T5, S5> const & m5)
1153 {
1154 typedef typename CoupledHandleType<N1, T1, T2, T3, T4, T5>::type P5;
1155 typedef typename P5::base_type P4;
1156 typedef typename P4::base_type P3;
1157 typedef typename P3::base_type P2;
1158 typedef typename P2::base_type P1;
1159 typedef typename P1::base_type P0;
1160 typedef CoupledScanOrderIterator<P1::dimensions, P5> IteratorType;
1161
1162 return IteratorType(P5(m5,
1163 P4(m4,
1164 P3(m3,
1165 P2(m2,
1166 P1(m1,
1167 P0(m1.shape())))))));
1168 }
1169
1170 //@}
1171
1172 } // namespace vigra
1173
1174 namespace std {
1175
1176 template <unsigned int N, class HANDLES, int DIMENSION>
1177 ostream & operator<<(ostream & o, vigra::CoupledScanOrderIterator<N, HANDLES, DIMENSION> const & i)
1178 {
1179 o << i.point();
1180 return o;
1181 }
1182
1183 } // namespace std
1184
1185 #endif /* MULTI_ITERATOR_COUPLED_HXX */

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.10.0 (Mon Nov 18 2013)