Merge branch 'next' of git://gitorious.org/fg/simgear into next

This commit is contained in:
Erik Hofman
2011-10-23 10:39:26 +02:00
15 changed files with 335 additions and 257 deletions

View File

@@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 2.6.4)
include (CheckFunctionExists)
include (CheckIncludeFile)
include (CheckCXXSourceCompiles)
include (CPack)
project(SimGear)
@@ -18,6 +18,7 @@ SET(CPACK_PACKAGE_VENDOR "The FlightGear project")
SET(CPACK_GENERATOR "TBZ2")
SET(CPACK_INSTALL_CMAKE_PROJECTS ${CMAKE_CURRENT_BINARY_DIR};SimGear;ALL;/)
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CPACK_PACKAGE_VERSION ${SIMGEAR_VERSION} )
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
@@ -26,6 +27,15 @@ set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
message(STATUS "version is ${CPACK_PACKAGE_VERSION_MAJOR} dot ${CPACK_PACKAGE_VERSION_MINOR} dot ${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_SOURCE_GENERATOR TBZ2)
set(CPACK_SOURCE_PACKAGE_FILE_NAME "simgear-${SIMGEAR_VERSION}" CACHE INTERNAL "tarball basename")
set(CPACK_SOURCE_IGNORE_FILES
"^${PROJECT_SOURCE_DIR}/.git;\\\\.gitignore;Makefile.am;~$;${CPACK_SOURCE_IGNORE_FILES}")
message(STATUS "ignoring: ${CPACK_SOURCE_IGNORE_FILES}")
include (CPack)
# We have some custom .cmake scripts not in the official distribution.
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}")

View File

@@ -5,3 +5,12 @@ set(HEADERS metar.hxx precipitation.hxx)
set(SOURCES metar.cxx precipitation.cxx)
simgear_component(environment environment "${SOURCES}" "${HEADERS}")
add_executable(test_metar test_metar.cxx)
target_link_libraries(test_metar
sgenvironment sgstructure sgmisc sgdebug
${CMAKE_THREAD_LIBS_INIT}
${ZLIB_LIBRARY}
${RT_LIBRARY})
add_test(metar ${EXECUTABLE_OUTPUT_PATH}/test_metar)

View File

