X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FMain%2Fpositioninit.cxx;h=816e997831fcaee8cf0fa37668f94c77a36450c2;hb=33425c671d20fc7a7fbb87c2db28aef455b5b5dd;hp=fd5db70b1069253774454940766f7188f4d41848;hpb=b1854459b3100e4c51e3a5704caa4e2c3869228c;p=flightgear.git diff --git a/src/Main/positioninit.cxx b/src/Main/positioninit.cxx index fd5db70b1..816e99783 100644 --- a/src/Main/positioninit.cxx +++ b/src/Main/positioninit.cxx @@ -25,20 +25,30 @@ // simgear #include #include +#include #include "globals.hxx" #include "fg_props.hxx" #include #include -#include +#include #include #include using std::endl; +using std::string; namespace flightgear { + +/// to avoid blocking when metar-fetch is enabled, but the network is +/// 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) { @@ -131,7 +141,7 @@ static void fgApplyStartOffset(const SGGeod& aStartPos, double aHeading, double } // Set current_options lon/lat given an airport id and heading (degrees) -bool setPosFromAirportIDandHdg( const string& id, double tgt_hdg ) { +static bool setPosFromAirportIDandHdg( const string& id, double tgt_hdg ) { if ( id.empty() ) return false; @@ -142,11 +152,23 @@ bool setPosFromAirportIDandHdg( const string& id, double tgt_hdg ) { 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; } @@ -169,7 +191,7 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par return false; } - int gateID; + ParkingAssignment pka; double radius = fgGetDouble("/sim/dimensions/radius-m"); if ((parkpos == string("AVAILABLE")) && (radius > 0)) { string fltType; @@ -203,27 +225,25 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par } string acType; // Currently not used by findAvailable parking, so safe to leave empty. - gateID = dcs->getAvailableParking(radius, fltType, acType, acOperator); - if (gateID >=0 ) { + pka = dcs->getAvailableParking(radius, fltType, acType, acOperator); + if (pka.isValid()) { fgGetString("/sim/presets/parkpos"); - fgSetString("/sim/presets/parkpos", dcs->getParking(gateID)->getName()); + fgSetString("/sim/presets/parkpos", pka.parking()->getName()); } else { SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find a suitable parking at airport " << id ); return false; } } else { - gateID = dcs->findParkingByName(parkpos); - if (gateID < 0) { + pka = dcs->getParkingByName(parkpos); + if (!pka.isValid()) { SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find a parking at airport " << id << ":" << parkpos); return false; } } - FGParking* parking = dcs->getParking(gateID); - parking->setAvailable(false); - fgApplyStartOffset(parking->getGeod(), parking->getHeading()); + fgApplyStartOffset(pka.parking()->geod(), pka.parking()->getHeading()); return true; } @@ -309,7 +329,7 @@ static bool fgSetPosFromNAV( const string& id, const double& freq, FGPositioned: 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; @@ -397,7 +417,12 @@ static bool fgSetPosFromFix( const string& id ) // Set the initial position based on presets (or defaults) bool initPosition() { - // cout << "initPosition()" << endl; + 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"); @@ -540,7 +565,77 @@ bool initPosition() fgSetBool("/sim/presets/onground", true); } + fgSetBool("/sim/position-finalized", false); + + 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; } +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. + * flightgear::initPosition is called very early in main.cxx/fgIdleFunction, + * one of the first things we do, long before scenarios/carriers are + * loaded. => When requested "initial preset position" relates to a + * carrier, recalculate the 'initial' position here + */ + std::string carrier = fgGetString("/sim/presets/carrier",""); + if (!carrier.empty()) + { + SG_LOG(SG_GENERAL, SG_INFO, "finalizePositioned: re-init-ing position on carrier"); + // clear preset location and re-trigger position setup + fgSetDouble("/sim/presets/longitude-deg", 9999); + fgSetDouble("/sim/presets/latitude-deg", 9999); + initPosition(); + } else { + done = finalizeMetar(); + } + + fgSetBool("/sim/position-finalized", done); + if (done) { + globals->get_event_mgr()->removeTask("finalizePosition"); + global_callbackRegistered = false; + } +} + } // of namespace flightgear