Subversion Repositories public iLand

Rev

Rev 438 | Rev 453 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1
 
15 Werner 2
#ifndef GRID_H
3
#define GRID_H
4
 
22 Werner 5
#include <QtCore>
15 Werner 6
 
7
 
8
#include <stdexcept>
145 Werner 9
#include <limits>
150 iland 10
#include <cstring>
15 Werner 11
 
373 werner 12
#include "global.h"
13
 
247 werner 14
/** Grid class (template).
15 Werner 15
 
74 Werner 16
Orientation
17
The grid is oriented as typically coordinates on the northern hemisphere: greater y-values -> north, greater x-values-> east.
18
The projection is reversed for drawing on screen (Viewport):
19
          N
20
  (2/0) (2/1) (2/2)
21
E (1/0) (1/1) (2/1)  W
22
  (0/0) (1/0) (2/0)
23
          S
24
*/
15 Werner 25
template <class T>
26
class Grid {
27
public:
28
 
29
    Grid();
30
    Grid(int cellsize, int sizex, int sizey) { mData=0; setup(cellsize, sizex, sizey); }
58 Werner 31
    Grid(const QRectF rect_metric, const float cellsize) { mData=0; setup(rect_metric,cellsize); }
33 Werner 32
    // copy ctor
33
    Grid(const Grid<T>& toCopy);
105 Werner 34
    ~Grid() { clear(); }
35
    void clear() { if (mData) delete[] mData; mData=0; }
15 Werner 36
 
18 Werner 37
    bool setup(const float cellsize, const int sizex, const int sizey);
22 Werner 38
    bool setup(const QRectF& rect, const double cellsize);
75 Werner 39
    void initialize(const T& value) {for( T *p = begin();p!=end(); ++p) *p=value; }
150 iland 40
    void wipe(); ///< write 0-bytes with memcpy to the whole area
154 werner 41
    void wipe(const T value); ///< overwrite the whole area with "value" size of T must be the size of "int" ERRORNOUS!!!
15 Werner 42
 
145 Werner 43
    int sizeX() const { return mSizeX; }
44
    int sizeY() const { return mSizeY; }
45
    float metricSizeX() const { return mSizeX*mCellsize; }
46
    float metricSizeY() const { return mSizeY*mCellsize; }
49 Werner 47
    QRectF metricRect() const { return mRect; }
145 Werner 48
    float cellsize() const { return mCellsize; }
373 werner 49
    int count() const { return mCount; } ///< returns the number of elements of the grid
50
    bool isEmpty() const { return mData==NULL; } ///< returns false if the grid was not setup
32 Werner 51
    // operations
15 Werner 52
    // query
33 Werner 53
    /// access (const) with index variables. use int.
54
    inline const T& operator()(const int ix, const int iy) const { return constValueAtIndex(ix, iy); }
55
    /// access (const) using metric variables. use float.
56
    inline const T& operator()(const float x, const float y) const { return constValueAt(x, y); }
48 Werner 57
    inline const T& operator[] (const QPointF &p) const { return constValueAt(p); }
33 Werner 58
 
77 Werner 59
    inline T& valueAtIndex(const QPoint& pos); ///< value at position defined by indices (x,y)
33 Werner 60
    T& valueAtIndex(const int ix, const int iy) { return valueAtIndex(QPoint(ix,iy)); } ///< const value at position defined by indices (x,y)
285 werner 61
    T& valueAtIndex(const int index) {return mData[index]; } ///< get a ref ot value at (one-dimensional) index 'index'.
33 Werner 62
 
63
    const T& constValueAtIndex(const QPoint& pos) const; ///< value at position defined by a (integer) QPoint
32 Werner 64
    const T& constValueAtIndex(const int ix, const int iy) const { return constValueAtIndex(QPoint(ix,iy)); }
33 Werner 65
 
66
    T& valueAt(const QPointF& posf); ///< value at position defined by metric coordinates (QPointF)
67
    const T& constValueAt(const QPointF& posf) const; ///< value at position defined by metric coordinates (QPointF)
68
 
69
    T& valueAt(const float x, const float y); ///< value at position defined by metric coordinates (x,y)
70
    const T& constValueAt(const float x, const float y) const; ///< value at position defined by metric coordinates (x,y)
71
 
105 Werner 72
    bool coordValid(const float x, const float y) const { return x>=mRect.left() && x<mRect.right()  && y>=mRect.top() && y<mRect.bottom(); }
49 Werner 73
    bool coordValid(const QPointF &pos) const { return coordValid(pos.x(), pos.y()); }
75 Werner 74
 
55 Werner 75
    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)
