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 | } |