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>
|
2008-03-04 09:03:54 +00:00
|
|
|
#include <simgear/math/SGMath.hxx>
|
2008-03-04 09:02:24 +00:00
|
|
|
#include <simgear/scene/sky/sky.hxx>
|
|
|
|
#include <simgear/scene/sky/cloud.hxx>
|
2008-11-02 09:45:31 +00:00
|
|
|
#include <simgear/environment/visual_enviro.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>
|
|
|
|
#include <Scenery/scenery.hxx>
|
2008-03-04 09:02:24 +00:00
|
|
|
|
|
|
|
#include "precipitation_mgr.hxx"
|
|
|
|
|
|
|
|
extern SGSky *thesky;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief FGPrecipitation Manager constructor
|
|
|
|
*
|
|
|
|
* Build a new object to manage the precipitation object
|
|
|
|
*/
|
|
|
|
FGPrecipitationMgr::FGPrecipitationMgr()
|
|
|
|
{
|
2008-03-04 09:03:54 +00:00
|
|
|
group = new osg::Group();
|
|
|
|
transform = new osg::MatrixTransform();
|
|
|
|
precipitation = new SGPrecipitation();
|
2008-03-04 09:02:24 +00:00
|
|
|
|
|
|
|
|
2008-03-04 09:03:54 +00:00
|
|
|
// By default, no precipitation
|
|
|
|
precipitation->setRainIntensity(0);
|
|
|
|
precipitation->setSnowIntensity(0);
|
|
|
|
transform->addChild(precipitation->build());
|
|
|
|
group->addChild(transform.get());
|
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);
|
|
|
|
osg::Matrix position(geod.makeZUpFrame());
|
|
|
|
// Move the precipitation object to player position
|
|
|
|
transform->setMatrix(position);
|
|
|
|
// Add to scene graph
|
|
|
|
osg::Group* scenery = globals->get_scenery()->get_scene_graph();
|
|
|
|
scenery->addChild(getObject());
|
2008-11-25 22:50:04 +00:00
|
|
|
fgGetNode("environment/params/precipitation-level-ft", true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGPrecipitationMgr::setPrecipitationLevel(double a)
|
|
|
|
{
|
|
|
|
fgSetDouble("environment/params/precipitation-level-ft",a);
|
2008-03-04 09:03:54 +00:00
|
|
|
}
|
2008-03-04 09:02:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get OSG precipitation object
|
|
|
|
*
|
|
|
|
* @returns A pointer on the OSG object (osg::Group *)
|
|
|
|
*/
|
|
|
|
osg::Group * FGPrecipitationMgr::getObject(void)
|
|
|
|
{
|
2008-03-04 09:03:54 +00:00
|
|
|
return this->group.get();
|
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
|
|
|
|
* find precipitation. The value is returned in meter.
|
|
|
|
*/
|
|
|
|
float FGPrecipitationMgr::getPrecipitationAtAltitudeMax(void)
|
|
|
|
{
|
2008-03-04 09:03:54 +00:00
|
|
|
int i;
|
|
|
|
int max;
|
2008-11-02 09:45:31 +00:00
|
|
|
double elev;
|
2008-03-04 09:03:54 +00:00
|
|
|
float result;
|
2008-11-02 09:45:31 +00:00
|
|
|
SGPropertyNode *boundaryNode, *boundaryEntry;
|
2008-03-04 09:03:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
// By default (not cloud layer)
|
|
|
|
max = SGCloudLayer::SG_MAX_CLOUD_COVERAGES;
|
|
|
|
result = 0;
|
|
|
|
|
|
|
|
// 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 ) {
|
|
|
|
elev = boundaryEntry->getDoubleValue( "elevation-ft" );
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-11-25 22:50:04 +00:00
|
|
|
altitudeCloudLayer = this->getPrecipitationAtAltitudeMax() * SG_METER_TO_FEET;
|
|
|
|
setPrecipitationLevel(altitudeCloudLayer);
|
|
|
|
|
2008-11-02 09:45:31 +00:00
|
|
|
// Does the user enable the precipitation ?
|
|
|
|
if (!sgEnviro.get_precipitation_enable_state()) {
|
|
|
|
// Disable precipitations
|
|
|
|
precipitation->setRainIntensity(0);
|
|
|
|
precipitation->setSnowIntensity(0);
|
|
|
|
|
|
|
|
// Update the drawing...
|
|
|
|
precipitation->update();
|
|
|
|
|
|
|
|
// Exit
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
rain_intensity = fgGetDouble("/environment/metar/rain-norm", 0.0);
|
|
|
|
snow_intensity = fgGetDouble("/environment/metar/snow-norm", 0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|