Rev 33 | Rev 37 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | |||
15 | Werner | 2 | #ifndef GRID_H |
3 | #define GRID_H |
||
4 | |||
22 | Werner | 5 | #include <QtCore> |
15 | Werner | 6 | |
7 | |||
8 | #include <stdexcept> |
||
9 | |||
10 | /** Grid class (template). |
||
11 | |||
12 | */ |
||
13 | template <class T> |
||
14 | class Grid { |
||
15 | public: |
||
16 | |||
17 | Grid(); |
||
18 | Grid(int cellsize, int sizex, int sizey) { mData=0; setup(cellsize, sizex, sizey); } |
||
33 | Werner | 19 | // copy ctor |
20 | Grid(const Grid<T>& toCopy); |
||
15 | Werner | 21 | ~Grid() { if (mData) delete[] mData; } |
22 | |||
18 | Werner | 23 | bool setup(const float cellsize, const int sizex, const int sizey); |
22 | Werner | 24 | bool setup(const QRectF& rect, const double cellsize); |
15 | Werner | 25 | void initialize(const T& value) {for( T *p = begin();p!=end(); ++p) *p=value;} |
26 | |||
27 | const int sizeX() const { return mSizeX; } |
||
28 | const int sizeY() const { return mSizeY; } |
||
29 | const float metricSizeX() const { return mSizeX*mCellsize; } |
||
30 | const float metricSizeY() const { return mSizeY*mCellsize; } |
||
31 | const float cellsize() const { return mCellsize; } |
||
27 | Werner | 32 | const int count() const { return mCount; } |
32 | Werner | 33 | // operations |
15 | Werner | 34 | // query |
33 | Werner | 35 | /// access (const) with index variables. use int. |
36 | inline const T& operator()(const int ix, const int iy) const { return constValueAtIndex(ix, iy); } |
||
37 | /// access (const) using metric variables. use float. |
||
38 | inline const T& operator()(const float x, const float y) const { return constValueAt(x, y); } |
||
39 | |||
25 | Werner | 40 | T& valueAtIndex(const QPoint& pos); ///< value at position defined by indices (x,y) |
33 | Werner | 41 | T& valueAtIndex(const int ix, const int iy) { return valueAtIndex(QPoint(ix,iy)); } ///< const value at position defined by indices (x,y) |
42 | |||
43 | const T& constValueAtIndex(const QPoint& pos) const; ///< value at position defined by a (integer) QPoint |
||
32 | Werner | 44 | const T& constValueAtIndex(const int ix, const int iy) const { return constValueAtIndex(QPoint(ix,iy)); } |
33 | Werner | 45 | |
46 | T& valueAt(const QPointF& posf); ///< value at position defined by metric coordinates (QPointF) |
||
47 | const T& constValueAt(const QPointF& posf) const; ///< value at position defined by metric coordinates (QPointF) |
||
48 | |||
49 | T& valueAt(const float x, const float y); ///< value at position defined by metric coordinates (x,y) |
||
50 | const T& constValueAt(const float x, const float y) const; ///< value at position defined by metric coordinates (x,y) |
||
51 | |||
27 | Werner | 52 | QPoint indexAt(const QPointF& pos) const { return QPoint(int((pos.x()-mOffset.x()) / mCellsize), int((pos.y()-mOffset.y())/mCellsize)); } /// get index of value at position pos (metric) |
53 | bool isIndexValid(const QPoint& pos) const { return (pos.x()>=0 && pos.x()<mSizeX && pos.y()>=0 && pos.y()<mSizeY); } /// get index of value at position pos (index) |
||
54 | void validate(QPoint &pos) const{ pos.setX( qMax(qMin(pos.x(), mSizeX-1), 0) ); pos.setY( qMax(qMin(pos.y(), mSizeY-1), 0) );} /// ensure that "pos" is a valid key. if out of range, pos is set to minimum/maximum values. |
||
32 | Werner | 55 | QPointF cellCoordinates(const QPoint &pos) { return QPointF( (pos.x()+0.5)*mCellsize+mOffset.x(), (pos.y()+0.5)*mCellsize + mOffset.y());} /// get metric coordinates of the cells center |
27 | Werner | 56 | inline T* begin() const { return mData; } ///< get "iterator" pointer |
57 | inline T* end() const { return &(mData[mCount]); } ///< get iterator end-pointer |
||
58 | QPoint indexOf(T* element) const; ///< retrieve index (x/y) of the pointer element. returns -1/-1 if element is not valid. |
||
59 | // special queries |
||
33 | Werner | 60 | T max() const; ///< retrieve the maximum value of a grid |
61 | T sum() const; ///< retrieve the sum of the grid |
||
62 | T avg() const; ///< retrieve the average value of a grid |
||
63 | /// creates a grid with lower resolution and averaged cell values. |
||
64 | /// @param factor factor by which grid size is reduced (e.g. 3 -> 3x3=9 pixels are averaged to 1 result pixel) |
||
65 | /// @param offsetx, offsety: start averaging with an offset from 0/0 (e.g.: x=1, y=2, factor=3: -> 1/2-3/4 -> 0/0) |
||
66 | /// @return Grid with size sizeX()/factor x sizeY()/factor |
||
67 | Grid<T> averaged(const int factor, const int offsetx=0, const int offsety=0) const; |
||
68 | /// normalized returns a normalized grid, in a way that the sum() = @param targetvalue. |
||
69 | /// if the grid is empty or the sum is 0, no modifications are performed. |
||
70 | Grid<T> normalized(const T targetvalue) const; |
||
15 | Werner | 71 | private: |
72 | T* mData; |
||
22 | Werner | 73 | QPointF mOffset; |
36 | Werner | 74 | float mCellsize; ///< size of a cell in meter |
75 | int mSizeX; ///< count of cells in x-direction |
||
76 | int mSizeY; ///< count of cells in y-direction |
||
77 | int mCount; ///< total number of cells in the grid |
||
15 | Werner | 78 | }; |
79 | |||
80 | typedef Grid<float> FloatGrid; |
||
81 | |||
33 | Werner | 82 | // copy constructor |
83 | template <class T> |
||
84 | Grid<T>::Grid(const Grid<T>& toCopy) |
||
85 | { |
||
86 | setup(toCopy.cellsize(), toCopy.sizeX(), toCopy.sizeY()); |
||
87 | const T* end = toCopy.end(); |
||
88 | T* ptr = begin(); |
||
89 | for (T* i= toCopy.begin(); i!=end; ++i, ++ptr) |
||
90 | *ptr = *i; |
||
91 | } |
||
22 | Werner | 92 | |
33 | Werner | 93 | // normalize function |
32 | Werner | 94 | template <class T> |
33 | Werner | 95 | Grid<T> Grid<T>::normalized(const T targetvalue) const |
32 | Werner | 96 | { |
33 | Werner | 97 | Grid<T> target(*this); |
98 | T total = sum(); |
||
99 | T multiplier; |
||
100 | if (total) |
||
101 | multiplier = targetvalue / total; |
||
102 | else |
||
103 | return target; |
||
104 | for (T* p=target.begin();p!=target.end();++p) |
||
105 | *p *= multiplier; |
||
106 | } |
||
107 | |||
108 | |||
109 | template <class T> |
||
110 | Grid<T> Grid<T>::averaged(const int factor, const int offsetx, const int offsety) const |
||
111 | { |
||
32 | Werner | 112 | Grid<T> target; |
113 | target.setup(cellsize()*factor, sizeX()/factor, sizeY()/factor); |
||
114 | int x,y; |
||
115 | T sum=0; |
||
116 | target.initialize(sum); |
||
117 | // sum over array of 2x2, 3x3, 4x4, ... |
||
118 | for (x=offsetx;x<mSizeX;x++) |
||
119 | for (y=offsety;y<mSizeY;y++) { |
||
120 | target.valueAtIndex((x-offsetx)/factor, (y-offsety)/factor) += constValueAtIndex(x,y); |
||
121 | } |
||
122 | // divide |
||
123 | double fsquare = factor*factor; |
||
124 | for (T* p=target.begin();p!=target.end();++p) |
||
125 | *p /= fsquare; |
||
126 | return target; |
||
127 | } |
||
22 | Werner | 128 | |
15 | Werner | 129 | template <class T> |
22 | Werner | 130 | T& Grid<T>::valueAtIndex(const QPoint& pos) |
131 | { |
||
132 | if (isIndexValid(pos)) { |
||
133 | return mData[pos.x()*mSizeX + pos.y()]; |
||
134 | } |
||
135 | throw std::logic_error("TGrid: invalid Index!"); |
||
136 | } |
||
36 | Werner | 137 | |
27 | Werner | 138 | template <class T> |
139 | const T& Grid<T>::constValueAtIndex(const QPoint& pos) const |
||
140 | { |
||
141 | if (isIndexValid(pos)) { |
||
142 | return mData[pos.x()*mSizeX + pos.y()]; |
||
143 | } |
||
144 | throw std::logic_error("TGrid: invalid Index!"); |
||
145 | } |
||
22 | Werner | 146 | |
147 | template <class T> |
||
33 | Werner | 148 | T& Grid<T>::valueAt(const float x, const float y) |
149 | { |
||
150 | return valueAtIndex( indexAt(QPointF(x,y)) ); |
||
151 | } |
||
36 | Werner | 152 | |
33 | Werner | 153 | template <class T> |
154 | const T& Grid<T>::constValueAt(const float x, const float y) const |
||
155 | { |
||
156 | return constValueAtIndex( indexAt(QPointF(x,y)) ); |
||
157 | } |
||
36 | Werner | 158 | |
33 | Werner | 159 | template <class T> |
22 | Werner | 160 | T& Grid<T>::valueAt(const QPointF& posf) |
161 | { |
||
162 | return valueAtIndex( indexAt(posf) ); |
||
163 | } |
||
36 | Werner | 164 | |
33 | Werner | 165 | template <class T> |
166 | const T& Grid<T>::constValueAt(const QPointF& posf) const |
||
167 | { |
||
168 | return constValueAtIndex( indexAt(posf) ); |
||
169 | } |
||
22 | Werner | 170 | |
171 | template <class T> |
||
15 | Werner | 172 | Grid<T>::Grid() |
173 | { |
||
174 | mData=0; mCellsize=0.f; |
||
175 | } |
||
176 | |||
177 | template <class T> |
||
18 | Werner | 178 | bool Grid<T>::setup(const float cellsize, const int sizex, const int sizey) |
15 | Werner | 179 | { |
180 | mSizeX=sizex; mSizeY=sizey; mCellsize=(float)cellsize; |
||
181 | mCount = mSizeX*mSizeY; |
||
182 | if (mData) |
||
183 | delete[] mData; |
||
184 | if (mCount>0) |
||
185 | mData = new T[mCount]; |
||
186 | return true; |
||
187 | } |
||
188 | |||
189 | template <class T> |
||
22 | Werner | 190 | bool Grid<T>::setup(const QRectF& rect, const double cellsize) |
15 | Werner | 191 | { |
22 | Werner | 192 | mOffset.setX(rect.left()); |
193 | mOffset.setY(rect.top()); |
||
194 | int dx = int(rect.width()/cellsize); |
||
195 | if (mOffset.x()+cellsize*dx<rect.right()) |
||
196 | dx++; |
||
197 | int dy = int(rect.height()/cellsize); |
||
198 | if (mOffset.y()+cellsize*dy<rect.bottom()) |
||
199 | dy++; |
||
200 | return setup(cellsize, dx, dy); |
||
15 | Werner | 201 | } |
202 | |||
25 | Werner | 203 | template <class T> |
27 | Werner | 204 | QPoint Grid<T>::indexOf(T* element) const |
25 | Werner | 205 | { |
206 | QPoint result(-1,-1); |
||
207 | if (element==NULL || element<mData || element>=end()) |
||
208 | return result; |
||
209 | int idx = element - mData; |
||
210 | result.setX( idx / mSizeX); |
||
211 | result.setY( idx % mSizeX); |
||
212 | return result; |
||
213 | } |
||
22 | Werner | 214 | |
27 | Werner | 215 | template <class T> |
216 | T Grid<T>::max() const |
||
217 | { |
||
218 | T maxv = std::numeric_limits<T>::min(); |
||
219 | T* p; |
||
220 | T* pend = end(); |
||
221 | for (p=begin(); p!=pend;++p) |
||
222 | maxv = std::max(maxv, *p); |
||
223 | return maxv; |
||
224 | } |
||
225 | |||
33 | Werner | 226 | template <class T> |
227 | T Grid<T>::sum() const |
||
228 | { |
||
229 | T* pend = end(); |
||
230 | T total = 0; |
||
231 | for (T *p=begin(); p!=pend;++p) |
||
232 | total += *p; |
||
233 | return total; |
||
234 | } |
||
235 | |||
236 | template <class T> |
||
237 | T Grid<T>::avg() const |
||
238 | { |
||
239 | if (count()) |
||
240 | return sum() / T(count()); |
||
241 | else return 0; |
||
242 | } |
||
243 | |||
36 | Werner | 244 | ////////////////////////////////////////////////////////////7 |
245 | // global functions |
||
246 | ////////////////////////////////////////////////////////////7 |
||
247 | |||
248 | /// dumps a FloatGrid to a String. |
||
249 | /// rows will be y-lines, columns x-values. |
||
250 | QString gridToString(const FloatGrid &grid); |
||
251 | |||
252 | /// creates and return a QImage from Grid-Data. |
||
253 | /// @param black_white true: max_value = white, min_value = black, false: color-mode: uses a HSV-color model from blue (min_value) to red (max_value), default: color mode (false) |
||
254 | /// @param min_value, max_value min/max bounds for color calcuations. values outside bounds are limited to these values. defaults: min=0, max=1 |
||
255 | /// @param reverse if true, color ramps are inversed (to: min_value = white (black and white mode) or red (color mode). default = false. |
||
256 | /// @return a QImage with the Grids size of pixels. Pixel coordinates relate to the index values of the grid. |
||
257 | QImage gridToImage(const FloatGrid &grid, |
||
258 | bool black_white=false, |
||
259 | double min_value=0., double max_value=1., |
||
260 | bool reverse=false); |
||
261 | |||
262 | /// template version for non-float grids. |
||
263 | template <class T> |
||
264 | QString gridToString(const Grid<T> &grid) |
||
265 | { |
||
266 | QString res; |
||
267 | QTextStream ts(&res); |
||
268 | |||
269 | for (int x=0;x<grid.sizeX();x++){ |
||
270 | for (int y=0;y<grid.sizeY();y++) { |
||
271 | ts << grid.constValueAtIndex(x,y) << ";"; |
||
272 | |||
273 | } |
||
274 | ts << "\r\n"; |
||
275 | } |
||
276 | |||
277 | return res; |
||
278 | } |
||
15 | Werner | 279 | #endif // GRID_H |