vigra - vigra/navigator.hxx Source File

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

navigator.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 2004 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35
36 #ifndef VIGRA_NAVIGATOR_HXX
37 #define VIGRA_NAVIGATOR_HXX
38
39 #include "multi_shape.hxx"
40
41 namespace vigra {
42
43 /********************************************************/
44 /* */
45 /* MultiArrayNavigator */
46 /* */
47 /********************************************************/
48
49 /** \brief A navigator that provides access to the 1D subranges of an
50 n-dimensional range given by a \ref vigra::MultiIterator and an nD shape.
51
52 Normally, the innermost loop of an iteration extends over the innermost
53 dimension of a given array. Sometimes, however, it is necessary to have
54 some other dimension in the inner loop. For example, instead of iterating over
55 the rows, the inner loop should extend over the columns. The class MultiArrayNavigator
56 encapsulates the necessary functionality. Given an arbitrary dimensional
57 array (represented by a vigra::MultiIterator/shape pair), and the desired
58 inner loop dimension <TT>d</TT>, it moves the encapsulated iterator to all possible
59 starting points of 1D subsets along the given dimension (e.g. all columns). By calling
60 <TT>begin()</TT> and <TT>end()</TT>, one can then obtain an STL-compatible 1-dimensional
61 iterator for the current subset.
62
63 The template parameters specify the embedded iterator type and its dimension.
64
65 <b>Usage:</b>
66
67 <b>\#include</b> <vigra/navigator.hxx>
68
69 Namespace: vigra
70
71 \code
72 typedef vigra::MultiArray<3, int> Array;
73
74 Array a(Array::size_type(X, Y, Z));
75
76 typedef vigra::MultiArrayNavigator<Array::traverser, 3> Navigator;
77
78 for(int d=0; d<3; ++d)
79 {
80 // create Navigator for dimension d
81 Navigator nav(a.traverser_begin(), a.shape(), d);
82
83 // outer loop: move navigator to all starting points
84 // of 1D subsets that run parallel to coordinate axis d
85 for(; nav.hasMore(); ++nav)
86 {
87 // inner loop: linear iteration over current subset
88 // d == {0, 1, 2}: iterate along {x, y, z}-axis respectively
89 Navigator::iterator i = nav.begin(), end = nav.end();
90 for(; i != end; ++i)
91 // do something
92 }
93 }
94 \endcode
95 */
96 template <class MULTI_ITERATOR, unsigned int N>
97 class MultiArrayNavigator
98 #ifndef DOXYGEN // doxygen doesn't understand this inheritance
99 : public MultiArrayNavigator<MULTI_ITERATOR, N-1>
100 #endif
101 {
102 typedef MultiArrayNavigator<MULTI_ITERATOR, N-1> base_type;
103
104 public:
105 enum { level = N-1 };
106
107 /** The required shape type for the given iterator type.
108 */
109 typedef typename MULTI_ITERATOR::multi_difference_type shape_type;
110
111 /** The iterator type for the inner loop (result of begin() and end()).
112 */
113 typedef typename MULTI_ITERATOR::iterator iterator;
114
115 /** Construct navigator for multi-dimensional iterator <TT>i</TT>, array shape <TT>shape</TT>
116 and inner loop dimension <TT>inner_dimension</TT>.
117 */
118 MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & shape, unsigned int inner_dimension)
119 : base_type(i, shape, inner_dimension)
120 {}
121
122 MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & start, shape_type const & stop,
123 unsigned int inner_dimension)
124 : base_type(i, start, stop, inner_dimension)
125 {}
126
127 /** Advance to next starting location.
128 */
129 void operator++()
130 {
131 base_type::operator++();
132 if(this->point_[level-1] == this->stop_[level-1])
133 {
134 base_type::reset();
135 ++this->point_[level];
136 ++this->i_.template dim<level>();
137 }
138 }
139
140 /** Advance to next starting location.
141 */
142 void operator++(int)
143 {
144 ++*this;
145 }
146
147 /** true if there are more elements.
148 */
149 bool hasMore() const
150 {
151 return this->point_[level] < this->stop_[level];
152 }
153
154 /** true if iterator is exhausted.
155 */
156 bool atEnd() const
157 {
158 return this->point_[level] >= this->stop_[level];
159 }
160
161 protected:
162 void reset()
163 {
164 this->point_[level] = this->start_[level];
165 this->i_.template dim<level>() -= (this->stop_[level] - this->start_[level]);
166 }
167 };
168
169 template <class MULTI_ITERATOR>
170 class MultiArrayNavigator<MULTI_ITERATOR, 1>
171 {
172 public:
173 enum { level = 0 };
174 typedef typename MULTI_ITERATOR::multi_difference_type shape_type;
175 typedef typename MULTI_ITERATOR::iterator iterator;
176
177 MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & shape, unsigned int inner_dimension)
178 : start_(), stop_(shape), point_(start_),
179 inner_dimension_(inner_dimension),
180 inner_shape_(stop_[inner_dimension] - start_[inner_dimension]),
181 i_(i + start_)
182 {
183 if(stop_[inner_dimension] > start_[inner_dimension])
184 stop_[inner_dimension] = start_[inner_dimension] + 1;
185 }
186
187 MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & start, shape_type const & stop,
188 unsigned int inner_dimension)
189 : start_(start), stop_(stop), point_(start_),
190 inner_dimension_(inner_dimension),
191 inner_shape_(stop_[inner_dimension] - start_[inner_dimension]),
192 i_(i + start_)
193 {
194 if(stop_[inner_dimension] > start_[inner_dimension])
195 stop_[inner_dimension] = start_[inner_dimension] + 1;
196 }
197
198 void operator++()
199 {
200 ++point_[level];
201 ++i_.template dim<level>();
202 }
203
204 void operator++(int)
205 {
206 ++*this;
207 }
208
209 iterator begin() const
210 {
211 return i_.iteratorForDimension(inner_dimension_);
212 }
213
214 iterator end() const
215 {
216 return begin() + inner_shape_;
217 }
218
219 bool hasMore() const
220 {
221 return point_[level] < stop_[level];
222 }
223
224 bool atEnd() const
225 {
226 return point_[level] >= stop_[level];
227 }
228
229 shape_type const & point() const
230 {
231 return point_;
232 }
233
234 protected:
235 void reset()
236 {
237 point_[level] = start_[level];
238 i_.template dim<level>() -= (stop_[level] - start_[level]);
239 }
240
241 shape_type start_, stop_, point_;
242 unsigned int inner_dimension_, inner_shape_;
243 MULTI_ITERATOR i_;
244 };
245
246 /********************************************************/
247 /* */
248 /* MultiCoordinateNavigator */
249 /* */
250 /********************************************************/
251
252 /** \brief A navigator that provides access to the 1D subranges of an
253 n-dimensional range given by an nD shape.
254
255 This class works similarly to \ref MultiArrayNavigator, but instead of a
256 1-dimensional iterator pair, it returns a pair of shapes whose difference
257 specifies a 1-dimensional range along the desired dimension. That is, when
258 the navigator refers to dimension <tt>d</tt>, the difference between
259 <tt>end()</tt> and <tt>begin()</tt> is <tt>1</tt> along all dimensions
260 except <tt>d</tt>.
261
262 The template parameters specifies the dimension of the shape.
263
264 <b>Usage:</b>
265
266 <b>\#include</b> <vigra/navigator.hxx>
267
268 Namespace: vigra
269
270 \code
271 typedef vigra::MultiArrayShape<3>::type Shape;
272 typedef vigra::MultiArray<3, int> Array;
273 typedef vigra::MultiCoordinateNavigator<3> Navigator;
274
275 Array a(Shape(X, Y, Z));
276
277 for(int d=0; d<3; ++d)
278 {
279 // create Navigator for dimension d
280 Navigator nav(a.shape(), d);
281
282 // outer loop: move navigator to all starting points
283 // of 1D subsets that run parallel to coordinate axis d
284 for(; nav.hasMore(); ++nav)
285 {
286 // inner loop: linear iteration over current subset
287 // d == {0, 1, 2}: iterate along {x, y, z}-axis respectively
288 Shape point = nav.begin(), end = nav.end();
289 for(; point[d] != end[d]; ++point[d])
290 a[point] = 5;
291 }
292 }
293 \endcode
294 */
295 template <unsigned int Dimensions, unsigned int N = Dimensions>
296 class MultiCoordinateNavigator
297 #ifndef DOXYGEN // doxygen doesn't understand this inheritance
298 : public MultiCoordinateNavigator<Dimensions, N-1>
299 #endif
300 {
301 typedef MultiCoordinateNavigator<Dimensions, N-1> base_type;
302
303 public:
304 enum { level = N-1 };
305
306 /** The shape type for the given iterator type.
307 */
308 typedef typename MultiArrayShape<Dimensions>::type value_type;
309
310
311 /** Construct navigator for multi-dimensional iterator <TT>i</TT>, array shape <TT>shape</TT>
312 and inner loop dimension <TT>inner_dimension</TT>.
313 */
314 MultiCoordinateNavigator(value_type const & shape, unsigned int inner_dimension)
315 : base_type(shape, inner_dimension)
316 {
317 this->end_[level] = (this->inner_dimension_ == level)
318 ? 1
319 : this->shape_[level];
320 }
321
322 /** Advance to next starting location.
323 */
324 void operator++()
325 {
326 base_type::operator++();
327 if(base_type::atEnd() && this->i_[level] < this->end_[level])
328 {
329 ++this->i_[level];
330 if(this->i_[level] < this->end_[level])
331 base_type::reset();
332 }
333 }
334
335 /** Advance to next starting location.
336 */
337 void operator++(int)
338 {
339 ++*this;
340 }
341
342 /** true if there are more elements.
343 */
344 bool hasMore() const
345 {
346 return this->inner_dimension_ == level
347 ? base_type::hasMore()
348 : this->i_[level] < this->end_[level];
349 }
350
351 /** true if iterator is exhausted.
352 */
353 bool atEnd() const
354 {
355 return !hasMore();
356 // return this->inner_dimension_ == level
357 // ? base_type::atEnd()
358 // : !(this->i_[level] < this->end_[level]);
359 }
360
361 protected:
362 void reset()
363 {
364 this->i_[level] = 0;
365 this->end_[level] = (this->inner_dimension_ == level)
366 ? 1
367 : this->shape_[level];
368 base_type::reset();
369 }
370 };
371
372 template <unsigned int Dimensions>
373 class MultiCoordinateNavigator<Dimensions, 1>
374 {
375 public:
376 enum { level = 0 };
377 typedef typename MultiArrayShape<Dimensions>::type value_type;
378
379 MultiCoordinateNavigator(value_type const & shape, unsigned int inner_dimension)
380 : shape_(shape),
381 inner_dimension_(inner_dimension)
382 {
383 end_[level] = (inner_dimension_ == level)
384 ? 1
385 : shape_[level];
386 }
387
388 void operator++()
389 {
390 ++i_[level];
391 }
392
393 void operator++(int)
394 {
395 ++*this;
396 }
397
398 value_type const & begin() const
399 {
400 return i_;
401 }
402
403 value_type end() const
404 {
405 value_type res = i_ + value_type(MultiArrayIndex(1));
406 res[inner_dimension_] = shape_[inner_dimension_];
407 return res;
408 }
409
410 bool hasMore() const
411 {
412 return i_[level] < end_[level];
413 }
414
415 bool atEnd() const
416 {
417 return !hasMore();
418 }
419
420 protected:
421 void reset()
422 {
423 i_[level] = 0;
424 end_[level] = (inner_dimension_ == level)
425 ? 1
426 : shape_[level];
427 }
428
429 value_type shape_, i_, end_;
430 unsigned int inner_dimension_;
431 };
432
433 } // namespace vigra
434
435 #endif /* VIGRA_NAVIGATOR_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)