Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
671 | werner | 1 | /******************************************************************************************** |
2 | ** iLand - an individual based forest landscape and disturbance model |
||
3 | ** http://iland.boku.ac.at |
||
4 | ** Copyright (C) 2009- Werner Rammer, Rupert Seidl |
||
5 | ** |
||
6 | ** This program is free software: you can redistribute it and/or modify |
||
7 | ** it under the terms of the GNU General Public License as published by |
||
8 | ** the Free Software Foundation, either version 3 of the License, or |
||
9 | ** (at your option) any later version. |
||
10 | ** |
||
11 | ** This program is distributed in the hope that it will be useful, |
||
12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | ** GNU General Public License for more details. |
||
15 | ** |
||
16 | ** You should have received a copy of the GNU General Public License |
||
17 | ** along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
18 | ********************************************************************************************/ |
||
19 | |||
15 | Werner | 20 | #ifndef GRID_H |
21 | #define GRID_H |
||
22 | |||
22 | Werner | 23 | #include <QtCore> |
15 | Werner | 24 | |
25 | |||
26 | #include <stdexcept> |
||
145 | Werner | 27 | #include <limits> |
150 | iland | 28 | #include <cstring> |
15 | Werner | 29 | |
373 | werner | 30 | #include "global.h" |
31 | |||
247 | werner | 32 | /** Grid class (template). |
697 | werner | 33 | @ingroup tools |
74 | Werner | 34 | Orientation |
656 | werner | 35 | The grid is oriented as typically coordinates on the northern hemisphere: higher y-values -> north, higher x-values-> east. |
490 | werner | 36 | The projection is reversed for drawing on screen (Viewport). |
74 | Werner | 37 | N |
490 | werner | 38 | (0/2) (1/2) (2/2) |
656 | werner | 39 | W (0/1) (1/1) (2/1) E |
74 | Werner | 40 | (0/0) (1/0) (2/0) |
41 | S |
||
42 | */ |
||
15 | Werner | 43 | template <class T> |
44 | class Grid { |
||
45 | public: |
||
46 | |||
47 | Grid(); |
||
1157 | werner | 48 | Grid(float cellsize, int sizex, int sizey) { mData=0; setup(cellsize, sizex, sizey); } |
914 | werner | 49 | /// create from a metric rect |
58 | Werner | 50 | Grid(const QRectF rect_metric, const float cellsize) { mData=0; setup(rect_metric,cellsize); } |
33 | Werner | 51 | // copy ctor |
52 | Grid(const Grid<T>& toCopy); |
||
105 | Werner | 53 | ~Grid() { clear(); } |
54 | void clear() { if (mData) delete[] mData; mData=0; } |
||
15 | Werner | 55 | |
18 | Werner | 56 | bool setup(const float cellsize, const int sizex, const int sizey); |
22 | Werner | 57 | bool setup(const QRectF& rect, const double cellsize); |
896 | werner | 58 | bool setup(const Grid<T>& source) { clear(); mRect = source.mRect; return setup(source.mRect, source.mCellsize); } |
75 | Werner | 59 | void initialize(const T& value) {for( T *p = begin();p!=end(); ++p) *p=value; } |
150 | iland | 60 | void wipe(); ///< write 0-bytes with memcpy to the whole area |
154 | werner | 61 | void wipe(const T value); ///< overwrite the whole area with "value" size of T must be the size of "int" ERRORNOUS!!! |
764 | werner | 62 | /// copies the content of the source grid to this grid. |
63 | /// no operation, if the grids are not of the same size. |
||
64 | void copy(const Grid<T> source) { if (source.count()==count()) memcpy(mData, source.mData, count()*sizeof(T)); } |
||
1083 | werner | 65 | /// create a double grid (same size as this grid) and convert this grid to double values. |
66 | /// NOTE: caller is responsible for freeing memory! |
||
67 | Grid<double> *toDouble() const; |
||
15 | Werner | 68 | |
797 | werner | 69 | // get the number of cells in x and y direction |
145 | Werner | 70 | int sizeX() const { return mSizeX; } |
71 | int sizeY() const { return mSizeY; } |
||
797 | werner | 72 | // get the size of the grid in metric coordinates (x and y direction) |
145 | Werner | 73 | float metricSizeX() const { return mSizeX*mCellsize; } |
74 | float metricSizeY() const { return mSizeY*mCellsize; } |
||
797 | werner | 75 | /// get the metric rectangle of the grid |
49 | Werner | 76 | QRectF metricRect() const { return mRect; } |
797 | werner | 77 | /// get the rectangle of the grid in terms of indices |
78 | QRect rectangle() const { return QRect(QPoint(0,0), QPoint(sizeX(), sizeY())); } |
||
79 | /// get the length of one pixel of the grid |
||
145 | Werner | 80 | float cellsize() const { return mCellsize; } |
373 | werner | 81 | int count() const { return mCount; } ///< returns the number of elements of the grid |
82 | bool isEmpty() const { return mData==NULL; } ///< returns false if the grid was not setup |
||
32 | Werner | 83 | // operations |
15 | Werner | 84 | // query |
33 | Werner | 85 | /// access (const) with index variables. use int. |
86 | inline const T& operator()(const int ix, const int iy) const { return constValueAtIndex(ix, iy); } |
||
87 | /// access (const) using metric variables. use float. |
||
88 | inline const T& operator()(const float x, const float y) const { return constValueAt(x, y); } |
||
1067 | werner | 89 | /// access value of grid with a QPoint |
90 | inline const T& operator[](const QPoint &p) const { return constValueAtIndex(p); } |
||
91 | /// use the square brackets to access by index |
||
92 | inline T& operator[](const int idx) const { return mData[idx]; } |
||
93 | /// use the square bracket to access by QPointF |
||
1070 | werner | 94 | inline T& operator[] (const QPointF &p) { return valueAt(p); } |
33 | Werner | 95 | |
705 | werner | 96 | inline T& valueAtIndex(const QPoint& pos) {return valueAtIndex(pos.x(), pos.y());} ///< value at position defined by a QPoint defining the two indices (x,y) |
97 | T& valueAtIndex(const int ix, const int iy) { return mData[iy*mSizeX + ix]; } ///< const value at position defined by indices (x,y) |
||
285 | werner | 98 | T& valueAtIndex(const int index) {return mData[index]; } ///< get a ref ot value at (one-dimensional) index 'index'. |
1111 | werner | 99 | inline int index(const int ix, const int iy) { return iy*mSizeX + ix; } ///< get the 0-based index of the cell with indices ix and iy. |
100 | inline int index(const QPoint &pos) { return pos.y()*mSizeX + pos.x(); } ///< get the 0-based index of the cell at 'pos'. |
||
705 | werner | 101 | /// value at position defined by a (integer) QPoint |
102 | inline const T& constValueAtIndex(const QPoint& pos) const {return constValueAtIndex(pos.x(), pos.y()); } |
||
103 | /// value at position defined by a pair of integer coordinates |
||
104 | inline const T& constValueAtIndex(const int ix, const int iy) const { return mData[iy*mSizeX + ix]; } |
||
105 | /// value at position defined by the index within the grid |
||
549 | werner | 106 | const T& constValueAtIndex(const int index) const {return mData[index]; } ///< get a ref ot value at (one-dimensional) index 'index'. |
33 | Werner | 107 | |
108 | T& valueAt(const QPointF& posf); ///< value at position defined by metric coordinates (QPointF) |
||
109 | const T& constValueAt(const QPointF& posf) const; ///< value at position defined by metric coordinates (QPointF) |
||
110 | |||
111 | T& valueAt(const float x, const float y); ///< value at position defined by metric coordinates (x,y) |
||
112 | const T& constValueAt(const float x, const float y) const; ///< value at position defined by metric coordinates (x,y) |
||
113 | |||
1067 | werner | 114 | |
105 | Werner | 115 | bool coordValid(const float x, const float y) const { return x>=mRect.left() && x<mRect.right() && y>=mRect.top() && y<mRect.bottom(); } |
49 | Werner | 116 | bool coordValid(const QPointF &pos) const { return coordValid(pos.x(), pos.y()); } |
75 | Werner | 117 | |
55 | Werner | 118 | QPoint indexAt(const QPointF& pos) const { return QPoint(int((pos.x()-mRect.left()) / mCellsize), int((pos.y()-mRect.top())/mCellsize)); } ///< get index of value at position pos (metric) |
538 | werner | 119 | /// get index (x/y) of the (linear) index 'index' (0..count-1) |
120 | QPoint indexOf(const int index) const {return QPoint(index % mSizeX, index / mSizeX); } |
||
373 | werner | 121 | bool isIndexValid(const QPoint& pos) const { return (pos.x()>=0 && pos.x()<mSizeX && pos.y()>=0 && pos.y()<mSizeY); } ///< return true, if position is within the grid |
122 | bool isIndexValid(const int x, const int y) const {return (x>=0 && x<mSizeX && y>=0 && y<mSizeY); } ///< return true, if index is within the grid |
||
1068 | werner | 123 | |
124 | /// returns the index of an aligned grid (with the same size and matching origin) with the double cell size (e.g. to scale from a 10m grid to a 20m grid) |
||
1118 | werner | 125 | int index2(int idx) const {return ((idx/mSizeX)/2)*(mSizeX/2) + (idx%mSizeX)/2; } |
1068 | werner | 126 | /// returns the index of an aligned grid (the same size) with the 5 times bigger cells (e.g. to scale from a 2m grid to a 10m grid) |
1118 | werner | 127 | int index5(int idx) const {return ((idx/mSizeX)/5)*(mSizeX/5) + (idx%mSizeX)/5; } |
1111 | werner | 128 | /// returns the index of an aligned grid (the same size) with the 10 times bigger cells (e.g. to scale from a 2m grid to a 20m grid) |
1118 | werner | 129 | int index10(int idx) const {return ((idx/mSizeX)/10)*(mSizeX/10) + (idx%mSizeX)/10; } |
1068 | werner | 130 | |
75 | Werner | 131 | /// force @param pos to contain valid indices with respect to this grid. |
55 | Werner | 132 | 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. |
105 | Werner | 133 | /// get the (metric) centerpoint of cell with index @p pos |
549 | werner | 134 | QPointF cellCenterPoint(const QPoint &pos) const { return QPointF( (pos.x()+0.5)*mCellsize+mRect.left(), (pos.y()+0.5)*mCellsize + mRect.top());} ///< get metric coordinates of the cells center |
881 | werner | 135 | /// get the metric cell center point of the cell given by index 'index' |
136 | QPointF cellCenterPoint(const int &index) const { QPoint pos=indexOf(index); return QPointF( (pos.x()+0.5)*mCellsize+mRect.left(), (pos.y()+0.5)*mCellsize + mRect.top());} |
||
105 | Werner | 137 | /// get the metric rectangle of the cell with index @pos |
439 | werner | 138 | QRectF cellRect(const QPoint &pos) const { QRectF r( QPointF(mRect.left() + mCellsize*pos.x(), mRect.top() + pos.y()*mCellsize), |
55 | Werner | 139 | QSizeF(mCellsize, mCellsize)); return r; } ///< return coordinates of rect given by @param pos. |
105 | Werner | 140 | |
27 | Werner | 141 | inline T* begin() const { return mData; } ///< get "iterator" pointer |
37 | Werner | 142 | inline T* end() const { return mEnd; } ///< get iterator end-pointer |
717 | werner | 143 | inline QPoint indexOf(const T* element) const; ///< retrieve index (x/y) of the pointer element. returns -1/-1 if element is not valid. |
27 | Werner | 144 | // special queries |
33 | Werner | 145 | T max() const; ///< retrieve the maximum value of a grid |
146 | T sum() const; ///< retrieve the sum of the grid |
||
147 | T avg() const; ///< retrieve the average value of a grid |
||
391 | werner | 148 | // modifying operations |
149 | void add(const T& summand); |
||
150 | void multiply(const T& factor); |
||
1085 | werner | 151 | /// limit each cell value to (including) min_value and (including) max_value |
152 | void limit(const T min_value, const T max_value); |
||
153 | |||
33 | Werner | 154 | /// creates a grid with lower resolution and averaged cell values. |
155 | /// @param factor factor by which grid size is reduced (e.g. 3 -> 3x3=9 pixels are averaged to 1 result pixel) |
||
156 | /// @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) |
||
157 | /// @return Grid with size sizeX()/factor x sizeY()/factor |
||
158 | Grid<T> averaged(const int factor, const int offsetx=0, const int offsety=0) const; |
||
159 | /// normalized returns a normalized grid, in a way that the sum() = @param targetvalue. |
||
160 | /// if the grid is empty or the sum is 0, no modifications are performed. |
||
161 | Grid<T> normalized(const T targetvalue) const; |
||
1010 | werner | 162 | T* ptr(int x, int y) { return &(mData[y*mSizeX + x]); } ///< get a pointer to the element indexed by "x" and "y" |
373 | werner | 163 | inline double distance(const QPoint &p1, const QPoint &p2); ///< distance (metric) between p1 and p2 |
164 | const QPoint randomPosition() const; ///< returns a (valid) random position within the grid |
||
15 | Werner | 165 | private: |
77 | Werner | 166 | |
15 | Werner | 167 | T* mData; |
37 | Werner | 168 | T* mEnd; ///< pointer to 1 element behind the last |
49 | Werner | 169 | QRectF mRect; |
36 | Werner | 170 | float mCellsize; ///< size of a cell in meter |
171 | int mSizeX; ///< count of cells in x-direction |
||
172 | int mSizeY; ///< count of cells in y-direction |
||
173 | int mCount; ///< total number of cells in the grid |
||
15 | Werner | 174 | }; |
175 | |||
1067 | werner | 176 | |
15 | Werner | 177 | typedef Grid<float> FloatGrid; |
178 | |||
1008 | werner | 179 | enum GridViewType { GridViewRainbow=0, GridViewRainbowReverse=1, GridViewGray=2, GridViewGrayReverse=3, GridViewHeat=4, |
1040 | werner | 180 | GridViewGreens=5, GridViewReds=6, GridViewBlues=7, |
880 | werner | 181 | GridViewBrewerDiv=10, GridViewBrewerQual=11, GridViewTerrain=12, GridViewCustom=14 }; |
643 | werner | 182 | |
438 | werner | 183 | /** @class GridRunner is a helper class to iterate over a rectangular fraction of a grid |
184 | */ |
||
185 | template <class T> |
||
186 | class GridRunner { |
||
187 | public: |
||
650 | werner | 188 | // constructors with a QRectF (metric coordinates) |
617 | werner | 189 | GridRunner(Grid<T> &target_grid, const QRectF &rectangle) {setup(&target_grid, rectangle);} |
190 | GridRunner(const Grid<T> &target_grid, const QRectF &rectangle) {setup(&target_grid, rectangle);} |
||
191 | GridRunner(Grid<T> *target_grid, const QRectF &rectangle) {setup(target_grid, rectangle);} |
||
650 | werner | 192 | // constructors with a QRect (indices within the grid) |
193 | GridRunner(Grid<T> &target_grid, const QRect &rectangle) {setup(&target_grid, rectangle);} |
||
194 | GridRunner(const Grid<T> &target_grid, const QRect &rectangle) {setup(&target_grid, rectangle);} |
||
195 | GridRunner(Grid<T> *target_grid, const QRect &rectangle) {setup(target_grid, rectangle);} |
||
914 | werner | 196 | GridRunner(Grid<T> *target_grid) {setup(target_grid, target_grid->rectangle()); } |
438 | werner | 197 | T* next(); ///< to to next element, return NULL if finished |
1157 | werner | 198 | /// return the current element, or NULL |
662 | werner | 199 | T* current() const { return mCurrent; } |
1157 | werner | 200 | /// return the first element |
201 | T* first() const { return mFirst; } |
||
202 | /// return the last element (not one element behind the last element!) |
||
203 | T* last() const { return mLast; } |
||
204 | /// checks if the state of the GridRunner is valid, returns false if out of scope |
||
1010 | werner | 205 | bool isValid() const {return mCurrent>=mFirst && mCurrent<=mLast; } |
902 | werner | 206 | /// return the (index) - coordinates of the current position in the grid |
207 | QPoint currentIndex() const { return mGrid->indexOf(mCurrent); } |
||
208 | /// return the coordinates of the cell center point of the current position in the grid. |
||
209 | QPointF currentCoord() const {return mGrid->cellCenterPoint(mGrid->indexOf(mCurrent));} |
||
650 | werner | 210 | void reset() { mCurrent = mFirst-1; mCurrentCol = -1; } |
1010 | werner | 211 | /// set the internal pointer to the pixel at index 'new_index'. The index is relative to the base grid! |
212 | void setPosition(QPoint new_index) { if (mGrid->isIndexValid(new_index)) mCurrent = const_cast<Grid<T> *>(mGrid)->ptr(new_index.x(), new_index.y()); else mCurrent=0; } |
||
650 | werner | 213 | // helpers |
214 | /// fill array with pointers to neighbors (north, east, west, south) |
||
215 | /// or Null-pointers if out of range. |
||
216 | /// the target array (rArray) is not checked and must be valid! |
||
217 | void neighbors4(T** rArray); |
||
218 | void neighbors8(T** rArray); |
||
438 | werner | 219 | private: |
617 | werner | 220 | void setup(const Grid<T> *target_grid, const QRectF &rectangle); |
650 | werner | 221 | void setup(const Grid<T> *target_grid, const QRect &rectangle); |
902 | werner | 222 | const Grid<T> *mGrid; |
650 | werner | 223 | T* mFirst; // points to the first element of the grid |
224 | T* mLast; // points to the last element of the grid |
||
438 | werner | 225 | T* mCurrent; |
226 | size_t mLineLength; |
||
227 | size_t mCols; |
||
984 | werner | 228 | int mCurrentCol; |
438 | werner | 229 | }; |
230 | |||
646 | werner | 231 | /** @class Vector3D is a simple 3d vector. |
232 | QVector3D (from Qt) is in QtGui so we needed a replacement. |
||
233 | */ |
||
234 | class Vector3D |
||
235 | { |
||
236 | public: |
||
237 | Vector3D(): mX(0.), mY(0.), mZ(0.) {} |
||
238 | Vector3D(const double x, const double y, const double z): mX(x), mY(y), mZ(z) {} |
||
239 | double x() const { return mX; } ///< get x-coordinate |
||
240 | double y() const { return mY; } ///< get y-coordinate |
||
241 | double z() const { return mZ; } ///< get z-coordinate |
||
242 | // set variables |
||
243 | void setX(const double x) { mX=x; } ///< set value of the x-coordinate |
||
244 | void setY(const double y) { mY=y; } ///< set value of the y-coordinate |
||
245 | void setZ(const double z) { mZ=z; } ///< set value of the z-coordinate |
||
246 | private: |
||
247 | double mX; |
||
248 | double mY; |
||
249 | double mZ; |
||
250 | }; |
||
438 | werner | 251 | |
33 | Werner | 252 | // copy constructor |
253 | template <class T> |
||
254 | Grid<T>::Grid(const Grid<T>& toCopy) |
||
255 | { |
||
40 | Werner | 256 | mData = 0; |
50 | Werner | 257 | mRect = toCopy.mRect; |
1088 | werner | 258 | setup(toCopy.metricRect(), toCopy.cellsize()); |
259 | //setup(toCopy.cellsize(), toCopy.sizeX(), toCopy.sizeY()); |
||
33 | Werner | 260 | const T* end = toCopy.end(); |
261 | T* ptr = begin(); |
||
262 | for (T* i= toCopy.begin(); i!=end; ++i, ++ptr) |
||
263 | *ptr = *i; |
||
264 | } |
||
22 | Werner | 265 | |
33 | Werner | 266 | // normalize function |
32 | Werner | 267 | template <class T> |
33 | Werner | 268 | Grid<T> Grid<T>::normalized(const T targetvalue) const |
32 | Werner | 269 | { |
33 | Werner | 270 | Grid<T> target(*this); |
271 | T total = sum(); |
||
272 | T multiplier; |
||
273 | if (total) |
||
274 | multiplier = targetvalue / total; |
||
275 | else |
||
276 | return target; |
||
277 | for (T* p=target.begin();p!=target.end();++p) |
||
278 | *p *= multiplier; |
||
40 | Werner | 279 | return target; |
33 | Werner | 280 | } |
281 | |||
282 | |||
283 | template <class T> |
||
284 | Grid<T> Grid<T>::averaged(const int factor, const int offsetx, const int offsety) const |
||
285 | { |
||
32 | Werner | 286 | Grid<T> target; |
287 | target.setup(cellsize()*factor, sizeX()/factor, sizeY()/factor); |
||
288 | int x,y; |
||
289 | T sum=0; |
||
290 | target.initialize(sum); |
||
291 | // sum over array of 2x2, 3x3, 4x4, ... |
||
292 | for (x=offsetx;x<mSizeX;x++) |
||
293 | for (y=offsety;y<mSizeY;y++) { |
||
294 | target.valueAtIndex((x-offsetx)/factor, (y-offsety)/factor) += constValueAtIndex(x,y); |
||
295 | } |
||
296 | // divide |
||
297 | double fsquare = factor*factor; |
||
298 | for (T* p=target.begin();p!=target.end();++p) |
||
299 | *p /= fsquare; |
||
300 | return target; |
||
301 | } |
||
22 | Werner | 302 | |
36 | Werner | 303 | |
27 | Werner | 304 | template <class T> |
33 | Werner | 305 | T& Grid<T>::valueAt(const float x, const float y) |
306 | { |
||
307 | return valueAtIndex( indexAt(QPointF(x,y)) ); |
||
308 | } |
||
36 | Werner | 309 | |
33 | Werner | 310 | template <class T> |
311 | const T& Grid<T>::constValueAt(const float x, const float y) const |
||
312 | { |
||
313 | return constValueAtIndex( indexAt(QPointF(x,y)) ); |
||
314 | } |
||
36 | Werner | 315 | |
33 | Werner | 316 | template <class T> |
22 | Werner | 317 | T& Grid<T>::valueAt(const QPointF& posf) |
318 | { |
||
319 | return valueAtIndex( indexAt(posf) ); |
||
320 | } |
||
36 | Werner | 321 | |
33 | Werner | 322 | template <class T> |
323 | const T& Grid<T>::constValueAt(const QPointF& posf) const |
||
324 | { |
||
325 | return constValueAtIndex( indexAt(posf) ); |
||
326 | } |
||
22 | Werner | 327 | |
328 | template <class T> |
||
15 | Werner | 329 | Grid<T>::Grid() |
330 | { |
||
37 | Werner | 331 | mData = 0; mCellsize=0.f; |
332 | mEnd = 0; |
||
912 | werner | 333 | mSizeX=0; mSizeY=0; mCount=0; |
15 | Werner | 334 | } |
335 | |||
336 | template <class T> |
||
18 | Werner | 337 | bool Grid<T>::setup(const float cellsize, const int sizex, const int sizey) |
15 | Werner | 338 | { |
912 | werner | 339 | mSizeX=sizex; mSizeY=sizey; |
951 | werner | 340 | if (mRect.isNull()) // only set rect if not set before (e.g. by call to setup(QRectF, double)) |
50 | Werner | 341 | mRect.setCoords(0., 0., cellsize*sizex, cellsize*sizey); |
912 | werner | 342 | |
343 | if (mData) { |
||
344 | // test if we can re-use the allocated memory. |
||
951 | werner | 345 | if (mSizeX*mSizeY > mCount || mCellsize != cellsize) { |
912 | werner | 346 | // we cannot re-use the memory - create new data |
347 | delete[] mData; mData=NULL; |
||
348 | } |
||
349 | } |
||
350 | mCellsize=cellsize; |
||
15 | Werner | 351 | mCount = mSizeX*mSizeY; |
951 | werner | 352 | if (mCount==0) |
353 | return false; |
||
354 | if (mData==NULL) |
||
37 | Werner | 355 | mData = new T[mCount]; |
912 | werner | 356 | mEnd = &(mData[mCount]); |
357 | return true; |
||
15 | Werner | 358 | } |
359 | |||
360 | template <class T> |
||
22 | Werner | 361 | bool Grid<T>::setup(const QRectF& rect, const double cellsize) |
15 | Werner | 362 | { |
49 | Werner | 363 | mRect = rect; |
22 | Werner | 364 | int dx = int(rect.width()/cellsize); |
49 | Werner | 365 | if (mRect.left()+cellsize*dx<rect.right()) |
22 | Werner | 366 | dx++; |
367 | int dy = int(rect.height()/cellsize); |
||
49 | Werner | 368 | if (mRect.top()+cellsize*dy<rect.bottom()) |
22 | Werner | 369 | dy++; |
370 | return setup(cellsize, dx, dy); |
||
15 | Werner | 371 | } |
372 | |||
261 | werner | 373 | /** retrieve from the index from an element reversely from a pointer to that element. |
374 | The internal memory layout is (for dimx=6, dimy=3): |
||
375 | |||
376 | 6 7 8 9 10 11 |
||
377 | 12 13 14 15 16 17 |
||
378 | Note: north and south are reversed, thus the item with index 0 is located in the south-western edge of the grid! */ |
||
487 | werner | 379 | template <class T> inline |
717 | werner | 380 | QPoint Grid<T>::indexOf(const T* element) const |
25 | Werner | 381 | { |
487 | werner | 382 | // QPoint result(-1,-1); |
25 | Werner | 383 | if (element==NULL || element<mData || element>=end()) |
487 | werner | 384 | return QPoint(-1, -1); |
25 | Werner | 385 | int idx = element - mData; |
487 | werner | 386 | return QPoint(idx % mSizeX, idx / mSizeX); |
387 | // result.setX( idx % mSizeX); |
||
388 | // result.setY( idx / mSizeX); |
||
389 | // return result; |
||
25 | Werner | 390 | } |
22 | Werner | 391 | |
27 | Werner | 392 | template <class T> |
393 | T Grid<T>::max() const |
||
394 | { |
||
143 | Werner | 395 | T maxv = -std::numeric_limits<T>::max(); |
27 | Werner | 396 | T* p; |
397 | T* pend = end(); |
||
398 | for (p=begin(); p!=pend;++p) |
||
399 | maxv = std::max(maxv, *p); |
||
400 | return maxv; |
||
401 | } |
||
402 | |||
33 | Werner | 403 | template <class T> |
404 | T Grid<T>::sum() const |
||
405 | { |
||
406 | T* pend = end(); |
||
407 | T total = 0; |
||
408 | for (T *p=begin(); p!=pend;++p) |
||
409 | total += *p; |
||
410 | return total; |
||
411 | } |
||
412 | |||
413 | template <class T> |
||
414 | T Grid<T>::avg() const |
||
415 | { |
||
416 | if (count()) |
||
417 | return sum() / T(count()); |
||
418 | else return 0; |
||
419 | } |
||
420 | |||
150 | iland | 421 | template <class T> |
391 | werner | 422 | void Grid<T>::add(const T& summand) |
423 | { |
||
424 | T* pend = end(); |
||
425 | for (T *p=begin(); p!=pend;*p+=summand,++p) |
||
426 | ; |
||
427 | } |
||
428 | |||
429 | template <class T> |
||
430 | void Grid<T>::multiply(const T& factor) |
||
431 | { |
||
432 | T* pend = end(); |
||
433 | for (T *p=begin(); p!=pend;*p*=factor,++p) |
||
1085 | werner | 434 | ; |
391 | werner | 435 | } |
436 | |||
1085 | werner | 437 | template <class T> |
438 | void Grid<T>::limit(const T min_value, const T max_value) |
||
439 | { |
||
440 | T* pend = end(); |
||
441 | for (T *p=begin(); p!=pend;++p) |
||
442 | *p = *p < min_value ? min_value : (*p>max_value? max_value : *p); |
||
443 | } |
||
391 | werner | 444 | |
445 | |||
1085 | werner | 446 | |
391 | werner | 447 | template <class T> |
150 | iland | 448 | void Grid<T>::wipe() |
449 | { |
||
450 | memset(mData, 0, mCount*sizeof(T)); |
||
451 | } |
||
452 | template <class T> |
||
453 | void Grid<T>::wipe(const T value) |
||
454 | { |
||
154 | werner | 455 | /* this does not work properly !!! */ |
153 | werner | 456 | if (sizeof(T)==sizeof(int)) { |
457 | float temp = value; |
||
458 | float *pf = &temp; |
||
459 | |||
460 | memset(mData, *((int*)pf), mCount*sizeof(T)); |
||
461 | } else |
||
150 | iland | 462 | initialize(value); |
463 | } |
||
464 | |||
373 | werner | 465 | template <class T> |
1083 | werner | 466 | Grid<double> *Grid<T>::toDouble() const |
467 | { |
||
468 | Grid<double> *g = new Grid<double>(); |
||
1088 | werner | 469 | g->setup(metricRect(), cellsize()); |
1083 | werner | 470 | if (g->isEmpty()) |
471 | return g; |
||
472 | double *dp = g->begin(); |
||
473 | for (T *p=begin(); p!=end(); ++p, ++dp) |
||
474 | *dp = *p; |
||
475 | return g; |
||
476 | } |
||
477 | |||
478 | template <class T> |
||
373 | werner | 479 | double Grid<T>::distance(const QPoint &p1, const QPoint &p2) |
480 | { |
||
481 | QPointF fp1=cellCenterPoint(p1); |
||
482 | QPointF fp2=cellCenterPoint(p2); |
||
483 | double distance = sqrt( (fp1.x()-fp2.x())*(fp1.x()-fp2.x()) + (fp1.y()-fp2.y())*(fp1.y()-fp2.y())); |
||
484 | return distance; |
||
485 | } |
||
486 | |||
487 | template <class T> |
||
488 | const QPoint Grid<T>::randomPosition() const |
||
489 | { |
||
1164 | werner | 490 | return QPoint(irandom(0,mSizeX), irandom(0, mSizeY)); |
373 | werner | 491 | } |
438 | werner | 492 | |
373 | werner | 493 | //////////////////////////////////////////////////////////// |
438 | werner | 494 | // grid runner |
495 | //////////////////////////////////////////////////////////// |
||
496 | template <class T> |
||
650 | werner | 497 | void GridRunner<T>::setup(const Grid<T> *target_grid, const QRect &rectangle) |
438 | werner | 498 | { |
650 | werner | 499 | QPoint upper_left = rectangle.topLeft(); |
651 | werner | 500 | // due to the strange behavior of QRect::bottom() and right(): |
650 | werner | 501 | QPoint lower_right = rectangle.bottomRight(); |
617 | werner | 502 | mCurrent = const_cast<Grid<T> *>(target_grid)->ptr(upper_left.x(), upper_left.y()); |
650 | werner | 503 | mFirst = mCurrent; |
585 | werner | 504 | mCurrent--; // point to first element -1 |
617 | werner | 505 | mLast = const_cast<Grid<T> *>(target_grid)->ptr(lower_right.x()-1, lower_right.y()-1); |
438 | werner | 506 | mCols = lower_right.x() - upper_left.x(); // |
617 | werner | 507 | mLineLength = target_grid->sizeX() - mCols; |
585 | werner | 508 | mCurrentCol = -1; |
902 | werner | 509 | mGrid = target_grid; |
585 | werner | 510 | // qDebug() << "GridRunner: rectangle:" << rectangle |
511 | // << "upper_left:" << target_grid.cellCenterPoint(target_grid.indexOf(mCurrent)) |
||
512 | // << "lower_right:" << target_grid.cellCenterPoint(target_grid.indexOf(mLast)); |
||
438 | werner | 513 | } |
514 | |||
515 | template <class T> |
||
650 | werner | 516 | void GridRunner<T>::setup(const Grid<T> *target_grid, const QRectF &rectangle_metric) |
517 | { |
||
518 | QRect rect(target_grid->indexAt(rectangle_metric.topLeft()), |
||
519 | target_grid->indexAt(rectangle_metric.bottomRight()) ); |
||
520 | setup (target_grid, rect); |
||
521 | } |
||
522 | |||
523 | template <class T> |
||
438 | werner | 524 | T* GridRunner<T>::next() |
525 | { |
||
526 | if (mCurrent>mLast) |
||
527 | return NULL; |
||
528 | mCurrent++; |
||
529 | mCurrentCol++; |
||
585 | werner | 530 | |
1031 | werner | 531 | if (mCurrentCol >= int(mCols)) { |
438 | werner | 532 | mCurrent += mLineLength; // skip to next line |
533 | mCurrentCol = 0; |
||
534 | } |
||
585 | werner | 535 | if (mCurrent>mLast) |
536 | return NULL; |
||
537 | else |
||
538 | return mCurrent; |
||
438 | werner | 539 | } |
540 | |||
650 | werner | 541 | template <class T> |
656 | werner | 542 | /// get pointers the the 4-neighborhood |
1037 | werner | 543 | /// north, east, west, south |
803 | werner | 544 | /// 0-pointers are returned for edge pixels. |
650 | werner | 545 | void GridRunner<T>::neighbors4(T** rArray) |
546 | { |
||
547 | // north: |
||
651 | werner | 548 | rArray[0] = mCurrent + mCols + mLineLength > mLast?0: mCurrent + mCols + mLineLength; |
650 | werner | 549 | // south: |
651 | werner | 550 | rArray[3] = mCurrent - (mCols + mLineLength) < mFirst?0: mCurrent - (mCols + mLineLength); |
650 | werner | 551 | // east / west |
1157 | werner | 552 | rArray[1] = mCurrentCol+1<int(mCols)? mCurrent + 1 : 0; |
656 | werner | 553 | rArray[2] = mCurrentCol>0? mCurrent-1 : 0; |
650 | werner | 554 | } |
555 | |||
556 | /// get pointers to the 8-neighbor-hood |
||
557 | /// north/east/west/south/NE/NW/SE/SW |
||
803 | werner | 558 | /// 0-pointers are returned for edge pixels. |
650 | werner | 559 | template <class T> |
560 | void GridRunner<T>::neighbors8(T** rArray) |
||
561 | { |
||
562 | neighbors4(rArray); |
||
563 | // north-east |
||
656 | werner | 564 | rArray[4] = rArray[0] && rArray[1]? rArray[0]+1: 0; |
650 | werner | 565 | // north-west |
656 | werner | 566 | rArray[5] = rArray[0] && rArray[2]? rArray[0]-1: 0; |
650 | werner | 567 | // south-east |
656 | werner | 568 | rArray[6] = rArray[3] && rArray[1]? rArray[3]+1: 0; |
650 | werner | 569 | // south-west |
656 | werner | 570 | rArray[7] = rArray[3] && rArray[2]? rArray[3]-1: 0; |
650 | werner | 571 | |
572 | } |
||
573 | |||
438 | werner | 574 | //////////////////////////////////////////////////////////// |
36 | Werner | 575 | // global functions |
373 | werner | 576 | //////////////////////////////////////////////////////////// |
36 | Werner | 577 | |
578 | /// dumps a FloatGrid to a String. |
||
46 | Werner | 579 | /// rows will be y-lines, columns x-values. (see grid.cpp) |
599 | werner | 580 | QString gridToString(const FloatGrid &grid, const QChar sep=QChar(';'), const int newline_after=-1); |
36 | Werner | 581 | |
582 | /// creates and return a QImage from Grid-Data. |
||
583 | /// @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) |
||
584 | /// @param min_value, max_value min/max bounds for color calcuations. values outside bounds are limited to these values. defaults: min=0, max=1 |
||
585 | /// @param reverse if true, color ramps are inversed (to: min_value = white (black and white mode) or red (color mode). default = false. |
||
586 | /// @return a QImage with the Grids size of pixels. Pixel coordinates relate to the index values of the grid. |
||
587 | QImage gridToImage(const FloatGrid &grid, |
||
588 | bool black_white=false, |
||
589 | double min_value=0., double max_value=1., |
||
590 | bool reverse=false); |
||
591 | |||
556 | werner | 592 | |
285 | werner | 593 | /** load into 'rGrid' the content of the image pointed at by 'fileName'. |
594 | Pixels are converted to grey-scale and then transformend to a value ranging from 0..1 (black..white). |
||
595 | */ |
||
596 | bool loadGridFromImage(const QString &fileName, FloatGrid &rGrid); |
||
597 | |||
46 | Werner | 598 | /// template version for non-float grids (see also version for FloatGrid) |
599 | werner | 599 | /// @param sep string separator |
600 | /// @param newline_after if <>-1 a newline is added after every 'newline_after' data values |
||
36 | Werner | 601 | template <class T> |
599 | werner | 602 | QString gridToString(const Grid<T> &grid, const QChar sep=QChar(';'), const int newline_after=-1) |
36 | Werner | 603 | { |
604 | QString res; |
||
605 | QTextStream ts(&res); |
||
606 | |||
599 | werner | 607 | int newl_counter = newline_after; |
708 | werner | 608 | for (int y=grid.sizeY()-1;y>=0;--y){ |
46 | Werner | 609 | for (int x=0;x<grid.sizeX();x++){ |
599 | werner | 610 | ts << grid.constValueAtIndex(x,y) << sep; |
611 | if (--newl_counter==0) { |
||
612 | ts << "\r\n"; |
||
613 | newl_counter = newline_after; |
||
614 | } |
||
36 | Werner | 615 | } |
616 | ts << "\r\n"; |
||
617 | } |
||
618 | |||
619 | return res; |
||
620 | } |
||
46 | Werner | 621 | |
599 | werner | 622 | /// template version for non-float grids (see also version for FloatGrid) |
623 | /// @param valueFunction pointer to a function with the signature: QString func(const T&) : this should return a QString |
||
624 | /// @param sep string separator |
||
625 | /// @param newline_after if <>-1 a newline is added after every 'newline_after' data values |
||
626 | template <class T> |
||
627 | QString gridToString(const Grid<T> &grid, QString (*valueFunction)(const T& value), const QChar sep=QChar(';'), const int newline_after=-1 ) |
||
708 | werner | 628 | { |
629 | QString res; |
||
630 | QTextStream ts(&res); |
||
599 | werner | 631 | |
708 | werner | 632 | int newl_counter = newline_after; |
633 | for (int y=grid.sizeY()-1;y>=0;--y){ |
||
634 | for (int x=0;x<grid.sizeX();x++){ |
||
635 | ts << (*valueFunction)(grid.constValueAtIndex(x,y)) << sep; |
||
599 | werner | 636 | |
708 | werner | 637 | if (--newl_counter==0) { |
638 | ts << "\r\n"; |
||
639 | newl_counter = newline_after; |
||
640 | } |
||
641 | } |
||
599 | werner | 642 | ts << "\r\n"; |
643 | } |
||
708 | werner | 644 | |
645 | return res; |
||
599 | werner | 646 | } |
646 | werner | 647 | void modelToWorld(const Vector3D &From, Vector3D &To); |
599 | werner | 648 | |
649 | template <class T> |
||
650 | QString gridToESRIRaster(const Grid<T> &grid, QString (*valueFunction)(const T& value) ) |
||
651 | { |
||
646 | werner | 652 | Vector3D model(grid.metricRect().left(), grid.metricRect().top(), 0.); |
653 | Vector3D world; |
||
599 | werner | 654 | modelToWorld(model, world); |
607 | werner | 655 | QString result = QString("ncols %1\r\nnrows %2\r\nxllcorner %3\r\nyllcorner %4\r\ncellsize %5\r\nNODATA_value %6\r\n") |
599 | werner | 656 | .arg(grid.sizeX()) |
657 | .arg(grid.sizeY()) |
||
600 | werner | 658 | .arg(world.x(),0,'f').arg(world.y(),0,'f') |
599 | werner | 659 | .arg(grid.cellsize()).arg(-9999); |
694 | werner | 660 | QString line = gridToString(grid, valueFunction, QChar(' ')); // for special grids |
661 | return result + line; |
||
662 | } |
||
599 | werner | 663 | |
664 | template <class T> |
||
665 | QString gridToESRIRaster(const Grid<T> &grid ) |
||
666 | { |
||
646 | werner | 667 | Vector3D model(grid.metricRect().left(), grid.metricRect().top(), 0.); |
668 | Vector3D world; |
||
599 | werner | 669 | modelToWorld(model, world); |
683 | werner | 670 | QString result = QString("ncols %1\r\nnrows %2\r\nxllcorner %3\r\nyllcorner %4\r\ncellsize %5\r\nNODATA_value %6\r\n") |
599 | werner | 671 | .arg(grid.sizeX()) |
672 | .arg(grid.sizeY()) |
||
680 | werner | 673 | .arg(world.x(),0,'f').arg(world.y(),0,'f') |
599 | werner | 674 | .arg(grid.cellsize()).arg(-9999); |
694 | werner | 675 | QString line = gridToString(grid, QChar(' ')); // for normal grids (e.g. float) |
676 | return result + line; |
||
599 | werner | 677 | } |
678 | |||
15 | Werner | 679 | #endif // GRID_H |