]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/positioninit.cxx
Update for changed SGPath::realpath signature
[flightgear.git] / src / Main / positioninit.cxx
index eb35799679e013dc0a09cf7a90642fe982603245..337ab7141fdc73e54e0592f4ecaa5c0696159ad8 100644 (file)
 #include <Airports/airport.hxx>
 #include <Airports/dynamics.hxx>
 #include <AIModel/AIManager.hxx>
+#include <GUI/MessageBox.hxx>
+
 
 using std::endl;
+using std::string;
 
 namespace flightgear
 {
@@ -64,7 +67,8 @@ 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))
@@ -81,7 +85,7 @@ struct FGTowerLocationListener : SGPropertyChangeListener {
   }
 };
 
-struct FGClosestTowerLocationListener : SGPropertyChangeListener
+class FGClosestTowerLocationListener : public SGPropertyChangeListener
 {
   void valueChanged(SGPropertyNode* )
   {
@@ -97,9 +101,14 @@ struct FGClosestTowerLocationListener : SGPropertyChangeListener
 };
 
 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)
@@ -151,17 +160,33 @@ static 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;
 }
 
 // Set current_options lon/lat given an airport id and parkig position name
 static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& parkpos )
 {
+  string fltType;
+  string acOperator;
+  string acType; // Currently not used by findAvailable parking, so safe to leave empty.
+  SGPath acData;
   if ( id.empty() )
     return false;
   
@@ -171,7 +196,7 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
     SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport " << id );
     return false;
   }
-  FGAirportDynamics* dcs = apt->getDynamics();
+  FGAirportDynamicsRef dcs = apt->getDynamics();
   if (!dcs) {
     SG_LOG( SG_GENERAL, SG_ALERT,
            "Airport " << id << "does not appear to have parking information available");
@@ -181,39 +206,38 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
   ParkingAssignment pka;
   double radius = fgGetDouble("/sim/dimensions/radius-m");
   if ((parkpos == string("AVAILABLE")) && (radius > 0)) {
-    string fltType;
-    string acOperator;
-    SGPath acData;
+    
     try {
       acData = globals->get_fg_home();
       acData.append("aircraft-data");
       string acfile = fgGetString("/sim/aircraft") + string(".xml");
       acData.append(acfile);
       SGPropertyNode root;
-      readProperties(acData.str(), &root);
+      readProperties(acData, &root);
       SGPropertyNode * node = root.getNode("sim");
       fltType    = node->getStringValue("aircraft-class", "NONE"     );
       acOperator = node->getStringValue("aircraft-operator", "NONE"     );
     } catch (const sg_exception &) {
       SG_LOG(SG_GENERAL, SG_INFO,
-             "Could not load aircraft aircrat type and operator information from: " << acData.str() << ". Using defaults");
+             "Could not load aircraft aircrat type and operator information from: " << acData << ". Using defaults");
       
       // cout << path.str() << endl;
     }
     if (fltType.empty() || fltType == "NONE") {
       SG_LOG(SG_GENERAL, SG_INFO,
-             "Aircraft type information not found in: " << acData.str() << ". Using default value");
+             "Aircraft type information not found in: " << acData << ". Using default value");
       fltType = fgGetString("/sim/aircraft-class"   );
     }
     if (acOperator.empty() || fltType == "NONE") {
       SG_LOG(SG_GENERAL, SG_INFO,
-             "Aircraft operator information not found in: " << acData.str() << ". Using default value");
+             "Aircraft operator information not found in: " << acData << ". Using default value");
       acOperator = fgGetString("/sim/aircraft-operator"   );
     }
     
-    string acType; // Currently not used by findAvailable parking, so safe to leave empty.
+    
     pka = dcs->getAvailableParking(radius, fltType, acType, acOperator);
     if (pka.isValid()) {
+        // why is the following line necessary?
       fgGetString("/sim/presets/parkpos");
       fgSetString("/sim/presets/parkpos", pka.parking()->getName());
     } else {
@@ -222,6 +246,7 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
       return false;
     }
   } else {
+      
     pka = dcs->getParkingByName(parkpos);
     if (!pka.isValid()) {
       SG_LOG( SG_GENERAL, SG_ALERT,
@@ -229,7 +254,14 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
       return false;
     }
   }
-  
+  // Why is the following line necessary?
+  fgGetString("/sim/presets/parkpos");
+  fgSetString("/sim/presets/parkpos", pka.parking()->getName());
+  // The problem is, this line doesn't work because the ParkingAssignment's refcounting mechanism:
+  // The parking will be released after this function returns. 
+  // As a temporary measure, I'll try to reserve the parking via the atc_manager, which should work, because it uses the same 
+  // mechanism as the AI traffic code. 
+  dcs->setParkingAvailable(pka.parking(), false);
   fgApplyStartOffset(pka.parking()->geod(), pka.parking()->getHeading());
   return true;
 }
