[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 2003-2008 by Gunnar Kedenburg and Ullrich Koethe */ 00004 /* */ 00005 /* This file is part of the VIGRA computer vision library. */ 00006 /* ( Version 1.6.0, Aug 13 2008 ) */ 00007 /* The VIGRA Website is */ 00008 /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ 00009 /* Please direct questions, bug reports, and contributions to */ 00010 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 00011 /* vigra@informatik.uni-hamburg.de */ 00012 /* */ 00013 /* Permission is hereby granted, free of charge, to any person */ 00014 /* obtaining a copy of this software and associated documentation */ 00015 /* files (the "Software"), to deal in the Software without */ 00016 /* restriction, including without limitation the rights to use, */ 00017 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 00018 /* sell copies of the Software, and to permit persons to whom the */ 00019 /* Software is furnished to do so, subject to the following */ 00020 /* conditions: */ 00021 /* */ 00022 /* The above copyright notice and this permission notice shall be */ 00023 /* included in all copies or substantial portions of the */ 00024 /* Software. */ 00025 /* */ 00026 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 00027 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 00028 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 00029 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 00030 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 00031 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 00032 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 00033 /* OTHER DEALINGS IN THE SOFTWARE. */ 00034 /* */ 00035 /************************************************************************/ 00036 00037 00038 #ifndef VIGRA_MULTI_ARRAY_HXX 00039 #define VIGRA_MULTI_ARRAY_HXX 00040 00041 #include <memory> 00042 #include <algorithm> 00043 #include "accessor.hxx" 00044 #include "tinyvector.hxx" 00045 #include "rgbvalue.hxx" 00046 #include "basicimageview.hxx" 00047 #include "imageiterator.hxx" 00048 #include "numerictraits.hxx" 00049 #include "multi_iterator.hxx" 00050 #include "metaprogramming.hxx" 00051 #include "mathutil.hxx" 00052 00053 namespace vigra 00054 { 00055 00056 namespace detail 00057 { 00058 /********************************************************/ 00059 /* */ 00060 /* defaultStride */ 00061 /* */ 00062 /********************************************************/ 00063 00064 /* generates the stride for a gapless shape. 00065 00066 Namespace: vigra::detail 00067 */ 00068 template <unsigned int N> 00069 inline TinyVector <MultiArrayIndex, N> 00070 defaultStride(const TinyVector <MultiArrayIndex, N> &shape) 00071 { 00072 TinyVector <MultiArrayIndex, N> ret; 00073 ret [0] = 1; 00074 for (int i = 1; i < (int)N; ++i) 00075 ret [i] = ret [i-1] * shape [i-1]; 00076 return ret; 00077 } 00078 00079 /********************************************************/ 00080 /* */ 00081 /* ScanOrderToOffset */ 00082 /* */ 00083 /********************************************************/ 00084 00085 /* transforms an index in scan order sense to a pointer offset in a possibly 00086 strided, multi-dimensional array. 00087 00088 Namespace: vigra::detail 00089 */ 00090 00091 template <int K> 00092 struct ScanOrderToOffset 00093 { 00094 template <int N> 00095 static MultiArrayIndex 00096 exec(MultiArrayIndex d, const TinyVector <MultiArrayIndex, N> &shape, 00097 const TinyVector <MultiArrayIndex, N> & stride) 00098 { 00099 return stride[N-K] * (d % shape[N-K]) + 00100 ScanOrderToOffset<K-1>::exec(d / shape[N-K], shape, stride); 00101 } 00102 }; 00103 00104 template <> 00105 struct ScanOrderToOffset<1> 00106 { 00107 template <int N> 00108 static MultiArrayIndex 00109 exec(MultiArrayIndex d, const TinyVector <MultiArrayIndex, N> & /*shape*/, 00110 const TinyVector <MultiArrayIndex, N> & stride) 00111 { 00112 return stride[N-1] * d; 00113 } 00114 }; 00115 00116 template <int K> 00117 struct ScanOrderToCoordinate 00118 { 00119 template <int N> 00120 static void 00121 exec(MultiArrayIndex d, const TinyVector <MultiArrayIndex, N> &shape, 00122 TinyVector <MultiArrayIndex, N> & result) 00123 { 00124 result[N-K] = (d % shape[N-K]); 00125 ScanOrderToCoordinate<K-1>::exec(d / shape[N-K], shape, result); 00126 } 00127 }; 00128 00129 template <> 00130 struct ScanOrderToCoordinate<1> 00131 { 00132 template <int N> 00133 static void 00134 exec(MultiArrayIndex d, const TinyVector <MultiArrayIndex, N> & /*shape*/, 00135 TinyVector <MultiArrayIndex, N> & result) 00136 { 00137 result[N-1] = d; 00138 } 00139 }; 00140 00141 template <int K> 00142 struct CoordinateToScanOrder 00143 { 00144 template <int N> 00145 static MultiArrayIndex 00146 exec(const TinyVector <MultiArrayIndex, N> &shape, 00147 const TinyVector <MultiArrayIndex, N> & coordinate) 00148 { 00149 return coordinate[N-K] + shape[N-K] * CoordinateToScanOrder<K-1>::exec(shape, coordinate); 00150 } 00151 }; 00152 00153 template <> 00154 struct CoordinateToScanOrder<1> 00155 { 00156 template <int N> 00157 static MultiArrayIndex 00158 exec(const TinyVector <MultiArrayIndex, N> & /*shape*/, 00159 const TinyVector <MultiArrayIndex, N> & coordinate) 00160 { 00161 return coordinate[N-1]; 00162 } 00163 }; 00164 00165 00166 template <class C> 00167 struct CoordinatesToOffest 00168 { 00169 template <int N> 00170 static MultiArrayIndex 00171 exec(const TinyVector <MultiArrayIndex, N> & stride, MultiArrayIndex x) 00172 { 00173 return stride[0] * x; 00174 } 00175 template <int N> 00176 static MultiArrayIndex 00177 exec(const TinyVector <MultiArrayIndex, N> & stride, MultiArrayIndex x, MultiArrayIndex y) 00178 { 00179 return stride[0] * x + stride[1] * y; 00180 } 00181 }; 00182 00183 template <> 00184 struct CoordinatesToOffest<UnstridedArrayTag> 00185 { 00186 template <int N> 00187 static MultiArrayIndex 00188 exec(const TinyVector <MultiArrayIndex, N> & /*stride*/, MultiArrayIndex x) 00189 { 00190 return x; 00191 } 00192 template <int N> 00193 static MultiArrayIndex 00194 exec(const TinyVector <MultiArrayIndex, N> & stride, MultiArrayIndex x, MultiArrayIndex y) 00195 { 00196 return x + stride[1] * y; 00197 } 00198 }; 00199 00200 /********************************************************/ 00201 /* */ 00202 /* MaybeStrided */ 00203 /* */ 00204 /********************************************************/ 00205 00206 /* metatag implementing a test for marking MultiArrays that were 00207 indexed at the zero'th dimension as strided, and all others as 00208 unstrided. 00209 00210 <b>\#include</b> 00211 <<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>> 00212 00213 Namespace: vigra::detail 00214 */ 00215 template <unsigned int N> 00216 struct MaybeStrided 00217 { 00218 typedef UnstridedArrayTag type; 00219 }; 00220 00221 template <> 00222 struct MaybeStrided <0> 00223 { 00224 typedef StridedArrayTag type; 00225 }; 00226 00227 /********************************************************/ 00228 /* */ 00229 /* MultiIteratorChooser */ 00230 /* */ 00231 /********************************************************/ 00232 00233 /* metatag implementing a test (by pattern matching) for marking 00234 MultiArrays that were indexed at the zero'th dimension as strided. 00235 00236 <b>\#include</b> 00237 <<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>> 00238 00239 Namespace: vigra::detail 00240 */ 00241 template <class O> 00242 struct MultiIteratorChooser 00243 { 00244 struct Nil {}; 00245 00246 template <unsigned int N, class T, class REFERENCE, class POINTER> 00247 struct Traverser 00248 { 00249 typedef Nil type; 00250 }; 00251 }; 00252 00253 /********************************************************/ 00254 /* */ 00255 /* MultiIteratorChooser <StridedArrayTag> */ 00256 /* */ 00257 /********************************************************/ 00258 00259 /* specialization of the MultiIteratorChooser for strided arrays. 00260 00261 <b>\#include</b> 00262 <<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>> 00263 00264 Namespace: vigra::detail 00265 */ 00266 template <> 00267 struct MultiIteratorChooser <StridedArrayTag> 00268 { 00269 template <unsigned int N, class T, class REFERENCE, class POINTER> 00270 struct Traverser 00271 { 00272 typedef StridedMultiIterator <N, T, REFERENCE, POINTER> type; 00273 }; 00274 }; 00275 00276 /********************************************************/ 00277 /* */ 00278 /* MultiIteratorChooser <UnstridedArrayTag> */ 00279 /* */ 00280 /********************************************************/ 00281 00282 /* specialization of the MultiIteratorChooser for unstrided arrays. 00283 00284 <b>\#include</b> 00285 <<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>> 00286 00287 Namespace: vigra::detail 00288 */ 00289 template <> 00290 struct MultiIteratorChooser <UnstridedArrayTag> 00291 { 00292 template <unsigned int N, class T, class REFERENCE, class POINTER> 00293 struct Traverser 00294 { 00295 typedef MultiIterator <N, T, REFERENCE, POINTER> type; 00296 }; 00297 }; 00298 00299 /********************************************************/ 00300 /* */ 00301 /* helper functions */ 00302 /* */ 00303 /********************************************************/ 00304 00305 template <class DestIterator, class Shape, class T> 00306 inline void 00307 initMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<0>) 00308 { 00309 DestIterator dend = d + shape[0]; 00310 for(; d < dend; ++d) 00311 { 00312 *d = init; 00313 } 00314 } 00315 00316 template <class DestIterator, class Shape, class T, int N> 00317 void 00318 initMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<N>) 00319 { 00320 DestIterator dend = d + shape[N]; 00321 for(; d < dend; ++d) 00322 { 00323 initMultiArrayData(d.begin(), shape, init, MetaInt<N-1>()); 00324 } 00325 } 00326 00327 #define VIGRA_COPY_MULTI_ARRAY_DATA(name, op) \ 00328 template <class SrcIterator, class Shape, class DestIterator> \ 00329 inline void \ 00330 name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>) \ 00331 { \ 00332 SrcIterator send = s + shape[0]; \ 00333 for(; s < send; ++s, ++d) \ 00334 { \ 00335 *d op *s; \ 00336 } \ 00337 } \ 00338 \ 00339 template <class SrcIterator, class Shape, class DestIterator, int N> \ 00340 void \ 00341 name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>) \ 00342 { \ 00343 SrcIterator send = s + shape[N]; \ 00344 for(; s < send; ++s, ++d) \ 00345 { \ 00346 name##MultiArrayData(s.begin(), shape, d.begin(), MetaInt<N-1>()); \ 00347 } \ 00348 } \ 00349 \ 00350 template <class DestIterator, class Shape, class T> \ 00351 inline void \ 00352 name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<0>) \ 00353 { \ 00354 DestIterator dend = d + shape[0]; \ 00355 for(; d < dend; ++d) \ 00356 { \ 00357 *d op init; \ 00358 } \ 00359 } \ 00360 \ 00361 template <class DestIterator, class Shape, class T, int N> \ 00362 void \ 00363 name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<N>) \ 00364 { \ 00365 DestIterator dend = d + shape[N]; \ 00366 for(; d < dend; ++d) \ 00367 { \ 00368 name##ScalarMultiArrayData(d.begin(), shape, init, MetaInt<N-1>()); \ 00369 } \ 00370 } 00371 00372 VIGRA_COPY_MULTI_ARRAY_DATA(copy, =) 00373 VIGRA_COPY_MULTI_ARRAY_DATA(copyAdd, +=) 00374 VIGRA_COPY_MULTI_ARRAY_DATA(copySub, -=) 00375 VIGRA_COPY_MULTI_ARRAY_DATA(copyMul, *=) 00376 VIGRA_COPY_MULTI_ARRAY_DATA(copyDiv, /=) 00377 00378 #undef VIGRA_COPY_MULTI_ARRAY_DATA 00379 00380 template <class SrcIterator, class Shape, class T, class ALLOC> 00381 inline void 00382 uninitializedCopyMultiArrayData(SrcIterator s, Shape const & shape, T * & d, ALLOC & a, MetaInt<0>) 00383 { 00384 SrcIterator send = s + shape[0]; 00385 for(; s < send; ++s, ++d) 00386 { 00387 a.construct(d, static_cast<T const &>(*s)); 00388 } 00389 } 00390 00391 template <class SrcIterator, class Shape, class T, class ALLOC, int N> 00392 void 00393 uninitializedCopyMultiArrayData(SrcIterator s, Shape const & shape, T * & d, ALLOC & a, MetaInt<N>) 00394 { 00395 SrcIterator send = s + shape[N]; 00396 for(; s < send; ++s) 00397 { 00398 uninitializedCopyMultiArrayData(s.begin(), shape, d, a, MetaInt<N-1>()); 00399 } 00400 } 00401 00402 template <class SrcIterator, class Shape, class T> 00403 inline void 00404 normMaxOfMultiArray(SrcIterator s, Shape const & shape, T & result, MetaInt<0>) 00405 { 00406 SrcIterator send = s + shape[0]; 00407 for(; s < send; ++s) 00408 { 00409 T v = norm(*s); 00410 if(result < v) 00411 result = v; 00412 } 00413 } 00414 00415 template <class SrcIterator, class Shape, class T, int N> 00416 void 00417 normMaxOfMultiArray(SrcIterator s, Shape const & shape, T & result, MetaInt<N>) 00418 { 00419 SrcIterator send = s + shape[N]; 00420 for(; s < send; ++s) 00421 { 00422 normMaxOfMultiArray(s.begin(), shape, result, MetaInt<N-1>()); 00423 } 00424 } 00425 00426 template <class T> 00427 struct MultiArrayL1Functor 00428 { 00429 template <class U> 00430 T operator()(U t) const 00431 { return norm(t); } 00432 }; 00433 00434 template <class T> 00435 struct MultiArrayL2Functor 00436 { 00437 template <class U> 00438 T operator()(U t) const 00439 { return squaredNorm(t); } 00440 }; 00441 00442 template <class T> 00443 struct MultiArrayScaledL2Functor 00444 { 00445 T scale; 00446 00447 MultiArrayScaledL2Functor(T s) 00448 : scale(s) 00449 {} 00450 00451 template <class U> 00452 T operator()(U t) const 00453 { return squaredNorm(T(t) / scale); } 00454 }; 00455 00456 template <class SrcIterator, class Shape, class Functor, class T> 00457 inline void 00458 sumOverMultiArray(SrcIterator s, Shape const & shape, Functor f, T & result, MetaInt<0>) 00459 { 00460 SrcIterator send = s + shape[0]; 00461 for(; s < send; ++s) 00462 { 00463 result += f(*s); 00464 } 00465 } 00466 00467 template <class SrcIterator, class Shape, class Functor, class T, int N> 00468 void 00469 sumOverMultiArray(SrcIterator s, Shape const & shape, Functor f, T & result, MetaInt<N>) 00470 { 00471 SrcIterator send = s + shape[N]; 00472 for(; s < send; ++s) 00473 { 00474 sumOverMultiArray(s.begin(), shape, f, result, MetaInt<N-1>()); 00475 } 00476 } 00477 00478 template <class SrcIterator, class Shape, class DestIterator> 00479 inline bool 00480 equalityOfMultiArrays(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>) 00481 { 00482 SrcIterator send = s + shape[0]; 00483 for(; s < send; ++s, ++d) 00484 { 00485 if(!(*s == *d)) 00486 return false; 00487 } 00488 return true; 00489 } 00490 00491 template <class SrcIterator, class Shape, class DestIterator, int N> 00492 bool 00493 equalityOfMultiArrays(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>) 00494 { 00495 SrcIterator send = s + shape[N]; 00496 for(; s < send; ++s, ++d) 00497 { 00498 if(!equalityOfMultiArrays(s.begin(), shape, d.begin(), MetaInt<N-1>())) 00499 return false; 00500 } 00501 return true; 00502 } 00503 00504 00505 template <class SrcIterator, class Shape, class DestIterator> 00506 inline void 00507 swapDataImpl(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>) 00508 { 00509 SrcIterator send = s + shape[0]; 00510 for(; s < send; ++s, ++d) 00511 std::swap(*s, *d); 00512 } 00513 00514 template <class SrcIterator, class Shape, class DestIterator, int N> 00515 void 00516 swapDataImpl(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>) 00517 { 00518 SrcIterator send = s + shape[N]; 00519 for(; s < send; ++s, ++d) 00520 swapDataImpl(s.begin(), shape, d.begin(), MetaInt<N-1>()); 00521 } 00522 00523 } // namespace detail 00524 00525 /********************************************************/ 00526 /* */ 00527 /* MultiArrayView */ 00528 /* */ 00529 /********************************************************/ 00530 00531 // forward declaration 00532 template <unsigned int N, class T, class C = UnstridedArrayTag> 00533 class MultiArrayView; 00534 template <unsigned int N, class T, class A = std::allocator<T> > 00535 class MultiArray; 00536 00537 /********************************************************/ 00538 /* */ 00539 /* NormTraits */ 00540 /* */ 00541 /********************************************************/ 00542 00543 template <unsigned int N, class T, class C> 00544 struct NormTraits<MultiArrayView<N, T, C> > 00545 { 00546 typedef MultiArrayView<N, T, C> Type; 00547 typedef typename NormTraits<T>::SquaredNormType SquaredNormType; 00548 typedef typename SquareRootTraits<SquaredNormType>::SquareRootResult NormType; 00549 }; 00550 00551 template <unsigned int N, class T, class A> 00552 struct NormTraits<MultiArray<N, T, A> > 00553 : public NormTraits<MultiArrayView<N, T, UnstridedArrayTag> > 00554 { 00555 typedef NormTraits<MultiArrayView<N, T, UnstridedArrayTag> > BaseType; 00556 typedef MultiArray<N, T, A> Type; 00557 typedef typename BaseType::SquaredNormType SquaredNormType; 00558 typedef typename BaseType::NormType NormType; 00559 }; 00560 00561 /** \brief Base class for, and view to, \ref vigra::MultiArray. 00562 00563 This class implements the interface of both MultiArray and 00564 MultiArrayView. By default, MultiArrayViews are tagged as 00565 unstrided. If necessary, strided arrays are constructed automatically 00566 by calls to a variant of the bind...() function. 00567 00568 If you want to apply an algorithm requiring an image to a 00569 <tt>MultiArrayView</tt> of appropriate (2-dimensional) shape, you can 00570 create a \ref vigra::BasicImageView that acts as a wrapper with the 00571 necessary interface -- see \ref MultiArrayToImage. 00572 00573 The template parameter are as follows 00574 \code 00575 N: the array dimension 00576 00577 T: the type of the array elements 00578 00579 C: a tag determining whether the array's inner dimension is strided 00580 or not. An array is unstrided if the array elements occupy consecutive 00581 memory location, strided if there is an offset in between (e.g. 00582 when a view is created that skips every other array element). 00583 The compiler can generate faster code for unstrided arrays. 00584 Possible values: UnstridedArrayTag (default), StridedArrayTag 00585 \endcode 00586 00587 <b>\#include</b> 00588 <<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>> 00589 00590 Namespace: vigra 00591 */ 00592 template <unsigned int N, class T, class C> 00593 class MultiArrayView 00594 { 00595 public: 00596 00597 /** the array's actual dimensionality. 00598 This ensures that MultiArrayView can also be used for 00599 scalars (that is, when <tt>N == 0</tt>). Calculated as:<br> 00600 \code 00601 actual_dimension = (N==0) ? 1 : N 00602 \endcode 00603 */ 00604 enum ActualDimension { actual_dimension = (N==0) ? 1 : N }; 00605 00606 /** the array's value type 00607 */ 00608 typedef T value_type; 00609 00610 /** reference type (result of operator[]) 00611 */ 00612 typedef value_type &reference; 00613 00614 /** const reference type (result of operator[] const) 00615 */ 00616 typedef const value_type &const_reference; 00617 00618 /** pointer type 00619 */ 00620 typedef value_type *pointer; 00621 00622 /** const pointer type 00623 */ 00624 typedef const value_type *const_pointer; 00625 00626 /** difference type (used for multi-dimensional offsets and indices) 00627 */ 00628 typedef typename MultiArrayShape<actual_dimension>::type difference_type; 00629 00630 /** size type 00631 */ 00632 typedef difference_type size_type; 00633 00634 /** difference and index type for a single dimension 00635 */ 00636 typedef MultiArrayIndex difference_type_1; 00637 00638 /** traverser (MultiIterator) type 00639 */ 00640 typedef typename vigra::detail::MultiIteratorChooser < 00641 C>::template Traverser <actual_dimension, T, T &, T *>::type traverser; 00642 00643 /** const traverser (MultiIterator) type 00644 */ 00645 typedef typename vigra::detail::MultiIteratorChooser < 00646 C>::template Traverser <actual_dimension, T, T const &, T const *>::type const_traverser; 00647 00648 /** the view type associated with this array. 00649 */ 00650 typedef MultiArrayView <N, T, C> view_type; 00651 00652 /** the matrix type associated with this array. 00653 */ 00654 typedef MultiArray <N, T> matrix_type; 00655 00656 protected: 00657 00658 typedef typename difference_type::value_type diff_zero_t; 00659 00660 /** the shape of the image pointed to is stored here. 00661 */ 00662 difference_type m_shape; 00663 00664 /** the strides (offset of a sample to the next) for every dimension 00665 are stored here. 00666 */ 00667 difference_type m_stride; 00668 00669 /** pointer to the image. 00670 */ 00671 pointer m_ptr; 00672 00673 template <class U, class CN> 00674 void copyImpl(const MultiArrayView <N, U, CN>& rhs); 00675 00676 template <class U, class CN> 00677 void swapDataImpl(MultiArrayView <N, U, CN> rhs); 00678 00679 template <class U, class CN> 00680 bool arraysOverlap(const MultiArrayView <N, U, CN>& rhs) const; 00681 00682 public: 00683 00684 /** default constructor: create an empty image of size 0. 00685 */ 00686 MultiArrayView () 00687 : m_shape (diff_zero_t(0)), m_stride (diff_zero_t(0)), m_ptr (0) 00688 {} 00689 00690 /** construct from shape and pointer 00691 */ 00692 MultiArrayView (const difference_type &shape, pointer ptr) 00693 : m_shape (shape), 00694 m_stride (detail::defaultStride <MultiArrayView<N,T>::actual_dimension> (shape)), 00695 m_ptr (ptr) 00696 {} 00697 00698 /** construct from shape, strides (offset of a sample to the next) 00699 for every dimension) and pointer 00700 */ 00701 MultiArrayView (const difference_type &shape, 00702 const difference_type &stride, 00703 pointer ptr) 00704 : m_shape (shape), 00705 m_stride (stride), 00706 m_ptr (ptr) 00707 {} 00708 00709 00710 /** Assignment. There are 3 cases: 00711 00712 <ul> 00713 <li> When this <tt>MultiArrayView</tt> does not point to valid data 00714 (e.g. after default construction), it becomes a copy of \a rhs. 00715 <li> When the shapes of the two arrays match, the array contents are copied. 00716 <li> Otherwise, a <tt>PreconditionViolation</tt> exception is thrown. 00717 </ul> 00718 */ 00719 MultiArrayView & operator=(MultiArrayView const & rhs); 00720 00721 /** Assignment of a differently typed MultiArrayView. Fails with 00722 <tt>PreconditionViolation</tt> exception when the shapes do not match. 00723 */ 00724 template<class U, class C1> 00725 MultiArrayView & operator=(MultiArrayView<N, U, C1> const & rhs) 00726 { 00727 vigra_precondition(this->shape() == rhs.shape(), 00728 "MultiArrayView::operator=() size mismatch."); 00729 this->copyImpl(rhs); 00730 return *this; 00731 } 00732 00733 /** Add-assignment of a compatible MultiArrayView. Fails with 00734 <tt>PreconditionViolation</tt> exception when the shapes do not match. 00735 */ 00736 template<class U, class C1> 00737 MultiArrayView & operator+=(MultiArrayView<N, U, C1> const & rhs); 00738 00739 /** Subtract-assignment of a compatible MultiArrayView. Fails with 00740 <tt>PreconditionViolation</tt> exception when the shapes do not match. 00741 */ 00742 template<class U, class C1> 00743 MultiArrayView & operator-=(MultiArrayView<N, U, C1> const & rhs); 00744 00745 /** Multiply-assignment of a compatible MultiArrayView. Fails with 00746 <tt>PreconditionViolation</tt> exception when the shapes do not match. 00747 */ 00748 template<class U, class C1> 00749 MultiArrayView & operator*=(MultiArrayView<N, U, C1> const & rhs); 00750 00751 /** Divide-assignment of a compatible MultiArrayView. Fails with 00752 <tt>PreconditionViolation</tt> exception when the shapes do not match. 00753 */ 00754 template<class U, class C1> 00755 MultiArrayView & operator/=(MultiArrayView<N, U, C1> const & rhs); 00756 00757 /** Add-assignment of a scalar. 00758 */ 00759 MultiArrayView & operator+=(T const & rhs) 00760 { 00761 detail::copyAddScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>()); 00762 return *this; 00763 } 00764 00765 /** Subtract-assignment of a scalar. 00766 */ 00767 MultiArrayView & operator-=(T const & rhs) 00768 { 00769 detail::copySubScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>()); 00770 return *this; 00771 } 00772 00773 /** Multiply-assignment of a scalar. 00774 */ 00775 MultiArrayView & operator*=(T const & rhs) 00776 { 00777 detail::copyMulScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>()); 00778 return *this; 00779 } 00780 00781 /** Divide-assignment of a scalar. 00782 */ 00783 MultiArrayView & operator/=(T const & rhs) 00784 { 00785 detail::copyDivScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>()); 00786 return *this; 00787 } 00788 00789 /** array access. 00790 */ 00791 reference operator[] (const difference_type &d) 00792 { 00793 return m_ptr [dot (d, m_stride)]; 00794 } 00795 00796 /** array access. 00797 */ 00798 const_reference operator[] (const difference_type &d) const 00799 { 00800 return m_ptr [dot (d, m_stride)]; 00801 } 00802 00803 /** array access in scan-order sense. 00804 Mostly useful to support standard indexing for 1-dimensional multi-arrays, 00805 but works for any N. Use scanOrderIndexToCoordinate() and 00806 coordinateToScanOrderIndex() for conversion between indices and coordinates. 00807 */ 00808 reference operator[](difference_type_1 d) 00809 { 00810 return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)]; 00811 } 00812 00813 /** array access in scan-order sense. 00814 Mostly useful to support standard indexing for 1-dimensional multi-arrays, 00815 but works for any N. Use scanOrderIndexToCoordinate() and 00816 coordinateToScanOrderIndex() for conversion between indices and coordinates. 00817 */ 00818 const_reference operator[](difference_type_1 d) const 00819 { 00820 return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)]; 00821 } 00822 00823 /** convert scan-order index to coordinate. 00824 */ 00825 difference_type scanOrderIndexToCoordinate(difference_type_1 d) const 00826 { 00827 difference_type result; 00828 detail::ScanOrderToCoordinate<actual_dimension>::exec(d, m_shape, result); 00829 return result; 00830 } 00831 00832 /** convert coordinate to scan-order index. 00833 */ 00834 difference_type_1 coordinateToScanOrderIndex(const difference_type &d) const 00835 { 00836 return detail::CoordinateToScanOrder<actual_dimension>::exec(m_shape, d); 00837 } 00838 00839 /** 1D array access. Use only if N == 1. 00840 */ 00841 reference operator() (difference_type_1 x) 00842 { 00843 return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x)]; 00844 } 00845 00846 /** 2D array access. Use only if N == 2. 00847 */ 00848 reference operator() (difference_type_1 x, difference_type_1 y) 00849 { 00850 return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x, y)]; 00851 } 00852 00853 /** 3D array access. Use only if N == 3. 00854 */ 00855 reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z) 00856 { 00857 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z]; 00858 } 00859 00860 /** 4D array access. Use only if N == 4. 00861 */ 00862 reference operator() (difference_type_1 x, difference_type_1 y, 00863 difference_type_1 z, difference_type_1 u) 00864 { 00865 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u]; 00866 } 00867 00868 /** 5D array access. Use only if N == 5. 00869 */ 00870 reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z, 00871 difference_type_1 u, difference_type_1 v) 00872 { 00873 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v]; 00874 } 00875 00876 /** 1D const array access. Use only if N == 1. 00877 */ 00878 const_reference operator() (difference_type_1 x) const 00879 { 00880 return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x)]; 00881 } 00882 00883 /** 2D const array access. Use only if N == 2. 00884 */ 00885 const_reference operator() (difference_type_1 x, difference_type_1 y) const 00886 { 00887 return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x, y)]; 00888 } 00889 00890 /** 3D const array access. Use only if N == 3. 00891 */ 00892 const_reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z) const 00893 { 00894 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z]; 00895 } 00896 00897 /** 4D const array access. Use only if N == 4. 00898 */ 00899 const_reference operator() (difference_type_1 x, difference_type_1 y, 00900 difference_type_1 z, difference_type_1 u) const 00901 { 00902 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u]; 00903 } 00904 00905 /** 5D const array access. Use only if N == 5. 00906 */ 00907 const_reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z, 00908 difference_type_1 u, difference_type_1 v) const 00909 { 00910 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v]; 00911 } 00912 00913 /** Init with a constant. 00914 */ 00915 template <class U> 00916 MultiArrayView & init(const U & init) 00917 { 00918 detail::copyScalarMultiArrayData(traverser_begin(), shape(), init, MetaInt<actual_dimension-1>()); 00919 return *this; 00920 } 00921 00922 00923 /** Copy the data of the right-hand array (array shapes must match). 00924 */ 00925 void copy(const MultiArrayView & rhs) 00926 { 00927 if(this == &rhs) 00928 return; 00929 this->copyImpl(rhs); 00930 } 00931 00932 /** Copy the data of the right-hand array (array shapes must match). 00933 */ 00934 template <class U, class CN> 00935 void copy(const MultiArrayView <N, U, CN>& rhs) 00936 { 00937 this->copyImpl(rhs); 00938 } 00939 00940 /** swap the data between two MultiArrayView objects. 00941 00942 The shapes of the two array must match. 00943 */ 00944 void swapData(MultiArrayView rhs) 00945 { 00946 if(this != &rhs) 00947 swapDataImpl(rhs); 00948 } 00949 00950 /** swap the data between two MultiArrayView objects. 00951 00952 The shapes of the two array must match. 00953 */ 00954 template <class T2, class C2> 00955 void swapData(MultiArrayView <N, T2, C2> rhs) 00956 { 00957 swapDataImpl(rhs); 00958 } 00959 00960 /** bind the M outmost dimensions to certain indices. 00961 this reduces the dimensionality of the image to 00962 max { 1, N-M }. 00963 00964 <b>Usage:</b> 00965 \code 00966 // create a 3D array of size 40x30x20 00967 typedef MultiArray<3, double>::difference_type Shape; 00968 MultiArray<3, double> array3(Shape(40, 30, 20)); 00969 00970 // get a 1D array by fixing index 1 to 12, and index 2 to 10 00971 MultiArrayView <1, double> array1 = array3.bindOuter(TinyVector<int, 2>(12, 10)); 00972 \endcode 00973 */ 00974 template <unsigned int M> 00975 MultiArrayView <N-M, T, C> bindOuter (const TinyVector <MultiArrayIndex, M> &d) const; 00976 00977 /** bind the M innermost dimensions to certain indices. 00978 this reduces the dimensionality of the image to 00979 max { 1, N-M }. 00980 00981 <b>Usage:</b> 00982 \code 00983 // create a 3D array of size 40x30x20 00984 typedef MultiArray<3, double>::difference_type Shape; 00985 MultiArray<3, double> array3(Shape(40, 30, 20)); 00986 00987 // get a 1D array by fixing index 0 to 12, and index 1 to 10 00988 MultiArrayView <1, double, StridedArrayTag> array1 = array3.bindInner(TinyVector<int, 2>(12, 10)); 00989 \endcode 00990 */ 00991 template <unsigned int M> 00992 MultiArrayView <N-M, T, StridedArrayTag> 00993 bindInner (const TinyVector <MultiArrayIndex, M> &d) const; 00994 00995 /** bind dimension M to index d. 00996 this reduces the dimensionality of the image to 00997 max { 1, N-1 }. 00998 00999 <b>Usage:</b> 01000 \code 01001 // create a 3D array of size 40x30x20 01002 typedef MultiArray<3, double>::difference_type Shape; 01003 MultiArray<3, double> array3(Shape(40, 30, 20)); 01004 01005 // get a 2D array by fixing index 1 to 12 01006 MultiArrayView <2, double> array2 = array3.bind<1>(12); 01007 01008 // get a 2D array by fixing index 0 to 23 01009 MultiArrayView <2, double, StridedArrayTag> array2a = array3.bind<0>(23); 01010 \endcode 01011 */ 01012 template <unsigned int M> 01013 MultiArrayView <N-1, T, typename vigra::detail::MaybeStrided <M>::type > 01014 bind (difference_type_1 d) const; 01015 01016 /** bind the outmost dimension to a certain index. 01017 this reduces the dimensionality of the image to 01018 max { 1, N-1 }. 01019 01020 <b>Usage:</b> 01021 \code 01022 // create a 3D array of size 40x30x20 01023 typedef MultiArray<3, double>::difference_type Shape; 01024 MultiArray<3, double> array3(Shape(40, 30, 20)); 01025 01026 // get a 2D array by fixing the outermost index (i.e. index 2) to 12 01027 MultiArrayView <2, double> array2 = array3.bindOuter(12); 01028 \endcode 01029 */ 01030 MultiArrayView <N-1, T, C> bindOuter (difference_type_1 d) const; 01031 01032 /** bind the innermost dimension to a certain index. 01033 this reduces the dimensionality of the image to 01034 max { 1, N-1 }. 01035 01036 <b>Usage:</b> 01037 \code 01038 // create a 3D array of size 40x30x20 01039 typedef MultiArray<3, double>::difference_type Shape; 01040 MultiArray<3, double> array3(Shape(40, 30, 20)); 01041 01042 // get a 2D array by fixing the innermost index (i.e. index 0) to 23 01043 MultiArrayView <2, double, StridedArrayTag> array2 = array3.bindInner(23); 01044 \endcode 01045 */ 01046 MultiArrayView <N-1, T, StridedArrayTag> bindInner (difference_type_1 d) const; 01047 01048 /** bind dimension m to index d. 01049 this reduces the dimensionality of the image to 01050 max { 1, N-1 }. 01051 01052 <b>Usage:</b> 01053 \code 01054 // create a 3D array of size 40x30x20 01055 typedef MultiArray<3, double>::difference_type Shape; 01056 MultiArray<3, double> array3(Shape(40, 30, 20)); 01057 01058 // get a 2D array by fixing index 2 to 15 01059 MultiArrayView <2, double, StridedArrayTag> array2 = array3.bindAt(2, 15); 01060 \endcode 01061 */ 01062 MultiArrayView <N-1, T, StridedArrayTag> 01063 bindAt (difference_type_1 m, difference_type_1 d) const; 01064 01065 /** create a rectangular subarray that spans between the 01066 points p and q, where p is in the subarray, q not. 01067 01068 <b>Usage:</b> 01069 \code 01070 // create a 3D array of size 40x30x20 01071 typedef MultiArray<3, double>::difference_type Shape; 01072 MultiArray<3, double> array3(Shape(40, 30, 20)); 01073 01074 // get a subarray set is smaller by one element at all sides 01075 MultiArrayView <3, double> subarray = array3.subarray(Shape(1,1,1), Shape(39, 29, 19)); 01076 \endcode 01077 */ 01078 MultiArrayView subarray (const difference_type &p, 01079 const difference_type &q) const 01080 { 01081 const difference_type_1 offset = dot (m_stride, p); 01082 return MultiArrayView (q - p, m_stride, m_ptr + offset); 01083 } 01084 01085 /** apply an additional striding to the image, thereby reducing 01086 the shape of the array. 01087 for example, multiplying the stride of dimension one by three 01088 turns an appropriately layed out (interleaved) rgb image into 01089 a single band image. 01090 */ 01091 MultiArrayView <N, T, StridedArrayTag> 01092 stridearray (const difference_type &s) const 01093 { 01094 difference_type shape = m_shape; 01095 for (unsigned int i = 0; i < actual_dimension; ++i) 01096 shape [i] /= s [i]; 01097 return MultiArrayView <N, T, StridedArrayTag> 01098 (shape, m_stride * s, m_ptr); 01099 } 01100 01101 /** permute the dimensions of the array. 01102 The function exchanges the meaning of the dimensions without copying the data. 01103 In case of a 2-dimensional array, this is simply array transposition. In higher dimensions, 01104 there are more possibilities. 01105 01106 <b>Usage:</b><br> 01107 \code 01108 typedef MultiArray<2, double>::difference_type Shape; 01109 MultiArray<2, double> array(10, 20); 01110 01111 MultiArray<2, double, StridedArrayTag> transposed = array.permuteDimensions(Shape(1,0)); 01112 01113 for(int i=0; i<array.shape(0), ++i) 01114 for(int j=0; j<array.shape(1); ++j) 01115 assert(array(i, j) == transposed(j, i)); 01116 \endcode 01117 */ 01118 MultiArrayView <N, T, StridedArrayTag> 01119 permuteDimensions (const difference_type &s) const 01120 { 01121 difference_type shape, stride, check((typename difference_type::value_type)0); 01122 for (unsigned int i = 0; i < actual_dimension; ++i) 01123 { 01124 shape[i] = m_shape[s[i]]; 01125 stride[i] = m_stride[s[i]]; 01126 ++check[s[i]]; 01127 } 01128 vigra_precondition(check == difference_type(1), 01129 "MultiArrayView::permuteDimensions(): every dimension must occur exactly once."); 01130 return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr); 01131 } 01132 01133 /** transpose a 2-dimensional array. Use only if N==2. 01134 01135 <b>Usage:</b><br> 01136 \code 01137 typedef MultiArray<2, double>::difference_type Shape; 01138 MultiArray<2, double> array(10, 20); 01139 01140 MultiArray<2, double, StridedArrayTag> transposed = array.transpose(); 01141 01142 for(int i=0; i<array.shape(0), ++i) 01143 for(int j=0; j<array.shape(1); ++j) 01144 assert(array(i, j) == transposed(j, i)); 01145 \endcode 01146 */ 01147 MultiArrayView <2, T, StridedArrayTag> 01148 transpose () const 01149 { 01150 difference_type shape(m_shape[1], m_shape[0]), 01151 stride(m_stride[1], m_stride[0]); 01152 return MultiArrayView <2, T, StridedArrayTag>(shape, stride, m_ptr); 01153 } 01154 01155 /** number of the elements in the array. 01156 */ 01157 difference_type_1 elementCount () const 01158 { 01159 difference_type_1 ret = m_shape[0]; 01160 for(int i = 1; i < actual_dimension; ++i) 01161 ret *= m_shape[i]; 01162 return ret; 01163 } 01164 01165 /** number of the elements in the array. 01166 Same as <tt>elementCount()</tt>. Mostly useful to support the std::vector interface. 01167 */ 01168 difference_type_1 size () const 01169 { 01170 return elementCount(); 01171 } 01172 01173 /** return the array's shape. 01174 */ 01175 const difference_type & shape () const 01176 { 01177 return m_shape; 01178 } 01179 01180 /** return the array's size at a certain dimension. 01181 */ 01182 difference_type_1 size (difference_type_1 n) const 01183 { 01184 return m_shape [n]; 01185 } 01186 01187 /** return the array's shape at a certain dimension 01188 (same as <tt>size(n)</tt>). 01189 */ 01190 difference_type_1 shape (difference_type_1 n) const 01191 { 01192 return m_shape [n]; 01193 } 01194 01195 /** return the array's stride for every dimension. 01196 */ 01197 const difference_type & stride () const 01198 { 01199 return m_stride; 01200 } 01201 01202 /** return the array's stride at a certain dimension. 01203 */ 01204 difference_type_1 stride (int n) const 01205 { 01206 return m_stride [n]; 01207 } 01208 01209 /** check whether two arrays are elementwise equal. 01210 */ 01211 template <class U, class C1> 01212 bool operator==(MultiArrayView<N, U, C1> const & rhs) const 01213 { 01214 if(this->shape() != rhs.shape()) 01215 return false; 01216 return detail::equalityOfMultiArrays(traverser_begin(), shape(), rhs.traverser_begin(), MetaInt<actual_dimension-1>()); 01217 } 01218 01219 /** check whether two arrays are not elementwise equal. 01220 Also true when the two arrays have different shapes. 01221 */ 01222 template <class U, class C1> 01223 bool operator!=(MultiArrayView<N, U, C1> const & rhs) const 01224 { 01225 return !operator==(rhs); 01226 } 01227 01228 /** check whether the given point is in the array range. 01229 */ 01230 bool isInside (difference_type const & p) const 01231 { 01232 for(int d=0; d<actual_dimension; ++d) 01233 if(p[d] < 0 || p[d] >= shape(d)) 01234 return false; 01235 return true; 01236 } 01237 01238 /** Compute the squared Euclidean norm of the array (sum of squares of the array elements). 01239 */ 01240 typename NormTraits<MultiArrayView>::SquaredNormType squaredNorm() const 01241 { 01242 typedef typename NormTraits<MultiArrayView>::SquaredNormType SquaredNormType; 01243 SquaredNormType res = NumericTraits<SquaredNormType>::zero(); 01244 detail::sumOverMultiArray(traverser_begin(), shape(), detail::MultiArrayL2Functor<SquaredNormType>(), 01245 res, MetaInt<actual_dimension-1>()); 01246 return res; 01247 } 01248 01249 /** Compute various norms of the array. 01250 The norm is determined by parameter \a type: 01251 01252 <ul> 01253 <li> type == 0: maximum norm (L-infinity): maximum of absolute values of the array elements 01254 <li> type == 1: Manhattan norm (L1): sum of absolute values of the array elements 01255 <li> type == 2: Euclidean norm (L2): square root of <tt>squaredNorm()</tt> when \a useSquaredNorm is <tt>true</tt>,<br> 01256 or direct algorithm that avoids underflow/overflow otherwise. 01257 </ul> 01258 01259 Parameter \a useSquaredNorm has no effect when \a type != 2. Defaults: compute L2 norm as square root of 01260 <tt>squaredNorm()</tt>. 01261 */ 01262 typename NormTraits<MultiArrayView>::NormType norm(int type = 2, bool useSquaredNorm = true) const; 01263 01264 /** return the pointer to the image data 01265 */ 01266 pointer data () const 01267 { 01268 return m_ptr; 01269 } 01270 01271 /** returns the N-dimensional MultiIterator pointing 01272 to the first element in every dimension. 01273 */ 01274 traverser traverser_begin () 01275 { 01276 traverser ret (m_ptr, m_stride.begin (), m_shape.begin ()); 01277 return ret; 01278 } 01279 01280 /** returns the N-dimensional MultiIterator pointing 01281 to the const first element in every dimension. 01282 */ 01283 const_traverser traverser_begin () const 01284 { 01285 const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ()); 01286 return ret; 01287 } 01288 01289 /** returns the N-dimensional MultiIterator pointing 01290 beyond the last element in dimension N, and to the 01291 first element in every other dimension. 01292 */ 01293 traverser traverser_end () 01294 { 01295 traverser ret (m_ptr, m_stride.begin (), m_shape.begin ()); 01296 ret += m_shape [actual_dimension-1]; 01297 return ret; 01298 } 01299 01300 /** returns the N-dimensional const MultiIterator pointing 01301 beyond the last element in dimension N, and to the 01302 first element in every other dimension. 01303 */ 01304 const_traverser traverser_end () const 01305 { 01306 const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ()); 01307 ret += m_shape [actual_dimension-1]; 01308 return ret; 01309 } 01310 01311 view_type view () 01312 { 01313 return *this; 01314 } 01315 }; 01316 01317 template <unsigned int N, class T, class C> 01318 MultiArrayView<N, T, C> & 01319 MultiArrayView <N, T, C>::operator=(MultiArrayView<N, T, C> const & rhs) 01320 { 01321 if(this == &rhs) 01322 return *this; 01323 vigra_precondition(this->shape() == rhs.shape() || m_ptr == 0, 01324 "MultiArrayView::operator=(MultiArrayView const &) size mismatch - use MultiArrayView::reset()."); 01325 if(m_ptr == 0) 01326 { 01327 m_shape = rhs.m_shape; 01328 m_stride = rhs.m_stride; 01329 m_ptr = rhs.m_ptr; 01330 } 01331 else 01332 this->copyImpl(rhs); 01333 return *this; 01334 } 01335 01336 template <unsigned int N, class T, class C> 01337 template <class U, class CN> 01338 bool 01339 MultiArrayView <N, T, C>::arraysOverlap(const MultiArrayView <N, U, CN>& rhs) const 01340 { 01341 vigra_precondition (shape () == rhs.shape (), 01342 "MultiArrayView::arraysOverlap(): shape mismatch."); 01343 const_pointer first_element = this->m_ptr, 01344 last_element = first_element + dot(this->m_shape - difference_type(1), this->m_stride); 01345 typename MultiArrayView <N, U, CN>::const_pointer 01346 rhs_first_element = rhs.data(), 01347 rhs_last_element = rhs_first_element + dot(rhs.shape() - difference_type(1), rhs.stride()); 01348 return !(last_element < rhs_first_element || rhs_last_element < first_element); 01349 } 01350 01351 template <unsigned int N, class T, class C> 01352 template <class U, class CN> 01353 void 01354 MultiArrayView <N, T, C>::copyImpl(const MultiArrayView <N, U, CN>& rhs) 01355 { 01356 if(!arraysOverlap(rhs)) 01357 { 01358 // no overlap -- can copy directly 01359 detail::copyMultiArrayData(rhs.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>()); 01360 } 01361 else 01362 { 01363 // overlap: we got different views to the same data -- copy to intermediate memory in order to avoid 01364 // overwriting elements that are still needed on the rhs. 01365 MultiArray<N, T> tmp(rhs); 01366 detail::copyMultiArrayData(tmp.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>()); 01367 } 01368 } 01369 01370 #define VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(name, op) \ 01371 template <unsigned int N, class T, class C> \ 01372 template<class U, class C1> \ 01373 MultiArrayView<N, T, C> & \ 01374 MultiArrayView <N, T, C>::operator op(MultiArrayView<N, U, C1> const & rhs) \ 01375 { \ 01376 vigra_precondition(this->shape() == rhs.shape(), "MultiArrayView::operator" #op "() size mismatch."); \ 01377 if(!arraysOverlap(rhs)) \ 01378 { \ 01379 detail::name##MultiArrayData(rhs.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>()); \ 01380 } \ 01381 else \ 01382 { \ 01383 MultiArray<N, T> tmp(rhs); \ 01384 detail::name##MultiArrayData(tmp.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>()); \ 01385 } \ 01386 return *this; \ 01387 } 01388 01389 VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(copyAdd, +=) 01390 VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(copySub, -=) 01391 VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(copyMul, *=) 01392 VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(copyDiv, /=) 01393 01394 #undef VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT 01395 01396 template <unsigned int N, class T, class C> 01397 template <class U, class CN> 01398 void 01399 MultiArrayView <N, T, C>::swapDataImpl(MultiArrayView <N, U, CN> rhs) 01400 { 01401 vigra_precondition (shape () == rhs.shape (), 01402 "MultiArrayView::swapData(): shape mismatch."); 01403 01404 // check for overlap of this and rhs 01405 const_pointer first_element = this->m_ptr, 01406 last_element = first_element + dot(this->m_shape - difference_type(1), this->m_stride); 01407 typename MultiArrayView <N, U, CN>::const_pointer 01408 rhs_first_element = rhs.data(), 01409 rhs_last_element = rhs_first_element + dot(rhs.shape() - difference_type(1), rhs.stride()); 01410 if(last_element < rhs_first_element || rhs_last_element < first_element) 01411 { 01412 // no overlap -- can swap directly 01413 detail::swapDataImpl(traverser_begin(), shape(), rhs.traverser_begin(), MetaInt<actual_dimension-1>()); 01414 } 01415 else 01416 { 01417 // overlap: we got different views to the same data -- copy to intermediate memory in order to avoid 01418 // overwriting elements that are still needed. 01419 MultiArray<N, T> tmp(*this); 01420 copy(rhs); 01421 rhs.copy(tmp); 01422 } 01423 } 01424 01425 template <unsigned int N, class T, class C> 01426 template <unsigned int M> 01427 MultiArrayView <N-M, T, C> 01428 MultiArrayView <N, T, C>::bindOuter (const TinyVector <MultiArrayIndex, M> &d) const 01429 { 01430 TinyVector <MultiArrayIndex, M> stride; 01431 stride.init (m_stride.begin () + N-M, m_stride.end ()); 01432 pointer ptr = m_ptr + dot (d, stride); 01433 static const int NNew = (N-M == 0) ? 1 : N-M; 01434 TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride; 01435 if (N-M == 0) 01436 { 01437 inner_shape [0] = 1; 01438 inner_stride [0] = 0; 01439 } 01440 else 01441 { 01442 inner_shape.init (m_shape.begin (), m_shape.end () - M); 01443 inner_stride.init (m_stride.begin (), m_stride.end () - M); 01444 } 01445 return MultiArrayView <N-M, T, C> (inner_shape, inner_stride, ptr); 01446 } 01447 01448 template <unsigned int N, class T, class C> 01449 template <unsigned int M> 01450 MultiArrayView <N - M, T, StridedArrayTag> 01451 MultiArrayView <N, T, C>::bindInner (const TinyVector <MultiArrayIndex, M> &d) const 01452 { 01453 TinyVector <MultiArrayIndex, M> stride; 01454 stride.init (m_stride.begin (), m_stride.end () - N + M); 01455 pointer ptr = m_ptr + dot (d, stride); 01456 static const int NNew = (N-M == 0) ? 1 : N-M; 01457 TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride; 01458 if (N-M == 0) 01459 { 01460 outer_shape [0] = 1; 01461 outer_stride [0] = 0; 01462 } 01463 else 01464 { 01465 outer_shape.init (m_shape.begin () + M, m_shape.end ()); 01466 outer_stride.init (m_stride.begin () + M, m_stride.end ()); 01467 } 01468 return MultiArrayView <N-M, T, StridedArrayTag> 01469 (outer_shape, outer_stride, ptr); 01470 } 01471 01472 template <unsigned int N, class T, class C> 01473 template <unsigned int M> 01474 MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type > 01475 MultiArrayView <N, T, C>::bind (difference_type_1 d) const 01476 { 01477 static const int NNew = (N-1 == 0) ? 1 : N-1; 01478 TinyVector <MultiArrayIndex, NNew> shape, stride; 01479 // the remaining dimensions are 0..n-1,n+1..N-1 01480 if (N-1 == 0) 01481 { 01482 shape[0] = 1; 01483 stride[0] = 0; 01484 } 01485 else 01486 { 01487 std::copy (m_shape.begin (), m_shape.begin () + M, shape.begin ()); 01488 std::copy (m_shape.begin () + M+1, m_shape.end (), 01489 shape.begin () + M); 01490 std::copy (m_stride.begin (), m_stride.begin () + M, stride.begin ()); 01491 std::copy (m_stride.begin () + M+1, m_stride.end (), 01492 stride.begin () + M); 01493 } 01494 return MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type> 01495 (shape, stride, m_ptr + d * m_stride[M]); 01496 } 01497 01498 template <unsigned int N, class T, class C> 01499 MultiArrayView <N - 1, T, C> 01500 MultiArrayView <N, T, C>::bindOuter (difference_type_1 d) const 01501 { 01502 static const int NNew = (N-1 == 0) ? 1 : N-1; 01503 TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride; 01504 if (N-1 == 0) 01505 { 01506 inner_shape [0] = 1; 01507 inner_stride [0] = 0; 01508 } 01509 else 01510 { 01511 inner_shape.init (m_shape.begin (), m_shape.end () - 1); 01512 inner_stride.init (m_stride.begin (), m_stride.end () - 1); 01513 } 01514 return MultiArrayView <N-1, T, C> (inner_shape, inner_stride, 01515 m_ptr + d * m_stride [N-1]); 01516 } 01517 01518 template <unsigned int N, class T, class C> 01519 MultiArrayView <N - 1, T, StridedArrayTag> 01520 MultiArrayView <N, T, C>::bindInner (difference_type_1 d) const 01521 { 01522 static const int NNew = (N-1 == 0) ? 1 : N-1; 01523 TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride; 01524 if (N-1 == 0) 01525 { 01526 outer_shape [0] = 1; 01527 outer_stride [0] = 0; 01528 } 01529 else 01530 { 01531 outer_shape.init (m_shape.begin () + 1, m_shape.end ()); 01532 outer_stride.init (m_stride.begin () + 1, m_stride.end ()); 01533 } 01534 return MultiArrayView <N-1, T, StridedArrayTag> 01535 (outer_shape, outer_stride, m_ptr + d * m_stride [0]); 01536 } 01537 01538 template <unsigned int N, class T, class C> 01539 MultiArrayView <N - 1, T, StridedArrayTag> 01540 MultiArrayView <N, T, C>::bindAt (difference_type_1 n, difference_type_1 d) const 01541 { 01542 vigra_precondition ( 01543 n < static_cast <int> (N), 01544 "MultiArrayView <N, T, C>::bindAt(): dimension out of range."); 01545 static const int NNew = (N-1 == 0) ? 1 : N-1; 01546 TinyVector <MultiArrayIndex, NNew> shape, stride; 01547 // the remaining dimensions are 0..n-1,n+1..N-1 01548 if (N-1 == 0) 01549 { 01550 shape [0] = 1; 01551 stride [0] = 0; 01552 } 01553 else 01554 { 01555 std::copy (m_shape.begin (), m_shape.begin () + n, shape.begin ()); 01556 std::copy (m_shape.begin () + n+1, m_shape.end (), 01557 shape.begin () + n); 01558 std::copy (m_stride.begin (), m_stride.begin () + n, stride.begin ()); 01559 std::copy (m_stride.begin () + n+1, m_stride.end (), 01560 stride.begin () + n); 01561 } 01562 return MultiArrayView <N-1, T, StridedArrayTag> 01563 (shape, stride, m_ptr + d * m_stride[n]); 01564 } 01565 01566 template <unsigned int N, class T, class C> 01567 typename NormTraits<MultiArrayView <N, T, C> >::NormType 01568 MultiArrayView <N, T, C>::norm(int type, bool useSquaredNorm) const 01569 { 01570 typedef typename NormTraits<MultiArrayView>::NormType NormType; 01571 01572 switch(type) 01573 { 01574 case 0: 01575 { 01576 NormType res = NumericTraits<NormType>::zero(); 01577 detail::normMaxOfMultiArray(traverser_begin(), shape(), res, MetaInt<actual_dimension-1>()); 01578 return res; 01579 } 01580 case 1: 01581 { 01582 NormType res = NumericTraits<NormType>::zero(); 01583 detail::sumOverMultiArray(traverser_begin(), shape(), detail::MultiArrayL1Functor<NormType>(), 01584 res, MetaInt<actual_dimension-1>()); 01585 return res; 01586 } 01587 case 2: 01588 { 01589 if(useSquaredNorm) 01590 { 01591 return sqrt((NormType)squaredNorm()); 01592 } 01593 else 01594 { 01595 NormType normMax = NumericTraits<NormType>::zero(); 01596 detail::normMaxOfMultiArray(traverser_begin(), shape(), normMax, MetaInt<actual_dimension-1>()); 01597 if(normMax == NumericTraits<NormType>::zero()) 01598 return normMax; 01599 NormType res = NumericTraits<NormType>::zero(); 01600 detail::sumOverMultiArray(traverser_begin(), shape(), detail::MultiArrayScaledL2Functor<NormType>(normMax), 01601 res, MetaInt<actual_dimension-1>()); 01602 return sqrt(res)*normMax; 01603 } 01604 } 01605 default: 01606 vigra_precondition(false, "MultiArrayView::norm(): Unknown norm type."); 01607 return NumericTraits<NormType>::zero(); // unreachable 01608 } 01609 } 01610 01611 01612 /********************************************************/ 01613 /* */ 01614 /* norm */ 01615 /* */ 01616 /********************************************************/ 01617 01618 template <unsigned int N, class T, class C> 01619 inline typename NormTraits<MultiArrayView <N, T, C> >::SquaredNormType 01620 squaredNorm(MultiArrayView <N, T, C> const & a) 01621 { 01622 return a.squaredNorm(); 01623 } 01624 01625 template <unsigned int N, class T, class C> 01626 inline typename NormTraits<MultiArrayView <N, T, C> >::NormType 01627 norm(MultiArrayView <N, T, C> const & a) 01628 { 01629 return a.norm(); 01630 } 01631 01632 /********************************************************/ 01633 /* */ 01634 /* MultiArray */ 01635 /* */ 01636 /********************************************************/ 01637 01638 /** \brief Main <TT>MultiArray</TT> class containing the memory 01639 management. 01640 01641 This class inherits the interface of MultiArrayView, and implements 01642 the memory ownership. 01643 MultiArray's are always unstrided, striding them creates a MultiArrayView. 01644 01645 01646 The template parameters are as follows 01647 \code 01648 N: the array dimension 01649 01650 T: the type of the array elements 01651 01652 A: the allocator used for internal storage management 01653 (default: std::allocator<T>) 01654 \endcode 01655 01656 <b>\#include</b> 01657 <<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>> 01658 01659 Namespace: vigra 01660 */ 01661 template <unsigned int N, class T, class A /* default already declared above */> 01662 class MultiArray : public MultiArrayView <N, T> 01663 { 01664 01665 public: 01666 using MultiArrayView <N, T>::actual_dimension; 01667 01668 /** the allocator type used to allocate the memory 01669 */ 01670 typedef A allocator_type; 01671 01672 /** the view type associated with this array. 01673 */ 01674 typedef MultiArrayView <N, T> view_type; 01675 01676 /** the matrix type associated with this array. 01677 */ 01678 typedef MultiArray <N, T, A> matrix_type; 01679 01680 /** the array's value type 01681 */ 01682 typedef typename view_type::value_type value_type; 01683 01684 /** pointer type 01685 */ 01686 typedef typename view_type::pointer pointer; 01687 01688 /** const pointer type 01689 */ 01690 typedef typename view_type::const_pointer const_pointer; 01691 01692 /** reference type (result of operator[]) 01693 */ 01694 typedef typename view_type::reference reference; 01695 01696 /** const reference type (result of operator[] const) 01697 */ 01698 typedef typename view_type::const_reference const_reference; 01699 01700 /** size type 01701 */ 01702 typedef typename view_type::size_type size_type; 01703 01704 /** difference type (used for multi-dimensional offsets and indices) 01705 */ 01706 typedef typename view_type::difference_type difference_type; 01707 01708 /** difference and index type for a single dimension 01709 */ 01710 typedef typename view_type::difference_type_1 difference_type_1; 01711 01712 /** traverser type 01713 */ 01714 typedef typename vigra::detail::MultiIteratorChooser < 01715 UnstridedArrayTag>::template Traverser <N, T, T &, T *>::type 01716 traverser; 01717 01718 /** traverser type to const data 01719 */ 01720 typedef typename vigra::detail::MultiIteratorChooser < 01721 UnstridedArrayTag>::template Traverser <N, T, T const &, T const *>::type 01722 const_traverser; 01723 01724 /** sequential (random access) iterator type 01725 */ 01726 typedef T * iterator; 01727 01728 /** sequential (random access) const iterator type 01729 */ 01730 typedef T * const_iterator; 01731 01732 protected: 01733 01734 typedef typename difference_type::value_type diff_zero_t; 01735 01736 /** the allocator used to allocate the memory 01737 */ 01738 allocator_type m_alloc; 01739 01740 /** allocate memory for s pixels, write its address into the given 01741 pointer and initialize the pixels with init. 01742 */ 01743 void allocate (pointer &ptr, difference_type_1 s, const_reference init); 01744 01745 /** allocate memory for s pixels, write its address into the given 01746 pointer and initialize the linearized pixels to the values of init. 01747 */ 01748 template <class U> 01749 void allocate (pointer &ptr, difference_type_1 s, U const * init); 01750 01751 /** allocate memory, write its address into the given 01752 pointer and initialize it by copying the data from the given MultiArrayView. 01753 */ 01754 template <class U, class C> 01755 void allocate (pointer &ptr, MultiArrayView<N, U, C> const & init); 01756 01757 /** deallocate the memory (of length s) starting at the given address. 01758 */ 01759 void deallocate (pointer &ptr, difference_type_1 s); 01760 01761 template <class U, class C> 01762 void copyOrReshape (const MultiArrayView<N, U, C> &rhs); 01763 public: 01764 /** default constructor 01765 */ 01766 MultiArray () 01767 : MultiArrayView <N, T> (difference_type (diff_zero_t(0)), 01768 difference_type (diff_zero_t(0)), 0) 01769 {} 01770 01771 /** construct with given allocator 01772 */ 01773 MultiArray (allocator_type const & alloc) 01774 : MultiArrayView <N, T> (difference_type (diff_zero_t(0)), 01775 difference_type (diff_zero_t(0)), 0), 01776 m_alloc(alloc) 01777 {} 01778 01779 /** construct with given shape 01780 */ 01781 explicit MultiArray (const difference_type &shape, 01782 allocator_type const & alloc = allocator_type()); 01783 01784 /** construct from shape with an initial value 01785 */ 01786 MultiArray (const difference_type &shape, const_reference init, 01787 allocator_type const & alloc = allocator_type()); 01788 01789 /** construct from shape and copy values from the given array 01790 */ 01791 MultiArray (const difference_type &shape, const_pointer init, 01792 allocator_type const & alloc = allocator_type()); 01793 01794 /** copy constructor 01795 */ 01796 MultiArray (const MultiArray &rhs) 01797 : MultiArrayView <N, T> (rhs.m_shape, rhs.m_stride, 0), 01798 m_alloc (rhs.m_alloc) 01799 { 01800 allocate (this->m_ptr, this->elementCount (), rhs.data ()); 01801 } 01802 01803 /** construct by copying from a MultiArrayView 01804 */ 01805 template <class U, class C> 01806 MultiArray (const MultiArrayView<N, U, C> &rhs, 01807 allocator_type const & alloc = allocator_type()); 01808 01809 /** assignment.<br> 01810 If the size of \a rhs is the same as the left-hand side arrays's old size, only 01811 the data are copied. Otherwise, new storage is allocated, which invalidates all 01812 objects (array views, iterators) depending on the lhs array. 01813 */ 01814 MultiArray & operator= (const MultiArray &rhs) 01815 { 01816 if (this != &rhs) 01817 this->copyOrReshape(rhs); 01818 return *this; 01819 } 01820 01821 /** assignment from arbitrary MultiArrayView.<br> 01822 If the size of \a rhs is the same as the left-hand side arrays's old size, only 01823 the data are copied. Otherwise, new storage is allocated, which invalidates all 01824 objects (array views, iterators) depending on the lhs array. 01825 */ 01826 template <class U, class C> 01827 MultiArray &operator= (const MultiArrayView<N, U, C> &rhs) 01828 { 01829 this->copyOrReshape(rhs); 01830 return *this; 01831 } 01832 01833 /** Add-assignment from arbitrary MultiArrayView. Fails with 01834 <tt>PreconditionViolation</tt> exception when the shapes do not match. 01835 */ 01836 template <class U, class C> 01837 MultiArray &operator+= (const MultiArrayView<N, U, C> &rhs) 01838 { 01839 view_type::operator+=(rhs); 01840 return *this; 01841 } 01842 01843 /** Subtract-assignment from arbitrary MultiArrayView. Fails with 01844 <tt>PreconditionViolation</tt> exception when the shapes do not match. 01845 */ 01846 template <class U, class C> 01847 MultiArray &operator-= (const MultiArrayView<N, U, C> &rhs) 01848 { 01849 view_type::operator-=(rhs); 01850 return *this; 01851 } 01852 01853 /** Multiply-assignment from arbitrary MultiArrayView. Fails with 01854 <tt>PreconditionViolation</tt> exception when the shapes do not match. 01855 */ 01856 template <class U, class C> 01857 MultiArray &operator*= (const MultiArrayView<N, U, C> &rhs) 01858 { 01859 view_type::operator*=(rhs); 01860 return *this; 01861 } 01862 01863 /** Divide-assignment from arbitrary MultiArrayView. Fails with 01864 <tt>PreconditionViolation</tt> exception when the shapes do not match. 01865 */ 01866 template <class U, class C> 01867 MultiArray &operator/= (const MultiArrayView<N, U, C> &rhs) 01868 { 01869 view_type::operator/=(rhs); 01870 return *this; 01871 } 01872 01873 /** Add-assignment of a scalar. 01874 */ 01875 MultiArray &operator+= (const T &rhs) 01876 { 01877 view_type::operator+=(rhs); 01878 return *this; 01879 } 01880 01881 /** Subtract-assignment of a scalar. 01882 */ 01883 MultiArray &operator-= (const T &rhs) 01884 { 01885 view_type::operator-=(rhs); 01886 return *this; 01887 } 01888 01889 /** Multiply-assignment of a scalar. 01890 */ 01891 MultiArray &operator*= (const T &rhs) 01892 { 01893 view_type::operator*=(rhs); 01894 return *this; 01895 } 01896 01897 /** Divide-assignment of a scalar. 01898 */ 01899 MultiArray &operator/= (const T &rhs) 01900 { 01901 view_type::operator/=(rhs); 01902 return *this; 01903 } 01904 01905 /** destructor 01906 */ 01907 ~MultiArray () 01908 { 01909 deallocate (this->m_ptr, this->elementCount ()); 01910 } 01911 01912 01913 /** init elements with a constant 01914 */ 01915 template <class U> 01916 MultiArray & init(const U & init) 01917 { 01918 view_type::init(init); 01919 return *this; 01920 } 01921 01922 /** change the shape and allocate new memory.<br> 01923 <em>Note:</em> this operation invalidates all dependent objects 01924 (array views and iterators) 01925 */ 01926 void reshape (const difference_type &shape) 01927 { 01928 reshape (shape, NumericTraits <T>::zero ()); 01929 } 01930 01931 /** change the shape, allocate new memory and initialize it 01932 with the given value.<br> 01933 <em>Note:</em> this operation invalidates all dependent objects 01934 (array views and iterators) 01935 */ 01936 void reshape (const difference_type &shape, const_reference init); 01937 01938 /** Swap the contents with another MultiArray. This is fast, 01939 because no data are copied, but only pointers and shapes swapped. 01940 <em>Note:</em> this operation invalidates all dependent objects 01941 (array views and iterators) 01942 */ 01943 void swap (MultiArray & other); 01944 01945 /** sequential iterator pointing to the first array element. 01946 */ 01947 iterator begin () 01948 { 01949 return this->data(); 01950 } 01951 01952 /** sequential iterator pointing beyond the last array element. 01953 */ 01954 iterator end () 01955 { 01956 return this->data() + this->elementCount(); 01957 } 01958 01959 /** sequential const iterator pointing to the first array element. 01960 */ 01961 const_iterator begin () const 01962 { 01963 return this->data(); 01964 } 01965 01966 /** sequential const iterator pointing beyond the last array element. 01967 */ 01968 const_iterator end () const 01969 { 01970 return this->data() + this->elementCount(); 01971 } 01972 01973 /** get the allocator. 01974 */ 01975 allocator_type const & allocator () const 01976 { 01977 return m_alloc; 01978 } 01979 }; 01980 01981 template <unsigned int N, class T, class A> 01982 MultiArray <N, T, A>::MultiArray (const difference_type &shape, 01983 allocator_type const & alloc) 01984 : MultiArrayView <N, T> (shape, 01985 detail::defaultStride <MultiArrayView<N,T>::actual_dimension> (shape), 01986 0), 01987 m_alloc(alloc) 01988 { 01989 if (N == 0) 01990 { 01991 this->m_shape [0] = 1; 01992 this->m_stride [0] = 0; 01993 } 01994 allocate (this->m_ptr, this->elementCount (), NumericTraits<T>::zero ()); 01995 } 01996 01997 template <unsigned int N, class T, class A> 01998 MultiArray <N, T, A>::MultiArray (const difference_type &shape, const_reference init, 01999 allocator_type const & alloc) 02000 : MultiArrayView <N, T> (shape, 02001 detail::defaultStride <MultiArrayView<N,T>::actual_dimension> (shape), 02002 0), 02003 m_alloc(alloc) 02004 { 02005 if (N == 0) 02006 { 02007 this->m_shape [0] = 1; 02008 this->m_stride [0] = 0; 02009 } 02010 allocate (this->m_ptr, this->elementCount (), init); 02011 } 02012 02013 template <unsigned int N, class T, class A> 02014 MultiArray <N, T, A>::MultiArray (const difference_type &shape, const_pointer init, 02015 allocator_type const & alloc) 02016 : MultiArrayView <N, T> (shape, 02017 detail::defaultStride <MultiArrayView<N,T>::actual_dimension> (shape), 02018 0), 02019 m_alloc(alloc) 02020 { 02021 if (N == 0) 02022 { 02023 this->m_shape [0] = 1; 02024 this->m_stride [0] = 0; 02025 } 02026 allocate (this->m_ptr, this->elementCount (), init); 02027 } 02028 02029 template <unsigned int N, class T, class A> 02030 template <class U, class C> 02031 MultiArray <N, T, A>::MultiArray(const MultiArrayView<N, U, C> &rhs, 02032 allocator_type const & alloc) 02033 : MultiArrayView <N, T> (rhs.shape(), 02034 detail::defaultStride <MultiArrayView<N,T>::actual_dimension>(rhs.shape()), 02035 0), 02036 m_alloc (alloc) 02037 { 02038 allocate (this->m_ptr, rhs); 02039 } 02040 02041 template <unsigned int N, class T, class A> 02042 template <class U, class C> 02043 void 02044 MultiArray <N, T, A>::copyOrReshape(const MultiArrayView<N, U, C> &rhs) 02045 { 02046 if (this->shape() == rhs.shape()) 02047 this->copy(rhs); 02048 else 02049 { 02050 MultiArray t(rhs); 02051 this->swap(t); 02052 } 02053 } 02054 02055 template <unsigned int N, class T, class A> 02056 void MultiArray <N, T, A>::reshape (const difference_type & new_shape, 02057 const_reference initial) 02058 { 02059 if (N== 0) 02060 { 02061 return; 02062 } 02063 else if(new_shape == this->shape()) 02064 { 02065 this->init(initial); 02066 } 02067 else 02068 { 02069 difference_type new_stride = detail::defaultStride <MultiArrayView<N,T>::actual_dimension> (new_shape); 02070 difference_type_1 new_size = new_shape [MultiArrayView<N,T>::actual_dimension-1] * new_stride [MultiArrayView<N,T>::actual_dimension-1]; 02071 T *new_ptr; 02072 allocate (new_ptr, new_size, initial); 02073 deallocate (this->m_ptr, this->elementCount ()); 02074 this->m_ptr = new_ptr; 02075 this->m_shape = new_shape; 02076 this->m_stride = new_stride; 02077 } 02078 } 02079 02080 02081 template <unsigned int N, class T, class A> 02082 inline void 02083 MultiArray <N, T, A>::swap (MultiArray <N, T, A> & other) 02084 { 02085 if (this == &other) 02086 return; 02087 std::swap(this->m_shape, other.m_shape); 02088 std::swap(this->m_stride, other.m_stride); 02089 std::swap(this->m_ptr, other.m_ptr); 02090 std::swap(this->m_alloc, other.m_alloc); 02091 } 02092 02093 template <unsigned int N, class T, class A> 02094 void MultiArray <N, T, A>::allocate (pointer & ptr, difference_type_1 s, 02095 const_reference init) 02096 { 02097 ptr = m_alloc.allocate ((typename A::size_type)s); 02098 difference_type_1 i; 02099 try { 02100 for (i = 0; i < s; ++i) 02101 m_alloc.construct (ptr + i, init); 02102 } 02103 catch (...) { 02104 for (difference_type_1 j = 0; j < i; ++j) 02105 m_alloc.destroy (ptr + j); 02106 m_alloc.deallocate (ptr, (typename A::size_type)s); 02107 throw; 02108 } 02109 } 02110 02111 template <unsigned int N, class T, class A> 02112 template <class U> 02113 void MultiArray <N, T, A>::allocate (pointer & ptr, difference_type_1 s, 02114 U const * init) 02115 { 02116 ptr = m_alloc.allocate ((typename A::size_type)s); 02117 difference_type_1 i; 02118 try { 02119 for (i = 0; i < s; ++i, ++init) 02120 m_alloc.construct (ptr + i, *init); 02121 } 02122 catch (...) { 02123 for (difference_type_1 j = 0; j < i; ++j) 02124 m_alloc.destroy (ptr + j); 02125 m_alloc.deallocate (ptr, (typename A::size_type)s); 02126 throw; 02127 } 02128 } 02129 02130 template <unsigned int N, class T, class A> 02131 template <class U, class C> 02132 void MultiArray <N, T, A>::allocate (pointer & ptr, MultiArrayView<N, U, C> const & init) 02133 { 02134 difference_type_1 s = init.elementCount(); 02135 ptr = m_alloc.allocate ((typename A::size_type)s); 02136 pointer p = ptr; 02137 try { 02138 detail::uninitializedCopyMultiArrayData(init.traverser_begin(), init.shape(), 02139 p, m_alloc, MetaInt<actual_dimension-1>()); 02140 } 02141 catch (...) { 02142 for (pointer pp = ptr; pp < p; ++pp) 02143 m_alloc.destroy (pp); 02144 m_alloc.deallocate (ptr, (typename A::size_type)s); 02145 throw; 02146 } 02147 } 02148 02149 template <unsigned int N, class T, class A> 02150 inline void MultiArray <N, T, A>::deallocate (pointer & ptr, difference_type_1 s) 02151 { 02152 if (ptr == 0) 02153 return; 02154 for (difference_type_1 i = 0; i < s; ++i) 02155 m_alloc.destroy (ptr + i); 02156 m_alloc.deallocate (ptr, (typename A::size_type)s); 02157 ptr = 0; 02158 } 02159 02160 /********************************************************/ 02161 /* */ 02162 /* argument object factories */ 02163 /* */ 02164 /********************************************************/ 02165 02166 template <unsigned int N, class T, class C> 02167 inline triple<typename MultiArrayView<N,T,C>::const_traverser, 02168 typename MultiArrayView<N,T,C>::difference_type, 02169 typename AccessorTraits<T>::default_const_accessor > 02170 srcMultiArrayRange( MultiArrayView<N,T,C> const & array ) 02171 { 02172 return triple<typename MultiArrayView<N,T,C>::const_traverser, 02173 typename MultiArrayView<N,T,C>::difference_type, 02174 typename AccessorTraits<T>::default_const_accessor > 02175 ( array.traverser_begin(), 02176 array.shape(), 02177 typename AccessorTraits<T>::default_const_accessor() ); 02178 } 02179 02180 template <unsigned int N, class T, class C, class Accessor> 02181 inline triple<typename MultiArrayView<N,T,C>::const_traverser, 02182 typename MultiArrayView<N,T,C>::difference_type, 02183 Accessor > 02184 srcMultiArrayRange( MultiArrayView<N,T,C> const & array, Accessor a ) 02185 { 02186 return triple<typename MultiArrayView<N,T,C>::const_traverser, 02187 typename MultiArrayView<N,T,C>::difference_type, 02188 Accessor > 02189 ( array.traverser_begin(), 02190 array.shape(), 02191 a); 02192 } 02193 02194 template <unsigned int N, class T, class C> 02195 inline pair<typename MultiArrayView<N,T,C>::const_traverser, 02196 typename AccessorTraits<T>::default_const_accessor > 02197 srcMultiArray( MultiArrayView<N,T,C> const & array ) 02198 { 02199 return pair<typename MultiArrayView<N,T,C>::const_traverser, 02200 typename AccessorTraits<T>::default_const_accessor > 02201 ( array.traverser_begin(), 02202 typename AccessorTraits<T>::default_const_accessor() ); 02203 } 02204 02205 template <unsigned int N, class T, class C, class Accessor> 02206 inline pair<typename MultiArrayView<N,T,C>::const_traverser, 02207 Accessor > 02208 srcMultiArray( MultiArrayView<N,T,C> const & array, Accessor a ) 02209 { 02210 return pair<typename MultiArrayView<N,T,C>::const_traverser, 02211 Accessor > 02212 ( array.traverser_begin(), a ); 02213 } 02214 02215 template <unsigned int N, class T, class C> 02216 inline triple<typename MultiArrayView<N,T,C>::traverser, 02217 typename MultiArrayView<N,T,C>::difference_type, 02218 typename AccessorTraits<T>::default_accessor > 02219 destMultiArrayRange( MultiArrayView<N,T,C> & array ) 02220 { 02221 return triple<typename MultiArrayView<N,T,C>::traverser, 02222 typename MultiArrayView<N,T,C>::difference_type, 02223 typename AccessorTraits<T>::default_accessor > 02224 ( array.traverser_begin(), 02225 array.shape(), 02226 typename AccessorTraits<T>::default_accessor() ); 02227 } 02228 02229 template <unsigned int N, class T, class C, class Accessor> 02230 inline triple<typename MultiArrayView<N,T,C>::traverser, 02231 typename MultiArrayView<N,T,C>::difference_type, 02232 Accessor > 02233 destMultiArrayRange( MultiArrayView<N,T,C> & array, Accessor a ) 02234 { 02235 return triple<typename MultiArrayView<N,T,C>::traverser, 02236 typename MultiArrayView<N,T,C>::difference_type, 02237 Accessor > 02238 ( array.traverser_begin(), 02239 array.shape(), 02240 a ); 02241 } 02242 02243 template <unsigned int N, class T, class C> 02244 inline pair<typename MultiArrayView<N,T,C>::traverser, 02245 typename AccessorTraits<T>::default_accessor > 02246 destMultiArray( MultiArrayView<N,T,C> & array ) 02247 { 02248 return pair<typename MultiArrayView<N,T,C>::traverser, 02249 typename AccessorTraits<T>::default_accessor > 02250 ( array.traverser_begin(), 02251 typename AccessorTraits<T>::default_accessor() ); 02252 } 02253 02254 template <unsigned int N, class T, class C, class Accessor> 02255 inline pair<typename MultiArrayView<N,T,C>::traverser, 02256 Accessor > 02257 destMultiArray( MultiArrayView<N,T,C> & array, Accessor a ) 02258 { 02259 return pair<typename MultiArrayView<N,T,C>::traverser, 02260 Accessor > 02261 ( array.traverser_begin(), a ); 02262 } 02263 02264 /********************************************************/ 02265 /* */ 02266 /* makeBasicImageView */ 02267 /* */ 02268 /********************************************************/ 02269 02270 /** \addtogroup MultiArrayToImage Wrap a \ref vigra::MultiArrayView in 02271 a \ref vigra::BasicImageView 02272 */ 02273 //@{ 02274 /** Create a \ref vigra::BasicImageView from an unstrided 2-dimensional 02275 \ref vigra::MultiArrayView. 02276 02277 The \ref vigra::BasicImageView will have the same <tt>value_type </tt> 02278 as the original \ref vigra::MultiArrayView. 02279 */ 02280 template <class T> 02281 BasicImageView <T> 02282 makeBasicImageView (MultiArrayView <2, T, UnstridedArrayTag> const &array) 02283 { 02284 return BasicImageView <T> (array.data (), array.shape (0), 02285 array.shape (1)); 02286 } 02287 02288 /** Create a \ref vigra::BasicImageView from a 3-dimensional 02289 \ref vigra::MultiArray. 02290 02291 This wrapper flattens the two innermost dimensions of the array 02292 into single rows of the resulting image. 02293 The \ref vigra::BasicImageView will have the same <tt>value_type </tt> 02294 as the original \ref vigra::MultiArray. 02295 */ 02296 template <class T> 02297 BasicImageView <T> 02298 makeBasicImageView (MultiArray <3, T> const &array) 02299 { 02300 return BasicImageView <T> (array.data (), 02301 array.shape (0)*array.shape (1), array.shape (2)); 02302 } 02303 02304 /** Create a \ref vigra::BasicImageView from a 3-dimensional 02305 \ref vigra::MultiArray. 02306 02307 This wrapper only works if <tt>T</tt> is a scalar type and the 02308 array's innermost dimension has size 3. It then re-interprets 02309 the data array as a 2-dimensional array with value_type 02310 <tt>RGBValue<T></tt>. 02311 */ 02312 template <class T> 02313 BasicImageView <RGBValue<T> > 02314 makeRGBImageView (MultiArray<3, T> const &array) 02315 { 02316 vigra_precondition ( 02317 array.shape (0) == 3, "makeRGBImageView(): array.shape(0) must be 3."); 02318 return BasicImageView <RGBValue<T> > ( 02319 reinterpret_cast <RGBValue <T> *> (array.data ()), 02320 array.shape (1), array.shape (2)); 02321 } 02322 02323 //@} 02324 02325 } // namespace vigra 02326 02327 #endif // VIGRA_MULTI_ARRAY_HXX
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|