2 * @file precipitation_mgr.cxx
3 * @author Nicolas VIVIEN
6 * @note Copyright (C) 2008 Nicolas VIVIEN
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.
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.
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.
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.
33 #include <osg/MatrixTransform>
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>
40 #include <Main/fg_props.hxx>
41 #include <Main/globals.hxx>
42 #include <Viewer/renderer.hxx>
43 #include <Scenery/scenery.hxx>
45 #include "precipitation_mgr.hxx"
48 * @brief FGPrecipitation Manager constructor
50 * Build a new object to manage the precipitation object
52 FGPrecipitationMgr::FGPrecipitationMgr()
54 group = new osg::Group();
55 transform = new osg::MatrixTransform();
56 precipitation = new SGPrecipitation();
59 // By default, no precipitation
60 precipitation->setRainIntensity(0);
61 precipitation->setSnowIntensity(0);
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());
71 * @brief FGPrecipitaiton Manager destructor
73 FGPrecipitationMgr::~FGPrecipitationMgr()
79 * SGSubsystem initialization
81 void FGPrecipitationMgr::init()
83 // Read latitude and longitude position
84 SGGeod geod = SGGeod::fromDegM(fgGetDouble("/position/longitude-deg", 0.0),
85 fgGetDouble("/position/latitude-deg", 0.0),
87 osg::Matrix position(makeZUpFrame(geod));
88 // Move the precipitation object to player position
89 transform->setMatrix(position);
91 osg::Group* scenery = globals->get_scenery()->get_scene_graph();
92 scenery->addChild(getObject());
93 fgGetNode("environment/params/precipitation-level-ft", true);
96 void FGPrecipitationMgr::bind ()
98 _tiedProperties.setRoot( fgGetNode("/sim/rendering", true ) );
99 _tiedProperties.Tie("precipitation-enable", precipitation.get(),
100 &SGPrecipitation::getEnabled,
101 &SGPrecipitation::setEnabled);
104 void FGPrecipitationMgr::unbind ()
106 _tiedProperties.Untie();
109 void FGPrecipitationMgr::setPrecipitationLevel(double a)
111 fgSetDouble("environment/params/precipitation-level-ft",a);
115 * @brief Get OSG precipitation object
117 * @returns A pointer on the OSG object (osg::Group *)
119 osg::Group * FGPrecipitationMgr::getObject(void)
121 return this->group.get();
125 * @brief Calculate the max alitutude with precipitation
127 * @returns Elevation max in meter
129 * This function permits you to know what is the altitude max where we can
130 * find precipitation. The value is returned in meters.
132 float FGPrecipitationMgr::getPrecipitationAtAltitudeMax(void)
137 SGPropertyNode *boundaryNode, *boundaryEntry;
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);
146 // By default (not cloud layer)
147 max = SGCloudLayer::SG_MAX_CLOUD_COVERAGES;
150 SGSky* thesky = globals->get_renderer()->getSky();
152 // To avoid messing up
156 // For each cloud layer
157 for (i=0; i<thesky->get_cloud_layer_count(); i++) {
161 // Value for q are (meaning / thickness) :
165 // 2 : "scattered" / 600
166 // 1 : "broken" / 750
167 // 0 : "overcast" / 1000
168 q = thesky->get_cloud_layer(i)->getCoverage();
170 // Save the coverage max
173 result = thesky->get_cloud_layer(i)->getElevation_m();
178 // If we haven't found clouds layers, we read the bounday layers table.
183 // Read boundary layers node
184 boundaryNode = fgGetNode("/environment/config/boundary");
186 if (boundaryNode != NULL) {
189 // For each boundary layers
190 while ( ( boundaryEntry = boundaryNode->getNode( "entry", i ) ) != NULL ) {
191 double elev = boundaryEntry->getDoubleValue( "elevation-ft" );
200 // Convert the result in meter
201 result = result * SG_FEET_TO_METER;
208 * @brief Update the precipitation drawing
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
213 * Moreover, below 0°C we change rain into snow.
215 void FGPrecipitationMgr::update(double dt)
219 double rain_intensity;
220 double snow_intensity;
222 float altitudeAircraft;
223 float altitudeCloudLayer;
224 float rainDropletSize;
228 altitudeCloudLayer = this->getPrecipitationAtAltitudeMax() * SG_METER_TO_FEET;
229 setPrecipitationLevel(altitudeCloudLayer);
233 // Does the user enable the precipitation ?
234 if (!precipitation->getEnabled() ) {
235 // Disable precipitations
236 precipitation->setRainIntensity(0);
237 precipitation->setSnowIntensity(0);
239 // Update the drawing...
240 precipitation->update();
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);
257 // Get the elevation of aicraft and of the cloud layer
258 altitudeAircraft = fgGetDouble("/position/altitude-ft", 0.0);
260 if ((altitudeCloudLayer > 0) && (altitudeAircraft > altitudeCloudLayer)) {
261 // The aircraft is above the cloud layer
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);
271 // Get the current and dew temperature
272 dewtemp = fgGetDouble("/environment/dewpoint-degc", 0.0);
273 currtemp = fgGetDouble("/environment/temperature-degc", 0.0);
275 if (currtemp < dewtemp) {
276 // There is fog... and the weather is very steamy
277 if (rain_intensity == 0)
278 rain_intensity = 0.15;
281 // If the current temperature is below 0°C, we turn off the rain to snow...
283 precipitation->setFreezing(true);
285 precipitation->setFreezing(false);
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));
293 // Set the intensity of precipitation
294 precipitation->setRainIntensity(rain_intensity);
295 precipitation->setSnowIntensity(snow_intensity);
297 // Update the drawing...
298 precipitation->update();