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