Subversion Repositories public iLand

Rev

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

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