1
0
Fork 0

Merge branch 'next' of D:\Git_New\flightgear into next

Conflicts:
	src/AIModel/AIBallistic.cxx
This commit is contained in:
Vivian Meazza 2010-08-29 00:08:50 +01:00
commit 9e44be1df7
45 changed files with 797 additions and 556 deletions

View file

@ -174,7 +174,7 @@
<TypeLibraryName>.\Release/FlightGear.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\..\..\src;..\..\..\src\include;..\..\..\src\FDM\JSBSim;..\..\..\..\SimGear;..\..\..\..\install\msvc100\OpenSceneGraph\include;..\..\..\..\3rdParty\include;..\..\..\..\boost_1_43_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>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)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>

View file

@ -149,6 +149,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<AdditionalDependencies>sg.lib;net.lib;ul.lib;ws2_32.lib;winmm.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>

View file

@ -151,6 +151,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<AdditionalDependencies>sg.lib;net.lib;ul.lib;ws2_32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>

View file

@ -151,6 +151,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<AdditionalDependencies>sg.lib;net.lib;ul.lib;ws2_32.lib;winmm.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>

View file

@ -142,7 +142,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..\..\..\..\SimGear;..\..\..\..\install\msvc100\OpenSceneGraph\include;..\..\..\..\3rdParty\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;HAVE_ZLIB;NOMINMAX;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

View file

@ -151,6 +151,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<AdditionalDependencies>sg.lib;js.lib;ul.lib;zlib.lib;winmm.lib;ws2_32.lib;OpenThreads.lib;%(AdditionalDependencies)</AdditionalDependencies>

View file

@ -151,6 +151,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<AdditionalDependencies>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)</AdditionalDependencies>

View file

@ -148,6 +148,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<AdditionalDependencies>sg.lib;ul.lib;net.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

View file

@ -151,6 +151,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<AdditionalDependencies>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)</AdditionalDependencies>

View file

@ -142,6 +142,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -151,6 +151,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
<Link>
<AdditionalDependencies>sg.lib;ul.lib;OpenThreads.lib;%(AdditionalDependencies)</AdditionalDependencies>

View file

@ -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() {

View file

@ -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.

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -896,7 +896,7 @@ void FGSubmodelMgr::setParentNode(int id) {
if (!model)
continue;
}// end for loop
}// end for loop
if (_selected_ac != 0){

View file

@ -20,7 +20,7 @@
#include <Main/fg_props.hxx>
using std::vector;
using std::string;
using std::string;
using std::list;
class FGAIBase;

View file

@ -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)

View file

@ -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

View file

@ -63,6 +63,7 @@ FGAirport::FGAirport(const string &id, const SGGeod& location, const SGGeod& tow
mRunwaysLoaded(false),
mTaxiwaysLoaded(true)
{
init(true); // init FGPositioned
}

View file

@ -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 );
}

View file

@ -28,117 +28,35 @@
#include "autopilot.hxx"
#include "autopilotgroup.hxx"
#include <string>
#include <vector>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/structure/exception.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Main/util.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/structure/SGExpression.hxx>
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<string> _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();
}

View file

