iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Array2D.H
Go to the documentation of this file.
1 /*! @file
2  @author Randolph Voorhies
3  @copyright GNU Public License (GPL v3)
4  @section License
5  @verbatim
6  // ////////////////////////////////////////////////////////////////////////
7  // The iLab Neuromorphic Robotics Toolkit (NRT) //
8  // Copyright 2010-2012 by the University of Southern California (USC) //
9  // and the iLab at USC. //
10  // //
11  // iLab - University of Southern California //
12  // Hedco Neurociences Building, Room HNB-10 //
13  // Los Angeles, Ca 90089-2520 - USA //
14  // //
15  // See http://ilab.usc.edu for information about this project. //
16  // ////////////////////////////////////////////////////////////////////////
17  // This file is part of The iLab Neuromorphic Robotics Toolkit. //
18  // //
19  // The iLab Neuromorphic Robotics Toolkit is free software: you can //
20  // redistribute it and/or modify it under the terms of the GNU General //
21  // Public License as published by the Free Software Foundation, either //
22  // version 3 of the License, or (at your option) any later version. //
23  // //
24  // The iLab Neuromorphic Robotics Toolkit is distributed in the hope //
25  // that it will be useful, but WITHOUT ANY WARRANTY; without even the //
26  // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
27  // PURPOSE. See the GNU General Public License for more details. //
28  // //
29  // You should have received a copy of the GNU General Public License //
30  // along with The iLab Neuromorphic Robotics Toolkit. If not, see //
31  // <http://www.gnu.org/licenses/>. //
32  // ////////////////////////////////////////////////////////////////////////
33  @endverbatim */
34 
35 
36 #ifndef INCLUDE_NRT_CORE_MEMORY_ARRAY2D_H
37 #define INCLUDE_NRT_CORE_MEMORY_ARRAY2D_H
38 
39 #include <nrt/config.h>
41 #include <nrt/Core/Geometry/Dims.H>
44 #include <nrt/Core/Memory/Array.H>
46 
48 
49 #include <nrt/External/cereal/access.hpp>
50 
51 namespace nrt
52 {
53  //! A shared, copy-on-write 2D addressable storage class for holding arbitrary types.
54  /*! The nrt::Array2D class is a simple wrapper around nrt::Array which provides convenience methods for addressing
55  nrt::Array as if it spanned 2 dimensions. If you are trying to represent a 2D array of pixels, you should instead
56  create an nrt::Image, of which nrt::Array2D is a base class. The most notable difference between nrt::Array2D and
57  nrt::Image is that nrt::Array2D will allow you to store any data type, whereas an nrt::Image can only hold data
58  types derived from nrt::PixelBase.
59 
60  \note Unlike Image, Array2D will never check the make sure the coordinates you pass to at() or operator() are
61  valid.
62 
63  \see Image
64  \ingroup arrays */
65  template <class T>
66  class Array2D : public Array2DBase
67  {
68  public:
69  //! Create an empty Array2D (will have size 0x0)
70  Array2D();
71 
72  //! Allocate an uninitialized Array2D with the given size
73  Array2D(DimsType const & dims);
74 
75  //! Allocate an uninitialized Array2D, and fill every element with a copy of val
76  Array2D(DimsType const & dims, T const & val);
77 
78  //! Copy constructor
79  /*! Copy another Array2D into this one.
80  \note This constructor uses nrt::Array's copy-on-write functionality, meaning that when this constructor is
81  called no actual data will be copied. The underlying data will only be copied if either Array attempts to
82  write to the data. */
83  Array2D(Array2D<T> const & other);
84 
85  //! Move constructor
86  /*! Move constructs another Array2D into this one. This will cause the other Array2D to become invalid; using an
87  invalid array will result in undefined behavior. */
88  Array2D(Array2D && other);
89 
90  //! Construct from a 2D initializer list
91  Array2D(std::initializer_list<std::initializer_list<T>> vals);
92 
93  //! Construct a 2D array from foreign memory by making a deep copy of it
94  Array2D(T const * data, DimsType const & dims);
95 
96  //! Assignment operator
97  /*! Copy another Array2D into this one.
98  \note This assignment uses nrt::Array's copy-on-write functionality, meaning that when this constructor is
99  called no actual data will be copied. The underlying data will only be copied if either Array attempts to
100  write to the data. */
101  Array2D & operator=(Array2D<T> const & other);
102 
103  //! Move assignment operator
104  /*! Move assigns another Array2D into this one. This will cause the other Array2D to become invalid; using an
105  invalid array will result in undefined behavior. */
106  Array2D & operator=(Array2D<T> && other);
107 
108  //! Clear contents (or set to given value) without changing the size of the Array2D
109  void clear(T const & val = T());
110 
111  //! Read the value at position (x, y)
112  /*! Use this method to read elements of your Array2D, e.g.
113  @code
114  int val = myArray.at(5, 2);
115  @endcode
116  This method can be much faster than operator() because it will never make a copy of the Array2D. */
117  T const & at(int32 x, int32 y) const;
118 
119  //! A convenient overload of at(int32 x, int32 y) const
120  T const & at(Point2D<int32> p) const;
121 
122  //! A convenient overload of at(int32 x, int32 y) const for linear read-only access to the Array2D.
123  T const & at(uint32 idx) const;
124 
125  //! Get a mutable reference to the value at position (x, y)
126  /*! Use this method to set elements of your Array2D, e.g.
127  @code
128  myArray2D(5, 2) = 17;
129  @endcode
130  Note that this method can be much slower than the .at() method when just reading values because it
131  may make a deep-copy of the underlying memory if it is shared with another Array2D. */
132  T & operator()(int32 x, int32 y);
133 
134  //! Get a const reference to the value at position (x, y)
135  T const & operator()(int32 x, int32 y) const;
136 
137  //! A convenient overload of operator()(int32 x, int32 y)
138  T & operator()(Point2D<int32> p);
139 
140  //! A convenient overload of operator()(int32 x, int32 y)
141  T const & operator()(Point2D<int32> p) const;
142 
143  //! A convenient overload of operator()(int32 x, int32 y) for linear write access to the Image
144  T & operator()(uint32 idx);
145 
146  //! A convenient overload of operator()(int32 x, int32 y) for linear write access to the Image
147  T const & operator()(uint32 idx) const;
148 
149  //! Test whether point falls inside array boundaries
150  template<class U> bool coordsOk(const U x, const U y) const;
151 
152  //! Test whether a rectangle falls inside array boundaries
153  template<class U> bool rectangleOk(const Rectangle<U> rect) const;
154 
155  //! Convenient overload of coordsOk(int32 x, int32 y)
156  template<class U> bool coordsOk(const Point2D<U>& P) const;
157 
158  //! Get the dimensions of the Array2D
159  DimsType const & dims() const;
160 
161  //! Get the bounding rectangle of the Array2D
162  Rectangle<int32> const bounds() const;
163 
164  //! Get the width of the Array2D
165  int32 const width() const;
166 
167  //! Get the height of the Array2D
168  int32 const height() const;
169 
170  //! Get the total number of elements in the Array2D; if it is zero then the image is un-initialized
171  int32 const size() const;
172 
173  //! Let the caller know whether the Array2D is empty (0x0 dimensions)
174  /*! This is equivalent to (size() == 0) */
175  bool const empty() const;
176 
177  //! Reshape an Array2D to new Dims without changing the number of elements in the underlying data
178  /*! This just changes the Dims but does not affect the pixel array. The new dims must have a size() equal to the
179  old size(), otherwise this throws BadDimsImageException. */
180  void reshape(Dims<int32> const & newDims);
181 
182  //! Reshape an image to new dims without changing the underlying data
183  /*! \see reshape(Dims<int32>) */
184  void reshape(int32 newWidth, int32 newHeight);
185 
186  //! Get a const reference to a (potentially non-const) Array2D
187  /*! The main purpose of this method is to allow easy and efficient read-only access via C++0x's range-based for
188  loop. Beware that if you just call begin() on an Array2D that is not instantiated as const, then the
189  non-const begin() will be called, potentially triggering an (expensive) deep copy. This would occur in the
190  following cases:
191 
192  @code
193  Array2D<int> img1 = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 } }, img2 = img1;
194  for (auto const & pix : img1) { ... } // Deep copy here because img1 is non const and data shared with img2
195  @endcode
196 
197  So the Array2D has to be non-const and shared for this problem to surface, if it is const, then the const
198  version of begin() will be called by our for() loop, or if it is not shared, then the non-const begin() is
199  called but no deep copy will occur anyway. To always avoid the deep copy, just use:
200 
201  @code
202  for (auto const & pix : img1.cref()) { ... } // no deep copy, const begin() used
203  @endcode */
204  Array2D<T> const & cref() const;
205 
206  //! Read-write iterator over the data, scans in standard raster fashion (x varies fastest, then y)
207  typedef T * iterator;
208 
209  //! Constant iterator over data, scans in standard raster fashion (x varies fastest, then y)
210  typedef T const * const_iterator;
211 
212  //! Get constant (read-only) iterators to the beginning of the Image
213  /*! If you only need to inspect elements of an Image, then this is the very fastest way to do so. */
214  const_iterator const_begin() const;
215 
216  //! Get constant (read-only) iterators to the beginning of the Image
217  /*! If you only need to inspect elements of a known-to-be-const Image, then this is the very fastest way to do so,
218  but see cref() for caveats. */
219  const_iterator begin() const;
220 
221  //! Get constant (read-only) iterators to the end of the Image
222  /*! If you only need to inspect elements of an Image, then this is the very fastest way to do so. */
223  const_iterator const_end() const;
224 
225  //! Get constant (read-only) iterators to the beginning of the Image
226  /*! If you only need to inspect elements of a known-to-be-const Image, then this is the very fastest way to do so,
227  but see cref() for caveats. */
228  const_iterator end() const;
229 
230  //! Gets a read-write iterator to the beginning of the Image
231  /*! Use this method only if you really do need to modify elements of your Image because they may invoke a
232  deep-copy of the Image memory if it is shared by another Image. If only read access is necessary, use the
233  const_begin() method instead. */
234  iterator begin();
235 
236  //! Gets a read-write iterator to the end of the Image
237  /*! \see begin() */
238  iterator end();
239 
240  //! Make a deep copy of our Memory.
241  /*! Immediately after a call to deepCopy(), our reference count is guaranteed to be 1 */
242  void deepCopy();
243 
244  protected:
245  friend class cereal::access;
246  template <class Archive>
247  void serialize( Archive & ar )
248  {
249  ar( itsDims, itsArray );
250  }
251 
252  DimsType itsDims;
253  Array<T> itsArray;
254  };
255 
256 } // namespace nrt
257 
259 
260 #endif // INCLUDE_NRT_CORE_MEMORY_ARRAY2D_H
261 
262