Merge branch 'next' into durk-atc
This commit is contained in:
commit
b5025ccf5d
8 changed files with 330 additions and 298 deletions
|
@ -65,7 +65,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="fltkd.lib ul_d.lib comctl32.lib wsock32.lib zlibd.lib sg_d.lib"
|
||||
AdditionalDependencies="fltkd.lib comctl32.lib wsock32.lib zlibd.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="..\..\..\..\3rdParty\lib"
|
||||
GenerateDebugInformation="true"
|
||||
|
@ -145,7 +145,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="fltkd.lib ul_d.lib comctl32.lib wsock32.lib zlibd.lib sg_d.lib"
|
||||
AdditionalDependencies="fltkd.lib comctl32.lib wsock32.lib zlibd.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="..\..\..\..\3rdParty.x64\lib"
|
||||
GenerateDebugInformation="true"
|
||||
|
@ -226,7 +226,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="fltk.lib ul.lib sg.lib comctl32.lib wsock32.lib zlib.lib"
|
||||
AdditionalDependencies="fltk.lib comctl32.lib wsock32.lib zlib.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="..\..\..\..\3rdParty\lib"
|
||||
GenerateDebugInformation="false"
|
||||
|
@ -309,7 +309,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="fltk.lib ul.lib sg.lib comctl32.lib wsock32.lib zlib.lib"
|
||||
AdditionalDependencies="fltk.lib comctl32.lib wsock32.lib zlib.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="..\..\..\..\3rdParty.x64\lib"
|
||||
GenerateDebugInformation="false"
|
||||
|
|
|
@ -219,6 +219,10 @@ FGEnvironmentMgr::bind ()
|
|||
&SGSky::get_3dCloudVisRange,
|
||||
&SGSky::set_3dCloudVisRange);
|
||||
|
||||
_tiedProperties.Tie("clouds3d-wrap", thesky,
|
||||
&SGSky::get_3dCloudWrap,
|
||||
&SGSky::set_3dCloudWrap);
|
||||
|
||||
// _tiedProperties.Tie("lightning-enable", &sgEnviro,
|
||||
// &SGEnviro::get_lightning_enable_state,
|
||||
// &SGEnviro::set_lightning_enable_state);
|
||||
|
|
|
@ -31,14 +31,16 @@
|
|||
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/props/tiedpropertylist.hxx>
|
||||
#include <simgear/io/HTTPClient.hxx>
|
||||
#include <simgear/io/HTTPRequest.hxx>
|
||||
#include <simgear/timing/sg_time.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
#if defined(ENABLE_THREADS)
|
||||
#include <OpenThreads/Thread>
|
||||
#include <simgear/threads/SGQueue.hxx>
|
||||
#endif
|
||||
|
||||
using simgear::PropertyList;
|
||||
|
||||
|
@ -110,6 +112,7 @@ protected:
|
|||
simgear::TiedPropertyList _tiedProperties;
|
||||
typedef std::vector<LiveMetarProperties_ptr> MetarPropertiesList;
|
||||
MetarPropertiesList _metarProperties;
|
||||
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
@ -195,86 +198,95 @@ public:
|
|||
virtual void update (bool first, double delta_time_sec);
|
||||
virtual void shutdown ();
|
||||
|
||||
class MetarLoadRequest {
|
||||
public:
|
||||
MetarLoadRequest( const string & stationId ) :
|
||||
_stationId(stationId),
|
||||
_proxyHost(fgGetNode("/sim/presets/proxy/host", true)->getStringValue()),
|
||||
_proxyPort(fgGetNode("/sim/presets/proxy/port", true)->getStringValue()),
|
||||
_proxyAuth(fgGetNode("/sim/presets/proxy/authentication", true)->getStringValue())
|
||||
{}
|
||||
MetarLoadRequest( const MetarLoadRequest & other ) :
|
||||
_stationId(other._stationId),
|
||||
_proxyHost(other._proxyAuth),
|
||||
_proxyPort(other._proxyPort),
|
||||
_proxyAuth(other._proxyAuth)
|
||||
{}
|
||||
string _stationId;
|
||||
string _proxyHost;
|
||||
string _proxyPort;
|
||||
string _proxyAuth;
|
||||
private:
|
||||
};
|
||||
|
||||
class MetarLoadResponse {
|
||||
public:
|
||||
MetarLoadResponse( const string & stationId, const string metar ) {
|
||||
_stationId = stationId;
|
||||
_metar = metar;
|
||||
}
|
||||
MetarLoadResponse( const MetarLoadResponse & other ) {
|
||||
_stationId = other._stationId;
|
||||
_metar = other._metar;
|
||||
}
|
||||
string _stationId;
|
||||
string _metar;
|
||||
};
|
||||
/**
|
||||
* callback from MetarGetRequest when a download succeeds
|
||||
*/
|
||||
void gotMetar(const string& stationId, const string& metar);
|
||||
private:
|
||||
double _positionTimeToLive;
|
||||
double _requestTimer;
|
||||
|
||||
#if defined(ENABLE_THREADS)
|
||||
class MetarLoadThread : public OpenThreads::Thread {
|
||||
public:
|
||||
MetarLoadThread( long maxAge );
|
||||
virtual ~MetarLoadThread( ) { stop(); }
|
||||
void requestMetar( const MetarLoadRequest & metarRequest, bool background = true );
|
||||
bool hasMetar() { return _responseQueue.size() > 0; }
|
||||
MetarLoadResponse getMetar() { return _responseQueue.pop(); }
|
||||
virtual void run();
|
||||
void stop();
|
||||
private:
|
||||
void fetch( const MetarLoadRequest & );
|
||||
long _maxAge;
|
||||
long _minRequestInterval;
|
||||
volatile bool _stop;
|
||||
SGBlockingQueue <MetarLoadRequest> _requestQueue;
|
||||
SGBlockingQueue <MetarLoadResponse> _responseQueue;
|
||||
};
|
||||
|
||||
MetarLoadThread * _metarLoadThread;
|
||||
#endif
|
||||
simgear::HTTP::Client _http;
|
||||
};
|
||||
|
||||
class MetarGetRequest : public simgear::HTTP::Request
|
||||
{
|
||||
public:
|
||||
MetarGetRequest(NoaaMetarRealWxController* con, const string& s) :
|
||||
Request(""),
|
||||
stationId(s),
|
||||
fromProxy(false),
|
||||
wxController(con)
|
||||
{
|
||||
setUrl("http://weather.noaa.gov/pub/data/observations/metar/stations/" + stationId + ".TXT");
|
||||
}
|
||||
|
||||
virtual string_list requestHeaders() const
|
||||
{
|
||||
string_list r;
|
||||
r.push_back("X-Time");
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual string header(const string& name) const
|
||||
{
|
||||
if (name == "X-Time") {
|
||||
char buf[16];
|
||||
snprintf(buf, 16, "%ld", globals->get_time_params()->get_cur_time());
|
||||
return buf;
|
||||
}
|
||||
|
||||
return Request::header(name);
|
||||
}
|
||||
|
||||
virtual void responseHeader(const string& key, const string& value)
|
||||
{
|
||||
if (key == "x-metarproxy") {
|
||||
fromProxy = true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void gotBodyData(const char* s, int n)
|
||||
{
|
||||
metar += string(s, n);
|
||||
}
|
||||
|
||||
virtual void responseComplete()
|
||||
{
|
||||
if (responseCode() == 200) {
|
||||
wxController->gotMetar(stationId, metar);
|
||||
} else {
|
||||
SG_LOG(SG_IO, SG_WARN, "metar download failed:" << url() << ": reason:" << responseReason());
|
||||
}
|
||||
}
|
||||
|
||||
bool fromMetarProxy() const
|
||||
{ return fromProxy; }
|
||||
private:
|
||||
string stationId;
|
||||
string metar;
|
||||
bool fromProxy;
|
||||
NoaaMetarRealWxController* wxController;
|
||||
};
|
||||
|
||||
|
||||
|
||||
NoaaMetarRealWxController::NoaaMetarRealWxController( SGPropertyNode_ptr rootNode ) :
|
||||
BasicRealWxController(rootNode),
|
||||
_positionTimeToLive(0.0),
|
||||
_requestTimer(0.0)
|
||||
{
|
||||
#if defined(ENABLE_THREADS)
|
||||
_metarLoadThread = new MetarLoadThread(getMetarMaxAgeMin());
|
||||
_metarLoadThread->start();
|
||||
#endif
|
||||
string proxyHost(fgGetString("/sim/presets/proxy/host"));
|
||||
int proxyPort(fgGetInt("/sim/presets/proxy/port"));
|
||||
string proxyAuth(fgGetString("/sim/presets/proxy/auth"));
|
||||
|
||||
if (!proxyHost.empty()) {
|
||||
_http.setProxy(proxyHost, proxyPort, proxyAuth);
|
||||
}
|
||||
}
|
||||
|
||||
void NoaaMetarRealWxController::shutdown()
|
||||
{
|
||||
#if defined(ENABLE_THREADS)
|
||||
if( _metarLoadThread ) {
|
||||
delete _metarLoadThread;
|
||||
_metarLoadThread = NULL;
|
||||
}
|
||||
#endif // ENABLE_THREADS
|
||||
}
|
||||
|
||||
NoaaMetarRealWxController::~NoaaMetarRealWxController()
|
||||
|
@ -283,6 +295,8 @@ NoaaMetarRealWxController::~NoaaMetarRealWxController()
|
|||
|
||||
void NoaaMetarRealWxController::update( bool first, double dt )
|
||||
{
|
||||
_http.update();
|
||||
|
||||
_positionTimeToLive -= dt;
|
||||
_requestTimer -= dt;
|
||||
|
||||
|
@ -315,143 +329,32 @@ void NoaaMetarRealWxController::update( bool first, double dt )
|
|||
|
||||
if( _requestTimer <= 0.0 ) {
|
||||
_requestTimer = 10.0;
|
||||
|
||||
BOOST_FOREACH(LiveMetarProperties* p, _metarProperties) {
|
||||
if( p->getTimeToLive() > 0.0 ) continue;
|
||||
const std::string & stationId = p->getStationId();
|
||||
if( stationId.empty() ) continue;
|
||||
|
||||
for( MetarPropertiesList::iterator it = _metarProperties.begin();
|
||||
it != _metarProperties.end(); it++ ) {
|
||||
|
||||
if( (*it)->getTimeToLive() > 0.0 ) continue;
|
||||
const std::string & stationId = (*it)->getStationId();
|
||||
if( stationId.empty() ) continue;
|
||||
|
||||
SG_LOG(SG_ALL, SG_INFO,
|
||||
"NoaaMetarRealWxController::update(): spawning load request for station-id '" << stationId << "'" );
|
||||
SG_LOG(SG_ALL, SG_INFO,
|
||||
"NoaaMetarRealWxController::update(): spawning load request for station-id '" << stationId << "'" );
|
||||
|
||||
MetarLoadRequest request( stationId );
|
||||
// load the metar for the nearest airport in the foreground if the fdm is uninitialized
|
||||
// to make sure a metar is received
|
||||
// before the automatic runway selection code runs. All subsequent calls
|
||||
// run in the background
|
||||
bool background = fgGetBool("/sim/fdm-initialized", false ) || it != _metarProperties.begin();
|
||||
_metarLoadThread->requestMetar( request, background );
|
||||
}
|
||||
}
|
||||
|
||||
// pick all the received responses from the result queue and update the associated
|
||||
// property tree
|
||||
while( _metarLoadThread->hasMetar() ) {
|
||||
MetarLoadResponse metar = _metarLoadThread->getMetar();
|
||||
SG_LOG( SG_ALL, SG_INFO, "NoaaMetarRwalWxController::update() received METAR for " << metar._stationId << ": " << metar._metar );
|
||||
for( MetarPropertiesList::iterator it = _metarProperties.begin();
|
||||
it != _metarProperties.end(); it++ ) {
|
||||
if( (*it)->getStationId() != metar._stationId )
|
||||
continue;
|
||||
(*it)->setTimeToLive(900);
|
||||
(*it)->setMetar( metar._metar );
|
||||
}
|
||||
_http.makeRequest(new MetarGetRequest(this, stationId));
|
||||
} // of MetarProperties iteration
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ENABLE_THREADS)
|
||||
NoaaMetarRealWxController::MetarLoadThread::MetarLoadThread( long maxAge ) :
|
||||
_maxAge(maxAge),
|
||||
_minRequestInterval(2000),
|
||||
_stop(false)
|
||||
void NoaaMetarRealWxController::gotMetar(const string& stationId, const string& metar)
|
||||
{
|
||||
}
|
||||
|
||||
void NoaaMetarRealWxController::MetarLoadThread::requestMetar( const MetarLoadRequest & metarRequest, bool background )
|
||||
{
|
||||
if( background ) {
|
||||
if( _requestQueue.size() > 10 ) {
|
||||
SG_LOG(SG_ALL,SG_ALERT,
|
||||
"NoaaMetarRealWxController::MetarLoadThread::requestMetar() more than 10 outstanding METAR requests, dropping "
|
||||
<< metarRequest._stationId );
|
||||
return;
|
||||
}
|
||||
|
||||
_requestQueue.push( metarRequest );
|
||||
} else {
|
||||
fetch( metarRequest );
|
||||
SG_LOG( SG_ALL, SG_INFO, "NoaaMetarRwalWxController::update() received METAR for " << stationId << ": " << metar );
|
||||
BOOST_FOREACH(LiveMetarProperties* p, _metarProperties) {
|
||||
if (p->getStationId() != stationId)
|
||||
continue;
|
||||
|
||||
p->setTimeToLive(900);
|
||||
p->setMetar( metar );
|
||||
}
|
||||
}
|
||||
|
||||
void NoaaMetarRealWxController::MetarLoadThread::stop()
|
||||
{
|
||||
// set stop flag and wake up the thread with an empty request
|
||||
_stop = true;
|
||||
MetarLoadRequest request("");
|
||||
requestMetar(request);
|
||||
join();
|
||||
}
|
||||
|
||||
void NoaaMetarRealWxController::MetarLoadThread::run()
|
||||
{
|
||||
SGTimeStamp lastRun = SGTimeStamp::fromSec(0);
|
||||
for( ;; ) {
|
||||
SGTimeStamp dt = SGTimeStamp::now() - lastRun;
|
||||
|
||||
long delayMs = _minRequestInterval - dt.getSeconds() * 1000;
|
||||
while (( delayMs > 0 ) && !_stop)
|
||||
{
|
||||
// sleep no more than 3 seconds at a time, otherwise shutdown response is too slow
|
||||
long sleepMs = (delayMs>3000) ? 3000 : delayMs;
|
||||
microSleep( sleepMs * 1000 );
|
||||
delayMs -= sleepMs;
|
||||
}
|
||||
|
||||
if (_stop)
|
||||
break;
|
||||
|
||||
lastRun = SGTimeStamp::now();
|
||||
|
||||
const MetarLoadRequest request = _requestQueue.pop();
|
||||
|
||||
if (( request._stationId.size() == 0 ) || _stop)
|
||||
break;
|
||||
|
||||
fetch( request );
|
||||
}
|
||||
}
|
||||
|
||||
void NoaaMetarRealWxController::MetarLoadThread::fetch( const MetarLoadRequest & request )
|
||||
{
|
||||
SGSharedPtr<FGMetar> result = NULL;
|
||||
|
||||
try {
|
||||
result = new FGMetar( request._stationId, request._proxyHost, request._proxyPort, request._proxyAuth );
|
||||
_minRequestInterval = 2000;
|
||||
} catch (const sg_io_exception& e) {
|
||||
SG_LOG( SG_GENERAL, SG_WARN, "NoaaMetarRealWxController::fetchMetar(): can't get METAR for "
|
||||
<< request._stationId << ":" << e.getFormattedMessage().c_str() );
|
||||
_minRequestInterval += _minRequestInterval/2;
|
||||
if( _minRequestInterval > 30000 )
|
||||
_minRequestInterval = 30000;
|
||||
return;
|
||||
}
|
||||
|
||||
string reply = result->getData();
|
||||
std::replace(reply.begin(), reply.end(), '\n', ' ');
|
||||
string metar = simgear::strutils::strip( reply );
|
||||
|
||||
if( metar.empty() ) {
|
||||
SG_LOG( SG_GENERAL, SG_WARN, "NoaaMetarRealWxController::fetchMetar(): dropping empty METAR for "
|
||||
<< request._stationId );
|
||||
return;
|
||||
}
|
||||
|
||||
if( _maxAge && result->getAge_min() > _maxAge ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "NoaaMetarRealWxController::fetchMetar(): dropping outdated METAR "
|
||||
<< metar );
|
||||
return;
|
||||
}
|
||||
|
||||
MetarLoadResponse response( request._stationId, metar );
|
||||
_responseQueue.push( response );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
||||
RealWxController * RealWxController::createInstance( SGPropertyNode_ptr rootNode )
|
||||
|
|
|
@ -60,6 +60,20 @@ FGEventHandler::FGEventHandler() :
|
|||
numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
|
||||
numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
|
||||
numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
|
||||
numlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = '.';
|
||||
|
||||
// mapping when NumLock is off
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = PU_KEY_INSERT;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_End] = PU_KEY_END;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Down] = PU_KEY_DOWN;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = PU_KEY_PAGE_DOWN;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Left] = PU_KEY_LEFT;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Right] = PU_KEY_RIGHT;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Home] = PU_KEY_HOME;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Up] = PU_KEY_UP;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = PU_KEY_PAGE_UP;
|
||||
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = 127;
|
||||
|
||||
for (int i = 0; i < 128; i++)
|
||||
release_keys[i] = i;
|
||||
|
@ -259,7 +273,6 @@ void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
|
|||
case GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break;
|
||||
case GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break;
|
||||
case GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break;
|
||||
case GUIEventAdapter::KEY_KP_Delete: key = '.'; break;
|
||||
case GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
|
||||
case GUIEventAdapter::KEY_KP_Add: key = '+'; break;
|
||||
case GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
|
||||
|
@ -268,18 +281,30 @@ void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
|
|||
}
|
||||
osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
|
||||
|
||||
std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
|
||||
|
||||
if (numPadIter != numlockKeyMap.end()) {
|
||||
#ifdef __APPLE__
|
||||
// Num Lock is always true on Mac
|
||||
// Num Lock is always true on Mac
|
||||
std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
|
||||
if (numPadIter != numlockKeyMap.end()) {
|
||||
key = numPadIter->second;
|
||||
}
|
||||
#else
|
||||
if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
|
||||
if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK)
|
||||
{
|
||||
// NumLock on: map to numeric keys
|
||||
std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
|
||||
if (numPadIter != numlockKeyMap.end()) {
|
||||
key = numPadIter->second;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// NumLock off: map to PU arrow keys
|
||||
std::map<int, int>::iterator numPadIter = noNumlockKeyMap.find(key);
|
||||
if (numPadIter != noNumlockKeyMap.end()) {
|
||||
key = numPadIter->second;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
modifiers = osgToFGModifiers(ea.getModKeyMask());
|
||||
currentModifiers = modifiers;
|
||||
|
|
|
@ -113,6 +113,7 @@ protected:
|
|||
int statsType;
|
||||
int currentModifiers;
|
||||
std::map<int, int> numlockKeyMap;
|
||||
std::map<int, int> noNumlockKeyMap;
|
||||
void handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers);
|
||||
bool resizable;
|
||||
bool mouseWarped;
|
||||
|
|
|
@ -28,8 +28,12 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Transform>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
#include <osg/CameraView>
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgUtil/IntersectVisitor>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
@ -38,6 +42,8 @@
|
|||
#include <simgear/scene/util/SGNodeMasks.hxx>
|
||||
#include <simgear/scene/util/SGSceneUserData.hxx>
|
||||
#include <simgear/scene/model/CheckSceneryVisitor.hxx>
|
||||
#include <simgear/scene/bvh/BVHNode.hxx>
|
||||
#include <simgear/scene/bvh/BVHLineSegmentVisitor.hxx>
|
||||
|
||||
#include <Main/renderer.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
@ -70,6 +76,138 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class FGSceneryIntersect : public osg::NodeVisitor {
|
||||
public:
|
||||
FGSceneryIntersect(const SGLineSegmentd& lineSegment,
|
||||
const osg::Node* skipNode) :
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
|
||||
_lineSegment(lineSegment),
|
||||
_skipNode(skipNode),
|
||||
_material(0),
|
||||
_haveHit(false)
|
||||
{ }
|
||||
|
||||
bool getHaveHit() const
|
||||
{ return _haveHit; }
|
||||
const SGLineSegmentd& getLineSegment() const
|
||||
{ return _lineSegment; }
|
||||
const SGMaterial* getMaterial() const
|
||||
{ return _material; }
|
||||
|
||||
virtual void apply(osg::Node& node)
|
||||
{
|
||||
if (&node == _skipNode)
|
||||
return;
|
||||
if (!testBoundingSphere(node.getBound()))
|
||||
return;
|
||||
|
||||
addBoundingVolume(node);
|
||||
}
|
||||
|
||||
virtual void apply(osg::Group& group)
|
||||
{
|
||||
if (&group == _skipNode)
|
||||
return;
|
||||
if (!testBoundingSphere(group.getBound()))
|
||||
return;
|
||||
|
||||
traverse(group);
|
||||
addBoundingVolume(group);
|
||||
}
|
||||
|
||||
virtual void apply(osg::Transform& transform)
|
||||
{ handleTransform(transform); }
|
||||
virtual void apply(osg::Camera& camera)
|
||||
{
|
||||
if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
|
||||
return;
|
||||
handleTransform(camera);
|
||||
}
|
||||
virtual void apply(osg::CameraView& transform)
|
||||
{ handleTransform(transform); }
|
||||
virtual void apply(osg::MatrixTransform& transform)
|
||||
{ handleTransform(transform); }
|
||||
virtual void apply(osg::PositionAttitudeTransform& transform)
|
||||
{ handleTransform(transform); }
|
||||
|
||||
private:
|
||||
void handleTransform(osg::Transform& transform)
|
||||
{
|
||||
if (&transform == _skipNode)
|
||||
return;
|
||||
// Hmm, may be this needs to be refined somehow ...
|
||||
if (transform.getReferenceFrame() != osg::Transform::RELATIVE_RF)
|
||||
return;
|
||||
|
||||
if (!testBoundingSphere(transform.getBound()))
|
||||
return;
|
||||
|
||||
osg::Matrix inverseMatrix;
|
||||
if (!transform.computeWorldToLocalMatrix(inverseMatrix, this))
|
||||
return;
|
||||
osg::Matrix matrix;
|
||||
if (!transform.computeLocalToWorldMatrix(matrix, this))
|
||||
return;
|
||||
|
||||
SGLineSegmentd lineSegment = _lineSegment;
|
||||
bool haveHit = _haveHit;
|
||||
const SGMaterial* material = _material;
|
||||
|
||||
_haveHit = false;
|
||||
_lineSegment = lineSegment.transform(SGMatrixd(inverseMatrix.ptr()));
|
||||
|
||||
addBoundingVolume(transform);
|
||||
traverse(transform);
|
||||
|
||||
if (_haveHit) {
|
||||
_lineSegment = _lineSegment.transform(SGMatrixd(matrix.ptr()));
|
||||
} else {
|
||||
_lineSegment = lineSegment;
|
||||
_material = material;
|
||||
_haveHit = haveHit;
|
||||
}
|
||||
}
|
||||
|
||||
simgear::BVHNode* getNodeBoundingVolume(osg::Node& node)
|
||||
{
|
||||
SGSceneUserData* userData = SGSceneUserData::getSceneUserData(&node);
|
||||
if (!userData)
|
||||
return 0;
|
||||
return userData->getBVHNode();
|
||||
}
|
||||
void addBoundingVolume(osg::Node& node)
|
||||
{
|
||||
simgear::BVHNode* bvNode = getNodeBoundingVolume(node);
|
||||
if (!bvNode)
|
||||
return;
|
||||
|
||||
// Find ground intersection on the bvh nodes
|
||||
simgear::BVHLineSegmentVisitor lineSegmentVisitor(_lineSegment,
|
||||
0/*startTime*/);
|
||||
bvNode->accept(lineSegmentVisitor);
|
||||
if (!lineSegmentVisitor.empty()) {
|
||||
_lineSegment = lineSegmentVisitor.getLineSegment();
|
||||
_material = lineSegmentVisitor.getMaterial();
|
||||
_haveHit = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool testBoundingSphere(const osg::BoundingSphere& bound) const
|
||||
{
|
||||
if (!bound.valid())
|
||||
return false;
|
||||
|
||||
SGSphered sphere(toVec3d(toSG(bound._center)), bound._radius);
|
||||
return intersects(_lineSegment, sphere);
|
||||
}
|
||||
|
||||
SGLineSegmentd _lineSegment;
|
||||
const osg::Node* _skipNode;
|
||||
|
||||
const SGMaterial* _material;
|
||||
bool _haveHit;
|
||||
};
|
||||
|
||||
// Scenery Management system
|
||||
FGScenery::FGScenery()
|
||||
{
|
||||
|
@ -138,43 +276,20 @@ FGScenery::get_elevation_m(const SGGeod& geod, double& alt,
|
|||
SGGeod geodEnd = geod;
|
||||
geodEnd.setElevationM(SGMiscd::min(geod.getElevationM() - 10, -10000));
|
||||
SGVec3d end = SGVec3d::fromGeod(geodEnd);
|
||||
|
||||
osgUtil::IntersectVisitor intersectVisitor;
|
||||
|
||||
FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end), butNotFrom);
|
||||
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
|
||||
osg::ref_ptr<osg::LineSegment> lineSegment;
|
||||
lineSegment = new osg::LineSegment(toOsg(start), toOsg(end));
|
||||
intersectVisitor.addLineSegment(lineSegment.get());
|
||||
get_scene_graph()->accept(intersectVisitor);
|
||||
bool hits = false;
|
||||
if (intersectVisitor.hits()) {
|
||||
int nHits = intersectVisitor.getNumHits(lineSegment.get());
|
||||
alt = -SGLimitsd::max();
|
||||
for (int i = 0; i < nHits; ++i) {
|
||||
const osgUtil::Hit& hit
|
||||
= intersectVisitor.getHitList(lineSegment.get())[i];
|
||||
if (butNotFrom &&
|
||||
std::find(hit.getNodePath().begin(), hit.getNodePath().end(),
|
||||
butNotFrom) != hit.getNodePath().end())
|
||||
continue;
|
||||
|
||||
// We might need the double variant of the intersection point.
|
||||
// Thus we cannot use the float variant delivered by
|
||||
// hit.getWorldIntersectPoint() but we have to redo that with osg::Vec3d.
|
||||
osg::Vec3d point = hit.getLocalIntersectPoint();
|
||||
if (hit.getMatrix())
|
||||
point = point*(*hit.getMatrix());
|
||||
SGGeod geod = SGGeod::fromCart(toSG(point));
|
||||
double elevation = geod.getElevationM();
|
||||
if (alt < elevation) {
|
||||
alt = elevation;
|
||||
hits = true;
|
||||
if (material)
|
||||
*material = SGMaterialLib::findMaterial(hit.getGeode());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!intersectVisitor.getHaveHit())
|
||||
return false;
|
||||
|
||||
return hits;
|
||||
geodEnd = SGGeod::fromCart(intersectVisitor.getLineSegment().getEnd());
|
||||
alt = geodEnd.getElevationM();
|
||||
if (material)
|
||||
*material = intersectVisitor.getMaterial();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -190,40 +305,16 @@ FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
|
|||
// computation of ground intersection.
|
||||
SGVec3d start = pos;
|
||||
SGVec3d end = start + 1e5*normalize(dir); // FIXME visibility ???
|
||||
|
||||
osgUtil::IntersectVisitor intersectVisitor;
|
||||
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
|
||||
osg::ref_ptr<osg::LineSegment> lineSegment;
|
||||
lineSegment = new osg::LineSegment(toOsg(start), toOsg(end));
|
||||
intersectVisitor.addLineSegment(lineSegment.get());
|
||||
get_scene_graph()->accept(intersectVisitor);
|
||||
bool hits = false;
|
||||
if (intersectVisitor.hits()) {
|
||||
int nHits = intersectVisitor.getNumHits(lineSegment.get());
|
||||
double dist = SGLimitsd::max();
|
||||
for (int i = 0; i < nHits; ++i) {
|
||||
const osgUtil::Hit& hit
|
||||
= intersectVisitor.getHitList(lineSegment.get())[i];
|
||||
if (butNotFrom &&
|
||||
std::find(hit.getNodePath().begin(), hit.getNodePath().end(),
|
||||
butNotFrom) != hit.getNodePath().end())
|
||||
continue;
|
||||
// We might need the double variant of the intersection point.
|
||||
// Thus we cannot use the float variant delivered by
|
||||
// hit.getWorldIntersectPoint() but we have to redo that with osg::Vec3d.
|
||||
osg::Vec3d point = hit.getLocalIntersectPoint();
|
||||
if (hit.getMatrix())
|
||||
point = point*(*hit.getMatrix());
|
||||
double newdist = length(start - toSG(point));
|
||||
if (newdist < dist) {
|
||||
dist = newdist;
|
||||
nearestHit = toSG(point);
|
||||
hits = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hits;
|
||||
FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end), butNotFrom);
|
||||
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
|
||||
get_scene_graph()->accept(intersectVisitor);
|
||||
|
||||
if (!intersectVisitor.getHaveHit())
|
||||
return false;
|
||||
|
||||
nearestHit = intersectVisitor.getLineSegment().getEnd();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FGScenery::scenery_available(const SGGeod& position, double range_m)
|
||||
|
|
|
@ -24,14 +24,12 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <direct.h>
|
||||
#endif
|
||||
|
||||
#include <FL/Fl_File_Chooser.H>
|
||||
#include <plib/ul.h>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
|
@ -142,11 +140,12 @@ void FGAdminUI::update_install_box() {
|
|||
install_box->clear();
|
||||
|
||||
if ( source.length() ) {
|
||||
ulDir *dir = ulOpenDir( source.c_str() ) ;
|
||||
ulDirEnt *ent;
|
||||
while ( dir != 0 && ( ent = ulReadDir( dir ) ) ) {
|
||||
struct dirent **list;
|
||||
int nb = fl_filename_list( source.c_str(), &list );
|
||||
for ( int i = 0; i < nb; ++i ) {
|
||||
// find base name of archive file
|
||||
char base[FL_PATH_MAX];
|
||||
dirent *ent = list[i];
|
||||
strncpy( base, ent->d_name, FL_PATH_MAX );
|
||||
const char *p = fl_filename_ext( base );
|
||||
int offset, expected_length = 0;
|
||||
|
@ -186,9 +185,10 @@ void FGAdminUI::update_install_box() {
|
|||
// cout << install.str() << " exists." << endl;
|
||||
}
|
||||
}
|
||||
free( ent );
|
||||
}
|
||||
free( list );
|
||||
|
||||
ulCloseDir( dir );
|
||||
for ( set<string>::iterator it = file_list.begin(); it != file_list.end(); ++it ) {
|
||||
install_box->add( it->c_str() );
|
||||
}
|
||||
|
@ -217,16 +217,18 @@ void FGAdminUI::update_remove_box() {
|
|||
set<string> dir_list;
|
||||
for ( int i = 0; i < 2; i++ ) {
|
||||
if ( !path[i].empty() ) {
|
||||
ulDir *dir = ulOpenDir( path[i].c_str() ) ;
|
||||
ulDirEnt *ent;
|
||||
while ( dir != 0 && ( ent = ulReadDir( dir ) ) ) {
|
||||
dirent **list;
|
||||
int nb = fl_filename_list( path[i].c_str(), &list );
|
||||
for ( int i = 0; i < nb; ++i ) {
|
||||
dirent *ent = list[i];
|
||||
if ( strlen(ent->d_name) == 7 &&
|
||||
( ent->d_name[0] == 'e' || ent->d_name[0] == 'w' ) &&
|
||||
( ent->d_name[4] == 'n' || ent->d_name[4] == 's' ) ) {
|
||||
dir_list.insert( ent->d_name );
|
||||
}
|
||||
free( ent );
|
||||
}
|
||||
ulCloseDir( dir );
|
||||
free( list );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,7 +256,7 @@ void FGAdminUI::install_selected() {
|
|||
SGPath file( source );
|
||||
file.append( f );
|
||||
struct stat info;
|
||||
stat( file.str().c_str(), &info );
|
||||
fl_stat( file.str().c_str(), &info );
|
||||
float old_max = progress->maximum();
|
||||
progress->maximum( info.st_size );
|
||||
progress_label = "Installing ";
|
||||
|
@ -279,23 +281,25 @@ void FGAdminUI::install_selected() {
|
|||
|
||||
static unsigned long count_dir( const char *dir_name, bool top = true ) {
|
||||
unsigned long cnt = 0L;
|
||||
ulDir *dir = ulOpenDir( dir_name ) ;
|
||||
if ( dir ) {
|
||||
ulDirEnt *ent;
|
||||
while ( ent = ulReadDir( dir ) ) {
|
||||
dirent **list;
|
||||
int nb = fl_filename_list( dir_name, &list );
|
||||
if ( nb != 0 ) {
|
||||
for ( int i = 0; i < nb; ++i ) {
|
||||
dirent *ent = list[i];
|
||||
if ( strcmp( ent->d_name, "." ) == 0 ) {
|
||||
// ignore "."
|
||||
} else if ( strcmp( ent->d_name, ".." ) == 0 ) {
|
||||
// ignore ".."
|
||||
} else if ( ent->d_isdir ) {
|
||||
} else if ( fl_filename_isdir( ent->d_name ) ) {
|
||||
SGPath child( dir_name );
|
||||
child.append( ent->d_name );
|
||||
cnt += count_dir( child.c_str(), false );
|
||||
} else {
|
||||
cnt += 1;
|
||||
}
|
||||
free( ent );
|
||||
}
|
||||
ulCloseDir( dir );
|
||||
free( list );
|
||||
} else if ( top ) {
|
||||
string base = dir_name;
|
||||
size_t pos = base.rfind('/');
|
||||
|
@ -310,15 +314,16 @@ static unsigned long count_dir( const char *dir_name, bool top = true ) {
|
|||
}
|
||||
|
||||
static void remove_dir( const char *dir_name, void (*step)(void*,int), void *data, bool top = true ) {
|
||||
ulDir *dir = ulOpenDir( dir_name ) ;
|
||||
if ( dir ) {
|
||||
ulDirEnt *ent;
|
||||
while ( ent = ulReadDir( dir ) ) {
|
||||
dirent **list;
|
||||
int nb = fl_filename_list( dir_name, &list );
|
||||
if ( nb != 0 ) {
|
||||
for ( int i = 0; i < nb; ++i ) {
|
||||
dirent *ent = list[i];
|
||||
if ( strcmp( ent->d_name, "." ) == 0 ) {
|
||||
// ignore "."
|
||||
} else if ( strcmp( ent->d_name, ".." ) == 0 ) {
|
||||
// ignore ".."
|
||||
} else if ( ent->d_isdir ) {
|
||||
} else if ( fl_filename_isdir( ent->d_name ) ) {
|
||||
SGPath child( dir_name );
|
||||
child.append( ent->d_name );
|
||||
remove_dir( child.c_str(), step, data, false );
|
||||
|
@ -328,8 +333,9 @@ static void remove_dir( const char *dir_name, void (*step)(void*,int), void *dat
|
|||
unlink( child.c_str() );
|
||||
if (step) step( data, 1 );
|
||||
}
|
||||
free( ent );
|
||||
}
|
||||
ulCloseDir( dir );
|
||||
free( list );
|
||||
rmdir( dir_name );
|
||||
} else if ( top ) {
|
||||
string base = dir_name;
|
||||
|
|
|
@ -441,6 +441,8 @@ sub serve()
|
|||
$metar .= sprintf "$icao %02d%02d%02dZ ", $day, $hour, $min;
|
||||
$metar .= $last_metar{$addr} || $METAR_DEFAULT;
|
||||
}
|
||||
|
||||
print $client "HTTP/1.0 200 OK\015\012";
|
||||
print $client "Content-Type: text/plain\015\012"
|
||||
. "X-MetarProxy: nasse Maus\015\012"
|
||||
. "\015\012"
|
||||
|
|
Loading…
Reference in a new issue