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

vigra/multi_iterator_coupled.hxx VIGRA

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*     Copyright 2011-2012 by Stefan Schmidt and Ullrich Koethe         */
00004 /*                                                                      */
00005 /*    This file is part of the VIGRA computer vision library.           */
00006 /*    The VIGRA Website is                                              */
00007 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
00008 /*    Please direct questions, bug reports, and contributions to        */
00009 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
00010 /*        vigra@informatik.uni-hamburg.de                               */
00011 /*                                                                      */
00012 /*    Permission is hereby granted, free of charge, to any person       */
00013 /*    obtaining a copy of this software and associated documentation    */
00014 /*    files (the "Software"), to deal in the Software without           */
00015 /*    restriction, including without limitation the rights to use,      */
00016 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
00017 /*    sell copies of the Software, and to permit persons to whom the    */
00018 /*    Software is furnished to do so, subject to the following          */
00019 /*    conditions:                                                       */
00020 /*                                                                      */
00021 /*    The above copyright notice and this permission notice shall be    */
00022 /*    included in all copies or substantial portions of the             */
00023 /*    Software.                                                         */
00024 /*                                                                      */
00025 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
00026 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
00027 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
00028 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
00029 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
00030 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
00031 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
00032 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
00033 /*                                                                      */
00034 /************************************************************************/
00035 
00036 #ifndef MULTI_ITERATOR_COUPLED_HXX_
00037 #define MULTI_ITERATOR_COUPLED_HXX_
00038 
00039 #include "metaprogramming.hxx"
00040 #include "multi_iterator.hxx"
00041 
00042 namespace vigra {
00043 
00044 /** \addtogroup MultiIteratorGroup
00045 */
00046 //@{
00047 
00048 
00049     // FIXME: this should go into its separate header file,
00050     //        together with the calculation of neighborhod offsets for GridGraph
00051 template <unsigned int N, unsigned int DIMENSION=N-1>
00052 struct NeighborhoodTypeImpl
00053 {
00054     typedef typename MultiArrayShape<N>::type shape_type;
00055     
00056     static unsigned int exec(shape_type const & point, shape_type const & shape)
00057     {
00058         unsigned int res = NeighborhoodTypeImpl<N, DIMENSION-1>::exec(point, shape);
00059         if(point[DIMENSION] == 0)
00060             res |= (1 << 2*DIMENSION);
00061         if(point[DIMENSION] == shape[DIMENSION]-1)
00062             res |= (2 << 2*DIMENSION);
00063         return res;
00064     }
00065 };
00066 
00067 template <unsigned int N>
00068 struct NeighborhoodTypeImpl<N, 0>
00069 {
00070     typedef typename MultiArrayShape<N>::type shape_type;
00071     static const unsigned int DIMENSION = 0;
00072     
00073     static unsigned int exec(shape_type const & point, shape_type const & shape)
00074     {
00075         unsigned int res = 0;
00076         if(point[DIMENSION] == 0)
00077             res |= (1 << 2*DIMENSION);
00078         if(point[DIMENSION] == shape[DIMENSION]-1)
00079             res |= (2 << 2*DIMENSION);
00080         return res;
00081     }
00082 };
00083 
00084   /**
00085      Handle class, used by CoupledScanOrderIterator as the value type to simultaneously itearate over multiple images.
00086   */
00087 template <class T, class NEXT>
00088 class CoupledHandle
00089 : public NEXT
00090 {
00091 public:
00092     typedef NEXT                            base_type;
00093     typedef CoupledHandle<T, NEXT>          self_type;
00094     
00095     static const int index =                NEXT::index + 1;    // index of this member of the chain
00096     static const unsigned int dimensions =  NEXT::dimensions;
00097 
00098     typedef T                               value_type;
00099     typedef T *                             pointer;
00100     typedef T const *                       const_pointer;
00101     typedef T &                             reference;
00102     typedef T const &                       const_reference;
00103     typedef typename base_type::shape_type  shape_type;
00104 
00105     CoupledHandle()
00106     : base_type(),
00107       pointer_(), 
00108       strides_()
00109     {}
00110 
00111     CoupledHandle(const_pointer p, shape_type const & strides, NEXT const & next)
00112     : base_type(next),
00113       pointer_(const_cast<pointer>(p)), 
00114       strides_(strides)
00115     {}
00116 
00117     template <class Stride>
00118     CoupledHandle(MultiArrayView<dimensions, T, Stride> const & v, NEXT const & next)
00119     : base_type(next),
00120       pointer_(const_cast<pointer>(v.data())), 
00121       strides_(v.stride())
00122     {
00123         vigra_precondition(v.shape() == this->shape(), "createCoupledIterator(): shape mismatch.");
00124     }
00125 
00126     template<int DIMENSION>
00127     inline void increment() 
00128     {
00129         pointer_ += strides_[DIMENSION];
00130         base_type::template increment<DIMENSION>();
00131     }
00132     
00133     template<int DIMENSION>
00134     inline void decrement() 
00135     {
00136         pointer_ -= strides_[DIMENSION];
00137         base_type::template decrement<DIMENSION>();
00138     }
00139     
00140     // TODO: test if making the above a default case of the this hurts performance
00141     template<int DIMENSION>
00142     inline void increment(MultiArrayIndex offset) 
00143     {
00144         pointer_ += offset*strides_[DIMENSION];
00145         base_type::template increment<DIMENSION>(offset);
00146     }
00147     
00148     template<int DIMENSION>
00149     inline void decrement(MultiArrayIndex offset) 
00150     {
00151         pointer_ -= offset*strides_[DIMENSION];
00152         base_type::template decrement<DIMENSION>(offset);
00153     }
00154     
00155     void restrictToSubarray(shape_type const & start, shape_type const & end)
00156     {
00157         pointer_ += dot(start, strides_);
00158         base_type::restrictToSubarray(start, end);
00159     }
00160 
00161     // ptr access
00162     reference operator*()
00163     {
00164         return *pointer_;
00165     }
00166 
00167     const_reference operator*() const
00168     {
00169         return *pointer_;
00170     }
00171 
00172     pointer operator->()
00173     {
00174         return pointer_;
00175     }
00176 
00177     const_pointer operator->() const
00178     {
00179         return pointer_;
00180     }
00181 
00182     pointer ptr()
00183     {
00184         return pointer_;
00185     }
00186 
00187     const_pointer ptr() const
00188     {
00189         return pointer_;
00190     }
00191 
00192     shape_type const & strides() const
00193     {
00194         return strides_;
00195     }
00196 
00197     pointer pointer_;
00198     shape_type strides_;
00199 };
00200 
00201 
00202 template <int N>
00203 class CoupledHandle<TinyVector<MultiArrayIndex, N>, void>
00204 {
00205 public:
00206     static const int index = 0;                   // index of this member of the chain
00207     static const unsigned int dimensions = N;
00208 
00209     typedef typename MultiArrayShape<N>::type   value_type;
00210     typedef value_type const *                  pointer;
00211     typedef value_type const *                  const_pointer;
00212     typedef value_type const &                  reference;
00213     typedef value_type const &                  const_reference;
00214     typedef value_type                          shape_type;
00215     typedef CoupledHandle<value_type, void>     self_type;
00216 
00217     CoupledHandle()
00218     : point_(),
00219       shape_(),
00220       scanOrderIndex_()
00221     {}
00222 
00223     CoupledHandle(value_type const & shape)
00224     : point_(),
00225       shape_(shape),
00226       scanOrderIndex_()
00227     {}
00228 
00229     CoupledHandle(typename MultiArrayShape<N+1>::type const & shape)
00230     : point_(),
00231       shape_(shape.begin()),
00232       scanOrderIndex_()
00233     {}
00234 
00235     template<int DIMENSION>
00236     inline void increment() 
00237     {
00238         ++point_[DIMENSION];
00239     }
00240     
00241     template<int DIMENSION>
00242     inline void decrement() 
00243     {
00244         --point_[DIMENSION];
00245     }
00246     
00247     // TODO: test if making the above a default case of the this hurts performance
00248     template<int DIMENSION>
00249     inline void increment(MultiArrayIndex offset) 
00250     {
00251         point_[DIMENSION] += offset;
00252     }
00253     
00254     template<int DIMENSION>
00255     inline void decrement(MultiArrayIndex offset) 
00256     {
00257         point_[DIMENSION] -= offset;
00258     }
00259     
00260     void restrictToSubarray(shape_type const & start, shape_type const & end)
00261     {
00262         point_ = shape_type();
00263         shape_ = end - start;
00264         scanOrderIndex_ = 0;
00265     }
00266 
00267     inline void incrementIndex() 
00268     {
00269         ++scanOrderIndex_;
00270     }
00271     
00272     inline void decrementIndex() 
00273     {
00274         --scanOrderIndex_;
00275     }
00276     
00277     inline void incrementIndex(MultiArrayIndex offset) 
00278     {
00279         scanOrderIndex_ += offset;
00280     }
00281     
00282     inline void decrementIndex(MultiArrayIndex offset) 
00283     {
00284         scanOrderIndex_ -= offset;
00285     }
00286 
00287     // access
00288     MultiArrayIndex scanOrderIndex() const
00289     {
00290         return scanOrderIndex_;
00291     }
00292     
00293     // access
00294     const_reference point() const
00295     {
00296         return point_;
00297     }
00298     
00299     // access
00300     const_reference shape() const
00301     {
00302         return shape_;
00303     }
00304 
00305     const_reference operator*() const
00306     {
00307         return point_;
00308     }
00309 
00310     const_pointer operator->() const
00311     {
00312         return &point_;
00313     }
00314 
00315     const_pointer ptr() const
00316     {
00317         return &point_;
00318     }
00319     
00320     unsigned int neighborhoodType() const
00321     {
00322         return NeighborhoodTypeImpl<N>::exec(point_, shape_);
00323     }
00324 
00325     value_type point_, shape_;
00326     MultiArrayIndex scanOrderIndex_;
00327 };
00328 
00329 template <class T>
00330 struct Multiband;
00331 
00332 template <unsigned int N, class T, class StrideTag>
00333 class MultiArrayView<N, Multiband<T>, StrideTag>
00334 : public MultiArrayView<N, T, StrideTag>
00335 {
00336   public:
00337     MultiArrayView(MultiArrayView<N, T, StrideTag> const & v)
00338     : MultiArrayView<N, T, StrideTag>(v)
00339     {}
00340 };
00341 
00342 template <class T, class NEXT>
00343 class CoupledHandle<Multiband<T>, NEXT>
00344 : public NEXT
00345 {
00346 public:
00347     typedef NEXT                                  base_type;
00348     typedef CoupledHandle<Multiband<T>, NEXT>     self_type;
00349     
00350     static const int index =                      NEXT::index + 1;    // index of this member of the chain
00351     static const unsigned int dimensions =        NEXT::dimensions;
00352 
00353     typedef MultiArrayView<1, T, StridedArrayTag> value_type;
00354     typedef value_type *                          pointer;
00355     typedef value_type const *                    const_pointer;
00356     typedef value_type &                          reference;
00357     typedef value_type const &                    const_reference;
00358     typedef typename base_type::shape_type        shape_type;
00359 
00360     CoupledHandle()
00361     : base_type(),
00362       view_(), 
00363       strides_()
00364     {}
00365 
00366     CoupledHandle(const_reference p, shape_type const & strides, NEXT const & next)
00367     : base_type(next),
00368       view_(p), 
00369       strides_(strides)
00370     {}
00371 
00372     template <class Stride>
00373     CoupledHandle(MultiArrayView<dimensions+1, Multiband<T>, Stride> const & v, NEXT const & next)
00374     : base_type(next),
00375       view_(v.bindInner(shape_type())), 
00376       strides_(v.bindOuter(0).stride())
00377     {
00378         vigra_precondition(v.bindOuter(0).shape() == this->shape(), "createCoupledIterator(): shape mismatch.");
00379     }
00380 
00381     template<int DIMENSION>
00382     inline void increment() 
00383     {
00384         view_.unsafePtr() += strides_[DIMENSION];
00385         base_type::template increment<DIMENSION>();
00386     }
00387     
00388     template<int DIMENSION>
00389     inline void decrement() 
00390     {
00391         view_.unsafePtr() -= strides_[DIMENSION];
00392         base_type::template decrement<DIMENSION>();
00393     }
00394     
00395     // TODO: test if making the above a default case of the this hurts performance
00396     template<int DIMENSION>
00397     inline void increment(MultiArrayIndex offset) 
00398     {
00399         view_.unsafePtr() += offset*strides_[DIMENSION];
00400         base_type::template increment<DIMENSION>(offset);
00401     }
00402     
00403     template<int DIMENSION>
00404     inline void decrement(MultiArrayIndex offset) 
00405     {
00406         view_.unsafePtr() -= offset*strides_[DIMENSION];
00407         base_type::template decrement<DIMENSION>(offset);
00408     }
00409     
00410     void restrictToSubarray(shape_type const & start, shape_type const & end)
00411     {
00412         view_.unsafePtr() += dot(start, strides_);
00413         base_type::restrictToSubarray(start, end);
00414     }
00415 
00416     // ptr access
00417     reference operator*()
00418     {
00419         return view_;
00420     }
00421 
00422     const_reference operator*() const
00423     {
00424         return view_;
00425     }
00426 
00427     pointer operator->()
00428     {
00429         return &view_;
00430     }
00431 
00432     const_pointer operator->() const
00433     {
00434         return &view_;
00435     }
00436 
00437     pointer ptr()
00438     {
00439         return &view_;
00440     }
00441 
00442     const_pointer ptr() const
00443     {
00444         return &view_;
00445     }
00446 
00447     shape_type const & strides() const
00448     {
00449         return strides_;
00450     }
00451 
00452     value_type view_;
00453     shape_type strides_;
00454 };
00455 
00456 template <unsigned TARGET_INDEX>
00457 struct Error__CoupledHandle_index_out_of_range;
00458 
00459 namespace detail {
00460 
00461 template <unsigned TARGET_INDEX, class Handle, bool isValid, unsigned int INDEX=Handle::index>
00462 struct CoupledHandleCastImpl
00463 {
00464     typedef typename CoupledHandleCastImpl<TARGET_INDEX, typename Handle::base_type, isValid>::type type;
00465 };
00466 
00467 template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX>
00468 struct CoupledHandleCastImpl<TARGET_INDEX, Handle, false, INDEX>
00469 {
00470     typedef Error__CoupledHandle_index_out_of_range<TARGET_INDEX> type;
00471 };
00472 
00473 template <unsigned TARGET_INDEX, class Handle>
00474 struct CoupledHandleCastImpl<TARGET_INDEX, Handle, true, TARGET_INDEX>
00475 {
00476     typedef Handle type;
00477 };
00478 
00479 } // namespace detail
00480 
00481 template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX=Handle::index>
00482 struct CoupledHandleCast
00483 : public detail::CoupledHandleCastImpl<TARGET_INDEX, Handle, (TARGET_INDEX <= INDEX), INDEX>
00484 {};
00485 
00486 template <unsigned int TARGET_INDEX, class Handle>
00487 typename CoupledHandleCast<TARGET_INDEX, Handle>::type &
00488 cast(Handle & handle)
00489 {
00490     return handle;
00491 };
00492 
00493 template <unsigned int TARGET_INDEX, class Handle>
00494 typename CoupledHandleCast<TARGET_INDEX, Handle>::type const &
00495 cast(Handle const & handle)
00496 {
00497     return handle;
00498 };
00499 
00500   /** Returns reference to the element in the band of the handle with index TARGET_INDEX.
00501    */
00502 template <unsigned int TARGET_INDEX, class Handle>
00503 typename CoupledHandleCast<TARGET_INDEX, Handle>::type::reference
00504 get(Handle & handle)
00505 {
00506     return *cast<TARGET_INDEX>(handle);
00507 };
00508 
00509   /** Returns a constant reference to the element in the band of the handle with index TARGET_INDEX.
00510    */
00511 template <unsigned int TARGET_INDEX, class Handle>
00512 typename CoupledHandleCast<TARGET_INDEX, Handle>::type::const_reference
00513 get(Handle const & handle)
00514 {
00515     return *cast<TARGET_INDEX>(handle);
00516 };
00517 
00518 /********************************************************/
00519 /*                                                      */
00520 /*               CoupledScanOrderIterator<N>            */
00521 /*                                                      */
00522 /********************************************************/
00523 
00524 /** \brief Iterate over multiple images simultaneously in scan order. 
00525 
00526     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).
00527     
00528     Instances of this class are usually constructed by calling createCoupledIterator() .
00529 
00530     To get the type of a CoupledScanOrderIterator for arrays of a certain dimension and element types use CoupledIteratorType::type.
00531 
00532     The iterator supports all functions listed in the STL documentation for
00533         <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
00534 Access Iterators</a>.
00535 
00536     Example of use:
00537     \code
00538     using namespace vigra;
00539     MultiArray<2, double> image1(Shape2(5, 5));
00540     MultiArray<2, double> image2(Shape2(5, 5));
00541     // fill image with data ...
00542     
00543     typedef CoupledIteratorType<2, double, double>::type Iterator; // the type of the CoupledScanOrderIterator
00544     
00545     Iterator start = createCoupledIterator(image1, image2); // create coupled iterator for simultaneous iteration over image1, image2 and their coordinates
00546     Iterator end = start.getEndIterator();
00547     
00548     for (Iterator it = start; it < end; ++it) {
00549       std::cout << "coordinates: " << it.get<0>() << std::endl;
00550       std::cout << "image1: " << it.get<1>() << std::endl;
00551       std::cout << "image2: " << it.get<2>() << std::endl;
00552     }
00553     
00554     //random access:
00555     Iterator::value_type handle = start[15];
00556     std::cout << "image1: " << get<1>(handle) << std::endl;
00557     \endcode
00558     
00559 <b>\#include</b> <vigra/multi_iterator_coupled.hxx>
00560 
00561 Namespace: vigra
00562 */
00563 
00564 template <unsigned int N,
00565           class HANDLES,
00566           int DIMENSION = N-1>
00567 class CoupledScanOrderIterator
00568 #ifndef DOXYGEN  // doxygen doesn't understand this inheritance
00569 : protected CoupledScanOrderIterator<N, HANDLES, DIMENSION-1>
00570 #endif
00571 {
00572     typedef CoupledScanOrderIterator<N, HANDLES, DIMENSION-1> base_type;
00573     static const int dimension = DIMENSION;
00574 
00575   public:
00576 
00577     typedef typename MultiArrayShape<dimension+1>::type        shape_type;
00578     typedef MultiArrayIndex                   difference_type;
00579     typedef CoupledScanOrderIterator          iterator;
00580     typedef std::random_access_iterator_tag   iterator_category;
00581 
00582     typedef typename base_type::value_type      value_type;
00583 
00584 #ifdef DOXYGEN
00585   /** The type of the CoupledHandle.
00586    */
00587     typedef HANDLES value_type;
00588 #endif
00589 
00590     typedef typename base_type::reference       reference;
00591     typedef typename base_type::const_reference const_reference; // FIXME: do we need both?
00592     typedef typename base_type::pointer         pointer;
00593 
00594     CoupledScanOrderIterator(value_type const & handles = value_type())
00595     : base_type(handles)
00596     {}
00597 
00598     value_type operator[](MultiArrayIndex i) const
00599     {
00600         return *(CoupledScanOrderIterator(*this) += i);
00601     }
00602 
00603     CoupledScanOrderIterator & operator++()
00604     {
00605         base_type::operator++();
00606         if(this->point()[dimension-1] == this->shape()[dimension-1])
00607         {
00608             base_type::reset();
00609             this->handles_.template increment<dimension>();
00610         }
00611         return *this;
00612     }
00613 
00614     CoupledScanOrderIterator operator++(int)
00615     {
00616         CoupledScanOrderIterator res(*this);
00617         ++*this;
00618         return res;
00619     }
00620 
00621     CoupledScanOrderIterator & operator+=(MultiArrayIndex i)
00622     {
00623         // FIXME: this looks very expensive
00624         shape_type coordOffset;
00625         detail::ScanOrderToCoordinate<N>::exec(i+scanOrderIndex(), this->shape(), coordOffset);
00626         coordOffset -= point();
00627         moveRelative(coordOffset);
00628         this->handles_.scanOrderIndex_ += i;
00629         return *this;
00630     }
00631 
00632     CoupledScanOrderIterator & operator+=(const shape_type &coordOffset)
00633     {
00634         moveRelative(coordOffset);
00635         this->handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec(this->shape(), coordOffset);
00636         return *this;
00637     }
00638 
00639     CoupledScanOrderIterator & operator--()
00640     {
00641         base_type::operator--();
00642         if(this->point()[dimension-1] == -1)
00643         {
00644             base_type::inverseReset();
00645             this->handles_.template decrement<dimension>();
00646         }
00647         return *this;
00648     }
00649 
00650     CoupledScanOrderIterator operator--(int)
00651     {
00652         CoupledScanOrderIterator res(*this);
00653         --*this;
00654         return res;
00655     }
00656 
00657     CoupledScanOrderIterator & operator-=(MultiArrayIndex i)
00658     {
00659         return operator+=(-i);
00660     }
00661 
00662     CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
00663     {
00664         return operator+=(-coordOffset);
00665     }
00666 
00667     /** Returns CoupledScanOrderIterator pointing beyond the last element.
00668     */
00669     CoupledScanOrderIterator getEndIterator() const
00670     {
00671         return operator+(prod(this->shape()));
00672     }
00673 
00674     CoupledScanOrderIterator operator+(MultiArrayIndex d) const
00675     {
00676         return CoupledScanOrderIterator(*this) += d;
00677     }
00678 
00679     CoupledScanOrderIterator operator-(MultiArrayIndex d) const
00680     {
00681         return CoupledScanOrderIterator(*this) -= d;
00682     }
00683 
00684     CoupledScanOrderIterator operator+(const shape_type &coordOffset) const
00685     {
00686         return CoupledScanOrderIterator(*this) += coordOffset;
00687     }
00688 
00689     CoupledScanOrderIterator operator-(const shape_type &coordOffset) const
00690     {
00691         return CoupledScanOrderIterator(*this) -= coordOffset;
00692     }
00693 
00694     MultiArrayIndex operator-(CoupledScanOrderIterator const & r) const
00695     {
00696         return base_type::operator-(r);
00697     }
00698 
00699     bool operator==(CoupledScanOrderIterator const & r)
00700     {
00701         return base_type::operator==(r);
00702     }
00703 
00704     bool operator!=(CoupledScanOrderIterator const & r) const
00705     {
00706         return base_type::operator!=(r);
00707     }
00708 
00709     bool operator<(CoupledScanOrderIterator const & r) const
00710     {
00711         return base_type::operator<(r);
00712     }
00713 
00714     bool operator<=(CoupledScanOrderIterator const & r) const
00715     {
00716         return base_type::operator<=(r);
00717     }
00718 
00719     bool operator>(CoupledScanOrderIterator const & r) const
00720     {
00721         return base_type::operator>(r);
00722     }
00723 
00724     bool operator>=(CoupledScanOrderIterator const & r) const
00725     {
00726         return base_type::operator>=(r);
00727     }
00728 
00729     using base_type::operator*;
00730     using base_type::point;
00731     using base_type::shape;
00732     using base_type::scanOrderIndex;
00733     using base_type::atBorder;
00734     using base_type::neighborhoodType;
00735     using base_type::get;
00736 
00737 #ifdef DOXYGEN
00738   
00739   /** Returns reference to the element in the band with index TARGET_INDEX.
00740   */
00741   template<unsigned int TARGET_INDEX> 
00742   typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference
00743   get() 
00744   {
00745     return vigra::get<TARGET_INDEX>(handles_);
00746   }
00747 
00748   /** Returns constant reference to the element in the band with index TARGET_INDEX.
00749   */
00750   template<unsigned int TARGET_INDEX> 
00751   typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_reference
00752   get() const
00753   {
00754     return vigra::get<TARGET_INDEX>(handles_);
00755   }
00756 #endif
00757 
00758   protected:
00759     void reset()
00760     {
00761         this->handles_.template decrement<dimension>(this->shape()[dimension]);
00762     }
00763 
00764     void inverseReset()
00765     {
00766         this->handles_.template increment<dimension>(this->shape()[dimension]);
00767     }
00768 
00769     void moveRelative(typename value_type::shape_type const & coordOffset)
00770     {
00771         base_type::moveRelative(coordOffset);
00772         this->handles_.template increment<dimension>(coordOffset[dimension]);
00773     }
00774 };
00775 
00776 
00777 
00778 template <unsigned int N, class HANDLES>
00779 class CoupledScanOrderIterator<N, HANDLES, 0>
00780 {
00781     static const int dimension = 0;
00782 
00783   public:
00784 
00785     typedef CoupledScanOrderIterator<N, HANDLES, 0>  self_type;
00786     typedef HANDLES                                  value_type;
00787     typedef MultiArrayIndex                          difference_type;
00788     typedef value_type &                             reference;
00789     typedef value_type const &                       const_reference; 
00790     typedef value_type *                             pointer;
00791     typedef typename MultiArrayShape<1>::type        shape_type;
00792     typedef CoupledScanOrderIterator                 iterator;
00793     typedef std::random_access_iterator_tag          iterator_category;
00794 
00795     CoupledScanOrderIterator(value_type const & handles = value_type())
00796     : handles_(handles)
00797     {}
00798 
00799     CoupledScanOrderIterator & operator++()
00800     {
00801         handles_.template increment<dimension>();
00802         handles_.incrementIndex();
00803         return *this;
00804     }
00805 
00806     CoupledScanOrderIterator operator++(int)
00807     {
00808         CoupledScanOrderIterator res(*this);
00809         ++*this;
00810         return res;
00811     }
00812 
00813     CoupledScanOrderIterator & operator+=(MultiArrayIndex i)
00814     {
00815         shape_type coordOffset;
00816         detail::ScanOrderToCoordinate<N>::exec(i, shape(), coordOffset);
00817         moveRelative(coordOffset);
00818         handles_.scanOrderIndex_ += i;
00819         return *this;
00820     }
00821 
00822     CoupledScanOrderIterator & operator+=(const shape_type &coordOffset)
00823     {
00824         moveRelative(coordOffset);
00825         handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec(shape(), coordOffset);
00826         return *this;
00827     }
00828 
00829     CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
00830     {
00831         return operator+=(-coordOffset);
00832     }
00833 
00834     CoupledScanOrderIterator & operator--()
00835     {
00836         handles_.template decrement<dimension>();
00837         handles_.decrementIndex();
00838         return *this;
00839     }
00840 
00841     CoupledScanOrderIterator operator--(int)
00842     {
00843         CoupledScanOrderIterator res(*this);
00844         --this;
00845         return res;
00846     }
00847 
00848     CoupledScanOrderIterator & operator-=(MultiArrayIndex i)
00849     {
00850         return operator+=(-i);
00851     }
00852 
00853     value_type operator[](MultiArrayIndex i) const
00854     {
00855         return *(CoupledScanOrderIterator(*this) += i);
00856     }
00857 
00858     CoupledScanOrderIterator
00859     operator+(MultiArrayIndex d) const
00860     {
00861         return CoupledScanOrderIterator(*this) += d;
00862     }
00863 
00864     CoupledScanOrderIterator
00865     operator-(MultiArrayIndex d) const
00866     {
00867         return CoupledScanOrderIterator(*this) -= d;
00868     }
00869 
00870     CoupledScanOrderIterator operator+(const shape_type &coordOffset) const
00871     {
00872         return CoupledScanOrderIterator(*this) += coordOffset;
00873     }
00874     
00875     CoupledScanOrderIterator operator-(const shape_type &coordOffset) const
00876     {
00877         return CoupledScanOrderIterator(*this) -= coordOffset;
00878     }
00879 
00880     MultiArrayIndex
00881     operator-(CoupledScanOrderIterator const & r) const
00882     {
00883         return scanOrderIndex() - r.scanOrderIndex();
00884     }
00885 
00886     bool
00887     operator==(CoupledScanOrderIterator const & r)
00888     {
00889         return scanOrderIndex() == r.scanOrderIndex();
00890     }
00891 
00892     bool
00893     operator!=(CoupledScanOrderIterator const & r) const
00894     {
00895         return scanOrderIndex() != r.scanOrderIndex();
00896     }
00897 
00898     bool
00899     operator<(CoupledScanOrderIterator const & r) const
00900     {
00901         return scanOrderIndex() < r.scanOrderIndex();
00902     }
00903 
00904     bool
00905     operator<=(CoupledScanOrderIterator const & r) const
00906     {
00907         return scanOrderIndex() <= r.scanOrderIndex();
00908     }
00909 
00910     bool
00911     operator>(CoupledScanOrderIterator const & r) const
00912     {
00913         return scanOrderIndex() > r.scanOrderIndex();
00914     }
00915 
00916     bool
00917     operator>=(CoupledScanOrderIterator const & r) const
00918     {
00919         return scanOrderIndex() >= r.scanOrderIndex();
00920     }
00921 
00922     MultiArrayIndex scanOrderIndex() const
00923     {
00924         return handles_.scanOrderIndex();
00925     }
00926 
00927     typename value_type::shape_type const & point() const
00928     {
00929         return handles_.point();
00930     }
00931 
00932     typename value_type::shape_type const & shape() const
00933     {
00934         return handles_.shape();
00935     }
00936 
00937     reference operator*()
00938     {
00939         return handles_;
00940     }
00941 
00942     const_reference operator*() const
00943     {
00944         return handles_;
00945     }
00946 
00947     void restrictToSubarray(shape_type const & start, shape_type const & end) const
00948     {
00949         operator+=(-point());
00950         handles_.restricToSubarray(start, end);
00951     }
00952 
00953     CoupledScanOrderIterator getEndIterator() const
00954     {
00955         return operator+(prod(shape()));
00956     }
00957 
00958     bool atBorder() const
00959     {
00960         return (handles_.neighborhoodType() != 0);
00961     }
00962 
00963     unsigned int neighborhoodType() const
00964     {
00965         return handles_.neighborhoodType();
00966     }
00967 
00968     template<unsigned int TARGET_INDEX> 
00969     typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference
00970     get() 
00971     {
00972         return vigra::get<TARGET_INDEX>(handles_);
00973     }
00974 
00975     template<unsigned int TARGET_INDEX> 
00976     typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_reference
00977     get() const
00978     {
00979         return vigra::get<TARGET_INDEX>(handles_);
00980     }
00981 
00982   protected:
00983     void reset()
00984     {
00985         handles_.template decrement<dimension>(shape()[dimension]);
00986     }
00987 
00988     void inverseReset()
00989     {
00990         handles_.template increment<dimension>(shape()[dimension]);
00991     }
00992 
00993     void moveRelative(typename value_type::shape_type const & coordOffset)
00994     {
00995         handles_.template increment<dimension>(coordOffset[dimension]);
00996     }   
00997     
00998     value_type handles_;
00999 };
01000 
01001 
01002 template <unsigned int N, class List>
01003 struct ComposeCoupledHandle;
01004 
01005 template <unsigned int N, class T, class TAIL>
01006 struct ComposeCoupledHandle<N, TypeList<T, TAIL> >
01007 {
01008     typedef typename ComposeCoupledHandle<N, TAIL>::type  BaseType;
01009     typedef typename MultiArrayShape<N>::type             shape_type;
01010     typedef CoupledHandle<T, BaseType>                    type;
01011     
01012     template <class S>
01013     type exec(MultiArrayView<N, T, S> const & m, 
01014               shape_type const & start, shape_type const & end,
01015               BaseType const & base)
01016     {
01017         return type(m.subarray(start, end).data(), m.stride(), base);
01018     }
01019     
01020     template <class S>
01021     type exec(MultiArrayView<N, T, S> const & m, BaseType const & base)
01022     {
01023         return type(m.data(), m.stride(), base);
01024     }
01025 };
01026 
01027 template <unsigned int N>
01028 struct ComposeCoupledHandle<N, void>
01029 {
01030     typedef typename MultiArrayShape<N>::type  shape_type;
01031     typedef CoupledHandle<shape_type, void>    type;
01032     
01033     type exec(shape_type const & shape)
01034     {
01035         return type(shape);
01036     }
01037     
01038     type exec(shape_type const & start, shape_type const & end)
01039     {
01040         return type(end-start);
01041     }
01042 };
01043 
01044 template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
01045 struct CoupledHandleType
01046 {
01047     // reverse the order to get the desired index order
01048     typedef typename MakeTypeList<T5, T4, T3, T2, T1>::type TypeList;
01049     typedef typename ComposeCoupledHandle<N, TypeList>::type type;
01050 };
01051 
01052 template <unsigned int N, class T1, class T2, class T3, class T4, class T5>
01053 struct CoupledHandleType<N, Multiband<T1>, T2, T3, T4, T5>
01054 {
01055     // reverse the order to get the desired index order
01056     typedef typename MakeTypeList<T5, T4, T3, T2, Multiband<T1> >::type TypeList;
01057     typedef typename ComposeCoupledHandle<N-1, TypeList>::type type;
01058 };
01059 
01060 /** 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.
01061  */
01062 template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
01063 struct CoupledIteratorType
01064 {
01065     /** Type of the CoupledHandle.*/
01066     typedef typename CoupledHandleType<N, T1, T2, T3, T4, T5>::type HandleType;
01067   
01068     /** Type of the CoupledScanOrderIterator.*/
01069     typedef CoupledScanOrderIterator<HandleType::dimensions, HandleType> type;
01070 };
01071 
01072 /** Returns a CoupledScanOrderIterator from shape to iterate over coordinates. 
01073  */
01074 template <int N>
01075 typename CoupledIteratorType<N>::type
01076 createCoupledIterator(TinyVector<MultiArrayIndex, N> const & shape)
01077 {
01078     typedef typename CoupledHandleType<N>::type   P0;
01079     typedef CoupledScanOrderIterator<N, P0> IteratorType;
01080     
01081     return IteratorType(P0(shape));
01082 }
01083 
01084 /** Returns a CoupledScanOrderIterator to simultaneously iterate over image m1 and its coordinates. 
01085  */
01086 template <unsigned int N1, class T1, class S1>
01087 typename CoupledIteratorType<N1, T1>::type
01088 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1)
01089 {
01090     typedef typename CoupledHandleType<N1, T1>::type             P1;
01091     typedef typename P1::base_type                               P0;
01092     typedef CoupledScanOrderIterator<P1::dimensions, P1>         IteratorType;
01093     
01094     return IteratorType(P1(m1, 
01095                         P0(m1.shape())));
01096 }
01097 
01098 /** Returns a CoupledScanOrderIterator to simultaneously iterate over images m1, m2 and their coordinates. 
01099  */
01100 template <unsigned int N1, class T1, class S1,
01101           unsigned int N2, class T2, class S2>
01102 typename CoupledIteratorType<N1, T1, T2>::type
01103 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
01104                       MultiArrayView<N2, T2, S2> const & m2)
01105 {
01106     typedef typename CoupledHandleType<N1, T1, T2>::type         P2;
01107     typedef typename P2::base_type                               P1;
01108     typedef typename P1::base_type                               P0;
01109     typedef CoupledScanOrderIterator<P2::dimensions, P2> IteratorType;
01110     
01111     return IteratorType(P2(m2, 
01112                         P1(m1, 
01113                         P0(m1.shape()))));
01114 }
01115 
01116 /** Returns a CoupledScanOrderIterator to simultaneously iterate over images m1, m2, m3 and their coordinates. 
01117  */
01118 template <unsigned int N1, class T1, class S1,
01119           unsigned int N2, class T2, class S2,
01120           unsigned int N3, class T3, class S3>
01121 typename CoupledIteratorType<N1, T1, T2, T3>::type
01122 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
01123                       MultiArrayView<N2, T2, S2> const & m2,
01124                       MultiArrayView<N3, T3, S3> const & m3)
01125 {
01126     typedef typename CoupledHandleType<N1, T1, T2, T3>::type     P3;
01127     typedef typename P3::base_type                               P2;
01128     typedef typename P2::base_type                               P1;
01129     typedef typename P1::base_type                               P0;
01130     typedef CoupledScanOrderIterator<P3::dimensions, P3> IteratorType;
01131     
01132     return IteratorType(P3(m3, 
01133                         P2(m2, 
01134                         P1(m1, 
01135                         P0(m1.shape())))));
01136 }
01137 
01138 /** Returns a CoupledScanOrderIterator to simultaneously iterate over images m1, m2, m3, m4 and their coordinates. 
01139  */
01140 template <unsigned int N1, class T1, class S1,
01141           unsigned int N2, class T2, class S2,
01142           unsigned int N3, class T3, class S3,
01143           unsigned int N4, class T4, class S4>
01144 typename CoupledIteratorType<N1, T1, T2, T3, T4>::type
01145 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
01146                       MultiArrayView<N2, T2, S2> const & m2,
01147                       MultiArrayView<N3, T3, S3> const & m3,
01148                       MultiArrayView<N4, T4, S4> const & m4)
01149 {
01150     typedef typename CoupledHandleType<N1, T1, T2, T3, T4>::type P4;
01151     typedef typename P4::base_type                               P3;
01152     typedef typename P3::base_type                               P2;
01153     typedef typename P2::base_type                               P1;
01154     typedef typename P1::base_type                               P0;
01155     typedef CoupledScanOrderIterator<P4::dimensions, P4> IteratorType;
01156     
01157     return IteratorType(P4(m4, 
01158                         P3(m3, 
01159                         P2(m2, 
01160                         P1(m1, 
01161                         P0(m1.shape()))))));
01162 }
01163 
01164 /** Returns a CoupledScanOrderIterator to simultaneously iterate over images m1, m2, m3, m4, m5 and their coordinates. 
01165  */
01166 template <unsigned int N1, class T1, class S1,
01167           unsigned int N2, class T2, class S2,
01168           unsigned int N3, class T3, class S3,
01169           unsigned int N4, class T4, class S4,
01170           unsigned int N5, class T5, class S5>
01171 typename CoupledIteratorType<N1, T1, T2, T3, T4, T5>::type
01172 createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
01173                       MultiArrayView<N2, T2, S2> const & m2,
01174                       MultiArrayView<N3, T3, S3> const & m3,
01175                       MultiArrayView<N4, T4, S4> const & m4,
01176                       MultiArrayView<N5, T5, S5> const & m5)
01177 {
01178     typedef typename CoupledHandleType<N1, T1, T2, T3, T4, T5>::type P5;
01179     typedef typename P5::base_type                                   P4;
01180     typedef typename P4::base_type                                   P3;
01181     typedef typename P3::base_type                                   P2;
01182     typedef typename P2::base_type                                   P1;
01183     typedef typename P1::base_type                                   P0;
01184     typedef CoupledScanOrderIterator<P1::dimensions, P5> IteratorType;
01185     
01186     return IteratorType(P5(m5, 
01187                         P4(m4, 
01188                         P3(m3, 
01189                         P2(m2, 
01190                         P1(m1, 
01191                         P0(m1.shape())))))));
01192 }
01193 
01194 //@}
01195 
01196 } // namespace vigra
01197 
01198 #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 (Tue Nov 6 2012)