@@ -250,19 +282,29 @@ static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy, bo
     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,
-           "Failed to find runway " << rwy <<
+
+  if (apt->hasRunwayWithIdent(rwy)) {
+      FGRunway* r(apt->getRunwayByIdent(rwy));
+      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());
+      return true;
+  } else if (apt->hasHelipadWithIdent(rwy)) {
+      FGHelipad* h(apt->getHelipadByIdent(rwy));
+      fgApplyStartOffset(h->geod(), h->headingDeg());
+      return true;
+  }
+
+  if (rwy_req) {
+      flightgear::modalMessageBox("Runway not available", "Runway/helipad "
+                                   + rwy + " not found at airport " + apt->getId()
+                                   + " - " + apt->getName() );
+  } else {
+    SG_LOG( SG_GENERAL, SG_INFO,
+           "Failed to find runway/helipad " << rwy <<
            " at airport " << id << ". Using default runway." );
-    return false;
   }
-  
-  FGRunway* r(apt->getRunwayByIdent(rwy));
-  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());
-  return true;
+  return false;
 }
 
 
@@ -311,37 +353,51 @@ static void fgSetDistOrAltFromGlideSlope() {
 
 
 // Set current_options lon/lat given an airport id and heading (degrees)
-static bool fgSetPosFromNAV( const string& id, const double& freq, FGPositioned::Type type )
+static bool fgSetPosFromNAV( const string& id,
+                             const double& freq,
+                             FGPositioned::Type type,
+                             PositionedID guid)
 {
-  FGNavList::TypeFilter filter(type);
-  const nav_list_type navlist = FGNavList::findByIdentAndFreq( id.c_str(), freq, &filter );
-  
-  if (navlist.size() == 0 ) {
-    SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
-           << id << ":" << freq );
-    return false;
-  }
-  
-  if( navlist.size() > 1 ) {
-    std::ostringstream buf;
-    buf << "Ambigous NAV-ID: '" << id << "'. Specify id and frequency. Available stations:" << endl;
-    for( nav_list_type::const_iterator it = navlist.begin(); it != navlist.end(); ++it ) {
-      // NDB stored in kHz, VOR stored in MHz * 100 :-P
-      double factor = (*it)->type() == FGPositioned::NDB ? 1.0 : 1/100.0;
-      string unit = (*it)->type() == FGPositioned::NDB ? "kHz" : "MHz";
-      buf << (*it)->ident() << " "
-      << std::setprecision(5) << (double)((*it)->get_freq() * factor) << " "
-      << (*it)->get_lat() << "/" << (*it)->get_lon()
-      << endl;
+    FGNavRecord* nav = 0;
+
+
+    if (guid != 0) {
+        nav = FGPositioned::loadById<FGNavRecord>(guid);
+        if (!nav)
+            return false;
+    } else {
+        FGNavList::TypeFilter filter(type);
+        const nav_list_type navlist = FGNavList::findByIdentAndFreq( id.c_str(), freq, &filter );
+
+        if (navlist.empty()) {
+          SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
+                 << id << ":" << freq );
+          return false;
+        }
+
+        if( navlist.size() > 1 ) {
+          std::ostringstream buf;
+          buf << "Ambigous NAV-ID: '" << id << "'. Specify id and frequency. Available stations:" << endl;
+          for( nav_list_type::const_iterator it = navlist.begin(); it != navlist.end(); ++it ) {
+            // NDB stored in kHz, VOR stored in MHz * 100 :-P
+            double factor = (*it)->type() == FGPositioned::NDB ? 1.0 : 1/100.0;
+            string unit = (*it)->type() == FGPositioned::NDB ? "kHz" : "MHz";
+            buf << (*it)->ident() << " "
+            << std::setprecision(5) << (double)((*it)->get_freq() * factor) << " "
+            << (*it)->get_lat() << "/" << (*it)->get_lon()
+            << endl;
+          }
+
+          SG_LOG( SG_GENERAL, SG_ALERT, buf.str() );
+          return false;
+        }
+
+        // nav list must be of length 1
+        nav = navlist[0];
     }
-    
-    SG_LOG( SG_GENERAL, SG_ALERT, buf.str() );
-    return false;
-  }
-  
-  FGNavRecord *nav = navlist[0];
-  fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg"));
-  return true;
+
+    fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg"));
+    return true;
 }
 
 // Set current_options lon/lat given an aircraft carrier id
