2008-03-04 09:02:24 +00:00
|
|
|
/**
|
|
|
|
* @file precipitation_mgr.cxx
|
|
|
|
* @author Nicolas VIVIEN
|
|
|
|
* @date 2008-02-10
|
|
|
|
*
|
|
|
|
* @note Copyright (C) 2008 Nicolas VIVIEN
|
|
|
|
*
|
|
|
|
* @brief Precipitation manager
|
|
|
|
* This manager calculate the intensity of precipitation in function of the altitude,
|
|
|
|
* calculate the wind direction and velocity, then update the drawing of precipitation.
|
|
|
|
*
|
|
|
|
* @par Licences
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2008-03-09 22:09:17 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2008-03-04 09:02:24 +00:00
|
|
|
#include <osg/MatrixTransform>
|
|
|
|
|
|
|
|
#include <simgear/constants.h>
|
|
|
|
#include <simgear/scene/sky/sky.hxx>
|
|
|
|
#include <simgear/scene/sky/cloud.hxx>
|
2012-03-03 13:37:43 +01:00
|
|
|
#include <simgear/scene/util/OsgMath.hxx>
|
2008-03-04 09:02:24 +00:00
|
|
|
|
|
|
|
#include <Main/fg_props.hxx>
|
2008-03-04 09:03:54 +00:00
|
|
|
#include <Main/globals.hxx>
|
2012-04-25 23:28:00 +02:00
|
|
|
#include <Viewer/renderer.hxx>
|
2008-03-04 09:03:54 +00:00
|
|
|
#include <Scenery/scenery.hxx>
|
2008-03-04 09:02:24 +00:00
|
|
|
|
|
|
|
#include "precipitation_mgr.hxx"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief FGPrecipitation Manager constructor
|
|
|
|
*
|
|
|
|
* Build a new object to manage the precipitation object
|
|
|
|
*/
|
|
|
|
FGPrecipitationMgr::FGPrecipitationMgr()
|
|
|
|
{
|
2016-05-03 09:56:06 +02:00
|
|
|
// Try to set up the scenegraph.
|
|
|
|
setupSceneGraph();
|
2008-03-04 09:02:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief FGPrecipitaiton Manager destructor
|
|
|
|
*/
|
|
|
|
FGPrecipitationMgr::~FGPrecipitationMgr()
|
|
|
|
{
|
2008-03-04 09:03:54 +00:00
|
|
|
|
2008-03-04 09:02:24 +00:00
|
|
|
}
|
|
|
|
|
2008-03-04 09:03:54 +00:00
|
|
|
/**
|
|
|
|
* SGSubsystem initialization
|
|
|
|
*/
|
|
|
|
void FGPrecipitationMgr::init()
|
|
|
|
{
|
|
|
|
// Read latitude and longitude position
|
|
|
|
SGGeod geod = SGGeod::fromDegM(fgGetDouble("/position/longitude-deg", 0.0),
|
|
|
|
fgGetDouble("/position/latitude-deg", 0.0),
|
|
|
|
0.0);
|
2012-03-03 13:37:43 +01:00
|
|
|
osg::Matrix position(makeZUpFrame(geod));
|
2008-03-04 09:03:54 +00:00
|
|
|
// Move the precipitation object to player position
|
|
|
|
transform->setMatrix(position);
|
2008-11-25 22:50:04 +00:00
|
|
|
fgGetNode("environment/params/precipitation-level-ft", true);
|
|
|
|
}
|
|
|
|
|
2011-05-06 14:12:17 +02:00
|
|
|
void FGPrecipitationMgr::bind ()
|
|
|
|
{
|
|
|
|
_tiedProperties.setRoot( fgGetNode("/sim/rendering", true ) );
|
|
|
|
_tiedProperties.Tie("precipitation-enable", precipitation.get(),
|
|
|
|
&SGPrecipitation::getEnabled,
|
|
|
|
&SGPrecipitation::setEnabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGPrecipitationMgr::unbind ()
|
|
|
|
{
|
|
|
|
_tiedProperties.Untie();
|
|
|
|
}
|
|
|
|
|
2016-05-03 09:56:06 +02:00
|
|
|
// Set up the precipitation manager scenegraph.
|
|
|
|
void FGPrecipitationMgr::setupSceneGraph(void)
|
2008-11-25 22:50:04 +00:00
|
|
|
{
|
2016-05-03 09:56:06 +02:00
|
|
|
FGScenery* scenery = globals->get_scenery();
|
|
|
|
osg::Group* group = scenery->get_precipitation_branch();
|
|
|
|
transform = new osg::MatrixTransform();
|
|
|
|
precipitation = new SGPrecipitation();
|
|
|
|
|
|
|
|
|
|
|
|
// By default, no precipitation
|
|
|
|
precipitation->setRainIntensity(0);
|
|
|
|
precipitation->setSnowIntensity(0);
|
|
|
|
|
|
|
|
// set the clip distance from the config
|
|
|
|
precipitation->setClipDistance(fgGetFloat("/environment/precipitation-control/clip-distance",5.0));
|
|
|
|
transform->addChild(precipitation->build());
|
|
|
|
group->addChild(transform.get());
|
2008-03-04 09:03:54 +00:00
|
|
|
}
|
2008-03-04 09:02:24 +00:00
|
|
|
|
2016-05-03 09:56:06 +02:00
|
|
|
|
|
|
|
void FGPrecipitationMgr::setPrecipitationLevel(double a)
|
2008-03-04 09:02:24 +00:00
|
|
|
{
|
2016-05-03 09:56:06 +02:00
|
|
|
fgSetDouble("environment/params/precipitation-level-ft",a);
|
2008-03-04 09:02:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Calculate the max alitutude with precipitation
|
|
|
|
*
|
|
|
|
* @returns Elevation max in meter
|
|
|
|
*
|
|
|
|
* This function permits you to know what is the altitude max where we can
|
2012-11-27 22:17:30 +00:00
|
|
|
* find precipitation. The value is returned in meters.
|
2008-03-04 09:02:24 +00:00
|
|
|
*/
|
|
|
|
float FGPrecipitationMgr::getPrecipitationAtAltitudeMax(void)
|
|
|
|
{
|
2008-03-04 09:03:54 +00:00
|
|
|
int i;
|
|
|
|
int max;
|
|
|
|
float result;
|
2008-11-02 09:45:31 +00:00
|
|
|
SGPropertyNode *boundaryNode, *boundaryEntry;
|
2012-11-27 22:17:30 +00:00
|
|
|
|
|
|
|
if (fgGetBool("/environment/params/use-external-precipitation-level", false)) {
|
|
|
|
// If we're not modeling the precipitation level based on the cloud
|
|
|
|
// layers, take it directly from the property tree.
|
|
|
|
return fgGetFloat("/environment/params/external-precipitation-level-m", 0.0);
|
|
|
|
}
|
2008-03-04 09:03:54 +00:00
|
|
|
|
2014-10-21 10:44:55 +02:00
|
|
|
|
2008-03-04 09:03:54 +00:00
|
|
|
// By default (not cloud layer)
|
|
|
|
max = SGCloudLayer::SG_MAX_CLOUD_COVERAGES;
|
|
|
|
result = 0;
|
|
|
|
|
2011-11-05 13:18:36 +00:00
|
|
|
SGSky* thesky = globals->get_renderer()->getSky();
|
|
|
|
|
2008-03-04 09:03:54 +00:00
|
|
|
// To avoid messing up
|
|
|
|
if (thesky == NULL)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
// For each cloud layer
|
|
|
|
for (i=0; i<thesky->get_cloud_layer_count(); i++) {
|
|
|
|
int q;
|
|
|
|
|
|
|
|
// Get coverage
|
|
|
|
// Value for q are (meaning / thickness) :
|
|
|
|
// 5 : "clear" / 0
|
|
|
|
// 4 : "cirrus" / ??
|
|
|
|
// 3 : "few" / 65
|
|
|
|
// 2 : "scattered" / 600
|
|
|
|
// 1 : "broken" / 750
|
|
|
|
// 0 : "overcast" / 1000
|
|
|
|
q = thesky->get_cloud_layer(i)->getCoverage();
|
|
|
|
|
|
|
|
// Save the coverage max
|
|
|
|
if (q < max) {
|
|
|
|
max = q;
|
|
|
|
result = thesky->get_cloud_layer(i)->getElevation_m();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-02 09:45:31 +00:00
|
|
|
|
|
|
|
// If we haven't found clouds layers, we read the bounday layers table.
|
|
|
|
if (result > 0)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
|
|
// Read boundary layers node
|
|
|
|
boundaryNode = fgGetNode("/environment/config/boundary");
|
|
|
|
|
|
|
|
if (boundaryNode != NULL) {
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
// For each boundary layers
|
|
|
|
while ( ( boundaryEntry = boundaryNode->getNode( "entry", i ) ) != NULL ) {
|
2012-03-06 22:28:18 +01:00
|
|
|
double elev = boundaryEntry->getDoubleValue( "elevation-ft" );
|
2008-11-02 09:45:31 +00:00
|
|
|
|
|
|
|
if (elev > result)
|
|
|
|
result = elev;
|
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the result in meter
|
|
|
|
result = result * SG_FEET_TO_METER;
|
|
|
|
|
2008-03-04 09:03:54 +00:00
|
|
|
return result;
|
2008-03-04 09:02:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Update the precipitation drawing
|
|
|
|
*
|
2008-11-02 09:45:31 +00:00
|
|
|
* To seem real, we stop the precipitation above the cloud or boundary layer.
|
|
|
|
* If METAR information doesn't give us this altitude, we will see precipitations
|
|
|
|
* in space...
|
|
|
|
* Moreover, below 0°C we change rain into snow.
|
2008-03-04 09:02:24 +00:00
|
|
|
*/
|
2008-03-04 09:03:54 +00:00
|
|
|
void FGPrecipitationMgr::update(double dt)
|
2008-03-04 09:02:24 +00:00
|
|
|
{
|
2008-03-04 09:03:54 +00:00
|
|
|
double dewtemp;
|
|
|
|
double currtemp;
|
|
|
|
double rain_intensity;
|
|
|
|
double snow_intensity;
|
|
|
|
|
|
|
|
float altitudeAircraft;
|
|
|
|
float altitudeCloudLayer;
|
2014-10-21 10:44:55 +02:00
|
|
|
float rainDropletSize;
|
|
|
|
float snowFlakeSize;
|
|
|
|
float illumination;
|
2008-03-04 09:03:54 +00:00
|
|
|
|
2008-11-25 22:50:04 +00:00
|
|
|
altitudeCloudLayer = this->getPrecipitationAtAltitudeMax() * SG_METER_TO_FEET;
|
|
|
|
setPrecipitationLevel(altitudeCloudLayer);
|
|
|
|
|
2014-10-21 10:44:55 +02:00
|
|
|
|
|
|
|
|
2012-11-27 22:17:30 +00:00
|
|
|
// Does the user enable the precipitation ?
|
|
|
|
if (!precipitation->getEnabled() ) {
|
|
|
|
// Disable precipitations
|
|
|
|
precipitation->setRainIntensity(0);
|
|
|
|
precipitation->setSnowIntensity(0);
|
2008-11-02 09:45:31 +00:00
|
|
|
|
2012-11-27 22:17:30 +00:00
|
|
|
// Update the drawing...
|
|
|
|
precipitation->update();
|
2008-11-02 09:45:31 +00:00
|
|
|
|
2012-11-27 22:17:30 +00:00
|
|
|
// Exit
|
|
|
|
return;
|
|
|
|
}
|
2008-11-02 09:45:31 +00:00
|
|
|
|
2014-10-21 10:44:55 +02:00
|
|
|
// See if external droplet size and illumination are used
|
|
|
|
if (fgGetBool("/environment/precipitation-control/detailed-precipitation", false)) {
|
|
|
|
precipitation->setDropletExternal(true);
|
|
|
|
rainDropletSize = fgGetFloat("/environment/precipitation-control/rain-droplet-size", 0.015);
|
|
|
|
snowFlakeSize = fgGetFloat("/environment/precipitation-control/snow-flake-size", 0.03);
|
|
|
|
illumination = fgGetFloat("/environment/precipitation-control/illumination", 1.0);
|
|
|
|
precipitation->setRainDropletSize(rainDropletSize);
|
|
|
|
precipitation->setSnowFlakeSize(snowFlakeSize);
|
|
|
|
precipitation->setIllumination(illumination);
|
|
|
|
}
|
|
|
|
|
2008-03-04 09:03:54 +00:00
|
|
|
// Get the elevation of aicraft and of the cloud layer
|
|
|
|
altitudeAircraft = fgGetDouble("/position/altitude-ft", 0.0);
|
|
|
|
|
2008-11-02 09:45:31 +00:00
|
|
|
if ((altitudeCloudLayer > 0) && (altitudeAircraft > altitudeCloudLayer)) {
|
2008-03-04 09:03:54 +00:00
|
|
|
// The aircraft is above the cloud layer
|
|
|
|
rain_intensity = 0;
|
|
|
|
snow_intensity = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// The aircraft is bellow the cloud layer
|
2010-12-21 09:59:23 +01:00
|
|
|
rain_intensity = fgGetDouble("/environment/rain-norm", 0.0);
|
|
|
|
snow_intensity = fgGetDouble("/environment/snow-norm", 0.0);
|
2008-03-04 09:03:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the current and dew temperature
|
|
|
|
dewtemp = fgGetDouble("/environment/dewpoint-degc", 0.0);
|
|
|
|
currtemp = fgGetDouble("/environment/temperature-degc", 0.0);
|
|
|
|
|
|
|
|
if (currtemp < dewtemp) {
|
|
|
|
// There is fog... and the weather is very steamy
|
|
|
|
if (rain_intensity == 0)
|
|
|
|
rain_intensity = 0.15;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the current temperature is below 0°C, we turn off the rain to snow...
|
|
|
|
if (currtemp < 0)
|
|
|
|
precipitation->setFreezing(true);
|
|
|
|
else
|
|
|
|
precipitation->setFreezing(false);
|
|
|
|
|
|
|
|
|
|
|
|
// Set the wind property
|
|
|
|
precipitation->setWindProperty(
|
|
|
|
fgGetDouble("/environment/wind-from-heading-deg", 0.0),
|
|
|
|
fgGetDouble("/environment/wind-speed-kt", 0.0));
|
|
|
|
|
|
|
|
// Set the intensity of precipitation
|
|
|
|
precipitation->setRainIntensity(rain_intensity);
|
|
|
|
precipitation->setSnowIntensity(snow_intensity);
|
|
|
|
|
|
|
|
// Update the drawing...
|
|
|
|
precipitation->update();
|
2008-03-04 09:02:24 +00:00
|
|
|
}
|