@ -24,11 +24,6 @@
#ifndef _XMLAUTO_HXX
#define _XMLAUTO_HXX 1
#include <string>
#include <vector>
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
/**
* @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<std::string> _autopilotNames;
static FGXMLAutopilotGroup * createInstance();
protected:
FGXMLAutopilotGroup() : SGSubsystemGroup() {}
};

View file

@ -26,6 +26,7 @@
#endif
#include <simgear/compiler.h>
#include <simgear/sg_inlines.h>
#include <stdlib.h>
#include <stdio.h>
@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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 <config.h>
#endif
#include <Main/fg_props.hxx>
#include <simgear/math/sg_random.h>
#include <Scenery/scenery.hxx>
#include <deque>
#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<double> _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<unsigned>::size_type)_max_samples ) {
// sampling complete?
analyse();
_outputPosition = _inputPosition;
_signalNode->setBoolValue( true );
break;
}
}
}
void AreaSampler::analyse()
{
double sum;
vector<int> histogram(_elevationHistogramCount,0);
for( deque<double>::size_type i = 0; i < _elevations.size(); i++ ) {
int idx = SGMisc<int>::clip( (int)(_elevations[i]/_elevationHistogramStep), 0, histogram.size()-1 );
histogram[idx]++;
}
_altMedian = 0.0;
sum = 0.0;
for( vector<int>::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<int>::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<int>::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<int>::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<int>::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

View file

@ -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 <simgear/structure/subsystem_mgr.hxx>
namespace Environment {
class TerrainSampler : public SGSubsystemGroup
{
public:
static TerrainSampler * createInstance( SGPropertyNode_ptr rootNode );
};
} // namespace
#endif

View file

@ -0,0 +1,80 @@
#ifndef __TIEDPROPERTYLIST_HXX
#define __TIEDPROPERTYLIST_HXX
#include <simgear/props/props.hxx>
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<typename T> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, const SGRawValue<T> &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 <class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, V * value, bool useDefault = true ) {
return Tie( node, SGRawValuePointer<V>(value), useDefault );
}
template <class V> SGPropertyNode_ptr Tie( const char * relative_path, V * value, bool useDefault = true ) {
return Tie( _root->getNode(relative_path,true), SGRawValuePointer<V>(value), useDefault );
}
template <class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true ) {
return Tie(node, SGRawValueFunctions<V>(getter, setter), useDefault );
}
template <class V> SGPropertyNode_ptr Tie( const char * relative_path, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true ) {
return Tie(_root->getNode(relative_path, true), SGRawValueFunctions<V>(getter, setter), useDefault );
}
template <class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, int index, V (*getter)(int), void (*setter)(int, V) = 0, bool useDefault = true) {
return Tie( node, SGRawValueFunctionsIndexed<V>(index, getter, setter), useDefault );
}
template <class V> 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<V>(index, getter, setter), useDefault );
}
template <class T, class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, T * obj, V (T::*getter)() const, void (T::*setter)(V) = 0, bool useDefault = true) {
return Tie( node, SGRawValueMethods<T,V>(*obj, getter, setter), useDefault );
}
template <class T, class V> 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<T,V>(*obj, getter, setter), useDefault );
}
template <class T, class V> 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<T,V>(*obj, index, getter, setter), useDefault);
}
template <class T, class V> 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<T,V>(*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

View file

@ -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();
}

View file

@ -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<GPS, double>
(*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<FGPositioned::Filter> 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<FGPositioned::Filter> 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);
}

View file

@ -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?

View file

@ -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));
}

View file

@ -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)");

View file

@ -109,7 +109,6 @@
#include <FDM/fdm_shell.hxx>
#include <Environment/environment_mgr.hxx>
#include <Environment/ridge_lift.hxx>
#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 );
////////////////////////////////////////////////////////////////////

View file

@ -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)

View file

@ -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;

View file

@ -39,6 +39,7 @@
FGFix::FGFix(const std::string& aIdent, const SGGeod& aPos) :
FGPositioned(FIX, aIdent, aPos)
{
init(true); // init FGPositioned
}
// Constructor

View file

@ -65,4 +65,5 @@ FGMarkerBeaconRecord::FGMarkerBeaconRecord(Type aTy, FGRunway* aRunway, const SG
FGPositioned(aTy, string(), aPos),
_runway(aRunway)
{
init(true); // init FGPositioned
}

View file

@ -82,6 +82,7 @@ FGNavRecord::FGNavRecord(Type aTy, const std::string& aIdent,
}
}
init(true); // init FGPositioned (now position is adjusted)
}
void FGNavRecord::initAirportRelation()

View file

@ -22,6 +22,8 @@
# include "config.h"
#endif
#include "positioned.hxx"
#include <map>
#include <set>
#include <algorithm> // for sort
@ -35,7 +37,7 @@
#include <simgear/structure/exception.hxx>
#include <simgear/math/SGGeometry.hxx>
#include "positioned.hxx"
typedef std::multimap<std::string, FGPositioned*> NamedPositionedIndex;
typedef std::pair<NamedPositionedIndex::const_iterator, NamedPositionedIndex::const_iterator> 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<FGPositioned*>& 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<char> &ct = std::use_facet<std::ctype<char> >(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<FGPositioned*> 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<count; ++i) {
aResult[i] = r[i].get();
}
aNext = ((int) matches.size() >= (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);
}

View file

@ -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;
};

View file

@ -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<char*>(pdata), strlen(pdata));
}
// Parse XML file.
// parsexml(<path> [, <start-tag> [, <end-tag> [, <data> [, <pi>]]]]);
//
@ -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 },