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