Subversion Repositories public iLand

Rev

Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
671 werner 1
/********************************************************************************************
2
**    iLand - an individual based forest landscape and disturbance model
3
**    http://iland.boku.ac.at
4
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
5
**
6
**    This program is free software: you can redistribute it and/or modify
7
**    it under the terms of the GNU General Public License as published by
8
**    the Free Software Foundation, either version 3 of the License, or
9
**    (at your option) any later version.
10
**
11
**    This program is distributed in the hope that it will be useful,
12
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
**    GNU General Public License for more details.
15
**
16
**    You should have received a copy of the GNU General Public License
17
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
********************************************************************************************/
19
 
642 werner 20
#include "global.h"
21
#include "dem.h"
22
 
23
#include "globalsettings.h"
24
#include "model.h"
25
 
26
#include "gisgrid.h"
27
 
881 werner 28
// from here: http://www.scratchapixel.com/lessons/3d-advanced-lessons/interpolation/bilinear-interpolation/
29
template<typename T>
30
T bilinear(
31
   const T &tx,
32
   const T &ty,
33
   const T &c00,
34
   const T &c10,
35
   const T &c01,
36
   const T &c11)
37
{
38
#if 1
39
    T a = c00 * (T(1) - tx) + c10 * tx;
40
    T b = c01 * (T(1) - tx) + c11 * tx;
41
    return a * (T(1) - ty) + b * ty;
42
#else
43
    return (T(1) - tx) * (T(1) - ty) * c00 +
44
        tx * (T(1) - ty) * c10 +
45
        (T(1) - tx) * ty * c01 +
46
        tx * ty * c11;
47
#endif
48
}
642 werner 49
 
50
/// loads a DEM from a ESRI style text file.
51
/// internally, the DEM has always a resolution of 10m
52
bool DEM::loadFromFile(const QString &fileName)
53
{
54
    if (!GlobalSettings::instance()->model())
55
        throw IException("DEM::create10mGrid: no valid model to retrieve height grid.");
56
 
57
    HeightGrid *h_grid = GlobalSettings::instance()->model()->heightGrid();
58
    if (!h_grid || h_grid->isEmpty())
59
        throw IException("GisGrid::create10mGrid: no valid height grid to copy grid size.");
60
 
61
    GisGrid gis_grid;
62
    if (!gis_grid.loadFromFile(fileName))
63
        throw IException(QString("Unable to load DEM file %1").arg(fileName));
64
    // create a grid with the same size as the height grid
65
    // (height-grid: 10m size, covering the full extent)
66
    clear();
67
    aspect_grid.clear();
68
    slope_grid.clear();
69
    view_grid.clear();
70
 
71
    setup(h_grid->metricRect(),h_grid->cellsize());
72
 
73
    const QRectF &world = GlobalSettings::instance()->model()->extent();
74
 
881 werner 75
    if (fmod(gis_grid.cellSize(), cellsize()) != 0) {
76
        QPointF p;
77
        // simple copy of the data
78
        for (int i=0;i<count();i++) {
79
            p = cellCenterPoint(indexOf(i));
80
            if (gis_grid.value(p) != gis_grid.noDataValue() && world.contains(p) )
81
                valueAtIndex(i) = gis_grid.value(p);
82
            else
83
                valueAtIndex(i) = -1;
84
        }
85
    } else {
86
        // bilinear approximation approach
87
        qDebug() << "DEM: built-in bilinear interpolation from cell size" << gis_grid.cellSize();
88
        int f = gis_grid.cellSize() / cellsize(); // size-factor
89
        initialize(-1.f);
90
        int ixmin = 10000000, iymin = 1000000, ixmax = -1, iymax = -1;
91
        for (int y=0;y<gis_grid.rows();++y)
92
            for (int x=0;x<gis_grid.cols(); ++x){
93
                Vector3D p3d = gis_grid.coord(x,y);
94
                if (world.contains(p3d.x(), p3d.y())) {
95
                    QPoint pt=indexAt(QPointF(p3d.x(), p3d.y()));
96
                    valueAt(p3d.x(), p3d.y()) = gis_grid.value(x,y);
97
                    ixmin = std::min(ixmin, pt.x()); ixmax=std::max(ixmax, pt.x());
98
                    iymin = std::min(iymin, pt.y()); iymax=std::max(iymax, pt.y());
99
                }
100
            }
101
        for (int y=iymin;y<=iymax-f;y+=f)
102
            for (int x=ixmin;x<=ixmax-f;x+=f){
103
                float c00 = valueAtIndex(x, y);
104
                float c10 = valueAtIndex(x+f, y);
105
                float c01 = valueAtIndex(x, y+f);
106
                float c11 = valueAtIndex(x+f, y+f);
107
                for (int my=0;my<f;++my)
108
                    for (int mx=0;mx<f;++mx)
109
                        valueAtIndex(x+mx, y+my) = bilinear<float>(mx/float(f), my/float(f), c00, c10, c01, c11);
110
            }
642 werner 111
    }
112
 
113
    return true;
114
}
115
 
