// 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
{
+
+/// 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) {
}
// 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;
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;
}
return false;
}
- int gateID;
+ ParkingAssignment pka;
double radius = fgGetDouble("/sim/dimensions/radius-m");
if ((parkpos == string("AVAILABLE")) && (radius > 0)) {
string fltType;
}
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;
}
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;
// 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");
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