@@ -32,7 +32,6 @@
#include <time.h>
#include <cstring>
#include <simgear/io/sg_socket.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
@@ -40,32 +39,28 @@
#define NaN SGMetarNaN
using std::string;
using std::map;
using std::vector;
/**
* The constructor takes a Metar string, or a four-letter ICAO code. In the
* latter case the metar string is downloaded from
* http://weather.noaa.gov/pub/data/observations/metar/stations/.
* The constructor takes a Metar string
* The constructor throws sg_io_exceptions on failure. The "METAR"
* keyword has no effect (apart from incrementing the group counter
* @a grpcount) and can be left away. A keyword "SPECI" is
* likewise accepted.
*
* @param m ICAO station id or metar string
* @param proxy proxy host (optional; default: "")
* @param port proxy port (optional; default: "80")
* @param auth proxy authorization information (optional; default: "")
*
* @par Examples:
* @code
* SGMetar *m = new SGMetar("METAR KSFO 061656Z 19004KT 9SM SCT100 OVC200 08/03 A3013");
* double t = m->getTemperature_F();
* delete m;
*
* SGMetar n("KSFO", "proxy.provider.foo", "3128", "proxy-password");
* double d = n.getDewpoint_C();
* @endcode
*/
SGMetar::SGMetar(const string& m, const string& proxy, const string& port,
const string& auth, const time_t time) :
SGMetar::SGMetar(const string& m) :
_grpcount(0),
_x_proxy(false),
_year(-1),
@@ -87,16 +82,10 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port,
_snow(false),
_cavok(false)
{
if (m.length() == 4 && isalnum(m[0]) && isalnum(m[1]) && isalnum(m[2]) && isalnum(m[3])) {
for (int i = 0; i < 4; i++)
_icao[i] = toupper(m[i]);
_icao[4] = '\0';
_data = loadData(_icao, proxy, port, auth, time);
} else {
_data = new char[m.length() + 2]; // make room for " \0"
strcpy(_data, m.c_str());
_url = _data;
}
_data = new char[m.length() + 2]; // make room for " \0"
strcpy(_data, m.c_str());
_url = _data;
normalizeData();
_m = _data;
@@ -169,85 +158,6 @@ void SGMetar::useCurrentDate()
_month = now.tm_mon + 1;
}
/**
* If called with "KSFO" loads data from
* @code
* http://weather.noaa.gov/pub/data/observations/metar/stations/KSFO.TXT.
* @endcode
* Throws sg_io_exception on failure. Gives up after waiting longer than 10 seconds.
*
* @param id four-letter ICAO Metar station code, e.g. "KSFO".
* @param proxy proxy host (optional; default: "")
* @param port proxy port (optional; default: "80")
* @param auth proxy authorization information (optional; default: "")
* @return pointer to Metar data string, allocated by new char[].
* @see rfc2068.txt for proxy spec ("Proxy-Authorization")
*/
char *SGMetar::loadData(const char *id, const string& proxy, const string& port,
const string& auth, time_t time)
{
const int buflen = 512;
char buf[2 * buflen];
string metar_server = "weather.noaa.gov";
string host = proxy.empty() ? metar_server : proxy;
string path = "/pub/data/observations/metar/stations/";
path += string(id) + ".TXT";
_url = "http://" + metar_server + path;
SGSocket *sock = new SGSocket(host, port.empty() ? "80" : port, "tcp");
sock->set_timeout(10000);
if (!sock->open(SG_IO_OUT)) {
delete sock;
throw sg_io_exception("cannot connect to ", sg_location(host));
}
string get = "GET ";
if (!proxy.empty())
get += "http://" + metar_server;
sprintf(buf, "%ld", time);
get += path + " HTTP/1.0\015\012X-Time: " + buf + "\015\012";
get += "Host: " + metar_server + "\015\012";
if (!auth.empty())
get += "Proxy-Authorization: " + auth + "\015\012";
get += "\015\012";
sock->writestring(get.c_str());
int i;
// skip HTTP header
while ((i = sock->readline(buf, buflen))) {
if (i <= 2 && isspace(buf[0]) && (!buf[1] || isspace(buf[1])))
break;
if (!strncmp(buf, "X-MetarProxy: ", 13))
_x_proxy = true;
}
if (i) {
i = sock->readline(buf, buflen);
if (i)
sock->readline(&buf[i], buflen);
}
sock->close();
delete sock;
char *b = buf;
scanBoundary(&b);
if (*b == '<')
throw sg_io_exception("no metar data available from ",
sg_location(_url));
char *metar = new char[strlen(b) + 2]; // make room for " \0"
strcpy(metar, b);
return metar;
}
/**
* Replace any number of subsequent spaces by just one space, and add
* a trailing space. This makes scanning for things like "ALL RWY" easier.

View File

@@ -29,18 +29,12 @@
#include <simgear/constants.h>
using std::vector;
using std::map;
using std::string;
const double SGMetarNaN = -1E20;
#define NaN SGMetarNaN
struct Token {
const char *id;
const char *text;
};
const double SGMetarNaN = -1E20;
class SGMetar;
@@ -48,7 +42,7 @@ class SGMetarVisibility {
friend class SGMetar;
public:
SGMetarVisibility() :
_distance(NaN),
_distance(SGMetarNaN),
_direction(-1),
_modifier(EQUALS),
_tendency(NONE) {}
@@ -70,8 +64,8 @@ public:
void set(double dist, int dir = -1, int mod = -1, int tend = -1);
inline double getVisibility_m() const { return _distance; }
inline double getVisibility_ft() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_FEET; }
inline double getVisibility_sm() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_SM; }
inline double getVisibility_ft() const { return _distance == SGMetarNaN ? SGMetarNaN : _distance * SG_METER_TO_FEET; }
inline double getVisibility_sm() const { return _distance == SGMetarNaN ? SGMetarNaN : _distance * SG_METER_TO_SM; }
inline int getDirection() const { return _direction; }
inline int getModifier() const { return _modifier; }
inline int getTendency() const { return _tendency; }
@@ -93,8 +87,8 @@ public:
_deposit_string(0),
_extent(-1),
_extent_string(0),
_depth(NaN),
_friction(NaN),
_depth(SGMetarNaN),
_friction(SGMetarNaN),
_friction_string(0),
_comment(0),
_wind_shear(false) {}
@@ -146,14 +140,14 @@ public:
static const char * COVERAGE_BROKEN_STRING;
static const char * COVERAGE_OVERCAST_STRING;
SGMetarCloud() : _coverage(COVERAGE_NIL), _altitude(NaN), _type(0), _type_long(0) {}
SGMetarCloud() : _coverage(COVERAGE_NIL), _altitude(SGMetarNaN), _type(0), _type_long(0) {}
void set(double alt, Coverage cov = COVERAGE_NIL );
inline Coverage getCoverage() const { return _coverage; }
static Coverage getCoverage( const std::string & coverage );
inline double getAltitude_m() const { return _altitude; }
inline double getAltitude_ft() const { return _altitude == NaN ? NaN : _altitude * SG_METER_TO_FEET; }
inline double getAltitude_ft() const { return _altitude == SGMetarNaN ? SGMetarNaN : _altitude * SG_METER_TO_FEET; }
inline const char *getTypeString() const { return _type; }
inline const char *getTypeLongString() const { return _type_long; }
@@ -167,8 +161,7 @@ protected:
class SGMetar {
public:
SGMetar(const string& m, const string& proxy = "", const string& port = "",
const string &auth = "", const time_t time = 0);
SGMetar(const std::string& m);
~SGMetar();
enum ReportType {
@@ -189,8 +182,8 @@ public:
Weather() { intensity = NIL; vincinity = false; }
Intensity intensity;
bool vincinity;
vector<string> descriptions;
vector<string> phenomena;
std::vector<std::string> descriptions;
std::vector<std::string> phenomena;
};
inline const char *getData() const { return _data; }
@@ -206,14 +199,14 @@ public:
inline int getWindDir() const { return _wind_dir; }
inline double getWindSpeed_mps() const { return _wind_speed; }
inline double getWindSpeed_kmh() const { return _wind_speed == NaN ? NaN : _wind_speed * SG_MPS_TO_KMH; }
inline double getWindSpeed_kt() const { return _wind_speed == NaN ? NaN : _wind_speed * SG_MPS_TO_KT; }
inline double getWindSpeed_mph() const { return _wind_speed == NaN ? NaN : _wind_speed * SG_MPS_TO_MPH; }
inline double getWindSpeed_kmh() const { return _wind_speed == SGMetarNaN ? SGMetarNaN : _wind_speed * SG_MPS_TO_KMH; }
inline double getWindSpeed_kt() const { return _wind_speed == SGMetarNaN ? SGMetarNaN : _wind_speed * SG_MPS_TO_KT; }
inline double getWindSpeed_mph() const { return _wind_speed == SGMetarNaN ? SGMetarNaN : _wind_speed * SG_MPS_TO_MPH; }
inline double getGustSpeed_mps() const { return _gust_speed; }
inline double getGustSpeed_kmh() const { return _gust_speed == NaN ? NaN : _gust_speed * SG_MPS_TO_KMH; }
inline double getGustSpeed_kt() const { return _gust_speed == NaN ? NaN : _gust_speed * SG_MPS_TO_KT; }
inline double getGustSpeed_mph() const { return _gust_speed == NaN ? NaN : _gust_speed * SG_MPS_TO_MPH; }
inline double getGustSpeed_kmh() const { return _gust_speed == SGMetarNaN ? SGMetarNaN : _gust_speed * SG_MPS_TO_KMH; }
inline double getGustSpeed_kt() const { return _gust_speed == SGMetarNaN ? SGMetarNaN : _gust_speed * SG_MPS_TO_KT; }
inline double getGustSpeed_mph() const { return _gust_speed == SGMetarNaN ? SGMetarNaN : _gust_speed * SG_MPS_TO_MPH; }
inline int getWindRangeFrom() const { return _wind_range_from; }
inline int getWindRangeTo() const { return _wind_range_to; }
@@ -224,11 +217,11 @@ public:
inline const SGMetarVisibility *getDirVisibility() const { return _dir_visibility; }
inline double getTemperature_C() const { return _temp; }
inline double getTemperature_F() const { return _temp == NaN ? NaN : 1.8 * _temp + 32; }
inline double getTemperature_F() const { return _temp == SGMetarNaN ? SGMetarNaN : 1.8 * _temp + 32; }
inline double getDewpoint_C() const { return _dewp; }
inline double getDewpoint_F() const { return _dewp == NaN ? NaN : 1.8 * _dewp + 32; }
inline double getPressure_hPa() const { return _pressure == NaN ? NaN : _pressure / 100; }
inline double getPressure_inHg() const { return _pressure == NaN ? NaN : _pressure * SG_PA_TO_INHG; }
inline double getDewpoint_F() const { return _dewp == SGMetarNaN ? SGMetarNaN : 1.8 * _dewp + 32; }
inline double getPressure_hPa() const { return _pressure == SGMetarNaN ? SGMetarNaN : _pressure / 100; }
inline double getPressure_inHg() const { return _pressure == SGMetarNaN ? SGMetarNaN : _pressure * SG_PA_TO_INHG; }
inline int getRain() const { return _rain; }
inline int getHail() const { return _hail; }
@@ -237,13 +230,13 @@ public:
double getRelHumidity() const;
inline const vector<SGMetarCloud>& getClouds() const { return _clouds; }
inline const map<string, SGMetarRunway>& getRunways() const { return _runways; }
inline const vector<string>& getWeather() const { return _weather; }
inline const vector<struct Weather> getWeather2() const { return _weather2; }
inline const std::vector<SGMetarCloud>& getClouds() const { return _clouds; }
inline const std::map<std::string, SGMetarRunway>& getRunways() const { return _runways; }
inline const std::vector<std::string>& getWeather() const { return _weather; }
inline const std::vector<struct Weather> getWeather2() const { return _weather2; }
protected:
string _url;
std::string _url;
int _grpcount;
bool _x_proxy;
char *_data;
@@ -267,15 +260,15 @@ protected:
int _hail;
int _snow;
bool _cavok;
vector<struct Weather> _weather2;
std::vector<struct Weather> _weather2;
SGMetarVisibility _min_visibility;
SGMetarVisibility _max_visibility;
SGMetarVisibility _vert_visibility;
SGMetarVisibility _dir_visibility[8];
vector<SGMetarCloud> _clouds;
map<string, SGMetarRunway> _runways;
vector<string> _weather;
std::vector<SGMetarCloud> _clouds;
std::map<std::string, SGMetarRunway> _runways;
std::vector<std::string> _weather;
bool scanPreambleDate();
bool scanPreambleTime();
@@ -303,10 +296,7 @@ protected:
int scanNumber(char **str, int *num, int min, int max = 0);
bool scanBoundary(char **str);
const struct Token *scanToken(char **str, const struct Token *list);
char *loadData(const char *id, const string& proxy, const string& port,
const string &auth, time_t time);
void normalizeData();
};
#undef NaN
#endif // _METAR_HXX

View File

@@ -0,0 +1,76 @@
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#ifdef _MSC_VER
# define random rand
#endif
#include <simgear/misc/sg_dir.hxx>
#include <simgear/structure/exception.hxx>
#include "metar.hxx"
using std::cout;
using std::cerr;
using std::endl;
using std::string;
#define COMPARE(a, b) \
if ((a) != (b)) { \
cerr << "failed:" << #a << " != " << #b << endl; \
cerr << "\tgot:" << a << endl; \
exit(1); \
}
#define FUZZY_COMPARE(a, b, epsilon) \
if (fabs(a - b) > epsilon) { \
cerr << "failed:" << #a << " != " << #b << endl; \
cerr << "\tgot:" << a << endl; \
cerr << "\tepsilon:" << epsilon << endl; \
}
#define VERIFY(a) \
if (!(a)) { \
cerr << "failed:" << #a << endl; \
exit(1); \
}
const double TEST_EPSILON = 1e-9;
void test_basic()
{
SGMetar m1("2011/10/20 11:25 EHAM 201125Z 27012KT 240V300 9999 VCSH FEW025CB SCT048 10/05 Q1025 TEMPO VRB03KT");
COMPARE(m1.getYear(), 2011);
COMPARE(m1.getMonth(), 10);
COMPARE(m1.getDay(), 20);
COMPARE(m1.getHour(), 11);
COMPARE(m1.getMinute(), 25);
COMPARE(m1.getReportType(), -1); // should default to NIL?
COMPARE(m1.getWindDir(), 270);
FUZZY_COMPARE(m1.getWindSpeed_kt(), 12, TEST_EPSILON);
FUZZY_COMPARE(m1.getTemperature_C(), 10, TEST_EPSILON);
FUZZY_COMPARE(m1.getDewpoint_C(), 5, TEST_EPSILON);
FUZZY_COMPARE(m1.getPressure_hPa(), 1025, TEST_EPSILON);
}
int main(int argc, char* argv[])
{
try {
test_basic();
} catch (sg_exception& e) {
cerr << "got exception:" << e.getMessage() << endl;
return -1;
}
return 0;
}

View File

@@ -47,22 +47,37 @@ using std::string;
namespace simgear
{
Dir::Dir()
Dir::Dir() :
_removeOnDestroy(false)
{
}
Dir::Dir(const SGPath& path) :
_path(path)
_path(path),
_removeOnDestroy(false)
{
_path.set_cached(false); // disable caching, so create/remove work
}
Dir::Dir(const Dir& rel, const SGPath& relPath) :
_path(rel.file(relPath.str()))
_path(rel.file(relPath.str())),
_removeOnDestroy(false)
{
_path.set_cached(false); // disable caching, so create/remove work
}
Dir::~Dir()
{
if (_removeOnDestroy) {
remove(true);
}
}
void Dir::setRemoveOnDestroy()
{
_removeOnDestroy = true;
}
Dir Dir::current()
{
#ifdef _WIN32
@@ -79,7 +94,7 @@ Dir Dir::tempDir(const std::string& templ)
{
#ifdef HAVE_MKDTEMP
char buf[1024];
char* tempPath = ::getenv("TMPDIR");
const char* tempPath = ::getenv("TMPDIR");
if (!tempPath) {
tempPath = "/tmp/";
}

View File

@@ -43,7 +43,15 @@ namespace simgear
{
public:
Dir();
~Dir();
/**
* when this directory object is destroyed, remove the corresponding
* diretory (and its contents) from the disk. Often used with temporary
* directories to ensure they are cleaned up.
*/
void setRemoveOnDestroy();
static Dir current();
/**
@@ -93,6 +101,7 @@ namespace simgear
Dir parent() const;
private:
mutable SGPath _path;
bool _removeOnDestroy;
};
} // of namespace simgear

View File

@@ -471,3 +471,16 @@ bool SGPath::operator!=(const SGPath& other) const
return (path != other.path);
}
bool SGPath::rename(const SGPath& newName)
{
if (::rename(c_str(), newName.c_str()) != 0) {
SG_LOG(SG_IO, SG_WARN, "renamed failed: from " << str() << " to " << newName.str()
<< " reason: " << strerror(errno));
return false;
}
path = newName.path;
_cached = false;
return true;
}

View File

@@ -213,6 +213,13 @@ public:
* modification time of the file
*/
time_t modTime() const;
/**
* rename the file / directory we point at, to a new name
* this may fail if the new location is on a different volume / share,
* or if the destination already exists, or is not writeable
*/
bool rename(const SGPath& newName);
private:
void fix();

