X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FMain%2Fpositioninit.cxx;h=337ab7141fdc73e54e0592f4ecaa5c0696159ad8;hb=0c00cd3c6d34e4e167457897a274864cb7236da6;hp=c7c63b5336f586c7079d4448672a076ff7f12675;hpb=487638be7fde7d75466c2df4c9019f7d177f4cff;p=flightgear.git diff --git a/src/Main/positioninit.cxx b/src/Main/positioninit.cxx index c7c63b533..337ab7141 100644 --- a/src/Main/positioninit.cxx +++ b/src/Main/positioninit.cxx @@ -32,11 +32,14 @@ #include #include -#include +#include #include #include +#include + 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(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(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,15 +629,24 @@ 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/startup/options/airport" ); - string rwy = fgGetString( "/sim/startup/options/runway" ); + 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 ); @@ -571,17 +656,17 @@ 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" )) { - // 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; }