]> git.mxchange.org Git - flightgear.git/blob - src/Environment/precipitation_mgr.cxx
Merge branch 'merge-requests/1555' into next
[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 <Main/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     transform->addChild(precipitation->build());
63     group->addChild(transform.get());
64 }
65
66
67 /** 
68  * @brief FGPrecipitaiton Manager destructor
69  */
70 FGPrecipitationMgr::~FGPrecipitationMgr()
71 {
72
73 }
74
75 /**
76  * SGSubsystem initialization
77  */
78 void FGPrecipitationMgr::init()
79 {
80     // Read latitude and longitude position
81     SGGeod geod = SGGeod::fromDegM(fgGetDouble("/position/longitude-deg", 0.0),
82                                    fgGetDouble("/position/latitude-deg", 0.0),
83                                    0.0);
84     osg::Matrix position(geod.makeZUpFrame());
85     // Move the precipitation object to player position
86     transform->setMatrix(position);
87     // Add to scene graph
88     osg::Group* scenery = globals->get_scenery()->get_scene_graph();
89     scenery->addChild(getObject());
90     fgGetNode("environment/params/precipitation-level-ft", true);
91 }
92
93 void FGPrecipitationMgr::bind ()
94 {
95   _tiedProperties.setRoot( fgGetNode("/sim/rendering", true ) );
96   _tiedProperties.Tie("precipitation-enable", precipitation.get(),
97           &SGPrecipitation::getEnabled,
98           &SGPrecipitation::setEnabled);
99 }
100
101 void FGPrecipitationMgr::unbind ()
102 {
103   _tiedProperties.Untie();
104 }
105
106 void FGPrecipitationMgr::setPrecipitationLevel(double a)
107 {
108     fgSetDouble("environment/params/precipitation-level-ft",a);
109 }
110
111 /** 
112  * @brief Get OSG precipitation object
113  * 
114  * @returns A pointer on the OSG object (osg::Group *)
115  */
116 osg::Group * FGPrecipitationMgr::getObject(void)
117 {
118     return this->group.get();
119 }
120
121 /** 
122  * @brief Calculate the max alitutude with precipitation
123  * 
124  * @returns Elevation max in meter
125  *
126  * This function permits you to know what is the altitude max where we can
127  * find precipitation. The value is returned in meter.
128  */
129 float FGPrecipitationMgr::getPrecipitationAtAltitudeMax(void)
130 {
131     int i;
132     int max;
133         double elev;
134     float result;
135     SGPropertyNode *boundaryNode, *boundaryEntry;
136
137
138     // By default (not cloud layer)
139     max = SGCloudLayer::SG_MAX_CLOUD_COVERAGES;
140     result = 0;
141
142      SGSky* thesky = globals->get_renderer()->getSky();
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 }