]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/positioninit.cxx
Remove confusing reference to SDL/GLUT
[flightgear.git] / src / Main / positioninit.cxx
index fd5db70b1069253774454940766f7188f4d41848..816e997831fcaee8cf0fa37668f94c77a36450c2 100644 (file)
 // 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) {
@@ -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