373 werner 76
    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
77
    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
75 Werner 78
    /// force @param pos to contain valid indices with respect to this grid.
55 Werner 79
    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 80
    /// get the (metric) centerpoint of cell with index @p pos
81
    QPointF cellCenterPoint(const QPoint &pos) { return QPointF( (pos.x()+0.5)*mCellsize+mRect.left(), (pos.y()+0.5)*mCellsize + mRect.top());} ///< get metric coordinates of the cells center
82
    /// get the metric rectangle of the cell with index @pos
439 werner 83
    QRectF cellRect(const QPoint &pos) const { QRectF r( QPointF(mRect.left() + mCellsize*pos.x(), mRect.top() + pos.y()*mCellsize),
55 Werner 84
                                                   QSizeF(mCellsize, mCellsize)); return r; } ///< return coordinates of rect given by @param pos.
105 Werner 85
 
27 Werner 86
    inline  T* begin() const { return mData; } ///< get "iterator" pointer
37 Werner 87
    inline  T* end() const { return mEnd; } ///< get iterator end-pointer
27 Werner 88
    QPoint indexOf(T* element) const; ///< retrieve index (x/y) of the pointer element. returns -1/-1 if element is not valid.
89
    // special queries
33 Werner 90
    T max() const; ///< retrieve the maximum value of a grid
91
    T sum() const; ///< retrieve the sum of the grid
92
    T avg() const; ///< retrieve the average value of a grid
391 werner 93
    // modifying operations
94
    void add(const T& summand);
95
    void multiply(const T& factor);
33 Werner 96
    /// creates a grid with lower resolution and averaged cell values.
97
    /// @param factor factor by which grid size is reduced (e.g. 3 -> 3x3=9 pixels are averaged to 1 result pixel)
98
    /// @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)
99
    /// @return Grid with size sizeX()/factor x sizeY()/factor
100
    Grid<T> averaged(const int factor, const int offsetx=0, const int offsety=0) const;
101
    /// normalized returns a normalized grid, in a way that the sum()  = @param targetvalue.
102
    /// if the grid is empty or the sum is 0, no modifications are performed.
103
    Grid<T> normalized(const T targetvalue) const;
373 werner 104
    T* ptr(int x, int y) { return &(mData[y*mSizeX + x]); } ///< get a pointer to the element denoted by "x" and "y"
105
    inline double distance(const QPoint &p1, const QPoint &p2); ///< distance (metric) between p1 and p2
106
    const QPoint randomPosition() const; ///< returns a (valid) random position within the grid
15 Werner 107
private:
77 Werner 108
 
15 Werner 109
    T* mData;
37 Werner 110
    T* mEnd; ///< pointer to 1 element behind the last
49 Werner 111
    QRectF mRect;
36 Werner 112
    float mCellsize; ///< size of a cell in meter
113
    int mSizeX; ///< count of cells in x-direction
114
    int mSizeY; ///< count of cells in y-direction
115
    int mCount; ///< total number of cells in the grid
15 Werner 116
};
117
 
118
typedef Grid<float> FloatGrid;
119
 
438 werner 120
/** @class GridRunner is a helper class to iterate over a rectangular fraction of a grid
121
*/
122
template <class T>
123
class GridRunner {
124
public:
439 werner 125
    GridRunner(Grid<T> &target_grid, const QRectF &rectangle) {setup(target_grid, rectangle);}
126
    GridRunner(const Grid<T> &target_grid, const QRectF &rectangle) {setup(target_grid, rectangle);}
438 werner 127
    T* next(); ///< to to next element, return NULL if finished
128
private:
439 werner 129
    void setup(const Grid<T> &target_grid, const QRectF &rectangle);
438 werner 130
    T* mLast;
131
    T* mCurrent;
132
    size_t mLineLength;
133
    size_t mCols;
134
    size_t mCurrentCol;
135
};
136
 
