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