From 4b74636d044b7e73020d66b19ac1a3dc7daa5a3a Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sat, 19 Mar 2011 14:51:39 +0100 Subject: [PATCH 01/23] Avoid nuisance sound effects after sim-reset. --- src/Model/acmodel.cxx | 3 ++- src/Model/acmodel.hxx | 2 +- src/Sound/fg_fx.cxx | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Model/acmodel.cxx b/src/Model/acmodel.cxx index 5c63963a9..3c9faaf23 100644 --- a/src/Model/acmodel.cxx +++ b/src/Model/acmodel.cxx @@ -1,4 +1,4 @@ -// model.cxx - manage a 3D aircraft model. +// acmodel.cxx - manage a 3D aircraft model. // Written by David Megginson, started 2002. // // This file is in the Public Domain, and comes with no warranty. @@ -84,6 +84,7 @@ void FGAircraftModel::reinit() { deinit(); + _fx->reinit(); init(); } diff --git a/src/Model/acmodel.hxx b/src/Model/acmodel.hxx index 7965658cd..b774874d2 100644 --- a/src/Model/acmodel.hxx +++ b/src/Model/acmodel.hxx @@ -1,4 +1,4 @@ -// model.hxx - manage a 3D aircraft model. +// acmodel.hxx - manage a 3D aircraft model. // Written by David Megginson, started 2002. // // This file is in the Public Domain, and comes with no warranty. diff --git a/src/Sound/fg_fx.cxx b/src/Sound/fg_fx.cxx index ab0ace0a9..f60f44114 100644 --- a/src/Sound/fg_fx.cxx +++ b/src/Sound/fg_fx.cxx @@ -109,6 +109,9 @@ FGFX::init() void FGFX::reinit() { + for ( unsigned int i = 0; i < _sound.size(); i++ ) { + delete _sound[i]; + } _sound.clear(); init(); }; From befc533398be7102874e44890cf7b8a25cb94336 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sat, 19 Mar 2011 15:02:17 +0100 Subject: [PATCH 02/23] More virtual destructors. --- src/Sound/voiceplayer.hxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Sound/voiceplayer.hxx b/src/Sound/voiceplayer.hxx index 762b9a36d..61b3e4975 100644 --- a/src/Sound/voiceplayer.hxx +++ b/src/Sound/voiceplayer.hxx @@ -135,6 +135,7 @@ public: public: bool silence; + virtual ~Element() {} virtual inline void play (float volume) {} virtual inline void stop () {} virtual bool is_playing () = 0; @@ -186,7 +187,7 @@ public: inline Voice (FGVoicePlayer *_player) : element(NULL), player(_player), volume(1.0) {} - ~Voice (); + virtual ~Voice (); inline void append (Element *_element) { elements.push_back(_element); } @@ -229,7 +230,7 @@ public: dev_name(_dev_name), dir_prefix(""), speaker(this,properties_handler) {} - ~FGVoicePlayer (); + virtual ~FGVoicePlayer (); void init (); void pause(); From 51a6302f48de5a5a0ac7311a36522b1d66494967 Mon Sep 17 00:00:00 2001 From: Erik Hofman Date: Sat, 19 Mar 2011 16:04:32 +0100 Subject: [PATCH 03/23] Make sure Include/config.h gets found which is located in /src --- src/Sound/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sound/Makefile.am b/src/Sound/Makefile.am index 4cd2df9e2..e6799c233 100644 --- a/src/Sound/Makefile.am +++ b/src/Sound/Makefile.am @@ -8,4 +8,4 @@ libSound_a_SOURCES = \ sample_queue.cxx sample_queue.hxx \ voiceplayer.cxx voiceplayer.hxx -INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir) -I$(top_builddir)/src From b6d70d2c719d2f62c161a4d8d2445bdba2b21a33 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sun, 20 Mar 2011 14:59:19 +0100 Subject: [PATCH 04/23] Replay improvements Clear replay buffers on sim reset. Allow instant replay to be activated properly when sim is paused. --- src/Aircraft/replay.cxx | 13 +++++++++---- src/Aircraft/replay.hxx | 2 ++ src/Main/fg_commands.cxx | 4 +++- src/Main/fg_init.cxx | 3 +++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Aircraft/replay.cxx b/src/Aircraft/replay.cxx index aa976adcb..6c5c410d8 100644 --- a/src/Aircraft/replay.cxx +++ b/src/Aircraft/replay.cxx @@ -83,6 +83,14 @@ FGReplay::~FGReplay() { */ void FGReplay::init() { + reinit(); +} + +/** + * Reset replay queues. + */ + +void FGReplay::reinit() { sim_time = 0.0; last_mt_time = 0.0; last_lt_time = 0.0; @@ -110,17 +118,16 @@ void FGReplay::init() { (lt_list_time*lt_dt)); for (int i = 0; i < estNrObjects; i++) { recycler.push_back(new FGReplayData); - } } - /** * Bind to the property tree */ void FGReplay::bind() { disable_replay = fgGetNode( "/sim/replay/disable", true ); + replay_master = fgGetNode( "/sim/freeze/replay-state", true ); } @@ -140,8 +147,6 @@ void FGReplay::unbind() { void FGReplay::update( double dt ) { timingInfo.clear(); stamp("begin"); - static SGPropertyNode *replay_master - = fgGetNode( "/sim/freeze/replay-state", true ); if( disable_replay->getBoolValue() ) { if ( sim_time != 0.0 ) { diff --git a/src/Aircraft/replay.hxx b/src/Aircraft/replay.hxx index 0e599c1a4..bad1ce8b1 100644 --- a/src/Aircraft/replay.hxx +++ b/src/Aircraft/replay.hxx @@ -69,6 +69,7 @@ public: virtual ~FGReplay(); virtual void init(); + virtual void reinit(); virtual void bind(); virtual void unbind(); virtual void update( double dt ); @@ -96,6 +97,7 @@ private: replay_list_type long_term; replay_list_type recycler; SGPropertyNode_ptr disable_replay; + SGPropertyNode_ptr replay_master; }; diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index 97f5ca399..d2b5b021e 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -1243,8 +1243,10 @@ do_log_level (const SGPropertyNode * arg) static bool do_replay (const SGPropertyNode * arg) { - // freeze the master fdm + // freeze the fdm, resume from sim pause fgSetInt( "/sim/freeze/replay-state", 1 ); + fgSetBool("/sim/freeze/master", 0 ); + fgSetBool("/sim/freeze/clock", 0 ); FGReplay *r = (FGReplay *)(globals->get_subsystem( "replay" )); diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index a615eddee..260f9ef22 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -1553,6 +1553,9 @@ void fgReInitSubsystems() // Initialize the FDM globals->get_subsystem("flight")->reinit(); + // reset replay buffers + globals->get_subsystem("replay")->reinit(); + // reload offsets from config defaults globals->get_viewmgr()->reinit(); From 991beb0b5ecf08df56ad77f6a49b0e20c191be11 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Mon, 21 Mar 2011 23:07:05 +0100 Subject: [PATCH 05/23] replay/FDM shell subsystem refactoring Move final bits of replay code to where it belongs. Use subsystem suspend/resume for FDM shell during instant replay. --- src/Aircraft/replay.cxx | 143 ++++++++++++++++++++++++++-------------- src/Aircraft/replay.hxx | 3 + src/FDM/fdm_shell.cxx | 34 ++++------ src/FDM/fdm_shell.hxx | 3 +- 4 files changed, 112 insertions(+), 71 deletions(-) diff --git a/src/Aircraft/replay.cxx b/src/Aircraft/replay.cxx index 6c5c410d8..9ecc353d8 100644 --- a/src/Aircraft/replay.cxx +++ b/src/Aircraft/replay.cxx @@ -25,12 +25,14 @@ #endif #include +#include #include
#include #include #include #include +#include #include "replay.hxx" @@ -46,7 +48,9 @@ const double FGReplay::lt_dt = 5.0; // long term sample rate (sec) * Constructor */ -FGReplay::FGReplay() { +FGReplay::FGReplay() : + last_replay_state(0) +{ } @@ -54,35 +58,44 @@ FGReplay::FGReplay() { * Destructor */ -FGReplay::~FGReplay() { - while ( !short_term.empty() ) { - //cerr << "Deleting Short term" <getBoolValue() ) { - if ( sim_time != 0.0 ) { - // we were recording data - init(); - } - return; + if (( sim_time != 0.0 )&& + ( disable_replay->getBoolValue() )) + { + // we were recording data + reinit(); } - //stamp("point_01"); - if ( replay_master->getIntValue() > 0 ) { - // don't record the replay session - return; + + int replay_state = replay_master->getIntValue(); + + if ((replay_state > 0)&& + (last_replay_state == 0)) + { + // replay is starting, suspend FDM + /* FIXME we need to suspend/resume the FDM - not the entire FDM shell. + * FDM isn't available via the global subsystem manager yet, so need a + * method at the FDMshell for now */ + ((FDMShell*) globals->get_subsystem("flight"))->getFDM()->suspend(); } + else + if ((replay_state == 0)&& + (last_replay_state > 0)) + { + // replay is finished, resume FDM + ((FDMShell*) globals->get_subsystem("flight"))->getFDM()->resume(); + } + + // remember recent state + last_replay_state = replay_state; + + switch(replay_state) + { + case 0: + // replay inactive, keep recording + break; + case 1: + // replay active + replay( replay_time->getDoubleValue() ); + replay_time->setDoubleValue( replay_time->getDoubleValue() + + ( dt * fgGetInt("/sim/speed-up") ) ); + return; // don't record the replay session + case 2: + // replay paused, no-op + return; // don't record the replay session + default: + throw sg_range_exception("unknown FGReplay state"); + } + + // flight recording + //cerr << "Recording replay" << endl; sim_time += dt; @@ -180,12 +222,13 @@ void FGReplay::update( double dt ) { if (!recycler.size()) { stamp("Replay_01"); r = new FGReplayData; - stamp("Replay_02"); + stamp("Replay_02"); } else { - r = recycler.front(); - recycler.pop_front(); - //stamp("point_04be"); + r = recycler.front(); + recycler.pop_front(); + //stamp("point_04be"); } + r->sim_time = sim_time; //r->ctrls = c; //stamp("point_04e"); diff --git a/src/Aircraft/replay.hxx b/src/Aircraft/replay.hxx index bad1ce8b1..3ad3aed0c 100644 --- a/src/Aircraft/replay.hxx +++ b/src/Aircraft/replay.hxx @@ -79,6 +79,7 @@ public: double get_end_time(); private: + void clear(); static const double st_list_time; // 60 secs of high res data static const double mt_list_time; // 10 mins of 1 fps data @@ -91,6 +92,7 @@ private: double sim_time; double last_mt_time; double last_lt_time; + int last_replay_state; replay_list_type short_term; replay_list_type medium_term; @@ -98,6 +100,7 @@ private: replay_list_type recycler; SGPropertyNode_ptr disable_replay; SGPropertyNode_ptr replay_master; + SGPropertyNode_ptr replay_time; }; diff --git a/src/FDM/fdm_shell.cxx b/src/FDM/fdm_shell.cxx index 7d936e3d1..401483e4b 100644 --- a/src/FDM/fdm_shell.cxx +++ b/src/FDM/fdm_shell.cxx @@ -139,8 +139,8 @@ void FDMShell::update(double dt) // pull environmental data in, since the FDMs are lazy _impl->set_Velocities_Local_Airmass( _props->getDoubleValue("environment/wind-from-north-fps", 0.0), - _props->getDoubleValue("environment/wind-from-east-fps", 0.0), - _props->getDoubleValue("environment/wind-from-down-fps", 0.0)); + _props->getDoubleValue("environment/wind-from-east-fps", 0.0), + _props->getDoubleValue("environment/wind-from-down-fps", 0.0)); if (_props->getBoolValue("environment/params/control-fdm-atmosphere")) { // convert from Rankine to Celsius @@ -160,24 +160,8 @@ void FDMShell::update(double dt) _impl->ToggleDataLogging(doLog); } -// FIXME - replay manager should handle most of this - int replayState = fgGetInt("/sim/freeze/replay-state", 0); - if (replayState == 0) { - _impl->update(dt); // normal code path - } else if (replayState == 1) { - // should be inside FGReplay! - SGPropertyNode* replay_time = fgGetNode("/sim/replay/time", true); - FGReplay *r = (FGReplay *)(globals->get_subsystem( "replay" )); - r->replay( replay_time->getDoubleValue() ); - replay_time->setDoubleValue( replay_time->getDoubleValue() - + ( dt - * fgGetInt("/sim/speed-up") ) ); - - } else if (replayState == 2) { - // paused replay, no-op - } else { - throw sg_range_exception("unknown FGReplay state"); - } + if (!_impl->is_suspended()) + _impl->update(dt); } void FDMShell::createImplementation() @@ -268,3 +252,13 @@ void FDMShell::createImplementation() } +/* + * Return FDM subsystem. + */ + +SGSubsystem* FDMShell::getFDM() +{ + /* FIXME we could drop/replace this method, when _impl was a added + * to the global subsystem manager - like other proper subsystems... */ + return _impl; +} diff --git a/src/FDM/fdm_shell.hxx b/src/FDM/fdm_shell.hxx index 759be1c9e..04bbf1b72 100644 --- a/src/FDM/fdm_shell.hxx +++ b/src/FDM/fdm_shell.hxx @@ -50,7 +50,8 @@ public: virtual void unbind(); virtual void update(double dt); - + SGSubsystem* getFDM(); + private: void createImplementation(); From 0114fd962e7450b080e580fe67414ca43cd99bd7 Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Tue, 22 Mar 2011 18:00:55 +0100 Subject: [PATCH 06/23] Fix broken tank properties. More verbose generic protocol error messages --- src/FDM/fdm_shell.cxx | 2 +- src/Network/generic.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FDM/fdm_shell.cxx b/src/FDM/fdm_shell.cxx index 401483e4b..5fa77d895 100644 --- a/src/FDM/fdm_shell.cxx +++ b/src/FDM/fdm_shell.cxx @@ -94,9 +94,9 @@ void FDMShell::bind() if (_impl->get_bound()) { throw sg_exception("FDMShell::bind of bound FGInterface impl"); } - _tankProperties.bind(); _impl->bind(); } + _tankProperties.bind(); } void FDMShell::unbind() diff --git a/src/Network/generic.cxx b/src/Network/generic.cxx index 1ed607a39..71ae5a874 100644 --- a/src/Network/generic.cxx +++ b/src/Network/generic.cxx @@ -541,9 +541,9 @@ FGGeneric::reinit() SGPropertyNode root; try { readProperties(path.str(), &root); - } catch (const sg_exception &) { + } catch (const sg_exception & ex) { SG_LOG(SG_GENERAL, SG_ALERT, - "Unable to load the protocol configuration file"); + "Unable to load the protocol configuration file: " << ex.getFormattedMessage() ); return; } From 5ace4e9632c7ee58e5df04afc927148c807c615d Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Tue, 22 Mar 2011 21:02:57 +0100 Subject: [PATCH 07/23] Fix reset during replay issue Need to properly reset the replay manager's states on sim reset. Also remove obsolete method. --- src/Aircraft/replay.cxx | 9 ++++++--- src/Main/fg_commands.cxx | 2 +- src/Main/fg_init.cxx | 9 +-------- src/Main/fg_init.hxx | 10 ++-------- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/Aircraft/replay.cxx b/src/Aircraft/replay.cxx index 9ecc353d8..538546c81 100644 --- a/src/Aircraft/replay.cxx +++ b/src/Aircraft/replay.cxx @@ -96,6 +96,9 @@ void FGReplay::clear() void FGReplay::init() { + disable_replay = fgGetNode( "/sim/replay/disable", true ); + replay_master = fgGetNode( "/sim/freeze/replay-state", true ); + replay_time = fgGetNode( "/sim/replay/time", true); reinit(); } @@ -120,6 +123,9 @@ void FGReplay::reinit() { recycler.push_back(new FGReplayData); } + replay_master->setIntValue(0); + disable_replay->setBoolValue(0); + replay_time->setDoubleValue(0); } /** @@ -128,9 +134,6 @@ void FGReplay::reinit() void FGReplay::bind() { - disable_replay = fgGetNode( "/sim/replay/disable", true ); - replay_master = fgGetNode( "/sim/freeze/replay-state", true ); - replay_time = fgGetNode( "/sim/replay/time", true); } diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index d2b5b021e..8f7a1c18c 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -221,7 +221,7 @@ do_exit (const SGPropertyNode * arg) static bool do_reset (const SGPropertyNode * arg) { - doSimulatorReset(); + fgReInitSubsystems(); return true; } diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 260f9ef22..d77a81a41 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -1517,7 +1517,7 @@ bool fgInitSubsystems() { return true; } - +// Reset: this is what the 'reset' command (and hence, GUI) is attached to void fgReInitSubsystems() { static const SGPropertyNode *master_freeze @@ -1570,13 +1570,6 @@ void fgReInitSubsystems() } -void doSimulatorReset(void) // from gui_local.cxx -- TODO merge with fgReInitSubsystems() -{ - - - fgReInitSubsystems(); -} - /////////////////////////////////////////////////////////////////////////////// // helper object to implement the --show-aircraft command. // resides here so we can share the fgFindAircraftInDir template above, diff --git a/src/Main/fg_init.hxx b/src/Main/fg_init.hxx index 256716a88..b23fead60 100644 --- a/src/Main/fg_init.hxx +++ b/src/Main/fg_init.hxx @@ -62,16 +62,10 @@ bool fgInitGeneral (); // gear, its initialization call should located in this routine. bool fgInitSubsystems(); - -// Reset + +// Reset: this is what the 'reset' command (and hence, GUI) is attached to void fgReInitSubsystems(); -/** - * this is what the 'reset' command (and hence, GUI) is attached too - * it overlaps with fgReInitSubsystems quite substantially - */ -void doSimulatorReset(void); - // Set the initial position based on presets (or defaults) bool fgInitPosition(); From 189457f2af9ac3ec748c32a7403f06702852fd17 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Wed, 23 Mar 2011 22:49:18 +0100 Subject: [PATCH 08/23] Minor namespace issue using "using" in the .cxx now :) --- src/Environment/realwx_ctrl.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Environment/realwx_ctrl.cxx b/src/Environment/realwx_ctrl.cxx index 03db5a87a..621fb11c3 100644 --- a/src/Environment/realwx_ctrl.cxx +++ b/src/Environment/realwx_ctrl.cxx @@ -40,6 +40,7 @@ #include #endif +using simgear::PropertyList; namespace Environment { From b4c47b06d50d055f363f14677a7d4d052af9a981 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Wed, 23 Mar 2011 22:50:56 +0100 Subject: [PATCH 09/23] Drop unnecessary include dependency. Make Csaba happy... --- src/Sound/voiceplayer.cxx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Sound/voiceplayer.cxx b/src/Sound/voiceplayer.cxx index 1a839cf3a..054a771fc 100644 --- a/src/Sound/voiceplayer.cxx +++ b/src/Sound/voiceplayer.cxx @@ -42,12 +42,6 @@ using std::string; -#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H -# include -#else -# include -#endif - #include "voiceplayer.hxx" /////////////////////////////////////////////////////////////////////////////// From 38226af24ec01e8f0a20d7fd73ef838a69f6ef25 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Wed, 23 Mar 2011 23:09:02 +0100 Subject: [PATCH 10/23] Improve timing statistics Enable/disable and print statistics at run-time. Configurable intervals and filters. --- src/Main/main.cxx | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Main/main.cxx b/src/Main/main.cxx index 677d0f36b..33bb062bb 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -121,6 +121,15 @@ static void fgMainLoop( void ) { static SGPropertyNode_ptr frame_signal = fgGetNode("/sim/signals/frame", true); + static SGPropertyNode_ptr _statisticsFlag + = fgGetNode("/sim/timing-statistics/enabled", true); + static SGPropertyNode_ptr _statisticsInterval + = fgGetNode("/sim/timing-statistics/interval-s", true); + static SGPropertyNode_ptr _statiticsMinJitter + = fgGetNode("/sim/timing-statistics/min-jitter-ms", true); + static SGPropertyNode_ptr _statiticsMinTime + = fgGetNode("/sim/timing-statistics/min-time-ms", true); + frame_signal->fireValueChanged(); SGCloudLayer::enable_bump_mapping = fgGetBool("/sim/rendering/bump-mapping"); @@ -206,6 +215,28 @@ static void fgMainLoop( void ) { simgear::sleepForMSec(500); } } + + // print timing statistics + static bool _lastStatisticsFlag = false; + if (_lastStatisticsFlag != _statisticsFlag->getBoolValue()) + { + // flag has changed, update subsystem manager + _lastStatisticsFlag = _statisticsFlag->getBoolValue(); + globals->get_subsystem_mgr()->collectDebugTiming(_lastStatisticsFlag); + } + if (_lastStatisticsFlag) + { + static double elapsed = 0; + elapsed += real_dt; + if (elapsed >= _statisticsInterval->getDoubleValue()) + { + // print and reset timing statistics + globals->get_subsystem_mgr()->printTimingStatistics(_statiticsMinTime->getDoubleValue(), + _statiticsMinJitter->getDoubleValue()); + elapsed = 0; + } + } + simgear::AtomicChangeListener::fireChangeListeners(); SG_LOG( SG_ALL, SG_DEBUG, "" ); From 11320e6b008eb85b8dff66a137f671743cc04580 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Wed, 23 Mar 2011 23:52:36 +0100 Subject: [PATCH 11/23] Bertrand Coconnier: Fix instant replay with JSBSim aircraft (bug #294) Avoid re-trim to be triggered by property listeners during instant replay (when the FDM is suspended). --- src/FDM/JSBSim/JSBSim.cxx | 56 ++++++++++++++++++++++++++++++++------- src/FDM/JSBSim/JSBSim.hxx | 6 +++++ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/FDM/JSBSim/JSBSim.cxx b/src/FDM/JSBSim/JSBSim.cxx index 0eb21888e..e2d98b673 100644 --- a/src/FDM/JSBSim/JSBSim.cxx +++ b/src/FDM/JSBSim/JSBSim.cxx @@ -570,6 +570,22 @@ void FGJSBsim::update( double dt ) /******************************************************************************/ +void FGJSBsim::suspend() +{ + fdmex->Hold(); + SGSubsystem::suspend(); +} + +/******************************************************************************/ + +void FGJSBsim::resume() +{ + fdmex->Resume(); + SGSubsystem::resume(); +} + +/******************************************************************************/ + // Convert from the FGInterface struct to the JSBsim generic_ struct bool FGJSBsim::copy_to_JSBsim() @@ -1011,7 +1027,9 @@ void FGJSBsim::set_Latitude(double lat) _set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET ); fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET ); fgic->SetLatitudeRadIC( lat_geoc ); - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } @@ -1024,7 +1042,9 @@ void FGJSBsim::set_Longitude(double lon) update_ic(); fgic->SetLongitudeRadIC( lon ); - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } // Sets the altitude above sea level. @@ -1049,7 +1069,9 @@ void FGJSBsim::set_Altitude(double alt) "Terrain elevation: " << FGInterface::get_Runway_altitude() * SG_METER_TO_FEET ); fgic->SetLatitudeRadIC( lat_geoc ); fgic->SetAltitudeASLFtIC(alt); - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } void FGJSBsim::set_V_calibrated_kts(double vc) @@ -1061,7 +1083,9 @@ void FGJSBsim::set_V_calibrated_kts(double vc) update_ic(); fgic->SetVcalibratedKtsIC(vc); - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } void FGJSBsim::set_Mach_number(double mach) @@ -1073,7 +1097,9 @@ void FGJSBsim::set_Mach_number(double mach) update_ic(); fgic->SetMachIC(mach); - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } void FGJSBsim::set_Velocities_Local( double north, double east, double down ) @@ -1088,7 +1114,9 @@ void FGJSBsim::set_Velocities_Local( double north, double east, double down ) fgic->SetVNorthFpsIC(north); fgic->SetVEastFpsIC(east); fgic->SetVDownFpsIC(down); - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } void FGJSBsim::set_Velocities_Wind_Body( double u, double v, double w) @@ -1103,7 +1131,9 @@ void FGJSBsim::set_Velocities_Wind_Body( double u, double v, double w) fgic->SetUBodyFpsIC(u); fgic->SetVBodyFpsIC(v); fgic->SetWBodyFpsIC(w); - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } //Euler angles @@ -1119,7 +1149,9 @@ void FGJSBsim::set_Euler_Angles( double phi, double theta, double psi ) fgic->SetThetaRadIC(theta); fgic->SetPhiRadIC(phi); fgic->SetPsiRadIC(psi); - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } //Flight Path @@ -1137,7 +1169,9 @@ void FGJSBsim::set_Climb_Rate( double roc) if( !(fabs(roc) > 1 && fabs(fgic->GetFlightPathAngleRadIC()) < 0.01) ) { fgic->SetClimbRateFpsIC(roc); } - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } void FGJSBsim::set_Gamma_vert_rad( double gamma) @@ -1148,7 +1182,9 @@ void FGJSBsim::set_Gamma_vert_rad( double gamma) if( !(fabs(gamma) < 0.01 && fabs(fgic->GetClimbRateFpsIC()) > 1) ) { fgic->SetFlightPathAngleRadIC(gamma); } - needTrim=true; + + if (!fdmex->Holding()) + needTrim=true; } void FGJSBsim::init_gear(void ) diff --git a/src/FDM/JSBSim/JSBSim.hxx b/src/FDM/JSBSim/JSBSim.hxx index a01146bcc..ca52f9223 100644 --- a/src/FDM/JSBSim/JSBSim.hxx +++ b/src/FDM/JSBSim/JSBSim.hxx @@ -113,6 +113,12 @@ public: /// Unbind properties void unbind(); + /// Suspend integration + void suspend(); + + /// Resume integration + void resume(); + /// @name Position Parameter Set //@{ /** Set geocentric latitude From 6a864eb57f2135b9f72e23635ec621f75a4dba8b Mon Sep 17 00:00:00 2001 From: "Curtis L. Olson" Date: Thu, 24 Mar 2011 14:31:13 -0500 Subject: [PATCH 12/23] Variant of innosetup config file for developer snapshot release. Uses separate paths so it can install along side the official release and not overwrite or conflict with any files. --- package/Win32-Inno/FlightGear-devel.iss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/Win32-Inno/FlightGear-devel.iss b/package/Win32-Inno/FlightGear-devel.iss index 568a9d53c..4f957c028 100644 --- a/package/Win32-Inno/FlightGear-devel.iss +++ b/package/Win32-Inno/FlightGear-devel.iss @@ -20,7 +20,7 @@ ; C:\> subst X: /d ; -#define FGVER "v20110228" +#define FGVER "v20110324" [Setup] AppId=FlightGear {#FGVER} @@ -52,7 +52,7 @@ Name: "insoal"; Description: "Install OpenAL (the sound engine)" ; NOTE: run subst X: F:\ (or whatever path the expanded tree resides at) Source: "X:\*.txt"; DestDir: "{app}"; Flags: ignoreversion Source: "X:\bin\Win32\*.*"; DestDir: "{app}\bin\Win32"; Flags: ignoreversion recursesubdirs -Source: "X:\bin\vcredist_x86.exe"; DestDir: "{app}\bin"; Flags: ignoreversion +;;; Source: "X:\bin\vcredist_x86.exe"; DestDir: "{app}\bin"; Flags: ignoreversion Source: "X:\bin\oalinst.exe"; DestDir: "{app}\bin"; Flags: ignoreversion Source: "X:\data\*.*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files @@ -88,7 +88,7 @@ Name: "{group}\Tools\Explore Documentation Folder"; Filename: "{app}\data\Docs" ; Name: "{userdesktop}\FlightGear {#FGVER}"; Filename: "{app}\bin\Win32\fgfs.exe"; Parameters: "--fg-root=."; WorkingDir: "{app}"; Tasks: desktopicon [Run] -Filename: "{app}\bin\vcredist_x86.exe"; WorkingDir: "{app}"; Parameters: "/qb!"; Description: "Installing Flightgear prerequisites" +;;; Filename: "{app}\bin\vcredist_x86.exe"; WorkingDir: "{app}"; Parameters: "/qb!"; Description: "Installing Flightgear prerequisites" ; Put installation directory into the fgrun.prefs filename: "{app}\bin\Win32\fgrun.exe"; WorkingDir: "{app}\bin\Win32"; Parameters: "--silent ""--fg-exe={app}\bin\Win32\fgfs.exe"" ""--ts-exe={app}\bin\Win32\terrasync.exe"" ""--fg-root={app}\data"" ""--fg-scenery={app}\data\Scenery;{app}\scenery;{code:TerrasyncDir}"" --ts-dir=3" From 3a901863412ce96836cd4325c822b860bc257d8f Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Thu, 24 Mar 2011 23:30:09 +0100 Subject: [PATCH 13/23] Minor replay issues When disabling replay: don't clear buffers and restore most recent frame --- src/Aircraft/replay.cxx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Aircraft/replay.cxx b/src/Aircraft/replay.cxx index 538546c81..bd3bab7bf 100644 --- a/src/Aircraft/replay.cxx +++ b/src/Aircraft/replay.cxx @@ -24,6 +24,7 @@ # include "config.h" #endif +#include #include #include @@ -156,11 +157,16 @@ void FGReplay::update( double dt ) timingInfo.clear(); stamp("begin"); - if (( sim_time != 0.0 )&& - ( disable_replay->getBoolValue() )) + if ( disable_replay->getBoolValue() ) { - // we were recording data - reinit(); + if (replay_master->getIntValue()) + { + // replay was active, restore most recent frame + replay(DBL_MAX); + } + replay_master->setIntValue(0); + replay_time->setDoubleValue(0); + disable_replay->setBoolValue(0); } int replay_state = replay_master->getIntValue(); From d051b800cc28b529d25acb81468365bfdd01ffd0 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Thu, 24 Mar 2011 23:41:12 +0100 Subject: [PATCH 14/23] Minor replay issues restore most recent frame --- src/Aircraft/replay.cxx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Aircraft/replay.cxx b/src/Aircraft/replay.cxx index bd3bab7bf..d5deeecd2 100644 --- a/src/Aircraft/replay.cxx +++ b/src/Aircraft/replay.cxx @@ -159,11 +159,6 @@ void FGReplay::update( double dt ) if ( disable_replay->getBoolValue() ) { - if (replay_master->getIntValue()) - { - // replay was active, restore most recent frame - replay(DBL_MAX); - } replay_master->setIntValue(0); replay_time->setDoubleValue(0); disable_replay->setBoolValue(0); @@ -184,6 +179,8 @@ void FGReplay::update( double dt ) if ((replay_state == 0)&& (last_replay_state > 0)) { + // replay was active, restore most recent frame + replay(DBL_MAX); // replay is finished, resume FDM ((FDMShell*) globals->get_subsystem("flight"))->getFDM()->resume(); } From 23971c17aa52edd257cd875b47cadbc3ab9bb3fc Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sat, 26 Mar 2011 11:02:00 +0000 Subject: [PATCH 15/23] Improve display of shipping in map widget. --- src/GUI/MapWidget.cxx | 507 +++++++++++++++++++++--------------------- 1 file changed, 252 insertions(+), 255 deletions(-) diff --git a/src/GUI/MapWidget.cxx b/src/GUI/MapWidget.cxx index 858eea1a1..c31347e2a 100644 --- a/src/GUI/MapWidget.cxx +++ b/src/GUI/MapWidget.cxx @@ -28,13 +28,13 @@ #include const char* RULER_LEGEND_KEY = "ruler-legend"; - + /* equatorial and polar earth radius */ const float rec = 6378137; // earth radius, equator (?) const float rpol = 6356752.314f; // earth radius, polar (?) /************************************************************************ - some trigonometric helper functions + some trigonometric helper functions (translated more or less directly from Alexei Novikovs perl original) *************************************************************************/ @@ -64,8 +64,8 @@ static bool puBoxIntersect(const puBox& a, const puBox& b) int y0 = SG_MAX2(a.min[1], b.min[1]); int x1 = SG_MIN2(a.max[0], b.max[0]); int y1 = SG_MIN2(a.max[1], b.max[1]); - - return (x0 <= x1) && (y0 <= y1); + + return (x0 <= x1) && (y0 <= y1); } class MapData; @@ -77,11 +77,11 @@ public: static const int HALIGN_LEFT = 1; static const int HALIGN_CENTER = 2; static const int HALIGN_RIGHT = 3; - + static const int VALIGN_TOP = 1 << 4; static const int VALIGN_CENTER = 2 << 4; static const int VALIGN_BOTTOM = 3 << 4; - + MapData(int priority) : _dirtyText(true), _age(0), @@ -93,151 +93,151 @@ public: _dataVisible(false) { } - + void setLabel(const std::string& label) { if (label == _label) { return; // common case, and saves invalidation } - + _label = label; _dirtyText = true; } - + void setText(const std::string &text) { if (_rawText == text) { return; // common case, and saves invalidation } - + _rawText = text; _dirtyText = true; } - + void setDataVisible(bool vis) { if (vis == _dataVisible) { return; } - + if (_rawText.empty()) { vis = false; } - + _dataVisible = vis; _dirtyText = true; } - + static void setFont(puFont f) { _font = f; _fontHeight = f.getStringHeight(); _fontDescender = f.getStringDescender(); } - + static void setPalette(puColor* pal) { _palette = pal; } - + void setPriority(int pri) { _priority = pri; } - + int priority() const { return _priority; } - + void setAnchor(const SGVec2d& anchor) { _anchor = anchor; } - + void setOffset(int direction, int px) { if ((_offsetPx == px) && (_offsetDir == direction)) { return; } - + _dirtyOffset = true; _offsetDir = direction; _offsetPx = px; } - + bool isClipped(const puBox& vis) const { validate(); if ((_width < 1) || (_height < 1)) { return true; } - + return !puBoxIntersect(vis, box()); } - + bool overlaps(const MapDataVec& l) const { validate(); puBox b(box()); - + MapDataVec::const_iterator it; for (it = l.begin(); it != l.end(); ++it) { if (puBoxIntersect(b, (*it)->box())) { return true; } } // of list iteration - + return false; } - + puBox box() const { validate(); return makePuBox( - _anchor.x() + _offset.x(), + _anchor.x() + _offset.x(), _anchor.y() + _offset.y(), _width, _height); } - + void draw() { validate(); - + int xx = _anchor.x() + _offset.x(); int yy = _anchor.y() + _offset.y(); - + if (_dataVisible) { puBox box(makePuBox(0,0,_width, _height)); int border = 1; box.draw(xx, yy, PUSTYLE_DROPSHADOW, _palette, FALSE, border); - + // draw lines int lineHeight = _fontHeight; int xPos = xx + MARGIN; int yPos = yy + _height - (lineHeight + MARGIN); glColor3f(0.8, 0.8, 0.8); - + for (unsigned int ln=0; ln<_lines.size(); ++ln) { _font.drawString(_lines[ln].c_str(), xPos, yPos); yPos -= lineHeight + LINE_LEADING; } - } else { + } else { glColor3f(0.8, 0.8, 0.8); _font.drawString(_label.c_str(), xx, yy + _fontDescender); } } - + void age() { ++_age; } - + void resetAge() { _age = 0; } - + bool isExpired() const { return (_age > 100); } - + static bool order(MapData* a, MapData* b) { return a->_priority > b->_priority; @@ -249,92 +249,92 @@ private: if (_dirtyOffset) { computeOffset(); } - + return; } - + if (_dataVisible) { measureData(); } else { measureLabel(); } - + computeOffset(); _dirtyText = false; } - + void measureData() const { _lines = simgear::strutils::split(_rawText, "\n"); // measure text to find width and height _width = -1; _height = 0; - + for (unsigned int ln=0; ln<_lines.size(); ++ln) { _height += _fontHeight; if (ln > 0) { _height += LINE_LEADING; } - + int lw = _font.getStringWidth(_lines[ln].c_str()); _width = std::max(_width, lw); } // of line measurement - + if ((_width < 1) || (_height < 1)) { // will be clipped return; } - + _height += MARGIN * 2; _width += MARGIN * 2; } - + void measureLabel() const { if (_label.empty()) { _width = _height = -1; return; } - + _height = _fontHeight; _width = _font.getStringWidth(_label.c_str()); } - + void computeOffset() const { _dirtyOffset = false; if ((_width <= 0) || (_height <= 0)) { return; } - + int hOffset = 0; int vOffset = 0; - + switch (_offsetDir & 0x0f) { default: case HALIGN_LEFT: hOffset = _offsetPx; break; - + case HALIGN_CENTER: hOffset = -(_width>>1); break; - + case HALIGN_RIGHT: hOffset = -(_offsetPx + _width); break; } - + switch (_offsetDir & 0xf0) { default: case VALIGN_TOP: vOffset = -(_offsetPx + _height); break; - + case VALIGN_CENTER: vOffset = -(_height>>1); break; - + case VALIGN_BOTTOM: vOffset = _offsetPx; break; @@ -342,10 +342,10 @@ private: _offset = SGVec2d(hOffset, vOffset); } - + static const int LINE_LEADING = 3; static const int MARGIN = 3; - + mutable bool _dirtyText; mutable bool _dirtyOffset; int _age; @@ -359,7 +359,7 @@ private: int _offsetPx; mutable SGVec2d _offset; bool _dataVisible; - + static puFont _font; static puColor* _palette; static int _fontHeight; @@ -377,19 +377,19 @@ const int MAX_ZOOM = 16; const int SHOW_DETAIL_ZOOM = 8; const int CURSOR_PAN_STEP = 32; -MapWidget::MapWidget(int x, int y, int maxX, int maxY) : +MapWidget::MapWidget(int x, int y, int maxX, int maxY) : puObject(x,y,maxX, maxY) { _route = static_cast(globals->get_subsystem("route-manager")); _gps = fgGetNode("/instrumentation/gps"); - + _zoom = 6; _width = maxX - x; _height = maxY - y; - + MapData::setFont(legendFont); MapData::setPalette(colour); - + _magVar = new SGMagVar(); } @@ -417,29 +417,29 @@ void MapWidget::setSize(int w, int h) void MapWidget::doHit( int button, int updown, int x, int y ) { - puObject::doHit(button, updown, x, y); - if (updown == PU_DRAG) { + puObject::doHit(button, updown, x, y); + if (updown == PU_DRAG) { handlePan(x, y); return; } - + if (button == 3) { // mouse-wheel up zoomIn(); } else if (button == 4) { // mouse-wheel down zoomOut(); } - + if (button != active_mouse_button) { return; } - + _hitLocation = SGVec2d(x - abox.min[0], y - abox.min[1]); - + if (updown == PU_UP) { puDeactivateWidget(); } else if (updown == PU_DOWN) { puSetActiveWidget(this, x, y); - + if (fgGetKeyModifiers() & KEYMOD_CTRL) { _clickGeod = unproject(_hitLocation - SGVec2d(_width>>1, _height>>1)); } @@ -458,7 +458,7 @@ int MapWidget::checkKey (int key, int updown ) if ((updown == PU_UP) || !isVisible () || !isActive () || (window != puGetWindow())) { return FALSE ; } - + switch (key) { @@ -469,24 +469,24 @@ int MapWidget::checkKey (int key, int updown ) case PU_KEY_DOWN: pan(SGVec2d(0, CURSOR_PAN_STEP)); break ; - + case PU_KEY_LEFT: pan(SGVec2d(CURSOR_PAN_STEP, 0)); break; - + case PU_KEY_RIGHT: pan(SGVec2d(-CURSOR_PAN_STEP, 0)); break; - + case '-': zoomOut(); - + break; - + case '=': zoomIn(); break; - + default : return FALSE; } @@ -504,7 +504,7 @@ void MapWidget::zoomIn() if (_zoom <= 0) { return; } - + --_zoom; SG_LOG(SG_GENERAL, SG_INFO, "zoom is now:" << _zoom); } @@ -514,22 +514,22 @@ void MapWidget::zoomOut() if (_zoom >= MAX_ZOOM) { return; } - + ++_zoom; SG_LOG(SG_GENERAL, SG_INFO, "zoom is now:" << _zoom); } void MapWidget::draw(int dx, int dy) { - _aircraft = SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), + _aircraft = SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), fgGetDouble("/position/latitude-deg")); _magneticHeadings = _root->getBoolValue("magnetic-headings"); - + if (_root->getBoolValue("centre-on-aircraft")) { _projectionCenter = _aircraft; _root->setBoolValue("centre-on-aircraft", false); } - + double julianDate = globals->get_time_params()->getJD(); _magVar->update(_projectionCenter, julianDate); @@ -550,37 +550,37 @@ void MapWidget::draw(int dx, int dy) sy = (int) abox.min[1]; glScissor(dx + sx, dy + sy, _width, _height); glEnable(GL_SCISSOR_TEST); - + glMatrixMode(GL_MODELVIEW); glPushMatrix(); // cetere drawing about the widget center (which is also the // projection centre) glTranslated(dx + sx + (_width/2), dy + sy + (_height/2), 0.0); - + drawLatLonGrid(); - + if (aircraftUp) { int textHeight = legendFont.getStringHeight() + 5; - + // draw heading line SGVec2d loc = project(_aircraft); glColor3f(1.0, 1.0, 1.0); drawLine(loc, SGVec2d(loc.x(), (_height / 2) - textHeight)); - + int displayHdg; if (_magneticHeadings) { displayHdg = (int) fgGetDouble("/orientation/heading-magnetic-deg"); } else { displayHdg = (int) _upHeading; } - + double y = (_height / 2) - textHeight; char buf[16]; ::snprintf(buf, 16, "%d", displayHdg); int sw = legendFont.getStringWidth(buf); legendFont.drawString(buf, loc.x() - sw/2, y); } - + drawAirports(); drawNavaids(); drawTraffic(); @@ -590,9 +590,9 @@ void MapWidget::draw(int dx, int dy) paintAircraftLocation(_aircraft); paintRoute(); paintRuler(); - + drawData(); - + glPopMatrix(); glDisable(GL_SCISSOR_TEST); } @@ -602,56 +602,56 @@ void MapWidget::paintRuler() if (_clickGeod == SGGeod()) { return; } - + SGVec2d acftPos = project(_aircraft); SGVec2d clickPos = project(_clickGeod); - + glColor4f(0.0, 1.0, 1.0, 0.6); drawLine(acftPos, clickPos); - + circleAtAlt(clickPos, 8, 10, 5); - + double dist, az, az2; SGGeodesy::inverse(_aircraft, _clickGeod, az, az2, dist); if (_magneticHeadings) { az -= _magVar->get_magvar(); SG_NORMALIZE_RANGE(az, 0.0, 360.0); } - + char buffer[1024]; ::snprintf(buffer, 1024, "%03d/%.1fnm", SGMiscd::roundToInt(az), dist * SG_METER_TO_NM); - + MapData* d = getOrCreateDataForKey((void*) RULER_LEGEND_KEY); d->setLabel(buffer); d->setAnchor(clickPos); d->setOffset(MapData::VALIGN_TOP | MapData::HALIGN_CENTER, 15); d->setPriority(20000); - + } void MapWidget::paintAircraftLocation(const SGGeod& aircraftPos) { SGVec2d loc = project(aircraftPos); - + double hdg = fgGetDouble("/orientation/heading-deg"); - + glLineWidth(2.0); glColor4f(1.0, 1.0, 0.0, 1.0); glPushMatrix(); glTranslated(loc.x(), loc.y(), 0.0); glRotatef(hdg - _upHeading, 0.0, 0.0, -1.0); - + const SGVec2d wingspan(12, 0); const SGVec2d nose(0, 8); const SGVec2d tail(0, -14); const SGVec2d tailspan(4,0); - + drawLine(-wingspan, wingspan); drawLine(nose, tail); drawLine(tail - tailspan, tail + tailspan); - + glPopMatrix(); glLineWidth(1.0); } @@ -661,40 +661,40 @@ void MapWidget::paintRoute() if (_route->numWaypts() < 2) { return; } - + RoutePath path(_route->waypts()); - + // first pass, draw the actual lines glLineWidth(2.0); - + for (int w=0; w<_route->numWaypts(); ++w) { SGGeodVec gv(path.pathForIndex(w)); if (gv.empty()) { continue; } - + if (w < _route->currentIndex()) { glColor4f(0.5, 0.5, 0.5, 0.7); } else { glColor4f(1.0, 0.0, 1.0, 1.0); } - + flightgear::WayptRef wpt(_route->wayptAtIndex(w)); if (wpt->flag(flightgear::WPT_MISS)) { glEnable(GL_LINE_STIPPLE); glLineStipple(1, 0x00FF); } - + glBegin(GL_LINE_STRIP); for (unsigned int i=0; inumWaypts(); ++w) { @@ -703,35 +703,35 @@ void MapWidget::paintRoute() if (g == SGGeod()) { continue; // Vectors or similar } - + SGVec2d p = project(g); glColor4f(1.0, 0.0, 1.0, 1.0); circleAtAlt(p, 8, 12, 5); - + std::ostringstream legend; legend << wpt->ident(); if (wpt->altitudeRestriction() != flightgear::RESTRICT_NONE) { legend << '\n' << SGMiscd::roundToInt(wpt->altitudeFt()) << '\''; } - + if (wpt->speedRestriction() == flightgear::SPEED_RESTRICT_MACH) { legend << '\n' << wpt->speedMach() << "M"; } else if (wpt->speedRestriction() != flightgear::RESTRICT_NONE) { legend << '\n' << SGMiscd::roundToInt(wpt->speedKts()) << "Kts"; } - + MapData* d = getOrCreateDataForKey(reinterpret_cast(w * 2)); d->setText(legend.str()); d->setLabel(wpt->ident()); d->setAnchor(p); d->setOffset(MapData::VALIGN_TOP | MapData::HALIGN_CENTER, 15); d->setPriority(w < _route->currentIndex() ? 9000 : 12000); - + } // of second waypoint iteration } /** - * Round a SGGeod to an arbitrary precision. + * Round a SGGeod to an arbitrary precision. * For example, passing precision of 0.5 will round to the nearest 0.5 of * a degree in both lat and lon - passing in 3.0 rounds to the nearest 3 degree * multiple, and so on. @@ -740,7 +740,7 @@ static SGGeod roundGeod(double precision, const SGGeod& g) { double lon = SGMiscd::round(g.getLongitudeDeg() / precision); double lat = SGMiscd::round(g.getLatitudeDeg() / precision); - + return SGGeod::fromDeg(lon * precision, lat * precision); } @@ -750,13 +750,13 @@ bool MapWidget::drawLineClipped(const SGVec2d& a, const SGVec2d& b) minY = SGMiscd::min(a.y(), b.y()), maxX = SGMiscd::max(a.x(), b.x()), maxY = SGMiscd::max(a.y(), b.y()); - + int hh = _height >> 1, hw = _width >> 1; - + if ((maxX < -hw) || (minX > hw) || (minY > hh) || (maxY < -hh)) { return false; } - + glVertex2dv(a.data()); glVertex2dv(b.data()); return true; @@ -769,11 +769,11 @@ SGVec2d MapWidget::gridPoint(int ix, int iy) if (it != _gridCache.end()) { return it->second; } - + SGGeod gp = SGGeod::fromDeg( _gridCenter.getLongitudeDeg() + ix * _gridSpacing, _gridCenter.getLatitudeDeg() + iy * _gridSpacing); - + SGVec2d proj = project(gp); _gridCache[key] = proj; return proj; @@ -784,7 +784,7 @@ void MapWidget::drawLatLonGrid() _gridSpacing = 1.0; _gridCenter = roundGeod(_gridSpacing, _projectionCenter); _gridCache.clear(); - + int ix = 0; int iy = 0; @@ -795,7 +795,7 @@ void MapWidget::drawLatLonGrid() didDraw = false; ++ix; ++iy; - + for (int x = -ix; x < ix; ++x) { didDraw |= drawLineClipped(gridPoint(x, -iy), gridPoint(x+1, -iy)); didDraw |= drawLineClipped(gridPoint(x, iy), gridPoint(x+1, iy)); @@ -803,62 +803,62 @@ void MapWidget::drawLatLonGrid() didDraw |= drawLineClipped(gridPoint(x, iy), gridPoint(x, iy - 1)); } - + for (int y = -iy; y < iy; ++y) { didDraw |= drawLineClipped(gridPoint(-ix, y), gridPoint(-ix, y+1)); didDraw |= drawLineClipped(gridPoint(-ix, y), gridPoint(-ix + 1, y)); didDraw |= drawLineClipped(gridPoint(ix, y), gridPoint(ix, y+1)); didDraw |= drawLineClipped(gridPoint(ix, y), gridPoint(ix - 1, y)); } - + if (ix > 30) { break; } } while (didDraw); - + glEnd(); } void MapWidget::drawGPSData() { std::string gpsMode = _gps->getStringValue("mode"); - + SGGeod wp0Geod = SGGeod::fromDeg( - _gps->getDoubleValue("wp/wp[0]/longitude-deg"), + _gps->getDoubleValue("wp/wp[0]/longitude-deg"), _gps->getDoubleValue("wp/wp[0]/latitude-deg")); - + SGGeod wp1Geod = SGGeod::fromDeg( - _gps->getDoubleValue("wp/wp[1]/longitude-deg"), + _gps->getDoubleValue("wp/wp[1]/longitude-deg"), _gps->getDoubleValue("wp/wp[1]/latitude-deg")); - + // draw track line double gpsTrackDeg = _gps->getDoubleValue("indicated-track-true-deg"); double gpsSpeed = _gps->getDoubleValue("indicated-ground-speed-kt"); double az2; - + if (gpsSpeed > 3.0) { // only draw track line if valid SGGeod trackRadial; SGGeodesy::direct(_aircraft, gpsTrackDeg, _drawRangeNm * SG_NM_TO_METER, trackRadial, az2); - + glColor4f(1.0, 1.0, 0.0, 1.0); glEnable(GL_LINE_STIPPLE); glLineStipple(1, 0x00FF); drawLine(project(_aircraft), project(trackRadial)); glDisable(GL_LINE_STIPPLE); } - + if (gpsMode == "dto") { SGVec2d wp0Pos = project(wp0Geod); SGVec2d wp1Pos = project(wp1Geod); - + glColor4f(1.0, 0.0, 1.0, 1.0); drawLine(wp0Pos, wp1Pos); - + } - + if (_gps->getBoolValue("scratch/valid")) { // draw scratch data - + } } @@ -871,16 +871,16 @@ public: _hardRunwaysOnly = nd->getBoolValue("hard-surfaced-airports", true); _minLengthFt = nd->getDoubleValue("min-runway-length-ft", 2000.0); } - + virtual FGPositioned::Type maxType() const { return _heliports ? FGPositioned::HELIPORT : FGPositioned::AIRPORT; } - + virtual bool passAirport(FGAirport* aApt) const { if (_hardRunwaysOnly) { return aApt->hasHardRunwayOfLengthFt(_minLengthFt); } - + return true; } @@ -906,26 +906,26 @@ public: _fixes(fixesEnabled), _navaids(navaidsEnabled) {} - - virtual bool pass(FGPositioned* aPos) const { + + virtual bool pass(FGPositioned* aPos) const { if (_fixes && (aPos->type() == FGPositioned::FIX)) { // ignore fixes which end in digits - expirmental if (isdigit(aPos->ident()[3]) && isdigit(aPos->ident()[4])) { return false; } } - + return true; } - + virtual FGPositioned::Type minType() const { return _fixes ? FGPositioned::FIX : FGPositioned::VOR; } - + virtual FGPositioned::Type maxType() const { return _navaids ? FGPositioned::NDB : FGPositioned::FIX; } - + private: bool _fixes, _navaids; }; @@ -934,10 +934,10 @@ void MapWidget::drawNavaids() { bool fixes = _root->getBoolValue("draw-fixes"); NavaidFilter f(fixes, _root->getBoolValue("draw-navaids")); - + if (f.minType() <= f.maxType()) { FGPositioned::List navs = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f); - + glLineWidth(1.0); for (unsigned int i=0; itype(); @@ -955,28 +955,28 @@ void MapWidget::drawNavaids() void MapWidget::drawNDB(bool tuned, FGNavRecord* ndb) { SGVec2d pos = project(ndb->geod()); - + if (tuned) { glColor3f(0.0, 1.0, 1.0); } else { glColor3f(0.0, 0.0, 0.0); } - + glEnable(GL_LINE_STIPPLE); glLineStipple(1, 0x00FF); circleAt(pos, 20, 6); circleAt(pos, 20, 10); glDisable(GL_LINE_STIPPLE); - + if (validDataForKey(ndb)) { setAnchorForKey(ndb, pos); return; } - + char buffer[1024]; ::snprintf(buffer, 1024, "%s\n%s %3.0fKhz", ndb->name().c_str(), ndb->ident().c_str(),ndb->get_freq()/100.0); - + MapData* d = createDataForKey(ndb); d->setPriority(40); d->setLabel(ndb->ident()); @@ -994,19 +994,19 @@ void MapWidget::drawVOR(bool tuned, FGNavRecord* vor) } else { glColor3f(0.0, 0.0, 1.0); } - + circleAt(pos, 6, 8); - + if (validDataForKey(vor)) { setAnchorForKey(vor, pos); return; } - + char buffer[1024]; ::snprintf(buffer, 1024, "%s\n%s %6.3fMhz", vor->name().c_str(), vor->ident().c_str(), vor->get_freq() / 100.0); - + MapData* d = createDataForKey(vor); d->setText(buffer); d->setLabel(vor->ident()); @@ -1020,7 +1020,7 @@ void MapWidget::drawFix(FGFix* fix) SGVec2d pos = project(fix->geod()); glColor3f(0.0, 0.0, 0.0); circleAt(pos, 3, 6); - + if (_zoom > SHOW_DETAIL_ZOOM) { return; // hide fix labels beyond a certain zoom level } @@ -1029,7 +1029,7 @@ void MapWidget::drawFix(FGFix* fix) setAnchorForKey(fix, pos); return; } - + MapData* d = createDataForKey(fix); d->setLabel(fix->ident()); d->setPriority(20); @@ -1039,15 +1039,15 @@ void MapWidget::drawFix(FGFix* fix) void MapWidget::drawNavRadio(SGPropertyNode_ptr radio) { - if (!radio || radio->getBoolValue("slaved-to-gps", false) + if (!radio || radio->getBoolValue("slaved-to-gps", false) || !radio->getBoolValue("in-range", false)) { return; } - + if (radio->getBoolValue("nav-loc", false)) { drawTunedLocalizer(radio); } - + // identify the tuned station - unfortunately we don't get lat/lon directly, // need to do the frequency search again double mhz = radio->getDoubleValue("frequencies/selected-mhz", 0.0); @@ -1056,37 +1056,37 @@ void MapWidget::drawNavRadio(SGPropertyNode_ptr radio) // mismatch between navradio selection logic and ours! return; } - + glLineWidth(1.0); drawVOR(true, nav); - + SGVec2d pos = project(nav->geod()); SGGeod range; double az2; double trueRadial = radio->getDoubleValue("radials/target-radial-deg"); SGGeodesy::direct(nav->geod(), trueRadial, nav->get_range() * SG_NM_TO_METER, range, az2); SGVec2d prange = project(range); - + SGVec2d norm = normalize(prange - pos); SGVec2d perp(norm.y(), -norm.x()); - + circleAt(pos, 64, length(prange - pos)); drawLine(pos, prange); - + // draw to/from arrows SGVec2d midPoint = (pos + prange) * 0.5; if (radio->getBoolValue("from-flag")) { norm = -norm; perp = -perp; } - + int sz = 10; SGVec2d arrowB = midPoint - (norm * sz) + (perp * sz); SGVec2d arrowC = midPoint - (norm * sz) - (perp * sz); drawLine(midPoint, arrowB); drawLine(arrowB, arrowC); drawLine(arrowC, midPoint); - + drawLine(pos, (2 * pos) - prange); // reciprocal radial } @@ -1098,7 +1098,7 @@ void MapWidget::drawTunedLocalizer(SGPropertyNode_ptr radio) // mismatch between navradio selection logic and ours! return; } - + if (loc->runway()) { drawILS(true, loc->runway()); } @@ -1118,18 +1118,18 @@ void MapWidget::drawAirport(FGAirport* apt) { // draw tower location SGVec2d towerPos = project(apt->getTowerLocation()); - + if (_zoom <= SHOW_DETAIL_ZOOM) { glColor3f(1.0, 1.0, 1.0); glLineWidth(1.0); - + drawLine(towerPos + SGVec2d(3, 0), towerPos + SGVec2d(3, 10)); drawLine(towerPos + SGVec2d(-3, 0), towerPos + SGVec2d(-3, 10)); drawLine(towerPos + SGVec2d(-6, 20), towerPos + SGVec2d(-3, 10)); drawLine(towerPos + SGVec2d(6, 20), towerPos + SGVec2d(3, 10)); drawLine(towerPos + SGVec2d(-6, 20), towerPos + SGVec2d(6, 20)); } - + if (validDataForKey(apt)) { setAnchorForKey(apt, towerPos); } else { @@ -1144,7 +1144,7 @@ void MapWidget::drawAirport(FGAirport* apt) d->setOffset(MapData::VALIGN_TOP | MapData::HALIGN_CENTER, 6); d->setAnchor(towerPos); } - + if (_zoom > SHOW_DETAIL_ZOOM) { return; } @@ -1155,25 +1155,25 @@ void MapWidget::drawAirport(FGAirport* apt) drawRunwayPre(rwy); } } - + for (unsigned int r=0; rnumRunways(); ++r) { FGRunway* rwy = apt->getRunwayByIndex(r); if (!rwy->isReciprocal()) { drawRunway(rwy); } - + if (rwy->ILS()) { drawILS(false, rwy); } } // of runway iteration - + } int MapWidget::scoreAirportRunways(FGAirport* apt) { bool needHardSurface = _root->getBoolValue("hard-surfaced-airports", true); double minLength = _root->getDoubleValue("min-runway-length-ft", 2000.0); - + int score = 0; unsigned int numRunways(apt->numRunways()); for (unsigned int r=0; risHardSurface()) { continue; } - + if (rwy->lengthFt() < minLength) { continue; } - + int scoreLength = SGMiscd::roundToInt(rwy->lengthFt() / 200.0); score += scoreLength; } // of runways iteration @@ -1201,7 +1201,7 @@ void MapWidget::drawRunwayPre(FGRunway* rwy) { SGVec2d p1 = project(rwy->begin()); SGVec2d p2 = project(rwy->end()); - + glLineWidth(4.0); glColor3f(1.0, 0.0, 1.0); drawLine(p1, p2); @@ -1209,24 +1209,24 @@ void MapWidget::drawRunwayPre(FGRunway* rwy) void MapWidget::drawRunway(FGRunway* rwy) { - // line for runway + // line for runway // optionally show active, stopway, etc // in legend, show published heading and length // and threshold elevation - + SGVec2d p1 = project(rwy->begin()); SGVec2d p2 = project(rwy->end()); glLineWidth(2.0); glColor3f(1.0, 1.0, 1.0); SGVec2d inset = normalize(p2 - p1) * 2; - + drawLine(p1 + inset, p2 - inset); - + if (validDataForKey(rwy)) { setAnchorForKey(rwy, (p1 + p2) * 0.5); return; } - + char buffer[1024]; ::snprintf(buffer, 1024, "%s/%s\n%3.0f/%3.0f\n%.0f'", rwy->ident().c_str(), @@ -1234,7 +1234,7 @@ void MapWidget::drawRunway(FGRunway* rwy) rwy->headingDeg(), rwy->reciprocalRunway()->headingDeg(), rwy->lengthFt()); - + MapData* d = createDataForKey(rwy); d->setText(buffer); d->setLabel(rwy->ident() + "/" + rwy->reciprocalRunway()->ident()); @@ -1249,7 +1249,7 @@ void MapWidget::drawILS(bool tuned, FGRunway* rwy) // using LOC transmitter position would be more accurate, but // is visually cluttered // arrow width is based upon the computed localizer width - + FGNavRecord* loc = rwy->ILS(); double halfBeamWidth = loc->localizerWidth() * 0.5; SGVec2d t = project(rwy->threshold()); @@ -1258,17 +1258,17 @@ void MapWidget::drawILS(bool tuned, FGRunway* rwy) double radial = loc->get_multiuse(); SG_NORMALIZE_RANGE(radial, 0.0, 360.0); double az2; - + // compute the three end points at the widge end of the arrow SGGeodesy::direct(loc->geod(), radial, -rangeM, locEnd, az2); SGVec2d endCentre = project(locEnd); - + SGGeodesy::direct(loc->geod(), radial + halfBeamWidth, -rangeM * 1.1, locEnd, az2); SGVec2d endR = project(locEnd); - + SGGeodesy::direct(loc->geod(), radial - halfBeamWidth, -rangeM * 1.1, locEnd, az2); SGVec2d endL = project(locEnd); - + // outline two triangles glLineWidth(1.0); if (tuned) { @@ -1276,7 +1276,7 @@ void MapWidget::drawILS(bool tuned, FGRunway* rwy) } else { glColor3f(0.0, 0.0, 1.0); } - + glBegin(GL_LINE_LOOP); glVertex2dv(t.data()); glVertex2dv(endCentre.data()); @@ -1287,16 +1287,16 @@ void MapWidget::drawILS(bool tuned, FGRunway* rwy) glVertex2dv(endCentre.data()); glVertex2dv(endR.data()); glEnd(); - + if (validDataForKey(loc)) { setAnchorForKey(loc, endR); return; } - + char buffer[1024]; ::snprintf(buffer, 1024, "%s\n%s\n%3.2fMHz", loc->name().c_str(), loc->ident().c_str(),loc->get_freq()/100.0); - + MapData* d = createDataForKey(loc); d->setPriority(40); d->setLabel(loc->ident()); @@ -1310,11 +1310,11 @@ void MapWidget::drawTraffic() if (!_root->getBoolValue("draw-traffic")) { return; } - + if (_zoom > SHOW_DETAIL_ZOOM) { return; } - + const SGPropertyNode* ai = fgGetNode("/ai/models", true); for (int i = 0; i < ai->nChildren(); ++i) { @@ -1329,14 +1329,14 @@ void MapWidget::drawTraffic() model->getDoubleValue("position/longitude-deg"), model->getDoubleValue("position/latitude-deg"), model->getDoubleValue("position/altitude-ft")); - + double dist = SGGeodesy::distanceNm(_projectionCenter, pos); if (dist > _drawRangeNm) { continue; } - + double heading = model->getDoubleValue("orientation/true-heading-deg"); - if ((name == "aircraft") || (name == "multiplayer") || + if ((name == "aircraft") || (name == "multiplayer") || (name == "wingman") || (name == "tanker")) { drawAIAircraft(model, pos, heading); } else if ((name == "ship") || (name == "carrier") || (name == "escort")) { @@ -1353,7 +1353,7 @@ void MapWidget::drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, d glColor3f(0.0, 0.0, 0.0); glLineWidth(2.0); circleAt(p, 4, 6.0); // black diamond - + // draw heading vector int speedKts = static_cast(model->getDoubleValue("velocities/true-airspeed-kt")); if (speedKts > 1) { @@ -1361,28 +1361,28 @@ void MapWidget::drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, d const double dt = 15.0 / (3600.0); // 15 seconds look-ahead double distanceM = speedKts * SG_NM_TO_METER * dt; - + SGGeod advance; double az2; SGGeodesy::direct(pos, hdg, distanceM, advance, az2); - + drawLine(p, project(advance)); } - + if (validDataForKey((void*) model)) { setAnchorForKey((void*) model, p); return; } - + // draw callsign / altitude / speed - + char buffer[1024]; ::snprintf(buffer, 1024, "%s\n%d'\n%dkts", model->getStringValue("callsign", "<>"), static_cast(pos.getElevationFt() / 50.0) * 50, speedKts); - + MapData* d = createDataForKey((void*) model); d->setText(buffer); d->setLabel(model->getStringValue("callsign", "<>")); @@ -1396,43 +1396,40 @@ void MapWidget::drawAIShip(const SGPropertyNode* model, const SGGeod& pos, doubl { SGVec2d p = project(pos); - glColor3f(0.0, 0.0, 0.0); + glColor3f(0.0, 0.0, 0.3); glLineWidth(2.0); - circleAt(p, 4, 6.0); // black diamond - + circleAt(p, 4, 6.0); // blue diamond (to differentiate from aircraft. + // draw heading vector - int speedKts = static_cast(model->getDoubleValue("velocities/true-airspeed-kt")); + int speedKts = static_cast(model->getDoubleValue("velocities/speed-kts")); if (speedKts > 1) { glLineWidth(1.0); const double dt = 15.0 / (3600.0); // 15 seconds look-ahead double distanceM = speedKts * SG_NM_TO_METER * dt; - + SGGeod advance; double az2; SGGeodesy::direct(pos, hdg, distanceM, advance, az2); - + drawLine(p, project(advance)); } - + if (validDataForKey((void*) model)) { setAnchorForKey((void*) model, p); return; } - - // draw callsign / altitude / speed - + // draw callsign / speed char buffer[1024]; - ::snprintf(buffer, 1024, "%s\n%d'\n%dkts", - model->getStringValue("callsign", "<>"), - static_cast(pos.getElevationFt() / 50.0) * 50, + ::snprintf(buffer, 1024, "%s\n%dkts", + model->getStringValue("name", "<>"), speedKts); - + MapData* d = createDataForKey((void*) model); d->setText(buffer); - d->setLabel(model->getStringValue("callsign", "<>")); - d->setPriority(speedKts > 5 ? 60 : 10); // low priority for parked aircraft + d->setLabel(model->getStringValue("name", "<>")); + d->setPriority(speedKts > 2 ? 30 : 10); // low priority for slow moving ships d->setOffset(MapData::VALIGN_CENTER | MapData::HALIGN_LEFT, 10); d->setAnchor(p); } @@ -1443,11 +1440,11 @@ SGVec2d MapWidget::project(const SGGeod& geod) const double r = earth_radius_lat(geod.getLatitudeRad()); double lonDiff = geod.getLongitudeRad() - _projectionCenter.getLongitudeRad(), latDiff = geod.getLatitudeRad() - _projectionCenter.getLatitudeRad(); - + SGVec2d p = SGVec2d(cos(geod.getLatitudeRad()) * lonDiff, latDiff) * r * currentScale(); - + // rotate as necessary - double cost = cos(_upHeading * SG_DEGREES_TO_RADIANS), + double cost = cos(_upHeading * SG_DEGREES_TO_RADIANS), sint = sin(_upHeading * SG_DEGREES_TO_RADIANS); double rx = cost * p.x() - sint * p.y(); double ry = sint * p.x() + cost * p.y(); @@ -1457,17 +1454,17 @@ SGVec2d MapWidget::project(const SGGeod& geod) const SGGeod MapWidget::unproject(const SGVec2d& p) const { // unrotate, if necessary - double cost = cos(-_upHeading * SG_DEGREES_TO_RADIANS), + double cost = cos(-_upHeading * SG_DEGREES_TO_RADIANS), sint = sin(-_upHeading * SG_DEGREES_TO_RADIANS); - SGVec2d ur(cost * p.x() - sint * p.y(), + SGVec2d ur(cost * p.x() - sint * p.y(), sint * p.x() + cost * p.y()); - + double r = earth_radius_lat(_projectionCenter.getLatitudeRad()); SGVec2d unscaled = ur * (1.0 / (currentScale() * r)); - + double lat = unscaled.y() + _projectionCenter.getLatitudeRad(); double lon = (unscaled.x() / cos(lat)) + _projectionCenter.getLongitudeRad(); - + return SGGeod::fromRad(lon, lat); } @@ -1516,25 +1513,25 @@ void MapWidget::drawLegendBox(const SGVec2d& pos, const std::string& t) std::vector lines(simgear::strutils::split(t, "\n")); const int LINE_LEADING = 4; const int MARGIN = 4; - + // measure int maxWidth = -1, totalHeight = 0; int lineHeight = legendFont.getStringHeight(); - + for (unsigned int ln=0; ln 0) { totalHeight += LINE_LEADING; } - + int lw = legendFont.getStringWidth(lines[ln].c_str()); maxWidth = std::max(maxWidth, lw); } // of line measurement - + if (maxWidth < 0) { return; // all lines are empty, don't draw } - + totalHeight += MARGIN * 2; // draw box @@ -1545,12 +1542,12 @@ void MapWidget::drawLegendBox(const SGVec2d& pos, const std::string& t) box.max[1] = 0; int border = 1; box.draw (pos.x(), pos.y(), PUSTYLE_DROPSHADOW, colour, FALSE, border); - + // draw lines int xPos = pos.x() + MARGIN; int yPos = pos.y() - (lineHeight + MARGIN); glColor3f(0.8, 0.8, 0.8); - + for (unsigned int ln=0; ln> 1, + + int hw = _width >> 1, hh = _height >> 1; puBox visBox(makePuBox(-hw, -hh, _width, _height)); - + unsigned int d = 0; int drawn = 0; std::vector drawQueue; - + bool drawData = _root->getBoolValue("draw-data"); const int MAX_DRAW_DATA = 25; const int MAX_DRAW = 50; - + for (; (d < _dataQueue.size()) && (drawn < MAX_DRAW); ++d) { MapData* md = _dataQueue[d]; md->setDataVisible(drawData); - + if (md->isClipped(visBox)) { continue; } - + if (md->overlaps(drawQueue)) { if (drawData) { // overlapped with data, let's try just the label md->setDataVisible(false); @@ -1591,20 +1588,20 @@ void MapWidget::drawData() continue; } } // of overlaps case - + drawQueue.push_back(md); ++drawn; if (drawData && (drawn >= MAX_DRAW_DATA)) { drawData = false; } } - + // draw lowest-priority first, so higher-priorty items appear on top std::vector::reverse_iterator r; for (r = drawQueue.rbegin(); r!= drawQueue.rend(); ++r) { (*r)->draw(); } - + _dataQueue.clear(); KeyDataMap::iterator it = _mapData.begin(); for (; it != _mapData.end(); ) { @@ -1625,7 +1622,7 @@ bool MapWidget::validDataForKey(void* key) if (it == _mapData.end()) { return false; // no valid data for the key! } - + it->second->resetAge(); // mark data as valid this frame _dataQueue.push_back(it->second); return true; @@ -1637,7 +1634,7 @@ void MapWidget::setAnchorForKey(void* key, const SGVec2d& anchor) if (it == _mapData.end()) { throw sg_exception("no valid data for key!"); } - + it->second->setAnchor(anchor); } @@ -1647,7 +1644,7 @@ MapData* MapWidget::getOrCreateDataForKey(void* key) if (it == _mapData.end()) { return createDataForKey(key); } - + it->second->resetAge(); // mark data as valid this frame _dataQueue.push_back(it->second); return it->second; @@ -1659,7 +1656,7 @@ MapData* MapWidget::createDataForKey(void* key) if (it != _mapData.end()) { throw sg_exception("duplicate data requested for key!"); } - + MapData* d = new MapData(0); _mapData[key] = d; _dataQueue.push_back(d); From d7798a7cc2fb68bd641558bde2ef9fe44d7d1331 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sun, 27 Mar 2011 11:32:41 +0200 Subject: [PATCH 16/23] Slightly brighter blue color level for map widget Almost couldn't see the new blue color on my screen. Enjoy the blues... :) --- src/GUI/MapWidget.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GUI/MapWidget.cxx b/src/GUI/MapWidget.cxx index c31347e2a..b482ada90 100644 --- a/src/GUI/MapWidget.cxx +++ b/src/GUI/MapWidget.cxx @@ -1396,7 +1396,7 @@ void MapWidget::drawAIShip(const SGPropertyNode* model, const SGGeod& pos, doubl { SGVec2d p = project(pos); - glColor3f(0.0, 0.0, 0.3); + glColor3f(0.0, 0.0, 0.5); glLineWidth(2.0); circleAt(p, 4, 6.0); // blue diamond (to differentiate from aircraft. From dca213208720b7a3d83c1130ed4f3b64bdf3bff1 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Mon, 28 Mar 2011 00:16:27 +0200 Subject: [PATCH 17/23] New property reporting worst-case frame latency. Shows maximum latency of any frame within the last second. --- src/Time/TimeManager.cxx | 10 ++++++++-- src/Time/TimeManager.hxx | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Time/TimeManager.cxx b/src/Time/TimeManager.cxx index 2e2389695..7d4ed5607 100644 --- a/src/Time/TimeManager.cxx +++ b/src/Time/TimeManager.cxx @@ -88,9 +88,11 @@ void TimeManager::init() _warp->getIntValue()); globals->set_time_params(_impl); -// frame/update-rate counters + // frame-rate / worst-case delay / update-rate counters _frameRate = fgGetNode("/sim/frame-rate", true); + _frameDelayMax = fgGetNode("/sim/frame-delay-max-ms", true); _lastFrameTime = 0; + _wcFrameDelayMax = 0.0; _frameCount = 0; } @@ -160,7 +162,9 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt) SGTimeStamp currentStamp; currentStamp.stamp(); double dt = (currentStamp - _lastStamp).toSecs(); - + if (dt > _wcFrameDelayMax) + _wcFrameDelayMax = dt; + // Limit the time we need to spend in simulation loops // That means, if the /sim/max-simtime-per-frame value is strictly positive // you can limit the maximum amount of time you will do simulations for @@ -251,7 +255,9 @@ void TimeManager::computeFrameRate() // Calculate frame rate average if ((_impl->get_cur_time() != _lastFrameTime)) { _frameRate->setIntValue(_frameCount); + _frameDelayMax->setDoubleValue(_wcFrameDelayMax*1000); _frameCount = 0; + _wcFrameDelayMax = 0.0; } _lastFrameTime = _impl->get_cur_time(); diff --git a/src/Time/TimeManager.hxx b/src/Time/TimeManager.hxx index 59aa03616..edf498013 100644 --- a/src/Time/TimeManager.hxx +++ b/src/Time/TimeManager.hxx @@ -78,9 +78,11 @@ private: SGPropertyNode_ptr _longitudeDeg; SGPropertyNode_ptr _latitudeDeg; -// frame-rate / update-rate counters + // frame-rate / worst-case delay / update-rate counters SGPropertyNode_ptr _frameRate; + SGPropertyNode_ptr _frameDelayMax; time_t _lastFrameTime; + double _wcFrameDelayMax; int _frameCount; }; From 7ec9d036d6120a4b659d906c1e4bac5bcc6c17e1 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Mon, 28 Mar 2011 00:30:23 +0200 Subject: [PATCH 18/23] Renaming / more consistent naming. --- src/Time/TimeManager.cxx | 14 +++++++------- src/Time/TimeManager.hxx | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Time/TimeManager.cxx b/src/Time/TimeManager.cxx index 7d4ed5607..4c4b28a76 100644 --- a/src/Time/TimeManager.cxx +++ b/src/Time/TimeManager.cxx @@ -88,11 +88,11 @@ void TimeManager::init() _warp->getIntValue()); globals->set_time_params(_impl); - // frame-rate / worst-case delay / update-rate counters + // frame-rate / worst-case latency / update-rate counters _frameRate = fgGetNode("/sim/frame-rate", true); - _frameDelayMax = fgGetNode("/sim/frame-delay-max-ms", true); + _frameLatency = fgGetNode("/sim/frame-latency-max-ms", true); _lastFrameTime = 0; - _wcFrameDelayMax = 0.0; + _frameLatencyMax = 0.0; _frameCount = 0; } @@ -162,8 +162,8 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt) SGTimeStamp currentStamp; currentStamp.stamp(); double dt = (currentStamp - _lastStamp).toSecs(); - if (dt > _wcFrameDelayMax) - _wcFrameDelayMax = dt; + if (dt > _frameLatencyMax) + _frameLatencyMax = dt; // Limit the time we need to spend in simulation loops // That means, if the /sim/max-simtime-per-frame value is strictly positive @@ -255,9 +255,9 @@ void TimeManager::computeFrameRate() // Calculate frame rate average if ((_impl->get_cur_time() != _lastFrameTime)) { _frameRate->setIntValue(_frameCount); - _frameDelayMax->setDoubleValue(_wcFrameDelayMax*1000); + _frameLatency->setDoubleValue(_frameLatencyMax*1000); _frameCount = 0; - _wcFrameDelayMax = 0.0; + _frameLatencyMax = 0.0; } _lastFrameTime = _impl->get_cur_time(); diff --git a/src/Time/TimeManager.hxx b/src/Time/TimeManager.hxx index edf498013..53dffd51b 100644 --- a/src/Time/TimeManager.hxx +++ b/src/Time/TimeManager.hxx @@ -78,11 +78,11 @@ private: SGPropertyNode_ptr _longitudeDeg; SGPropertyNode_ptr _latitudeDeg; - // frame-rate / worst-case delay / update-rate counters + // frame-rate / worst-case latency / update-rate counters SGPropertyNode_ptr _frameRate; - SGPropertyNode_ptr _frameDelayMax; + SGPropertyNode_ptr _frameLatency; time_t _lastFrameTime; - double _wcFrameDelayMax; + double _frameLatencyMax; int _frameCount; }; From 4141b80b0ccd2ddc6cf023672f7ffae3c2024b00 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Tue, 29 Mar 2011 23:31:59 +0200 Subject: [PATCH 19/23] fix #296: FDMshell+TankProperties not bound after sim reset Well, when we need to unbind something temporarily, it's wise to really bind it again... --- src/FDM/TankProperties.cxx | 12 ++++++------ src/FDM/fdm_shell.cxx | 2 +- src/Main/fg_init.cxx | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/FDM/TankProperties.cxx b/src/FDM/TankProperties.cxx index 05e83ce11..e07036f8f 100644 --- a/src/FDM/TankProperties.cxx +++ b/src/FDM/TankProperties.cxx @@ -236,12 +236,6 @@ TankPropertiesList::TankPropertiesList( SGPropertyNode_ptr rootNode ) } _tiedProperties.setRoot( rootNode ); - _tiedProperties.Tie("total-fuel-kg", this, &TankPropertiesList::getTotalContent_kg ); - _tiedProperties.Tie("total-fuel-lbs", this, &TankPropertiesList::getTotalContent_lbs ); - _tiedProperties.Tie("total-fuel-gal_us", this, &TankPropertiesList::getTotalContent_gal_us ); - _tiedProperties.Tie("total-fuel-gals", this, &TankPropertiesList::getTotalContent_gal_us ); - _tiedProperties.Tie("total-fuel-gal_imp", this, &TankPropertiesList::getTotalContent_gal_imp ); - _tiedProperties.Tie("total-fuel-norm", this, &TankPropertiesList::getTotalContent_norm ); } double TankPropertiesList::getTotalContent_lbs() const @@ -297,6 +291,12 @@ double TankPropertiesList::getTotalContent_norm() const void TankPropertiesList::bind() { + _tiedProperties.Tie("total-fuel-kg", this, &TankPropertiesList::getTotalContent_kg ); + _tiedProperties.Tie("total-fuel-lbs", this, &TankPropertiesList::getTotalContent_lbs ); + _tiedProperties.Tie("total-fuel-gal_us", this, &TankPropertiesList::getTotalContent_gal_us ); + _tiedProperties.Tie("total-fuel-gals", this, &TankPropertiesList::getTotalContent_gal_us ); + _tiedProperties.Tie("total-fuel-gal_imp", this, &TankPropertiesList::getTotalContent_gal_imp ); + _tiedProperties.Tie("total-fuel-norm", this, &TankPropertiesList::getTotalContent_norm ); for( const_iterator it = begin(); it != end(); ++it ) { (*it)->bind(); } diff --git a/src/FDM/fdm_shell.cxx b/src/FDM/fdm_shell.cxx index 5fa77d895..8055bce5a 100644 --- a/src/FDM/fdm_shell.cxx +++ b/src/FDM/fdm_shell.cxx @@ -90,13 +90,13 @@ void FDMShell::reinit() void FDMShell::bind() { + _tankProperties.bind(); if (_impl && _impl->get_inited()) { if (_impl->get_bound()) { throw sg_exception("FDMShell::bind of bound FGInterface impl"); } _impl->bind(); } - _tankProperties.bind(); } void FDMShell::unbind() diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index d77a81a41..9eb8ae7a9 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -1561,6 +1561,9 @@ void fgReInitSubsystems() globals->get_subsystem("time")->reinit(); + // need to bind FDMshell again, since we manually unbound it above... + globals->get_subsystem("flight")->bind(); + // setup state to end re-init fgSetBool("/sim/signals/reinit", false); if ( !freeze ) { From 298f832d4313cdba882ca5a398efdbc7a3599789 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sat, 2 Apr 2011 15:13:29 +0200 Subject: [PATCH 20/23] Support optional Nasal modules in fgdata/Nasal/MyModuleFoo - Allow structuring generic Nasal sources into modules (i.e. support separate source folders for multiplayer/local weather/... sources) - Option to enable/disable loading of generic Nasal modules (i.e we only need to load stuff that is really needed/enabled). - Provide basic loading sequence: subfolders are strictly loaded _after_ the base directory. So submodules can rely on .nas-scripts like math.nas, io.nas, debug.nas, ... to be already loaded - dropping the need for awkward listeners/timers to delay module initialization (loading order within Nasal/*.nas is still random) --- src/Scripting/NasalSys.cxx | 106 +++++++++++++++++++++++++++---------- src/Scripting/NasalSys.hxx | 3 ++ 2 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 1f952b325..72a99bc93 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -737,12 +737,15 @@ void FGNasalSys::init() // Now load the various source files in the Nasal directory simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal")); - simgear::PathList scripts = nasalDir.children(simgear::Dir::TYPE_FILE, ".nas"); - - for (unsigned int i=0; i0) + { + SGPropertyNode* nasal = globals->get_props()->getNode("nasal"); + SGPropertyNode* module_node = nasal->getChild(moduleName,0,true); + for (unsigned int i=0; igetChild("file",i,true); + pFileNode->setStringValue(scripts[i].c_str()); + } + if (!module_node->hasChild("enabled",0)) + { + SGPropertyNode* node = module_node->getChild("enabled",0,true); + node->setBoolValue(true); + node->setAttribute(SGPropertyNode::USERARCHIVE,true); + } + } +} + // Loads the scripts found under /nasal in the global tree void FGNasalSys::loadPropertyScripts() { @@ -785,33 +819,51 @@ void FGNasalSys::loadPropertyScripts() for(int i=0; inChildren(); i++) { SGPropertyNode* n = nasal->getChild(i); + bool is_loaded = false; const char* module = n->getName(); if(n->hasChild("module")) module = n->getStringValue("module"); + if (n->getBoolValue("enabled",true)) + { + // allow multiple files to be specified within a single + // Nasal module tag + int j = 0; + SGPropertyNode *fn; + bool file_specified = false; + while((fn = n->getChild("file", j)) != NULL) { + file_specified = true; + const char* file = fn->getStringValue(); + SGPath p(file); + if (!p.isAbsolute() || !p.exists()) + { + p = globals->resolve_maybe_aircraft_path(file); + } + loadModule(p, module); + j++; + } + + const char* src = n->getStringValue("script"); + if(!n->hasChild("script")) src = 0; // Hrm... + if(src) + createModule(module, n->getPath().c_str(), src, strlen(src)); + + if(!file_specified && !src) + { + // module no longer exists - clear the archived "enable" flag + n->setAttribute(SGPropertyNode::USERARCHIVE,false); + SGPropertyNode* node = n->getChild("enabled",0,false); + if (node) + node->setAttribute(SGPropertyNode::USERARCHIVE,false); - // allow multiple files to be specified within a single - // Nasal module tag - int j = 0; - SGPropertyNode *fn; - bool file_specified = false; - while((fn = n->getChild("file", j)) != NULL) { - file_specified = true; - const char* file = fn->getStringValue(); - SGPath p = globals->resolve_maybe_aircraft_path(file); - loadModule(p, module); - j++; + SG_LOG(SG_NASAL, SG_ALERT, "Nasal error: " << + "no or