]> git.mxchange.org Git - flightgear.git/blob - src/Environment/precipitation_mgr.cxx
Bind the CAVOK flag to metarproperties
[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     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(makeZUpFrame(geod));
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 meters.
128  */
129 float FGPrecipitationMgr::getPrecipitationAtAltitudeMax(void)
130 {
131     int i;
132     int max;
133     float result;
134     SGPropertyNode *boundaryNode, *boundaryEntry;
135     
136     if (fgGetBool("/environment/params/use-external-precipitation-level", false)) {
137         // If we're not modeling the precipitation level based on the cloud
138         // layers, take it directly from the property tree.
139         return fgGetFloat("/environment/params/external-precipitation-level-m", 0.0);    
140     }
141
142     // By default (not cloud layer)
143     max = SGCloudLayer::SG_MAX_CLOUD_COVERAGES;
144     result = 0;
145
146      SGSky* thesky = globals->get_renderer()->getSky();
147     
148     // To avoid messing up
149     if (thesky == NULL)
150         return result;
151
152     // For each cloud layer
153     for (i=0; i<thesky->get_cloud_layer_count(); i++) {
154         int q;
155
156         // Get coverage
157         // Value for q are (meaning / thickness) :
158         //   5 : "clear"                / 0
159         //   4 : "cirrus"       / ??
160         //   3 : "few"                  / 65
161         //   2 : "scattered"    / 600
162         //   1 : "broken"               / 750
163         //   0 : "overcast"             / 1000
164         q = thesky->get_cloud_layer(i)->getCoverage();
165
166         // Save the coverage max
167         if (q < max) {
168             max = q;
169             result = thesky->get_cloud_layer(i)->getElevation_m();
170         }
171     }
172
173
174     // If we haven't found clouds layers, we read the bounday layers table.
175     if (result > 0)
176         return result;
177
178
179     // Read boundary layers node
180     boundaryNode = fgGetNode("/environment/config/boundary");
181
182     if (boundaryNode != NULL) {
183         i = 0;
184
185         // For each boundary layers
186         while ( ( boundaryEntry = boundaryNode->getNode( "entry", i ) ) != NULL ) {
187             double elev = boundaryEntry->getDoubleValue( "elevation-ft" );
188
189             if (elev > result)
190                 result = elev;
191
192             ++i;
193         }
194     }
195
196         // Convert the result in meter
197         result = result * SG_FEET_TO_METER;
198
199     return result;
200 }
201
202
203 /** 
204  * @brief Update the precipitation drawing
205  * 
206  * To seem real, we stop the precipitation above the cloud or boundary layer.
207  * If METAR information doesn't give us this altitude, we will see precipitations
208  * in space...
209  * Moreover, below 0°C we change rain into snow.
210  */
211 void FGPrecipitationMgr::update(double dt)
212 {
213     double dewtemp;
214     double currtemp;
215     double rain_intensity;
216     double snow_intensity;
217
218     float altitudeAircraft;
219     float altitudeCloudLayer;
220
221     altitudeCloudLayer = this->getPrecipitationAtAltitudeMax() * SG_METER_TO_FEET;
222     setPrecipitationLevel(altitudeCloudLayer);
223
224     // Does the user enable the precipitation ?
225     if (!precipitation->getEnabled() ) {
226         // Disable precipitations
227         precipitation->setRainIntensity(0);
228         precipitation->setSnowIntensity(0);
229
230         // Update the drawing...
231         precipitation->update();
232
233         // Exit
234         return;
235     }
236
237     // Get the elevation of aicraft and of the cloud layer
238     altitudeAircraft = fgGetDouble("/position/altitude-ft", 0.0);
239
240     if ((altitudeCloudLayer > 0) && (altitudeAircraft > altitudeCloudLayer)) {
241         // The aircraft is above the cloud layer
242         rain_intensity = 0;
243         snow_intensity = 0;
244     }
245     else {
246         // The aircraft is bellow the cloud layer
247         rain_intensity = fgGetDouble("/environment/rain-norm", 0.0);
248         snow_intensity = fgGetDouble("/environment/snow-norm", 0.0);
249     }
250
251     // Get the current and dew temperature
252     dewtemp = fgGetDouble("/environment/dewpoint-degc", 0.0);
253     currtemp = fgGetDouble("/environment/temperature-degc", 0.0);
254
255     if (currtemp < dewtemp) {
256         // There is fog... and the weather is very steamy
257         if (rain_intensity == 0)
258             rain_intensity = 0.15;
259     }
260
261     // If the current temperature is below 0°C, we turn off the rain to snow...
262     if (currtemp < 0)
263         precipitation->setFreezing(true);
264     else
265         precipitation->setFreezing(false);
266
267
268     // Set the wind property
269     precipitation->setWindProperty(
270         fgGetDouble("/environment/wind-from-heading-deg", 0.0),
271         fgGetDouble("/environment/wind-speed-kt", 0.0));
272
273     // Set the intensity of precipitation
274     precipitation->setRainIntensity(rain_intensity);
275     precipitation->setSnowIntensity(snow_intensity);
276
277     // Update the drawing...
278     precipitation->update();
279 }