]> git.mxchange.org Git - flightgear.git/blob - src/Environment/precipitation_mgr.cxx
Precipitation updates from ThorstenR
[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/scene/sky/sky.hxx>
37 #include <simgear/scene/sky/cloud.hxx>
38 #include <simgear/scene/util/OsgMath.hxx>
39
40 #include <Main/fg_props.hxx>
41 #include <Main/globals.hxx>
42 #include <Viewer/renderer.hxx>
43 #include <Scenery/scenery.hxx>
44
45 #include "precipitation_mgr.hxx"
46
47 /** 
48  * @brief FGPrecipitation Manager constructor 
49  *
50  * Build a new object to manage the precipitation object
51  */
52 FGPrecipitationMgr::FGPrecipitationMgr()
53 {       
54     group = new osg::Group();
55     transform = new osg::MatrixTransform();
56     precipitation = new SGPrecipitation();
57
58
59     // By default, no precipitation
60     precipitation->setRainIntensity(0);
61     precipitation->setSnowIntensity(0);
62
63     // set the clip distance from the config
64     precipitation->setClipDistance(fgGetFloat("/environment/precipitation-control/clip-distance",5.0));
65     transform->addChild(precipitation->build());
66     group->addChild(transform.get());
67 }
68
69
70 /** 
71  * @brief FGPrecipitaiton Manager destructor
72  */
73 FGPrecipitationMgr::~FGPrecipitationMgr()
74 {
75
76 }
77
78 /**
79  * SGSubsystem initialization
80  */
81 void FGPrecipitationMgr::init()
82 {
83     // Read latitude and longitude position
84     SGGeod geod = SGGeod::fromDegM(fgGetDouble("/position/longitude-deg", 0.0),
85                                    fgGetDouble("/position/latitude-deg", 0.0),
86                                    0.0);
87     osg::Matrix position(makeZUpFrame(geod));
88     // Move the precipitation object to player position
89     transform->setMatrix(position);
90     // Add to scene graph
91     osg::Group* scenery = globals->get_scenery()->get_scene_graph();
92     scenery->addChild(getObject());
93     fgGetNode("environment/params/precipitation-level-ft", true);
94 }
95
96 void FGPrecipitationMgr::bind ()
97 {
98   _tiedProperties.setRoot( fgGetNode("/sim/rendering", true ) );
99   _tiedProperties.Tie("precipitation-enable", precipitation.get(),
100           &SGPrecipitation::getEnabled,
101           &SGPrecipitation::setEnabled);
102 }
103
104 void FGPrecipitationMgr::unbind ()
105 {
106   _tiedProperties.Untie();
107 }
108
109 void FGPrecipitationMgr::setPrecipitationLevel(double a)
110 {
111     fgSetDouble("environment/params/precipitation-level-ft",a);
112 }
113
114 /** 
115  * @brief Get OSG precipitation object
116  * 
117  * @returns A pointer on the OSG object (osg::Group *)
118  */
119 osg::Group * FGPrecipitationMgr::getObject(void)
120 {
121     return this->group.get();
122 }
123
124 /** 
125  * @brief Calculate the max alitutude with precipitation
126  * 
127  * @returns Elevation max in meter
128  *
129  * This function permits you to know what is the altitude max where we can
130  * find precipitation. The value is returned in meters.
131  */
132 float FGPrecipitationMgr::getPrecipitationAtAltitudeMax(void)
133 {
134     int i;
135     int max;
136     float result;
137     SGPropertyNode *boundaryNode, *boundaryEntry;
138     
139     if (fgGetBool("/environment/params/use-external-precipitation-level", false)) {
140         // If we're not modeling the precipitation level based on the cloud
141         // layers, take it directly from the property tree.
142         return fgGetFloat("/environment/params/external-precipitation-level-m", 0.0);    
143     }
144
145
146     // By default (not cloud layer)
147     max = SGCloudLayer::SG_MAX_CLOUD_COVERAGES;
148     result = 0;
149
150      SGSky* thesky = globals->get_renderer()->getSky();
151     
152     // To avoid messing up
153     if (thesky == NULL)
154         return result;
155
156     // For each cloud layer
157     for (i=0; i<thesky->get_cloud_layer_count(); i++) {
158         int q;
159
160         // Get coverage
161         // Value for q are (meaning / thickness) :
162         //   5 : "clear"                / 0
163         //   4 : "cirrus"       / ??
164         //   3 : "few"                  / 65
165         //   2 : "scattered"    / 600
166         //   1 : "broken"               / 750
167         //   0 : "overcast"             / 1000
168         q = thesky->get_cloud_layer(i)->getCoverage();
169
170         // Save the coverage max
171         if (q < max) {
172             max = q;
173             result = thesky->get_cloud_layer(i)->getElevation_m();
174         }
175     }
176
177
178     // If we haven't found clouds layers, we read the bounday layers table.
179     if (result > 0)
180         return result;
181
182
183     // Read boundary layers node
184     boundaryNode = fgGetNode("/environment/config/boundary");
185
186     if (boundaryNode != NULL) {
187         i = 0;
188
189         // For each boundary layers
190         while ( ( boundaryEntry = boundaryNode->getNode( "entry", i ) ) != NULL ) {
191             double elev = boundaryEntry->getDoubleValue( "elevation-ft" );
192
193             if (elev > result)
194                 result = elev;
195
196             ++i;
197         }
198     }
199
200         // Convert the result in meter
201         result = result * SG_FEET_TO_METER;
202
203     return result;
204 }
205
206
207 /** 
208  * @brief Update the precipitation drawing
209  * 
210  * To seem real, we stop the precipitation above the cloud or boundary layer.
211  * If METAR information doesn't give us this altitude, we will see precipitations
212  * in space...
213  * Moreover, below 0°C we change rain into snow.
214  */
215 void FGPrecipitationMgr::update(double dt)
216 {
217     double dewtemp;
218     double currtemp;
219     double rain_intensity;
220     double snow_intensity;
221
222     float altitudeAircraft;
223     float altitudeCloudLayer;
224     float rainDropletSize;
225     float snowFlakeSize;
226     float illumination;
227
228     altitudeCloudLayer = this->getPrecipitationAtAltitudeMax() * SG_METER_TO_FEET;
229     setPrecipitationLevel(altitudeCloudLayer);
230
231
232
233     // Does the user enable the precipitation ?
234     if (!precipitation->getEnabled() ) {
235         // Disable precipitations
236         precipitation->setRainIntensity(0);
237         precipitation->setSnowIntensity(0);
238
239         // Update the drawing...
240         precipitation->update();
241
242         // Exit
243         return;
244     }
245
246    // See if external droplet size and illumination are used
247    if (fgGetBool("/environment/precipitation-control/detailed-precipitation", false)) {
248         precipitation->setDropletExternal(true);
249         rainDropletSize = fgGetFloat("/environment/precipitation-control/rain-droplet-size", 0.015);
250         snowFlakeSize = fgGetFloat("/environment/precipitation-control/snow-flake-size", 0.03);
251         illumination = fgGetFloat("/environment/precipitation-control/illumination", 1.0);
252         precipitation->setRainDropletSize(rainDropletSize);
253         precipitation->setSnowFlakeSize(snowFlakeSize);
254         precipitation->setIllumination(illumination);
255    }
256
257     // Get the elevation of aicraft and of the cloud layer
258     altitudeAircraft = fgGetDouble("/position/altitude-ft", 0.0);
259
260     if ((altitudeCloudLayer > 0) && (altitudeAircraft > altitudeCloudLayer)) {
261         // The aircraft is above the cloud layer
262         rain_intensity = 0;
263         snow_intensity = 0;
264     }
265     else {
266         // The aircraft is bellow the cloud layer
267         rain_intensity = fgGetDouble("/environment/rain-norm", 0.0);
268         snow_intensity = fgGetDouble("/environment/snow-norm", 0.0);
269     }
270
271     // Get the current and dew temperature
272     dewtemp = fgGetDouble("/environment/dewpoint-degc", 0.0);
273     currtemp = fgGetDouble("/environment/temperature-degc", 0.0);
274
275     if (currtemp < dewtemp) {
276         // There is fog... and the weather is very steamy
277         if (rain_intensity == 0)
278             rain_intensity = 0.15;
279     }
280
281     // If the current temperature is below 0°C, we turn off the rain to snow...
282     if (currtemp < 0)
283         precipitation->setFreezing(true);
284     else
285         precipitation->setFreezing(false);
286
287
288     // Set the wind property
289     precipitation->setWindProperty(
290         fgGetDouble("/environment/wind-from-heading-deg", 0.0),
291         fgGetDouble("/environment/wind-speed-kt", 0.0));
292
293     // Set the intensity of precipitation
294     precipitation->setRainIntensity(rain_intensity);
295     precipitation->setSnowIntensity(snow_intensity);
296
297     // Update the drawing...
298     precipitation->update();
299 }