vigra - vigra/multi_array.hxx Source File

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

multi_array.hxx |

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

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