116
/// calculate slope and aspect at a given point.
117
/// results are params per reference.
118
/// returns the height at point (x/y)
119
/// calculation follows: Burrough, P. A. and McDonell, R.A., 1998.Principles of Geographical Information Systems.(Oxford University Press, New York), p. 190.
120
/// http://uqu.edu.sa/files2/tiny_mce/plugins/filemanager/files/4280125/Principles%20of%20Geographical%20Information%20Systems.pdf
654 werner 121
/// @param point metric coordinates of point to derive orientation
912 werner 122
/// @param rslope_angle RESULTING (passed by reference) slope angle as percentage (i.e: 1:=45 degrees)
654 werner 123
/// @param rslope_aspect RESULTING slope direction in degrees (0: North, 90: east, 180: south, 270: west)
1009 werner 124
float DEM::orientation(const QPointF &point, float &rslope_angle, float &rslope_aspect) const
642 werner 125
{
126
    QPoint pt = indexAt(point);
127
    if (pt.x()>0 && pt.x()<sizeX()+1 && pt.y()>0 && pt.y()<sizeY()-1) {
1009 werner 128
        float *p = const_cast<DEM*>(this)->ptr(pt.x(), pt.y());
642 werner 129
        float z2 = *(p-sizeX());
130
        float z4 = *(p-1);
131
        float z6 = *(p+1);
132
        float z8 = *(p+sizeX());
133
        float g = (-z4 + z6) / (2*cellsize());
134
        float h = (z2 - z8) / (2*cellsize());
135
 
136
        if (z2<=0. || z4<=0. || z6<=0. || z8<=0) {
137
            rslope_angle = 0.;
138
            rslope_aspect = 0.;
139
            return *p;
140
        }
141
        rslope_angle = sqrt(g*g + h*h);
142
        // atan2: returns -pi : +pi
143
        // North: -pi/2, east: 0, south: +pi/2, west: -pi/+pi
144
        float aspect = atan2(-h, -g);
145
        // transform to degree:
146
        // north: 0, east: 90, south: 180, west: 270
147
        aspect = aspect * 180. / M_PI + 360. + 90.;
781 werner 148
        aspect = fmod(aspect, 360.f);
642 werner 149
 
150
        rslope_aspect = aspect;
151
        return *p;
152
    } else {
153
        rslope_angle = 0.;
154
        rslope_aspect = 0.;
155
        return 0.;
156
    }
157
}
158
 
1009 werner 159
void DEM::createSlopeGrid() const
642 werner 160
{
161
    if (slope_grid.isEmpty()) {
162
        // setup custom grids with the same size as this DEM
163
        slope_grid.setup(*this);
164
        view_grid.setup(*this);
165
        aspect_grid.setup(*this);
166
    } else {
167
        return;
168
    }
169
    float *slope = slope_grid.begin();
170
    float *view = view_grid.begin();
171
    float *aspect = aspect_grid.begin();
172
 
912 werner 173
    // use fixed values for azimuth (315) and angle (45 deg) and calculate
642 werner 174
    // norm vectors
175
    float sun_x = cos(315. * M_PI/180.) * cos(45.*M_PI/180.);
176
    float sun_y = sin(315. * M_PI/180.) * cos(45.*M_PI/180.);
177
    float sun_z = sin(45.*M_PI/180.);
178
 
179
    float a_x, a_y, a_z;
180
    for (float *p = begin(); p!=end(); ++p, ++slope, ++view, ++aspect) {
181
        QPointF pt = cellCenterPoint(indexOf(p));
182
        float height = orientation(pt, *slope, *aspect);
183
        // calculate the view value:
184
        if (height>0) {
185
            float h = atan(*slope);
186
            a_x = cos(*aspect * M_PI/180.) * cos(h);
187
            a_y = sin(*aspect * M_PI/180.) * cos(h);
188
            a_z = sin(h);
189
 
190
            // use the scalar product to calculate the angle, and then
191
            // transform from [-1,1] to [0,1]
192
            *view = (a_x*sun_x + a_y*sun_y + a_z*sun_z + 1.)/2.;
193
        } else {
194
            *view = 0.;
195
        }
196
    }
197
 
198
}