View File

@@ -278,6 +278,19 @@ namespace simgear {
return v1parts.size() - v2parts.size();
}
string join(const string_list& l, const string& joinWith)
{
string result;
unsigned int count = l.size();
for (unsigned int i=0; i < count; ++i) {
result += l[i];
if (i < (count - 1)) {
result += joinWith;
}
}
return result;
}
} // end namespace strutils

View File

@@ -33,6 +33,7 @@
#include <vector>
#include <cstdlib>
typedef std::vector < std::string > string_list;
namespace simgear {
namespace strutils {
@@ -93,11 +94,17 @@ namespace simgear {
* resulting in at most maxsplit+1 words.
* @return Array of words.
*/
std::vector<std::string>
string_list
split( const std::string& s,
const char* sep = 0,
int maxsplit = 0 );
/**
* create a single string by joining the elements of a list with
* another string.
*/
std::string join(const string_list& l, const std::string& joinWith = "");
/**
* Test if a string starts with a string
*

View File

@@ -63,6 +63,20 @@ int main (int ac, char ** av)
// since we compare numerically, leasing zeros shouldn't matter
VERIFY(compare_versions("0.06.7", "0.6.07") == 0);
string_list la = split("zero one two three four five");
COMPARE(la[2], "two");
COMPARE(la[5], "five");
COMPARE(la.size(), 6);
string_list lb = split("alpha:beta:gamma:delta", ":", 2);
COMPARE(lb.size(), 3);
COMPARE(lb[0], "alpha");
COMPARE(lb[1], "beta");
COMPARE(lb[2], "gamma:delta");
std::string j = join(la, "&");
COMPARE(j, "zero&one&two&three&four&five");
cout << "all tests passed successfully!" << endl;
return 0;
}

View File

@@ -68,8 +68,8 @@ float SGCloudField::fieldSize = 50000.0f;
double SGCloudField::timer_dt = 0.0;
float SGCloudField::view_distance = 20000.0f;
bool SGCloudField::wrap = true;
float SGCloudField::RADIUS_LEVEL_1 = 20000.0f;
float SGCloudField::RADIUS_LEVEL_2 = 5000.0f;
float SGCloudField::RADIUS_LEVEL_1 = 5000.0f;
float SGCloudField::RADIUS_LEVEL_2 = 1000.0f;
SGVec3f SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
@@ -81,7 +81,9 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
if (placed_root->getNumChildren() == 0) return false;
SGVec3<double> cart;
SGGeodesy::SGGeodToCart(SGGeod::fromRadFt(lon, lat, 0.0f), cart);
SGGeod new_pos = SGGeod::fromRadFt(lon, lat, 0.0f);
SGGeodesy::SGGeodToCart(new_pos, cart);
osg::Vec3f osg_pos = toOsg(cart);
osg::Quat orient = toOsg(SGQuatd::fromLonLatRad(lon, lat) * SGQuatd::fromRealImag(0, SGVec3d(0, 1, 0)));
@@ -93,8 +95,6 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
osg::Vec3f wind = osg::Vec3f(-cos((direction + 180)* SGD_DEGREES_TO_RADIANS) * speed * dt,
sin((direction + 180)* SGD_DEGREES_TO_RADIANS) * speed * dt,
0.0f);
//cout << "Wind: " << direction << "@" << speed << "\n";
osg::Vec3f windosg = field_transform->getAttitude() * wind;
field_transform->setPosition(field_transform->getPosition() + windosg);
@@ -108,39 +108,40 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
field_transform->setPosition(osg_pos);
field_transform->setAttitude(orient);
old_pos = osg_pos;
} else {
} else {
osg::Quat fta = field_transform->getAttitude();
osg::Quat ftainv = field_transform->getAttitude().inverse();
// delta is the vector from the old position to the new position in cloud-coords
osg::Vec3f delta = field_transform->getAttitude().inverse() * (osg_pos - old_pos);
//cout << "Delta: " << delta.length() << "\n";
for (unsigned int i = 0; i < placed_root->getNumChildren(); i++) {
osg::ref_ptr<osg::LOD> lodnode1 = (osg::LOD*) placed_root->getChild(i);
osg::Vec3f v = delta - lodnode1->getCenter();
if ((v.x() < -0.5*fieldSize) ||
(v.x() > 0.5*fieldSize) ||
(v.y() < -0.5*fieldSize) ||
(v.y() > 0.5*fieldSize) ) {
//cout << "V: " << v.x() << ", " << v.y() << "\n";
osg::Vec3f shift = osg::Vec3f(0.0f, 0.0f, 0.0f);
if (v.x() > 0.5*fieldSize) { shift += osg::Vec3f(fieldSize, 0.0f, 0.0f); }
if (v.x() < -0.5*fieldSize) { shift -= osg::Vec3f(fieldSize, 0.0f, 0.0f); }
if (v.y() > 0.5*fieldSize) { shift += osg::Vec3f(0.0f, fieldSize, 0.0f); }
if (v.y() < -0.5*fieldSize) { shift -= osg::Vec3f(0.0f, fieldSize, 0.0f); }
//cout << "Shift: " << shift.x() << ", " << shift.y() << "\n\n";
for (unsigned int j = 0; j < lodnode1->getNumChildren(); j++) {
osg::ref_ptr<osg::LOD> lodnode2 = (osg::LOD*) lodnode1->getChild(j);
for (unsigned int k = 0; k < lodnode2->getNumChildren(); k++) {
osg::ref_ptr<osg::PositionAttitudeTransform> pat =(osg::PositionAttitudeTransform*) lodnode2->getChild(k);
pat->setPosition(pat->getPosition() + shift);
}
}
osg::Vec3f delta = ftainv * (osg_pos - old_pos);
old_pos = osg_pos;
// Check if any of the clouds should be moved.
for(CloudHash::const_iterator itr = cloud_hash.begin(), end = cloud_hash.end();
itr != end;
++itr) {
osg::ref_ptr<osg::PositionAttitudeTransform> pat = itr->second;
osg::Vec3f currpos = field_transform->getPosition() + fta * pat->getPosition();
// Determine the vector from the new position to the cloud in cloud-space.
osg::Vec3f w = ftainv * (currpos - toOsg(cart));
// Determine a course if required. Note that this involves some axis translation.
float x = 0.0;
float y = 0.0;
if (w.x() > 0.6*fieldSize) { y = fieldSize; }
if (w.x() < -0.6*fieldSize) { y = -fieldSize; }
if (w.y() > 0.6*fieldSize) { x = -fieldSize; }
if (w.y() < -0.6*fieldSize) { x = fieldSize; }
if ((x != 0.0) || (y != 0.0)) {
removeCloudFromTree(pat);
SGGeod p = SGGeod::fromCart(toSG(field_transform->getPosition() +
fta * pat->getPosition()));
addCloudToTree(pat, p, x, y);
}
}
}
}
// Render the clouds in order from farthest away layer to nearest one.
@@ -231,28 +232,32 @@ void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> t
float lon, float lat, float alt, float x, float y) {
// Get the base position
SGGeod loc = SGGeod::fromDegFt(lon, lat, 0.0);
SGGeod loc = SGGeod::fromDegFt(lon, lat, alt);
addCloudToTree(transform, loc, x, y);
}
void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform,
SGGeod loc, float x, float y) {
float alt = loc.getElevationFt();
// Determine any shift by x/y
if ((x != 0.0f) || (y != 0.0f)) {
double crs;
if (y == 0.0f) {
crs = (x < 0.0f) ? -90.0 : 90.0;
} else {
crs = SG_RADIANS_TO_DEGREES * tan(x/y);
}
double crs = 90.0 - SG_RADIANS_TO_DEGREES * atan2(y, x);
double dst = sqrt(x*x + y*y);
double endcrs;
SGGeod base_pos = SGGeod::fromDegFt(lon, lat, 0.0f);
SGGeod base_pos = SGGeod::fromGeodFt(loc, 0.0f);
SGGeodesy::direct(base_pos, crs, dst, loc, endcrs);
}
// The direct call provides the position at 0 alt, so adjust as required.
loc.setElevationFt(alt);
// The direct call provides the position at 0 alt, so adjust as required.
loc.setElevationFt(alt);
addCloudToTree(transform, loc);
}
void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc) {
// Work out where this cloud should go in OSG coordinates.
SGVec3<double> cart;
SGGeodesy::SGGeodToCart(loc, cart);
@@ -266,16 +271,17 @@ void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> t
// Convert to the scenegraph orientation where we just rotate around
// the y axis 180 degrees.
osg::Quat orient = toOsg(SGQuatd::fromLonLatDeg(loc.getLongitudeDeg(), loc.getLatitudeDeg()) * SGQuatd::fromRealImag(0, SGVec3d(0, 1, 0)));
field_transform->setPosition(toOsg(fieldcenter));
osg::Vec3f osg_pos = toOsg(fieldcenter);
field_transform->setPosition(osg_pos);
field_transform->setAttitude(orient);
old_pos = toOsg(fieldcenter);
old_pos = osg_pos;
}
// Convert position to cloud-coordinates
pos = pos - field_transform->getPosition();
//pos = orient.inverse() * pos;
pos = field_transform->getAttitude().inverse() * pos;
pos = field_transform->getAttitude().inverse() * pos;
// We have a two level dynamic quad tree which the cloud will be added
// to. If there are no appropriate nodes in the quad tree, they are
@@ -288,7 +294,6 @@ void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> t
lodnode1 = (osg::LOD*) placed_root->getChild(i);
if ((lodnode1->getCenter() - pos).length2() < RADIUS_LEVEL_1*RADIUS_LEVEL_1) {
// New cloud is within RADIUS_LEVEL_1 of the center of the LOD node.
//cout << "Adding cloud to existing LoD level 1 node. Distance:" << (lodnode1->getCenter() - pos).length() << "\n";
found = true;
}
}
@@ -296,7 +301,6 @@ void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> t
if (!found) {
lodnode1 = new osg::LOD();
placed_root->addChild(lodnode1.get());
//cout << "Adding cloud to new LoD node\n";
}
// Now check if there is a second level LOD node at an appropriate distance
@@ -306,17 +310,15 @@ void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> t
lodnode = (osg::LOD*) lodnode1->getChild(j);
if ((lodnode->getCenter() - pos).length2() < RADIUS_LEVEL_2*RADIUS_LEVEL_2) {
// We've found the right leaf LOD node
//cout << "Found existing LOD leaf node. Distance:"<< (lodnode->getCenter() - pos).length() << "\n";
found = true;
}
}
}
if (!found) {
// No suitable leave node was found, so we need to add one.
lodnode = new osg::LOD();
lodnode1->addChild(lodnode, 0.0f, 4*RADIUS_LEVEL_1);
//cout << "Adding cloud to new LoD node\n";
}
}
transform->setPosition(pos);
lodnode->addChild(transform.get(), 0.0f, view_distance);

View File

@@ -70,7 +70,7 @@ private:
bool visible;
};
float Rnd(float);
float Rnd(float);
// Radius of the LoD nodes for the dynamic quadtrees.
static float RADIUS_LEVEL_1;
@@ -79,23 +79,25 @@ private:
// this is a relative position only, with that we can move all clouds at once
SGVec3f relative_position;
osg::ref_ptr<osg::Group> field_root;
osg::ref_ptr<osg::Group> field_root;
osg::ref_ptr<osg::Group> placed_root;
osg::ref_ptr<osg::PositionAttitudeTransform> field_transform;
osg::ref_ptr<osg::PositionAttitudeTransform> altitude_transform;
osg::ref_ptr<osg::LOD> field_lod;
osg::ref_ptr<osg::PositionAttitudeTransform> altitude_transform;
osg::ref_ptr<osg::LOD> field_lod;
osg::Vec3f old_pos;
CloudHash cloud_hash;
struct CloudFog : public simgear::Singleton<CloudFog>
{
CloudFog();
osg::ref_ptr<osg::Fog> fog;
};
struct CloudFog : public simgear::Singleton<CloudFog>
{
CloudFog();
osg::ref_ptr<osg::Fog> fog;
};
void removeCloudFromTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform);
void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, float lon, float lat, float alt, float x, float y);
void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc, float x, float y);
void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc);
void applyVisRangeAndCoverage(void);
public:
@@ -122,44 +124,44 @@ public:
/**
* reposition the cloud layer at the specified origin and
* orientation.
* @param p position vector
* @param up the local up vector
* @param lon specifies a rotation about the Z axis
* @param lat specifies a rotation about the new Y axis
* @param dt the time elapsed since the last call
* @param asl altitude of the layer
* @param speed of cloud layer movement (due to wind)
* @param direction of cloud layer movement (due to wind)
*/
bool reposition( const SGVec3f& p, const SGVec3f& up,
double lon, double lat, double dt, int asl, float speed, float direction);
* reposition the cloud layer at the specified origin and
* orientation.
* @param p position vector
* @param up the local up vector
* @param lon specifies a rotation about the Z axis
* @param lat specifies a rotation about the new Y axis
* @param dt the time elapsed since the last call
* @param asl altitude of the layer
* @param speed of cloud layer movement (due to wind)
* @param direction of cloud layer movement (due to wind)
*/
bool reposition( const SGVec3f& p, const SGVec3f& up,
double lon, double lat, double dt, int asl, float speed, float direction);
osg::Group* getNode() { return field_root.get(); }
osg::Group* getNode() { return field_root.get(); }
// visibility distance for clouds in meters
static float CloudVis;
// visibility distance for clouds in meters
static float CloudVis;
static SGVec3f view_vec, view_X, view_Y;
static SGVec3f view_vec, view_X, view_Y;
static float view_distance;
static double timer_dt;
static float fieldSize;
static bool wrap;
static bool getWrap(void) { return wrap; }
static void setWrap(bool w) { wrap = w; }
static float view_distance;
static double timer_dt;
static float fieldSize;
static bool wrap;
static float getVisRange(void) { return view_distance; }
static void setVisRange(float d) { view_distance = d; }
void applyVisRange(void);
static osg::Fog* getFog()
{
return CloudFog::instance()->fog.get();
}
static void updateFog(double visibility, const osg::Vec4f& color);
static bool getWrap(void) { return wrap; }
static void setWrap(bool w) { wrap = w; }
static float getVisRange(void) { return view_distance; }
static void setVisRange(float d) { view_distance = d; }
void applyVisRange(void);
static osg::Fog* getFog()
{
return CloudFog::instance()->fog.get();
}
static void updateFog(double visibility, const osg::Vec4f& color);
};
#endif // _CLOUDFIELD_HXX

View File

@@ -135,11 +135,12 @@ osg::Geometry* SGNewCloud::createOrthQuad(float w, float h, int varieties_x, int
osg::Vec2Array& t = *(new osg::Vec2Array(4));
float cw = w*0.5f;
v[0].set(0.0f, -cw, 0.0f);
v[1].set(0.0f, cw, 0.0f);
v[2].set(0.0f, cw, h);
v[3].set(0.0f, -cw, h);
float ch = h*0.5f;
v[0].set(0.0f, -cw, -ch);
v[1].set(0.0f, cw, -ch);
v[2].set(0.0f, cw, ch);
v[3].set(0.0f, -cw, ch);
// The texture coordinate range is not the
// entire coordinate space - as the texture