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