tecorrec: Check for OpenGL and add includes/libs
[tecorrec.git] / geo / tcSrtmModel.cpp
blob593f393934eb02f48e39b299032b08ad4be25396
1 /***************************************************************************
2 * This file is part of Tecorrec. *
3 * Copyright 2008 James Hogan <james@albanarts.com> *
4 * *
5 * Tecorrec is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * Tecorrec is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with Tecorrec. If not, write to the Free Software Foundation, *
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
20 /**
21 * @file tcSrtmModel.cpp
22 * @brief SRTM elevation model.
25 #include "tcSrtmModel.h"
26 #include "tcSrtmCache.h"
27 #include "tcSrtmData.h"
29 #include <inttypes.h>
32 * Constructors + destructor
35 /// Default constructor.
36 tcSrtmModel::tcSrtmModel()
37 : m_cache(0)
41 /// Destructor.
42 tcSrtmModel::~tcSrtmModel()
44 delete m_cache;
48 * Main interface
51 /// Get information to allow alignment with actual samples.
52 void tcSrtmModel::sampleAlign(const tcGeo& swCorner, const tcGeo& neCorner, RenderState* state, int maxSamples)
54 state->swCorner = swCorner;
55 state->neCorner = neCorner;
56 state->moreAvailableLon = false;
57 state->moreAvailableLat = false;
59 tcSrtmData* data = 0;
60 if (0 != m_cache)
62 data = m_cache->findData(swCorner, neCorner);
63 if (data)
65 tcGeo resolution = data->sampleResolution();
66 maths::Vector<2,double> swSampleSpace = swCorner / resolution;
67 maths::Vector<2,double> neSampleSpace = neCorner / resolution;
68 maths::Vector<2,double> first(floor(swSampleSpace[0] + 1.0),
69 floor(swSampleSpace[1] + 1.0));
70 maths::Vector<2,double> last( ceil( neSampleSpace[0] - 1.0),
71 ceil( neSampleSpace[1] - 1.0));
72 state->samplesLon = 3 + (int)(last[0] - first[0]);
73 state->samplesLat = 3 + (int)(last[1] - first[1]);
74 state->swSample = swCorner + resolution*(first - swSampleSpace);
75 state->sampleDelta = resolution;
77 // Sample evenly
78 if (maxSamples >= 2)
80 if (state->samplesLon > maxSamples)
82 state->sampleDelta.setLon((neCorner.lon()-swCorner.lon()) / (maxSamples-1));
83 state->swSample.setLon(swCorner.lon() + state->sampleDelta.lon());
84 state->samplesLon = maxSamples;
85 state->moreAvailableLon = true;
87 if (state->samplesLat > maxSamples)
89 state->sampleDelta.setLat((neCorner.lat()-swCorner.lat()) / (maxSamples-1));
90 state->swSample.setLat(swCorner.lat() + state->sampleDelta.lat());
91 state->samplesLat = maxSamples;
92 state->moreAvailableLat = true;
95 return;
99 int samplesLon = (int)((neCorner.lon() - swCorner.lon())/(M_PI/180.0/60.0));
100 int samplesLat = (int)((neCorner.lat() - swCorner.lat())/(M_PI/180.0/60.0));
101 if (samplesLon > maxSamples)
103 state->moreAvailableLon = true;
105 if (samplesLat > maxSamples)
107 state->moreAvailableLat = true;
111 state->samplesLon = maxSamples;
112 state->samplesLat = maxSamples;
113 state->sampleDelta = (neCorner - swCorner)/(maxSamples-1);
114 state->swSample = swCorner + state->sampleDelta;
117 /// Get the altitude at a sample in a render state.
118 double tcSrtmModel::altitudeAt(const RenderState& state, int x, int y, tcGeo* outCoord, bool corrected, bool* accurate)
120 double lon;
121 if (x <= 0)
123 lon = state.swCorner.lon();
125 else if (x >= state.samplesLon - 1)
127 lon = state.neCorner.lon();
129 else
131 lon = state.swSample.lon() + state.sampleDelta.lon() * (x-1);
133 double lat;
134 if (y <= 0)
136 lat = state.swCorner.lat();
138 else if (y >= state.samplesLat - 1)
140 lat = state.neCorner.lat();
142 else
144 lat = state.swSample.lat() + state.sampleDelta.lat() * (y-1);
146 return altitudeAt(*outCoord = tcGeo(lon, lat), corrected, accurate);
149 /// Get the altitude at a coordinate.
150 double tcSrtmModel::altitudeAt(const tcGeo& coord, bool corrected, bool* accurate)
152 // Round down to nearest degree
153 tcSrtmData* data = 0;
154 if (0 != m_cache)
156 data = m_cache->loadData(coord);
158 if (0 != data)
160 return data->sampleAltitude(coord, corrected, accurate);
162 return 0.0;
165 /// Get the normal at a coordinate.
166 maths::Vector<3,float> tcSrtmModel::normalAt(const tcGeo& coord, bool corrected, bool* accurate)
168 if (0 != m_cache)
170 tcSrtmData* data = m_cache->loadData(coord);
171 if (0 != data)
173 // Sample altitudes a fixed angle in each direction.
174 const double radiusEarth = 6378.137e3;
175 tcGeo angRes = data->sampleResolution();
176 bool alta, xpa, xma, ypa, yma;
177 double alt = altitudeAt(coord, corrected, &alta);
178 double xp = altitudeAt(coord + tcGeo(angRes.lon()*0.5, 0.0), corrected, &xpa);
179 double xm = altitudeAt(coord - tcGeo(angRes.lon()*0.5, 0.0), corrected, &xma);
180 double yp = altitudeAt(coord + tcGeo(0.0, angRes.lat()*0.5), corrected, &ypa);
181 double ym = altitudeAt(coord - tcGeo(0.0, angRes.lat()*0.5), corrected, &yma);
182 double dx = xp-xm;
183 double dy = yp-ym;
184 if (0 != accurate)
186 *accurate = xpa && xma && ypa && yma;
188 maths::Vector<2,float> res((radiusEarth+alt) * angRes.lon() * cos(coord.lat()),
189 (radiusEarth+alt) * angRes.lat());
190 // (1.0f, 0.0f, dx/res[0]) x (0.0f, -1.0f, dy/res[1])
191 maths::Vector<3,float> norm(-dx/res[0], -dy/res[1], 1.0f);
192 norm.normalize();
193 return norm;
196 if (0 != accurate)
198 *accurate = false;
200 return maths::Vector<3,float>(0.0f, 0.0f, 1.0f);
203 /// Use raytracing to find how lit a point is.
204 float tcSrtmModel::litAt(const tcGeo& coord, const maths::Vector<3,float>& light, float angularRadius, bool corrected, bool* accurate)
206 if (0 != m_cache)
208 tcSrtmData* data = m_cache->loadData(coord);
209 if (0 != data)
211 // Sample altitudes a fixed angle in each direction.
212 const float radiusEarth = 6378.137e3;
213 tcGeo angRes = data->sampleResolution();
214 float distance = 0.0f;
215 float step = (angRes.lon() + angRes.lat()) / 4.0;
216 bool ac = true;
217 float result = 1.0f;
218 bool xa;
219 tcGeo cur = coord;
220 float alt = altitudeAt(cur, corrected, &xa);
221 ac = ac && xa;
222 Q_ASSERT(light[2] > 0.0);
223 while (alt < 8000.0)
225 // Move towards light source
226 cur.setLon(cur.lon() + step*light[0] / cos(cur.lat()));
227 cur.setLat(cur.lat() + step*light[1]);
228 alt += radiusEarth*step*light[2];
229 distance += radiusEarth*step;
230 // Check for collision
231 float x = altitudeAt(cur, corrected, &xa);
232 ac = ac && xa;
233 float flex = distance*angularRadius;
234 if (x >= alt + flex)
236 result = 0.0f;
237 break;
239 else if (x >= alt - flex)
241 float portion = (x - alt + flex) / (2.0f*flex);
242 if (result > portion)
244 result = portion;
247 // Can take bigger steps the further we are from the ground
248 // here we are assuming that the terrain isn't extremely steep
249 step = 0.5f * (alt - x + flex) / radiusEarth;
251 if (0 != accurate)
253 *accurate = ac;
255 return result;
258 if (0 != accurate)
260 *accurate = false;
262 return 1.0f;
265 /// Set the data set to use.
266 void tcSrtmModel::setDataSet(const QString& name)
268 delete m_cache;
269 if (!name.isEmpty())
271 m_cache = new tcSrtmCache(name);
272 if (0 != m_cache)
274 connect(m_cache, SIGNAL(progressing(const QString&)), this, SIGNAL(progressing(const QString&)));
277 else
279 m_cache = 0;
281 emit dataSetChanged();
284 /// Update any samples affected by the elevation field.
285 void tcSrtmModel::updateFromElevationData(const tcElevationData* elevation)
287 if (0 != m_cache)
289 m_cache->updateFromElevationData(elevation);
290 emit dataSetChanged();