diff --git a/projects/VC100/FlightGear/FlightGear.vcxproj b/projects/VC100/FlightGear/FlightGear.vcxproj index dffa08cb4..fa563816b 100644 --- a/projects/VC100/FlightGear/FlightGear.vcxproj +++ b/projects/VC100/FlightGear/FlightGear.vcxproj @@ -174,7 +174,7 @@ .\Release/FlightGear.tlb - OnlyExplicitInline + AnySuitable ..\..\..\src;..\..\..\src\include;..\..\..\src\FDM\JSBSim;..\..\..\..\SimGear;..\..\..\..\install\msvc100\OpenSceneGraph\include;..\..\..\..\3rdParty\include;..\..\..\..\boost_1_43_0;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;HAVE_CONFIG_H;FGFS;ENABLE_AUDIO_SUPPORT;_FG_NDEBUG;ENABLE_THREADS=1;FG_ENABLE_MULTIPASS_CLOUDS;ENABLE_SP_FMDS;_USE_MATH_DEFINES;FG_JPEG_SERVER;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) true diff --git a/projects/VC100/GPSsmooth/GPSsmooth.vcxproj b/projects/VC100/GPSsmooth/GPSsmooth.vcxproj index 501151db0..01e9faee7 100644 --- a/projects/VC100/GPSsmooth/GPSsmooth.vcxproj +++ b/projects/VC100/GPSsmooth/GPSsmooth.vcxproj @@ -149,6 +149,7 @@ Level3 ProgramDatabase + AnySuitable sg.lib;net.lib;ul.lib;ws2_32.lib;winmm.lib;zlib.lib;%(AdditionalDependencies) diff --git a/projects/VC100/MIDGsmooth/MIDGsmooth.vcxproj b/projects/VC100/MIDGsmooth/MIDGsmooth.vcxproj index 3e3ae732a..4c52c0bac 100644 --- a/projects/VC100/MIDGsmooth/MIDGsmooth.vcxproj +++ b/projects/VC100/MIDGsmooth/MIDGsmooth.vcxproj @@ -151,6 +151,7 @@ Level3 ProgramDatabase + AnySuitable sg.lib;net.lib;ul.lib;ws2_32.lib;winmm.lib;%(AdditionalDependencies) diff --git a/projects/VC100/UGsmooth/UGsmooth.vcxproj b/projects/VC100/UGsmooth/UGsmooth.vcxproj index 4e100688e..44d5a52d7 100644 --- a/projects/VC100/UGsmooth/UGsmooth.vcxproj +++ b/projects/VC100/UGsmooth/UGsmooth.vcxproj @@ -151,6 +151,7 @@ Level3 ProgramDatabase + AnySuitable sg.lib;net.lib;ul.lib;ws2_32.lib;winmm.lib;zlib.lib;%(AdditionalDependencies) diff --git a/projects/VC100/fgadmin/fgadmin.vcxproj b/projects/VC100/fgadmin/fgadmin.vcxproj index 3b7795bdc..c7c59e4ec 100644 --- a/projects/VC100/fgadmin/fgadmin.vcxproj +++ b/projects/VC100/fgadmin/fgadmin.vcxproj @@ -142,7 +142,7 @@ MaxSpeed - OnlyExplicitInline + AnySuitable true ..\..\..\..\SimGear;..\..\..\..\install\msvc100\OpenSceneGraph\include;..\..\..\..\3rdParty\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;HAVE_ZLIB;NOMINMAX;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) diff --git a/projects/VC100/fgjs/fgjs.vcxproj b/projects/VC100/fgjs/fgjs.vcxproj index e34b9b53c..f9b1b2e4f 100644 --- a/projects/VC100/fgjs/fgjs.vcxproj +++ b/projects/VC100/fgjs/fgjs.vcxproj @@ -151,6 +151,7 @@ Level3 ProgramDatabase + AnySuitable sg.lib;js.lib;ul.lib;zlib.lib;winmm.lib;ws2_32.lib;OpenThreads.lib;%(AdditionalDependencies) diff --git a/projects/VC100/fgviewer/fgviewer.vcxproj b/projects/VC100/fgviewer/fgviewer.vcxproj index a981fce78..4c37c4d30 100644 --- a/projects/VC100/fgviewer/fgviewer.vcxproj +++ b/projects/VC100/fgviewer/fgviewer.vcxproj @@ -151,6 +151,7 @@ Level3 ProgramDatabase + AnySuitable opengl32.lib;osg.lib;osgDB.lib;osgViewer.lib;osgGA.lib;openthreads.lib;osgParticle.lib;osgUtil.lib;osgText.lib;ul.lib;sg.lib;zlib.lib;%(AdditionalDependencies) diff --git a/projects/VC100/metar/metar.vcxproj b/projects/VC100/metar/metar.vcxproj index 5102d960c..d40361f04 100644 --- a/projects/VC100/metar/metar.vcxproj +++ b/projects/VC100/metar/metar.vcxproj @@ -148,6 +148,7 @@ Level3 ProgramDatabase + AnySuitable sg.lib;ul.lib;net.lib;ws2_32.lib;%(AdditionalDependencies) diff --git a/projects/VC100/terrasync/terrasync.vcxproj b/projects/VC100/terrasync/terrasync.vcxproj index 9107c115e..2edb4903e 100644 --- a/projects/VC100/terrasync/terrasync.vcxproj +++ b/projects/VC100/terrasync/terrasync.vcxproj @@ -151,6 +151,7 @@ Level3 ProgramDatabase + AnySuitable ul.lib;sg.lib;net.lib;ws2_32.lib;libsvn_client-1.lib;libsvn_diff-1.lib;libsvn_delta-1.lib;libsvn_ra-1.lib;libsvn_subr-1.lib;libsvn_wc-1.lib;libapr-1.lib;%(AdditionalDependencies) diff --git a/projects/VC100/xmlgrep/xmlgrep.vcxproj b/projects/VC100/xmlgrep/xmlgrep.vcxproj index d12aecfea..f2894ce6f 100644 --- a/projects/VC100/xmlgrep/xmlgrep.vcxproj +++ b/projects/VC100/xmlgrep/xmlgrep.vcxproj @@ -142,6 +142,7 @@ Level3 ProgramDatabase + AnySuitable true diff --git a/projects/VC100/yasim/yasim.vcxproj b/projects/VC100/yasim/yasim.vcxproj index 9a8b1047f..cb3477d7b 100644 --- a/projects/VC100/yasim/yasim.vcxproj +++ b/projects/VC100/yasim/yasim.vcxproj @@ -151,6 +151,7 @@ Level3 ProgramDatabase + AnySuitable sg.lib;ul.lib;OpenThreads.lib;%(AdditionalDependencies) diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx index 5f67d88e4..0306c3ec5 100644 --- a/src/AIModel/AIBallistic.cxx +++ b/src/AIModel/AIBallistic.cxx @@ -940,7 +940,7 @@ void FGAIBallistic::handle_impact() { invisible = true; } else if (_subID == 0) // kill the AIObject if there is no subsubmodel setDie(true); - } + } } void FGAIBallistic::handle_expiry() { diff --git a/src/AIModel/AIBallistic.hxx b/src/AIModel/AIBallistic.hxx index 6ce9c13d8..c9613de89 100644 --- a/src/AIModel/AIBallistic.hxx +++ b/src/AIModel/AIBallistic.hxx @@ -15,7 +15,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // -// You should have received a copy of the GNU General Public License +// You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/src/AIModel/AIBase.cxx b/src/AIModel/AIBase.cxx index ac8c4fb57..517b91b1d 100644 --- a/src/AIModel/AIBase.cxx +++ b/src/AIModel/AIBase.cxx @@ -236,7 +236,7 @@ void FGAIBase::initModel(osg::Node *node) SG_LOG(SG_INPUT, SG_WARN, "AIBase: Could not load model " << model_path); } - //props->setStringValue("submodels/path", _path.c_str()); + //props->setStringValue("submodels/path", _path.c_str()); setDie(false); } diff --git a/src/AIModel/AIBase.hxx b/src/AIModel/AIBase.hxx index 20bca1d9c..4c2c591af 100644 --- a/src/AIModel/AIBase.hxx +++ b/src/AIModel/AIBase.hxx @@ -1,7 +1,7 @@ // FGAIBase.hxx - abstract base class for AI objects // Written by David Culp, started Nov 2003, based on // David Luff's FGAIEntity class. -// - davidculp2@comcast.net +// - davidculp2@comcast.net // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx index 1c83ca479..4255709ab 100644 --- a/src/AIModel/AIManager.cxx +++ b/src/AIModel/AIManager.cxx @@ -2,7 +2,7 @@ // - a global management type for AI objects // // Written by David Culp, started October 2003. -// - davidculp2@comcast.net +// - davidculp2@comcast.net // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as diff --git a/src/AIModel/AIWingman.cxx b/src/AIModel/AIWingman.cxx index 0ed84e85a..39c20bbc6 100644 --- a/src/AIModel/AIWingman.cxx +++ b/src/AIModel/AIWingman.cxx @@ -1,7 +1,7 @@ // FGAIWingman - FGAIBllistic-derived class creates an AI Wingman // // Written by Vivian Meazza, started February 2008. -// - vivian.meazza at lineone.net +// - vivian.meazza at lineone.net // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as diff --git a/src/AIModel/submodel.cxx b/src/AIModel/submodel.cxx index 7f9f80c02..471b45dd1 100644 --- a/src/AIModel/submodel.cxx +++ b/src/AIModel/submodel.cxx @@ -896,7 +896,7 @@ void FGSubmodelMgr::setParentNode(int id) { if (!model) continue; - }// end for loop + }// end for loop if (_selected_ac != 0){ diff --git a/src/AIModel/submodel.hxx b/src/AIModel/submodel.hxx index e6c9f9e1f..2abff45ce 100644 --- a/src/AIModel/submodel.hxx +++ b/src/AIModel/submodel.hxx @@ -20,7 +20,7 @@ #include
using std::vector; -using std::string; +using std::string; using std::list; class FGAIBase; diff --git a/src/Airports/pavement.cxx b/src/Airports/pavement.cxx index 7e5f60763..4f06a9a1d 100755 --- a/src/Airports/pavement.cxx +++ b/src/Airports/pavement.cxx @@ -25,8 +25,9 @@ #include "pavement.hxx" FGPavement::FGPavement(const std::string& aIdent, const SGGeod& aPos) : - FGPositioned(PAVEMENT, aIdent, aPos, false) + FGPositioned(PAVEMENT, aIdent, aPos) { + init(false); // FGPositioned::init } void FGPavement::addNode(const SGGeod &aPos, bool aClose) diff --git a/src/Airports/runwaybase.cxx b/src/Airports/runwaybase.cxx index fd82406ad..1131e22a0 100644 --- a/src/Airports/runwaybase.cxx +++ b/src/Airports/runwaybase.cxx @@ -51,12 +51,14 @@ FGRunwayBase::FGRunwayBase(Type aTy, const string& aIdent, const double width, const int surface_code, bool index) : - FGPositioned(aTy, aIdent, aGeod, index) + FGPositioned(aTy, aIdent, aGeod) { _heading = heading; _length = length; _width = width; _surface_code = surface_code; + + init(index); } SGGeod FGRunwayBase::pointOnCenterline(double aOffset) const diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx index 249e5a72b..a418bd414 100644 --- a/src/Airports/simple.cxx +++ b/src/Airports/simple.cxx @@ -63,6 +63,7 @@ FGAirport::FGAirport(const string &id, const SGGeod& location, const SGGeod& tow mRunwaysLoaded(false), mTaxiwaysLoaded(true) { + init(true); // init FGPositioned } diff --git a/src/Autopilot/autopilot.cxx b/src/Autopilot/autopilot.cxx index 809001d61..e8bb91b02 100644 --- a/src/Autopilot/autopilot.cxx +++ b/src/Autopilot/autopilot.cxx @@ -97,11 +97,11 @@ void Autopilot::add_component( Component * component ) std::string name = component->get_name(); for( unsigned i = 0; get_subsystem( name.c_str() ) != NULL; i++ ) { ostringstream buf; - buf << name << "_" << i; + buf << component->get_name() << "_" << i; name = buf.str(); } if( name != component->get_name() ) - SG_LOG( SG_ALL, SG_ALERT, "Duplicate autopilot component " << component->get_name() << ", renamed to " << name ); + SG_LOG( SG_ALL, SG_WARN, "Duplicate autopilot component " << component->get_name() << ", renamed to " << name ); set_subsystem( name.c_str(), component ); } diff --git a/src/Autopilot/autopilotgroup.cxx b/src/Autopilot/autopilotgroup.cxx index e5bb6d03c..347a39e0e 100644 --- a/src/Autopilot/autopilotgroup.cxx +++ b/src/Autopilot/autopilotgroup.cxx @@ -28,117 +28,35 @@ #include "autopilot.hxx" #include "autopilotgroup.hxx" +#include +#include + +#include +#include #include
-#include
-#include
-#include -#include -#include - -using std::cout; -using std::endl; using simgear::PropertyList; -FGXMLAutopilotGroup::FGXMLAutopilotGroup() : - SGSubsystemGroup() -#ifdef XMLAUTO_USEHELPER - ,average(0.0), // average/filtered prediction - v_last(0.0), // last velocity - last_static_pressure(0.0), - vel(fgGetNode( "/velocities/airspeed-kt", true )), - // Estimate speed in 5,10 seconds - lookahead5(fgGetNode( "/autopilot/internal/lookahead-5-sec-airspeed-kt", true )), - lookahead10(fgGetNode( "/autopilot/internal/lookahead-10-sec-airspeed-kt", true )), - bug(fgGetNode( "/autopilot/settings/heading-bug-deg", true )), - mag_hdg(fgGetNode( "/orientation/heading-magnetic-deg", true )), - bug_error(fgGetNode( "/autopilot/internal/heading-bug-error-deg", true )), - fdm_bug_error(fgGetNode( "/autopilot/internal/fdm-heading-bug-error-deg", true )), - target_true(fgGetNode( "/autopilot/settings/true-heading-deg", true )), - true_hdg(fgGetNode( "/orientation/heading-deg", true )), - true_error(fgGetNode( "/autopilot/internal/true-heading-error-deg", true )), - target_nav1(fgGetNode( "/instrumentation/nav[0]/radials/target-auto-hdg-deg", true )), - true_nav1(fgGetNode( "/autopilot/internal/nav1-heading-error-deg", true )), - true_track_nav1(fgGetNode( "/autopilot/internal/nav1-track-error-deg", true )), - nav1_course_error(fgGetNode( "/autopilot/internal/nav1-course-error", true )), - nav1_selected_course(fgGetNode( "/instrumentation/nav[0]/radials/selected-deg", true )), - vs_fps(fgGetNode( "/velocities/vertical-speed-fps", true )), - vs_fpm(fgGetNode( "/autopilot/internal/vert-speed-fpm", true )), - static_pressure(fgGetNode( "/systems/static[0]/pressure-inhg", true )), - pressure_rate(fgGetNode( "/autopilot/internal/pressure-rate", true )), - track(fgGetNode( "/orientation/track-deg", true )) -#endif +class FGXMLAutopilotGroupImplementation : public FGXMLAutopilotGroup { -} +public: + void init(); + void reinit(); + void update( double dt ); +private: + void initFrom( SGPropertyNode_ptr rootNode, const char * childName ); + vector _autopilotNames; -void FGXMLAutopilotGroup::update( double dt ) +}; + +void FGXMLAutopilotGroupImplementation::update( double dt ) { // update all configured autopilots SGSubsystemGroup::update( dt ); -#ifdef XMLAUTO_USEHELPER - // update helper values - double v = vel->getDoubleValue(); - double a = 0.0; - if ( dt > 0.0 ) { - a = (v - v_last) / dt; - - if ( dt < 1.0 ) { - average = (1.0 - dt) * average + dt * a; - } else { - average = a; - } - - lookahead5->setDoubleValue( v + average * 5.0 ); - lookahead10->setDoubleValue( v + average * 10.0 ); - v_last = v; - } - - // Calculate heading bug error normalized to +/- 180.0 - double diff = bug->getDoubleValue() - mag_hdg->getDoubleValue(); - SG_NORMALIZE_RANGE(diff, -180.0, 180.0); - bug_error->setDoubleValue( diff ); - - fdm_bug_error->setDoubleValue( diff ); - - // Calculate true heading error normalized to +/- 180.0 - diff = target_true->getDoubleValue() - true_hdg->getDoubleValue(); - SG_NORMALIZE_RANGE(diff, -180.0, 180.0); - true_error->setDoubleValue( diff ); - - // Calculate nav1 target heading error normalized to +/- 180.0 - diff = target_nav1->getDoubleValue() - true_hdg->getDoubleValue(); - SG_NORMALIZE_RANGE(diff, -180.0, 180.0); - true_nav1->setDoubleValue( diff ); - - // Calculate true groundtrack - diff = target_nav1->getDoubleValue() - track->getDoubleValue(); - SG_NORMALIZE_RANGE(diff, -180.0, 180.0); - true_track_nav1->setDoubleValue( diff ); - - // Calculate nav1 selected course error normalized to +/- 180.0 - diff = nav1_selected_course->getDoubleValue() - mag_hdg->getDoubleValue(); - SG_NORMALIZE_RANGE( diff, -180.0, 180.0 ); - nav1_course_error->setDoubleValue( diff ); - - // Calculate vertical speed in fpm - vs_fpm->setDoubleValue( vs_fps->getDoubleValue() * 60.0 ); - - - // Calculate static port pressure rate in [inhg/s]. - // Used to determine vertical speed. - if ( dt > 0.0 ) { - double current_static_pressure = static_pressure->getDoubleValue(); - double current_pressure_rate = - ( current_static_pressure - last_static_pressure ) / dt; - - pressure_rate->setDoubleValue(current_pressure_rate); - last_static_pressure = current_static_pressure; - } -#endif } -void FGXMLAutopilotGroup::reinit() +void FGXMLAutopilotGroupImplementation::reinit() { SGSubsystemGroup::unbind(); @@ -152,18 +70,29 @@ void FGXMLAutopilotGroup::reinit() init(); } -void FGXMLAutopilotGroup::init() +void FGXMLAutopilotGroupImplementation::init() { - PropertyList autopilotNodes = fgGetNode( "/sim/systems", true )->getChildren("autopilot"); - if( autopilotNodes.size() == 0 ) { - SG_LOG( SG_ALL, SG_WARN, "No autopilot configuration specified for this model!"); - return; - } + static const char * nodeNames[] = { + "autopilot", + "property-rule" + }; + for( unsigned i = 0; i < sizeof(nodeNames)/sizeof(nodeNames[0]); i++ ) + initFrom( fgGetNode( "/sim/systems" ), nodeNames[i] ); + SGSubsystemGroup::bind(); + SGSubsystemGroup::init(); +} + +void FGXMLAutopilotGroupImplementation::initFrom( SGPropertyNode_ptr rootNode, const char * childName ) +{ + if( rootNode == NULL ) + return; + + PropertyList autopilotNodes = rootNode->getChildren(childName); for( PropertyList::size_type i = 0; i < autopilotNodes.size(); i++ ) { SGPropertyNode_ptr pathNode = autopilotNodes[i]->getNode( "path" ); if( pathNode == NULL ) { - SG_LOG( SG_ALL, SG_WARN, "No autopilot configuration file specified for this autopilot!"); + SG_LOG( SG_ALL, SG_WARN, "No configuration file specified for this property-rule!"); continue; } @@ -182,40 +111,36 @@ void FGXMLAutopilotGroup::init() string name = apName; for( unsigned i = 0; get_subsystem( apName.c_str() ) != NULL; i++ ) { ostringstream buf; - buf << apName << "_" << i; + buf << name << "_" << i; apName = buf.str(); } if( apName != name ) - SG_LOG( SG_ALL, SG_ALERT, "Duplicate autopilot component " << name << ", renamed to " << apName ); + SG_LOG( SG_ALL, SG_WARN, "Duplicate property-rule configuration name " << name << ", renamed to " << apName ); } - if( get_subsystem( apName.c_str() ) != NULL ) { - SG_LOG( SG_ALL, SG_ALERT, "Duplicate autopilot configuration name " << apName << " ignored" ); - continue; - } + SGPath config = globals->resolve_maybe_aircraft_path(pathNode->getStringValue()); - SGPath config = globals->resolve_aircraft_path(pathNode->getStringValue()); - - SG_LOG( SG_ALL, SG_INFO, "Reading autopilot configuration from " << config.str() ); + SG_LOG( SG_ALL, SG_INFO, "Reading property-rule configuration from " << config.str() ); try { SGPropertyNode_ptr root = new SGPropertyNode(); readProperties( config.str(), root ); - SG_LOG( SG_AUTOPILOT, SG_INFO, "adding autopilot subsystem " << apName ); + SG_LOG( SG_AUTOPILOT, SG_INFO, "adding property-rule subsystem " << apName ); FGXMLAutopilot::Autopilot * ap = new FGXMLAutopilot::Autopilot( autopilotNodes[i], root ); ap->set_name( apName ); set_subsystem( apName, ap ); _autopilotNames.push_back( apName ); } catch (const sg_exception& e) { - SG_LOG( SG_AUTOPILOT, SG_ALERT, "Failed to load autopilot configuration: " + SG_LOG( SG_AUTOPILOT, SG_ALERT, "Failed to load property-rule configuration: " << config.str() << ":" << e.getMessage() ); continue; } } - - SGSubsystemGroup::bind(); - SGSubsystemGroup::init(); } +FGXMLAutopilotGroup * FGXMLAutopilotGroup::createInstance() +{ + return new FGXMLAutopilotGroupImplementation(); +} diff --git a/src/Autopilot/autopilotgroup.hxx b/src/Autopilot/autopilotgroup.hxx index e27a6b16d..1ccb0be76 100644 --- a/src/Autopilot/autopilotgroup.hxx +++ b/src/Autopilot/autopilotgroup.hxx @@ -24,11 +24,6 @@ #ifndef _XMLAUTO_HXX #define _XMLAUTO_HXX 1 -#include -#include - -#include -#include /** * @brief Model an autopilot system by implementing a SGSubsystemGroup @@ -37,12 +32,9 @@ class FGXMLAutopilotGroup : public SGSubsystemGroup { public: - FGXMLAutopilotGroup(); - void init(); - void reinit(); - void update( double dt ); -private: - std::vector _autopilotNames; + static FGXMLAutopilotGroup * createInstance(); +protected: + FGXMLAutopilotGroup() : SGSubsystemGroup() {} }; diff --git a/src/Cockpit/cockpit.cxx b/src/Cockpit/cockpit.cxx index 54ccd2a23..a2f542cbc 100644 --- a/src/Cockpit/cockpit.cxx +++ b/src/Cockpit/cockpit.cxx @@ -26,6 +26,7 @@ #endif #include +#include #include #include @@ -245,7 +246,8 @@ float get_climb_rate( void ) float get_view_direction( void ) { double view_off = 360.0 - globals->get_current_view()->getHeadingOffset_deg(); - double view = SGMiscd::normalizeAngle(fgGetDouble("/orientation/heading-deg") + view_off); + double view = fgGetDouble("/orientation/heading-deg") + view_off; + SG_NORMALIZE_RANGE(view, 0.0, 360.0); return view; } diff --git a/src/Environment/environment_ctrl.cxx b/src/Environment/environment_ctrl.cxx index 74f1d82ea..0cc434e69 100644 --- a/src/Environment/environment_ctrl.cxx +++ b/src/Environment/environment_ctrl.cxx @@ -135,7 +135,9 @@ FGInterpolateEnvironmentCtrl::init () read_table( boundary_n, _boundary_table); // pass in a pointer to the environment of the last bondary layer as // a starting point - read_table( aloft_n, _aloft_table, &(*(_boundary_table.end()-1))->environment); + read_table( aloft_n, _aloft_table, + _boundary_table.size() > 0 ? + &(*(_boundary_table.end()-1))->environment : NULL ); } void diff --git a/src/Environment/environment_mgr.cxx b/src/Environment/environment_mgr.cxx index 98184acf9..c81022258 100644 --- a/src/Environment/environment_mgr.cxx +++ b/src/Environment/environment_mgr.cxx @@ -41,6 +41,7 @@ #include "environment_ctrl.hxx" #include "fgclouds.hxx" #include "precipitation_mgr.hxx" +#include "ridge_lift.hxx" class SGSky; extern SGSky *thesky; @@ -65,10 +66,18 @@ FGEnvironmentMgr::FGEnvironmentMgr () _precipitationManager = new FGPrecipitationMgr; set_subsystem("precipitation", _precipitationManager); + + set_subsystem("ridgelift", new FGRidgeLift); } FGEnvironmentMgr::~FGEnvironmentMgr () { + SGSubsystem * subsys; + + subsys = get_subsystem( "ridgelift" ); + remove_subsystem( "ridgelift" ); + delete subsys; + remove_subsystem("precipitation"); delete _precipitationManager; diff --git a/src/Environment/terrainsampler.cxx b/src/Environment/terrainsampler.cxx new file mode 100644 index 000000000..276c8ffb1 --- /dev/null +++ b/src/Environment/terrainsampler.cxx @@ -0,0 +1,402 @@ +// terrainsampler.cxx -- +// +// Written by Torsten Dreyer, started July 2010 +// Based on local weather implementation in nasal from +// Thorsten Renk +// +// Copyright (C) 2010 Curtis Olson +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +#ifdef HAVE_CONFIG_H +# include +#endif + +#include
+#include +#include +#include + +#include "terrainsampler.hxx" +using simgear::PropertyList; + +#include "tiedpropertylist.hxx" + +namespace Environment { +/** + * @brief Class for presampling the terrain roughness + */ +class AreaSampler : public SGSubsystem { +public: + AreaSampler( SGPropertyNode_ptr rootNode ); + virtual ~AreaSampler(); + void update( double dt ); + void bind(); + void unbind(); + void init(); + void reinit(); + + int getElevationHistogramStep() const { return _elevationHistogramStep; } + void setElevationHistograpStep( int value ) { + _elevationHistogramStep = value > 0 ? value : 500; + _elevationHistogramCount = _elevationHistogramMax / _elevationHistogramStep; + } + + int getElevationHistogramMax() const { return _elevationHistogramMax; } + void setElevationHistograpMax( int value ) { + _elevationHistogramMax = value > 0 ? value : 10000; + _elevationHistogramCount = _elevationHistogramMax / _elevationHistogramStep; + } + + int getElevationHistogramCount() const { return _elevationHistogramCount; } + +private: + void analyse(); + + SGPropertyNode_ptr _rootNode; + + bool _enabled; + bool _useAircraftPosition; + double _heading_deg; + double _speed_kt; + int _radius; + double _max_computation_time_norm; + int _max_samples; // keep xx samples in queue for analysis + double _reuse_samples_norm; + double _recalc_distance_norm; + int _elevationHistogramMax; + int _elevationHistogramStep; + int _elevationHistogramCount; + SGGeod _inputPosition; + + double _altOffset; + double _altMedian; + double _altMin; + double _altLayered; + double _altMean; + SGGeod _outputPosition; + + SGPropertyNode_ptr _signalNode; + SGPropertyNode_ptr _positionLatitudeNode; + SGPropertyNode_ptr _positionLongitudeNode; + + deque _elevations; + TiedPropertyList _tiedProperties; +}; + +AreaSampler::AreaSampler( SGPropertyNode_ptr rootNode ) : + _rootNode(rootNode), + _enabled(true), + _useAircraftPosition(false), + _heading_deg(0.0), + _speed_kt(0.0), + _radius(40000.0), + _max_computation_time_norm(0.1), + _max_samples(1000), + _reuse_samples_norm(0.8), + _recalc_distance_norm(0.1), + _elevationHistogramMax(10000), + _elevationHistogramStep(500), + _elevationHistogramCount(_elevationHistogramMax/_elevationHistogramStep), + _altOffset(0), + _altMedian(0), + _altMin(0), + _altLayered(0), + _altMean(0), + _signalNode(rootNode->getNode("output/valid", true )), + _positionLatitudeNode(fgGetNode( "/position/latitude-deg", true )), + _positionLongitudeNode(fgGetNode( "/position/longitude-deg", true )) +{ + _inputPosition.setElevationM( SG_MAX_ELEVATION_M ); +} + +AreaSampler::~AreaSampler() +{ +} + + +void AreaSampler::bind() +{ + _tiedProperties.setRoot( _rootNode ); + _tiedProperties.Tie( "enabled", &_enabled ); + + _tiedProperties.setRoot( _rootNode->getNode( "input", true ) ); + _tiedProperties.Tie( "use-aircraft-position", &_useAircraftPosition ); + _tiedProperties.Tie( "latitude-deg", &_inputPosition, &SGGeod::getLatitudeDeg, &SGGeod::setLatitudeDeg ); + _tiedProperties.Tie( "longitude-deg", &_inputPosition, &SGGeod::getLongitudeDeg, &SGGeod::setLongitudeDeg ); + _tiedProperties.Tie( "heading-deg", &_heading_deg ); + _tiedProperties.Tie( "speed-kt", &_speed_kt ); + _tiedProperties.Tie( "radius-m", &_radius ); + _tiedProperties.Tie( "max-computation-time-norm", &_max_computation_time_norm ); + _tiedProperties.Tie( "max-samples", &_max_samples ); + _tiedProperties.Tie( "reuse-samples-norm", &_reuse_samples_norm ); + _tiedProperties.Tie( "recalc-distance-norm", &_recalc_distance_norm ); + _tiedProperties.Tie( "elevation-histogram-max-ft", this, &AreaSampler::getElevationHistogramMax, &AreaSampler::setElevationHistograpMax ); + _tiedProperties.Tie( "elevation-histogram-step-ft", this, &AreaSampler::getElevationHistogramStep, &AreaSampler::setElevationHistograpStep ); + _tiedProperties.Tie( "elevation-histogram-count", this, &AreaSampler::getElevationHistogramCount ); + + _tiedProperties.setRoot( _rootNode->getNode( "output", true ) ); + _tiedProperties.Tie( "alt-offset-ft", &_altOffset ); + _tiedProperties.Tie( "alt-median-ft", &_altMedian ); + _tiedProperties.Tie( "alt-min-ft", &_altMin ); + _tiedProperties.Tie( "alt-layered-ft", &_altLayered ); + _tiedProperties.Tie( "alt-mean-ft", &_altMean ); + _tiedProperties.Tie( "longitude-deg", &_outputPosition, &SGGeod::getLongitudeDeg ); + _tiedProperties.Tie( "latitude-deg", &_outputPosition, &SGGeod::getLatitudeDeg ); + +} + +void AreaSampler::unbind() +{ + _tiedProperties.Untie(); +} + +void AreaSampler::init() +{ + _signalNode->setBoolValue(false); + _elevations.clear(); + _altOffset = 0.0; + _altMedian = 0.0; + _altMin = 0.0; + _altLayered = 0.0; + _altMean = 0.0; +} + +void AreaSampler::reinit() +{ + init(); +} + +void AreaSampler::update( double dt ) +{ + // if not enabled or time has stalled, do nothing + if( !(_enabled && dt > SGLimitsd::min()) ) + return; + + // get the aircraft's position if requested + if( _useAircraftPosition && _speed_kt < 0.5 ) { + _inputPosition = SGGeod::fromDegM( + _positionLongitudeNode->getDoubleValue(), + _positionLatitudeNode->getDoubleValue(), + SG_MAX_ELEVATION_M ); + } + + // need geocentric coordinates + SGGeoc center = SGGeoc::fromGeod( _inputPosition ); + + // if a speed is set, move the input position + if( _speed_kt >= 0.5 ) { + double distance_m = _speed_kt * dt * SG_NM_TO_METER; + center = center.advanceRadM( _heading_deg * SG_DEGREES_TO_RADIANS, distance_m ); + _inputPosition = SGGeod::fromGeoc( center ); + } + + if( _signalNode->getBoolValue() ) { + // if we had finished the iteration and moved more than 10% of the radius + // of the sampling area, drop the oldest samples and continue sampling + if( SGGeoc::distanceM( center, SGGeoc::fromGeod(_outputPosition ) ) >= _recalc_distance_norm * _radius ) { + _elevations.resize( _max_samples * _reuse_samples_norm ); + _signalNode->setBoolValue( false ); + } + } + + if( _signalNode->getBoolValue() ) + return; // nothing to do. + + FGScenery * scenery = globals->get_scenery(); + + SGTimeStamp start = SGTimeStamp::now(); + while( (SGTimeStamp::now() - start).toSecs() < dt * _max_computation_time_norm ) { + // sample until we used up all our configured time + double distance = sg_random(); + distance = _radius * (1-distance*distance); + double course = sg_random() * 2.0 * SG_PI; + SGGeod probe = SGGeod::fromGeoc(center.advanceRadM( course, distance )); + double elevation_m = 0.0; + + if (scenery->get_elevation_m( probe, elevation_m, NULL )) + _elevations.push_front(elevation_m *= SG_METER_TO_FEET); + + if( _elevations.size() >= (deque::size_type)_max_samples ) { + // sampling complete? + analyse(); + _outputPosition = _inputPosition; + _signalNode->setBoolValue( true ); + break; + } + } +} + +void AreaSampler::analyse() +{ + double sum; + + vector histogram(_elevationHistogramCount,0); + + for( deque::size_type i = 0; i < _elevations.size(); i++ ) { + int idx = SGMisc::clip( (int)(_elevations[i]/_elevationHistogramStep), 0, histogram.size()-1 ); + histogram[idx]++; + } + + _altMedian = 0.0; + sum = 0.0; + for( vector::size_type i = 0; i < histogram.size(); i++ ) { + sum += histogram[i]; + if( sum > 0.5 * _elevations.size() ) { + _altMedian = i * _elevationHistogramStep; + break; + } + } + + _altOffset = 0.0; + sum = 0.0; + for( vector::size_type i = 0; i < histogram.size(); i++ ) { + sum += histogram[i]; + if( sum > 0.3 * _elevations.size() ) { + _altOffset = i * _elevationHistogramStep; + break; + } + } + + _altMean = 0.0; + for( vector::size_type i = 0; i < histogram.size(); i++ ) { + _altMean += histogram[i] * i; + } + _altMean *= _elevationHistogramStep; + if( _elevations.size() != 0.0 ) _altMean /= _elevations.size(); + + _altMin = 0.0; + for( vector::size_type i = 0; i < histogram.size(); i++ ) { + if( histogram[i] > 0 ) { + _altMin = i * _elevationHistogramStep; + break; + } + } + + double alt_low_min = 0.0; + double n_max = 0.0; + sum = 0.0; + for( vector::size_type i = 0; i < histogram.size()-1; i++ ) { + sum += histogram[i]; + if( histogram[i] > n_max ) n_max = histogram[i]; + if( n_max > histogram[i+1] && sum > 0.3*_elevations.size()) { + alt_low_min = i * _elevationHistogramStep; + break; + } + } + + _altLayered = 0.5 * (_altMin + _altOffset); + +#if 0 +append(alt_50_array, alt_med); +#endif +} + +/* --------------------- End of AreaSampler implementation ------------- */ + +/* --------------------- TerrainSamplerImplementation -------------------------- */ + +class TerrainSamplerImplementation : public TerrainSampler +{ +public: + TerrainSamplerImplementation ( SGPropertyNode_ptr rootNode ); + virtual ~TerrainSamplerImplementation (); + + virtual void init (); + virtual void postinit(); + virtual void reinit (); + virtual void bind(); + virtual void unbind(); + virtual void update (double delta_time_sec); +private: + inline string areaSubsystemName( unsigned i ) { + ostringstream name; + name << "area" << i; + return name.str(); + } + + SGPropertyNode_ptr _rootNode; + bool _enabled; + TiedPropertyList _tiedProperties; +}; + +TerrainSamplerImplementation::TerrainSamplerImplementation( SGPropertyNode_ptr rootNode ) : + _rootNode( rootNode ), + _enabled(true) +{ +} + +TerrainSamplerImplementation::~TerrainSamplerImplementation() +{ +} + +void TerrainSamplerImplementation::init() +{ + PropertyList areaNodes = _rootNode->getChildren( "area" ); + + for( PropertyList::size_type i = 0; i < areaNodes.size(); i++ ) + set_subsystem( areaSubsystemName(i), new AreaSampler( areaNodes[i] ) ); + + SGSubsystemGroup::init(); +} + +void TerrainSamplerImplementation::postinit() +{ + SGSubsystemGroup::bind();// +} + +void TerrainSamplerImplementation::reinit() +{ + for( unsigned i = 0;; i++ ) { + string subsystemName = areaSubsystemName(i); + SGSubsystem * subsys = get_subsystem( subsystemName ); + if( subsys == NULL ) + break; + remove_subsystem( subsystemName ); + } + + init(); +} + +void TerrainSamplerImplementation::bind() +{ + SGSubsystemGroup::bind(); + _tiedProperties.Tie( _rootNode->getNode("enabled",true), &_enabled ); +} + +void TerrainSamplerImplementation::unbind() +{ + _tiedProperties.Untie(); + SGSubsystemGroup::unbind(); +} + +void TerrainSamplerImplementation::update( double dt ) +{ + if( !(_enabled && dt > SGLimitsd::min()) ) + return; + SGSubsystemGroup::update(dt); +} + +/* ----------------------------------------------------------------------- */ + +/* implementation of the TerrainSampler factory to hide the implementation + details */ +TerrainSampler * TerrainSampler::createInstance( SGPropertyNode_ptr rootNode ) +{ + return new TerrainSamplerImplementation( rootNode ); +} + +} // namespace + diff --git a/src/Environment/terrainsampler.hxx b/src/Environment/terrainsampler.hxx new file mode 100644 index 000000000..e9fa3c319 --- /dev/null +++ b/src/Environment/terrainsampler.hxx @@ -0,0 +1,36 @@ +// terrainsampler.hxx -- +// +// Written by Torsten Dreyer, started July 2010 +// Based on local weather implementation in nasal from +// Thorsten Renk +// +// Copyright (C) 2010 Curtis Olson +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +#ifndef _TERRAIN_SAMPLER_HXX +#define _TERRAIN_SAMPLER_HXX + +#include + +namespace Environment { +class TerrainSampler : public SGSubsystemGroup +{ +public: + static TerrainSampler * createInstance( SGPropertyNode_ptr rootNode ); +}; + +} // namespace +#endif diff --git a/src/Environment/tiedpropertylist.hxx b/src/Environment/tiedpropertylist.hxx new file mode 100644 index 000000000..dbb9cc45a --- /dev/null +++ b/src/Environment/tiedpropertylist.hxx @@ -0,0 +1,80 @@ +#ifndef __TIEDPROPERTYLIST_HXX +#define __TIEDPROPERTYLIST_HXX +#include +using simgear::PropertyList; + +// Maybe this goes into SimGear's props.hxx later? +class TiedPropertyList : PropertyList { +public: + TiedPropertyList() {} + TiedPropertyList( SGPropertyNode_ptr root ) { _root = root; } + + void setRoot( SGPropertyNode_ptr root ) { _root = root; } + SGPropertyNode_ptr getRoot() const { return _root; } + + template SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, const SGRawValue &rawValue, bool useDefault = true ) { + bool success = node->tie( rawValue, useDefault ); + if( success ) { + SG_LOG( SG_ALL, SG_INFO, "Tied " << node->getPath() ); + push_back( node ); + } else { +#if PROPS_STANDALONE + cerr << "Failed to tie property " << node->getPath() << endl; +#else + SG_LOG(SG_GENERAL, SG_WARN, "Failed to tie property " << node->getPath() ); +#endif + } + return node; + } + + template SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, V * value, bool useDefault = true ) { + return Tie( node, SGRawValuePointer(value), useDefault ); + } + + template SGPropertyNode_ptr Tie( const char * relative_path, V * value, bool useDefault = true ) { + return Tie( _root->getNode(relative_path,true), SGRawValuePointer(value), useDefault ); + } + + template SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true ) { + return Tie(node, SGRawValueFunctions(getter, setter), useDefault ); + } + + template SGPropertyNode_ptr Tie( const char * relative_path, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true ) { + return Tie(_root->getNode(relative_path, true), SGRawValueFunctions(getter, setter), useDefault ); + } + + template SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, int index, V (*getter)(int), void (*setter)(int, V) = 0, bool useDefault = true) { + return Tie( node, SGRawValueFunctionsIndexed(index, getter, setter), useDefault ); + } + + template SGPropertyNode_ptr Tie( const char * relative_path, int index, V (*getter)(int), void (*setter)(int, V) = 0, bool useDefault = true) { + return Tie( _root->getNode( relative_path, true ), SGRawValueFunctionsIndexed(index, getter, setter), useDefault ); + } + + template SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, T * obj, V (T::*getter)() const, void (T::*setter)(V) = 0, bool useDefault = true) { + return Tie( node, SGRawValueMethods(*obj, getter, setter), useDefault ); + } + + template SGPropertyNode_ptr Tie( const char * relative_path, T * obj, V (T::*getter)() const, void (T::*setter)(V) = 0, bool useDefault = true) { + return Tie( _root->getNode( relative_path, true), SGRawValueMethods(*obj, getter, setter), useDefault ); + } + + template SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, T * obj, int index, V (T::*getter)(int) const, void (T::*setter)(int, V) = 0, bool useDefault = true) { + return Tie( node, SGRawValueMethodsIndexed(*obj, index, getter, setter), useDefault); + } + + template SGPropertyNode_ptr Tie( const char * relative_path, T * obj, int index, V (T::*getter)(int) const, void (T::*setter)(int, V) = 0, bool useDefault = true) { + return Tie( _root->getNode( relative_path, true ), SGRawValueMethodsIndexed(*obj, index, getter, setter), useDefault); + } + + void Untie() { + while( size() > 0 ) { + SG_LOG( SG_ALL, SG_INFO, "untie of " << back()->getPath() ); + back()->untie(); + pop_back(); + } + } +private: + SGPropertyNode_ptr _root; +}; +#endif diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index d3da8e828..018e943c4 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -1102,7 +1102,8 @@ FGPositioned* DCLGPS::FindTypedFirstById(const string& id, FGPositioned::Type ty if (exact) { FGPositioned::List matches = - FGPositioned::findAllWithIdentSortedByRange(id, SGGeod::fromRad(_lon, _lat), &filter); + FGPositioned::findAllWithIdent(id, &filter); + FGPositioned::sortByRange(matches, SGGeod::fromRad(_lon, _lat)); multi = (matches.size() > 1); return matches.empty() ? NULL : matches.front().ptr(); } diff --git a/src/Instrumentation/gps.cxx b/src/Instrumentation/gps.cxx index 06647d4ad..71e3becbd 100644 --- a/src/Instrumentation/gps.cxx +++ b/src/Instrumentation/gps.cxx @@ -220,7 +220,6 @@ GPS::GPS ( SGPropertyNode *node) : _mode("init"), _name(node->getStringValue("name", "gps")), _num(node->getIntValue("number", 0)), - _searchResultsCached(false), _computeTurnData(false), _anticipateTurn(false), _inTurn(false) @@ -333,7 +332,7 @@ GPS::bind() tie(_gpsNode, "desired-course-deg", SGRawValueMethods (*this, &GPS::getDesiredCourse, NULL)); - _desiredCourseNode = _gpsNode->getChild("desired-course-deg"); + _desiredCourseNode = _gpsNode->getChild("desired-course-deg", 0, true); tieSGGeodReadOnly(_gpsNode, _indicated_pos, "indicated-longitude-deg", "indicated-latitude-deg", "indicated-altitude-ft"); @@ -1384,9 +1383,6 @@ void GPS::setScratchFromRouteWaypoint(int aIndex) _scratchValid = true; _scratchNode->setDoubleValue("course", wp.get_track()); _scratchNode->setIntValue("index", aIndex); - - int lastResult = _routeMgr->size() - 1; - _searchHasNext = (_searchResultIndex < lastResult); } void GPS::loadNearest() @@ -1411,17 +1407,14 @@ void GPS::loadNearest() _searchResults = FGPositioned::findClosestN(searchPos, limitCount, cutoffDistance, f.get()); - _searchResultsCached = true; _searchResultIndex = 0; _searchIsRoute = false; - _searchHasNext = false; if (_searchResults.empty()) { SG_LOG(SG_INSTR, SG_INFO, "GPS:loadNearest: no matches at all"); return; } - _searchHasNext = (_searchResults.size() > 1); setScratchFromCachedSearchResult(); } @@ -1478,66 +1471,47 @@ void GPS::search() } _searchExact = _scratchNode->getBoolValue("exact", true); - _searchOrderByRange = _scratchNode->getBoolValue("order-by-distance", true); _searchResultIndex = 0; _searchIsRoute = false; - _searchHasNext = false; - - if (_searchExact && _searchOrderByRange) { - // immediate mode search, get all the results now and cache them - auto_ptr f(createFilter(_searchType)); - if (_searchNames) { - _searchResults = FGPositioned::findAllWithNameSortedByRange(_searchQuery, _indicated_pos, f.get()); - } else { - _searchResults = FGPositioned::findAllWithIdentSortedByRange(_searchQuery, _indicated_pos, f.get()); - } - - _searchResultsCached = true; - - if (_searchResults.empty()) { - clearScratch(); - return; - } - - _searchHasNext = (_searchResults.size() > 1); - setScratchFromCachedSearchResult(); - } else { - // iterative search, look up result zero - _searchResultsCached = false; - performSearch(); - } -} -void GPS::performSearch() -{ auto_ptr f(createFilter(_searchType)); - clearScratch(); - - FGPositionedRef r; if (_searchNames) { - if (_searchOrderByRange) { - r = FGPositioned::findClosestWithPartialName(_indicated_pos, _searchQuery, f.get(), _searchResultIndex, _searchHasNext); - } else { - r = FGPositioned::findWithPartialName(_searchQuery, f.get(), _searchResultIndex, _searchHasNext); - } + _searchResults = FGPositioned::findAllWithName(_searchQuery, f.get()); } else { - if (_searchOrderByRange) { - r = FGPositioned::findClosestWithPartialId(_indicated_pos, _searchQuery, f.get(), _searchResultIndex, _searchHasNext); - } else { - r = FGPositioned::findWithPartialId(_searchQuery, f.get(), _searchResultIndex, _searchHasNext); - } + _searchResults = FGPositioned::findAllWithIdent(_searchQuery, f.get()); } - if (!r) { + bool orderByRange = _scratchNode->getBoolValue("order-by-distance", true); + if (orderByRange) { + FGPositioned::sortByRange(_searchResults, _indicated_pos); + } + + if (_searchResults.empty()) { + clearScratch(); return; } - setScratchFromPositioned(r.get(), _searchResultIndex); + setScratchFromCachedSearchResult(); +} + +bool GPS::getScratchHasNext() const +{ + int lastResult; + if (_searchIsRoute) { + lastResult = _routeMgr->size() - 1; + } else { + lastResult = (int) _searchResults.size() - 1; + } + + if (lastResult < 0) { // search array might be empty + return false; + } + + return (_searchResultIndex < lastResult); } void GPS::setScratchFromCachedSearchResult() { - assert(_searchResultsCached); int index = _searchResultIndex; if ((index < 0) || (index >= (int) _searchResults.size())) { @@ -1546,9 +1520,6 @@ void GPS::setScratchFromCachedSearchResult() } setScratchFromPositioned(_searchResults[index], index); - - int lastResult = (int) _searchResults.size() - 1; - _searchHasNext = (_searchResultIndex < lastResult); } void GPS::setScratchFromPositioned(FGPositioned* aPos, int aIndex) @@ -1566,9 +1537,7 @@ void GPS::setScratchFromPositioned(FGPositioned* aPos, int aIndex) } _scratchValid = true; - if (_searchResultsCached) { - _scratchNode->setIntValue("result-count", _searchResults.size()); - } + _scratchNode->setIntValue("result-count", _searchResults.size()); switch (aPos->type()) { case FGPositioned::VOR: @@ -1652,20 +1621,17 @@ void GPS::selectLegMode() void GPS::nextResult() { - if (!_searchHasNext) { + if (!getScratchHasNext()) { return; } clearScratch(); if (_searchIsRoute) { setScratchFromRouteWaypoint(++_searchResultIndex); - } else if (_searchResultsCached) { - ++_searchResultIndex; - setScratchFromCachedSearchResult(); } else { ++_searchResultIndex; - performSearch(); - } // of iterative search case + setScratchFromCachedSearchResult(); + } } void GPS::previousResult() @@ -1679,10 +1645,8 @@ void GPS::previousResult() if (_searchIsRoute) { setScratchFromRouteWaypoint(_searchResultIndex); - } else if (_searchResultsCached) { - setScratchFromCachedSearchResult(); } else { - performSearch(); + setScratchFromCachedSearchResult(); } } @@ -1701,14 +1665,15 @@ void GPS::defineWaypoint() // check for duplicate idents FGPositioned::TypeFilter f(FGPositioned::WAYPOINT); - FGPositioned::List dups = FGPositioned::findAllWithIdentSortedByRange(ident, _indicated_pos, &f); + FGPositioned::List dups = FGPositioned::findAllWithIdent(ident, &f); if (!dups.empty()) { SG_LOG(SG_INSTR, SG_WARN, "GPS:defineWaypoint: non-unique waypoint identifier, ho-hum"); } SG_LOG(SG_INSTR, SG_INFO, "GPS:defineWaypoint: creating waypoint:" << ident); FGPositionedRef wpt = FGPositioned::createUserWaypoint(ident, _scratchPos); - _searchResultsCached = false; + _searchResults.clear(); + _searchResults.push_back(wpt); setScratchFromPositioned(wpt.get(), -1); } diff --git a/src/Instrumentation/gps.hxx b/src/Instrumentation/gps.hxx index cbdca3bc4..d6c3a7069 100644 --- a/src/Instrumentation/gps.hxx +++ b/src/Instrumentation/gps.hxx @@ -264,7 +264,7 @@ private: double getScratchDistance() const; double getScratchMagBearing() const; double getScratchTrueBearing() const; - bool getScratchHasNext() const { return _searchHasNext; } + bool getScratchHasNext() const; double getSelectedCourse() const { return _selectedCourse; } void setSelectedCourse(double crs); @@ -394,8 +394,6 @@ private: std::string _searchQuery; FGPositioned::Type _searchType; bool _searchExact; - bool _searchOrderByRange; - bool _searchResultsCached; FGPositioned::List _searchResults; bool _searchIsRoute; ///< set if 'search' is actually the current route bool _searchHasNext; ///< is there a result after this one? diff --git a/src/Instrumentation/instrument_mgr.cxx b/src/Instrumentation/instrument_mgr.cxx index b85f191ae..2e3f21e3f 100644 --- a/src/Instrumentation/instrument_mgr.cxx +++ b/src/Instrumentation/instrument_mgr.cxx @@ -92,6 +92,7 @@ void FGInstrumentMgr::init() SGPropertyNode_ptr nd(new SGPropertyNode); nd->setStringValue("name", "gps"); nd->setIntValue("number", 0); + _instruments.push_back("gps[0]"); set_subsystem("gps[0]", new GPS(nd)); } diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index c277b6b73..ddeab463b 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -1349,6 +1349,10 @@ do_load_xml_to_proptree(const SGPropertyNode * arg) if (file.extension() != "xml") file.concat(".xml"); + if (file.isRelative()) { + file = globals->resolve_maybe_aircraft_path(file.str()); + } + if (!fgValidatePath(file.c_str(), false)) { SG_LOG(SG_IO, SG_ALERT, "loadxml: reading '" << file.str() << "' denied " "(unauthorized access)"); diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 2db7f32e2..7d1b82fd8 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -109,7 +109,6 @@ #include #include -#include #include "fg_init.hxx" #include "fg_io.hxx" @@ -1259,8 +1258,8 @@ bool fgInitGeneral() { curr->setStringValue(cwd ? cwd : ""); curr->setAttribute(SGPropertyNode::WRITE, false); - fgSetBool("/sim/startup/stdout-to-terminal", isatty(1)); - fgSetBool("/sim/startup/stderr-to-terminal", isatty(2)); + fgSetBool("/sim/startup/stdout-to-terminal", isatty(1) != 0 ); + fgSetBool("/sim/startup/stderr-to-terminal", isatty(2) != 0 ); return true; } @@ -1349,13 +1348,6 @@ bool fgInitSubsystems() { // Initialize the weather modeling subsystem globals->add_subsystem("environment", new FGEnvironmentMgr); - //////////////////////////////////////////////////////////////////// - // Initialize the ridge lift simulation. - //////////////////////////////////////////////////////////////////// - - // Initialize the ridgelift subsystem - globals->add_subsystem("ridgelift", new FGRidgeLift); - //////////////////////////////////////////////////////////////////// // Initialize the aircraft systems and instrumentation (before the // autopilot.) @@ -1368,7 +1360,7 @@ bool fgInitSubsystems() { // Initialize the XML Autopilot subsystem. //////////////////////////////////////////////////////////////////// - globals->add_subsystem( "xml-autopilot", new FGXMLAutopilotGroup, SGSubsystemMgr::FDM ); + globals->add_subsystem( "xml-autopilot", FGXMLAutopilotGroup::createInstance(), SGSubsystemMgr::FDM ); globals->add_subsystem( "route-manager", new FGRouteMgr ); //////////////////////////////////////////////////////////////////// diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index 35bc8f02d..bfa51f72f 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -105,6 +105,7 @@ FGGlobals::FGGlobals() : airwaynet( NULL ), multiplayer_mgr( NULL ) { + } @@ -239,7 +240,15 @@ void FGGlobals::append_aircraft_path(const std::string& path) return; } + unsigned int index = fg_aircraft_dirs.size(); fg_aircraft_dirs.push_back(path); + +// make aircraft dirs available to Nasal + SGPropertyNode* sim = fgGetNode("/sim", true); + sim->removeChild("fg-aircraft", index, false); + SGPropertyNode* n = sim->getChild("fg-aircraft", index, true); + n->setStringValue(path); + n->setAttribute(SGPropertyNode::WRITE, false); } void FGGlobals::append_aircraft_paths(const std::string& path) diff --git a/src/Model/model_panel.cxx b/src/Model/model_panel.cxx index 8a2ec9b2f..a316243c1 100644 --- a/src/Model/model_panel.cxx +++ b/src/Model/model_panel.cxx @@ -30,7 +30,8 @@ using namespace simgear; osg::Node * fgLoad3DModelPanel(const std::string &path, SGPropertyNode *prop_root) { - osg::Node* node = SGModelLib::loadModel(path, prop_root); + bool loadPanels = true; + osg::Node* node = SGModelLib::loadModel(path, prop_root, NULL, loadPanels); if (node) node->setNodeMask(~SG_NODEMASK_TERRAIN_BIT); return node; diff --git a/src/Navaids/fixlist.cxx b/src/Navaids/fixlist.cxx index 835a2b1b5..50c06ac56 100644 --- a/src/Navaids/fixlist.cxx +++ b/src/Navaids/fixlist.cxx @@ -39,6 +39,7 @@ FGFix::FGFix(const std::string& aIdent, const SGGeod& aPos) : FGPositioned(FIX, aIdent, aPos) { + init(true); // init FGPositioned } // Constructor diff --git a/src/Navaids/markerbeacon.cxx b/src/Navaids/markerbeacon.cxx index 3a49e3280..651879961 100644 --- a/src/Navaids/markerbeacon.cxx +++ b/src/Navaids/markerbeacon.cxx @@ -65,4 +65,5 @@ FGMarkerBeaconRecord::FGMarkerBeaconRecord(Type aTy, FGRunway* aRunway, const SG FGPositioned(aTy, string(), aPos), _runway(aRunway) { + init(true); // init FGPositioned } diff --git a/src/Navaids/navrecord.cxx b/src/Navaids/navrecord.cxx index 041c12f1a..a22bebb69 100644 --- a/src/Navaids/navrecord.cxx +++ b/src/Navaids/navrecord.cxx @@ -82,6 +82,7 @@ FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent, } } + init(true); // init FGPositioned (now position is adjusted) } void FGNavRecord::initAirportRelation() diff --git a/src/Navaids/positioned.cxx b/src/Navaids/positioned.cxx index 48f284648..917156877 100644 --- a/src/Navaids/positioned.cxx +++ b/src/Navaids/positioned.cxx @@ -22,6 +22,8 @@ # include "config.h" #endif +#include "positioned.hxx" + #include #include #include // for sort @@ -35,7 +37,7 @@ #include #include -#include "positioned.hxx" + typedef std::multimap NamedPositionedIndex; typedef std::pair NamedIndexRange; @@ -355,13 +357,17 @@ addToIndices(FGPositioned* aPos) { assert(aPos); if (!aPos->ident().empty()) { + std::string u(boost::to_upper_copy(aPos->ident())); + global_identIndex.insert(global_identIndex.begin(), - std::make_pair(aPos->ident(), aPos)); + std::make_pair(u, aPos)); } if (!aPos->name().empty()) { + std::string u(boost::to_upper_copy(aPos->name())); + global_nameIndex.insert(global_nameIndex.begin(), - std::make_pair(aPos->name(), aPos)); + std::make_pair(u, aPos)); } if (!Octree::global_spatialOctree) { @@ -378,8 +384,9 @@ removeFromIndices(FGPositioned* aPos) assert(aPos); if (!aPos->ident().empty()) { - NamedPositionedIndex::iterator it = global_identIndex.find(aPos->ident()); - while (it != global_identIndex.end() && (it->first == aPos->ident())) { + std::string u(boost::to_upper_copy(aPos->ident())); + NamedPositionedIndex::iterator it = global_identIndex.find(u); + while (it != global_identIndex.end() && (it->first == u)) { if (it->second == aPos) { global_identIndex.erase(it); break; @@ -390,8 +397,9 @@ removeFromIndices(FGPositioned* aPos) } if (!aPos->name().empty()) { - NamedPositionedIndex::iterator it = global_nameIndex.find(aPos->name()); - while (it != global_nameIndex.end() && (it->first == aPos->name())) { + std::string u(boost::to_upper_copy(aPos->name())); + NamedPositionedIndex::iterator it = global_nameIndex.find(u); + while (it != global_nameIndex.end() && (it->first == u)) { if (it->second == aPos) { global_nameIndex.erase(it); break; @@ -402,91 +410,6 @@ removeFromIndices(FGPositioned* aPos) } } -class DistanceOrdering -{ -public: - DistanceOrdering(const SGGeod& aPos) : - mPos(SGVec3d::fromGeod(aPos)) - { } - - bool operator()(const FGPositionedRef& a, const FGPositionedRef& b) const - { - if (!a || !b) { - throw sg_exception("empty reference passed to DistanceOrdering"); - } - - double dA = distSqr(a->cart(), mPos), - dB = distSqr(b->cart(), mPos); - return dA < dB; - } - -private: - SGVec3d mPos; -}; - -static void -sortByDistance(const SGGeod& aPos, FGPositioned::List& aResult) -{ - std::sort(aResult.begin(), aResult.end(), DistanceOrdering(aPos)); -} - -static FGPositionedRef -namedFindClosest(const NamedPositionedIndex& aIndex, const std::string& aName, - const SGGeod& aOrigin, FGPositioned::Filter* aFilter) -{ - NamedIndexRange range = aIndex.equal_range(aName); - if (range.first == range.second) { - return NULL; - } - -// common case, only one result. looks a bit ugly because these are -// sequential iterators, not random-access ones - NamedPositionedIndex::const_iterator check = range.first; - if (++check == range.second) { - // excellent, only one match in the range - FGPositioned* r = range.first->second; - if (aFilter) { - if (aFilter->hasTypeRange() && !aFilter->passType(r->type())) { - return NULL; - } - - if (!aFilter->pass(r)) { - return NULL; - } - } // of have a filter - - return r; - } // of short-circuit logic for single-element range - -// multiple matches, we need to actually check the distance to each one - double minDist = HUGE_VAL; - FGPositionedRef result; - NamedPositionedIndex::const_iterator it = range.first; - SGVec3d cartOrigin(SGVec3d::fromGeod(aOrigin)); - - for (; it != range.second; ++it) { - FGPositioned* r = it->second; - if (aFilter) { - if (aFilter->hasTypeRange() && !aFilter->passType(r->type())) { - continue; - } - - if (!aFilter->pass(r)) { - continue; - } - } - - // find distance - double d2 = distSqr(cartOrigin, r->cart()); - if (d2 < minDist) { - minDist = d2; - result = r; - } - } - - return result; -} - ////////////////////////////////////////////////////////////////////////////// class OrderByName @@ -498,6 +421,27 @@ public: } }; +void findInIndex(NamedPositionedIndex& aIndex, const std::string& aFind, std::vector& aResult) +{ + NamedPositionedIndex::const_iterator it = aIndex.begin(); + NamedPositionedIndex::const_iterator end = aIndex.end(); + + bool haveFilter = !aFind.empty(); + + for (; it != end; ++it) { + FGPositioned::Type ty = it->second->type(); + if ((ty < FGPositioned::AIRPORT) || (ty > FGPositioned::SEAPORT)) { + continue; + } + + if (haveFilter && it->first.find(aFind) == std::string::npos) { + continue; + } + + aResult.push_back(it->second); + } // of index iteration +} + /** * A special purpose helper (imported by FGAirport::searchNamesAndIdents) to * implement the AirportList dialog. It's unfortunate that it needs to reside @@ -505,43 +449,23 @@ public: */ char** searchAirportNamesAndIdents(const std::string& aFilter) { - const std::ctype &ct = std::use_facet >(std::locale()); - std::string filter(aFilter); - bool hasFilter = !filter.empty(); - if (hasFilter) { - ct.toupper((char *)filter.data(), (char *)filter.data() + filter.size()); - } - - NamedPositionedIndex::const_iterator it = global_identIndex.begin(); - NamedPositionedIndex::const_iterator end = global_identIndex.end(); - - // note this is a vector of raw pointers, not smart pointers, because it - // may get very large and smart-pointer-atomicity-locking then becomes a - // bottleneck for this case. +// note this is a vector of raw pointers, not smart pointers, because it +// may get very large and smart-pointer-atomicity-locking then becomes a +// bottleneck for this case. std::vector matches; - std::string upper; - - for (; it != end; ++it) { - FGPositioned::Type ty = it->second->type(); - if ((ty < FGPositioned::AIRPORT) || (ty > FGPositioned::SEAPORT)) { - continue; - } + if (!aFilter.empty()) { + std::string filter = boost::to_upper_copy(aFilter); + findInIndex(global_identIndex, filter, matches); + findInIndex(global_nameIndex, filter, matches); + } else { - if (hasFilter && (it->second->ident().find(aFilter) == std::string::npos)) { - upper = it->second->name(); // string copy, sadly - ct.toupper((char *)upper.data(), (char *)upper.data() + upper.size()); - if (upper.find(aFilter) == std::string::npos) { - continue; - } - } - - matches.push_back(it->second); + findInIndex(global_identIndex, std::string(), matches); } - // sort alphabetically on name +// sort alphabetically on name std::sort(matches.begin(), matches.end(), OrderByName()); - // convert results to format comptible with puaList +// convert results to format comptible with puaList unsigned int numMatches = matches.size(); char** result = new char*[numMatches + 1]; result[numMatches] = NULL; // end-of-list marker @@ -592,14 +516,23 @@ FGPositioned::Filter::passType(Type aTy) const return (minType() <= aTy) && (maxType() >= aTy); } -static FGPositioned::List -findAllSortedByRange(const NamedPositionedIndex& aIndex, - const std::string& aName, const SGGeod& aPos, FGPositioned::Filter* aFilter) +static FGPositioned::List +findAll(const NamedPositionedIndex& aIndex, + const std::string& aName, FGPositioned::Filter* aFilter) { FGPositioned::List result; - NamedIndexRange range = aIndex.equal_range(aName); - for (; range.first != range.second; ++range.first) { - FGPositioned* candidate = range.first->second; + if (aName.empty()) { + return result; + } + + std::string name = boost::to_upper_copy(aName); + std::string upperBoundId = name; + upperBoundId[upperBoundId.size()-1]++; + NamedPositionedIndex::const_iterator upperBound = aIndex.lower_bound(upperBoundId); + NamedPositionedIndex::const_iterator it = aIndex.lower_bound(name); + + for (; it != upperBound; ++it) { + FGPositionedRef candidate = it->second; if (aFilter) { if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) { continue; @@ -610,70 +543,28 @@ findAllSortedByRange(const NamedPositionedIndex& aIndex, } } - result.push_back(range.first->second); + result.push_back(candidate); } - sortByDistance(aPos, result); return result; } -static FGPositionedRef -findWithPartial(const NamedPositionedIndex& aIndex, const std::string& aName, - FGPositioned::Filter* aFilter, int aOffset, bool& aNext) -{ - // see comment in findNextWithPartialId concerning upperBoundId - std::string upperBoundId = aName; - upperBoundId[upperBoundId.size()-1]++; - NamedPositionedIndex::const_iterator upperBound = aIndex.lower_bound(upperBoundId); - - NamedIndexRange range = aIndex.equal_range(aName); - FGPositionedRef result; - - while (range.first != upperBound) { - for (; range.first != range.second; ++range.first) { - FGPositionedRef candidate = range.first->second; - if (aFilter) { - if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) { - continue; - } - - if (!aFilter->pass(candidate)) { - continue; - } - } - - if (result) { - aNext = true; - return result; - } else if (aOffset == 0) { - // okay, found our result. we need to go around once more to set aNext - result = candidate; - } else { - --aOffset; // seen one more valid result, decrement the count - } - } - - // Unable to match the filter with this range - try the next range. - range = aIndex.equal_range(range.second->first); - } - - // if we fell out, we reached the end of the valid range. We might have a - // valid result, but we definitiely don't have a next result. - aNext = false; - return result; -} - /////////////////////////////////////////////////////////////////////////////// -FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos, bool aIndexed) : +FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos) : mPosition(aPos), mType(ty), mIdent(aIdent) { +} + +void FGPositioned::init(bool aIndexed) +{ SGReferenced::get(this); // hold an owning ref, for the moment + mCart = SGVec3d::fromGeod(mPosition); if (aIndexed) { - assert(ty != TAXIWAY && ty != PAVEMENT); + assert(mType != TAXIWAY && mType != PAVEMENT); addToIndices(this); } } @@ -687,13 +578,15 @@ FGPositioned::~FGPositioned() FGPositioned* FGPositioned::createUserWaypoint(const std::string& aIdent, const SGGeod& aPos) { - return new FGPositioned(WAYPOINT, aIdent, aPos, true); + FGPositioned* wpt = new FGPositioned(WAYPOINT, aIdent, aPos); + wpt->init(true); + return wpt; } -SGVec3d +const SGVec3d& FGPositioned::cart() const { - return SGVec3d::fromGeod(mPosition); + return mCart; } FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) @@ -770,7 +663,13 @@ const char* FGPositioned::nameForType(Type aTy) FGPositionedRef FGPositioned::findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter) { - return namedFindClosest(global_identIndex, aIdent, aPos, aFilter); + FGPositioned::List r(findAll(global_identIndex, aIdent, aFilter)); + if (r.empty()) { + return FGPositionedRef(); + } + + sortByRange(r, aPos); + return r.front(); } FGPositioned::List @@ -783,15 +682,15 @@ FGPositioned::findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilt } FGPositioned::List -FGPositioned::findAllWithIdentSortedByRange(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter) +FGPositioned::findAllWithIdent(const std::string& aIdent, Filter* aFilter) { - return findAllSortedByRange(global_identIndex, aIdent, aPos, aFilter); + return findAll(global_identIndex, aIdent, aFilter); } FGPositioned::List -FGPositioned::findAllWithNameSortedByRange(const std::string& aName, const SGGeod& aPos, Filter* aFilter) +FGPositioned::findAllWithName(const std::string& aName, Filter* aFilter) { - return findAllSortedByRange(global_nameIndex, aName, aPos, aFilter); + return findAll(global_nameIndex, aName, aFilter); } FGPositionedRef @@ -861,115 +760,24 @@ FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId return NULL; // Reached the end of the valid sequence with no match. } -FGPositionedRef -FGPositioned::findWithPartialId(const std::string& aId, Filter* aFilter, int aOffset, bool& aNext) +void +FGPositioned::sortByRange(List& aResult, const SGGeod& aPos) { - return findWithPartial(global_identIndex, aId, aFilter, aOffset, aNext); -} - - -FGPositionedRef -FGPositioned::findWithPartialName(const std::string& aName, Filter* aFilter, int aOffset, bool& aNext) -{ - return findWithPartial(global_nameIndex, aName, aFilter, aOffset, aNext); -} - -/** - * Wrapper filter which proxies to an inner filter, but also ensures the - * ident starts with supplied partial ident. - */ -class PartialIdentFilter : public FGPositioned::Filter -{ -public: - PartialIdentFilter(const std::string& ident, FGPositioned::Filter* filter) : - _inner(filter) - { - _ident = boost::to_upper_copy(ident); + SGVec3d cartPos(SGVec3d::fromGeod(aPos)); +// computer ordering values + Octree::FindNearestResults r; + List::iterator it = aResult.begin(), lend = aResult.end(); + for (; it != lend; ++it) { + double d2 = distSqr((*it)->cart(), cartPos); + r.push_back(Octree::OrderedPositioned(*it, d2)); } - virtual bool pass(FGPositioned* aPos) const - { - if (!_inner->pass(aPos)) { - return false; - } - - return (boost::algorithm::starts_with(aPos->ident(), _ident)); - } - - virtual FGPositioned::Type minType() const - { return _inner->minType(); } - - virtual FGPositioned::Type maxType() const - { return _inner->maxType(); } - -private: - std::string _ident; - FGPositioned::Filter* _inner; -}; - -static FGPositionedRef -findClosestWithPartial(const SGGeod& aPos, FGPositioned::Filter* aFilter, int aOffset, bool& aNext) -{ - // why aOffset +2 ? at offset=3, we want the fourth search result, but also - // to know if the fifth result exists (to set aNext flag for iterative APIs) - FGPositioned::List matches; - Octree::findNearestN(SGVec3d::fromGeod(aPos), aOffset + 2, 1000 * SG_NM_TO_METER, aFilter, matches); +// sort + std::sort(r.begin(), r.end()); - if ((int) matches.size() <= aOffset) { - SG_LOG(SG_GENERAL, SG_INFO, "findClosestWithPartial, couldn't match enough with prefix"); - aNext = false; - return NULL; // couldn't find a match within the cutoff distance +// convert to a plain list + unsigned int count = aResult.size(); + for (unsigned int i=0; i= (aOffset + 2)); - return matches[aOffset]; - } - -FGPositionedRef -FGPositioned::findClosestWithPartialId(const SGGeod& aPos, const std::string& aId, Filter* aFilter, int aOffset, bool& aNext) -{ - PartialIdentFilter pf(aId, aFilter); - return findClosestWithPartial(aPos, &pf, aOffset, aNext); -} - -/** - * Wrapper filter which proxies to an inner filter, but also ensures the - * name starts with supplied partial name. - */ -class PartialNameFilter : public FGPositioned::Filter -{ -public: - PartialNameFilter(const std::string& nm, FGPositioned::Filter* filter) : - _inner(filter) - { - _name = nm; - } - - virtual bool pass(FGPositioned* aPos) const - { - if (!_inner->pass(aPos)) { - return false; - } - - return (boost::algorithm::istarts_with(aPos->name(), _name)); - } - - virtual FGPositioned::Type minType() const - { return _inner->minType(); } - - virtual FGPositioned::Type maxType() const - { return _inner->maxType(); } - -private: - std::string _name; - FGPositioned::Filter* _inner; -}; - -FGPositionedRef -FGPositioned::findClosestWithPartialName(const SGGeod& aPos, const std::string& aName, Filter* aFilter, int aOffset, bool& aNext) -{ - PartialNameFilter pf(aName, aFilter); - return findClosestWithPartial(aPos, &pf, aOffset, aNext); -} - diff --git a/src/Navaids/positioned.hxx b/src/Navaids/positioned.hxx index d5f9b3672..27d807a72 100644 --- a/src/Navaids/positioned.hxx +++ b/src/Navaids/positioned.hxx @@ -84,9 +84,9 @@ public: { return mPosition; } /** - * Compute the cartesian position associated with this object + * The cartesian position associated with this object */ - SGVec3d cart() const; + const SGVec3d& cart() const; double latitude() const { return mPosition.getLatitudeDeg(); } @@ -157,27 +157,20 @@ public: static FGPositionedRef findNextWithPartialId(FGPositionedRef aCur, const std::string& aId, Filter* aFilter = NULL); /** - * As above, but searches using an offset index - */ - static FGPositionedRef findWithPartialId(const std::string& aId, Filter* aFilter, int aOffset, bool& aNext); - - /** - * As above, but search names instead of idents - */ - static FGPositionedRef findWithPartialName(const std::string& aName, Filter* aFilter, int aOffset, bool& aNext); - - /** - * Find all items with the specified ident, and return then sorted by - * distance from a position - * + * Find all items with the specified ident * @param aFilter - optional filter on items */ - static List findAllWithIdentSortedByRange(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter = NULL); + static List findAllWithIdent(const std::string& aIdent, Filter* aFilter = NULL); /** * As above, but searches names instead of idents */ - static List findAllWithNameSortedByRange(const std::string& aName, const SGGeod& aPos, Filter* aFilter = NULL); + static List findAllWithName(const std::string& aName, Filter* aFilter = NULL); + + /** + * Sort an FGPositionedList by distance from a position + */ + static void sortByRange(List&, const SGGeod& aPos); /** * Find the closest item to a position, which pass the specified filter @@ -201,18 +194,6 @@ public: */ static List findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter = NULL); - /** - * Find the closest match based on partial id (with an offset to allow selecting the n-th closest). - * Cutoff distance is limited internally, to avoid making this very slow. - */ - static FGPositionedRef findClosestWithPartialId(const SGGeod& aPos, const std::string& aId, Filter* aFilter, int aOffset, bool& aNext); - - /** - * As above, but matches on name - */ - static FGPositionedRef findClosestWithPartialName(const SGGeod& aPos, const std::string& aName, Filter* aFilter, int aOffset, bool& aNext); - - /** * Map a candidate type string to a real type. Returns INVALID if the string * does not correspond to a defined type. @@ -227,12 +208,15 @@ public: static FGPositioned* createUserWaypoint(const std::string& aIdent, const SGGeod& aPos); protected: - FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos, bool aIndex = true); + FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos); + + void init(bool aIndexed); // can't be const right now, navrecord at least needs to fix up the position // after navaids are parsed SGGeod mPosition; + SGVec3d mCart; // once mPosition is const, this can be const too const Type mType; const std::string mIdent; }; diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 055ad879d..0a221fc6e 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -374,6 +374,19 @@ static naRef f_directory(naContext c, naRef me, int argc, naRef* args) return result; } +/** + * Given a data path, resolve it in FG_ROOT or an FG_AIRCRFT directory + */ +static naRef f_resolveDataPath(naContext c, naRef me, int argc, naRef* args) +{ + if(argc != 1 || !naIsString(args[0])) + naRuntimeError(c, "bad arguments to resolveDataPath()"); + + SGPath p = globals->resolve_maybe_aircraft_path(naStr_data(args[0])); + const char* pdata = p.c_str(); + return naStr_fromdata(naNewString(c), const_cast(pdata), strlen(pdata)); +} + // Parse XML file. // parsexml( [, [, [, [, ]]]]); // @@ -635,6 +648,7 @@ static struct { const char* name; naCFunction func; } funcs[] = { { "srand", f_srand }, { "abort", f_abort }, { "directory", f_directory }, + { "resolvepath", f_resolveDataPath }, { "parsexml", f_parsexml }, { "systime", f_systime }, { "carttogeod", f_carttogeod },