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

multi_array.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2003-2008 by Gunnar Kedenburg and Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 
37 #ifndef VIGRA_MULTI_ARRAY_HXX
38 #define VIGRA_MULTI_ARRAY_HXX
39 
40 #include <memory>
41 #include <algorithm>
42 #include "accessor.hxx"
43 #include "tinyvector.hxx"
44 #include "rgbvalue.hxx"
45 #include "basicimage.hxx"
46 #include "imageiterator.hxx"
47 #include "numerictraits.hxx"
48 #include "multi_iterator.hxx"
49 #include "multi_pointoperators.hxx"
50 #include "metaprogramming.hxx"
51 #include "mathutil.hxx"
52 #include "algorithm.hxx"
53 
54 // Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined.
55 #ifdef VIGRA_CHECK_BOUNDS
56 #define VIGRA_ASSERT_INSIDE(diff) \
57  vigra_precondition(this->isInside(diff), "Index out of bounds")
58 #else
59 #define VIGRA_ASSERT_INSIDE(diff)
60 #endif
61 
62 namespace vigra
63 {
64 
65 namespace detail
66 {
67 
68 /********************************************************/
69 /* */
70 /* MaybeStrided */
71 /* */
72 /********************************************************/
73 
74 /* metatag implementing a test for marking MultiArrays that were
75  indexed at the zero'th dimension as strided, and all others as
76  unstrided.
77 
78  <b>\#include</b> <vigra/multi_array.hxx> <br/>
79  Namespace: vigra::detail
80 */
81 template <class StrideTag, unsigned int N>
82 struct MaybeStrided
83 {
84  typedef StrideTag type;
85 };
86 
87 template <class StrideTag>
88 struct MaybeStrided <StrideTag, 0>
89 {
90  typedef StridedArrayTag type;
91 };
92 
93 /********************************************************/
94 /* */
95 /* MultiIteratorChooser */
96 /* */
97 /********************************************************/
98 
99 /* metatag implementing a test (by pattern matching) for marking
100  MultiArrays that were indexed at the zero'th dimension as strided.
101 
102  <b>\#include</b> <vigra/multi_array.hxx> <br/>
103  Namespace: vigra::detail
104 */
105 template <class O>
106 struct MultiIteratorChooser;
107 
108 /********************************************************/
109 /* */
110 /* MultiIteratorChooser <StridedArrayTag> */
111 /* */
112 /********************************************************/
113 
114 /* specialization of the MultiIteratorChooser for strided arrays.
115 
116  <b>\#include</b> <vigra/multi_array.hxx> <br/>
117  Namespace: vigra::detail
118 */
119 template <>
120 struct MultiIteratorChooser <StridedArrayTag>
121 {
122  template <unsigned int N, class T, class REFERENCE, class POINTER>
123  struct Traverser
124  {
125  typedef StridedMultiIterator <N, T, REFERENCE, POINTER> type;
126  };
127 
128  template <unsigned int N, class T, class REFERENCE, class POINTER>
129  struct Iterator
130  {
131  typedef StridedScanOrderIterator <N, T, REFERENCE, POINTER> type;
132  };
133 
134  template <class Iter, class View>
135  static Iter constructIterator(View * v)
136  {
137  return v->begin();
138  }
139 };
140 
141 /********************************************************/
142 /* */
143 /* MultiIteratorChooser <UnstridedArrayTag> */
144 /* */
145 /********************************************************/
146 
147 /* specialization of the MultiIteratorChooser for unstrided arrays.
148 
149  <b>\#include</b> <vigra/multi_array.hxx> <br/>
150  Namespace: vigra::detail
151 */
152 template <>
153 struct MultiIteratorChooser <UnstridedArrayTag>
154 {
155  template <unsigned int N, class T, class REFERENCE, class POINTER>
156  struct Traverser
157  {
158  typedef MultiIterator <N, T, REFERENCE, POINTER> type;
159  };
160 
161  template <unsigned int N, class T, class REFERENCE, class POINTER>
162  struct Iterator
163  {
164  typedef POINTER type;
165  };
166 
167  template <class Iter, class View>
168  static Iter constructIterator(View * v)
169  {
170  return v->data();
171  }
172 };
173 
174 /********************************************************/
175 /* */
176 /* helper functions */
177 /* */
178 /********************************************************/
179 
180 template <class DestIterator, class Shape, class T>
181 inline void
182 initMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<0>)
183 {
184  DestIterator dend = d + shape[0];
185  for(; d < dend; ++d)
186  {
187  *d = init;
188  }
189 }
190 
191 template <class DestIterator, class Shape, class T, int N>
192 void
193 initMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<N>)
194 {
195  DestIterator dend = d + shape[N];
196  for(; d < dend; ++d)
197  {
198  initMultiArrayData(d.begin(), shape, init, MetaInt<N-1>());
199  }
200 }
201 
202 // FIXME: the explicit overload for MultiIterator<1, UInt8, ... > works around a compiler crash in VisualStudio 2010
203 #define VIGRA_COPY_MULTI_ARRAY_DATA(name, op) \
204 template <class SrcIterator, class Shape, class DestIterator> \
205 inline void \
206 name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>) \
207 { \
208  for(MultiArrayIndex i=0; i < shape[0]; ++i, ++s, ++d) \
209  { \
210  *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(*s); \
211  } \
212 } \
213  \
214 template <class Ref, class Ptr, class Shape, class DestIterator> \
215 inline void \
216 name##MultiArrayData(MultiIterator<1, UInt8, Ref, Ptr> si, Shape const & shape, DestIterator d, MetaInt<0>) \
217 { \
218  Ptr s = &(*si); \
219  for(MultiArrayIndex i=0; i < shape[0]; ++i, ++s, ++d) \
220  { \
221  *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(*s); \
222  } \
223 } \
224 \
225 template <class SrcIterator, class Shape, class DestIterator, int N> \
226 void \
227 name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>) \
228 { \
229  for(MultiArrayIndex i=0; i < shape[N]; ++i, ++s, ++d) \
230  { \
231  name##MultiArrayData(s.begin(), shape, d.begin(), MetaInt<N-1>()); \
232  } \
233 } \
234 \
235 template <class DestIterator, class Shape, class T> \
236 inline void \
237 name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<0>) \
238 { \
239  for(MultiArrayIndex i=0; i < shape[0]; ++i, ++d) \
240  { \
241  *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(init); \
242  } \
243 } \
244  \
245 template <class DestIterator, class Shape, class T, int N> \
246 void \
247 name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<N>) \
248 { \
249  for(MultiArrayIndex i=0; i < shape[N]; ++i, ++d) \
250  { \
251  name##ScalarMultiArrayData(d.begin(), shape, init, MetaInt<N-1>()); \
252  } \
253 }
254 
255 VIGRA_COPY_MULTI_ARRAY_DATA(copy, =)
256 VIGRA_COPY_MULTI_ARRAY_DATA(copyAdd, +=)
257 VIGRA_COPY_MULTI_ARRAY_DATA(copySub, -=)
258 VIGRA_COPY_MULTI_ARRAY_DATA(copyMul, *=)
259 VIGRA_COPY_MULTI_ARRAY_DATA(copyDiv, /=)
260 
261 #undef VIGRA_COPY_MULTI_ARRAY_DATA
262 
263 template <class SrcIterator, class Shape, class T, class ALLOC>
264 inline void
265 uninitializedCopyMultiArrayData(SrcIterator s, Shape const & shape, T * & d, ALLOC & a, MetaInt<0>)
266 {
267  SrcIterator send = s + shape[0];
268  for(; s < send; ++s, ++d)
269  {
270  a.construct(d, static_cast<T const &>(*s));
271  }
272 }
273 
274 // FIXME: this overload works around a compiler crash in VisualStudio 2010
275 template <class Ref, class Ptr, class Shape, class T, class ALLOC>
276 inline void
277 uninitializedCopyMultiArrayData(MultiIterator<1, UInt8, Ref, Ptr> si, Shape const & shape, T * & d, ALLOC & a, MetaInt<0>)
278 {
279  Ptr s = &(*si), send = s + shape[0];
280  for(; s < send; ++s, ++d)
281  {
282  a.construct(d, static_cast<T const &>(*s));
283  }
284 }
285 
286 template <class SrcIterator, class Shape, class T, class ALLOC, int N>
287 void
288 uninitializedCopyMultiArrayData(SrcIterator s, Shape const & shape, T * & d, ALLOC & a, MetaInt<N>)
289 {
290  SrcIterator send = s + shape[N];
291  for(; s < send; ++s)
292  {
293  uninitializedCopyMultiArrayData(s.begin(), shape, d, a, MetaInt<N-1>());
294  }
295 }
296 
297 template <class SrcIterator, class Shape, class T, class Functor>
298 inline void
299 reduceOverMultiArray(SrcIterator s, Shape const & shape, T & result, Functor const & f, MetaInt<0>)
300 {
301  SrcIterator send = s + shape[0];
302  for(; s < send; ++s)
303  {
304  f(result, *s);
305  }
306 }
307 
308 template <class SrcIterator, class Shape, class T, class Functor, int N>
309 void
310 reduceOverMultiArray(SrcIterator s, Shape const & shape, T & result, Functor const & f, MetaInt<N>)
311 {
312  SrcIterator send = s + shape[N];
313  for(; s < send; ++s)
314  {
315  reduceOverMultiArray(s.begin(), shape, result, f, MetaInt<N-1>());
316  }
317 }
318 
319 struct MaxNormReduceFunctor
320 {
321  template <class T, class U>
322  void operator()(T & result, U const & u) const
323  {
324  T v = norm(u);
325  if(result < v)
326  result = v;
327  }
328 };
329 
330 struct L1NormReduceFunctor
331 {
332  template <class T, class U>
333  void operator()(T & result, U const & u) const
334  {
335  result += norm(u);
336  }
337 };
338 
339 struct SquaredL2NormReduceFunctor
340 {
341  template <class T, class U>
342  void operator()(T & result, U const & u) const
343  {
344  result += squaredNorm(u);
345  }
346 };
347 
348 template <class T>
349 struct WeightedL2NormReduceFunctor
350 {
351  T scale;
352 
353  WeightedL2NormReduceFunctor(T s)
354  : scale(s)
355  {}
356 
357  template <class U>
358  void operator()(T & result, U const & u) const
359  {
360  result += squaredNorm(u * scale);
361  }
362 };
363 
364 struct SumReduceFunctor
365 {
366  template <class T, class U>
367  void operator()(T & result, U const & u) const
368  {
369  result += u;
370  }
371 };
372 
373 struct ProdReduceFunctor
374 {
375  template <class T, class U>
376  void operator()(T & result, U const & u) const
377  {
378  result *= u;
379  }
380 };
381 
382 struct MinmaxReduceFunctor
383 {
384  template <class T, class U>
385  void operator()(T & result, U const & u) const
386  {
387  if(u < result.first)
388  result.first = u;
389  if(result.second < u)
390  result.second = u;
391  }
392 };
393 
394 struct MeanVarianceReduceFunctor
395 {
396  template <class T, class U>
397  void operator()(T & result, U const & u) const
398  {
399  ++result.first;
400  typename T::second_type t1 = u - result.second;
401  typename T::second_type t2 = t1 / result.first;
402  result.second += t2;
403  result.third += (result.first-1.0)*t1*t2;
404  }
405 };
406 
407 struct AllTrueReduceFunctor
408 {
409  template <class T, class U>
410  void operator()(T & result, U const & u) const
411  {
412  result = result && (u != NumericTraits<U>::zero());
413  }
414 };
415 
416 struct AnyTrueReduceFunctor
417 {
418  template <class T, class U>
419  void operator()(T & result, U const & u) const
420  {
421  result = result || (u != NumericTraits<U>::zero());
422  }
423 };
424 
425 template <class SrcIterator, class Shape, class DestIterator>
426 inline bool
427 equalityOfMultiArrays(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>)
428 {
429  SrcIterator send = s + shape[0];
430  for(; s < send; ++s, ++d)
431  {
432  if(!(*s == *d))
433  return false;
434  }
435  return true;
436 }
437 
438 template <class SrcIterator, class Shape, class DestIterator, int N>
439 bool
440 equalityOfMultiArrays(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>)
441 {
442  SrcIterator send = s + shape[N];
443  for(; s < send; ++s, ++d)
444  {
445  if(!equalityOfMultiArrays(s.begin(), shape, d.begin(), MetaInt<N-1>()))
446  return false;
447  }
448  return true;
449 }
450 
451 
452 template <class SrcIterator, class Shape, class DestIterator>
453 inline void
454 swapDataImpl(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>)
455 {
456  SrcIterator send = s + shape[0];
457  for(; s < send; ++s, ++d)
458  std::swap(*s, *d);
459 }
460 
461 template <class SrcIterator, class Shape, class DestIterator, int N>
462 void
463 swapDataImpl(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>)
464 {
465  SrcIterator send = s + shape[N];
466  for(; s < send; ++s, ++d)
467  swapDataImpl(s.begin(), shape, d.begin(), MetaInt<N-1>());
468 }
469 
470 } // namespace detail
471 
472 /********************************************************/
473 /* */
474 /* namespace multi_math forward declarations */
475 /* */
476 /********************************************************/
477 
478 /** \brief Arithmetic and algebraic functions for multi-dimensional arrays.
479 
480  \defgroup MultiMathModule vigra::multi_math
481 
482  Namespace <tt>vigra::multi_math</tt> holds VIGRA's support for efficient arithmetic and algebraic functions on multi-dimensional arrays (that is, \ref MultiArrayView and its subclasses). All <tt>multi_math</tt> functions operate element-wise. If you need matrix multiplication, use \ref LinearAlgebraModule instead.
483 
484  In order to avoid overload ambiguities, multi-array arithmetic must be explicitly activated by
485  \code
486  using namespace vigra::multi_math;
487  \endcode
488  (this should not be done globally, but only in the scope where the functionality is actually used).
489 
490  You can then use the standard operators in the expected way:
491  \code
492  MultiArray<2, float> i(Shape2(100, 100)), j(Shape2(100, 100));
493 
494  MultiArray<2, float> h = i + 4.0 * j;
495  h += (i.transpose() - j) / 2.0;
496  \endcode
497  etc. (supported operators are <tt>+ - * / ! ~ % && || == != &lt; &lt;= &gt; &gt;= &lt;&lt; &gt;&gt; & | ^ = += -= *= /=</tt>, with both scalar and array arguments).
498 
499  Algebraic functions are available as well:
500  \code
501  h = exp(-(sq(i) + sq(j)));
502  h *= atan2(-i, j);
503  \endcode
504  The following functions are implemented: <tt>abs, erf, even, odd, sign, signi, round, roundi, sqrt, sqrti, sq,
505  norm, squaredNorm, gamma, loggamma, exp, log, log10, sin, sin_pi, cos, cos_pi, asin, acos, tan, atan,
506  floor, ceil, conj, real, imag, arg, atan2, pow, fmod, min, max</tt>,
507  provided the array's element type supports the respective function.
508 
509  Supported element types currently include the built-in numeric types, \ref TinyVector, \ref RGBValue,
510  <tt>std::complex</tt>, and \ref FFTWComplex.
511 
512  In addition, <tt>multi_math</tt> supports a number of functions that reduce arrays to scalars:
513  \code
514  double s = sum<double>(i); // compute the sum of the elements, using 'double' as accumulator type
515  double p = product<double>(abs(i)); // compute the product of the elements' absolute values
516 
517  bool a = any(i < 0.0); // check if any element of i is negative
518  bool b = all(i > 0.0); // check if all elements of i are positive
519  \endcode
520 
521  Expressions are expanded so that no temporary arrays have to be created. To optimize cache locality,
522  loops are executed in the stride ordering of the left-hand-side array.
523 
524  <b>\#include</b> <vigra/multi_math.hxx>
525 
526  Namespace: vigra::multi_math
527 */
528 namespace multi_math {
529 
530 template <class T>
531 struct MultiMathOperand;
532 
533 namespace math_detail {
534 
535 template <unsigned int N, class T, class C, class E>
536 void assign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
537 
538 template <unsigned int N, class T, class C, class E>
539 void plusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
540 
541 template <unsigned int N, class T, class C, class E>
542 void minusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
543 
544 template <unsigned int N, class T, class C, class E>
545 void multiplyAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
546 
547 template <unsigned int N, class T, class C, class E>
548 void divideAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
549 
550 template <unsigned int N, class T, class A, class E>
551 void assignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
552 
553 template <unsigned int N, class T, class A, class E>
554 void plusAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
555 
556 template <unsigned int N, class T, class A, class E>
557 void minusAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
558 
559 template <unsigned int N, class T, class A, class E>
560 void multiplyAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
561 
562 template <unsigned int N, class T, class A, class E>
563 void divideAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
564 
565 } // namespace math_detail
566 
567 } // namespace multi_math
568 
569 template <class T> class FindSum;
570 
571 struct UnsuitableTypeForExpandElements {};
572 
573 template <class T>
574 struct ExpandElementResult
575 {
576  typedef UnsuitableTypeForExpandElements type;
577 };
578 
579 template <class T>
580 struct ExpandElementResult<std::complex<T> >
581 {
582  typedef T type;
583  enum { size = 2 };
584 };
585 
586 template <class T>
587 class FFTWComplex;
588 
589 template <class T>
590 struct ExpandElementResult<FFTWComplex<T> >
591 {
592  typedef T type;
593  enum { size = 2 };
594 };
595 
596 template <class T, int SIZE>
597 struct ExpandElementResult<TinyVector<T, SIZE> >
598 {
599  typedef T type;
600  enum { size = SIZE };
601 };
602 
603 template <class T, unsigned int R, unsigned int G, unsigned int B>
604 struct ExpandElementResult<RGBValue<T, R, G, B> >
605 {
606  typedef T type;
607  enum { size = 3 };
608 };
609 
610 #define VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(TYPE) \
611 template <> \
612 struct ExpandElementResult<TYPE> \
613 { \
614  typedef TYPE type; \
615  enum { size = 1 }; \
616 }; \
617 
618 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(bool)
619 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(char)
620 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed char)
621 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed short)
622 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed int)
623 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed long)
624 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed long long)
625 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned char)
626 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned short)
627 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned int)
628 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned long)
629 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned long long)
630 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(float)
631 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(double)
632 VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(long double)
633 
634 #undef VIGRA_DEFINE_EXPAND_ELEMENT_RESULT
635 
636 
637 /********************************************************/
638 /* */
639 /* NormTraits */
640 /* */
641 /********************************************************/
642 
643 template <unsigned int N, class T, class C>
644 struct NormTraits<MultiArrayView<N, T, C> >
645 {
646  typedef MultiArrayView<N, T, C> Type;
647  typedef typename NormTraits<T>::SquaredNormType SquaredNormType;
648  typedef typename SquareRootTraits<SquaredNormType>::SquareRootResult NormType;
649 };
650 
651 template <unsigned int N, class T, class A>
652 struct NormTraits<MultiArray<N, T, A> >
653 : public NormTraits<typename MultiArray<N, T, A>::view_type>
654 {
655  typedef NormTraits<typename MultiArray<N, T, A>::view_type> BaseType;
656  typedef MultiArray<N, T, A> Type;
657  typedef typename BaseType::SquaredNormType SquaredNormType;
658  typedef typename BaseType::NormType NormType;
659 };
660 
661 /********************************************************/
662 /* */
663 /* MultiArrayView */
664 /* */
665 /********************************************************/
666 
667 /** \brief Base class for, and view to, \ref vigra::MultiArray.
668 
669 This class implements the interface of both MultiArray and
670 MultiArrayView. By default, MultiArrayViews are tagged as
671 strided (using <tt>StridedArrayTag</tt> as third template parameter).
672 This means that the array elements need not be consecutive in memory,
673 making the view flexible to represent all kinds of subarrays and slices.
674 In certain cases (which have become rare due to improvements of
675 optimizer and processor technology), an array may be tagged with
676 <tt>UnstridedArrayTag</tt> which indicates that the first array dimension
677 is guaranteed to be unstrided, i.e. has consecutive elements in memory.
678 
679 In addition to the member functions described here, <tt>MultiArrayView</tt>
680 and its subclasses support arithmetic and algebraic functions via the
681 module \ref MultiMathModule.
682 
683 If you want to apply an algorithm requiring an image to a
684 <tt>MultiArrayView</tt> of appropriate (2-dimensional) shape, you can
685 create a \ref vigra::BasicImageView that acts as a wrapper with the
686 necessary interface -- see \ref MultiArrayToImage.
687 
688 The template parameter are as follows
689 \code
690  N: the array dimension
691 
692  T: the type of the array elements
693 
694  C: a tag determining if the array's inner dimension is strided
695  (the tag can be used to specialize algorithms for different memory
696  layouts, see \ref MultiArrayTags for details). Users normally need
697  not care about this parameter.
698 \endcode
699 
700 <b>\#include</b> <vigra/multi_array.hxx> <br/>
701 Namespace: vigra
702 */
703 template <unsigned int N, class T, class StrideTag>
705 {
706 public:
707 
708  /** the array's actual dimensionality.
709  This ensures that MultiArrayView can also be used for
710  scalars (that is, when <tt>N == 0</tt>). Calculated as:<br>
711  \code
712  actual_dimension = (N==0) ? 1 : N
713  \endcode
714  */
715  enum ActualDimension { actual_dimension = (N==0) ? 1 : N };
716 
717  /** the array's value type
718  */
719  typedef T value_type;
720 
721  /** reference type (result of operator[])
722  */
723  typedef value_type &reference;
724 
725  /** const reference type (result of operator[] const)
726  */
727  typedef const value_type &const_reference;
728 
729  /** pointer type
730  */
731  typedef value_type *pointer;
732 
733  /** const pointer type
734  */
735  typedef const value_type *const_pointer;
736 
737  /** difference type (used for multi-dimensional offsets and indices)
738  */
740 
741  /** key type (argument of index operator array[i] -- same as difference_type)
742  */
743  typedef difference_type key_type;
744 
745  /** size type
746  */
747  typedef difference_type size_type;
748 
749  /** difference and index type for a single dimension
750  */
752 
753  /** scan-order iterator (StridedScanOrderIterator) type
754  */
756 
757  /** const scan-order iterator (StridedScanOrderIterator) type
758  */
760 
761  /** traverser (MultiIterator) type
762  */
763  typedef typename vigra::detail::MultiIteratorChooser <
764  StrideTag>::template Traverser <actual_dimension, T, T &, T *>::type traverser;
765 
766  /** const traverser (MultiIterator) type
767  */
768  typedef typename vigra::detail::MultiIteratorChooser <
769  StrideTag>::template Traverser <actual_dimension, T, T const &, T const *>::type const_traverser;
770 
771  /** the view type associated with this array.
772  */
774 
775  /** the matrix type associated with this array.
776  */
778 
779  bool checkInnerStride(UnstridedArrayTag) const
780  {
781  return m_stride[0] <= 1;
782  }
783 
784  bool checkInnerStride(StridedArrayTag) const
785  {
786  return true;
787  }
788 
789  protected:
790 
791  typedef typename difference_type::value_type diff_zero_t;
792 
793  /** the shape of the image pointed to is stored here.
794  */
795  difference_type m_shape;
796 
797  /** the strides (offset of a sample to the next) for every dimension
798  are stored here.
799  */
800  difference_type m_stride;
801 
802  /** pointer to the image.
803  */
804  pointer m_ptr;
805 
806  template <class CN>
807  void assignImpl(const MultiArrayView <N, T, CN>& rhs);
808 
809  template <class U, class CN>
810  void copyImpl(const MultiArrayView <N, U, CN>& rhs);
811 
812  template <class U, class CN>
813  void swapDataImpl(MultiArrayView <N, U, CN> rhs);
814 
815  template <class CN>
816  bool arraysOverlap(const MultiArrayView <N, T, CN>& rhs) const;
817 
818  template <class U, class CN>
819  bool arraysOverlap(const MultiArrayView <N, U, CN>&) const
820  {
821  return false;
822  }
823 
824 public:
825 
826  /** default constructor: create an invalid view,
827  * i.e. hasData() returns false and size() is zero.
828  */
830  : m_shape (diff_zero_t(0)), m_stride (diff_zero_t(0)), m_ptr (0)
831  {}
832 
833  /** construct from another array view.
834  Throws a precondition error if this array has UnstridedArrayTag, but the
835  innermost dimension of \a other is strided.
836  */
837  template <class Stride>
839  : m_shape (other.shape()),
840  m_stride (other.stride()),
841  m_ptr (other.data())
842  {
843  vigra_precondition(other.checkInnerStride(StrideTag()),
844  "MultiArrayView<..., UnstridedArrayTag>(MultiArrayView const &): cannot create unstrided view from strided array.");
845  }
846 
847  /** construct from shape and pointer
848  */
849  MultiArrayView (const difference_type &shape, const_pointer ptr)
850  : m_shape (shape),
851  m_stride (detail::defaultStride<actual_dimension>(shape)),
852  m_ptr (const_cast<pointer>(ptr))
853  {}
854 
855  /** Construct from shape, strides (offset of a sample to the
856  next) for every dimension, and pointer. (Note that
857  strides are not given in bytes, but in offset steps of the
858  respective pointer type.)
859  */
860  MultiArrayView (const difference_type &shape,
861  const difference_type &stride,
862  const_pointer ptr)
863  : m_shape (shape),
864  m_stride (stride),
865  m_ptr (const_cast<pointer>(ptr))
866  {
867  vigra_precondition(checkInnerStride(StrideTag()),
868  "MultiArrayView<..., UnstridedArrayTag>::MultiArrayView(): First dimension of given array is not unstrided.");
869  }
870 
871  /** Construct from an old-style BasicImage.
872  */
873  template <class ALLOC>
875  : m_shape (Shape2(image.width(), image.height())),
876  m_stride (detail::defaultStride<actual_dimension>(m_shape)),
877  m_ptr (const_cast<pointer>(image.data()))
878  {}
879 
880  /** Conversion to a strided view.
881  */
883  {
885  }
886 
887  /** Reset this <tt>MultiArrayView</tt> to an invalid state (as after default construction).
888  Can e.g. be used prior to assignment to make a view object point to new data.
889  */
890  void reset() {
891  m_shape = diff_zero_t(0);
892  m_stride = diff_zero_t(0);
893  m_ptr = 0;
894  }
895 
896 
897  /** Assignment. There are 3 cases:
898 
899  <ul>
900  <li> When this <tt>MultiArrayView</tt> does not point to valid data
901  (e.g. after default construction), it becomes a new view of \a rhs.
902  <li> Otherwise, when the shapes of the two arrays match, the contents
903  (i.e. the elements) of \a rhs are copied.
904  <li> Otherwise, a <tt>PreconditionViolation</tt> exception is thrown.
905  </ul>
906  */
908  {
909  if(this != &rhs)
910  assignImpl(rhs);
911  return *this;
912  }
913 
914  template<class Stride2>
916  {
917  assignImpl(rhs);
918  return *this;
919  }
920 
921  /** Assignment of a differently typed MultiArrayView. It copies the elements
922  of\a rhs or fails with <tt>PreconditionViolation</tt> exception when
923  the shapes do not match.
924  */
925  template<class U, class C1>
927  {
928  vigra_precondition(this->shape() == rhs.shape(),
929  "MultiArrayView::operator=(): shape mismatch.");
930  this->copyImpl(rhs);
931  return *this;
932  }
933 
934  /** Assignment of a scalar. Equivalent to MultiArrayView::init(v).
935  */
936  MultiArrayView & operator=(value_type const & v)
937  {
938  return init(v);
939  }
940 
941  /** Add-assignment of a compatible MultiArrayView. Fails with
942  <tt>PreconditionViolation</tt> exception when the shapes do not match.
943  */
944  template<class U, class C1>
946 
947  /** Subtract-assignment of a compatible MultiArrayView. Fails with
948  <tt>PreconditionViolation</tt> exception when the shapes do not match.
949  */
950  template<class U, class C1>
952 
953  /** Multiply-assignment of a compatible MultiArrayView. Fails with
954  <tt>PreconditionViolation</tt> exception when the shapes do not match.
955  */
956  template<class U, class C1>
958 
959  /** Divide-assignment of a compatible MultiArrayView. Fails with
960  <tt>PreconditionViolation</tt> exception when the shapes do not match.
961  */
962  template<class U, class C1>
964 
965  /** Add-assignment of a scalar.
966  */
967  MultiArrayView & operator+=(T const & rhs)
968  {
969  detail::copyAddScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>());
970  return *this;
971  }
972 
973  /** Subtract-assignment of a scalar.
974  */
975  MultiArrayView & operator-=(T const & rhs)
976  {
977  detail::copySubScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>());
978  return *this;
979  }
980 
981  /** Multiply-assignment of a scalar.
982  */
983  MultiArrayView & operator*=(T const & rhs)
984  {
985  detail::copyMulScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>());
986  return *this;
987  }
988 
989  /** Divide-assignment of a scalar.
990  */
991  MultiArrayView & operator/=(T const & rhs)
992  {
993  detail::copyDivScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>());
994  return *this;
995  }
996 
997  /** Assignment of an array expression. Fails with
998  <tt>PreconditionViolation</tt> exception when the shapes do not match.
999  */
1000  template<class Expression>
1001  MultiArrayView & operator=(multi_math::MultiMathOperand<Expression> const & rhs)
1002  {
1003  multi_math::math_detail::assign(*this, rhs);
1004  return *this;
1005  }
1006 
1007  /** Add-assignment of an array expression. Fails with
1008  <tt>PreconditionViolation</tt> exception when the shapes do not match.
1009  */
1010  template<class Expression>
1011  MultiArrayView & operator+=(multi_math::MultiMathOperand<Expression> const & rhs)
1012  {
1013  multi_math::math_detail::plusAssign(*this, rhs);
1014  return *this;
1015  }
1016 
1017  /** Subtract-assignment of an array expression. Fails with
1018  <tt>PreconditionViolation</tt> exception when the shapes do not match.
1019  */
1020  template<class Expression>
1021  MultiArrayView & operator-=(multi_math::MultiMathOperand<Expression> const & rhs)
1022  {
1023  multi_math::math_detail::minusAssign(*this, rhs);
1024  return *this;
1025  }
1026 
1027  /** Multiply-assignment of an array expression. Fails with
1028  <tt>PreconditionViolation</tt> exception when the shapes do not match.
1029  */
1030  template<class Expression>
1031  MultiArrayView & operator*=(multi_math::MultiMathOperand<Expression> const & rhs)
1032  {
1033  multi_math::math_detail::multiplyAssign(*this, rhs);
1034  return *this;
1035  }
1036 
1037  /** Divide-assignment of an array expression. Fails with
1038  <tt>PreconditionViolation</tt> exception when the shapes do not match.
1039  */
1040  template<class Expression>
1041  MultiArrayView & operator/=(multi_math::MultiMathOperand<Expression> const & rhs)
1042  {
1043  multi_math::math_detail::divideAssign(*this, rhs);
1044  return *this;
1045  }
1046 
1047  /** array access.
1048  */
1049  reference operator[] (const difference_type &d)
1050  {
1051  VIGRA_ASSERT_INSIDE(d);
1052  return m_ptr [dot (d, m_stride)];
1053  }
1054 
1055  /** array access.
1056  */
1057  const_reference operator[] (const difference_type &d) const
1058  {
1059  VIGRA_ASSERT_INSIDE(d);
1060  return m_ptr [dot (d, m_stride)];
1061  }
1062 
1063  /** equivalent to bindInner(), when M < N.
1064  */
1065  template <int M>
1067  {
1068  return bindInner(d);
1069  }
1070 
1071  /** Array access in scan-order sense.
1072  Mostly useful to support standard indexing for 1-dimensional multi-arrays,
1073  but works for any N. Use scanOrderIndexToCoordinate() and
1074  coordinateToScanOrderIndex() for conversion between indices and coordinates.
1075 
1076  <b>Note:</b> This function should not be used in the inner loop, because the
1077  conversion of the scan order index into a memory address is expensive
1078  (it must take into account that memory may not be consecutive for subarrays
1079  and/or strided arrays). Always prefer operator() if possible.
1080  */
1081  reference operator[](difference_type_1 d)
1082  {
1083  VIGRA_ASSERT_INSIDE(scanOrderIndexToCoordinate(d));
1084  return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)];
1085  }
1086 
1087  /** Array access in scan-order sense.
1088  Mostly useful to support standard indexing for 1-dimensional multi-arrays,
1089  but works for any N. Use scanOrderIndexToCoordinate() and
1090  coordinateToScanOrderIndex() for conversion between indices and coordinates.
1091 
1092  <b>Note:</b> This function should not be used in the inner loop, because the
1093  conversion of the scan order index into a memory address is expensive
1094  (it must take into account that memory may not be consecutive for subarrays
1095  and/or strided arrays). Always prefer operator() if possible.
1096  */
1097  const_reference operator[](difference_type_1 d) const
1098  {
1099  VIGRA_ASSERT_INSIDE(scanOrderIndexToCoordinate(d));
1100  return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)];
1101  }
1102 
1103  /** convert scan-order index to coordinate.
1104  */
1105  difference_type scanOrderIndexToCoordinate(difference_type_1 d) const
1106  {
1107  difference_type result;
1108  detail::ScanOrderToCoordinate<actual_dimension>::exec(d, m_shape, result);
1109  return result;
1110  }
1111 
1112  /** convert coordinate to scan-order index.
1113  */
1114  difference_type_1 coordinateToScanOrderIndex(const difference_type &d) const
1115  {
1116  return detail::CoordinateToScanOrder<actual_dimension>::exec(m_shape, d);
1117  }
1118 
1119  /** 1D array access. Use only if N == 1.
1120  */
1121  reference operator() (difference_type_1 x)
1122  {
1123  VIGRA_ASSERT_INSIDE(difference_type(x));
1124  return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x)];
1125  }
1126 
1127  /** 2D array access. Use only if N == 2.
1128  */
1129  reference operator() (difference_type_1 x, difference_type_1 y)
1130  {
1131  VIGRA_ASSERT_INSIDE(difference_type(x, y));
1132  return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x, y)];
1133  }
1134 
1135  /** 3D array access. Use only if N == 3.
1136  */
1137  reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z)
1138  {
1139  VIGRA_ASSERT_INSIDE(difference_type(x, y, z));
1140  return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
1141  }
1142 
1143  /** 4D array access. Use only if N == 4.
1144  */
1145  reference operator() (difference_type_1 x, difference_type_1 y,
1146  difference_type_1 z, difference_type_1 u)
1147  {
1148  VIGRA_ASSERT_INSIDE(difference_type(x, y, z, u));
1149  return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u];
1150  }
1151 
1152  /** 5D array access. Use only if N == 5.
1153  */
1154  reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z,
1155  difference_type_1 u, difference_type_1 v)
1156  {
1157  VIGRA_ASSERT_INSIDE(difference_type(x, y,z, u,v));
1158  return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v];
1159  }
1160 
1161  /** 1D const array access. Use only if N == 1.
1162  */
1163  const_reference operator() (difference_type_1 x) const
1164  {
1165  VIGRA_ASSERT_INSIDE(difference_type(x));
1166  return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x)];
1167  }
1168 
1169  /** 2D const array access. Use only if N == 2.
1170  */
1171  const_reference operator() (difference_type_1 x, difference_type_1 y) const
1172  {
1173  VIGRA_ASSERT_INSIDE(difference_type(x, y));
1174  return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x, y)];
1175  }
1176 
1177  /** 3D const array access. Use only if N == 3.
1178  */
1179  const_reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z) const
1180  {
1181  VIGRA_ASSERT_INSIDE(difference_type(x,y,z));
1182  return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
1183  }
1184 
1185  /** 4D const array access. Use only if N == 4.
1186  */
1187  const_reference operator() (difference_type_1 x, difference_type_1 y,
1188  difference_type_1 z, difference_type_1 u) const
1189  {
1190  VIGRA_ASSERT_INSIDE(difference_type(x,y,z,u));
1191  return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u];
1192  }
1193 
1194  /** 5D const array access. Use only if N == 5.
1195  */
1196  const_reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z,
1197  difference_type_1 u, difference_type_1 v) const
1198  {
1199  VIGRA_ASSERT_INSIDE(difference_type(x,y,z,u,v));
1200  return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v];
1201  }
1202 
1203  /** Init with a constant.
1204  */
1205  template <class U>
1206  MultiArrayView & init(const U & init)
1207  {
1208  if(hasData())
1209  detail::copyScalarMultiArrayData(traverser_begin(), shape(), init, MetaInt<actual_dimension-1>());
1210  return *this;
1211  }
1212 
1213 
1214  /** Copy the data of the right-hand array (array shapes must match).
1215  */
1216  void copy(const MultiArrayView & rhs)
1217  {
1218  if(this == &rhs)
1219  return;
1220  this->copyImpl(rhs);
1221  }
1222 
1223  /** Copy the data of the right-hand array (array shapes must match).
1224  */
1225  template <class U, class CN>
1227  {
1228  this->copyImpl(rhs);
1229  }
1230 
1231  /** Swap the pointers, shaes and strides between two array views.
1232 
1233  This function must be used with care. Never swap a MultiArray
1234  (which owns data) with a MultiArrayView:
1235  \code
1236  MultiArray<2, int> a(3,2), b(3,2);
1237  MultiArrayView<2, int> va(a);
1238 
1239  va.swap(b); // danger!
1240  \endcode
1241  Now, <tt>a</tt> and <tt>b</tt> refer to the same memory. This may lead
1242  to a crash in their destructor, and in any case leaks <tt>b</tt>'s original
1243  memory. Only use swap() on copied MultiArrayViews:
1244  \code
1245  MultiArray<2, int> a(3,2), b(3,2);
1246  MultiArrayView<2, int> va(a), vb(b);
1247 
1248  va.swap(vb); // OK
1249  \endcode
1250  */
1251  void swap(MultiArrayView & other)
1252  {
1253  if (this == &other)
1254  return;
1255  std::swap(this->m_shape, other.m_shape);
1256  std::swap(this->m_stride, other.m_stride);
1257  std::swap(this->m_ptr, other.m_ptr);
1258  }
1259 
1260  /** swap the data between two MultiArrayView objects.
1261 
1262  The shapes of the two array must match.
1263  */
1265  {
1266  if(this != &rhs)
1267  swapDataImpl(rhs);
1268  }
1269 
1270  /** swap the data between two MultiArrayView objects.
1271 
1272  The shapes of the two array must match.
1273  */
1274  template <class T2, class C2>
1276  {
1277  swapDataImpl(rhs);
1278  }
1279 
1280  /** check whether the array is unstrided (i.e. has consecutive memory) up
1281  to the given dimension.
1282 
1283  \a dimension can range from 0 ... N-1. If a certain dimension is unstrided,
1284  all lower dimensions are also unstrided.
1285  */
1286  bool isUnstrided(unsigned int dimension = N-1) const
1287  {
1288  difference_type s = vigra::detail::defaultStride<actual_dimension>(shape());
1289  for(unsigned int k = 0; k <= dimension; ++k)
1290  if(stride(k) != s[k])
1291  return false;
1292  return true;
1293  }
1294 
1295  /** bind the M outmost dimensions to certain indices.
1296  this reduces the dimensionality of the image to
1297  max { 1, N-M }.
1298 
1299  <b>Usage:</b>
1300  \code
1301  // create a 3D array of size 40x30x20
1302  typedef MultiArray<3, double>::difference_type Shape;
1303  MultiArray<3, double> array3(Shape(40, 30, 20));
1304 
1305  // get a 1D array by fixing index 1 to 12, and index 2 to 10
1306  MultiArrayView <1, double> array1 = array3.bindOuter(TinyVector<MultiArrayIndex, 2>(12, 10));
1307  \endcode
1308  */
1309  template <int M, class Index>
1310  MultiArrayView <N-M, T, StrideTag> bindOuter(const TinyVector <Index, M> &d) const;
1311 
1312  /** bind the M innermost dimensions to certain indices.
1313  this reduces the dimensionality of the image to
1314  max { 1, N-M }.
1315 
1316  <b>Usage:</b>
1317  \code
1318  // create a 3D array of size 40x30x20
1319  typedef MultiArray<3, double>::difference_type Shape;
1320  MultiArray<3, double> array3(Shape(40, 30, 20));
1321 
1322  // get a 1D array by fixing index 0 to 12, and index 1 to 10
1323  MultiArrayView <1, double, StridedArrayTag> array1 = array3.bindInner(TinyVector<MultiArrayIndex, 2>(12, 10));
1324  \endcode
1325  */
1326  template <int M, class Index>
1328 
1329  /** bind dimension M to index d.
1330  this reduces the dimensionality of the image to
1331  max { 1, N-1 }.
1332 
1333  <b>Usage:</b>
1334  \code
1335  // create a 3D array of size 40x30x20
1336  typedef MultiArray<3, double>::difference_type Shape;
1337  MultiArray<3, double> array3(Shape(40, 30, 20));
1338 
1339  // get a 2D array by fixing index 1 to 12
1340  MultiArrayView <2, double> array2 = array3.bind<1>(12);
1341 
1342  // get a 2D array by fixing index 0 to 23
1343  MultiArrayView <2, double, StridedArrayTag> array2a = array3.bind<0>(23);
1344  \endcode
1345  */
1346  template <unsigned int M>
1347  MultiArrayView <N-1, T, typename vigra::detail::MaybeStrided<StrideTag, M>::type >
1348  bind (difference_type_1 d) const;
1349 
1350  /** bind the outmost dimension to a certain index.
1351  this reduces the dimensionality of the image to
1352  max { 1, N-1 }.
1353 
1354  <b>Usage:</b>
1355  \code
1356  // create a 3D array of size 40x30x20
1357  typedef MultiArray<3, double>::difference_type Shape;
1358  MultiArray<3, double> array3(Shape(40, 30, 20));
1359 
1360  // get a 2D array by fixing the outermost index (i.e. index 2) to 12
1361  MultiArrayView <2, double> array2 = array3.bindOuter(12);
1362  \endcode
1363  */
1364  MultiArrayView <N-1, T, StrideTag> bindOuter (difference_type_1 d) const;
1365 
1366  /** bind the innermost dimension to a certain index.
1367  this reduces the dimensionality of the image to
1368  max { 1, N-1 }.
1369 
1370  <b>Usage:</b>
1371  \code
1372  // create a 3D array of size 40x30x20
1373  typedef MultiArray<3, double>::difference_type Shape;
1374  MultiArray<3, double> array3(Shape(40, 30, 20));
1375 
1376  // get a 2D array by fixing the innermost index (i.e. index 0) to 23
1377  MultiArrayView <2, double, StridedArrayTag> array2 = array3.bindInner(23);
1378  \endcode
1379  */
1380  MultiArrayView <N-1, T, StridedArrayTag> bindInner (difference_type_1 d) const;
1381 
1382  /** bind dimension m to index d.
1383  this reduces the dimensionality of the image to
1384  max { 1, N-1 }.
1385 
1386  <b>Usage:</b>
1387  \code
1388  // create a 3D array of size 40x30x20
1389  typedef MultiArray<3, double>::difference_type Shape;
1390  MultiArray<3, double> array3(Shape(40, 30, 20));
1391 
1392  // get a 2D array by fixing index 2 to 15
1393  MultiArrayView <2, double, StridedArrayTag> array2 = array3.bindAt(2, 15);
1394  \endcode
1395  */
1397  bindAt (difference_type_1 m, difference_type_1 d) const;
1398 
1399  /** Create a view to channel 'i' of a vector-like value type. Possible value types
1400  (of the original array) are: \ref TinyVector, \ref RGBValue, \ref FFTWComplex,
1401  and <tt>std::complex</tt>. The list can be extended to any type whose memory
1402  layout is equivalent to a fixed-size C array, by specializing
1403  <tt>ExpandElementResult</tt>.
1404 
1405  <b>Usage:</b>
1406  \code
1407  MultiArray<2, RGBValue<float> > rgb_image(Shape2(w, h));
1408 
1409  MultiArrayView<2, float, StridedArrayTag> red = rgb_image.bindElementChannel(0);
1410  MultiArrayView<2, float, StridedArrayTag> green = rgb_image.bindElementChannel(1);
1411  MultiArrayView<2, float, StridedArrayTag> blue = rgb_image.bindElementChannel(2);
1412  \endcode
1413  */
1415  bindElementChannel(difference_type_1 i) const
1416  {
1417  vigra_precondition(0 <= i && i < ExpandElementResult<T>::size,
1418  "MultiArrayView::bindElementChannel(i): 'i' out of range.");
1419  return expandElements(0).bindInner(i);
1420  }
1421 
1422  /** Create a view where a vector-like element type is expanded into a new
1423  array dimension. The new dimension is inserted at index position 'd',
1424  which must be between 0 and N inclusive.
1425 
1426  Possible value types of the original array are: \ref TinyVector, \ref RGBValue,
1427  \ref FFTWComplex, <tt>std::complex</tt>, and the built-in number types (in this
1428  case, <tt>expandElements</tt> is equivalent to <tt>insertSingletonDimension</tt>).
1429  The list of supported types can be extended to any type whose memory
1430  layout is equivalent to a fixed-size C array, by specializing
1431  <tt>ExpandElementResult</tt>.
1432 
1433  <b>Usage:</b>
1434  \code
1435  MultiArray<2, RGBValue<float> > rgb_image(Shape2(w, h));
1436 
1437  MultiArrayView<3, float, StridedArrayTag> multiband_image = rgb_image.expandElements(2);
1438  \endcode
1439  */
1441  expandElements(difference_type_1 d) const;
1442 
1443  /** Add a singleton dimension (dimension of length 1).
1444 
1445  Singleton dimensions don't change the size of the data, but introduce
1446  a new index that can only take the value 0. This is mainly useful for
1447  the 'reduce mode' of transformMultiArray() and combineTwoMultiArrays(),
1448  because these functions require the source and destination arrays to
1449  have the same number of dimensions.
1450 
1451  The range of \a i must be <tt>0 <= i <= N</tt>. The new dimension will become
1452  the i'th index, and the old indices from i upwards will shift one
1453  place to the right.
1454 
1455  <b>Usage:</b>
1456 
1457  Suppose we want have a 2D array and want to create a 1D array that contains
1458  the row average of the first array.
1459  \code
1460  typedef MultiArrayShape<2>::type Shape2;
1461  MultiArray<2, double> original(Shape2(40, 30));
1462 
1463  typedef MultiArrayShape<1>::type Shape1;
1464  MultiArray<1, double> rowAverages(Shape1(30));
1465 
1466  // temporarily add a singleton dimension to the destination array
1467  transformMultiArray(srcMultiArrayRange(original),
1468  destMultiArrayRange(rowAverages.insertSingletonDimension(0)),
1469  FindAverage<double>());
1470  \endcode
1471  */
1473  insertSingletonDimension (difference_type_1 i) const;
1474 
1475  /** create a multiband view for this array.
1476 
1477  The type <tt>MultiArrayView<N, Multiband<T> ></tt> tells VIGRA
1478  algorithms which recognize the <tt>Multiband</tt> modifier to
1479  interpret the outermost (last) dimension as a channel dimension.
1480  In effect, these algorithms will treat the data as a set of
1481  (N-1)-dimensional arrays instead of a single N-dimensional array.
1482  */
1484  {
1485  return MultiArrayView<N, Multiband<value_type>, StrideTag>(*this);
1486  }
1487 
1488  /** Create a view to the diagonal elements of the array.
1489 
1490  This produces a 1D array view whose size equals the size
1491  of the shortest dimension of the original array.
1492 
1493  <b>Usage:</b>
1494  \code
1495  // create a 3D array of size 40x30x20
1496  typedef MultiArray<3, double>::difference_type Shape;
1497  MultiArray<3, double> array3(Shape(40, 30, 20));
1498 
1499  // get a view to the diagonal elements
1500  MultiArrayView <1, double, StridedArrayTag> diagonal = array3.diagonal();
1501  assert(diagonal.shape(0) == 20);
1502  \endcode
1503  */
1505  {
1507  Shape1(vigra::sum(m_stride)), m_ptr);
1508  }
1509 
1510  /** create a rectangular subarray that spans between the
1511  points p and q, where p is in the subarray, q not.
1512  If an element of p or q is negative, it is subtracted
1513  from the correspongng shape.
1514 
1515  <b>Usage:</b>
1516  \code
1517  // create a 3D array of size 40x30x20
1518  typedef MultiArray<3, double>::difference_type Shape;
1519  MultiArray<3, double> array3(Shape(40, 30, 20));
1520 
1521  // get a subarray set is smaller by one element at all sides
1522  MultiArrayView <3, double> subarray = array3.subarray(Shape(1,1,1), Shape(39, 29, 19));
1523 
1524  // specifying the end point with a vector of '-1' is equivalent
1525  MultiArrayView <3, double> subarray2 = array3.subarray(Shape(1,1,1), Shape(-1, -1, -1));
1526  \endcode
1527  */
1528  MultiArrayView subarray (difference_type p, difference_type q) const
1529  {
1530  detail::RelativeToAbsoluteCoordinate<actual_dimension-1>::exec(shape(), p);
1531  detail::RelativeToAbsoluteCoordinate<actual_dimension-1>::exec(shape(), q);
1532  const difference_type_1 offset = dot (m_stride, p);
1533  return MultiArrayView (q - p, m_stride, m_ptr + offset);
1534  }
1535 
1536  /** apply an additional striding to the image, thereby reducing
1537  the shape of the array.
1538  for example, multiplying the stride of dimension one by three
1539  turns an appropriately laid out (interleaved) rgb image into
1540  a single band image.
1541  */
1543  stridearray (const difference_type &s) const
1544  {
1545  difference_type shape = m_shape;
1546  for (unsigned int i = 0; i < actual_dimension; ++i)
1547  shape[i] = (shape[i] + s[i] - 1) / s[i];
1548  return MultiArrayView <N, T, StridedArrayTag>(shape, m_stride * s, m_ptr);
1549  }
1550 
1551  /** Transpose an array. If N==2, this implements the usual matrix transposition.
1552  For N > 2, it reverses the order of the indices.
1553 
1554  <b>Usage:</b><br>
1555  \code
1556  typedef MultiArray<2, double>::difference_type Shape;
1557  MultiArray<2, double> array(10, 20);
1558 
1559  MultiArrayView<2, double, StridedArrayTag> transposed = array.transpose();
1560 
1561  for(int i=0; i<array.shape(0), ++i)
1562  for(int j=0; j<array.shape(1); ++j)
1563  assert(array(i, j) == transposed(j, i));
1564  \endcode
1565  */
1567  transpose () const
1568  {
1569  difference_type shape(m_shape.begin(), ReverseCopy),
1570  stride(m_stride.begin(), ReverseCopy);
1572  }
1573 
1574  /** Permute the dimensions of the array.
1575  The function exchanges the orer of the array's axes without copying the data.
1576  Argument\a permutation specifies the desired order such that
1577  <tt>permutation[k] = j</tt> means that axis <tt>j</tt> in the original array
1578  becomes axis <tt>k</tt> in the transposed array.
1579 
1580  <b>Usage:</b><br>
1581  \code
1582  typedef MultiArray<2, double>::difference_type Shape;
1583  MultiArray<2, double> array(10, 20);
1584 
1585  MultiArrayView<2, double, StridedArrayTag> transposed = array.transpose(Shape(1,0));
1586 
1587  for(int i=0; i<array.shape(0), ++i)
1588  for(int j=0; j<array.shape(1); ++j)
1589  assert(array(i, j) == transposed(j, i));
1590  \endcode
1591  */
1593  transpose(const difference_type &permutation) const
1594  {
1595  return permuteDimensions(permutation);
1596  }
1597 
1599  permuteDimensions (const difference_type &s) const;
1600 
1601  /** Permute the dimensions of the array so that the strides are in ascending order.
1602  Determines the appropriate permutation and then calls permuteDimensions().
1603  */
1605  permuteStridesAscending() const;
1606 
1607  /** Permute the dimensions of the array so that the strides are in descending order.
1608  Determines the appropriate permutation and then calls permuteDimensions().
1609  */
1611  permuteStridesDescending() const;
1612 
1613  /** Compute the ordering of the strides in this array.
1614  The result is describes the current permutation of the axes relative
1615  to the standard ascending stride order.
1616  */
1617  difference_type strideOrdering() const
1618  {
1619  return strideOrdering(m_stride);
1620  }
1621 
1622  /** Compute the ordering of the given strides.
1623  The result is describes the current permutation of the axes relative
1624  to the standard ascending stride order.
1625  */
1626  static difference_type strideOrdering(difference_type strides);
1627 
1628  /** number of the elements in the array.
1629  */
1630  difference_type_1 elementCount () const
1631  {
1632  difference_type_1 ret = m_shape[0];
1633  for(int i = 1; i < actual_dimension; ++i)
1634  ret *= m_shape[i];
1635  return ret;
1636  }
1637 
1638  /** number of the elements in the array.
1639  Same as <tt>elementCount()</tt>. Mostly useful to support the std::vector interface.
1640  */
1641  difference_type_1 size () const
1642  {
1643  return elementCount();
1644  }
1645 
1646  /** return the array's shape.
1647  */
1648  const difference_type & shape () const
1649  {
1650  return m_shape;
1651  }
1652 
1653  /** return the array's size at a certain dimension.
1654  */
1655  difference_type_1 size (difference_type_1 n) const
1656  {
1657  return m_shape [n];
1658  }
1659 
1660  /** return the array's shape at a certain dimension
1661  (same as <tt>size(n)</tt>).
1662  */
1663  difference_type_1 shape (difference_type_1 n) const
1664  {
1665  return m_shape [n];
1666  }
1667 
1668  /** return the array's width (same as <tt>shape(0)</tt>).
1669  */
1670  difference_type_1 width() const
1671  {
1672  return m_shape [0];
1673  }
1674 
1675  /** return the array's height (same as <tt>shape(1)</tt>).
1676  */
1677  difference_type_1 height() const
1678  {
1679  return m_shape [1];
1680  }
1681 
1682  /** return the array's stride for every dimension.
1683  */
1684  const difference_type & stride () const
1685  {
1686  return m_stride;
1687  }
1688 
1689  /** return the array's stride at a certain dimension.
1690  */
1691  difference_type_1 stride (int n) const
1692  {
1693  return m_stride [n];
1694  }
1695 
1696  /** check whether two arrays are elementwise equal.
1697  */
1698  template <class U, class C1>
1699  bool operator==(MultiArrayView<N, U, C1> const & rhs) const
1700  {
1701  if(this->shape() != rhs.shape())
1702  return false;
1703  return detail::equalityOfMultiArrays(traverser_begin(), shape(), rhs.traverser_begin(), MetaInt<actual_dimension-1>());
1704  }
1705 
1706  /** check whether two arrays are not elementwise equal.
1707  Also true when the two arrays have different shapes.
1708  */
1709  template <class U, class C1>
1710  bool operator!=(MultiArrayView<N, U, C1> const & rhs) const
1711  {
1712  return !operator==(rhs);
1713  }
1714 
1715  /** check whether the given point is in the array range.
1716  */
1717  bool isInside (difference_type const & p) const
1718  {
1719  for(int d=0; d<actual_dimension; ++d)
1720  if(p[d] < 0 || p[d] >= shape(d))
1721  return false;
1722  return true;
1723  }
1724  /** check whether the given point is not in the array range.
1725  */
1726  bool isOutside (difference_type const & p) const
1727  {
1728  for(int d=0; d<actual_dimension; ++d)
1729  if(p[d] < 0 || p[d] >= shape(d))
1730  return true;
1731  return false;
1732  }
1733 
1734  /** Check if the array contains only non-zero elements (or if all elements
1735  are 'true' if the value type is 'bool').
1736  */
1737  bool all() const
1738  {
1739  bool res = true;
1740  detail::reduceOverMultiArray(traverser_begin(), shape(),
1741  res,
1742  detail::AllTrueReduceFunctor(),
1743  MetaInt<actual_dimension-1>());
1744  return res;
1745  }
1746 
1747  /** Check if the array contains a non-zero element (or an element
1748  that is 'true' if the value type is 'bool').
1749  */
1750  bool any() const
1751  {
1752  bool res = false;
1753  detail::reduceOverMultiArray(traverser_begin(), shape(),
1754  res,
1755  detail::AnyTrueReduceFunctor(),
1756  MetaInt<actual_dimension-1>());
1757  return res;
1758  }
1759 
1760  /** Find the minimum and maximum element in this array.
1761  See \ref FeatureAccumulators for a general feature
1762  extraction framework.
1763  */
1764  void minmax(T * minimum, T * maximum) const
1765  {
1766  std::pair<T, T> res(NumericTraits<T>::max(), NumericTraits<T>::min());
1767  detail::reduceOverMultiArray(traverser_begin(), shape(),
1768  res,
1769  detail::MinmaxReduceFunctor(),
1770  MetaInt<actual_dimension-1>());
1771  *minimum = res.first;
1772  *maximum = res.second;
1773  }
1774 
1775  /** Compute the mean and variance of the values in this array.
1776  See \ref FeatureAccumulators for a general feature
1777  extraction framework.
1778  */
1779  template <class U>
1780  void meanVariance(U * mean, U * variance) const
1781  {
1782  typedef typename NumericTraits<U>::RealPromote R;
1783  R zero = R();
1784  triple<double, R, R> res(0.0, zero, zero);
1785  detail::reduceOverMultiArray(traverser_begin(), shape(),
1786  res,
1787  detail::MeanVarianceReduceFunctor(),
1788  MetaInt<actual_dimension-1>());
1789  *mean = res.second;
1790  *variance = res.third / res.first;
1791  }
1792 
1793  /** Compute the sum of the array elements.
1794 
1795  You must provide the type of the result by an explicit template parameter:
1796  \code
1797  MultiArray<2, UInt8> A(width, height);
1798 
1799  double sum = A.sum<double>();
1800  \endcode
1801  */
1802  template <class U>
1803  U sum() const
1804  {
1805  U res = NumericTraits<U>::zero();
1806  detail::reduceOverMultiArray(traverser_begin(), shape(),
1807  res,
1808  detail::SumReduceFunctor(),
1809  MetaInt<actual_dimension-1>());
1810  return res;
1811  }
1812 
1813  /** Compute the sum of the array elements over selected axes.
1814 
1815  \arg sums must have the same shape as this array, except for the
1816  axes along which the sum is to be accumulated. These axes must be
1817  singletons. Note that you must include <tt>multi_pointoperators.hxx</tt>
1818  for this function to work.
1819 
1820  <b>Usage:</b>
1821  \code
1822  #include <vigra/multi_array.hxx>
1823  #include <vigra/multi_pointoperators.hxx>
1824 
1825  MultiArray<2, double> A(Shape2(rows, cols));
1826  ... // fill A
1827 
1828  // make the first axis a singleton to sum over the first index
1829  MultiArray<2, double> rowSums(Shape2(1, cols));
1830  A.sum(rowSums);
1831 
1832  // this is equivalent to
1833  transformMultiArray(srcMultiArrayRange(A),
1834  destMultiArrayRange(rowSums),
1835  FindSum<double>());
1836  \endcode
1837  */
1838  template <class U, class S>
1839  void sum(MultiArrayView<N, U, S> sums) const
1840  {
1841  transformMultiArray(srcMultiArrayRange(*this),
1842  destMultiArrayRange(sums),
1843  FindSum<U>());
1844  }
1845 
1846  /** Compute the product of the array elements.
1847 
1848  You must provide the type of the result by an explicit template parameter:
1849  \code
1850  MultiArray<2, UInt8> A(width, height);
1851 
1852  double prod = A.product<double>();
1853  \endcode
1854  */
1855  template <class U>
1856  U product() const
1857  {
1858  U res = NumericTraits<U>::one();
1859  detail::reduceOverMultiArray(traverser_begin(), shape(),
1860  res,
1861  detail::ProdReduceFunctor(),
1862  MetaInt<actual_dimension-1>());
1863  return res;
1864  }
1865 
1866  /** Compute the squared Euclidean norm of the array (sum of squares of the array elements).
1867  */
1868  typename NormTraits<MultiArrayView>::SquaredNormType
1869  squaredNorm() const
1870  {
1871  typedef typename NormTraits<MultiArrayView>::SquaredNormType SquaredNormType;
1872  SquaredNormType res = NumericTraits<SquaredNormType>::zero();
1873  detail::reduceOverMultiArray(traverser_begin(), shape(),
1874  res,
1875  detail::SquaredL2NormReduceFunctor(),
1876  MetaInt<actual_dimension-1>());
1877  return res;
1878  }
1879 
1880  /** Compute various norms of the array.
1881  The norm is determined by parameter \a type:
1882 
1883  <ul>
1884  <li> type == 0: maximum norm (L-infinity): maximum of absolute values of the array elements
1885  <li> type == 1: Manhattan norm (L1): sum of absolute values of the array elements
1886  <li> type == 2: Euclidean norm (L2): square root of <tt>squaredNorm()</tt> when \a useSquaredNorm is <tt>true</tt>,<br>
1887  or direct algorithm that avoids underflow/overflow otherwise.
1888  </ul>
1889 
1890  Parameter \a useSquaredNorm has no effect when \a type != 2. Defaults: compute L2 norm as square root of
1891  <tt>squaredNorm()</tt>.
1892  */
1893  typename NormTraits<MultiArrayView>::NormType
1894  norm(int type = 2, bool useSquaredNorm = true) const;
1895 
1896  /** return the pointer to the image data
1897  */
1898  pointer data () const
1899  {
1900  return m_ptr;
1901  }
1902 
1903  pointer & unsafePtr()
1904  {
1905  return m_ptr;
1906  }
1907 
1908  /**
1909  * returns true iff this view refers to valid data,
1910  * i.e. data() is not a NULL pointer. (this is false after
1911  * default construction.)
1912  */
1913  bool hasData () const
1914  {
1915  return m_ptr != 0;
1916  }
1917 
1918  /** returns a scan-order iterator pointing
1919  to the first array element.
1920  */
1921  iterator begin()
1922  {
1923  return iterator(*this);
1924  }
1925 
1926  /** returns a const scan-order iterator pointing
1927  to the first array element.
1928  */
1929  const_iterator begin() const
1930  {
1931  return const_iterator(*this);
1932  }
1933 
1934  /** returns a scan-order iterator pointing
1935  beyond the last array element.
1936  */
1937  iterator end()
1938  {
1939  return begin().getEndIterator();
1940  }
1941 
1942  /** returns a const scan-order iterator pointing
1943  beyond the last array element.
1944  */
1945  const_iterator end() const
1946  {
1947  return begin().getEndIterator();
1948  }
1949 
1950  /** returns the N-dimensional MultiIterator pointing
1951  to the first element in every dimension.
1952  */
1953  traverser traverser_begin ()
1954  {
1955  traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
1956  return ret;
1957  }
1958 
1959  /** returns the N-dimensional MultiIterator pointing
1960  to the const first element in every dimension.
1961  */
1962  const_traverser traverser_begin () const
1963  {
1964  const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
1965  return ret;
1966  }
1967 
1968  /** returns the N-dimensional MultiIterator pointing
1969  beyond the last element in dimension N, and to the
1970  first element in every other dimension.
1971  */
1972  traverser traverser_end ()
1973  {
1974  traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
1975  ret += m_shape [actual_dimension-1];
1976  return ret;
1977  }
1978 
1979  /** returns the N-dimensional const MultiIterator pointing
1980  beyond the last element in dimension N, and to the
1981  first element in every other dimension.
1982  */
1983  const_traverser traverser_end () const
1984  {
1985  const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
1986  ret += m_shape [actual_dimension-1];
1987  return ret;
1988  }
1989 
1990  view_type view () const
1991  {
1992  return *this;
1993  }
1994 };
1995 
1996 template <unsigned int N, class T, class StrideTag>
1997 class MultiArrayView<N, Multiband<T>, StrideTag>
1998 : public MultiArrayView<N, T, StrideTag>
1999 {
2000  public:
2001  MultiArrayView(MultiArrayView<N, T, StrideTag> const & v)
2002  : MultiArrayView<N, T, StrideTag>(v)
2003  {}
2004 };
2005 
2006 
2007 template <unsigned int N, class T, class Stride1>
2008 template <class Stride2>
2009 void
2010 MultiArrayView <N, T, Stride1>::assignImpl(MultiArrayView<N, T, Stride2> const & rhs)
2011 {
2012  if(m_ptr == 0)
2013  {
2014  vigra_precondition(rhs.checkInnerStride(Stride1()),
2015  "MultiArrayView<..., UnstridedArrayTag>::operator=(MultiArrayView const &): cannot create unstrided view from strided array.");
2016 
2017  m_shape = rhs.shape();
2018  m_stride = rhs.stride();
2019  m_ptr = rhs.data();
2020  }
2021  else
2022  {
2023  vigra_precondition(this->shape() == rhs.shape(),
2024  "MultiArrayView::operator=(MultiArrayView const &): shape mismatch.");
2025  this->copyImpl(rhs);
2026  }
2027 }
2028 
2029 template <unsigned int N, class T, class StrideTag>
2030 template <class CN>
2031 bool
2032 MultiArrayView <N, T, StrideTag>::arraysOverlap(const MultiArrayView <N, T, CN>& rhs) const
2033 {
2034  vigra_precondition (shape () == rhs.shape (),
2035  "MultiArrayView::arraysOverlap(): shape mismatch.");
2036  const_pointer first_element = this->m_ptr,
2037  last_element = first_element + dot(this->m_shape - difference_type(1), this->m_stride);
2038  typename MultiArrayView <N, T, CN>::const_pointer
2039  rhs_first_element = rhs.data(),
2040  rhs_last_element = rhs_first_element + dot(rhs.shape() - difference_type(1), rhs.stride());
2041  return !(last_element < rhs_first_element || rhs_last_element < first_element);
2042 }
2043 
2044 template <unsigned int N, class T, class StrideTag>
2045 template <class U, class CN>
2046 void
2047 MultiArrayView <N, T, StrideTag>::copyImpl(const MultiArrayView <N, U, CN>& rhs)
2048 {
2049  if(!arraysOverlap(rhs))
2050  {
2051  // no overlap -- can copy directly
2052  detail::copyMultiArrayData(rhs.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>());
2053  }
2054  else
2055  {
2056  // overlap: we got different views to the same data -- copy to intermediate memory in order to avoid
2057  // overwriting elements that are still needed on the rhs.
2058  MultiArray<N, T> tmp(rhs);
2059  detail::copyMultiArrayData(tmp.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>());
2060  }
2061 }
2062 
2063 #define VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(name, op) \
2064 template <unsigned int N, class T, class StrideTag> \
2065 template<class U, class C1> \
2066 MultiArrayView<N, T, StrideTag> & \
2067 MultiArrayView <N, T, StrideTag>::operator op(MultiArrayView<N, U, C1> const & rhs) \
2068 { \
2069  vigra_precondition(this->shape() == rhs.shape(), "MultiArrayView::operator" #op "() size mismatch."); \
2070  if(!arraysOverlap(rhs)) \
2071  { \
2072  detail::name##MultiArrayData(rhs.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>()); \
2073  } \
2074  else \
2075  { \
2076  MultiArray<N, T> tmp(rhs); \
2077  detail::name##MultiArrayData(tmp.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>()); \
2078  } \
2079  return *this; \
2080 }
2081 
2082 VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyAdd, +=)
2083 VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copySub, -=)
2084 VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyMul, *=)
2085 VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyDiv, /=)
2086 
2087 #undef VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT
2088 
2089 template <unsigned int N, class T, class StrideTag>
2090 template <class U, class CN>
2091 void
2092 MultiArrayView <N, T, StrideTag>::swapDataImpl(MultiArrayView <N, U, CN> rhs)
2093 {
2094  vigra_precondition (shape () == rhs.shape (),
2095  "MultiArrayView::swapData(): shape mismatch.");
2096 
2097  // check for overlap of this and rhs
2098  const_pointer first_element = this->m_ptr,
2099  last_element = first_element + dot(this->m_shape - difference_type(1), this->m_stride);
2100  typename MultiArrayView <N, U, CN>::const_pointer
2101  rhs_first_element = rhs.data(),
2102  rhs_last_element = rhs_first_element + dot(rhs.shape() - difference_type(1), rhs.stride());
2103  if(last_element < rhs_first_element || rhs_last_element < first_element)
2104  {
2105  // no overlap -- can swap directly
2106  detail::swapDataImpl(traverser_begin(), shape(), rhs.traverser_begin(), MetaInt<actual_dimension-1>());
2107  }
2108  else
2109  {
2110  // overlap: we got different views to the same data -- copy to intermediate memory in order to avoid
2111  // overwriting elements that are still needed.
2112  MultiArray<N, T> tmp(*this);
2113  copy(rhs);
2114  rhs.copy(tmp);
2115  }
2116 }
2117 
2118 template <unsigned int N, class T, class StrideTag>
2119 MultiArrayView <N, T, StridedArrayTag>
2120 MultiArrayView <N, T, StrideTag>::permuteDimensions (const difference_type &s) const
2121 {
2122  difference_type shape, stride, check((typename difference_type::value_type)0);
2123  for (unsigned int i = 0; i < actual_dimension; ++i)
2124  {
2125  shape[i] = m_shape[s[i]];
2126  stride[i] = m_stride[s[i]];
2127  ++check[s[i]];
2128  }
2129  vigra_precondition(check == difference_type(1),
2130  "MultiArrayView::transpose(): every dimension must occur exactly once.");
2131  return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr);
2132 }
2133 
2134 template <unsigned int N, class T, class StrideTag>
2135 typename MultiArrayView <N, T, StrideTag>::difference_type
2137 {
2138  difference_type permutation;
2139  for(int k=0; k<(int)N; ++k)
2140  permutation[k] = k;
2141  for(int k=0; k<(int)N-1; ++k)
2142  {
2143  int smallest = k;
2144  for(int j=k+1; j<(int)N; ++j)
2145  {
2146  if(stride[j] < stride[smallest])
2147  smallest = j;
2148  }
2149  if(smallest != k)
2150  {
2151  std::swap(stride[k], stride[smallest]);
2152  std::swap(permutation[k], permutation[smallest]);
2153  }
2154  }
2155  difference_type ordering;
2156  for(unsigned int k=0; k<N; ++k)
2157  ordering[permutation[k]] = k;
2158  return ordering;
2159 }
2160 
2161 template <unsigned int N, class T, class StrideTag>
2164 {
2165  difference_type ordering(strideOrdering(m_stride)), permutation;
2166  for(MultiArrayIndex k=0; k<N; ++k)
2167  permutation[ordering[k]] = k;
2168  return permuteDimensions(permutation);
2169 }
2170 
2171 template <unsigned int N, class T, class StrideTag>
2174 {
2175  difference_type ordering(strideOrdering(m_stride)), permutation;
2176  for(MultiArrayIndex k=0; k<N; ++k)
2177  permutation[N-1-ordering[k]] = k;
2178  return permuteDimensions(permutation);
2179 }
2180 
2181 template <unsigned int N, class T, class StrideTag>
2182 template <int M, class Index>
2183 MultiArrayView <N-M, T, StrideTag>
2185 {
2187  stride.init (m_stride.begin () + N-M, m_stride.end ());
2188  pointer ptr = m_ptr + dot (d, stride);
2189  static const int NNew = (N-M == 0) ? 1 : N-M;
2190  TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride;
2191  if (N-M == 0)
2192  {
2193  inner_shape [0] = 1;
2194  inner_stride [0] = 1;
2195  }
2196  else
2197  {
2198  inner_shape.init (m_shape.begin (), m_shape.end () - M);
2199  inner_stride.init (m_stride.begin (), m_stride.end () - M);
2200  }
2201  return MultiArrayView <N-M, T, StrideTag> (inner_shape, inner_stride, ptr);
2202 }
2203 
2204 template <unsigned int N, class T, class StrideTag>
2205 template <int M, class Index>
2206 MultiArrayView <N - M, T, StridedArrayTag>
2208 {
2210  stride.init (m_stride.begin (), m_stride.end () - N + M);
2211  pointer ptr = m_ptr + dot (d, stride);
2212  static const int NNew = (N-M == 0) ? 1 : N-M;
2213  TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride;
2214  if (N-M == 0)
2215  {
2216  outer_shape [0] = 1;
2217  outer_stride [0] = 1;
2218  }
2219  else
2220  {
2221  outer_shape.init (m_shape.begin () + M, m_shape.end ());
2222  outer_stride.init (m_stride.begin () + M, m_stride.end ());
2223  }
2224  return MultiArrayView <N-M, T, StridedArrayTag>
2225  (outer_shape, outer_stride, ptr);
2226 }
2227 
2228 template <unsigned int N, class T, class StrideTag>
2229 template <unsigned int M>
2230 MultiArrayView <N-1, T, typename detail::MaybeStrided<StrideTag, M>::type >
2232 {
2233  static const int NNew = (N-1 == 0) ? 1 : N-1;
2235  // the remaining dimensions are 0..n-1,n+1..N-1
2236  if (N-1 == 0)
2237  {
2238  shape[0] = 1;
2239  stride[0] = 1;
2240  }
2241  else
2242  {
2243  std::copy (m_shape.begin (), m_shape.begin () + M, shape.begin ());
2244  std::copy (m_shape.begin () + M+1, m_shape.end (),
2245  shape.begin () + M);
2246  std::copy (m_stride.begin (), m_stride.begin () + M, stride.begin ());
2247  std::copy (m_stride.begin () + M+1, m_stride.end (),
2248  stride.begin () + M);
2249  }
2250  return MultiArrayView <N-1, T, typename detail::MaybeStrided<StrideTag, M>::type>
2251  (shape, stride, m_ptr + d * m_stride[M]);
2252 }
2253 
2254 template <unsigned int N, class T, class StrideTag>
2255 MultiArrayView <N - 1, T, StrideTag>
2257 {
2258  static const int NNew = (N-1 == 0) ? 1 : N-1;
2259  TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride;
2260  if (N-1 == 0)
2261  {
2262  inner_shape [0] = 1;
2263  inner_stride [0] = 1;
2264  }
2265  else
2266  {
2267  inner_shape.init (m_shape.begin (), m_shape.end () - 1);
2268  inner_stride.init (m_stride.begin (), m_stride.end () - 1);
2269  }
2270  return MultiArrayView <N-1, T, StrideTag> (inner_shape, inner_stride,
2271  m_ptr + d * m_stride [N-1]);
2272 }
2273 
2274 template <unsigned int N, class T, class StrideTag>
2275 MultiArrayView <N - 1, T, StridedArrayTag>
2277 {
2278  static const int NNew = (N-1 == 0) ? 1 : N-1;
2279  TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride;
2280  if (N-1 == 0)
2281  {
2282  outer_shape [0] = 1;
2283  outer_stride [0] = 1;
2284  }
2285  else
2286  {
2287  outer_shape.init (m_shape.begin () + 1, m_shape.end ());
2288  outer_stride.init (m_stride.begin () + 1, m_stride.end ());
2289  }
2290  return MultiArrayView <N-1, T, StridedArrayTag>
2291  (outer_shape, outer_stride, m_ptr + d * m_stride [0]);
2292 }
2293 
2294 template <unsigned int N, class T, class StrideTag>
2295 MultiArrayView <N - 1, T, StridedArrayTag>
2297 {
2298  vigra_precondition (
2299  n < static_cast <int> (N),
2300  "MultiArrayView <N, T, StrideTag>::bindAt(): dimension out of range.");
2301  static const int NNew = (N-1 == 0) ? 1 : N-1;
2303  // the remaining dimensions are 0..n-1,n+1..N-1
2304  if (N-1 == 0)
2305  {
2306  shape [0] = 1;
2307  stride [0] = 1;
2308  }
2309  else
2310  {
2311  std::copy (m_shape.begin (), m_shape.begin () + n, shape.begin ());
2312  std::copy (m_shape.begin () + n+1, m_shape.end (),
2313  shape.begin () + n);
2314  std::copy (m_stride.begin (), m_stride.begin () + n, stride.begin ());
2315  std::copy (m_stride.begin () + n+1, m_stride.end (),
2316  stride.begin () + n);
2317  }
2318  return MultiArrayView <N-1, T, StridedArrayTag>
2319  (shape, stride, m_ptr + d * m_stride[n]);
2320 }
2321 
2322 
2323 template <unsigned int N, class T, class StrideTag>
2326 {
2327  vigra_precondition(0 <= d && d <= static_cast <difference_type_1> (N),
2328  "MultiArrayView<N, ...>::expandElements(d): 0 <= 'd' <= N required.");
2329 
2330  int elementSize = ExpandElementResult<T>::size;
2331  typename MultiArrayShape<N+1>::type newShape, newStrides;
2332  for(int k=0; k<d; ++k)
2333  {
2334  newShape[k] = m_shape[k];
2335  newStrides[k] = m_stride[k]*elementSize;
2336  }
2337 
2338  newShape[d] = elementSize;
2339  newStrides[d] = 1;
2340 
2341  for(unsigned k=d; k<N; ++k)
2342  {
2343  newShape[k+1] = m_shape[k];
2344  newStrides[k+1] = m_stride[k]*elementSize;
2345  }
2346 
2347  typedef typename ExpandElementResult<T>::type U;
2349  newShape, newStrides, reinterpret_cast<U*>(m_ptr));
2350 }
2351 
2352 template <unsigned int N, class T, class StrideTag>
2355 {
2356  vigra_precondition (
2357  0 <= i && i <= static_cast <difference_type_1> (N),
2358  "MultiArrayView <N, T, StrideTag>::insertSingletonDimension(): index out of range.");
2360  std::copy (m_shape.begin (), m_shape.begin () + i, shape.begin ());
2361  std::copy (m_shape.begin () + i, m_shape.end (), shape.begin () + i + 1);
2362  std::copy (m_stride.begin (), m_stride.begin () + i, stride.begin ());
2363  std::copy (m_stride.begin () + i, m_stride.end (), stride.begin () + i + 1);
2364  shape[i] = 1;
2365  stride[i] = 1;
2366 
2368 }
2369 
2370 template <unsigned int N, class T, class StrideTag>
2371 typename NormTraits<MultiArrayView <N, T, StrideTag> >::NormType
2372 MultiArrayView <N, T, StrideTag>::norm(int type, bool useSquaredNorm) const
2373 {
2374  typedef typename NormTraits<MultiArrayView>::NormType NormType;
2375 
2376  switch(type)
2377  {
2378  case 0:
2379  {
2380  NormType res = NumericTraits<NormType>::zero();
2381  detail::reduceOverMultiArray(traverser_begin(), shape(),
2382  res,
2383  detail::MaxNormReduceFunctor(),
2384  MetaInt<actual_dimension-1>());
2385  return res;
2386  }
2387  case 1:
2388  {
2389  NormType res = NumericTraits<NormType>::zero();
2390  detail::reduceOverMultiArray(traverser_begin(), shape(),
2391  res,
2392  detail::L1NormReduceFunctor(),
2393  MetaInt<actual_dimension-1>());
2394  return res;
2395  }
2396  case 2:
2397  {
2398  if(useSquaredNorm)
2399  {
2400  return sqrt((NormType)squaredNorm());
2401  }
2402  else
2403  {
2404  NormType normMax = NumericTraits<NormType>::zero();
2405  detail::reduceOverMultiArray(traverser_begin(), shape(),
2406  normMax,
2407  detail::MaxNormReduceFunctor(),
2408  MetaInt<actual_dimension-1>());
2409  if(normMax == NumericTraits<NormType>::zero())
2410  return normMax;
2411  NormType res = NumericTraits<NormType>::zero();
2412  detail::reduceOverMultiArray(traverser_begin(), shape(),
2413  res,
2414  detail::WeightedL2NormReduceFunctor<NormType>(1.0/normMax),
2415  MetaInt<actual_dimension-1>());
2416  return sqrt(res)*normMax;
2417  }
2418  }
2419  default:
2420  vigra_precondition(false, "MultiArrayView::norm(): Unknown norm type.");
2421  return NumericTraits<NormType>::zero(); // unreachable
2422  }
2423 }
2424 
2425 
2426 /********************************************************/
2427 /* */
2428 /* norm */
2429 /* */
2430 /********************************************************/
2431 
2432 template <unsigned int N, class T, class StrideTag>
2433 inline typename NormTraits<MultiArrayView <N, T, StrideTag> >::SquaredNormType
2435 {
2436  return a.squaredNorm();
2437 }
2438 
2439 template <unsigned int N, class T, class StrideTag>
2440 inline typename NormTraits<MultiArrayView <N, T, StrideTag> >::NormType
2441 norm(MultiArrayView <N, T, StrideTag> const & a)
2442 {
2443  return a.norm();
2444 }
2445 
2446 /********************************************************/
2447 /* */
2448 /* MultiArray */
2449 /* */
2450 /********************************************************/
2451 
2452 /** \brief Main <TT>MultiArray</TT> class containing the memory
2453  management.
2454 
2455 This class inherits the interface of MultiArrayView, and implements
2456 the memory ownership.
2457 MultiArray's are always unstrided, striding them creates a MultiArrayView.
2458 
2459 
2460 The template parameters are as follows
2461 \code
2462  N: the array dimension
2463 
2464  T: the type of the array elements
2465 
2466  A: the allocator used for internal storage management
2467  (default: std::allocator<T>)
2468 \endcode
2469 
2470 <b>\#include</b> <vigra/multi_array.hxx> <br/>
2471 Namespace: vigra
2472 */
2473 template <unsigned int N, class T, class A /* default already declared above */>
2475 : public MultiArrayView <N, typename vigra::detail::ResolveMultiband<T>::type,
2476  typename vigra::detail::ResolveMultiband<T>::Stride>
2477 {
2478  public:
2480 
2481  /** the view type associated with this array.
2482  */
2485 
2486  using view_type::actual_dimension;
2487 
2488  /** the allocator type used to allocate the memory
2489  */
2490  typedef A allocator_type;
2491 
2492  /** the matrix type associated with this array.
2493  */
2495 
2496  /** the array's value type
2497  */
2499 
2500  /** pointer type
2501  */
2502  typedef typename view_type::pointer pointer;
2503 
2504  /** const pointer type
2505  */
2507 
2508  /** reference type (result of operator[])
2509  */
2511 
2512  /** const reference type (result of operator[] const)
2513  */
2515 
2516  /** size type
2517  */
2519 
2520  /** difference type (used for multi-dimensional offsets and indices)
2521  */
2523 
2524  /** difference and index type for a single dimension
2525  */
2527 
2528  /** traverser type
2529  */
2531 
2532  /** traverser type to const data
2533  */
2535 
2536  // /** sequential (random access) iterator type
2537  // */
2538  // typedef typename vigra::detail::MultiIteratorChooser<actual_stride>::template Iterator<N, value_type, reference, pointer>::type
2539  // iterator;
2540 
2541  // /** sequential (random access) const iterator type
2542  // */
2543  // typedef typename vigra::detail::MultiIteratorChooser<actual_stride>::template Iterator<N, value_type, const_reference, const_pointer>::type
2544  // const_iterator;
2545 
2546  /** sequential (random access) iterator type
2547  */
2548  typedef typename view_type::iterator iterator;
2549 
2550  /** sequential (random access) const iterator type
2551  */
2553 
2554 protected:
2555 
2556  typedef typename difference_type::value_type diff_zero_t;
2557 
2558  /** the allocator used to allocate the memory
2559  */
2561 
2562  /** allocate memory for s pixels, write its address into the given
2563  pointer and initialize the pixels with init.
2564  */
2565  void allocate (pointer &ptr, difference_type_1 s, const_reference init);
2566 
2567  /** allocate memory for s pixels, write its address into the given
2568  pointer and initialize the linearized pixels to the values of init.
2569  */
2570  template <class U>
2571  void allocate (pointer &ptr, difference_type_1 s, U const * init);
2572 
2573  /** allocate memory, write its address into the given
2574  pointer and initialize it by copying the data from the given MultiArrayView.
2575  */
2576  template <class U, class StrideTag>
2577  void allocate (pointer &ptr, MultiArrayView<N, U, StrideTag> const & init);
2578 
2579  /** deallocate the memory (of length s) starting at the given address.
2580  */
2581  void deallocate (pointer &ptr, difference_type_1 s);
2582 
2583  template <class U, class StrideTag>
2584  void copyOrReshape (const MultiArrayView<N, U, StrideTag> &rhs);
2585 public:
2586  /** default constructor
2587  */
2589  : view_type (difference_type (diff_zero_t(0)),
2590  difference_type (diff_zero_t(0)), 0)
2591  {}
2592 
2593  /** construct with given allocator
2594  */
2595  MultiArray (allocator_type const & alloc)
2596  : view_type(difference_type (diff_zero_t(0)),
2597  difference_type (diff_zero_t(0)), 0),
2598  m_alloc(alloc)
2599  {}
2600 
2601  /** construct with given length
2602 
2603  Use only for 1-dimensional arrays (<tt>N==1</tt>).
2604  */
2605  explicit MultiArray (difference_type_1 length,
2606  allocator_type const & alloc = allocator_type());
2607 
2608 
2609  /** construct with given width and height
2610 
2611  Use only for 2-dimensional arrays (<tt>N==2</tt>).
2612  */
2614  allocator_type const & alloc = allocator_type());
2615 
2616  /** construct with given shape
2617  */
2618  explicit MultiArray (const difference_type &shape,
2619  allocator_type const & alloc = allocator_type());
2620 
2621  /** construct from shape with an initial value
2622  */
2623  MultiArray (const difference_type &shape, const_reference init,
2624  allocator_type const & alloc = allocator_type());
2625 
2626  /** construct from shape and initialize with a linear sequence in scan order
2627  (i.e. first pixel gets value 0, second on gets value 1 and so on).
2628  */
2630  allocator_type const & alloc = allocator_type());
2631 
2632  /** construct from shape and copy values from the given array
2633  */
2634  MultiArray (const difference_type &shape, const_pointer init,
2635  allocator_type const & alloc = allocator_type());
2636 
2637  /** copy constructor
2638  */
2639  MultiArray (const MultiArray &rhs)
2640  : view_type(rhs.m_shape, rhs.m_stride, 0),
2641  m_alloc (rhs.m_alloc)
2642  {
2643  allocate (this->m_ptr, this->elementCount (), rhs.data ());
2644  }
2645 
2646  /** constructor from an array expression
2647  */
2648  template<class Expression>
2649  MultiArray (multi_math::MultiMathOperand<Expression> const & rhs,
2650  allocator_type const & alloc = allocator_type())
2651  : view_type(difference_type (diff_zero_t(0)),
2652  difference_type (diff_zero_t(0)), 0),
2653  m_alloc (alloc)
2654  {
2655  multi_math::math_detail::assignOrResize(*this, rhs);
2656  }
2657 
2658  /** construct by copying from a MultiArrayView
2659  */
2660  template <class U, class StrideTag>
2662  allocator_type const & alloc = allocator_type());
2663 
2664  /** assignment.<br>
2665  If the size of \a rhs is the same as the left-hand side arrays's old size, only
2666  the data are copied. Otherwise, new storage is allocated, which invalidates all
2667  objects (array views, iterators) depending on the lhs array.
2668  */
2670  {
2671  if (this != &rhs)
2672  this->copyOrReshape(rhs);
2673  return *this;
2674  }
2675 
2676  /** assignment from arbitrary MultiArrayView.<br>
2677  If the size of \a rhs is the same as the left-hand side arrays's old size, only
2678  the data are copied. Otherwise, new storage is allocated, which invalidates all
2679  objects (array views, iterators) depending on the lhs array.
2680  */
2681  template <class U, class StrideTag>
2683  {
2684  this->copyOrReshape(rhs);
2685  return *this;
2686  }
2687 
2688  /** assignment from scalar.<br>
2689  Equivalent to MultiArray::init(v).
2690  */
2692  {
2693  return this->init(v);
2694  }
2695 
2696  /** Add-assignment from arbitrary MultiArrayView. Fails with
2697  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2698  If the left array has no data (hasData() is false), this function is
2699  equivalent to a normal assignment (i.e. an empty
2700  array is interpreted as a zero-array of appropriate size).
2701  */
2702  template <class U, class StrideTag>
2704  {
2705  if(this->hasData())
2706  view_type::operator+=(rhs);
2707  else
2708  *this = rhs;
2709  return *this;
2710  }
2711 
2712  /** Subtract-assignment from arbitrary MultiArrayView. Fails with
2713  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2714  If the left array has no data (hasData() is false), this function is
2715  equivalent to an assignment of the negated rhs (i.e. an empty
2716  array is interpreted as a zero-array of appropriate size).
2717  */
2718  template <class U, class StrideTag>
2720  {
2721  if(!this->hasData())
2722  this->reshape(rhs.shape());
2723  view_type::operator-=(rhs);
2724  return *this;
2725  }
2726 
2727  /** Multiply-assignment from arbitrary MultiArrayView. Fails with
2728  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2729  If the left array has no data (hasData() is false), this function is
2730  equivalent to reshape(rhs.shape()) with zero initialisation (i.e. an empty
2731  array is interpreted as a zero-array of appropriate size).
2732  */
2733  template <class U, class StrideTag>
2735  {
2736  if(this->hasData())
2737  view_type::operator*=(rhs);
2738  else
2739  this->reshape(rhs.shape());
2740  return *this;
2741  }
2742 
2743  /** Divide-assignment from arbitrary MultiArrayView. Fails with
2744  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2745  If the left array has no data (hasData() is false), this function is
2746  equivalent to reshape(rhs.shape()) with zero initialisation (i.e. an empty
2747  array is interpreted as a zero-array of appropriate size).
2748  */
2749  template <class U, class StrideTag>
2751  {
2752  if(this->hasData())
2753  view_type::operator/=(rhs);
2754  else
2755  this->reshape(rhs.shape());
2756  return *this;
2757  }
2758 
2759  /** Add-assignment of a scalar.
2760  */
2761  MultiArray &operator+= (const T &rhs)
2762  {
2763  view_type::operator+=(rhs);
2764  return *this;
2765  }
2766 
2767  /** Subtract-assignment of a scalar.
2768  */
2769  MultiArray &operator-= (const T &rhs)
2770  {
2771  view_type::operator-=(rhs);
2772  return *this;
2773  }
2774 
2775  /** Multiply-assignment of a scalar.
2776  */
2777  MultiArray &operator*= (const T &rhs)
2778  {
2779  view_type::operator*=(rhs);
2780  return *this;
2781  }
2782 
2783  /** Divide-assignment of a scalar.
2784  */
2785  MultiArray &operator/= (const T &rhs)
2786  {
2787  view_type::operator/=(rhs);
2788  return *this;
2789  }
2790  /** Assignment of an array expression. Fails with
2791  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2792  */
2793  template<class Expression>
2794  MultiArray & operator=(multi_math::MultiMathOperand<Expression> const & rhs)
2795  {
2796  multi_math::math_detail::assignOrResize(*this, rhs);
2797  return *this;
2798  }
2799 
2800  /** Add-assignment of an array expression. Fails with
2801  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2802  */
2803  template<class Expression>
2804  MultiArray & operator+=(multi_math::MultiMathOperand<Expression> const & rhs)
2805  {
2806  multi_math::math_detail::plusAssignOrResize(*this, rhs);
2807  return *this;
2808  }
2809 
2810  /** Subtract-assignment of an array expression. Fails with
2811  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2812  */
2813  template<class Expression>
2814  MultiArray & operator-=(multi_math::MultiMathOperand<Expression> const & rhs)
2815  {
2816  multi_math::math_detail::minusAssignOrResize(*this, rhs);
2817  return *this;
2818  }
2819 
2820  /** Multiply-assignment of an array expression. Fails with
2821  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2822  */
2823  template<class Expression>
2824  MultiArray & operator*=(multi_math::MultiMathOperand<Expression> const & rhs)
2825  {
2826  multi_math::math_detail::multiplyAssignOrResize(*this, rhs);
2827  return *this;
2828  }
2829 
2830  /** Divide-assignment of an array expression. Fails with
2831  <tt>PreconditionViolation</tt> exception when the shapes do not match.
2832  */
2833  template<class Expression>
2834  MultiArray & operator/=(multi_math::MultiMathOperand<Expression> const & rhs)
2835  {
2836  multi_math::math_detail::divideAssignOrResize(*this, rhs);
2837  return *this;
2838  }
2839 
2840  /** destructor
2841  */
2843  {
2844  deallocate (this->m_ptr, this->elementCount ());
2845  }
2846 
2847 
2848  /** init elements with a constant
2849  */
2850  template <class U>
2851  MultiArray & init(const U & init)
2852  {
2853  view_type::init(init);
2854  return *this;
2855  }
2856 
2857  /** Allocate new memory with the given shape and initialize with zeros.<br>
2858  <em>Note:</em> this operation invalidates all dependent objects
2859  (array views and iterators)
2860  */
2861  void reshape (const difference_type &shape)
2862  {
2863  reshape (shape, value_type());
2864  }
2865 
2866  /** Allocate new memory with the given shape and initialize it
2867  with the given value.<br>
2868  <em>Note:</em> this operation invalidates all dependent objects
2869  (array views and iterators)
2870  */
2871  void reshape (const difference_type &shape, const_reference init);
2872 
2873  /** Swap the contents with another MultiArray. This is fast,
2874  because no data are copied, but only pointers and shapes swapped.
2875  <em>Note:</em> this operation invalidates all dependent objects
2876  (array views and iterators)
2877  */
2878  void swap (MultiArray & other);
2879 
2880  // /** sequential iterator pointing to the first array element.
2881  // */
2882  // iterator begin ()
2883  // {
2884  // return vigra::detail::MultiIteratorChooser<actual_stride>::template constructIterator<iterator>((view_type *)this);
2885  // }
2886 
2887  // /** sequential iterator pointing beyond the last array element.
2888  // */
2889  // iterator end ()
2890  // {
2891  // return begin() + this->elementCount();
2892  // }
2893 
2894  // /** sequential const iterator pointing to the first array element.
2895  // */
2896  // const_iterator begin () const
2897  // {
2898  // return vigra::detail::MultiIteratorChooser<actual_stride>::template constructIterator<iterator>((view_type const *)this);
2899  // }
2900 
2901  // /** sequential const iterator pointing beyond the last array element.
2902  // */
2903  // const_iterator end () const
2904  // {
2905  // return begin() + this->elementCount();
2906  // }
2907 
2908  /** get the allocator.
2909  */
2910  allocator_type const & allocator () const
2911  {
2912  return m_alloc;
2913  }
2914 
2915  static difference_type defaultStride(difference_type const & shape)
2916  {
2917  return vigra::detail::ResolveMultiband<T>::defaultStride(shape);
2918  }
2919 };
2920 
2921 template <unsigned int N, class T, class A>
2923  allocator_type const & alloc)
2924 : view_type(difference_type(length),
2925  defaultStride(difference_type(length)),
2926  0),
2927  m_alloc(alloc)
2928 {
2929  allocate (this->m_ptr, this->elementCount (), value_type());
2930 }
2931 
2932 template <unsigned int N, class T, class A>
2934  allocator_type const & alloc)
2935 : view_type(difference_type(width, height),
2936  defaultStride(difference_type(width, height)),
2937  0),
2938  m_alloc(alloc)
2939 {
2940  allocate (this->m_ptr, this->elementCount (), value_type());
2941 }
2942 
2943 template <unsigned int N, class T, class A>
2945  allocator_type const & alloc)
2946 : view_type(shape,
2947  defaultStride(shape),
2948  0),
2949  m_alloc(alloc)
2950 {
2951  if (N == 0)
2952  {
2953  this->m_shape [0] = 1;
2954  this->m_stride [0] = 1;
2955  }
2956  allocate (this->m_ptr, this->elementCount (), value_type());
2957 }
2958 
2959 template <unsigned int N, class T, class A>
2961  allocator_type const & alloc)
2962 : view_type(shape,
2963  defaultStride(shape),
2964  0),
2965  m_alloc(alloc)
2966 {
2967  if (N == 0)
2968  {
2969  this->m_shape [0] = 1;
2970  this->m_stride [0] = 1;
2971  }
2972  allocate (this->m_ptr, this->elementCount (), init);
2973 }
2974 
2975 template <unsigned int N, class T, class A>
2977  allocator_type const & alloc)
2978 : view_type(shape,
2979  defaultStride(shape),
2980  0),
2981  m_alloc(alloc)
2982 {
2983  if (N == 0)
2984  {
2985  this->m_shape [0] = 1;
2986  this->m_stride [0] = 1;
2987  }
2988  allocate (this->m_ptr, this->elementCount (), value_type());
2989  switch(init)
2990  {
2991  case LinearSequence:
2992  linearSequence(this->begin(), this->end());
2993  break;
2994  default:
2995  vigra_precondition(false,
2996  "MultiArray(): invalid MultiArrayInitializationTag.");
2997  }
2998 }
2999 
3000 template <unsigned int N, class T, class A>
3002  allocator_type const & alloc)
3003 : view_type(shape,
3004  defaultStride(shape),
3005  0),
3006  m_alloc(alloc)
3007 {
3008  if (N == 0)
3009  {
3010  this->m_shape [0] = 1;
3011  this->m_stride [0] = 1;
3012  }
3013  allocate (this->m_ptr, this->elementCount (), init);
3014 }
3015 
3016 template <unsigned int N, class T, class A>
3017 template <class U, class StrideTag>
3019  allocator_type const & alloc)
3020 : view_type(rhs.shape(),
3021  defaultStride(rhs.shape()),
3022  0),
3023  m_alloc (alloc)
3024 {
3025  allocate (this->m_ptr, rhs);
3026 }
3027 
3028 template <unsigned int N, class T, class A>
3029 template <class U, class StrideTag>
3030 void
3032 {
3033  if (this->shape() == rhs.shape())
3034  this->copy(rhs);
3035  else
3036  {
3037  MultiArray t(rhs);
3038  this->swap(t);
3039  }
3040 }
3041 
3042 template <unsigned int N, class T, class A>
3044  const_reference initial)
3045 {
3046  if (N == 0)
3047  {
3048  return;
3049  }
3050  else if(new_shape == this->shape())
3051  {
3052  this->init(initial);
3053  }
3054  else
3055  {
3056  difference_type new_stride = defaultStride(new_shape);
3057  difference_type_1 new_size = prod(new_shape);
3058  pointer new_ptr = pointer();
3059  allocate (new_ptr, new_size, initial);
3060  deallocate (this->m_ptr, this->elementCount ());
3061  this->m_ptr = new_ptr;
3062  this->m_shape = new_shape;
3063  this->m_stride = new_stride;
3064  }
3065 }
3066 
3067 
3068 template <unsigned int N, class T, class A>
3069 inline void
3071 {
3072  if (this == &other)
3073  return;
3074  this->view_type::swap(other);
3075  std::swap(this->m_alloc, other.m_alloc);
3076 }
3077 
3078 template <unsigned int N, class T, class A>
3081 {
3082  if(s == 0)
3083  {
3084  ptr = 0;
3085  return;
3086  }
3087  ptr = m_alloc.allocate ((typename A::size_type)s);
3088  difference_type_1 i = 0;
3089  try {
3090  for (; i < s; ++i)
3091  m_alloc.construct (ptr + i, init);
3092  }
3093  catch (...) {
3094  for (difference_type_1 j = 0; j < i; ++j)
3095  m_alloc.destroy (ptr + j);
3096  m_alloc.deallocate (ptr, (typename A::size_type)s);
3097  throw;
3098  }
3099 }
3100 
3101 template <unsigned int N, class T, class A>
3102 template <class U>
3104  U const * init)
3105 {
3106  if(s == 0)
3107  {
3108  ptr = 0;
3109  return;
3110  }
3111  ptr = m_alloc.allocate ((typename A::size_type)s);
3112  difference_type_1 i = 0;
3113  try {
3114  for (; i < s; ++i, ++init)
3115  m_alloc.construct (ptr + i, *init);
3116  }
3117  catch (...) {
3118  for (difference_type_1 j = 0; j < i; ++j)
3119  m_alloc.destroy (ptr + j);
3120  m_alloc.deallocate (ptr, (typename A::size_type)s);
3121  throw;
3122  }
3123 }
3124 
3125 template <unsigned int N, class T, class A>
3126 template <class U, class StrideTag>
3128 {
3129  difference_type_1 s = init.elementCount();
3130  if(s == 0)
3131  {
3132  ptr = 0;
3133  return;
3134  }
3135  ptr = m_alloc.allocate ((typename A::size_type)s);
3136  pointer p = ptr;
3137  try {
3138  detail::uninitializedCopyMultiArrayData(init.traverser_begin(), init.shape(),
3139  p, m_alloc, MetaInt<actual_dimension-1>());
3140  }
3141  catch (...) {
3142  for (pointer pp = ptr; pp < p; ++pp)
3143  m_alloc.destroy (pp);
3144  m_alloc.deallocate (ptr, (typename A::size_type)s);
3145  throw;
3146  }
3147 }
3148 
3149 template <unsigned int N, class T, class A>
3151 {
3152  if (ptr == 0)
3153  return;
3154  for (difference_type_1 i = 0; i < s; ++i)
3155  m_alloc.destroy (ptr + i);
3156  m_alloc.deallocate (ptr, (typename A::size_type)s);
3157  ptr = 0;
3158 }
3159 
3160 /********************************************************/
3161 /* */
3162 /* argument object factories */
3163 /* */
3164 /********************************************************/
3165 
3166 template <unsigned int N, class T, class StrideTag>
3167 inline triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3170 srcMultiArrayRange( MultiArrayView<N,T,StrideTag> const & array )
3171 {
3172  return triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3175  ( array.traverser_begin(),
3176  array.shape(),
3178 }
3179 
3180 template <unsigned int N, class T, class StrideTag, class Accessor>
3181 inline triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3182  typename MultiArrayView<N,T,StrideTag>::difference_type,
3183  Accessor >
3184 srcMultiArrayRange( MultiArrayView<N,T,StrideTag> const & array, Accessor a )
3185 {
3186  return triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3187  typename MultiArrayView<N,T,StrideTag>::difference_type,
3188  Accessor >
3189  ( array.traverser_begin(),
3190  array.shape(),
3191  a);
3192 }
3193 
3194 template <unsigned int N, class T, class StrideTag>
3195 inline pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3196  typename AccessorTraits<T>::default_const_accessor >
3197 srcMultiArray( MultiArrayView<N,T,StrideTag> const & array )
3198 {
3199  return pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3200  typename AccessorTraits<T>::default_const_accessor >
3201  ( array.traverser_begin(),
3202  typename AccessorTraits<T>::default_const_accessor() );
3203 }
3204 
3205 template <unsigned int N, class T, class StrideTag, class Accessor>
3206 inline pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3207  Accessor >
3208 srcMultiArray( MultiArrayView<N,T,StrideTag> const & array, Accessor a )
3209 {
3210  return pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3211  Accessor >
3212  ( array.traverser_begin(), a );
3213 }
3214 
3215 template <unsigned int N, class T, class StrideTag>
3216 inline triple<typename MultiArrayView<N,T,StrideTag>::traverser,
3217  typename MultiArrayView<N,T,StrideTag>::difference_type,
3218  typename AccessorTraits<T>::default_accessor >
3219 destMultiArrayRange( MultiArrayView<N,T,StrideTag> & array )
3220 {
3221  return triple<typename MultiArrayView<N,T,StrideTag>::traverser,
3222  typename MultiArrayView<N,T,StrideTag>::difference_type,
3223  typename AccessorTraits<T>::default_accessor >
3224  ( array.traverser_begin(),
3225  array.shape(),
3226  typename AccessorTraits<T>::default_accessor() );
3227 }
3228 
3229 template <unsigned int N, class T, class StrideTag, class Accessor>
3230 inline triple<typename MultiArrayView<N,T,StrideTag>::traverser,
3231  typename MultiArrayView<N,T,StrideTag>::difference_type,
3232  Accessor >
3233 destMultiArrayRange( MultiArrayView<N,T,StrideTag> & array, Accessor a )
3234 {
3235  return triple<typename MultiArrayView<N,T,StrideTag>::traverser,
3236  typename MultiArrayView<N,T,StrideTag>::difference_type,
3237  Accessor >
3238  ( array.traverser_begin(),
3239  array.shape(),
3240  a );
3241 }
3242 
3243 template <unsigned int N, class T, class StrideTag>
3244 inline pair<typename MultiArrayView<N,T,StrideTag>::traverser,
3245  typename AccessorTraits<T>::default_accessor >
3246 destMultiArray( MultiArrayView<N,T,StrideTag> & array )
3247 {
3248  return pair<typename MultiArrayView<N,T,StrideTag>::traverser,
3249  typename AccessorTraits<T>::default_accessor >
3250  ( array.traverser_begin(),
3251  typename AccessorTraits<T>::default_accessor() );
3252 }
3253 
3254 template <unsigned int N, class T, class StrideTag, class Accessor>
3255 inline pair<typename MultiArrayView<N,T,StrideTag>::traverser,
3256  Accessor >
3257 destMultiArray( MultiArrayView<N,T,StrideTag> & array, Accessor a )
3258 {
3259  return pair<typename MultiArrayView<N,T,StrideTag>::traverser,
3260  Accessor >
3261  ( array.traverser_begin(), a );
3262 }
3263 
3264 /********************************************************************/
3265 
3266 template <class PixelType, class Accessor>
3267 inline triple<ConstStridedImageIterator<PixelType>,
3268  ConstStridedImageIterator<PixelType>, Accessor>
3269 srcImageRange(const MultiArrayView<2, PixelType, StridedArrayTag> & img, Accessor a)
3270 {
3271  ConstStridedImageIterator<PixelType>
3272  ul(img.data(), 1, img.stride(0), img.stride(1));
3273  return triple<ConstStridedImageIterator<PixelType>,
3274  ConstStridedImageIterator<PixelType>,
3275  Accessor>(
3276  ul, ul + Size2D(img.shape(0), img.shape(1)), a);
3277 }
3278 
3279 template <class PixelType, class Accessor>
3280 inline pair<ConstStridedImageIterator<PixelType>, Accessor>
3281 srcImage(const MultiArrayView<2, PixelType, StridedArrayTag> & img, Accessor a)
3282 {
3283  ConstStridedImageIterator<PixelType>
3284  ul(img.data(), 1, img.stride(0), img.stride(1));
3285  return pair<ConstStridedImageIterator<PixelType>, Accessor>
3286  (ul, a);
3287 }
3288 
3289 template <class PixelType, class Accessor>
3290 inline triple<StridedImageIterator<PixelType>,
3291  StridedImageIterator<PixelType>, Accessor>
3292 destImageRange(MultiArrayView<2, PixelType, StridedArrayTag> & img, Accessor a)
3293 {
3294  StridedImageIterator<PixelType>
3295  ul(img.data(), 1, img.stride(0), img.stride(1));
3296  return triple<StridedImageIterator<PixelType>,
3297  StridedImageIterator<PixelType>,
3298  Accessor>(
3299  ul, ul + Size2D(img.shape(0), img.shape(1)), a);
3300 }
3301 
3302 template <class PixelType, class Accessor>
3303 inline pair<StridedImageIterator<PixelType>, Accessor>
3304 destImage(MultiArrayView<2, PixelType, StridedArrayTag> & img, Accessor a)
3305 {
3306  StridedImageIterator<PixelType>
3307  ul(img.data(), 1, img.stride(0), img.stride(1));
3308  return pair<StridedImageIterator<PixelType>, Accessor>
3309  (ul, a);
3310 }
3311 
3312 template <class PixelType, class Accessor>
3313 inline pair<StridedImageIterator<PixelType>, Accessor>
3314 maskImage(MultiArrayView<2, PixelType, StridedArrayTag> & img, Accessor a)
3315 {
3316  StridedImageIterator<PixelType>
3317  ul(img.data(), 1, img.stride(0), img.stride(1));
3318  return pair<StridedImageIterator<PixelType>, Accessor>
3319  (ul, a);
3320 }
3321 
3322 // -------------------------------------------------------------------
3323 
3324 template <class PixelType>
3325 inline triple<ConstStridedImageIterator<PixelType>,
3326  ConstStridedImageIterator<PixelType>,
3327  typename AccessorTraits<PixelType>::default_const_accessor>
3328 srcImageRange(MultiArrayView<2, PixelType, StridedArrayTag> const & img)
3329 {
3330  ConstStridedImageIterator<PixelType>
3331  ul(img.data(), 1, img.stride(0), img.stride(1));
3332  typedef typename AccessorTraits<PixelType>::default_const_accessor Accessor;
3333  return triple<ConstStridedImageIterator<PixelType>,
3334  ConstStridedImageIterator<PixelType>,
3335  Accessor>
3336  (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor());
3337 }
3338 
3339 template <class PixelType>
3340 inline triple<ConstImageIterator<PixelType>,
3341  ConstImageIterator<PixelType>,
3342  typename AccessorTraits<PixelType>::default_const_accessor>
3343 srcImageRange(MultiArrayView<2, PixelType, UnstridedArrayTag> const & img)
3344 {
3345  ConstImageIterator<PixelType>
3346  ul(img.data(), img.stride(1));
3347  typedef typename AccessorTraits<PixelType>::default_const_accessor Accessor;
3348  return triple<ConstImageIterator<PixelType>,
3349  ConstImageIterator<PixelType>,
3350  Accessor>
3351  (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor());
3352 }
3353 
3354 template <class PixelType>
3355 inline pair< ConstStridedImageIterator<PixelType>,
3356  typename AccessorTraits<PixelType>::default_const_accessor>
3357 srcImage(MultiArrayView<2, PixelType, StridedArrayTag> const & img)
3358 {
3359  ConstStridedImageIterator<PixelType>
3360  ul(img.data(), 1, img.stride(0), img.stride(1));
3361  typedef typename AccessorTraits<PixelType>::default_const_accessor Accessor;
3362  return pair<ConstStridedImageIterator<PixelType>,
3363  Accessor>
3364  (ul, Accessor());
3365 }
3366 
3367 template <class PixelType>
3368 inline pair< ConstImageIterator<PixelType>,
3369  typename AccessorTraits<PixelType>::default_const_accessor>
3370 srcImage(MultiArrayView<2, PixelType, UnstridedArrayTag> const & img)
3371 {
3372  ConstImageIterator<PixelType>
3373  ul(img.data(), img.stride(1));
3374  typedef typename AccessorTraits<PixelType>::default_const_accessor Accessor;
3375  return pair<ConstImageIterator<PixelType>,
3376  Accessor>
3377  (ul, Accessor());
3378 }
3379 
3380 template <class PixelType>
3381 inline triple< StridedImageIterator<PixelType>,
3382  StridedImageIterator<PixelType>,
3383  typename AccessorTraits<PixelType>::default_accessor>
3384 destImageRange(MultiArrayView<2, PixelType, StridedArrayTag> & img)
3385 {
3386  StridedImageIterator<PixelType>
3387  ul(img.data(), 1, img.stride(0), img.stride(1));
3388  typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3389  return triple<StridedImageIterator<PixelType>,
3390  StridedImageIterator<PixelType>,
3391  Accessor>
3392  (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor());
3393 }
3394 
3395 template <class PixelType>
3396 inline triple< ImageIterator<PixelType>,
3397  ImageIterator<PixelType>,
3398  typename AccessorTraits<PixelType>::default_accessor>
3399 destImageRange(MultiArrayView<2, PixelType, UnstridedArrayTag> & img)
3400 {
3401  ImageIterator<PixelType>
3402  ul(img.data(), img.stride(1));
3403  typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3404  return triple<ImageIterator<PixelType>,
3405  ImageIterator<PixelType>,
3406  Accessor>
3407  (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor());
3408 }
3409 
3410 template <class PixelType>
3411 inline pair< StridedImageIterator<PixelType>,
3412  typename AccessorTraits<PixelType>::default_accessor>
3413 destImage(MultiArrayView<2, PixelType, StridedArrayTag> & img)
3414 {
3415  StridedImageIterator<PixelType>
3416  ul(img.data(), 1, img.stride(0), img.stride(1));
3417  typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3418  return pair<StridedImageIterator<PixelType>, Accessor>
3419  (ul, Accessor());
3420 }
3421 
3422 template <class PixelType>
3423 inline pair< ImageIterator<PixelType>,
3424  typename AccessorTraits<PixelType>::default_accessor>
3425 destImage(MultiArrayView<2, PixelType, UnstridedArrayTag> & img)
3426 {
3427  ImageIterator<PixelType> ul(img.data(), img.stride(1));
3428  typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3429  return pair<ImageIterator<PixelType>, Accessor>(ul, Accessor());
3430 }
3431 
3432 template <class PixelType>
3433 inline pair< ConstStridedImageIterator<PixelType>,
3434  typename AccessorTraits<PixelType>::default_accessor>
3435 maskImage(MultiArrayView<2, PixelType, StridedArrayTag> const & img)
3436 {
3437  ConstStridedImageIterator<PixelType>
3438  ul(img.data(), 1, img.stride(0), img.stride(1));
3439  typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3440  return pair<ConstStridedImageIterator<PixelType>, Accessor>
3441  (ul, Accessor());
3442 }
3443 
3444 template <class PixelType>
3445 inline pair< ConstImageIterator<PixelType>,
3446  typename AccessorTraits<PixelType>::default_accessor>
3447 maskImage(MultiArrayView<2, PixelType, UnstridedArrayTag> const & img)
3448 {
3449  ConstImageIterator<PixelType>
3450  ul(img.data(), img.stride(1));
3451  typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3452  return pair<ConstImageIterator<PixelType>, Accessor>
3453  (ul, Accessor());
3454 }
3455 
3456 /********************************************************/
3457 /* */
3458 /* makeBasicImageView */
3459 /* */
3460 /********************************************************/
3461 
3462 /** \addtogroup MultiArrayToImage Create BasicImageView from MultiArrayViews
3463 
3464  Some convenience functions for wrapping a \ref vigra::MultiArrayView's
3465  data in a \ref vigra::BasicImageView.
3466 */
3467 //@{
3468 /** Create a \ref vigra::BasicImageView from an unstrided 2-dimensional
3469  \ref vigra::MultiArrayView.
3470 
3471  The \ref vigra::BasicImageView will have the same <tt>value_type </tt>
3472  as the original \ref vigra::MultiArrayView.
3473 */
3474 template <class T, class Stride>
3475 BasicImageView <T>
3477 {
3478  vigra_precondition(array.isUnstrided(0),
3479  "makeBasicImageView(array): array must be unstrided along x (i.e. array.isUnstrided(0) == true).");
3480  return BasicImageView <T> (array.data (), array.shape (0),
3481  array.shape (1), array.stride(1));
3482 }
3483 
3484 /** Create a \ref vigra::BasicImageView from a 3-dimensional
3485  \ref vigra::MultiArray.
3486 
3487  This wrapper flattens the two innermost dimensions of the array
3488  into single rows of the resulting image.
3489  The \ref vigra::BasicImageView will have the same <tt>value_type </tt>
3490  as the original \ref vigra::MultiArray.
3491 */
3492 template <class T>
3493 BasicImageView <T>
3495 {
3496  vigra_precondition(array.stride(1) == array.shape(0),
3497  "makeBasicImageView(): cannot join strided dimensions");
3498  return BasicImageView <T> (array.data (),
3499  array.shape (0)*array.shape (1), array.shape (2), array.stride(2));
3500 }
3501 
3502 /** Create a \ref vigra::BasicImageView from a 3-dimensional
3503  \ref vigra::MultiArray.
3504 
3505  This wrapper only works if <tt>T</tt> is a scalar type and the
3506  array's innermost dimension has size 3. It then re-interprets
3507  the data array as a 2-dimensional array with value_type
3508  <tt>RGBValue<T></tt>.
3509 */
3510 template <class T, class Stride>
3511 BasicImageView <RGBValue<T> >
3513 {
3514  vigra_precondition(array.shape (0) == 3,
3515  "makeRGBImageView(): array.shape(0) must be 3.");
3516  vigra_precondition(array.isUnstrided(),
3517  "makeRGBImageView(array): array must be unstrided (i.e. array.isUnstrided() == true).");
3518  return BasicImageView <RGBValue<T> > (
3519  reinterpret_cast <RGBValue <T> *> (array.data ()),
3520  array.shape (1), array.shape (2));
3521 }
3522 
3523 //@}
3524 
3525 } // namespace vigra
3526 
3527 #undef VIGRA_ASSERT_INSIDE
3528 
3529 #endif // VIGRA_MULTI_ARRAY_HXX
MultiArray & operator/=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:2834
MultiArrayView< N, typename vigra::detail::ResolveMultiband< T >::type, typename vigra::detail::ResolveMultiband< T >::Stride > view_type
Definition: multi_array.hxx:2484
const value_type & const_reference
Definition: multi_array.hxx:727
MultiArrayView(const difference_type &shape, const difference_type &stride, const_pointer ptr)
Definition: multi_array.hxx:860
MultiArray & operator=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:2794
void sum(MultiArrayView< N, U, S > sums) const
Definition: multi_array.hxx:1839
MultiArrayView & operator=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:1001
iterator end()
Definition: multi_array.hxx:1937
Sequential iterator for MultiArrayView.
Definition: multi_fwd.hxx:161
MultiArrayView & operator*=(MultiArrayView< N, U, C1 > const &rhs)
MultiArrayView & operator+=(T const &rhs)
Definition: multi_array.hxx:967
MultiArray< N, T > matrix_type
Definition: multi_array.hxx:777
MultiArray< N, T, A > matrix_type
Definition: multi_array.hxx:2494
PromoteTraits< V1, V2 >::Promote dot(RGBValue< V1, RIDX1, GIDX1, BIDX1 > const &r1, RGBValue< V2, RIDX2, GIDX2, BIDX2 > const &r2)
dot product
Definition: rgbvalue.hxx:906
view_type::pointer pointer
Definition: multi_array.hxx:2502
MultiArrayShape< actual_dimension >::type difference_type
Definition: multi_array.hxx:739
MultiArrayView & operator=(value_type const &v)
Definition: multi_array.hxx:936
MultiArray & operator+=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:2804
MultiArray()
Definition: multi_array.hxx:2588
const difference_type & shape() const
Definition: multi_array.hxx:1648
ActualDimension
Definition: multi_array.hxx:715
MultiArrayView< N, T, StrideTag > view_type
Definition: multi_array.hxx:773
void linearSequence(Iterator first, Iterator last, Value start, Value step)
Fill an array with a sequence of numbers.
Definition: algorithm.hxx:208
MultiArrayInitializationTag
Initialize a MultiArray in a standard way.
Definition: multi_fwd.hxx:104
difference_type m_shape
Definition: multi_array.hxx:795
MultiArray(allocator_type const &alloc)
Definition: multi_array.hxx:2595
difference_type_1 width() const
Definition: multi_array.hxx:1670
MultiArray & operator=(value_type const &v)
Definition: multi_array.hxx:2691
A allocator_type
Definition: multi_array.hxx:2490
U product() const
Definition: multi_array.hxx:1856
view_type::iterator iterator
Definition: multi_array.hxx:2548
reference operator[](difference_type_1 d)
Definition: multi_array.hxx:1081
MultiArrayView & operator-=(T const &rhs)
Definition: multi_array.hxx:975
difference_type size_type
Definition: multi_array.hxx:747
MultiArrayView & operator*=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:1031
pointer data() const
Definition: multi_array.hxx:1898
void deallocate(pointer &ptr, difference_type_1 s)
Definition: multi_array.hxx:3150
difference_type_1 elementCount() const
Definition: multi_array.hxx:1630
FFTWComplex< R >::SquaredNormType squaredNorm(const FFTWComplex< R > &a)
squared norm (= squared magnitude)
Definition: fftw3.hxx:1044
MultiArrayView & operator-=(MultiArrayView< N, U, C1 > const &rhs)
iterator begin()
Definition: multi_array.hxx:1921
MultiArrayView & operator/=(T const &rhs)
Definition: multi_array.hxx:991
void reshape(const difference_type &shape)
Definition: multi_array.hxx:2861
view_type::traverser traverser
Definition: multi_array.hxx:2530
reference operator()(difference_type_1 x)
Definition: multi_array.hxx:1121
Initialize array by a linear sequence in scan order.
Definition: multi_fwd.hxx:105
void reset()
Definition: multi_array.hxx:890
BasicImageView< RGBValue< T > > makeRGBImageView(MultiArrayView< 3, T, Stride > const &array)
Definition: multi_array.hxx:3512
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
Find the sum of the pixel values in an image or ROI.
Definition: inspectimage.hxx:1143
MultiArrayView(const difference_type &shape, const_pointer ptr)
Definition: multi_array.hxx:849
const_iterator begin() const
Definition: multi_array.hxx:1929
StridedScanOrderIterator< actual_dimension, T, T &, T * > iterator
Definition: multi_array.hxx:755
vigra::detail::MultiIteratorChooser< StrideTag >::template Traverser< actual_dimension, T, T const &, T const * >::type const_traverser
Definition: multi_array.hxx:769
MultiArrayView & operator/=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:1041
NormTraits< MultiArrayView >::NormType norm(int type=2, bool useSquaredNorm=true) const
Definition: multi_array.hxx:2372
MultiArrayView< N, T, StridedArrayTag > transpose() const
Definition: multi_array.hxx:1567
view_type::difference_type difference_type
Definition: multi_array.hxx:2522
void meanVariance(U *mean, U *variance) const
Definition: multi_array.hxx:1780
MultiArray(multi_math::MultiMathOperand< Expression > const &rhs, allocator_type const &alloc=allocator_type())
Definition: multi_array.hxx:2649
MultiArrayView< N+1, T, StrideTag > insertSingletonDimension(difference_type_1 i) const
Definition: multi_array.hxx:2354
view_type::const_traverser const_traverser
Definition: multi_array.hxx:2534
MultiArrayView< N-M, T, StridedArrayTag > bindInner(const TinyVector< Index, M > &d) const
Definition: multi_array.hxx:2207
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
vigra::detail::MultiIteratorChooser< StrideTag >::template Traverser< actual_dimension, T, T &, T * >::type traverser
Definition: multi_array.hxx:764
difference_type_1 size() const
Definition: multi_array.hxx:1641
void swapData(MultiArrayView< N, T2, C2 > rhs)
Definition: multi_array.hxx:1275
NormTraits< MultiArrayView >::SquaredNormType squaredNorm() const
Definition: multi_array.hxx:1869
Definition: multi_fwd.hxx:63
bool operator==(MultiArrayView< N, U, C1 > const &rhs) const
Definition: multi_array.hxx:1699
view_type::reference reference
Definition: multi_array.hxx:2510
NumericTraits< V >::Promote prod(TinyVectorBase< V, SIZE, D1, D2 > const &l)
product of the vector's elements
Definition: tinyvector.hxx:2097
BasicImageView< T > makeBasicImageView(MultiArrayView< 2, T, Stride > const &array)
Definition: multi_array.hxx:3476
MultiArrayIndex difference_type_1
Definition: multi_array.hxx:751
MultiArrayView< N, Multiband< value_type >, StrideTag > multiband() const
Definition: multi_array.hxx:1483
const difference_type & stride() const
Definition: multi_array.hxx:1684
bool any() const
Definition: multi_array.hxx:1750
bool operator!=(MultiArrayView< N, U, C1 > const &rhs) const
Definition: multi_array.hxx:1710
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements
Definition: tinyvector.hxx:2073
MultiArray & operator*=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:2824
value_type & reference
Definition: multi_array.hxx:723
MultiArrayView & operator-=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:1021
const_reference operator[](difference_type_1 d) const
Definition: multi_array.hxx:1097
difference_type_1 stride(int n) const
Definition: multi_array.hxx:1691
bool isInside(difference_type const &p) const
Definition: multi_array.hxx:1717
difference_type_1 coordinateToScanOrderIndex(const difference_type &d) const
Definition: multi_array.hxx:1114
const_iterator end() const
Definition: multi_array.hxx:1945
MultiArray & init(const U &init)
Definition: multi_array.hxx:2851
MultiArrayView< 1, T, StridedArrayTag > diagonal() const
Definition: multi_array.hxx:1504
MultiArrayView< N-1, T, StridedArrayTag > bindAt(difference_type_1 m, difference_type_1 d) const
Definition: multi_array.hxx:2296
allocator_type m_alloc
Definition: multi_array.hxx:2560
void minmax(T *minimum, T *maximum) const
Definition: multi_array.hxx:1764
MultiArrayView(const MultiArrayView< N, T, Stride > &other)
Definition: multi_array.hxx:838
void copy(const MultiArrayView< N, U, CN > &rhs)
Definition: multi_array.hxx:1226
BasicImage using foreign memory.
Definition: basicimageview.hxx:76
MultiArrayView< N, T, StridedArrayTag > permuteStridesDescending() const
Definition: multi_array.hxx:2173
void copy(const MultiArrayView &rhs)
Definition: multi_array.hxx:1216
difference_type scanOrderIndexToCoordinate(difference_type_1 d) const
Definition: multi_array.hxx:1105
Definition: metaprogramming.hxx:116
allocator_type const & allocator() const
Definition: multi_array.hxx:2910
MultiArrayView< N, typename ExpandElementResult< T >::type, StridedArrayTag > bindElementChannel(difference_type_1 i) const
Definition: multi_array.hxx:1415
view_type::size_type size_type
Definition: multi_array.hxx:2518
MultiArrayView & operator/=(MultiArrayView< N, U, C1 > const &rhs)
difference_type_1 size(difference_type_1 n) const
Definition: multi_array.hxx:1655
view_type::const_pointer const_pointer
Definition: multi_array.hxx:2506
view_type::value_type value_type
Definition: multi_array.hxx:2498
Definition: metaprogramming.hxx:123
const_traverser traverser_begin() const
Definition: multi_array.hxx:1962
Class for fixed size vectors.This class contains an array of size SIZE of the specified VALUETYPE...
Definition: accessor.hxx:940
T value_type
Definition: multi_array.hxx:719
MultiArrayView< N, T, StridedArrayTag > transpose(const difference_type &permutation) const
Definition: multi_array.hxx:1593
Fundamental class template for images.
Definition: basicimage.hxx:475
bool hasData() const
Definition: multi_array.hxx:1913
pointer m_ptr
Definition: multi_array.hxx:804
~MultiArray()
Definition: multi_array.hxx:2842
difference_type_1 height() const
Definition: multi_array.hxx:1677
view_type::difference_type_1 difference_type_1
Definition: multi_array.hxx:2526
MultiArrayView & operator+=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:1011
MultiArrayView & operator=(MultiArrayView< N, U, C1 > const &rhs)
Definition: multi_array.hxx:926
MultiArray(const MultiArray &rhs)
Definition: multi_array.hxx:2639
Encapsulate read access to the values an iterator points to.
Definition: accessor.hxx:269
MultiArrayView(BasicImage< T, ALLOC > const &image)
Definition: multi_array.hxx:874
bool isUnstrided(unsigned int dimension=N-1) const
Definition: multi_array.hxx:1286
Base class for, and view to, vigra::MultiArray.
Definition: multi_array.hxx:704
void transformMultiArray(...)
Transform a multi-dimensional array with a unary function or functor.
MultiArrayView & init(const U &init)
Definition: multi_array.hxx:1206
MultiArray & operator-=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition: multi_array.hxx:2814
void swap(MultiArrayView &other)
Definition: multi_array.hxx:1251
void swapData(MultiArrayView rhs)
Definition: multi_array.hxx:1264
value_type * pointer
Definition: multi_array.hxx:731
traverser traverser_end()
Definition: multi_array.hxx:1972
MultiArrayView subarray(difference_type p, difference_type q) const
Definition: multi_array.hxx:1528
Class for a single RGB value.
Definition: accessor.hxx:938
bool all() const
Definition: multi_array.hxx:1737
MultiArrayView< N-1, T, typename vigra::detail::MaybeStrided< StrideTag, M >::type > bind(difference_type_1 d) const
StridedScanOrderIterator< actual_dimension, T, T const &, T const * > const_iterator
Definition: multi_array.hxx:759
reference operator[](const difference_type &d)
Definition: multi_array.hxx:1049
bool isOutside(difference_type const &p) const
Definition: multi_array.hxx:1726
view_type::const_iterator const_iterator
Definition: multi_array.hxx:2552
MultiArrayView< N+1, typename ExpandElementResult< T >::type, StridedArrayTag > expandElements(difference_type_1 d) const
Definition: multi_array.hxx:2325
MultiArrayView & operator=(MultiArrayView const &rhs)
Definition: multi_array.hxx:907
MultiArrayView & operator*=(T const &rhs)
Definition: multi_array.hxx:983
MultiArrayView< N, T, StridedArrayTag > permuteStridesAscending() const
Definition: multi_array.hxx:2163
difference_type m_stride
Definition: multi_array.hxx:800
void init(Iterator i, Iterator end)
Definition: tinyvector.hxx:708
U sum() const
Definition: multi_array.hxx:1803
const value_type * const_pointer
Definition: multi_array.hxx:735
difference_type_1 shape(difference_type_1 n) const
Definition: multi_array.hxx:1663
traverser traverser_begin()
Definition: multi_array.hxx:1953
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
MultiArrayView< N, T, StridedArrayTag > stridearray(const difference_type &s) const
Definition: multi_array.hxx:1543
MultiArrayView()
Definition: multi_array.hxx:829
MultiArrayView< N-M, T, StrideTag > bindOuter(const TinyVector< Index, M > &d) const
Definition: multi_array.hxx:2184
difference_type key_type
Definition: multi_array.hxx:743
V const & min(TinyVectorBase< V, SIZE, D1, D2 > const &l)
minimum element
Definition: tinyvector.hxx:2161
view_type::const_reference const_reference
Definition: multi_array.hxx:2514
void allocate(pointer &ptr, difference_type_1 s, const_reference init)
Definition: multi_array.hxx:3079
MultiArrayView & operator+=(MultiArrayView< N, U, C1 > const &rhs)
const_traverser traverser_end() const
Definition: multi_array.hxx:1983
difference_type strideOrdering() const
Definition: multi_array.hxx:1617

© 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.11.1 (Fri May 19 2017)