137
 
33 Werner 138
// copy constructor
139
template <class T>
140
Grid<T>::Grid(const Grid<T>& toCopy)
141
{
40 Werner 142
    mData = 0;
50 Werner 143
    mRect = toCopy.mRect;
33 Werner 144
    setup(toCopy.cellsize(), toCopy.sizeX(), toCopy.sizeY());
145
    const T* end = toCopy.end();
146
    T* ptr = begin();
147
    for (T* i= toCopy.begin(); i!=end; ++i, ++ptr)
148
       *ptr = *i;
149
}
22 Werner 150
 
33 Werner 151
// normalize function
32 Werner 152
template <class T>
33 Werner 153
Grid<T> Grid<T>::normalized(const T targetvalue) const
32 Werner 154
{
33 Werner 155
    Grid<T> target(*this);
156
    T total = sum();
157
    T multiplier;
158
    if (total)
159
        multiplier = targetvalue / total;
160
    else
161
        return target;
162
    for (T* p=target.begin();p!=target.end();++p)
163
        *p *= multiplier;
40 Werner 164
    return target;
33 Werner 165
}
166
 
167
 
168
template <class T>
169
Grid<T> Grid<T>::averaged(const int factor, const int offsetx, const int offsety) const
170
{
32 Werner 171
    Grid<T> target;
172
    target.setup(cellsize()*factor, sizeX()/factor, sizeY()/factor);
173
    int x,y;
174
    T sum=0;
175
    target.initialize(sum);
176
    // sum over array of 2x2, 3x3, 4x4, ...
177
    for (x=offsetx;x<mSizeX;x++)
178
        for (y=offsety;y<mSizeY;y++) {
179
            target.valueAtIndex((x-offsetx)/factor, (y-offsety)/factor) += constValueAtIndex(x,y);
180
        }
181
    // divide
182
    double fsquare = factor*factor;
183
    for (T* p=target.begin();p!=target.end();++p)
184
        *p /= fsquare;
185
    return target;
186
}
22 Werner 187
 
15 Werner 188
template <class T>
22 Werner 189
T&  Grid<T>::valueAtIndex(const QPoint& pos)
190
{
75 Werner 191
    //if (isIndexValid(pos)) {
77 Werner 192
        return mData[pos.y()*mSizeX + pos.x()];
75 Werner 193
    //}
194
    //qCritical("Grid::valueAtIndex. invalid: %d/%d", pos.x(), pos.y());
195
    //return mData[0];
22 Werner 196
}
36 Werner 197
 
27 Werner 198
template <class T>
199
const T&  Grid<T>::constValueAtIndex(const QPoint& pos) const
200
{
75 Werner 201
    //if (isIndexValid(pos)) {
77 Werner 202
        return mData[pos.y()*mSizeX + pos.x()];
75 Werner 203
    //}
204
    //qCritical("Grid::constValueAtIndex. invalid: %d/%d", pos.x(), pos.y());
205
    //return mData[0];
27 Werner 206
}
22 Werner 207
 
208
template <class T>
33 Werner 209
T&  Grid<T>::valueAt(const float x, const float y)
210
{
211
    return valueAtIndex( indexAt(QPointF(x,y)) );
212
}
36 Werner 213
 
33 Werner 214
template <class T>
215
const T&  Grid<T>::constValueAt(const float x, const float y) const
216
{
217
    return constValueAtIndex( indexAt(QPointF(x,y)) );
218
}
36 Werner 219
 
33 Werner 220
template <class T>
22 Werner 221
T&  Grid<T>::valueAt(const QPointF& posf)
222
{
223
    return valueAtIndex( indexAt(posf) );
224
}
36 Werner 225
 
33 Werner 226
template <class T>
227
const T&  Grid<T>::constValueAt(const QPointF& posf) const
228
{
229
    return constValueAtIndex( indexAt(posf) );
230
}
22 Werner 231
 
