2001-07-02 22:14:09 +00:00
|
|
|
// fg_init.cxx -- Flight Gear top level initialization routines
|
1998-04-25 15:11:10 +00:00
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started August 1997.
|
|
|
|
//
|
2004-11-19 22:10:41 +00:00
|
|
|
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
|
1998-04-25 15:11:10 +00:00
|
|
|
//
|
|
|
|
// 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
|
2006-02-21 01:16:04 +00:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
1998-04-25 15:11:10 +00:00
|
|
|
//
|
|
|
|
// $Id$
|
1997-08-23 01:46:20 +00:00
|
|
|
|
|
|
|
|
1998-04-24 00:49:17 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
1998-04-22 13:25:39 +00:00
|
|
|
|
1997-08-23 01:46:20 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2002-10-04 13:20:53 +00:00
|
|
|
#include <string.h> // strcmp()
|
1998-07-22 21:40:43 +00:00
|
|
|
|
2001-03-22 04:02:11 +00:00
|
|
|
#if defined( unix ) || defined( __CYGWIN__ )
|
2002-10-04 13:20:53 +00:00
|
|
|
# include <unistd.h> // for gethostname()
|
2001-03-22 04:02:11 +00:00
|
|
|
#endif
|
2010-01-23 22:26:30 +00:00
|
|
|
#ifdef _WIN32
|
2007-06-16 21:35:16 +00:00
|
|
|
# include <direct.h> // for getcwd()
|
|
|
|
# define getcwd _getcwd
|
2008-10-01 15:03:53 +00:00
|
|
|
# include <io.h> // isatty()
|
|
|
|
# define isatty _isatty
|
2010-01-23 22:26:30 +00:00
|
|
|
# include "winsock2.h" // for gethostname()
|
2007-06-16 21:35:16 +00:00
|
|
|
#endif
|
2001-03-22 04:02:11 +00:00
|
|
|
|
1998-07-22 21:40:43 +00:00
|
|
|
// work around a stdc++ lib bug in some versions of linux, but doesn't
|
|
|
|
// seem to hurt to have this here for all versions of Linux.
|
|
|
|
#ifdef linux
|
|
|
|
# define _G_NO_EXTERN_TEMPLATES
|
|
|
|
#endif
|
|
|
|
|
2000-02-15 03:30:01 +00:00
|
|
|
#include <simgear/compiler.h>
|
1999-02-26 22:08:34 +00:00
|
|
|
|
2008-07-25 18:38:29 +00:00
|
|
|
#include <string>
|
2009-12-05 14:25:31 +00:00
|
|
|
#include <boost/algorithm/string/compare.hpp>
|
|
|
|
#include <boost/algorithm/string/predicate.hpp>
|
1997-08-23 01:46:20 +00:00
|
|
|
|
2000-02-15 03:30:01 +00:00
|
|
|
#include <simgear/constants.h>
|
2000-02-16 23:01:03 +00:00
|
|
|
#include <simgear/debug/logstream.hxx>
|
2003-09-24 17:20:55 +00:00
|
|
|
#include <simgear/structure/exception.hxx>
|
|
|
|
#include <simgear/structure/event_mgr.hxx>
|
2001-03-25 14:20:12 +00:00
|
|
|
#include <simgear/misc/sg_path.hxx>
|
2010-07-06 20:06:50 +00:00
|
|
|
#include <simgear/misc/sg_dir.hxx>
|
2003-12-05 01:52:34 +00:00
|
|
|
#include <simgear/misc/interpolator.hxx>
|
2003-05-12 21:34:29 +00:00
|
|
|
#include <simgear/scene/material/matlib.hxx>
|
2008-02-15 06:45:19 +00:00
|
|
|
#include <simgear/scene/model/particles.hxx>
|
2009-10-05 09:12:50 +00:00
|
|
|
#include <simgear/sound/soundmgr_openal.hxx>
|
2000-07-06 22:13:24 +00:00
|
|
|
#include <simgear/timing/sg_time.hxx>
|
2002-02-06 23:31:33 +00:00
|
|
|
#include <simgear/timing/lowleveltime.h>
|
2000-02-15 03:30:01 +00:00
|
|
|
|
2008-07-29 08:27:48 +00:00
|
|
|
#include <Aircraft/controls.hxx>
|
2005-11-01 13:41:49 +00:00
|
|
|
#include <Aircraft/replay.hxx>
|
2004-12-22 23:57:07 +00:00
|
|
|
#include <Airports/apt_loader.hxx>
|
2000-08-16 00:09:03 +00:00
|
|
|
#include <Airports/runways.hxx>
|
1998-08-25 16:59:08 +00:00
|
|
|
#include <Airports/simple.hxx>
|
2008-08-14 18:13:39 +00:00
|
|
|
#include <Airports/dynamics.hxx>
|
|
|
|
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
#include <AIModel/AIManager.hxx>
|
2009-12-30 14:11:16 +00:00
|
|
|
|
|
|
|
#if ENABLE_ATCDCL
|
|
|
|
# include <ATCDCL/ATCmgr.hxx>
|
|
|
|
# include <ATCDCL/AIMgr.hxx>
|
|
|
|
# include "ATCDCL/commlist.hxx"
|
2010-01-05 20:04:54 +00:00
|
|
|
#else
|
|
|
|
# include "ATC/atcutils.hxx"
|
2009-12-30 14:11:16 +00:00
|
|
|
#endif
|
|
|
|
|
2004-01-31 19:47:45 +00:00
|
|
|
#include <Autopilot/route_mgr.hxx>
|
2010-06-24 15:09:33 +00:00
|
|
|
#include <Autopilot/autopilotgroup.hxx>
|
2009-09-21 13:57:39 +00:00
|
|
|
|
1998-04-24 00:49:17 +00:00
|
|
|
#include <Cockpit/cockpit.hxx>
|
User-visible
- knobs now continue to rotate when you hold down the mouse
- the middle mouse button makes knobs rotate much faster
- there are NAV1, NAV2, and ADF radios that can be tuned using the mouse
- there are standby frequencies for NAV1 and NAV2, and buttons to swap
- there is a crude, rather silly-looking DME, hard-wired to NAV1
- there is a crude, rather silly-looking autopilot that can lock
the heading (to the bug on the gyro), can lock to NAV1, and can lock
the current altitude
- the knobs for changing the radials on NAV1 and NAV2 look much better
and are in the right place
- tuning into an ILS frequency doesn't change the displayed radial for
NAV1
Code
- I've created a new module, sp_panel.[ch]xx, that constructs the
default single-prop panel; this works entirely outside of FGPanel,
so it is possible to construct similar modules for other sorts of
panels; all code specific to the default panel has been removed from
panel.cxx
- current_panel is now a pointer
- radiostack.[ch]xx keeps track both of the actual radial and of the
selected radial (they will differ with ILS); the NAV gauges should
not spin around automatically to show the actual radial (we need to
do something similar with the autopilot)
- the panel is initialized fairly early
- make sure that standby frequencies also get initialized
- I've started combining and clipping small textures to save texture
memory; there's a lot more to do, but at least I've made a start
2000-05-02 18:26:00 +00:00
|
|
|
#include <Cockpit/panel.hxx>
|
2000-09-22 17:20:56 +00:00
|
|
|
#include <Cockpit/panel_io.hxx>
|
2009-12-30 14:11:16 +00:00
|
|
|
|
2002-11-07 16:27:47 +00:00
|
|
|
#include <GUI/new_gui.hxx>
|
1999-03-11 23:09:26 +00:00
|
|
|
#include <Include/general.hxx>
|
I'm attaching diffs to add a new FGInput module to FlightGear
(src/Input). So far, FGInput replaces most of src/Main/keyboard.cxx
(I've left a tiny stub); in the very near future, it will also take
over control of the joystick, mouse (Norm permitting), and panel
instrument interactions, so that there is a single mechanism for
configuring all input devices.
The new format should be (close to) self-explanatory by looking at the
new base-package file keyboard.xml, which is now included by
preferences.xml (I'll do the same thing for the joystick when I have a
chance). I have not managed to move all keybindings into this file
yet, but I've made a good start. I'm including Tony in the recipient
list so that he can see how bindings can use an external XML file.
This patch also adds support for multiple bindings for a single key,
special keys (i.e. keypad and function keys), and key modifiers
(shift/alt/ctrl); special keys use the PUI convention of adding 256 to
the Glut key code.
Unfortunately, everything comes with a price; in this case, I have not
yet found a general mechanism for the old (hard-coded) modal bindings,
which behaved differently depending on the autopilot state (i.e. left
rudder or move AP heading left); with my patches, this functionality
disappears, but you can still adjust the autopilot using the panel or
the GUI input dialogs.
2001-05-23 23:01:15 +00:00
|
|
|
#include <Input/input.hxx>
|
2002-09-24 14:51:37 +00:00
|
|
|
#include <Instrumentation/instrument_mgr.hxx>
|
2002-04-09 18:58:24 +00:00
|
|
|
#include <Model/acmodel.hxx>
|
2004-10-22 09:58:24 +00:00
|
|
|
#include <AIModel/submodel.hxx>
|
2003-11-28 15:48:05 +00:00
|
|
|
#include <AIModel/AIManager.hxx>
|
2004-05-28 05:24:54 +00:00
|
|
|
#include <Navaids/navdb.hxx>
|
2000-04-24 23:51:26 +00:00
|
|
|
#include <Navaids/navlist.hxx>
|
2008-09-10 08:54:49 +00:00
|
|
|
#include <Navaids/fix.hxx>
|
2008-12-25 23:11:43 +00:00
|
|
|
#include <Navaids/fixlist.hxx>
|
1998-04-30 12:34:17 +00:00
|
|
|
#include <Scenery/scenery.hxx>
|
1998-04-22 13:25:39 +00:00
|
|
|
#include <Scenery/tilemgr.hxx>
|
2003-11-25 21:08:36 +00:00
|
|
|
#include <Scripting/NasalSys.hxx>
|
2006-02-11 12:02:40 +00:00
|
|
|
#include <Sound/voice.hxx>
|
2002-09-23 19:55:10 +00:00
|
|
|
#include <Systems/system_mgr.hxx>
|
1998-04-22 13:25:39 +00:00
|
|
|
#include <Time/light.hxx>
|
2003-09-15 22:55:39 +00:00
|
|
|
#include <Time/sunsolver.hxx>
|
2000-07-05 02:39:30 +00:00
|
|
|
#include <Time/tmp.hxx>
|
2004-06-03 17:59:14 +00:00
|
|
|
#include <Traffic/TrafficMgr.hxx>
|
2005-11-01 13:41:49 +00:00
|
|
|
#include <MultiPlayer/multiplaymgr.hxx>
|
2010-06-16 07:31:59 +00:00
|
|
|
#include <FDM/fdm_shell.hxx>
|
2003-03-19 20:45:09 +00:00
|
|
|
|
2004-03-16 20:19:07 +00:00
|
|
|
#include <Environment/environment_mgr.hxx>
|
2009-04-20 14:20:05 +00:00
|
|
|
#include <Environment/ridge_lift.hxx>
|
1997-08-23 01:46:20 +00:00
|
|
|
|
1998-04-22 13:25:39 +00:00
|
|
|
#include "fg_init.hxx"
|
1999-11-19 02:10:24 +00:00
|
|
|
#include "fg_io.hxx"
|
2001-06-01 17:52:28 +00:00
|
|
|
#include "fg_commands.hxx"
|
2001-06-05 22:12:08 +00:00
|
|
|
#include "fg_props.hxx"
|
2001-01-13 22:06:39 +00:00
|
|
|
#include "options.hxx"
|
2000-07-08 06:29:19 +00:00
|
|
|
#include "globals.hxx"
|
2002-03-12 16:29:00 +00:00
|
|
|
#include "logger.hxx"
|
2008-07-09 12:22:33 +00:00
|
|
|
#include "renderer.hxx"
|
2001-07-22 19:51:16 +00:00
|
|
|
#include "viewmgr.hxx"
|
2005-12-21 13:36:04 +00:00
|
|
|
#include "main.hxx"
|
2009-12-30 14:11:16 +00:00
|
|
|
|
1998-04-22 13:25:39 +00:00
|
|
|
|
2008-07-27 16:25:13 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
# include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#endif
|
1998-06-27 16:54:32 +00:00
|
|
|
|
2008-07-27 16:25:13 +00:00
|
|
|
using std::string;
|
2009-12-05 14:25:31 +00:00
|
|
|
using namespace boost::algorithm;
|
2003-05-09 18:44:33 +00:00
|
|
|
|
1998-02-12 21:58:27 +00:00
|
|
|
extern const char *default_root;
|
2004-04-18 18:01:10 +00:00
|
|
|
|
1997-08-25 20:27:21 +00:00
|
|
|
|
2002-11-16 20:41:00 +00:00
|
|
|
// Scan the command line options for the specified option and return
|
|
|
|
// the value.
|
|
|
|
static string fgScanForOption( const string& option, int argc, char **argv ) {
|
2002-11-16 20:17:11 +00:00
|
|
|
int i = 1;
|
|
|
|
|
2005-12-27 14:02:38 +00:00
|
|
|
if (hostname == NULL)
|
|
|
|
{
|
|
|
|
char _hostname[256];
|
|
|
|
gethostname(_hostname, 256);
|
|
|
|
hostname = strdup(_hostname);
|
|
|
|
free_hostname = true;
|
|
|
|
}
|
|
|
|
|
2002-11-16 20:41:00 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Scanning command line for: " << option );
|
|
|
|
|
|
|
|
int len = option.length();
|
2002-11-16 20:17:11 +00:00
|
|
|
|
|
|
|
while ( i < argc ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_DEBUG, "argv[" << i << "] = " << argv[i] );
|
|
|
|
|
|
|
|
string arg = argv[i];
|
2002-11-16 20:41:00 +00:00
|
|
|
if ( arg.find( option ) == 0 ) {
|
|
|
|
return arg.substr( len );
|
2002-11-16 20:17:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-16 20:41:00 +00:00
|
|
|
// Scan the user config files for the specified option and return
|
|
|
|
// the value.
|
|
|
|
static string fgScanForOption( const string& option, const string& path ) {
|
2002-11-16 20:17:11 +00:00
|
|
|
sg_gzifstream in( path );
|
2002-11-16 20:41:00 +00:00
|
|
|
if ( !in.is_open() ) {
|
|
|
|
return "";
|
|
|
|
}
|
2002-11-16 20:17:11 +00:00
|
|
|
|
2002-11-16 20:41:00 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "Scanning " << path << " for: " << option );
|
|
|
|
|
|
|
|
int len = option.length();
|
2002-11-16 20:17:11 +00:00
|
|
|
|
|
|
|
in >> skipcomment;
|
|
|
|
while ( ! in.eof() ) {
|
|
|
|
string line;
|
|
|
|
getline( in, line, '\n' );
|
|
|
|
|
|
|
|
// catch extraneous (DOS) line ending character
|
|
|
|
if ( line[line.length() - 1] < 32 ) {
|
|
|
|
line = line.substr( 0, line.length()-1 );
|
|
|
|
}
|
|
|
|
|
2002-11-16 20:41:00 +00:00
|
|
|
if ( line.find( option ) == 0 ) {
|
|
|
|
return line.substr( len );
|
2002-11-16 20:17:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
in >> skipcomment;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2005-12-22 10:25:07 +00:00
|
|
|
// Scan the user config files for the specified option and return
|
|
|
|
// the value.
|
|
|
|
static string fgScanForOption( const string& option ) {
|
|
|
|
string arg("");
|
2001-01-13 22:06:39 +00:00
|
|
|
|
2001-03-22 04:02:11 +00:00
|
|
|
#if defined( unix ) || defined( __CYGWIN__ )
|
|
|
|
// Next check home directory for .fgfsrc.hostname file
|
2005-12-22 10:25:07 +00:00
|
|
|
if ( arg.empty() ) {
|
2005-12-21 13:36:04 +00:00
|
|
|
if ( homedir != NULL ) {
|
|
|
|
SGPath config( homedir );
|
2002-10-04 13:20:53 +00:00
|
|
|
config.append( ".fgfsrc" );
|
|
|
|
config.concat( "." );
|
2005-12-21 13:36:04 +00:00
|
|
|
config.concat( hostname );
|
2005-12-22 10:25:07 +00:00
|
|
|
arg = fgScanForOption( option, config.str() );
|
2002-10-04 13:20:53 +00:00
|
|
|
}
|
2001-03-22 04:02:11 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-01-13 22:06:39 +00:00
|
|
|
// Next check home directory for .fgfsrc file
|
2005-12-22 10:25:07 +00:00
|
|
|
if ( arg.empty() ) {
|
2005-12-21 13:36:04 +00:00
|
|
|
if ( homedir != NULL ) {
|
|
|
|
SGPath config( homedir );
|
2002-10-04 13:20:53 +00:00
|
|
|
config.append( ".fgfsrc" );
|
2005-12-22 10:25:07 +00:00
|
|
|
arg = fgScanForOption( option, config.str() );
|
2002-10-04 13:20:53 +00:00
|
|
|
}
|
2001-01-13 22:06:39 +00:00
|
|
|
}
|
2005-12-22 10:25:07 +00:00
|
|
|
|
|
|
|
if ( arg.empty() ) {
|
|
|
|
// Check for $fg_root/system.fgfsrc
|
|
|
|
SGPath config( globals->get_fg_root() );
|
|
|
|
config.append( "system.fgfsrc" );
|
|
|
|
arg = fgScanForOption( option, config.str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Read in configuration (files and command line options) but only set
|
|
|
|
// fg_root
|
|
|
|
bool fgInitFGRoot ( int argc, char **argv ) {
|
|
|
|
string root;
|
|
|
|
|
|
|
|
// First parse command line options looking for --fg-root=, this
|
|
|
|
// will override anything specified in a config file
|
|
|
|
root = fgScanForOption( "--fg-root=", argc, argv);
|
|
|
|
|
|
|
|
// Check in one of the user configuration files.
|
2005-12-22 14:14:08 +00:00
|
|
|
if (root.empty() )
|
|
|
|
root = fgScanForOption( "--fg-root=" );
|
2003-03-20 09:38:06 +00:00
|
|
|
|
2001-01-13 22:06:39 +00:00
|
|
|
// Next check if fg-root is set as an env variable
|
2002-03-20 19:16:13 +00:00
|
|
|
if ( root.empty() ) {
|
2005-12-21 13:36:04 +00:00
|
|
|
char *envp = ::getenv( "FG_ROOT" );
|
2002-10-04 13:20:53 +00:00
|
|
|
if ( envp != NULL ) {
|
|
|
|
root = envp;
|
|
|
|
}
|
2001-01-13 22:06:39 +00:00
|
|
|
}
|
2000-10-04 22:52:34 +00:00
|
|
|
|
2001-01-13 22:06:39 +00:00
|
|
|
// Otherwise, default to a random compiled-in location if we can't
|
|
|
|
// find fg-root any other way.
|
2002-03-20 19:16:13 +00:00
|
|
|
if ( root.empty() ) {
|
2001-04-05 20:25:40 +00:00
|
|
|
#if defined( __CYGWIN__ )
|
2010-01-23 22:26:30 +00:00
|
|
|
root = "../data";
|
|
|
|
#elif defined( _WIN32 )
|
|
|
|
root = "..\\data";
|
2008-07-25 08:39:28 +00:00
|
|
|
#elif defined(__APPLE__)
|
|
|
|
/*
|
|
|
|
The following code looks for the base package inside the application
|
|
|
|
bundle, in the standard Contents/Resources location.
|
2003-10-19 19:15:41 +00:00
|
|
|
*/
|
2008-07-25 08:39:28 +00:00
|
|
|
CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
|
2003-10-19 19:15:41 +00:00
|
|
|
|
2008-07-25 08:39:28 +00:00
|
|
|
// look for a 'data' subdir
|
|
|
|
CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent(NULL, resourcesUrl, CFSTR("data"), true);
|
2003-10-19 19:15:41 +00:00
|
|
|
|
|
|
|
// now convert down to a path, and the a c-string
|
|
|
|
CFStringRef path = CFURLCopyFileSystemPath(dataDir, kCFURLPOSIXPathStyle);
|
|
|
|
root = CFStringGetCStringPtr(path, CFStringGetSystemEncoding());
|
|
|
|
|
2008-07-25 08:39:28 +00:00
|
|
|
CFRelease(resourcesUrl);
|
2003-10-19 19:15:41 +00:00
|
|
|
CFRelease(dataDir);
|
|
|
|
CFRelease(path);
|
2001-01-13 22:06:39 +00:00
|
|
|
#else
|
2002-10-04 13:20:53 +00:00
|
|
|
root = PKGLIBDIR;
|
2001-01-13 22:06:39 +00:00
|
|
|
#endif
|
2000-10-04 22:52:34 +00:00
|
|
|
}
|
|
|
|
|
2001-03-24 06:03:11 +00:00
|
|
|
SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root );
|
2001-01-13 22:06:39 +00:00
|
|
|
globals->set_fg_root(root);
|
2000-10-04 22:52:34 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-16 20:17:11 +00:00
|
|
|
// Read in configuration (files and command line options) but only set
|
|
|
|
// aircraft
|
|
|
|
bool fgInitFGAircraft ( int argc, char **argv ) {
|
|
|
|
string aircraft;
|
|
|
|
|
|
|
|
// First parse command line options looking for --aircraft=, this
|
|
|
|
// will override anything specified in a config file
|
2002-11-16 20:41:00 +00:00
|
|
|
aircraft = fgScanForOption( "--aircraft=", argc, argv );
|
2007-11-02 18:39:10 +00:00
|
|
|
if ( aircraft.empty() ) {
|
|
|
|
// check synonym option
|
|
|
|
aircraft = fgScanForOption( "--vehicle=", argc, argv );
|
|
|
|
}
|
2002-11-16 20:17:11 +00:00
|
|
|
|
2005-12-22 10:25:07 +00:00
|
|
|
// Check in one of the user configuration files.
|
2007-11-02 18:39:10 +00:00
|
|
|
if ( aircraft.empty() ) {
|
2005-12-22 14:14:08 +00:00
|
|
|
aircraft = fgScanForOption( "--aircraft=" );
|
2007-11-02 18:39:10 +00:00
|
|
|
}
|
|
|
|
if ( aircraft.empty() ) {
|
|
|
|
aircraft = fgScanForOption( "--vehicle=" );
|
|
|
|
}
|
2002-11-16 20:17:11 +00:00
|
|
|
|
|
|
|
// if an aircraft was specified, set the property name
|
|
|
|
if ( !aircraft.empty() ) {
|
|
|
|
SG_LOG(SG_INPUT, SG_INFO, "aircraft = " << aircraft );
|
|
|
|
fgSetString("/sim/aircraft", aircraft.c_str() );
|
|
|
|
} else {
|
|
|
|
SG_LOG(SG_INPUT, SG_INFO, "No user specified aircraft, using default" );
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-07-16 19:17:58 +00:00
|
|
|
// Return the current base package version
|
|
|
|
string fgBasePackageVersion() {
|
|
|
|
SGPath base_path( globals->get_fg_root() );
|
|
|
|
base_path.append("version");
|
|
|
|
|
|
|
|
sg_gzifstream in( base_path.str() );
|
|
|
|
if ( !in.is_open() ) {
|
2002-10-04 13:20:53 +00:00
|
|
|
SGPath old_path( globals->get_fg_root() );
|
|
|
|
old_path.append( "Thanks" );
|
|
|
|
sg_gzifstream old( old_path.str() );
|
|
|
|
if ( !old.is_open() ) {
|
|
|
|
return "[none]";
|
|
|
|
} else {
|
|
|
|
return "[old version]";
|
|
|
|
}
|
2001-07-16 19:17:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string version;
|
|
|
|
in >> version;
|
|
|
|
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-07 15:45:00 +00:00
|
|
|
// Initialize the localization
|
|
|
|
SGPropertyNode *fgInitLocale(const char *language) {
|
|
|
|
SGPropertyNode *c_node = NULL, *d_node = NULL;
|
|
|
|
SGPropertyNode *intl = fgGetNode("/sim/intl");
|
|
|
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Selecting language: " << language );
|
|
|
|
|
|
|
|
// localization not defined
|
|
|
|
if (!intl)
|
|
|
|
return NULL;
|
2002-10-10 15:02:50 +00:00
|
|
|
|
2002-10-07 15:45:00 +00:00
|
|
|
//
|
|
|
|
// Select the proper language from the list
|
|
|
|
//
|
|
|
|
vector<SGPropertyNode_ptr> locale = intl->getChildren("locale");
|
|
|
|
for (unsigned int i = 0; i < locale.size(); i++) {
|
|
|
|
|
|
|
|
vector<SGPropertyNode_ptr> lang = locale[i]->getChildren("lang");
|
|
|
|
for (unsigned int j = 0; j < lang.size(); j++) {
|
|
|
|
|
|
|
|
if (!strcmp(lang[j]->getStringValue(), language)) {
|
|
|
|
c_node = locale[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the defaults
|
|
|
|
d_node = intl->getChild("locale");
|
|
|
|
if (!c_node)
|
|
|
|
c_node = d_node;
|
|
|
|
|
|
|
|
// Check for localized font
|
|
|
|
SGPropertyNode *font_n = c_node->getNode("font", true);
|
|
|
|
if ( !strcmp(font_n->getStringValue(), "") )
|
|
|
|
font_n->setStringValue(d_node->getStringValue("font", "typewriter.txf"));
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Load the default strings
|
|
|
|
//
|
|
|
|
SGPath d_path( globals->get_fg_root() );
|
|
|
|
|
|
|
|
const char *d_path_str = d_node->getStringValue("strings");
|
|
|
|
if (!d_path_str) {
|
2007-03-29 21:26:33 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "No path in " << d_node->getPath() << "/strings.");
|
2002-10-07 15:45:00 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
d_path.append(d_path_str);
|
2007-03-29 21:26:33 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from " << d_path.str());
|
2002-10-07 15:45:00 +00:00
|
|
|
|
|
|
|
SGPropertyNode *strings = c_node->getNode("strings");
|
|
|
|
try {
|
|
|
|
readProperties(d_path.str(), strings);
|
2008-07-27 09:45:33 +00:00
|
|
|
} catch (const sg_exception &) {
|
2002-10-07 15:45:00 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Load the language specific strings
|
|
|
|
//
|
|
|
|
if (c_node != d_node) {
|
|
|
|
SGPath c_path( globals->get_fg_root() );
|
|
|
|
|
|
|
|
const char *c_path_str = c_node->getStringValue("strings");
|
|
|
|
if (!c_path_str) {
|
2007-03-29 21:26:33 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "No path in " << c_node->getPath() << "/strings");
|
2002-10-07 15:45:00 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
c_path.append(c_path_str);
|
2007-03-29 21:26:33 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from " << c_path.str());
|
2002-10-07 15:45:00 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
readProperties(c_path.str(), strings);
|
2008-07-27 09:45:33 +00:00
|
|
|
} catch (const sg_exception &) {
|
2007-03-29 21:26:33 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
|
|
|
"Unable to read the localized strings from " << c_path.str());
|
2002-10-07 15:45:00 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return c_node;
|
|
|
|
}
|
|
|
|
|
1999-06-18 03:42:54 +00:00
|
|
|
|
2002-10-10 15:02:50 +00:00
|
|
|
|
|
|
|
// Initialize the localization routines
|
|
|
|
bool fgDetectLanguage() {
|
2008-06-02 21:09:51 +00:00
|
|
|
const char *language = ::getenv("LANG");
|
2002-10-10 15:02:50 +00:00
|
|
|
|
|
|
|
if (language == NULL) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Unable to detect the language" );
|
|
|
|
language = "C";
|
|
|
|
}
|
|
|
|
|
|
|
|
SGPropertyNode *locale = fgInitLocale(language);
|
|
|
|
if (!locale) {
|
2003-03-20 10:43:02 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
|
|
|
"No internationalization settings specified in preferences.xml" );
|
2002-10-10 15:02:50 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
globals->set_locale( locale );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-10-10 18:39:52 +00:00
|
|
|
// Attempt to locate and parse the various non-XML config files in order
|
|
|
|
// from least precidence to greatest precidence
|
|
|
|
static void
|
|
|
|
do_options (int argc, char ** argv)
|
|
|
|
{
|
|
|
|
// Check for $fg_root/system.fgfsrc
|
|
|
|
SGPath config( globals->get_fg_root() );
|
|
|
|
config.append( "system.fgfsrc" );
|
|
|
|
fgParseOptions(config.str());
|
|
|
|
|
|
|
|
#if defined( unix ) || defined( __CYGWIN__ )
|
|
|
|
config.concat( "." );
|
2005-12-21 13:36:04 +00:00
|
|
|
config.concat( hostname );
|
2002-10-10 18:39:52 +00:00
|
|
|
fgParseOptions(config.str());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Check for ~/.fgfsrc
|
2005-12-21 13:36:04 +00:00
|
|
|
if ( homedir != NULL ) {
|
|
|
|
config.set( homedir );
|
2002-10-10 18:39:52 +00:00
|
|
|
config.append( ".fgfsrc" );
|
|
|
|
fgParseOptions(config.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined( unix ) || defined( __CYGWIN__ )
|
|
|
|
// Check for ~/.fgfsrc.hostname
|
|
|
|
config.concat( "." );
|
2005-12-21 13:36:04 +00:00
|
|
|
config.concat( hostname );
|
2002-10-10 18:39:52 +00:00
|
|
|
fgParseOptions(config.str());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Parse remaining command line options
|
|
|
|
// These will override anything specified in a config file
|
|
|
|
fgParseArgs(argc, argv);
|
|
|
|
}
|
|
|
|
|
2010-07-06 20:06:50 +00:00
|
|
|
template <class T>
|
|
|
|
void fgFindAircraftInDir(const SGPath& dirPath, T* obj, bool (T::*pred)(const SGPath& p))
|
2007-04-05 19:59:44 +00:00
|
|
|
{
|
2010-07-06 20:06:50 +00:00
|
|
|
if (!dirPath.exists()) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "fgFindAircraftInDir: no such path:" << dirPath.str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool recurse = true;
|
|
|
|
simgear::Dir dir(dirPath);
|
|
|
|
simgear::PathList setFiles(dir.children(simgear::Dir::TYPE_FILE, "-set.xml"));
|
|
|
|
simgear::PathList::iterator p;
|
|
|
|
for (p = setFiles.begin(); p != setFiles.end(); ++p) {
|
|
|
|
// check file name ends with -set.xml
|
|
|
|
|
|
|
|
// if we found a -set.xml at this level, don't recurse any deeper
|
|
|
|
recurse = false;
|
|
|
|
|
|
|
|
bool done = (obj->*pred)(*p);
|
|
|
|
if (done) {
|
|
|
|
return;
|
2003-09-19 20:06:27 +00:00
|
|
|
}
|
2010-07-06 20:06:50 +00:00
|
|
|
} // of -set.xml iteration
|
|
|
|
|
|
|
|
if (recurse) {
|
|
|
|
simgear::PathList subdirs(dir.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT));
|
|
|
|
for (p = subdirs.begin(); p != subdirs.end(); ++p) {
|
|
|
|
if (p->file() == "CVS") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fgFindAircraftInDir(*p, obj, pred);
|
|
|
|
}
|
|
|
|
} // of recursive case
|
|
|
|
}
|
2003-09-19 20:06:27 +00:00
|
|
|
|
2010-07-06 20:06:50 +00:00
|
|
|
class FindAndCacheAircraft
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FindAndCacheAircraft(SGPropertyNode* autoSave)
|
|
|
|
{
|
|
|
|
_cache = autoSave->getNode("sim/startup/path-cache", true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool loadAircraft()
|
|
|
|
{
|
|
|
|
std::string aircraft = fgGetString( "/sim/aircraft", "");
|
|
|
|
if (aircraft.empty()) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "no aircraft specified");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
_searchAircraft = aircraft + "-set.xml";
|
|
|
|
if (!checkCache()) {
|
|
|
|
// prepare cache for re-scan
|
|
|
|
SGPropertyNode *n = _cache->getNode("fg-root", true);
|
|
|
|
n->setStringValue(globals->get_fg_root().c_str());
|
|
|
|
n->setAttribute(SGPropertyNode::USERARCHIVE, true);
|
|
|
|
_cache->removeChildren("aircraft");
|
|
|
|
|
|
|
|
SGPath aircraftDir(globals->get_fg_root());
|
|
|
|
aircraftDir.append("Aircraft");
|
|
|
|
|
|
|
|
fgFindAircraftInDir(aircraftDir, this, &FindAndCacheAircraft::checkAircraft);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_foundPath.str().empty()) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find specified aircraft: " << aircraft );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Loading aircraft -set file from:" << _foundPath.str());
|
|
|
|
fgSetString( "/sim/aircraft-dir", _foundPath.dir().c_str());
|
|
|
|
if (!_foundPath.exists()) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "Unable to find -set file:" << _foundPath.str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
readProperties(_foundPath.str(), globals->get_props());
|
|
|
|
} catch ( const sg_exception &e ) {
|
|
|
|
SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool checkCache()
|
|
|
|
{
|
|
|
|
if (globals->get_fg_root() != _cache->getStringValue("fg-root", "")) {
|
|
|
|
return false; // cache mismatch
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<SGPropertyNode_ptr> cache = _cache->getChildren("aircraft");
|
|
|
|
for (unsigned int i = 0; i < cache.size(); i++) {
|
|
|
|
const char *name = cache[i]->getStringValue("file", "");
|
|
|
|
if (!boost::equals(_searchAircraft, name, is_iequal())) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
SGPath xml(cache[i]->getStringValue("path", ""));
|
|
|
|
xml.append(name);
|
|
|
|
if (xml.exists()) {
|
|
|
|
_foundPath = xml;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
} // of aircraft in cache iteration
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool checkAircraft(const SGPath& p)
|
|
|
|
{
|
|
|
|
// create cache node
|
|
|
|
int i = 0;
|
|
|
|
while (1) {
|
|
|
|
if (!_cache->getChild("aircraft", i++, false))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SGPropertyNode *n, *entry = _cache->getChild("aircraft", --i, true);
|
2007-04-02 23:19:36 +00:00
|
|
|
|
2010-07-06 20:06:50 +00:00
|
|
|
std::string fileName(p.file());
|
|
|
|
n = entry->getNode("file", true);
|
|
|
|
n->setStringValue(fileName);
|
|
|
|
n->setAttribute(SGPropertyNode::USERARCHIVE, true);
|
2007-04-02 23:19:36 +00:00
|
|
|
|
2010-07-06 20:06:50 +00:00
|
|
|
n = entry->getNode("path", true);
|
|
|
|
n->setStringValue(p.dir());
|
|
|
|
n->setAttribute(SGPropertyNode::USERARCHIVE, true);
|
2007-04-02 23:19:36 +00:00
|
|
|
|
2010-07-06 20:06:50 +00:00
|
|
|
if ( boost::equals(fileName, _searchAircraft.c_str(), is_iequal()) ) {
|
|
|
|
_foundPath = p;
|
|
|
|
return true;
|
2003-09-19 20:06:27 +00:00
|
|
|
}
|
|
|
|
|
2010-07-06 20:06:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string _searchAircraft;
|
|
|
|
SGPath _foundPath;
|
|
|
|
SGPropertyNode* _cache;
|
|
|
|
};
|
2003-09-19 20:06:27 +00:00
|
|
|
|
2002-10-10 15:02:50 +00:00
|
|
|
// Read in configuration (file and command line)
|
|
|
|
bool fgInitConfig ( int argc, char **argv ) {
|
|
|
|
|
2002-11-16 20:17:11 +00:00
|
|
|
// First, set some sane default values
|
2002-10-10 15:02:50 +00:00
|
|
|
fgSetDefaults();
|
|
|
|
|
|
|
|
// Read global preferences from $FG_ROOT/preferences.xml
|
|
|
|
SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
|
2002-11-06 18:57:31 +00:00
|
|
|
fgLoadProps("preferences.xml", globals->get_props());
|
2002-10-10 15:02:50 +00:00
|
|
|
SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
|
|
|
|
|
|
|
|
// Detect the required language as early as possible
|
2002-11-16 20:17:11 +00:00
|
|
|
if ( !fgDetectLanguage() ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-04-05 19:59:44 +00:00
|
|
|
SGPropertyNode autosave;
|
2010-01-23 22:26:30 +00:00
|
|
|
#ifdef _WIN32
|
2007-04-05 19:59:44 +00:00
|
|
|
char *envp = ::getenv( "APPDATA" );
|
|
|
|
if (envp != NULL ) {
|
|
|
|
SGPath config( envp );
|
|
|
|
config.append( "flightgear.org" );
|
|
|
|
#else
|
|
|
|
if ( homedir != NULL ) {
|
|
|
|
SGPath config( homedir );
|
|
|
|
config.append( ".fgfs" );
|
|
|
|
#endif
|
2008-06-13 10:52:47 +00:00
|
|
|
const char *fg_home = getenv("FG_HOME");
|
|
|
|
if (fg_home)
|
|
|
|
config = fg_home;
|
|
|
|
|
2009-01-10 16:48:22 +00:00
|
|
|
SGPath home_export(config.str());
|
|
|
|
home_export.append("Export/dummy");
|
|
|
|
home_export.create_dir(0777);
|
|
|
|
|
2008-06-13 10:52:47 +00:00
|
|
|
// Set /sim/fg-home and don't allow malign code to override it until
|
|
|
|
// Nasal security is set up. Use FG_HOME if necessary.
|
|
|
|
SGPropertyNode *home = fgGetNode("/sim", true);
|
|
|
|
home->removeChild("fg-home", 0, false);
|
|
|
|
home = home->getChild("fg-home", 0, true);
|
|
|
|
home->setStringValue(config.c_str());
|
|
|
|
home->setAttribute(SGPropertyNode::WRITE, false);
|
|
|
|
|
2007-04-05 19:59:44 +00:00
|
|
|
config.append( "autosave.xml" );
|
2010-07-06 20:06:50 +00:00
|
|
|
if (config.exists()) {
|
|
|
|
SG_LOG(SG_INPUT, SG_INFO, "Reading user settings from " << config.str());
|
|
|
|
try {
|
|
|
|
readProperties(config.str(), &autosave, SGPropertyNode::USERARCHIVE);
|
|
|
|
} catch (sg_exception& e) {
|
|
|
|
SG_LOG(SG_INPUT, SG_WARN, "failed to read user settings:" << e.getMessage()
|
|
|
|
<< "(from " << e.getOrigin() << ")");
|
|
|
|
}
|
2007-04-05 19:59:44 +00:00
|
|
|
}
|
|
|
|
}
|
2010-07-06 20:06:50 +00:00
|
|
|
|
2002-11-16 20:17:11 +00:00
|
|
|
// Scan user config files and command line for a specified aircraft.
|
|
|
|
fgInitFGAircraft(argc, argv);
|
2010-07-06 20:06:50 +00:00
|
|
|
FindAndCacheAircraft f(&autosave);
|
|
|
|
if (!f.loadAircraft()) {
|
|
|
|
return false;
|
2002-10-10 15:02:50 +00:00
|
|
|
}
|
|
|
|
|
2007-04-05 19:59:44 +00:00
|
|
|
copyProperties(&autosave, globals->get_props());
|
2005-12-17 15:34:37 +00:00
|
|
|
|
2002-11-16 20:17:11 +00:00
|
|
|
// parse options after loading aircraft to ensure any user
|
|
|
|
// overrides of defaults are honored.
|
2002-10-10 18:39:52 +00:00
|
|
|
do_options(argc, argv);
|
2002-10-10 15:02:50 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-04-06 17:23:18 +00:00
|
|
|
// Set current tower position lon/lat given an airport id
|
2007-09-09 23:21:48 +00:00
|
|
|
static bool fgSetTowerPosFromAirportID( const string& id) {
|
2005-12-29 13:58:21 +00:00
|
|
|
const FGAirport *a = fgFindAirportID( id);
|
2007-09-09 23:21:48 +00:00
|
|
|
if (a) {
|
|
|
|
SGGeod tower = a->getTowerLocation();
|
|
|
|
fgSetDouble("/sim/tower/longitude-deg", tower.getLongitudeDeg());
|
|
|
|
fgSetDouble("/sim/tower/latitude-deg", tower.getLatitudeDeg());
|
|
|
|
fgSetDouble("/sim/tower/altitude-ft", tower.getElevationFt());
|
2002-10-04 13:20:53 +00:00
|
|
|
return true;
|
2002-04-06 17:23:18 +00:00
|
|
|
} else {
|
2002-10-04 13:20:53 +00:00
|
|
|
return false;
|
2002-04-06 17:23:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-10-19 19:21:45 +00:00
|
|
|
struct FGTowerLocationListener : SGPropertyChangeListener {
|
|
|
|
void valueChanged(SGPropertyNode* node) {
|
|
|
|
const string id(node->getStringValue());
|
2007-09-09 23:21:48 +00:00
|
|
|
fgSetTowerPosFromAirportID(id);
|
2005-10-19 19:21:45 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2007-04-04 19:05:59 +00:00
|
|
|
void fgInitTowerLocationListener() {
|
2005-10-19 19:21:45 +00:00
|
|
|
fgGetNode("/sim/tower/airport-id", true)
|
2007-04-26 20:27:25 +00:00
|
|
|
->addChangeListener( new FGTowerLocationListener(), true );
|
2005-10-19 19:21:45 +00:00
|
|
|
}
|
2002-04-06 17:23:18 +00:00
|
|
|
|
2008-09-13 08:06:15 +00:00
|
|
|
static void fgApplyStartOffset(const SGGeod& aStartPos, double aHeading, double aTargetHeading = HUGE_VAL)
|
|
|
|
{
|
|
|
|
SGGeod startPos(aStartPos);
|
|
|
|
if (aTargetHeading == HUGE_VAL) {
|
|
|
|
aTargetHeading = aHeading;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( fabs( fgGetDouble("/sim/presets/offset-distance-nm") ) > SG_EPSILON ) {
|
|
|
|
double offsetDistance = fgGetDouble("/sim/presets/offset-distance-nm");
|
|
|
|
offsetDistance *= SG_NM_TO_METER;
|
|
|
|
double offsetAzimuth = aHeading;
|
|
|
|
if ( fabs(fgGetDouble("/sim/presets/offset-azimuth-deg")) > SG_EPSILON ) {
|
|
|
|
offsetAzimuth = fgGetDouble("/sim/presets/offset-azimuth-deg");
|
|
|
|
aHeading = aTargetHeading;
|
|
|
|
}
|
|
|
|
|
|
|
|
SGGeod offset;
|
|
|
|
double az2; // dummy
|
|
|
|
SGGeodesy::direct(startPos, offsetAzimuth + 180, offsetDistance, offset, az2);
|
|
|
|
startPos = offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
// presets
|
|
|
|
fgSetDouble("/sim/presets/longitude-deg", startPos.getLongitudeDeg() );
|
|
|
|
fgSetDouble("/sim/presets/latitude-deg", startPos.getLatitudeDeg() );
|
|
|
|
fgSetDouble("/sim/presets/heading-deg", aHeading );
|
|
|
|
|
|
|
|
// other code depends on the actual values being set ...
|
|
|
|
fgSetDouble("/position/longitude-deg", startPos.getLongitudeDeg() );
|
|
|
|
fgSetDouble("/position/latitude-deg", startPos.getLatitudeDeg() );
|
|
|
|
fgSetDouble("/orientation/heading-deg", aHeading );
|
|
|
|
}
|
|
|
|
|
2000-08-16 00:09:03 +00:00
|
|
|
// Set current_options lon/lat given an airport id and heading (degrees)
|
2002-11-16 21:34:51 +00:00
|
|
|
static bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
|
2007-10-04 17:13:41 +00:00
|
|
|
if ( id.empty() )
|
|
|
|
return false;
|
2002-02-05 20:54:08 +00:00
|
|
|
|
2007-10-04 17:13:41 +00:00
|
|
|
// set initial position from runway and heading
|
|
|
|
SG_LOG( SG_GENERAL, SG_INFO,
|
|
|
|
"Attempting to set starting position from airport code "
|
|
|
|
<< id << " heading " << tgt_hdg );
|
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
const FGAirport* apt = fgFindAirportID(id);
|
|
|
|
if (!apt) return false;
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* r = apt->findBestRunwayForHeading(tgt_hdg);
|
|
|
|
fgSetString("/sim/atc/runway", r->ident().c_str());
|
2000-08-16 00:09:03 +00:00
|
|
|
|
2008-09-13 08:06:15 +00:00
|
|
|
SGGeod startPos = r->pointOnCenterline(fgGetDouble("/sim/airport/runways/start-offset-m", 5.0));
|
|
|
|
fgApplyStartOffset(startPos, r->headingDeg(), tgt_hdg);
|
2000-08-16 00:09:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-02-28 21:39:25 +00:00
|
|
|
// Set current_options lon/lat given an airport id and parkig position name
|
|
|
|
static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& parkpos ) {
|
|
|
|
if ( id.empty() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// can't see an easy way around this const_cast at the moment
|
|
|
|
FGAirport* apt = const_cast<FGAirport*>(fgFindAirportID(id));
|
|
|
|
if (!apt) {
|
2008-09-13 08:06:15 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport " << id );
|
2008-02-28 21:39:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
FGAirportDynamics* dcs = apt->getDynamics();
|
|
|
|
if (!dcs) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Failed to find parking position " << parkpos <<
|
|
|
|
" at airport " << id );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int park_index = dcs->getNrOfParkings() - 1;
|
|
|
|
while (park_index >= 0 && dcs->getParkingName(park_index) != parkpos) park_index--;
|
|
|
|
if (park_index < 0) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Failed to find parking position " << parkpos <<
|
|
|
|
" at airport " << id );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
FGParking* parking = dcs->getParking(park_index);
|
2010-01-30 15:40:33 +00:00
|
|
|
parking->setAvailable(false);
|
2008-09-13 08:06:15 +00:00
|
|
|
fgApplyStartOffset(
|
|
|
|
SGGeod::fromDeg(parking->getLongitude(), parking->getLatitude()),
|
|
|
|
parking->getHeading());
|
2008-02-28 21:39:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-05-14 05:22:52 +00:00
|
|
|
|
2003-03-20 09:38:06 +00:00
|
|
|
// Set current_options lon/lat given an airport id and runway number
|
2006-05-31 07:20:10 +00:00
|
|
|
static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy, bool rwy_req ) {
|
2007-10-04 17:13:41 +00:00
|
|
|
if ( id.empty() )
|
|
|
|
return false;
|
2002-11-17 04:04:21 +00:00
|
|
|
|
2007-10-04 17:13:41 +00:00
|
|
|
// set initial position from airport and runway number
|
|
|
|
SG_LOG( SG_GENERAL, SG_INFO,
|
|
|
|
"Attempting to set starting position for "
|
|
|
|
<< id << ":" << rwy );
|
2002-11-17 04:04:21 +00:00
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
const FGAirport* apt = fgFindAirportID(id);
|
|
|
|
if (!apt) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport:" << id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!apt->hasRunwayWithIdent(rwy)) {
|
|
|
|
SG_LOG( SG_GENERAL, rwy_req ? SG_ALERT : SG_INFO,
|
2007-10-04 17:13:41 +00:00
|
|
|
"Failed to find runway " << rwy <<
|
|
|
|
" at airport " << id << ". Using default runway." );
|
2008-08-14 18:13:39 +00:00
|
|
|
return false;
|
2002-11-17 04:04:21 +00:00
|
|
|
}
|
2008-08-14 18:13:39 +00:00
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* r(apt->getRunwayByIdent(rwy));
|
|
|
|
fgSetString("/sim/atc/runway", r->ident().c_str());
|
2008-09-13 08:06:15 +00:00
|
|
|
SGGeod startPos = r->pointOnCenterline( fgGetDouble("/sim/airport/runways/start-offset-m", 5.0));
|
|
|
|
fgApplyStartOffset(startPos, r->headingDeg());
|
2003-03-20 09:38:06 +00:00
|
|
|
return true;
|
2002-11-17 04:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-16 21:34:51 +00:00
|
|
|
static void fgSetDistOrAltFromGlideSlope() {
|
2003-11-11 17:46:23 +00:00
|
|
|
// cout << "fgSetDistOrAltFromGlideSlope()" << endl;
|
2002-11-30 20:10:16 +00:00
|
|
|
string apt_id = fgGetString("/sim/presets/airport-id");
|
2002-11-18 21:31:33 +00:00
|
|
|
double gs = fgGetDouble("/sim/presets/glideslope-deg")
|
|
|
|
* SG_DEGREES_TO_RADIANS ;
|
2008-05-01 21:14:02 +00:00
|
|
|
double od = fgGetDouble("/sim/presets/offset-distance-nm");
|
2002-11-15 21:13:29 +00:00
|
|
|
double alt = fgGetDouble("/sim/presets/altitude-ft");
|
2002-11-30 20:10:16 +00:00
|
|
|
|
|
|
|
double apt_elev = 0.0;
|
|
|
|
if ( ! apt_id.empty() ) {
|
|
|
|
apt_elev = fgGetAirportElev( apt_id );
|
|
|
|
if ( apt_elev < -9990.0 ) {
|
|
|
|
apt_elev = 0.0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
apt_elev = 0.0;
|
|
|
|
}
|
|
|
|
|
2002-02-20 16:56:44 +00:00
|
|
|
if( fabs(gs) > 0.01 && fabs(od) > 0.1 && alt < -9990 ) {
|
2002-11-16 21:34:51 +00:00
|
|
|
// set altitude from glideslope and offset-distance
|
2002-10-04 13:20:53 +00:00
|
|
|
od *= SG_NM_TO_METER * SG_METER_TO_FEET;
|
2002-11-30 20:10:16 +00:00
|
|
|
alt = fabs(od*tan(gs)) + apt_elev;
|
2002-11-16 21:34:51 +00:00
|
|
|
fgSetDouble("/sim/presets/altitude-ft", alt);
|
2002-11-15 21:13:29 +00:00
|
|
|
fgSetBool("/sim/presets/onground", false);
|
2002-12-12 01:24:48 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "Calculated altitude as: "
|
|
|
|
<< alt << " ft" );
|
2002-02-20 16:56:44 +00:00
|
|
|
} else if( fabs(gs) > 0.01 && alt > 0 && fabs(od) < 0.1) {
|
2002-11-16 21:34:51 +00:00
|
|
|
// set offset-distance from glideslope and altitude
|
2002-11-30 20:10:16 +00:00
|
|
|
od = (alt - apt_elev) / tan(gs);
|
2002-10-04 13:20:53 +00:00
|
|
|
od *= -1*SG_FEET_TO_METER * SG_METER_TO_NM;
|
2008-05-01 21:14:02 +00:00
|
|
|
fgSetDouble("/sim/presets/offset-distance-nm", od);
|
2002-12-12 01:24:48 +00:00
|
|
|
fgSetBool("/sim/presets/onground", false);
|
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "Calculated offset distance as: "
|
|
|
|
<< od << " nm" );
|
2002-02-20 16:56:44 +00:00
|
|
|
} else if( fabs(gs) > 0.01 ) {
|
2002-11-16 20:17:11 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Glideslope given but not altitude or offset-distance." );
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" );
|
2002-11-18 21:31:33 +00:00
|
|
|
fgSetDouble("/sim/presets/glideslope-deg", 0);
|
2002-11-30 20:10:16 +00:00
|
|
|
fgSetBool("/sim/presets/onground", true);
|
2008-05-02 21:31:30 +00:00
|
|
|
}
|
2004-04-15 22:09:46 +00:00
|
|
|
}
|
2000-08-16 00:09:03 +00:00
|
|
|
|
2002-11-16 20:17:11 +00:00
|
|
|
|
2003-01-05 00:10:36 +00:00
|
|
|
// Set current_options lon/lat given an airport id and heading (degrees)
|
|
|
|
static bool fgSetPosFromNAV( const string& id, const double& freq ) {
|
2004-05-28 05:24:54 +00:00
|
|
|
FGNavRecord *nav
|
|
|
|
= globals->get_navlist()->findByIdentAndFreq( id.c_str(), freq );
|
2003-01-05 00:10:36 +00:00
|
|
|
|
2008-09-13 08:06:15 +00:00
|
|
|
if (!nav) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
|
2003-01-05 00:10:36 +00:00
|
|
|
<< id << ":" << freq );
|
2008-09-13 08:06:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg"));
|
|
|
|
return true;
|
2003-01-05 00:10:36 +00:00
|
|
|
}
|
|
|
|
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
// Set current_options lon/lat given an aircraft carrier id
|
|
|
|
static bool fgSetPosFromCarrier( const string& carrier, const string& posid ) {
|
|
|
|
|
|
|
|
// set initial position from runway and heading
|
2006-02-19 17:28:31 +00:00
|
|
|
SGGeod geodPos;
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
double heading;
|
2006-02-19 17:28:31 +00:00
|
|
|
SGVec3d uvw;
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
if (FGAIManager::getStartPosition(carrier, posid, geodPos, heading, uvw)) {
|
2006-02-19 17:28:31 +00:00
|
|
|
double lon = geodPos.getLongitudeDeg();
|
|
|
|
double lat = geodPos.getLatitudeDeg();
|
|
|
|
double alt = geodPos.getElevationFt();
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
|
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for "
|
|
|
|
<< carrier << " at lat = " << lat << ", lon = " << lon
|
|
|
|
<< ", alt = " << alt << ", heading = " << heading);
|
|
|
|
|
|
|
|
fgSetDouble("/sim/presets/longitude-deg", lon);
|
|
|
|
fgSetDouble("/sim/presets/latitude-deg", lat);
|
|
|
|
fgSetDouble("/sim/presets/altitude-ft", alt);
|
|
|
|
fgSetDouble("/sim/presets/heading-deg", heading);
|
|
|
|
fgSetDouble("/position/longitude-deg", lon);
|
|
|
|
fgSetDouble("/position/latitude-deg", lat);
|
|
|
|
fgSetDouble("/position/altitude-ft", alt);
|
|
|
|
fgSetDouble("/orientation/heading-deg", heading);
|
|
|
|
|
|
|
|
fgSetString("/sim/presets/speed-set", "UVW");
|
2006-02-19 17:28:31 +00:00
|
|
|
fgSetDouble("/velocities/uBody-fps", uvw(0));
|
|
|
|
fgSetDouble("/velocities/vBody-fps", uvw(1));
|
|
|
|
fgSetDouble("/velocities/wBody-fps", uvw(2));
|
|
|
|
fgSetDouble("/sim/presets/uBody-fps", uvw(0));
|
|
|
|
fgSetDouble("/sim/presets/vBody-fps", uvw(1));
|
|
|
|
fgSetDouble("/sim/presets/wBody-fps", uvw(2));
|
2003-01-05 00:10:36 +00:00
|
|
|
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
fgSetBool("/sim/presets/onground", true);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} else {
|
2005-10-04 20:36:38 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = "
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
<< carrier );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-05 00:10:36 +00:00
|
|
|
// Set current_options lon/lat given an airport id and heading (degrees)
|
2008-09-13 08:06:15 +00:00
|
|
|
static bool fgSetPosFromFix( const string& id )
|
|
|
|
{
|
2008-12-23 14:41:58 +00:00
|
|
|
FGPositioned::TypeFilter fixFilter(FGPositioned::FIX);
|
|
|
|
FGPositioned* fix = FGPositioned::findNextWithPartialId(NULL, id, &fixFilter);
|
|
|
|
if (!fix) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate fix = " << id );
|
2008-09-13 08:06:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fgApplyStartOffset(fix->geod(), fgGetDouble("/sim/presets/heading-deg"));
|
|
|
|
return true;
|
2003-01-05 00:10:36 +00:00
|
|
|
}
|
|
|
|
|
2003-02-21 02:45:47 +00:00
|
|
|
/**
|
2003-08-28 20:53:08 +00:00
|
|
|
* Initialize vor/ndb/ils/fix list management and query systems (as
|
|
|
|
* well as simple airport db list)
|
2003-02-21 02:45:47 +00:00
|
|
|
*/
|
|
|
|
bool
|
|
|
|
fgInitNav ()
|
|
|
|
{
|
2004-12-22 23:57:07 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Loading Airport Database ...");
|
|
|
|
|
|
|
|
SGPath aptdb( globals->get_fg_root() );
|
|
|
|
aptdb.append( "Airports/apt.dat" );
|
|
|
|
|
2004-02-23 18:25:29 +00:00
|
|
|
SGPath p_metar( globals->get_fg_root() );
|
|
|
|
p_metar.append( "Airports/metar.dat" );
|
2003-08-28 20:53:08 +00:00
|
|
|
|
2009-09-18 15:27:19 +00:00
|
|
|
// Initialise the frequency search map BEFORE reading
|
|
|
|
// the airport database:
|
2009-12-30 14:11:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2009-09-18 15:27:19 +00:00
|
|
|
current_commlist = new FGCommList;
|
|
|
|
current_commlist->init( globals->get_fg_root() );
|
|
|
|
fgAirportDBLoad( aptdb.str(), current_commlist, p_metar.str() );
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2004-05-26 18:15:19 +00:00
|
|
|
FGNavList *navlist = new FGNavList;
|
2004-05-28 05:24:54 +00:00
|
|
|
FGNavList *loclist = new FGNavList;
|
|
|
|
FGNavList *gslist = new FGNavList;
|
|
|
|
FGNavList *dmelist = new FGNavList;
|
2005-10-01 09:56:53 +00:00
|
|
|
FGNavList *tacanlist = new FGNavList;
|
|
|
|
FGNavList *carrierlist = new FGNavList;
|
|
|
|
FGTACANList *channellist = new FGTACANList;
|
2004-05-28 05:24:54 +00:00
|
|
|
|
2004-05-26 18:15:19 +00:00
|
|
|
globals->set_navlist( navlist );
|
2004-05-28 05:24:54 +00:00
|
|
|
globals->set_loclist( loclist );
|
|
|
|
globals->set_gslist( gslist );
|
|
|
|
globals->set_dmelist( dmelist );
|
2005-10-01 09:56:53 +00:00
|
|
|
globals->set_tacanlist( tacanlist );
|
|
|
|
globals->set_carrierlist( carrierlist );
|
|
|
|
globals->set_channellist( channellist );
|
2003-02-21 02:45:47 +00:00
|
|
|
|
2008-12-25 23:11:43 +00:00
|
|
|
if ( !fgNavDBInit(navlist, loclist, gslist, dmelist, tacanlist, carrierlist, channellist) ) {
|
2004-05-28 05:24:54 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Problems loading one or more navigational database" );
|
|
|
|
}
|
2008-09-13 08:06:15 +00:00
|
|
|
|
2003-02-21 02:45:47 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, " Fixes");
|
|
|
|
SGPath p_fix( globals->get_fg_root() );
|
2004-05-26 16:40:27 +00:00
|
|
|
p_fix.append( "Navaids/fix.dat" );
|
2009-05-07 10:27:16 +00:00
|
|
|
FGFixList fixlist;
|
|
|
|
fixlist.init( p_fix ); // adds fixes to the DB in positioned.cxx
|
2003-03-03 04:34:27 +00:00
|
|
|
|
2006-07-27 14:49:41 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, " Airways");
|
|
|
|
SGPath p_awy( globals->get_fg_root() );
|
|
|
|
p_awy.append( "Navaids/awy.dat" );
|
|
|
|
FGAirwayNetwork *awyNet = new FGAirwayNetwork;
|
|
|
|
//cerr << "Loading Airways" << endl;
|
|
|
|
awyNet->load (p_awy );
|
|
|
|
awyNet->init();
|
|
|
|
//cerr << "initializing airways" << endl;
|
|
|
|
globals->set_airwaynet( awyNet );
|
|
|
|
|
2003-03-03 04:34:27 +00:00
|
|
|
return true;
|
2003-02-21 02:45:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-16 21:34:51 +00:00
|
|
|
// Set the initial position based on presets (or defaults)
|
|
|
|
bool fgInitPosition() {
|
2003-11-11 17:46:23 +00:00
|
|
|
// cout << "fgInitPosition()" << endl;
|
2003-11-10 22:00:22 +00:00
|
|
|
double gs = fgGetDouble("/sim/presets/glideslope-deg")
|
|
|
|
* SG_DEGREES_TO_RADIANS ;
|
2008-05-01 21:14:02 +00:00
|
|
|
double od = fgGetDouble("/sim/presets/offset-distance-nm");
|
2003-11-10 22:00:22 +00:00
|
|
|
double alt = fgGetDouble("/sim/presets/altitude-ft");
|
|
|
|
|
2002-11-17 04:04:21 +00:00
|
|
|
bool set_pos = false;
|
|
|
|
|
2003-05-13 03:18:42 +00:00
|
|
|
// If glideslope is specified, then calculate offset-distance or
|
|
|
|
// altitude relative to glide slope if either of those was not
|
|
|
|
// specified.
|
2003-11-10 22:00:22 +00:00
|
|
|
if ( fabs( gs ) > 0.01 ) {
|
2003-05-13 03:18:42 +00:00
|
|
|
fgSetDistOrAltFromGlideSlope();
|
|
|
|
}
|
|
|
|
|
2003-05-07 16:00:31 +00:00
|
|
|
|
2002-11-16 21:34:51 +00:00
|
|
|
// If we have an explicit, in-range lon/lat, don't change it, just use it.
|
|
|
|
// If not, check for an airport-id and use that.
|
|
|
|
// If not, default to the middle of the KSFO field.
|
|
|
|
// The default values for lon/lat are deliberately out of range
|
|
|
|
// so that the airport-id can take effect; valid lon/lat will
|
|
|
|
// override airport-id, however.
|
|
|
|
double lon_deg = fgGetDouble("/sim/presets/longitude-deg");
|
|
|
|
double lat_deg = fgGetDouble("/sim/presets/latitude-deg");
|
|
|
|
if ( lon_deg >= -180.0 && lon_deg <= 180.0
|
|
|
|
&& lat_deg >= -90.0 && lat_deg <= 90.0 )
|
|
|
|
{
|
2002-11-17 04:04:21 +00:00
|
|
|
set_pos = true;
|
|
|
|
}
|
2002-11-16 21:34:51 +00:00
|
|
|
|
2002-11-17 04:04:21 +00:00
|
|
|
string apt = fgGetString("/sim/presets/airport-id");
|
|
|
|
string rwy_no = fgGetString("/sim/presets/runway");
|
2006-05-31 07:20:10 +00:00
|
|
|
bool rwy_req = fgGetBool("/sim/presets/runway-requested");
|
2003-01-05 00:10:36 +00:00
|
|
|
string vor = fgGetString("/sim/presets/vor-id");
|
|
|
|
double vor_freq = fgGetDouble("/sim/presets/vor-freq");
|
|
|
|
string ndb = fgGetString("/sim/presets/ndb-id");
|
|
|
|
double ndb_freq = fgGetDouble("/sim/presets/ndb-freq");
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
string carrier = fgGetString("/sim/presets/carrier");
|
|
|
|
string parkpos = fgGetString("/sim/presets/parkpos");
|
2003-01-05 00:10:36 +00:00
|
|
|
string fix = fgGetString("/sim/presets/fix");
|
2007-10-05 14:34:04 +00:00
|
|
|
SGPropertyNode *hdg_preset = fgGetNode("/sim/presets/heading-deg", true);
|
|
|
|
double hdg = hdg_preset->getDoubleValue();
|
2003-07-02 16:24:50 +00:00
|
|
|
|
2007-10-07 19:27:05 +00:00
|
|
|
// save some start parameters, so that we can later say what the
|
|
|
|
// user really requested. TODO generalize that and move it to options.cxx
|
|
|
|
static bool start_options_saved = false;
|
|
|
|
if (!start_options_saved) {
|
|
|
|
start_options_saved = true;
|
|
|
|
SGPropertyNode *opt = fgGetNode("/sim/startup/options", true);
|
|
|
|
|
|
|
|
opt->setDoubleValue("latitude-deg", lat_deg);
|
|
|
|
opt->setDoubleValue("longitude-deg", lon_deg);
|
|
|
|
opt->setDoubleValue("heading-deg", hdg);
|
|
|
|
opt->setStringValue("airport", apt.c_str());
|
|
|
|
opt->setStringValue("runway", rwy_no.c_str());
|
|
|
|
}
|
|
|
|
|
2007-10-04 17:13:41 +00:00
|
|
|
if (hdg > 9990.0)
|
|
|
|
hdg = fgGetDouble("/environment/config/boundary/entry/wind-from-heading-deg", 270);
|
2005-10-19 19:21:45 +00:00
|
|
|
|
2008-02-28 21:39:25 +00:00
|
|
|
if ( !set_pos && !apt.empty() && !parkpos.empty() ) {
|
|
|
|
// An airport + parking position is requested
|
|
|
|
if ( fgSetPosFromAirportIDandParkpos( apt, parkpos ) ) {
|
|
|
|
// set tower position
|
|
|
|
fgSetString("/sim/tower/airport-id", apt.c_str());
|
|
|
|
set_pos = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-17 04:04:21 +00:00
|
|
|
if ( !set_pos && !apt.empty() && !rwy_no.empty() ) {
|
|
|
|
// An airport + runway is requested
|
2006-05-31 07:20:10 +00:00
|
|
|
if ( fgSetPosFromAirportIDandRwy( apt, rwy_no, rwy_req ) ) {
|
2003-07-02 16:24:50 +00:00
|
|
|
// set tower position (a little off the heading for single
|
2002-11-16 21:34:51 +00:00
|
|
|
// runway airports)
|
2005-10-19 19:21:45 +00:00
|
|
|
fgSetString("/sim/tower/airport-id", apt.c_str());
|
2002-11-17 04:04:21 +00:00
|
|
|
set_pos = true;
|
|
|
|
}
|
|
|
|
}
|
2003-07-02 16:24:50 +00:00
|
|
|
|
2002-11-17 04:04:21 +00:00
|
|
|
if ( !set_pos && !apt.empty() ) {
|
2003-01-05 00:10:36 +00:00
|
|
|
// An airport is requested (find runway closest to hdg)
|
2003-07-02 16:24:50 +00:00
|
|
|
if ( fgSetPosFromAirportIDandHdg( apt, hdg ) ) {
|
|
|
|
// set tower position (a little off the heading for single
|
|
|
|
// runway airports)
|
2005-10-19 19:21:45 +00:00
|
|
|
fgSetString("/sim/tower/airport-id", apt.c_str());
|
2002-11-17 04:04:21 +00:00
|
|
|
set_pos = true;
|
2002-11-16 21:34:51 +00:00
|
|
|
}
|
|
|
|
}
|
2003-07-02 16:24:50 +00:00
|
|
|
|
2007-10-05 14:34:04 +00:00
|
|
|
if (hdg_preset->getDoubleValue() > 9990.0)
|
|
|
|
hdg_preset->setDoubleValue(hdg);
|
|
|
|
|
2003-01-05 00:10:36 +00:00
|
|
|
if ( !set_pos && !vor.empty() ) {
|
|
|
|
// a VOR is requested
|
|
|
|
if ( fgSetPosFromNAV( vor, vor_freq ) ) {
|
|
|
|
set_pos = true;
|
|
|
|
}
|
|
|
|
}
|
2003-07-02 16:24:50 +00:00
|
|
|
|
2003-01-05 00:10:36 +00:00
|
|
|
if ( !set_pos && !ndb.empty() ) {
|
|
|
|
// an NDB is requested
|
|
|
|
if ( fgSetPosFromNAV( ndb, ndb_freq ) ) {
|
|
|
|
set_pos = true;
|
|
|
|
}
|
|
|
|
}
|
2003-07-02 16:24:50 +00:00
|
|
|
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
if ( !set_pos && !carrier.empty() ) {
|
|
|
|
// an aircraft carrier is requested
|
|
|
|
if ( fgSetPosFromCarrier( carrier, parkpos ) ) {
|
|
|
|
set_pos = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-05 00:10:36 +00:00
|
|
|
if ( !set_pos && !fix.empty() ) {
|
|
|
|
// a Fix is requested
|
|
|
|
if ( fgSetPosFromFix( fix ) ) {
|
|
|
|
set_pos = true;
|
|
|
|
}
|
|
|
|
}
|
2002-11-16 21:34:51 +00:00
|
|
|
|
2002-11-17 04:04:21 +00:00
|
|
|
if ( !set_pos ) {
|
|
|
|
// No lon/lat specified, no airport specified, default to
|
|
|
|
// middle of KSFO field.
|
|
|
|
fgSetDouble("/sim/presets/longitude-deg", -122.374843);
|
|
|
|
fgSetDouble("/sim/presets/latitude-deg", 37.619002);
|
|
|
|
}
|
|
|
|
|
2002-11-16 21:34:51 +00:00
|
|
|
fgSetDouble( "/position/longitude-deg",
|
|
|
|
fgGetDouble("/sim/presets/longitude-deg") );
|
|
|
|
fgSetDouble( "/position/latitude-deg",
|
|
|
|
fgGetDouble("/sim/presets/latitude-deg") );
|
2007-10-05 14:34:04 +00:00
|
|
|
fgSetDouble( "/orientation/heading-deg", hdg_preset->getDoubleValue());
|
2002-11-16 21:34:51 +00:00
|
|
|
|
2003-11-10 22:00:22 +00:00
|
|
|
// determine if this should be an on-ground or in-air start
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
if ((fabs(gs) > 0.01 || fabs(od) > 0.1 || alt > 0.1) && carrier.empty()) {
|
2003-11-10 22:00:22 +00:00
|
|
|
fgSetBool("/sim/presets/onground", false);
|
|
|
|
} else {
|
|
|
|
fgSetBool("/sim/presets/onground", true);
|
2007-10-05 14:34:04 +00:00
|
|
|
}
|
2003-11-10 22:00:22 +00:00
|
|
|
|
2002-11-16 21:34:51 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-04-25 15:11:10 +00:00
|
|
|
// General house keeping initializations
|
2002-11-16 21:34:51 +00:00
|
|
|
bool fgInitGeneral() {
|
1998-08-27 17:01:55 +00:00
|
|
|
string root;
|
1999-11-19 02:10:24 +00:00
|
|
|
|
2001-03-24 06:03:11 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "General Initialization" );
|
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "======= ==============" );
|
1998-04-25 20:24:00 +00:00
|
|
|
|
2001-01-13 22:06:39 +00:00
|
|
|
root = globals->get_fg_root();
|
1998-09-08 21:40:08 +00:00
|
|
|
if ( ! root.length() ) {
|
2002-10-04 13:20:53 +00:00
|
|
|
// No root path set? Then bail ...
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Cannot continue without a path to the base package "
|
|
|
|
<< "being defined." );
|
|
|
|
exit(-1);
|
1998-04-25 15:11:10 +00:00
|
|
|
}
|
2001-03-24 06:03:11 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "FG_ROOT = " << '"' << root << '"' << endl );
|
1998-04-25 15:11:10 +00:00
|
|
|
|
2008-07-09 19:35:53 +00:00
|
|
|
globals->set_browser(fgGetString("/sim/startup/browser-app", "firefox %u"));
|
|
|
|
|
2008-06-22 11:29:32 +00:00
|
|
|
char buf[512], *cwd = getcwd(buf, 511);
|
|
|
|
buf[511] = '\0';
|
|
|
|
SGPropertyNode *curr = fgGetNode("/sim", true);
|
|
|
|
curr->removeChild("fg-current", 0, false);
|
|
|
|
curr = curr->getChild("fg-current", 0, true);
|
|
|
|
curr->setStringValue(cwd ? cwd : "");
|
|
|
|
curr->setAttribute(SGPropertyNode::WRITE, false);
|
2008-10-01 15:03:53 +00:00
|
|
|
|
|
|
|
fgSetBool("/sim/startup/stdout-to-terminal", isatty(1));
|
|
|
|
fgSetBool("/sim/startup/stderr-to-terminal", isatty(2));
|
1999-06-18 03:42:54 +00:00
|
|
|
return true;
|
1998-04-25 15:11:10 +00:00
|
|
|
}
|
|
|
|
|
2002-02-05 20:54:08 +00:00
|
|
|
// Initialize view parameters
|
|
|
|
void fgInitView() {
|
2002-04-13 13:11:34 +00:00
|
|
|
// force update of model so that viewer can get some data...
|
|
|
|
globals->get_aircraft_model()->update(0);
|
2002-04-21 03:27:34 +00:00
|
|
|
// run update for current view so that data is current...
|
2002-03-14 00:29:20 +00:00
|
|
|
globals->get_viewmgr()->update(0);
|
2002-02-05 20:54:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-02-06 23:31:33 +00:00
|
|
|
SGTime *fgInitTime() {
|
|
|
|
// Initialize time
|
|
|
|
static const SGPropertyNode *longitude
|
2002-10-04 13:20:53 +00:00
|
|
|
= fgGetNode("/position/longitude-deg");
|
2002-02-06 23:31:33 +00:00
|
|
|
static const SGPropertyNode *latitude
|
2002-10-04 13:20:53 +00:00
|
|
|
= fgGetNode("/position/latitude-deg");
|
2002-02-11 23:33:20 +00:00
|
|
|
static const SGPropertyNode *cur_time_override
|
2002-10-04 13:20:53 +00:00
|
|
|
= fgGetNode("/sim/time/cur-time-override", true);
|
2002-02-11 23:33:20 +00:00
|
|
|
|
2002-02-06 23:31:33 +00:00
|
|
|
SGPath zone( globals->get_fg_root() );
|
|
|
|
zone.append( "Timezone" );
|
|
|
|
SGTime *t = new SGTime( longitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
2002-02-11 23:33:20 +00:00
|
|
|
zone.str(),
|
|
|
|
cur_time_override->getLongValue() );
|
2002-02-06 23:31:33 +00:00
|
|
|
|
2003-09-15 22:55:39 +00:00
|
|
|
globals->set_warp_delta( 0 );
|
|
|
|
|
|
|
|
t->update( 0.0, 0.0,
|
|
|
|
cur_time_override->getLongValue(),
|
|
|
|
globals->get_warp() );
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// set up a time offset (aka warp) if one is specified
|
|
|
|
void fgInitTimeOffset() {
|
|
|
|
static const SGPropertyNode *longitude
|
|
|
|
= fgGetNode("/position/longitude-deg");
|
|
|
|
static const SGPropertyNode *latitude
|
|
|
|
= fgGetNode("/position/latitude-deg");
|
|
|
|
static const SGPropertyNode *cur_time_override
|
|
|
|
= fgGetNode("/sim/time/cur-time-override", true);
|
|
|
|
|
2002-02-06 23:31:33 +00:00
|
|
|
// Handle potential user specified time offsets
|
2003-09-16 22:34:22 +00:00
|
|
|
int orig_warp = globals->get_warp();
|
2003-09-15 22:55:39 +00:00
|
|
|
SGTime *t = globals->get_time_params();
|
2002-02-06 23:31:33 +00:00
|
|
|
time_t cur_time = t->get_cur_time();
|
|
|
|
time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
|
|
|
|
time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
|
|
|
|
time_t aircraftLocalTime =
|
|
|
|
sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) );
|
2006-07-09 08:02:47 +00:00
|
|
|
|
2003-09-15 22:55:39 +00:00
|
|
|
// Okay, we now have several possible scenarios
|
2002-02-06 23:31:33 +00:00
|
|
|
int offset = fgGetInt("/sim/startup/time-offset");
|
2005-10-12 08:55:58 +00:00
|
|
|
string offset_type = fgGetString("/sim/startup/time-offset-type");
|
2003-09-17 15:49:15 +00:00
|
|
|
|
|
|
|
int warp = 0;
|
|
|
|
if ( offset_type == "real" ) {
|
|
|
|
warp = 0;
|
|
|
|
} else if ( offset_type == "dawn" ) {
|
|
|
|
warp = fgTimeSecondsUntilSunAngle( cur_time,
|
2003-09-15 22:55:39 +00:00
|
|
|
longitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue()
|
2003-09-17 15:49:15 +00:00
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
90.0, true );
|
|
|
|
} else if ( offset_type == "morning" ) {
|
|
|
|
warp = fgTimeSecondsUntilSunAngle( cur_time,
|
|
|
|
longitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
75.0, true );
|
|
|
|
} else if ( offset_type == "noon" ) {
|
|
|
|
warp = fgTimeSecondsUntilSunAngle( cur_time,
|
|
|
|
longitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
0.0, true );
|
|
|
|
} else if ( offset_type == "afternoon" ) {
|
|
|
|
warp = fgTimeSecondsUntilSunAngle( cur_time,
|
|
|
|
longitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
60.0, false );
|
2003-09-15 22:55:39 +00:00
|
|
|
} else if ( offset_type == "dusk" ) {
|
2003-09-17 15:49:15 +00:00
|
|
|
warp = fgTimeSecondsUntilSunAngle( cur_time,
|
|
|
|
longitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
90.0, false );
|
|
|
|
} else if ( offset_type == "evening" ) {
|
|
|
|
warp = fgTimeSecondsUntilSunAngle( cur_time,
|
|
|
|
longitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
100.0, false );
|
|
|
|
} else if ( offset_type == "midnight" ) {
|
|
|
|
warp = fgTimeSecondsUntilSunAngle( cur_time,
|
|
|
|
longitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue()
|
|
|
|
* SGD_DEGREES_TO_RADIANS,
|
|
|
|
180.0, false );
|
2003-09-15 22:55:39 +00:00
|
|
|
} else if ( offset_type == "system-offset" ) {
|
|
|
|
warp = offset;
|
2006-07-09 08:02:47 +00:00
|
|
|
orig_warp = 0;
|
2003-09-15 22:55:39 +00:00
|
|
|
} else if ( offset_type == "gmt-offset" ) {
|
|
|
|
warp = offset - (currGMT - systemLocalTime);
|
2006-07-09 08:02:47 +00:00
|
|
|
orig_warp = 0;
|
2003-09-15 22:55:39 +00:00
|
|
|
} else if ( offset_type == "latitude-offset" ) {
|
|
|
|
warp = offset - (aircraftLocalTime - systemLocalTime);
|
2006-07-09 08:02:47 +00:00
|
|
|
orig_warp = 0;
|
2003-09-15 22:55:39 +00:00
|
|
|
} else if ( offset_type == "system" ) {
|
2006-07-09 08:02:47 +00:00
|
|
|
warp = offset - (systemLocalTime - currGMT) - cur_time;
|
2003-09-15 22:55:39 +00:00
|
|
|
} else if ( offset_type == "gmt" ) {
|
2006-07-09 08:02:47 +00:00
|
|
|
warp = offset - cur_time;
|
2003-09-15 22:55:39 +00:00
|
|
|
} else if ( offset_type == "latitude" ) {
|
2006-07-09 08:02:47 +00:00
|
|
|
warp = offset - (aircraftLocalTime - currGMT)- cur_time;
|
2002-02-06 23:31:33 +00:00
|
|
|
} else {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"FG_TIME::Unsupported offset type " << offset_type );
|
|
|
|
exit( -1 );
|
|
|
|
}
|
2003-09-16 22:34:22 +00:00
|
|
|
globals->set_warp( orig_warp + warp );
|
|
|
|
t->update( longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS,
|
|
|
|
latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS,
|
|
|
|
cur_time_override->getLongValue(),
|
2003-09-15 22:55:39 +00:00
|
|
|
globals->get_warp() );
|
2002-02-06 23:31:33 +00:00
|
|
|
|
2003-09-15 22:55:39 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "After fgInitTimeOffset(): warp = "
|
2002-02-06 23:31:33 +00:00
|
|
|
<< globals->get_warp() );
|
|
|
|
}
|
|
|
|
|
2004-11-18 05:00:44 +00:00
|
|
|
|
1998-04-25 15:11:10 +00:00
|
|
|
// This is the top level init routine which calls all the other
|
|
|
|
// initialization routines. If you are adding a subsystem to flight
|
|
|
|
// gear, its initialization call should located in this routine.
|
|
|
|
// Returns non-zero if a problem encountered.
|
2002-11-18 21:31:33 +00:00
|
|
|
bool fgInitSubsystems() {
|
2003-05-06 23:46:24 +00:00
|
|
|
// static const SGPropertyNode *longitude
|
|
|
|
// = fgGetNode("/sim/presets/longitude-deg");
|
|
|
|
// static const SGPropertyNode *latitude
|
|
|
|
// = fgGetNode("/sim/presets/latitude-deg");
|
|
|
|
// static const SGPropertyNode *altitude
|
|
|
|
// = fgGetNode("/sim/presets/altitude-ft");
|
2009-10-24 09:22:20 +00:00
|
|
|
|
2001-03-24 06:03:11 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems");
|
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
|
1998-04-25 15:11:10 +00:00
|
|
|
|
2003-09-24 17:20:55 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the event manager subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2004-11-18 05:00:44 +00:00
|
|
|
globals->get_event_mgr()->init();
|
2005-11-09 20:34:46 +00:00
|
|
|
globals->get_event_mgr()->setRealtimeProperty(fgGetNode("/sim/time/delta-realtime-sec", true));
|
2001-04-05 20:20:44 +00:00
|
|
|
|
2003-12-05 01:52:34 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
2007-05-01 18:06:48 +00:00
|
|
|
// Initialize the property interpolator subsystem. Put into the INIT
|
|
|
|
// group because the "nasal" subsystem may need it at GENERAL take-down.
|
2003-12-05 01:52:34 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
2007-05-01 18:06:48 +00:00
|
|
|
globals->add_subsystem("interpolator", new SGInterpolator, SGSubsystemMgr::INIT);
|
2004-02-20 17:35:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Add the FlightGear property utilities.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
globals->add_subsystem("properties", new FGProperties);
|
2003-12-05 01:52:34 +00:00
|
|
|
|
2001-04-05 20:20:44 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the material property subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2001-03-25 14:20:12 +00:00
|
|
|
SGPath mpath( globals->get_fg_root() );
|
2001-12-28 23:33:32 +00:00
|
|
|
mpath.append( "materials.xml" );
|
2009-05-22 18:20:58 +00:00
|
|
|
if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
|
2008-02-15 17:54:23 +00:00
|
|
|
globals->get_props()) ) {
|
2002-10-04 13:20:53 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Error loading material lib!" );
|
|
|
|
exit(-1);
|
2000-06-23 00:30:04 +00:00
|
|
|
}
|
|
|
|
|
2001-04-05 20:20:44 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the scenery management subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2002-12-06 22:29:46 +00:00
|
|
|
if ( globals->get_tile_mgr()->init() ) {
|
2002-10-04 13:20:53 +00:00
|
|
|
// Load the local scenery data
|
|
|
|
double visibility_meters = fgGetDouble("/environment/visibility-m");
|
2002-12-06 22:29:46 +00:00
|
|
|
globals->get_tile_mgr()->update( visibility_meters );
|
1998-08-22 14:49:55 +00:00
|
|
|
} else {
|
2002-10-04 13:20:53 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Error in Tile Manager initialization!" );
|
|
|
|
exit(-1);
|
1998-08-22 14:49:55 +00:00
|
|
|
}
|
|
|
|
|
2008-02-15 06:45:38 +00:00
|
|
|
globals->get_scenery()->get_scene_graph()
|
|
|
|
->addChild(simgear::Particles::getCommonRoot());
|
2008-10-17 21:25:03 +00:00
|
|
|
simgear::GlobalParticleCallback::setSwitch(fgGetNode("/sim/rendering/particles", true));
|
2008-02-15 06:45:19 +00:00
|
|
|
|
2001-04-05 20:20:44 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the flight model subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-06-16 07:31:59 +00:00
|
|
|
globals->add_subsystem("flight", new FDMShell, SGSubsystemMgr::FDM);
|
2007-11-03 21:02:28 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the weather subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Initialize the weather modeling subsystem
|
|
|
|
globals->add_subsystem("environment", new FGEnvironmentMgr);
|
|
|
|
|
2009-04-20 14:20:05 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the ridge lift simulation.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Initialize the ridgelift subsystem
|
|
|
|
globals->add_subsystem("ridgelift", new FGRidgeLift);
|
|
|
|
|
2006-06-24 03:42:30 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the aircraft systems and instrumentation (before the
|
|
|
|
// autopilot.)
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-06-16 07:31:59 +00:00
|
|
|
globals->add_subsystem("instrumentation", new FGInstrumentMgr, SGSubsystemMgr::FDM);
|
|
|
|
globals->add_subsystem("systems", new FGSystemMgr, SGSubsystemMgr::FDM);
|
1998-08-22 14:49:55 +00:00
|
|
|
|
2004-01-31 19:47:45 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the XML Autopilot subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-06-16 07:31:59 +00:00
|
|
|
globals->add_subsystem( "xml-autopilot", new FGXMLAutopilotGroup, SGSubsystemMgr::FDM );
|
2004-01-31 19:47:45 +00:00
|
|
|
globals->add_subsystem( "route-manager", new FGRouteMgr );
|
2009-09-21 13:57:39 +00:00
|
|
|
|
2002-04-13 13:11:34 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the view manager subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
fgInitView();
|
|
|
|
|
2009-09-07 07:27:38 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the Input-Output subsystem
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
globals->add_subsystem( "io", new FGIO );
|
|
|
|
|
2002-03-12 16:29:00 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
2002-11-07 16:27:47 +00:00
|
|
|
// Create and register the logger.
|
2002-03-12 16:29:00 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-01-16 16:01:26 +00:00
|
|
|
globals->add_subsystem("logger", new FGLogger);
|
2002-03-12 16:29:00 +00:00
|
|
|
|
2002-11-07 16:27:47 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Create and register the XML GUI.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-09-24 17:20:55 +00:00
|
|
|
globals->add_subsystem("gui", new NewGUI, SGSubsystemMgr::INIT);
|
2002-11-07 16:27:47 +00:00
|
|
|
|
|
|
|
|
2001-04-05 20:20:44 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the local time subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
1999-10-22 00:27:49 +00:00
|
|
|
// update the current timezone each 30 minutes
|
2003-11-25 21:08:36 +00:00
|
|
|
globals->get_event_mgr()->addTask( "fgUpdateLocalTime()",
|
|
|
|
&fgUpdateLocalTime, 30*60 );
|
2005-05-04 21:28:42 +00:00
|
|
|
fgInitTimeOffset(); // the environment subsystem needs this
|
1998-04-22 13:25:39 +00:00
|
|
|
|
2001-04-05 20:20:44 +00:00
|
|
|
|
2003-09-24 17:20:55 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the lighting subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-07-08 22:24:39 +00:00
|
|
|
globals->add_subsystem("lighting", new FGLight, SGSubsystemMgr::DISPLAY);
|
2003-09-24 17:20:55 +00:00
|
|
|
|
2004-05-20 13:27:40 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the 2D cloud subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
2004-10-20 08:18:29 +00:00
|
|
|
fgGetBool("/sim/rendering/bump-mapping", false);
|
2003-09-24 17:20:55 +00:00
|
|
|
|
2004-04-24 19:28:12 +00:00
|
|
|
#ifdef ENABLE_AUDIO_SUPPORT
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the sound-effects subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
2010-07-08 22:24:39 +00:00
|
|
|
globals->add_subsystem("voice", new FGVoiceMgr, SGSubsystemMgr::DISPLAY);
|
2004-04-24 19:28:12 +00:00
|
|
|
#endif
|
|
|
|
|
2001-11-07 17:55:28 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
2002-03-01 17:39:52 +00:00
|
|
|
// Initialise the ATC Manager
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-01-05 20:04:54 +00:00
|
|
|
#if ENABLE_ATCDCL
|
2002-03-01 17:39:52 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, " ATC Manager");
|
|
|
|
globals->set_ATC_mgr(new FGATCMgr);
|
2002-04-03 23:54:44 +00:00
|
|
|
globals->get_ATC_mgr()->init();
|
2010-01-05 20:04:54 +00:00
|
|
|
|
2002-04-03 23:54:44 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialise the AI Manager
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-04-01 13:42:10 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, " AI Manager");
|
|
|
|
globals->set_AI_mgr(new FGAIMgr);
|
|
|
|
globals->get_AI_mgr()->init();
|
2010-01-05 20:04:54 +00:00
|
|
|
#endif
|
2003-11-28 15:48:05 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialise the AI Model Manager
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, " AI Model Manager");
|
2010-07-08 22:24:39 +00:00
|
|
|
globals->add_subsystem("ai_model", new FGAIManager, SGSubsystemMgr::POST_FDM);
|
|
|
|
globals->add_subsystem("submodel_mgr", new FGSubmodelMgr, SGSubsystemMgr::POST_FDM);
|
2003-11-28 15:48:05 +00:00
|
|
|
|
|
|
|
|
2007-04-04 19:05:59 +00:00
|
|
|
// It's probably a good idea to initialize the top level traffic manager
|
|
|
|
// After the AI and ATC systems have been initialized properly.
|
|
|
|
// AI Traffic manager
|
2010-07-08 22:24:39 +00:00
|
|
|
globals->add_subsystem("Traffic Manager", new FGTrafficManager, SGSubsystemMgr::POST_FDM);
|
2004-06-03 17:59:14 +00:00
|
|
|
|
|
|
|
|
2010-07-01 21:33:51 +00:00
|
|
|
if( fgCockpitInit()) {
|
2002-10-04 13:20:53 +00:00
|
|
|
// Cockpit initialized ok.
|
1998-02-12 21:58:27 +00:00
|
|
|
} else {
|
2002-10-04 13:20:53 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Error in Cockpit initialization!" );
|
|
|
|
exit(-1);
|
1997-09-04 02:17:18 +00:00
|
|
|
}
|
1997-08-25 20:27:21 +00:00
|
|
|
|
1998-02-12 21:58:27 +00:00
|
|
|
|
2003-03-30 12:46:08 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Add a new 2D panel.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2001-01-13 22:06:39 +00:00
|
|
|
string panel_path = fgGetString("/sim/panel/path",
|
2002-10-04 13:20:53 +00:00
|
|
|
"Panels/Default/default.xml");
|
2003-03-30 12:46:08 +00:00
|
|
|
|
|
|
|
globals->set_current_panel( fgReadPanel(panel_path) );
|
|
|
|
if (globals->get_current_panel() == 0) {
|
2006-05-08 14:35:29 +00:00
|
|
|
SG_LOG( SG_INPUT, SG_ALERT,
|
2002-10-04 13:20:53 +00:00
|
|
|
"Error reading new panel from " << panel_path );
|
2000-10-25 19:27:13 +00:00
|
|
|
} else {
|
2002-10-04 13:20:53 +00:00
|
|
|
SG_LOG( SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path );
|
2003-03-30 12:46:08 +00:00
|
|
|
globals->get_current_panel()->init();
|
|
|
|
globals->get_current_panel()->bind();
|
2000-09-22 17:20:56 +00:00
|
|
|
}
|
User-visible
- knobs now continue to rotate when you hold down the mouse
- the middle mouse button makes knobs rotate much faster
- there are NAV1, NAV2, and ADF radios that can be tuned using the mouse
- there are standby frequencies for NAV1 and NAV2, and buttons to swap
- there is a crude, rather silly-looking DME, hard-wired to NAV1
- there is a crude, rather silly-looking autopilot that can lock
the heading (to the bug on the gyro), can lock to NAV1, and can lock
the current altitude
- the knobs for changing the radials on NAV1 and NAV2 look much better
and are in the right place
- tuning into an ILS frequency doesn't change the displayed radial for
NAV1
Code
- I've created a new module, sp_panel.[ch]xx, that constructs the
default single-prop panel; this works entirely outside of FGPanel,
so it is possible to construct similar modules for other sorts of
panels; all code specific to the default panel has been removed from
panel.cxx
- current_panel is now a pointer
- radiostack.[ch]xx keeps track both of the actual radial and of the
selected radial (they will differ with ILS); the NAV gauges should
not spin around automatically to show the actual radial (we need to
do something similar with the autopilot)
- the panel is initialized fairly early
- make sure that standby frequencies also get initialized
- I've started combining and clipping small textures to save texture
memory; there's a lot more to do, but at least I've made a start
2000-05-02 18:26:00 +00:00
|
|
|
|
2006-05-08 14:35:29 +00:00
|
|
|
|
2001-04-05 20:20:44 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the controls subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2001-07-22 19:51:16 +00:00
|
|
|
globals->get_controls()->init();
|
|
|
|
globals->get_controls()->bind();
|
2001-01-05 17:38:58 +00:00
|
|
|
|
2001-04-05 20:20:44 +00:00
|
|
|
|
I'm attaching diffs to add a new FGInput module to FlightGear
(src/Input). So far, FGInput replaces most of src/Main/keyboard.cxx
(I've left a tiny stub); in the very near future, it will also take
over control of the joystick, mouse (Norm permitting), and panel
instrument interactions, so that there is a single mechanism for
configuring all input devices.
The new format should be (close to) self-explanatory by looking at the
new base-package file keyboard.xml, which is now included by
preferences.xml (I'll do the same thing for the joystick when I have a
chance). I have not managed to move all keybindings into this file
yet, but I've made a good start. I'm including Tony in the recipient
list so that he can see how bindings can use an external XML file.
This patch also adds support for multiple bindings for a single key,
special keys (i.e. keypad and function keys), and key modifiers
(shift/alt/ctrl); special keys use the PUI convention of adding 256 to
the Glut key code.
Unfortunately, everything comes with a price; in this case, I have not
yet found a general mechanism for the old (hard-coded) modal bindings,
which behaved differently depending on the autopilot state (i.e. left
rudder or move AP heading left); with my patches, this functionality
disappears, but you can still adjust the autopilot using the panel or
the GUI input dialogs.
2001-05-23 23:01:15 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the input subsystem.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-01-16 16:01:26 +00:00
|
|
|
globals->add_subsystem("input", new FGInput);
|
I'm attaching diffs to add a new FGInput module to FlightGear
(src/Input). So far, FGInput replaces most of src/Main/keyboard.cxx
(I've left a tiny stub); in the very near future, it will also take
over control of the joystick, mouse (Norm permitting), and panel
instrument interactions, so that there is a single mechanism for
configuring all input devices.
The new format should be (close to) self-explanatory by looking at the
new base-package file keyboard.xml, which is now included by
preferences.xml (I'll do the same thing for the joystick when I have a
chance). I have not managed to move all keybindings into this file
yet, but I've made a good start. I'm including Tony in the recipient
list so that he can see how bindings can use an external XML file.
This patch also adds support for multiple bindings for a single key,
special keys (i.e. keypad and function keys), and key modifiers
(shift/alt/ctrl); special keys use the PUI convention of adding 256 to
the Glut key code.
Unfortunately, everything comes with a price; in this case, I have not
yet found a general mechanism for the old (hard-coded) modal bindings,
which behaved differently depending on the autopilot state (i.e. left
rudder or move AP heading left); with my patches, this functionality
disappears, but you can still adjust the autopilot using the panel or
the GUI input dialogs.
2001-05-23 23:01:15 +00:00
|
|
|
|
|
|
|
|
2003-07-17 18:24:17 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the replay subsystem
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
globals->add_subsystem("replay", new FGReplay);
|
|
|
|
|
2009-10-04 13:52:53 +00:00
|
|
|
|
2002-10-03 21:20:56 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Bind and initialize subsystems.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
globals->get_subsystem_mgr()->bind();
|
|
|
|
globals->get_subsystem_mgr()->init();
|
|
|
|
|
2003-03-19 20:45:09 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize multiplayer subsystem
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2005-10-30 18:01:51 +00:00
|
|
|
globals->set_multiplayer_mgr(new FGMultiplayMgr);
|
|
|
|
globals->get_multiplayer_mgr()->init();
|
2003-03-19 20:45:09 +00:00
|
|
|
|
2003-11-25 21:08:36 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the Nasal interpreter.
|
|
|
|
// Do this last, so that the loaded scripts see initialized state
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
FGNasalSys* nasal = new FGNasalSys();
|
2006-06-10 22:24:05 +00:00
|
|
|
globals->add_subsystem("nasal", nasal, SGSubsystemMgr::INIT);
|
2003-11-25 21:08:36 +00:00
|
|
|
nasal->init();
|
|
|
|
|
2005-06-11 09:13:44 +00:00
|
|
|
// initialize methods that depend on other subsystems.
|
|
|
|
globals->get_subsystem_mgr()->postinit();
|
2004-04-15 22:09:46 +00:00
|
|
|
|
2001-04-05 20:20:44 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// End of subsystem initialization.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2001-03-24 06:03:11 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, endl);
|
1998-04-24 00:49:17 +00:00
|
|
|
|
2002-10-04 13:20:53 +00:00
|
|
|
// Save the initial state for future
|
|
|
|
// reference.
|
2001-01-19 22:57:24 +00:00
|
|
|
globals->saveInitialState();
|
2005-12-29 13:58:21 +00:00
|
|
|
|
1999-06-18 03:42:54 +00:00
|
|
|
return true;
|
1997-08-23 01:46:20 +00:00
|
|
|
}
|
1999-04-27 15:52:32 +00:00
|
|
|
|
|
|
|
|
2002-11-18 21:31:33 +00:00
|
|
|
void fgReInitSubsystems()
|
1999-04-27 15:52:32 +00:00
|
|
|
{
|
2003-05-06 23:46:24 +00:00
|
|
|
// static const SGPropertyNode *longitude
|
|
|
|
// = fgGetNode("/sim/presets/longitude-deg");
|
|
|
|
// static const SGPropertyNode *latitude
|
|
|
|
// = fgGetNode("/sim/presets/latitude-deg");
|
2001-10-28 16:16:30 +00:00
|
|
|
static const SGPropertyNode *altitude
|
2002-11-15 21:13:29 +00:00
|
|
|
= fgGetNode("/sim/presets/altitude-ft");
|
2002-01-20 03:52:36 +00:00
|
|
|
static const SGPropertyNode *master_freeze
|
2002-10-04 13:20:53 +00:00
|
|
|
= fgGetNode("/sim/freeze/master");
|
2001-10-28 16:16:30 +00:00
|
|
|
|
2001-03-24 06:03:11 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO,
|
2002-10-04 13:20:53 +00:00
|
|
|
"fgReInitSubsystems(): /position/altitude = "
|
2002-07-02 20:45:02 +00:00
|
|
|
<< altitude->getDoubleValue() );
|
2001-01-17 23:30:35 +00:00
|
|
|
|
2002-01-20 03:52:36 +00:00
|
|
|
bool freeze = master_freeze->getBoolValue();
|
|
|
|
if ( !freeze ) {
|
2002-10-04 13:20:53 +00:00
|
|
|
fgSetBool("/sim/freeze/master", true);
|
2001-10-28 16:16:30 +00:00
|
|
|
}
|
2003-12-29 10:10:35 +00:00
|
|
|
fgSetBool("/sim/crashed", false);
|
2000-07-23 21:32:59 +00:00
|
|
|
|
2005-07-13 12:25:16 +00:00
|
|
|
// Force reupdating the positions of the ai 3d models. They are used for
|
|
|
|
// initializing ground level for the FDM.
|
|
|
|
globals->get_subsystem("ai_model")->reinit();
|
|
|
|
|
2002-11-18 21:31:33 +00:00
|
|
|
// Initialize the FDM
|
2010-06-16 07:31:59 +00:00
|
|
|
globals->get_subsystem("flight")->reinit();
|
2000-10-27 22:00:43 +00:00
|
|
|
|
2003-02-06 19:44:32 +00:00
|
|
|
// reload offsets from config defaults
|
|
|
|
globals->get_viewmgr()->reinit();
|
2002-04-21 03:27:34 +00:00
|
|
|
|
2002-02-05 20:54:08 +00:00
|
|
|
fgInitView();
|
1999-04-27 15:52:32 +00:00
|
|
|
|
2001-07-22 19:51:16 +00:00
|
|
|
globals->get_controls()->reset_all();
|
1999-05-12 02:07:21 +00:00
|
|
|
|
2001-04-05 21:14:37 +00:00
|
|
|
fgUpdateLocalTime();
|
|
|
|
|
2003-10-23 17:00:16 +00:00
|
|
|
// re-init to proper time of day setting
|
|
|
|
fgInitTimeOffset();
|
|
|
|
|
2002-01-20 03:52:36 +00:00
|
|
|
if ( !freeze ) {
|
2002-10-04 13:20:53 +00:00
|
|
|
fgSetBool("/sim/freeze/master", false);
|
2002-01-20 03:52:36 +00:00
|
|
|
}
|
2004-07-22 16:42:14 +00:00
|
|
|
fgSetBool("/sim/sceneryloaded",false);
|
1999-04-27 15:52:32 +00:00
|
|
|
}
|
2002-04-13 13:11:34 +00:00
|
|
|
|
2008-07-09 12:22:33 +00:00
|
|
|
|
2010-07-01 21:50:11 +00:00
|
|
|
void doSimulatorReset(void) // from gui_local.cxx -- TODO merge with fgReInitSubsystems()
|
2008-07-09 12:22:33 +00:00
|
|
|
{
|
|
|
|
static SGPropertyNode_ptr master_freeze = fgGetNode("/sim/freeze/master", true);
|
|
|
|
|
|
|
|
bool freeze = master_freeze->getBoolValue();
|
|
|
|
if (!freeze)
|
|
|
|
master_freeze->setBoolValue(true);
|
|
|
|
|
|
|
|
fgSetBool("/sim/signals/reinit", true);
|
2010-06-16 07:31:59 +00:00
|
|
|
|
|
|
|
globals->get_subsystem("flight")->unbind();
|
2008-07-09 12:22:33 +00:00
|
|
|
|
|
|
|
// in case user has changed window size as
|
|
|
|
// restoreInitialState() overwrites these
|
|
|
|
int xsize = fgGetInt("/sim/startup/xsize");
|
|
|
|
int ysize = fgGetInt("/sim/startup/ysize");
|
|
|
|
|
2008-11-25 22:50:20 +00:00
|
|
|
// viewports also needs to be saved/restored as
|
|
|
|
// restoreInitialState() overwrites these
|
|
|
|
SGPropertyNode *guiNode = new SGPropertyNode;
|
|
|
|
SGPropertyNode *cameraNode = new SGPropertyNode;
|
|
|
|
SGPropertyNode *cameraGroupNode = fgGetNode("/sim/rendering/camera-group");
|
|
|
|
copyProperties(cameraGroupNode->getChild("camera"), cameraNode);
|
|
|
|
copyProperties(cameraGroupNode->getChild("gui"), guiNode);
|
|
|
|
|
2008-07-09 12:22:33 +00:00
|
|
|
globals->restoreInitialState();
|
|
|
|
|
|
|
|
// update our position based on current presets
|
|
|
|
fgInitPosition();
|
|
|
|
|
|
|
|
// We don't know how to resize the window, so keep the last values
|
|
|
|
// for xsize and ysize, and don't use the one set initially
|
|
|
|
fgSetInt("/sim/startup/xsize", xsize);
|
|
|
|
fgSetInt("/sim/startup/ysize", ysize);
|
|
|
|
|
2008-11-25 22:50:20 +00:00
|
|
|
copyProperties(cameraNode, cameraGroupNode->getChild("camera"));
|
|
|
|
copyProperties(guiNode, cameraGroupNode->getChild("gui"));
|
|
|
|
|
|
|
|
delete guiNode;
|
|
|
|
delete cameraNode;
|
|
|
|
|
2008-07-09 12:22:33 +00:00
|
|
|
SGTime *t = globals->get_time_params();
|
|
|
|
delete t;
|
|
|
|
t = fgInitTime();
|
|
|
|
globals->set_time_params(t);
|
|
|
|
|
|
|
|
fgReInitSubsystems();
|
|
|
|
|
|
|
|
globals->get_tile_mgr()->update(fgGetDouble("/environment/visibility-m"));
|
|
|
|
globals->get_renderer()->resize(xsize, ysize);
|
|
|
|
fgSetBool("/sim/signals/reinit", false);
|
|
|
|
|
|
|
|
if (!freeze)
|
|
|
|
master_freeze->setBoolValue(false);
|
|
|
|
}
|
|
|
|
|
2010-07-06 20:06:50 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// helper object to implement the --show-aircraft command.
|
|
|
|
// resides here so we can share the fgFindAircraftInDir template above,
|
|
|
|
// and hence ensure this command lists exectly the same aircraft as the normal
|
|
|
|
// loading path.
|
|
|
|
class ShowAircraft
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ShowAircraft()
|
|
|
|
{
|
|
|
|
_minStatus = getNumMaturity(fgGetString("/sim/aircraft-min-status", "all"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void show(const SGPath& path)
|
|
|
|
{
|
|
|
|
fgFindAircraftInDir(path, this, &ShowAircraft::processAircraft);
|
|
|
|
|
|
|
|
std::sort(_aircraft.begin(), _aircraft.end(), ciLessLibC());
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "" ); // To popup the console on Windows
|
|
|
|
cout << "Available aircraft:" << endl;
|
|
|
|
for ( unsigned int i = 0; i < _aircraft.size(); i++ ) {
|
|
|
|
cout << _aircraft[i] << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool processAircraft(const SGPath& path)
|
|
|
|
{
|
|
|
|
SGPropertyNode root;
|
|
|
|
try {
|
|
|
|
readProperties(path.str(), &root);
|
|
|
|
} catch (sg_exception& e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int maturity = 0;
|
|
|
|
string descStr(" ");
|
|
|
|
descStr += path.file();
|
|
|
|
|
|
|
|
SGPropertyNode *node = root.getNode("sim");
|
|
|
|
if (node) {
|
|
|
|
SGPropertyNode* desc = node->getNode("description");
|
|
|
|
// if a status tag is found, read it in
|
|
|
|
if (node->hasValue("status")) {
|
|
|
|
maturity = getNumMaturity(node->getStringValue("status"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (desc) {
|
|
|
|
if (descStr.size() <= 27+3) {
|
|
|
|
descStr.append(29+3-descStr.size(), ' ');
|
|
|
|
} else {
|
|
|
|
descStr += '\n';
|
|
|
|
descStr.append( 32, ' ');
|
|
|
|
}
|
|
|
|
descStr += desc->getStringValue();
|
|
|
|
}
|
|
|
|
} // of have 'sim' node
|
|
|
|
|
|
|
|
if (maturity < _minStatus) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
_aircraft.push_back(descStr);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int getNumMaturity(const char * str)
|
|
|
|
{
|
|
|
|
// changes should also be reflected in $FG_ROOT/data/options.xml &
|
|
|
|
// $FG_ROOT/data/Translations/string-default.xml
|
|
|
|
const char* levels[] = {"alpha","beta","early-production","production"};
|
|
|
|
|
|
|
|
if (!strcmp(str, "all")) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=0; i<(sizeof(levels)/sizeof(levels[0]));i++)
|
|
|
|
if (strcmp(str,levels[i])==0)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// recommended in Meyers, Effective STL when internationalization and embedded
|
|
|
|
// NULLs aren't an issue. Much faster than the STL or Boost lex versions.
|
|
|
|
struct ciLessLibC : public std::binary_function<string, string, bool>
|
|
|
|
{
|
|
|
|
bool operator()(const std::string &lhs, const std::string &rhs) const
|
|
|
|
{
|
|
|
|
return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
int _minStatus;
|
|
|
|
string_list _aircraft;
|
|
|
|
};
|
|
|
|
|
|
|
|
void fgShowAircraft(const SGPath &path)
|
|
|
|
{
|
|
|
|
ShowAircraft s;
|
|
|
|
s.show(path);
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
cout << "Hit a key to continue..." << endl;
|
|
|
|
cin.get();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|