]> git.mxchange.org Git - flightgear.git/blob - src/WeatherCM/FGLocalWeatherDatabase.cpp
6a91b4508af76f67a96d488f056b91a7ad8b86c4
[flightgear.git] / src / WeatherCM / FGLocalWeatherDatabase.cpp
1 /*****************************************************************************
2
3  Module:       FGLocalWeatherDatabase.cpp
4  Author:       Christian Mayer
5  Date started: 28.05.99
6  Called by:    main program
7
8  -------- Copyright (C) 1999 Christian Mayer (fgfs@christianmayer.de) --------
9
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU General Public License as published by the Free Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  version.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  details.
19
20  You should have received a copy of the GNU General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA  02111-1307, USA.
23
24  Further information about the GNU General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26
27 FUNCTIONAL DESCRIPTION
28 ------------------------------------------------------------------------------
29 Database for the local weather
30 This database is the only one that gets called from FG
31
32 HISTORY
33 ------------------------------------------------------------------------------
34 28.05.1999 Christian Mayer      Created
35 16.06.1999 Durk Talsma          Portability for Linux
36 20.06.1999 Christian Mayer      added lots of consts
37 11.10.1999 Christian Mayer      changed set<> to map<> on Bernie Bright's 
38                                 suggestion
39 19.10.1999 Christian Mayer      change to use PLIB's sg instead of Point[2/3]D
40                                 and lots of wee code cleaning
41 *****************************************************************************/
42
43 /****************************************************************************/
44 /* INCLUDES                                                                 */
45 /****************************************************************************/
46 #include <Include/compiler.h>
47 #include <Include/fg_constants.h>
48
49 #include <Aircraft/aircraft.hxx>
50
51 #include "FGLocalWeatherDatabase.h"
52 #include "FGVoronoi.h"
53
54 #include "FGWeatherParse.h"
55
56 /****************************************************************************/
57 /********************************** CODE ************************************/
58 /****************************************************************************/
59
60 /****************************************************************************/
61 /* return the index (better: ID) of the area with point p                   */
62 /****************************************************************************/
63 unsigned int FGLocalWeatherDatabase::AreaWith(const sgVec2& p) const
64 {
65     
66     for (FGMicroWeatherList::size_type i = 0; i != WeatherAreas.size(); i++)
67     {
68         if (WeatherAreas[i].hasPoint(p) == true)
69             return i+1;
70     }
71
72     return 0;   //nothing found
73 }
74
75 /****************************************************************************/
76 /* make tiles out of points on a 2D plane                                   */
77 /****************************************************************************/
78 void FGLocalWeatherDatabase::tileLocalWeather(const FGPhysicalProperties2DVector& EntryList)
79 {
80     FGVoronoiInputList input;
81
82     for (FGPhysicalProperties2DVectorConstIt it1 = EntryList.begin(); it1 != EntryList.end(); it1++)
83         input.push_back(FGVoronoiInput(it1->p, *it1));
84
85     FGVoronoiOutputList output = Voronoiate(input);
86
87     for (FGVoronoiOutputList::iterator it2 = output.begin(); it2 != output.end(); it2++)
88         WeatherAreas.push_back(FGMicroWeather(it2->value, it2->boundary));
89 }
90
91 FGLocalWeatherDatabase* FGLocalWeatherDatabase::theFGLocalWeatherDatabase = 0;
92 FGLocalWeatherDatabase *WeatherDatabase;
93
94 void FGLocalWeatherDatabase::init(const WeatherPrecision visibility, const DatabaseWorkingType type)
95 {
96     cerr << "Initializing FGLocalWeatherDatabase\n";
97     cerr << "-----------------------------------\n";
98
99     if (theFGLocalWeatherDatabase)
100     {
101         //FG_LOG( FG_GENERAL, FG_ALERT, "Error: only one local weather allowed" );
102         cerr << "Error: only one local weather allowed";
103         exit(-1);
104     }
105
106     setWeatherVisibility(visibility);
107
108     DatabaseStatus = type;
109     global = 0;     //just get sure...
110
111     Thunderstorm = false;
112     //I don't need to set theThunderstorm as Thunderstorm == false
113
114     switch(DatabaseStatus)
115     {
116     case use_global:
117         {
118             global = new FGGlobalWeatherDatabase;       //initialize GlobalDatabase
119             global->setDatabaseStatus(FGGlobalWeatherDatabase_working);
120             tileLocalWeather(global->getAll(last_known_position, WeatherVisibility, 3));
121         }
122         break;
123
124     case use_internet:
125         {
126             FGWeatherParse parsed_data;
127
128             parsed_data.input( "weather/current.gz" );
129             global = new FGGlobalWeatherDatabase;       //initialize GlobalDatabase
130             global->setDatabaseStatus(FGGlobalWeatherDatabase_working);
131
132             // fill the database
133             for (unsigned int i = 0; i != parsed_data.stored_stations(); i++) 
134             {
135                 global->add( parsed_data.getFGPhysicalProperties2D(i) );
136                 //cerr << parsed_data.getFGPhysicalProperties2D(i);
137
138                 if ( (i%100) == 0)
139                     cerr << ".";
140             }
141             cerr << "\n";
142
143             //and finally tile it
144             tileLocalWeather(global->getAll(last_known_position, WeatherVisibility, 3));
145             cerr << "Finished weather init.\n";
146
147         }
148         break;
149
150     case distant:
151         cerr << "FGLocalWeatherDatabase error: Distant database isn't implemented yet!\n";
152         cerr << "  using random mode instead!\n";
153     case random:
154     case manual:
155     case default_mode:
156         {
157
158             vector<sgVec2Wrap> emptyList;
159             WeatherAreas.push_back(FGMicroWeather(FGPhysicalProperties2D(), emptyList));   //in these cases I've only got one tile
160         }
161         break;
162
163     default:
164         cerr << "FGLocalWeatherDatabase error: Unknown database type specified!\n";
165     };
166 }
167
168 FGLocalWeatherDatabase::~FGLocalWeatherDatabase()
169 {
170     //Tidying up:
171
172     //delete every stored area
173     WeatherAreas.erase(WeatherAreas.begin(), WeatherAreas.end());
174
175     //delete global database if necessary
176     if (DatabaseStatus == use_global)
177         delete global;
178 }
179
180 /****************************************************************************/
181 /* reset the whole database                                                 */
182 /****************************************************************************/
183 void FGLocalWeatherDatabase::reset(const DatabaseWorkingType type)
184 {
185     //delete global database if necessary
186     if ((DatabaseStatus == use_global) && (type != use_global))
187         delete global;
188
189     DatabaseStatus = type;
190     if (DatabaseStatus == use_global)
191         tileLocalWeather(global->getAll(last_known_position, WeatherVisibility, 3));
192
193     //delete every stored area
194     WeatherAreas.erase(WeatherAreas.begin(), WeatherAreas.end());
195 }
196
197 /****************************************************************************/
198 /* update the database. Since the last call we had dt seconds               */
199 /****************************************************************************/
200 void FGLocalWeatherDatabase::update(const WeatherPrecision dt)
201 {
202     if (DatabaseStatus==use_global)
203         global->update(dt);
204 }
205
206 void FGLocalWeatherDatabase::update(const sgVec3& p) //position has changed
207 {
208     sgCopyVec3(last_known_position, p);
209
210     if ( AreaWith(p) == 0 )
211     {   //I have moved out of my local area...
212
213         //now I should erase all my areas and get the new ones
214         //but that takes too long :-( I have to take care about that soon
215     }
216
217     //uncomment this when you are using the GlobalDatabase
218     /*
219     cerr << "****\nupdate(p) inside\n";
220     cerr << "Parameter: " << p[0] << "/" << p[1] << "/" << p[2] << "\n";
221     sgVec2 p2d;
222     sgSetVec2( p2d, p[0], p[1] );
223     cerr << FGPhysicalProperties2D(global->get(p2d), p2d);
224     cerr << "****\n";
225     */
226 }
227
228 void FGLocalWeatherDatabase::update(const sgVec3& p, const WeatherPrecision dt)   //time and/or position has changed
229 {
230     sgCopyVec3(last_known_position, p);
231
232     if ( AreaWith(p) == 0 )
233     {   //I have moved out of my local area...
234
235         //now I should erase all my areas and get the new ones
236         //but that takes too long :-( I have to take care about that soon
237     }
238
239     if (DatabaseStatus==use_global)
240         global->update(dt);
241 }
242
243 /****************************************************************************/
244 /* Get the physical properties on the specified point p out of the database */
245 /****************************************************************************/
246 FGPhysicalProperty FGLocalWeatherDatabase::get(const sgVec3& p) const
247 {
248     unsigned int a = AreaWith(p);
249     if (a != 0)
250         return WeatherAreas[a-1].get(p[3]);
251     else    //point is outside => ask GlobalWeatherDatabase
252         return global->get(p);
253 }
254
255 FGPhysicalProperties FGLocalWeatherDatabase::get(const sgVec2& p) const
256 {
257     sgVec3 temp;
258     sgSetVec3(temp, p[0], p[1], 0.0);
259
260     unsigned int a = AreaWith(temp);
261     if (a != 0)
262         return WeatherAreas[a-1].get();
263     else    //point is outside => ask GlobalWeatherDatabase
264         return global->get(p);
265 }
266
267 WeatherPrecision FGLocalWeatherDatabase::getAirDensity(const sgVec3& p) const
268 {
269     FGPhysicalProperty dummy;
270     unsigned int a = AreaWith(p);
271     if (a != 0)
272         dummy = WeatherAreas[a-1].get(p[3]);
273     else    //point is outside => ask GlobalWeatherDatabase
274         dummy = global->get(p);
275
276     return 
277         (dummy.AirPressure*FG_WEATHER_DEFAULT_AIRDENSITY*FG_WEATHER_DEFAULT_TEMPERATURE) / 
278         (dummy.Temperature*FG_WEATHER_DEFAULT_AIRPRESSURE);
279 }
280
281 /****************************************************************************/
282 /* Add a weather feature at the point p and surrounding area                */
283 /****************************************************************************/
284 void FGLocalWeatherDatabase::addWind(const WeatherPrecision alt, const sgVec3& x, const sgVec2& p)
285 {
286     unsigned int a = AreaWith(p);
287     if (a != 0)
288         WeatherAreas[a-1].addWind(alt, x);
289 }
290
291 void FGLocalWeatherDatabase::addTurbulence(const WeatherPrecision alt, const sgVec3& x, const sgVec2& p)
292 {
293     unsigned int a = AreaWith(p);
294     if (a != 0)
295         WeatherAreas[a-1].addTurbulence(alt, x);
296 }
297
298 void FGLocalWeatherDatabase::addTemperature(const WeatherPrecision alt, const WeatherPrecision x, const sgVec2& p)
299 {
300     unsigned int a = AreaWith(p);
301     if (a != 0)
302         WeatherAreas[a-1].addTemperature(alt, x);
303 }
304
305 void FGLocalWeatherDatabase::addAirPressure(const WeatherPrecision alt, const WeatherPrecision x, const sgVec2& p)
306 {
307     unsigned int a = AreaWith(p);
308     if (a != 0)
309         WeatherAreas[a-1].addAirPressure(alt, x);
310 }
311
312 void FGLocalWeatherDatabase::addVaporPressure(const WeatherPrecision alt, const WeatherPrecision x, const sgVec2& p)
313 {
314     unsigned int a = AreaWith(p);
315     if (a != 0)
316         WeatherAreas[a-1].addVaporPressure(alt, x);
317 }
318
319 void FGLocalWeatherDatabase::addCloud(const WeatherPrecision alt, const FGCloudItem& x, const sgVec2& p)
320 {
321     unsigned int a = AreaWith(p);
322     if (a != 0)
323         WeatherAreas[a-1].addCloud(alt, x);
324 }
325
326 void FGLocalWeatherDatabase::setSnowRainIntensity(const WeatherPrecision x, const sgVec2& p)
327 {
328     unsigned int a = AreaWith(p);
329     if (a != 0)
330         WeatherAreas[a-1].setSnowRainIntensity(x);
331 }
332
333 void FGLocalWeatherDatabase::setSnowRainType(const SnowRainType x, const sgVec2& p)
334 {
335     unsigned int a = AreaWith(p);
336     if (a != 0)
337         WeatherAreas[a-1].setSnowRainType(x);
338 }
339
340 void FGLocalWeatherDatabase::setLightningProbability(const WeatherPrecision x, const sgVec2& p)
341 {
342     unsigned int a = AreaWith(p);
343     if (a != 0)
344         WeatherAreas[a-1].setLightningProbability(x);
345 }
346
347 void FGLocalWeatherDatabase::addProperties(const FGPhysicalProperties2D& x)
348 {
349     if (DatabaseStatus==use_global)
350     {
351         global->add(x);
352
353         //BAD, BAD, BAD thing I'm doing here: I'm adding to the global database a point that
354         //changes my voronoi diagram but I don't update it! instead I'm changing one local value
355         //that could be anywhere!!
356         //This only *might* work when the plane moves so far so fast that the diagram gets newly
357         //calculated soon...
358         unsigned int a = AreaWith(x.p);
359         if (a != 0)
360             WeatherAreas[a-1].setStoredWeather(x);
361     }
362     else
363     {
364         unsigned int a = AreaWith(x.p);
365         if (a != 0)
366             WeatherAreas[a-1].setStoredWeather(x);
367     }
368 }
369
370 void FGLocalWeatherDatabase::setProperties(const FGPhysicalProperties2D& x)
371 {
372     if (DatabaseStatus==use_global)
373     {
374         global->change(x);
375
376         //BAD, BAD, BAD thing I'm doing here: I'm adding to the global database a point that
377         //changes my voronoi diagram but I don't update it! Instead I'm changing one local value
378         //that could be anywhere!!
379         //This only *might* work when the plane moves so far so fast that the diagram gets newly
380         //calculated soon...
381         unsigned int a = AreaWith(x.p);
382         if (a != 0)
383             WeatherAreas[a-1].setStoredWeather(x);
384     }
385     else
386     {
387         unsigned int a = AreaWith(x.p);
388         if (a != 0)
389             WeatherAreas[a-1].setStoredWeather(x);
390     }
391 }
392
393 void fgUpdateWeatherDatabase(void)
394 {
395     //cerr << "FGLocalWeatherDatabase::update()\n";
396     sgVec3 position;
397     sgSetVec3(position, 
398         current_aircraft.fdm_state->get_Latitude(),
399         current_aircraft.fdm_state->get_Longitude(),
400         current_aircraft.fdm_state->get_Altitude() * FEET_TO_METER);
401
402     WeatherDatabase->update( position );
403 }
404