1999-08-10 03:40:34 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
|
|
|
|
Module: FGLocalWeatherDatabase.cpp
|
|
|
|
Author: Christian Mayer
|
|
|
|
Date started: 28.05.99
|
|
|
|
Called by: main program
|
|
|
|
|
|
|
|
---------- Copyright (C) 1999 Christian Mayer (vader@t-online.de) ----------
|
|
|
|
|
|
|
|
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., 59 Temple
|
|
|
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
Further information about the GNU General Public License can also be found on
|
|
|
|
the world wide web at http://www.gnu.org.
|
|
|
|
|
|
|
|
FUNCTIONAL DESCRIPTION
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
Database for the local weather
|
|
|
|
This database is the only one that gets called from FG
|
|
|
|
|
|
|
|
HISTORY
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
28.05.1999 Christian Mayer Created
|
|
|
|
16.06.1999 Durk Talsma Portability for Linux
|
|
|
|
20.06.1999 Christian Mayer added lots of consts
|
1999-10-14 20:30:54 +00:00
|
|
|
11.10.1999 Christian Mayer changed set<> to map<> on Bernie Bright's
|
|
|
|
suggestion
|
1999-08-10 03:40:34 +00:00
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/* INCLUDES */
|
|
|
|
/****************************************************************************/
|
|
|
|
#include "FGLocalWeatherDatabase.h"
|
|
|
|
#include "FGVoronoi.h"
|
|
|
|
#include "fg_constants.h"
|
|
|
|
|
|
|
|
#include <Aircraft/aircraft.hxx>
|
|
|
|
#include <Include/fg_constants.h>
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/********************************** CODE ************************************/
|
|
|
|
/****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/* return the index (better: ID) of the area with point p */
|
|
|
|
/****************************************************************************/
|
|
|
|
unsigned int FGLocalWeatherDatabase::AreaWith(const Point2D& p) const
|
|
|
|
{
|
|
|
|
|
|
|
|
for (FGMicroWeatherList::size_type i = 0; i != WeatherAreas.size(); i++)
|
|
|
|
{
|
|
|
|
if (WeatherAreas[i].hasPoint(p) == true)
|
|
|
|
return i+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; //nothing found
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/* make tiles out of points on a 2D plane */
|
|
|
|
/****************************************************************************/
|
|
|
|
void FGLocalWeatherDatabase::tileLocalWeather(const FGPhysicalProperties2DVector& EntryList)
|
|
|
|
{
|
|
|
|
FGVoronoiInputList input;
|
|
|
|
|
|
|
|
for (FGPhysicalProperties2DVector::const_iterator it1 = EntryList.begin(); it1 != EntryList.end(); it1++)
|
|
|
|
input.push_back(FGVoronoiInput(it1->p, *it1));
|
|
|
|
|
|
|
|
FGVoronoiOutputList output = Voronoiate(input);
|
|
|
|
|
|
|
|
for (FGVoronoiOutputList::iterator it2 = output.begin(); it2 != output.end(); it2++)
|
|
|
|
WeatherAreas.push_back(FGMicroWeather(it2->value, it2->boundary));
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Constructor and Destructor */
|
|
|
|
/****************************************************************************/
|
|
|
|
FGLocalWeatherDatabase* FGLocalWeatherDatabase::theFGLocalWeatherDatabase = 0;
|
|
|
|
FGLocalWeatherDatabase *WeatherDatabase;
|
|
|
|
|
|
|
|
FGLocalWeatherDatabase::FGLocalWeatherDatabase(const Point3D& posititon, const WeatherPrecition& visibility, const DatabaseWorkingType& type)
|
|
|
|
{
|
|
|
|
cerr << "Initializing FGLocalWeatherDatabase\n";
|
|
|
|
cerr << "-----------------------------------\n";
|
|
|
|
|
|
|
|
if (theFGLocalWeatherDatabase)
|
|
|
|
{
|
|
|
|
//FG_LOG( FG_GENERAL, FG_ALERT, "Error: only one local weather allowed" );
|
|
|
|
cerr << "Error: only one local weather allowed";
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
setWeatherVisibility(visibility);
|
|
|
|
//WeatherVisibility = visibility;
|
|
|
|
DatabaseStatus = type;
|
|
|
|
global = 0; //just get sure...
|
|
|
|
last_known_position = posititon;
|
|
|
|
|
|
|
|
|
|
|
|
theFGLocalWeatherDatabase = this;
|
|
|
|
|
|
|
|
switch(DatabaseStatus)
|
|
|
|
{
|
|
|
|
case use_global:
|
|
|
|
{
|
|
|
|
global = new FGGlobalWeatherDatabase; //initialize GlobalDatabase
|
|
|
|
global->setDatabaseStatus(FGGlobalWeatherDatabase_working);
|
|
|
|
tileLocalWeather(global->getAll(posititon, WeatherVisibility, 3));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case distant:
|
|
|
|
cerr << "FGLocalWeatherDatabase error: Distant database isn't implemented yet!\n";
|
|
|
|
cerr << " using random mode instead!\n";
|
|
|
|
case random:
|
|
|
|
case manual:
|
|
|
|
case default_mode:
|
|
|
|
{
|
|
|
|
vector<Point2D> emptyList;
|
|
|
|
WeatherAreas.push_back(FGMicroWeather(FGPhysicalProperties2D(), emptyList)); //in these cases I've only got one tile
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
cerr << "FGLocalWeatherDatabase error: Unknown database type specified!\n";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
FGLocalWeatherDatabase::~FGLocalWeatherDatabase()
|
|
|
|
{
|
|
|
|
//Tidying up:
|
|
|
|
|
|
|
|
//delete every stored area
|
|
|
|
WeatherAreas.erase(WeatherAreas.begin(), WeatherAreas.end());
|
|
|
|
|
|
|
|
//delete global database if necessary
|
|
|
|
if (DatabaseStatus == use_global)
|
|
|
|
delete global;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/* reset the whole database */
|
|
|
|
/****************************************************************************/
|
|
|
|
void FGLocalWeatherDatabase::reset(const DatabaseWorkingType& type)
|
|
|
|
{
|
|
|
|
//delete global database if necessary
|
|
|
|
if ((DatabaseStatus == use_global) && (type != use_global))
|
|
|
|
delete global;
|
|
|
|
|
|
|
|
DatabaseStatus = type;
|
|
|
|
if (DatabaseStatus == use_global)
|
|
|
|
tileLocalWeather(global->getAll(last_known_position, WeatherVisibility, 3));
|
|
|
|
|
|
|
|
//delete every stored area
|
|
|
|
WeatherAreas.erase(WeatherAreas.begin(), WeatherAreas.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/* update the database. Since the last call we had dt seconds */
|
|
|
|
/****************************************************************************/
|
|
|
|
void FGLocalWeatherDatabase::update(const WeatherPrecition& dt)
|
|
|
|
{
|
|
|
|
if (DatabaseStatus==use_global)
|
|
|
|
global->update(dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGLocalWeatherDatabase::update(const Point3D& p) //position has changed
|
|
|
|
{
|
|
|
|
last_known_position = p;
|
|
|
|
//cerr << "****\nupdate inside\n";
|
|
|
|
//cerr << "Parameter: " << p << "\n";
|
|
|
|
//cerr << "****\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGLocalWeatherDatabase::update(const Point3D& p, const WeatherPrecition& dt) //time and/or position has changed
|
|
|
|
{
|
|
|
|
last_known_position = p;
|
|
|
|
|
|
|
|
if (DatabaseStatus==use_global)
|
|
|
|
global->update(dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Get the physical properties on the specified point p out of the database */
|
|
|
|
/****************************************************************************/
|
|
|
|
FGPhysicalProperty FGLocalWeatherDatabase::get(const Point3D& p) const
|
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
|
|
|
return WeatherAreas[a-1].get(p.elev());
|
|
|
|
else //point is outside => ask GlobalWeatherDatabase
|
|
|
|
return global->get(p);
|
|
|
|
}
|
|
|
|
|
1999-10-12 03:30:24 +00:00
|
|
|
FGPhysicalProperty FGLocalWeatherDatabase::get(const sgVec3& p) const
|
|
|
|
{
|
|
|
|
Point3D temp(p[0], p[1], p[2]);
|
|
|
|
|
|
|
|
unsigned int a = AreaWith(temp);
|
|
|
|
if (a != 0)
|
|
|
|
return WeatherAreas[a-1].get(temp.elev());
|
|
|
|
else //point is outside => ask GlobalWeatherDatabase
|
|
|
|
return global->get(temp);
|
|
|
|
}
|
|
|
|
|
1999-10-14 20:30:54 +00:00
|
|
|
FGPhysicalProperties FGLocalWeatherDatabase::get(const sgVec2& p) const
|
|
|
|
{
|
|
|
|
Point3D temp(p[0], p[1], 0.0);
|
|
|
|
|
|
|
|
unsigned int a = AreaWith(temp);
|
|
|
|
if (a != 0)
|
|
|
|
return WeatherAreas[a-1].get();
|
|
|
|
else //point is outside => ask GlobalWeatherDatabase
|
|
|
|
return global->get(p);
|
|
|
|
}
|
|
|
|
|
1999-08-10 03:40:34 +00:00
|
|
|
WeatherPrecition FGLocalWeatherDatabase::getAirDensity(const Point3D& p) const
|
|
|
|
{
|
|
|
|
FGPhysicalProperty dummy;
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
|
|
|
dummy = WeatherAreas[a-1].get(p.elev());
|
|
|
|
else //point is outside => ask GlobalWeatherDatabase
|
|
|
|
dummy = global->get(p);
|
|
|
|
|
|
|
|
return
|
|
|
|
(dummy.AirPressure*FG_WEATHER_DEFAULT_AIRDENSITY*FG_WEATHER_DEFAULT_TEMPERATURE) /
|
|
|
|
(dummy.Temperature*FG_WEATHER_DEFAULT_AIRPRESSURE);
|
|
|
|
}
|
|
|
|
|
1999-10-12 03:30:24 +00:00
|
|
|
WeatherPrecition FGLocalWeatherDatabase::getAirDensity(const sgVec3& p) const
|
|
|
|
{
|
|
|
|
Point3D temp(p[0], p[1], p[2]);
|
|
|
|
|
|
|
|
FGPhysicalProperty dummy;
|
|
|
|
unsigned int a = AreaWith(temp);
|
|
|
|
if (a != 0)
|
|
|
|
dummy = WeatherAreas[a-1].get(temp.elev());
|
|
|
|
else //point is outside => ask GlobalWeatherDatabase
|
|
|
|
dummy = global->get(temp);
|
|
|
|
|
|
|
|
return
|
|
|
|
(dummy.AirPressure*FG_WEATHER_DEFAULT_AIRDENSITY*FG_WEATHER_DEFAULT_TEMPERATURE) /
|
|
|
|
(dummy.Temperature*FG_WEATHER_DEFAULT_AIRPRESSURE);
|
|
|
|
}
|
1999-08-10 03:40:34 +00:00
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Add a weather feature at the point p and surrounding area */
|
|
|
|
/****************************************************************************/
|
1999-10-14 20:30:54 +00:00
|
|
|
void FGLocalWeatherDatabase::addWind(const WeatherPrecition alt, const Point3D& x, const Point2D& p)
|
1999-08-10 03:40:34 +00:00
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
1999-10-14 20:30:54 +00:00
|
|
|
WeatherAreas[a-1].addWind(alt, x);
|
1999-08-10 03:40:34 +00:00
|
|
|
}
|
|
|
|
|
1999-10-14 20:30:54 +00:00
|
|
|
void FGLocalWeatherDatabase::addTurbulence(const WeatherPrecition alt, const Point3D& x, const Point2D& p)
|
1999-08-10 03:40:34 +00:00
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
1999-10-14 20:30:54 +00:00
|
|
|
WeatherAreas[a-1].addTurbulence(alt, x);
|
1999-08-10 03:40:34 +00:00
|
|
|
}
|
|
|
|
|
1999-10-14 20:30:54 +00:00
|
|
|
void FGLocalWeatherDatabase::addTemperature(const WeatherPrecition alt, const WeatherPrecition x, const Point2D& p)
|
1999-08-10 03:40:34 +00:00
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
1999-10-14 20:30:54 +00:00
|
|
|
WeatherAreas[a-1].addTemperature(alt, x);
|
1999-08-10 03:40:34 +00:00
|
|
|
}
|
|
|
|
|
1999-10-14 20:30:54 +00:00
|
|
|
void FGLocalWeatherDatabase::addAirPressure(const WeatherPrecition alt, const WeatherPrecition x, const Point2D& p)
|
1999-08-10 03:40:34 +00:00
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
1999-10-14 20:30:54 +00:00
|
|
|
WeatherAreas[a-1].addAirPressure(alt, x);
|
1999-08-10 03:40:34 +00:00
|
|
|
}
|
|
|
|
|
1999-10-14 20:30:54 +00:00
|
|
|
void FGLocalWeatherDatabase::addVaporPressure(const WeatherPrecition alt, const WeatherPrecition x, const Point2D& p)
|
1999-08-10 03:40:34 +00:00
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
1999-10-14 20:30:54 +00:00
|
|
|
WeatherAreas[a-1].addVaporPressure(alt, x);
|
1999-08-10 03:40:34 +00:00
|
|
|
}
|
|
|
|
|
1999-10-14 20:30:54 +00:00
|
|
|
void FGLocalWeatherDatabase::addCloud(const WeatherPrecition alt, const FGCloudItem& x, const Point2D& p)
|
1999-08-10 03:40:34 +00:00
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
1999-10-14 20:30:54 +00:00
|
|
|
WeatherAreas[a-1].addCloud(alt, x);
|
1999-08-10 03:40:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FGLocalWeatherDatabase::setSnowRainIntensity(const WeatherPrecition& x, const Point2D& p)
|
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
|
|
|
WeatherAreas[a-1].setSnowRainIntensity(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGLocalWeatherDatabase::setSnowRainType(const SnowRainType& x, const Point2D& p)
|
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
|
|
|
WeatherAreas[a-1].setSnowRainType(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGLocalWeatherDatabase::setLightningProbability(const WeatherPrecition& x, const Point2D& p)
|
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(p);
|
|
|
|
if (a != 0)
|
|
|
|
WeatherAreas[a-1].setLightningProbability(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGLocalWeatherDatabase::addProperties(const FGPhysicalProperties2D& x)
|
|
|
|
{
|
|
|
|
if (DatabaseStatus==use_global)
|
|
|
|
{
|
|
|
|
global->add(x);
|
|
|
|
|
|
|
|
//BAD, BAD, BAD thing I'm doing here: I'm adding to the global database a point that
|
|
|
|
//changes my voronoi diagram but I don't update it! instead I'm changing one local value
|
|
|
|
//that could be anywhere!!
|
|
|
|
//This only *might* work when the plane moves so far so fast that the diagram gets new
|
|
|
|
//calculated soon...
|
|
|
|
unsigned int a = AreaWith(x.p);
|
|
|
|
if (a != 0)
|
|
|
|
WeatherAreas[a-1].setStoredWeather(x);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(x.p);
|
|
|
|
if (a != 0)
|
|
|
|
WeatherAreas[a-1].setStoredWeather(x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGLocalWeatherDatabase::setProperties(const FGPhysicalProperties2D& x)
|
|
|
|
{
|
|
|
|
if (DatabaseStatus==use_global)
|
|
|
|
{
|
|
|
|
global->change(x);
|
|
|
|
|
|
|
|
//BAD, BAD, BAD thing I'm doing here: I'm adding to the global database a point that
|
|
|
|
//changes my voronoi diagram but I don't update it! Instead I'm changing one local value
|
|
|
|
//that could be anywhere!!
|
|
|
|
//This only *might* work when the plane moves so far so fast that the diagram gets newly
|
|
|
|
//calculated soon...
|
|
|
|
unsigned int a = AreaWith(x.p);
|
|
|
|
if (a != 0)
|
|
|
|
WeatherAreas[a-1].setStoredWeather(x);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned int a = AreaWith(x.p);
|
|
|
|
if (a != 0)
|
|
|
|
WeatherAreas[a-1].setStoredWeather(x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void fgUpdateWeatherDatabase(void)
|
|
|
|
{
|
|
|
|
//cerr << "FGLocalWeatherDatabase::update()\n";
|
|
|
|
WeatherDatabase->update( Point3D(
|
|
|
|
current_aircraft.fdm_state->get_Latitude(),
|
|
|
|
current_aircraft.fdm_state->get_Longitude(),
|
|
|
|
current_aircraft.fdm_state->get_Altitude() * FEET_TO_METER) );
|
|
|
|
}
|
|
|
|
|