// simgear
#include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx>
+#include <simgear/structure/event_mgr.hxx>
#include "globals.hxx"
#include "fg_props.hxx"
#include <Navaids/navlist.hxx>
#include <Airports/runways.hxx>
-#include <Airports/simple.hxx>
+#include <Airports/airport.hxx>
#include <Airports/dynamics.hxx>
#include <AIModel/AIManager.hxx>
using std::endl;
+using std::string;
namespace flightgear
{
/// unresponsive, we need a timeout value. This value is reset on initPosition,
/// and tracked through each call to finalizePosition.
static SGTimeStamp global_finalizeTime;
+static bool global_callbackRegistered = false;
+
+static void finalizePosition();
// Set current tower position lon/lat given an airport id
static bool fgSetTowerPosFromAirportID( const string& id) {
}
-struct FGTowerLocationListener : SGPropertyChangeListener {
+class FGTowerLocationListener : public SGPropertyChangeListener {
+
void valueChanged(SGPropertyNode* node) {
string id(node->getStringValue());
if (fgGetBool("/sim/tower/auto-position",true))
}
};
-struct FGClosestTowerLocationListener : SGPropertyChangeListener
+class FGClosestTowerLocationListener : public SGPropertyChangeListener
{
void valueChanged(SGPropertyNode* )
{
};
void initTowerLocationListener() {
+
+ SGPropertyChangeListener* tll = new FGTowerLocationListener();
+ globals->addListenerToCleanup(tll);
fgGetNode("/sim/tower/airport-id", true)
- ->addChangeListener( new FGTowerLocationListener(), true );
+ ->addChangeListener( tll, true );
+
FGClosestTowerLocationListener* ntcl = new FGClosestTowerLocationListener();
+ globals->addListenerToCleanup(ntcl);
fgGetNode("/sim/airport/closest-airport-id", true)
->addChangeListener(ntcl , true );
fgGetNode("/sim/tower/auto-position", true)
const FGAirport* apt = fgFindAirportID(id);
if (!apt) return false;
- FGRunway* r = apt->findBestRunwayForHeading(tgt_hdg);
- fgSetString("/sim/atc/runway", r->ident().c_str());
- SGGeod startPos = r->pointOnCenterline(fgGetDouble("/sim/airport/runways/start-offset-m", 5.0));
- fgApplyStartOffset(startPos, r->headingDeg(), tgt_hdg);
+ SGGeod startPos;
+ double heading = tgt_hdg;
+ if (apt->type() == FGPositioned::HELIPORT) {
+ if (apt->numHelipads() > 0) {
+ startPos = apt->getHelipadByIndex(0)->geod();
+ } else {
+ startPos = apt->geod();
+ }
+ } else {
+ FGRunway* r = apt->findBestRunwayForHeading(tgt_hdg);
+ fgSetString("/sim/atc/runway", r->ident().c_str());
+ startPos = r->pointOnCenterline(fgGetDouble("/sim/airport/runways/start-offset-m", 5.0));
+ heading = r->headingDeg();
+ }
+
+ fgApplyStartOffset(startPos, heading, tgt_hdg);
return true;
}
FGNavList::TypeFilter filter(type);
const nav_list_type navlist = FGNavList::findByIdentAndFreq( id.c_str(), freq, &filter );
- if (navlist.size() == 0 ) {
+ if (navlist.empty()) {
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
<< id << ":" << freq );
return false;
bool initPosition()
{
global_finalizeTime = SGTimeStamp(); // reset to invalid
-
+ if (!global_callbackRegistered) {
+ globals->get_event_mgr()->addTask("finalizePosition", &finalizePosition, 0.1);
+ global_callbackRegistered = true;
+ }
+
double gs = fgGetDouble("/sim/presets/glideslope-deg")
* SG_DEGREES_TO_RADIANS ;
double od = fgGetDouble("/sim/presets/offset-distance-nm");
fgSetBool("/sim/presets/onground", true);
}
+ fgSetBool("/sim/position-finalized", false);
+
+// Initialize the longitude, latitude and altitude to the initial position
+ fgSetDouble("/position/altitude-ft", fgGetDouble("/sim/presets/altitude-ft"));
+ fgSetDouble("/position/longitude-deg", fgGetDouble("/sim/presets/longitude-deg"));
+ fgSetDouble("/position/latitude-deg", fgGetDouble("/sim/presets/latitude-deg"));
+
+ return true;
+}
+
+bool finalizeMetar()
+{
+ double hdg = fgGetDouble( "/environment/metar/base-wind-dir-deg", 9999.0 );
+ string apt = fgGetString("/sim/presets/airport-id");
+ string rwy = fgGetString("/sim/presets/runway");
+ double strthdg = fgGetDouble( "/sim/startup/options/heading-deg", 9999.0 );
+ string parkpos = fgGetString( "/sim/presets/parkpos" );
+ bool onground = fgGetBool( "/sim/presets/onground", false );
+ // this logic is taken from former startup.nas
+ bool needMetar = (hdg < 360.0) && !apt.empty() && (strthdg > 360.0) &&
+ rwy.empty() && onground && parkpos.empty();
+
+ if (needMetar) {
+ // timeout so we don't spin forever if the network is down
+ if (global_finalizeTime.elapsedMSec() > fgGetInt("/sim/startup/metar-fetch-timeout-msec", 10000)) {
+ SG_LOG(SG_GENERAL, SG_WARN, "finalizePosition: timed out waiting for METAR fetch");
+ return true;
+ }
+
+ if (!fgGetBool( "/environment/metar/valid" )) {
+ return false;
+ }
+
+ SG_LOG(SG_ENVIRONMENT, SG_INFO,
+ "Using METAR for runway selection: '" << fgGetString("/environment/metar/data") << "'" );
+ setPosFromAirportIDandHdg( apt, hdg );
+ // fall through to return true
+ } // of need-metar case
+
return true;
}
-bool finalizePosition()
+void finalizePosition()
{
// first call to finalize after an initPosition call
if (global_finalizeTime.get_usec() == 0) {
global_finalizeTime = SGTimeStamp::now();
}
+ bool done = true;
+
/* Scenarios require Nasal, so FGAIManager loads the scenarios,
* including its models such as a/c carriers, in its 'postinit',
* which is the very last thing we do.
// clear preset location and re-trigger position setup
fgSetDouble("/sim/presets/longitude-deg", 9999);
fgSetDouble("/sim/presets/latitude-deg", 9999);
- return initPosition();
+ initPosition();
+ } else {
+ done = finalizeMetar();
+ }
+
+ fgSetBool("/sim/position-finalized", done);
+ if (done) {
+ globals->get_event_mgr()->removeTask("finalizePosition");
+ global_callbackRegistered = false;
}
-
- double hdg = fgGetDouble( "/environment/metar/base-wind-dir-deg", 9999.0 );
- string apt = fgGetString( "/sim/startup/options/airport" );
- string rwy = fgGetString( "/sim/startup/options/runway" );
- double strthdg = fgGetDouble( "/sim/startup/options/heading-deg", 9999.0 );
- string parkpos = fgGetString( "/sim/presets/parkpos" );
- bool onground = fgGetBool( "/sim/presets/onground", false );
-// this logic is taken from former startup.nas
- bool needMetar = (hdg < 360.0) && !apt.empty() && (strthdg > 360.0) &&
- rwy.empty() && onground && parkpos.empty();
-
- if (needMetar) {
- // timeout so we don't spin forever if the network is down
- if (global_finalizeTime.elapsedMSec() > fgGetInt("/sim/startup/metar-fetch-timeout-msec", 5000)) {
- SG_LOG(SG_GENERAL, SG_WARN, "finalizePosition: timed out waiting for METAR fetch");
- return true;
- }
-
- if (!fgGetBool( "/environment/metar/valid" )) {
- // bit hacky - run these two subsystems. We can't run the whole
- // lot since some view things aren't initialised and hence FGLight
- // crashes.
- globals->get_subsystem("http")->update(0.0);
- globals->get_subsystem("environment")->update(0.0);
- return false;
- }
-
- SG_LOG(SG_ENVIRONMENT, SG_INFO,
- "Using METAR for runway selection: '" << fgGetString("/environment/metar/data") << "'" );
- setPosFromAirportIDandHdg( apt, hdg );
- // fall through to return true
- } // of need-metar case
-
- return true;
}
} // of namespace flightgear