@@ -387,11 +443,17 @@ static bool fgSetPosFromCarrier( const string& carrier, const string& posid ) {
   }
 }
 
-// Set current_options lon/lat given an airport id and heading (degrees)
-static bool fgSetPosFromFix( const string& id )
+// Set current_options lon/lat given a fix ident and GUID
+static bool fgSetPosFromFix( const string& id, PositionedID guid )
 {
-  FGPositioned::TypeFilter fixFilter(FGPositioned::FIX);
-  FGPositioned* fix = FGPositioned::findFirstWithIdent(id, &fixFilter);
+    FGPositioned* fix = NULL;
+    if (guid != 0) {
+        fix = FGPositioned::loadById<FGPositioned>(guid);
+    } else {
+        FGPositioned::TypeFilter fixFilter(FGPositioned::FIX);
+        fix = FGPositioned::findFirstWithIdent(id, &fixFilter);
+    }
+
   if (!fix) {
     SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate fix = " << id );
     return false;
@@ -449,6 +511,10 @@ bool initPosition()
   string carrier = fgGetString("/sim/presets/carrier");
   string parkpos = fgGetString("/sim/presets/parkpos");
   string fix = fgGetString("/sim/presets/fix");
+
+  // the launcher sets this to precisely identify a navaid
+    PositionedID navaidId = fgGetInt("/sim/presets/navaid-id");
+
   SGPropertyNode *hdg_preset = fgGetNode("/sim/presets/heading-deg", true);
   double hdg = hdg_preset->getDoubleValue();
   
@@ -506,14 +572,14 @@ bool initPosition()
   
   if ( !set_pos && !vor.empty() ) {
     // a VOR is requested
-    if ( fgSetPosFromNAV( vor, vor_freq, FGPositioned::VOR ) ) {
+    if ( fgSetPosFromNAV( vor, vor_freq, FGPositioned::VOR, navaidId ) ) {
       set_pos = true;
     }
   }
   
   if ( !set_pos && !ndb.empty() ) {
     // an NDB is requested
-    if ( fgSetPosFromNAV( ndb, ndb_freq, FGPositioned::NDB ) ) {
+    if ( fgSetPosFromNAV( ndb, ndb_freq, FGPositioned::NDB, navaidId ) ) {
       set_pos = true;
     }
   }
@@ -527,16 +593,26 @@ bool initPosition()
   
   if ( !set_pos && !fix.empty() ) {
     // a Fix is requested
-    if ( fgSetPosFromFix( fix ) ) {
+    if ( fgSetPosFromFix( fix, navaidId ) ) {
       set_pos = true;
     }
   }
   
   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);
+    // No lon/lat specified, no airport specified, use the default airport
+    // TODO: don't hardcode this
+    const FGAirport* airport = fgFindAirportID("LEBL");
+    if( airport ) {
+      const SGGeod & airportGeod = airport->geod();
+      fgSetDouble("/sim/presets/longitude-deg", airportGeod.getLongitudeDeg());
+      fgSetDouble("/sim/presets/latitude-deg", airportGeod.getLatitudeDeg());
+    } else {
+      // So, the default airport is unknown? We are in serious trouble. 
+      // Let's hope KSFO still exists somehow
+      fgSetDouble("/sim/presets/longitude-deg", -122.374843);
+      fgSetDouble("/sim/presets/latitude-deg", 37.619002);
+      SG_LOG(SG_GENERAL, SG_ALERT, "Sorry, the default airport seems to be unknown.");
+    }
   }
   
   fgSetDouble( "/position/longitude-deg",
@@ -553,12 +629,21 @@ bool initPosition()
   }
   
   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()
 {
+  if (!fgGetBool("/environment/realwx/enabled")) {
+    return true;
+  }
+  
   double hdg = fgGetDouble( "/environment/metar/base-wind-dir-deg", 9999.0 );
   string apt = fgGetString("/sim/presets/airport-id");
   string rwy = fgGetString("/sim/presets/runway");
@@ -571,11 +656,16 @@ bool finalizeMetar()
   
   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)) {
+    if (global_finalizeTime.elapsedMSec() > fgGetInt("/sim/startup/metar-fetch-timeout-msec", 6000)) {
       SG_LOG(SG_GENERAL, SG_WARN, "finalizePosition: timed out waiting for METAR fetch");
       return true;
     }
     
+    if (fgGetBool( "/environment/metar/failure" )) {
+      SG_LOG(SG_ENVIRONMENT, SG_INFO, "metar download failed, not waiting");
+      return true;
+    }
+
     if (!fgGetBool( "/environment/metar/valid" )) {
       return false;
     }