232
template <class T>
15 Werner 233
Grid<T>::Grid()
234
{
37 Werner 235
    mData = 0; mCellsize=0.f;
236
    mEnd = 0;
15 Werner 237
}
238
 
239
template <class T>
18 Werner 240
bool Grid<T>::setup(const float cellsize, const int sizex, const int sizey)
15 Werner 241
{
37 Werner 242
    mSizeX=sizex; mSizeY=sizey; mCellsize=cellsize;
50 Werner 243
    if (mRect.isNull()) // only set rect if not set before
244
        mRect.setCoords(0., 0., cellsize*sizex, cellsize*sizey);
15 Werner 245
    mCount = mSizeX*mSizeY;
37 Werner 246
    if (mData) {
247
         delete[] mData; mData=NULL;
248
     }
15 Werner 249
   if (mCount>0)
37 Werner 250
        mData = new T[mCount];
251
   mEnd = &(mData[mCount]);
15 Werner 252
   return true;
253
}
254
 
255
template <class T>
22 Werner 256
bool Grid<T>::setup(const QRectF& rect, const double cellsize)
15 Werner 257
{
49 Werner 258
    mRect = rect;
22 Werner 259
    int dx = int(rect.width()/cellsize);
49 Werner 260
    if (mRect.left()+cellsize*dx<rect.right())
22 Werner 261
        dx++;
262
    int dy = int(rect.height()/cellsize);
49 Werner 263
    if (mRect.top()+cellsize*dy<rect.bottom())
22 Werner 264
        dy++;
265
    return setup(cellsize, dx, dy);
15 Werner 266
}
267
 
261 werner 268
/** retrieve from the index from an element reversely from a pointer to that element.
269
    The internal memory layout is (for dimx=6, dimy=3):
270
 
271
6  7  8  9  10 11
272
12 13 14 15 16 17
273
Note: north and south are reversed, thus the item with index 0 is located in the south-western edge of the grid! */
25 Werner 274
template <class T>
27 Werner 275
QPoint Grid<T>::indexOf(T* element) const
25 Werner 276
{
277
    QPoint result(-1,-1);
278
    if (element==NULL || element<mData || element>=end())
279
        return result;
280
    int idx = element - mData;
105 Werner 281
    result.setX( idx % mSizeX);
282
    result.setY( idx / mSizeX);
25 Werner 283
    return result;
284
}
22 Werner 285
 
27 Werner 286
template <class T>
287
T  Grid<T>::max() const
288
{
143 Werner 289
    T maxv = -std::numeric_limits<T>::max();
27 Werner 290
    T* p;
291
    T* pend = end();
292
    for (p=begin(); p!=pend;++p)
293
       maxv = std::max(maxv, *p);
294
    return maxv;
295
}
296
 
33 Werner 297
template <class T>
298
T  Grid<T>::sum() const
299
{
300
    T* pend = end();
301
    T total = 0;
302
    for (T *p=begin(); p!=pend;++p)
303
       total += *p;
304
    return total;
305
}
306
 
307
template <class T>
308
T  Grid<T>::avg() const
309
{
310
    if (count())
311
        return sum() / T(count());
312
    else return 0;
313
}
314
 
150 iland 315
template <class T>
391 werner 316
void Grid<T>::add(const T& summand)
317
{
318
    T* pend = end();
319
    for (T *p=begin(); p!=pend;*p+=summand,++p)
320
       ;
321
}
322
 
323
template <class T>
324
void Grid<T>::multiply(const T& factor)
325
{
326
    T* pend = end();
327
    for (T *p=begin(); p!=pend;*p*=factor,++p)
328
       ;
329
}
330
 
331
 
332
 
333
template <class T>
150 iland 334
void  Grid<T>::wipe()
335
{
336
    memset(mData, 0, mCount*sizeof(T));
337
}
338
template <class T>
339
void  Grid<T>::wipe(const T value)
340
{
154 werner 341
    /* this does not work properly !!! */
153 werner 342
    if (sizeof(T)==sizeof(int)) {
343
        float temp = value;
344
        float *pf = &temp;
345
 
346
        memset(mData, *((int*)pf), mCount*sizeof(T));
347
    } else
150 iland 348
        initialize(value);
349
}
350
 
