]> git.mxchange.org Git - flightgear.git/blob - src/Environment/precipitation_mgr.cxx
Continuous replay: use correct replay duration
[flightgear.git] / src / Environment / precipitation_mgr.cxx
1 /**
2  * @file precipitation_mgr.cxx
3  * @author Nicolas VIVIEN
4  * @date 2008-02-10
5  *
6  * @note Copyright (C) 2008 Nicolas VIVIEN
7  *
8  * @brief Precipitation manager
9  *   This manager calculate the intensity of precipitation in function of the altitude,
10  *   calculate the wind direction and velocity, then update the drawing of precipitation.
11  *
12  * @par Licences
13  *   This program is free software; you can redistribute it and/or
14  *   modify it under the terms of the GNU General Public License as
15  *   published by the Free Software Foundation; either version 2 of the
16  *   License, or (at your option) any later version.
17  *
18  *   This program is distributed in the hope that it will be useful, but
19  *   WITHOUT ANY WARRANTY; without even the implied warranty of
20  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  *   General Public License for more details.
22  *
23  *   You should have received a copy of the GNU General Public License
24  *   along with this program; if not, write to the Free Software
25  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26  *
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif
32
33 #include <osg/MatrixTransform>
34
35 #include <simgear/constants.h>
36 #include <simgear/math/SGMath.hxx>
37 #include <simgear/scene/sky/sky.hxx>
38 #include <simgear/scene/sky/cloud.hxx>
39
40 #include <Main/fg_props.hxx>
41 #include <Main/globals.hxx>
42 #include <Scenery/scenery.hxx>
43
44 #include "precipitation_mgr.hxx"
45
46 extern SGSky *thesky;
47
48
49 /** 
50  * @brief FGPrecipitation Manager constructor 
51  *
52  * Build a new object to manage the precipitation object
53  */
54 FGPrecipitationMgr::FGPrecipitationMgr()
55 {       
56     group = new osg::Group();
57     transform = new osg::MatrixTransform();
58     precipitation = new SGPrecipitation();
59
60
61     // By default, no precipitation
62     precipitation->setRainIntensity(0);
63     precipitation->setSnowIntensity(0);
64     transform->addChild(precipitation->build());
65     group->addChild(transform.get());
66 }
67
68
69 /** 
70  * @brief FGPrecipitaiton Manager destructor
71  */
72 FGPrecipitationMgr::~FGPrecipitationMgr()
73 {
74
75 }
76
77 /**
78  * SGSubsystem initialization
79  */
80 void FGPrecipitationMgr::init()
81 {
82     // Read latitude and longitude position
83     SGGeod geod = SGGeod::fromDegM(fgGetDouble("/position/longitude-deg", 0.0),
84                                    fgGetDouble("/position/latitude-deg", 0.0),
85                                    0.0);
86     osg::Matrix position(geod.makeZUpFrame());
87     // Move the precipitation object to player position
88     transform->setMatrix(position);
89     // Add to scene graph
90     osg::Group* scenery = globals->get_scenery()->get_scene_graph();
91     scenery->addChild(getObject());
92     fgGetNode("environment/params/precipitation-level-ft", true);
93 }
94
95 void FGPrecipitationMgr::bind ()
96 {
97   _tiedProperties.setRoot( fgGetNode("/sim/rendering", true ) );
98   _tiedProperties.Tie("precipitation-enable", precipitation.get(),
99           &SGPrecipitation::getEnabled,
100           &SGPrecipitation::setEnabled);
101 }
102
103 void FGPrecipitationMgr::unbind ()
104 {
105   _tiedProperties.Untie();
106 }
107
108 void FGPrecipitationMgr::setPrecipitationLevel(double a)
109 {
110     fgSetDouble("environment/params/precipitation-level-ft",a);
111 }
112
113 /** 
114  * @brief Get OSG precipitation object
115  * 
116  * @returns A pointer on the OSG object (osg::Group *)
117  */
118 osg::Group * FGPrecipitationMgr::getObject(void)
119 {
120     return this->group.get();
121 }
122
123 /** 
124  * @brief Calculate the max alitutude with precipitation
125  * 
126  * @returns Elevation max in meter
127  *
128  * This function permits you to know what is the altitude max where we can
129  * find precipitation. The value is returned in meter.
130  */
131 float FGPrecipitationMgr::getPrecipitationAtAltitudeMax(void)
132 {
133     int i;
134     int max;
135         double elev;
136     float result;
137     SGPropertyNode *boundaryNode, *boundaryEntry;
138
139
140     // By default (not cloud layer)
141     max = SGCloudLayer::SG_MAX_CLOUD_COVERAGES;
142     result = 0;
143
144     // To avoid messing up
145     if (thesky == NULL)
146         return result;
147
148     // For each cloud layer
149     for (i=0; i<thesky->get_cloud_layer_count(); i++) {
150         int q;
151
152         // Get coverage
153         // Value for q are (meaning / thickness) :
154         //   5 : "clear"                / 0
155         //   4 : "cirrus"       / ??
156         //   3 : "few"                  / 65
157         //   2 : "scattered"    / 600
158         //   1 : "broken"               / 750
159         //   0 : "overcast"             / 1000
160         q = thesky->get_cloud_layer(i)->getCoverage();
161
162         // Save the coverage max
163         if (q < max) {
164             max = q;
165             result = thesky->get_cloud_layer(i)->getElevation_m();
166         }
167     }
168
169
170     // If we haven't found clouds layers, we read the bounday layers table.
171     if (result > 0)
172         return result;
173
174
175     // Read boundary layers node
176     boundaryNode = fgGetNode("/environment/config/boundary");
177
178     if (boundaryNode != NULL) {
179         i = 0;
180
181         // For each boundary layers
182         while ( ( boundaryEntry = boundaryNode->getNode( "entry", i ) ) != NULL ) {
183             elev = boundaryEntry->getDoubleValue( "elevation-ft" );
184
185             if (elev > result)
186                 result = elev;
187
188             ++i;
189         }
190     }
191
192         // Convert the result in meter
193         result = result * SG_FEET_TO_METER;
194
195     return result;
196 }
197
198
199 /** 
200  * @brief Update the precipitation drawing
201  * 
202  * To seem real, we stop the precipitation above the cloud or boundary layer.
203  * If METAR information doesn't give us this altitude, we will see precipitations
204  * in space...
205  * Moreover, below 0°C we change rain into snow.
206  */
207 void FGPrecipitationMgr::update(double dt)
208 {
209     double dewtemp;
210     double currtemp;
211     double rain_intensity;
212     double snow_intensity;
213
214     float altitudeAircraft;
215     float altitudeCloudLayer;
216
217     altitudeCloudLayer = this->getPrecipitationAtAltitudeMax() * SG_METER_TO_FEET;
218     setPrecipitationLevel(altitudeCloudLayer);
219
220         // Does the user enable the precipitation ?
221         if (!precipitation->getEnabled() ) {
222                 // Disable precipitations
223             precipitation->setRainIntensity(0);
224             precipitation->setSnowIntensity(0);
225
226             // Update the drawing...
227             precipitation->update();
228
229                 // Exit
230                 return;
231         }
232
233     // Get the elevation of aicraft and of the cloud layer
234     altitudeAircraft = fgGetDouble("/position/altitude-ft", 0.0);
235
236     if ((altitudeCloudLayer > 0) && (altitudeAircraft > altitudeCloudLayer)) {
237         // The aircraft is above the cloud layer
238         rain_intensity = 0;
239         snow_intensity = 0;
240     }
241     else {
242         // The aircraft is bellow the cloud layer
243         rain_intensity = fgGetDouble("/environment/rain-norm", 0.0);
244         snow_intensity = fgGetDouble("/environment/snow-norm", 0.0);
245     }
246
247     // Get the current and dew temperature
248     dewtemp = fgGetDouble("/environment/dewpoint-degc", 0.0);
249     currtemp = fgGetDouble("/environment/temperature-degc", 0.0);
250
251     if (currtemp < dewtemp) {
252         // There is fog... and the weather is very steamy
253         if (rain_intensity == 0)
254             rain_intensity = 0.15;
255     }
256
257     // If the current temperature is below 0°C, we turn off the rain to snow...
258     if (currtemp < 0)
259         precipitation->setFreezing(true);
260     else
261         precipitation->setFreezing(false);
262
263
264     // Set the wind property
265     precipitation->setWindProperty(
266         fgGetDouble("/environment/wind-from-heading-deg", 0.0),
267         fgGetDouble("/environment/wind-speed-kt", 0.0));
268
269     // Set the intensity of precipitation
270     precipitation->setRainIntensity(rain_intensity);
271     precipitation->setSnowIntensity(snow_intensity);
272
273     // Update the drawing...
274     precipitation->update();
275 }