373 werner 351
template <class T>
352
double Grid<T>::distance(const QPoint &p1, const QPoint &p2)
353
{
354
    QPointF fp1=cellCenterPoint(p1);
355
    QPointF fp2=cellCenterPoint(p2);
356
    double distance = sqrt( (fp1.x()-fp2.x())*(fp1.x()-fp2.x()) + (fp1.y()-fp2.y())*(fp1.y()-fp2.y()));
357
    return distance;
358
}
359
 
360
template <class T>
361
const QPoint Grid<T>::randomPosition() const
362
{
363
    return QPoint(irandom(0,mSizeX-1), irandom(0, mSizeY-1));
364
}
438 werner 365
 
373 werner 366
////////////////////////////////////////////////////////////
438 werner 367
// grid runner
368
////////////////////////////////////////////////////////////
369
template <class T>
439 werner 370
void GridRunner<T>::setup(const Grid<T> &target_grid, const QRectF &rectangle)
438 werner 371
{
372
    QPoint upper_left = target_grid.indexAt(rectangle.topLeft());
373
    QPoint lower_right = target_grid.indexAt(rectangle.bottomRight());
439 werner 374
    mCurrent = const_cast<Grid<T> &>(target_grid).ptr(upper_left.x(), upper_left.y());
375
    mLast = const_cast<Grid<T> &>(target_grid).ptr(lower_right.x()-1, lower_right.y()-1);
438 werner 376
    mCols = lower_right.x() - upper_left.x(); //
377
    mLineLength =  target_grid.sizeX() - mCols;
378
    mCurrentCol = 0;
379
}
380
 
381
template <class T>
382
T* GridRunner<T>::next()
383
{
384
    if (mCurrent>mLast)
385
        return NULL;
386
    T* t = mCurrent;
387
    mCurrent++;
388
    mCurrentCol++;
389
    if (mCurrentCol >= mCols) {
390
        mCurrent += mLineLength; // skip to next line
391
        mCurrentCol = 0;
392
    }
393
    return t;
394
}
395
 
396
////////////////////////////////////////////////////////////
36 Werner 397
// global functions
373 werner 398
////////////////////////////////////////////////////////////
36 Werner 399
 
400
/// dumps a FloatGrid to a String.
46 Werner 401
/// rows will be y-lines, columns x-values. (see grid.cpp)
36 Werner 402
QString gridToString(const FloatGrid &grid);
403
 
404
/// creates and return a QImage from Grid-Data.
405
/// @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)
406
/// @param min_value, max_value min/max bounds for color calcuations. values outside bounds are limited to these values. defaults: min=0, max=1
407
/// @param reverse if true, color ramps are inversed (to: min_value = white (black and white mode) or red (color mode). default = false.
408
/// @return a QImage with the Grids size of pixels. Pixel coordinates relate to the index values of the grid.
409
QImage gridToImage(const FloatGrid &grid,
410
                   bool black_white=false,
411
                   double min_value=0., double max_value=1.,
412
                   bool reverse=false);
413
 
285 werner 414
/** load into 'rGrid' the content of the image pointed at by 'fileName'.
415
    Pixels are converted to grey-scale and then transformend to a value ranging from 0..1 (black..white).
416
  */
417
bool loadGridFromImage(const QString &fileName, FloatGrid &rGrid);
418
 
46 Werner 419
/// template version for non-float grids (see also version for FloatGrid)
36 Werner 420
template <class T>
46 Werner 421
        QString gridToString(const Grid<T> &grid)
36 Werner 422
{
423
    QString res;
424
    QTextStream ts(&res);
425
 
46 Werner 426
    for (int y=0;y<grid.sizeY();y++){
427
        for (int x=0;x<grid.sizeX();x++){
36 Werner 428
            ts << grid.constValueAtIndex(x,y) << ";";
429
        }
430
        ts << "\r\n";
431
    }
432
 
433
    return res;
434
}
46 Werner 435
 
15 Werner 436
#endif // GRID_H