diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt index e6ce58f0f..78b93e346 100644 --- a/src/Main/CMakeLists.txt +++ b/src/Main/CMakeLists.txt @@ -20,6 +20,7 @@ set(SOURCES main.cxx options.cxx util.cxx + positioninit.cxx ${RESOURCE_FILE} ) @@ -34,6 +35,7 @@ set(HEADERS main.hxx options.hxx util.hxx + positioninit.hxx ) get_property(FG_SOURCES GLOBAL PROPERTY FG_SOURCES) diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index b248e1383..f9efa5b47 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -49,6 +49,7 @@ #include "logger.hxx" #include "util.hxx" #include "main.hxx" +#include "positioninit.hxx" #include @@ -1228,7 +1229,7 @@ do_presets_commit (const SGPropertyNode * arg) // Nasal can trigger this during initial init, which confuses // the logic in ReInitSubsystems, since initial state has not been // saved at that time. Short-circuit everything here. - fgInitPosition(); + flightgear::initPosition(); } return true; diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index a5fb21fee..b7cf36058 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -116,7 +116,7 @@ #include "globals.hxx" #include "logger.hxx" #include "main.hxx" - +#include "positioninit.hxx" using std::string; using namespace boost::algorithm; @@ -454,365 +454,6 @@ bool fgInitConfig ( int argc, char **argv ) return true; } -// Set current tower position lon/lat given an airport id -static bool fgSetTowerPosFromAirportID( const string& id) { - const FGAirport *a = fgFindAirportID( id); - if (a) { - SGGeod tower = a->getTowerLocation(); - fgSetDouble("/sim/tower/longitude-deg", tower.getLongitudeDeg()); - fgSetDouble("/sim/tower/latitude-deg", tower.getLatitudeDeg()); - fgSetDouble("/sim/tower/altitude-ft", tower.getElevationFt()); - return true; - } else { - return false; - } - -} - -struct FGTowerLocationListener : SGPropertyChangeListener { - void valueChanged(SGPropertyNode* node) { - string id(node->getStringValue()); - if (fgGetBool("/sim/tower/auto-position",true)) - { - // enforce using closest airport when auto-positioning is enabled - const char* closest_airport = fgGetString("/sim/airport/closest-airport-id", ""); - if (closest_airport && (id != closest_airport)) - { - id = closest_airport; - node->setStringValue(id); - } - } - fgSetTowerPosFromAirportID(id); - } -}; - -struct FGClosestTowerLocationListener : SGPropertyChangeListener -{ - void valueChanged(SGPropertyNode* ) - { - // closest airport has changed - if (fgGetBool("/sim/tower/auto-position",true)) - { - // update tower position - const char* id = fgGetString("/sim/airport/closest-airport-id", ""); - if (id && *id!=0) - fgSetString("/sim/tower/airport-id", id); - } - } -}; - -void fgInitTowerLocationListener() { - fgGetNode("/sim/tower/airport-id", true) - ->addChangeListener( new FGTowerLocationListener(), true ); - FGClosestTowerLocationListener* ntcl = new FGClosestTowerLocationListener(); - fgGetNode("/sim/airport/closest-airport-id", true) - ->addChangeListener(ntcl , true ); - fgGetNode("/sim/tower/auto-position", true) - ->addChangeListener(ntcl, true ); -} - -static void fgApplyStartOffset(const SGGeod& aStartPos, double aHeading, double aTargetHeading = HUGE_VAL) -{ - SGGeod startPos(aStartPos); - if (aTargetHeading == HUGE_VAL) { - aTargetHeading = aHeading; - } - - if ( fabs( fgGetDouble("/sim/presets/offset-distance-nm") ) > SG_EPSILON ) { - double offsetDistance = fgGetDouble("/sim/presets/offset-distance-nm"); - offsetDistance *= SG_NM_TO_METER; - double offsetAzimuth = aHeading; - if ( fabs(fgGetDouble("/sim/presets/offset-azimuth-deg")) > SG_EPSILON ) { - offsetAzimuth = fgGetDouble("/sim/presets/offset-azimuth-deg"); - aHeading = aTargetHeading; - } - - SGGeod offset; - double az2; // dummy - SGGeodesy::direct(startPos, offsetAzimuth + 180, offsetDistance, offset, az2); - startPos = offset; - } - - // presets - fgSetDouble("/sim/presets/longitude-deg", startPos.getLongitudeDeg() ); - fgSetDouble("/sim/presets/latitude-deg", startPos.getLatitudeDeg() ); - fgSetDouble("/sim/presets/heading-deg", aHeading ); - - // other code depends on the actual values being set ... - fgSetDouble("/position/longitude-deg", startPos.getLongitudeDeg() ); - fgSetDouble("/position/latitude-deg", startPos.getLatitudeDeg() ); - fgSetDouble("/orientation/heading-deg", aHeading ); -} - -// Set current_options lon/lat given an airport id and heading (degrees) -bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) { - if ( id.empty() ) - return false; - - // set initial position from runway and heading - SG_LOG( SG_GENERAL, SG_INFO, - "Attempting to set starting position from airport code " - << id << " heading " << 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); - return true; -} - -// Set current_options lon/lat given an airport id and parkig position name -static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& parkpos ) { - if ( id.empty() ) - return false; - - // can't see an easy way around this const_cast at the moment - FGAirport* apt = const_cast(fgFindAirportID(id)); - if (!apt) { - SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport " << id ); - return false; - } - FGAirportDynamics* dcs = apt->getDynamics(); - if (!dcs) { - SG_LOG( SG_GENERAL, SG_ALERT, - "Airport " << id << "does not appear to have parking information available"); - return false; - } - - int park_index = dcs->getNrOfParkings() - 1; - bool succes; - double radius = fgGetDouble("/sim/dimensions/radius-m"); - if ((parkpos == string("AVAILABLE")) && (radius > 0)) { - double lat, lon, heading; - 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); - 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"); - - // 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"); - 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"); - acOperator = fgGetString("/sim/aircraft-operator" ); - } - - cerr << "Running aircraft " << fltType << " of livery " << acOperator << endl; - string acType; // Currently not used by findAvailable parking, so safe to leave empty. - succes = dcs->getAvailableParking(&lat, &lon, &heading, &park_index, radius, fltType, acType, acOperator); - if (succes) { - fgGetString("/sim/presets/parkpos"); - fgSetString("/sim/presets/parkpos", dcs->getParking(park_index)->getName()); - } else { - SG_LOG( SG_GENERAL, SG_ALERT, - "Failed to find a suitable parking at airport " << id ); - return false; - } - } else { - //cerr << "We shouldn't get here when AVAILABLE" << endl; - while (park_index >= 0 && dcs->getParkingName(park_index) != parkpos) park_index--; - if (park_index < 0) { - SG_LOG( SG_GENERAL, SG_ALERT, - "Failed to find parking position " << parkpos << - " at airport " << id ); - return false; - } - } - FGParking* parking = dcs->getParking(park_index); - parking->setAvailable(false); - fgApplyStartOffset( - SGGeod::fromDeg(parking->getLongitude(), parking->getLatitude()), - parking->getHeading()); - return true; -} - - -// Set current_options lon/lat given an airport id and runway number -static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy, bool rwy_req ) { - if ( id.empty() ) - return false; - - // set initial position from airport and runway number - SG_LOG( SG_GENERAL, SG_INFO, - "Attempting to set starting position for " - << id << ":" << rwy ); - - const FGAirport* apt = fgFindAirportID(id); - if (!apt) { - 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 << - " 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; -} - - -static void fgSetDistOrAltFromGlideSlope() { - // cout << "fgSetDistOrAltFromGlideSlope()" << endl; - string apt_id = fgGetString("/sim/presets/airport-id"); - double gs = fgGetDouble("/sim/presets/glideslope-deg") - * SG_DEGREES_TO_RADIANS ; - double od = fgGetDouble("/sim/presets/offset-distance-nm"); - double alt = fgGetDouble("/sim/presets/altitude-ft"); - - double apt_elev = 0.0; - if ( ! apt_id.empty() ) { - apt_elev = fgGetAirportElev( apt_id ); - if ( apt_elev < -9990.0 ) { - apt_elev = 0.0; - } - } else { - apt_elev = 0.0; - } - - if( fabs(gs) > 0.01 && fabs(od) > 0.1 && alt < -9990 ) { - // set altitude from glideslope and offset-distance - od *= SG_NM_TO_METER * SG_METER_TO_FEET; - alt = fabs(od*tan(gs)) + apt_elev; - fgSetDouble("/sim/presets/altitude-ft", alt); - fgSetBool("/sim/presets/onground", false); - SG_LOG( SG_GENERAL, SG_INFO, "Calculated altitude as: " - << alt << " ft" ); - } else if( fabs(gs) > 0.01 && alt > 0 && fabs(od) < 0.1) { - // set offset-distance from glideslope and altitude - od = (alt - apt_elev) / tan(gs); - od *= -1*SG_FEET_TO_METER * SG_METER_TO_NM; - fgSetDouble("/sim/presets/offset-distance-nm", od); - fgSetBool("/sim/presets/onground", false); - SG_LOG( SG_GENERAL, SG_INFO, "Calculated offset distance as: " - << od << " nm" ); - } else if( fabs(gs) > 0.01 ) { - SG_LOG( SG_GENERAL, SG_ALERT, - "Glideslope given but not altitude or offset-distance." ); - SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" ); - fgSetDouble("/sim/presets/glideslope-deg", 0); - fgSetBool("/sim/presets/onground", true); - } -} - - -// Set current_options lon/lat given an airport id and heading (degrees) -static bool fgSetPosFromNAV( const string& id, const double& freq, FGPositioned::Type type ) { - - const nav_list_type navlist - = globals->get_navlist()->findByIdentAndFreq( id.c_str(), freq, type ); - - if (navlist.size() == 0 ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = " - << id << ":" << freq ); - return false; - } - - if( navlist.size() > 1 ) { - 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() << " " - << setprecision(5) << (double)((*it)->get_freq() * factor) << " " - << (*it)->get_lat() << "/" << (*it)->get_lon() - << endl; - } - - SG_LOG( SG_GENERAL, SG_ALERT, buf.str() ); - return false; - } - - FGNavRecord *nav = navlist[0]; - fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg")); - return true; -} - -// Set current_options lon/lat given an aircraft carrier id -static bool fgSetPosFromCarrier( const string& carrier, const string& posid ) { - - // set initial position from runway and heading - SGGeod geodPos; - double heading; - SGVec3d uvw; - if (FGAIManager::getStartPosition(carrier, posid, geodPos, heading, uvw)) { - double lon = geodPos.getLongitudeDeg(); - double lat = geodPos.getLatitudeDeg(); - double alt = geodPos.getElevationFt(); - - SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for " - << carrier << " at lat = " << lat << ", lon = " << lon - << ", alt = " << alt << ", heading = " << heading); - - fgSetDouble("/sim/presets/longitude-deg", lon); - fgSetDouble("/sim/presets/latitude-deg", lat); - fgSetDouble("/sim/presets/altitude-ft", alt); - fgSetDouble("/sim/presets/heading-deg", heading); - fgSetDouble("/position/longitude-deg", lon); - fgSetDouble("/position/latitude-deg", lat); - fgSetDouble("/position/altitude-ft", alt); - fgSetDouble("/orientation/heading-deg", heading); - - fgSetString("/sim/presets/speed-set", "UVW"); - fgSetDouble("/velocities/uBody-fps", uvw(0)); - fgSetDouble("/velocities/vBody-fps", uvw(1)); - fgSetDouble("/velocities/wBody-fps", uvw(2)); - fgSetDouble("/sim/presets/uBody-fps", uvw(0)); - fgSetDouble("/sim/presets/vBody-fps", uvw(1)); - fgSetDouble("/sim/presets/wBody-fps", uvw(2)); - - fgSetBool("/sim/presets/onground", true); - - return true; - } else { - SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = " - << carrier ); - return false; - } -} - -// Set current_options lon/lat given an airport id and heading (degrees) -static bool fgSetPosFromFix( const string& id ) -{ - FGPositioned::TypeFilter fixFilter(FGPositioned::FIX); - FGPositioned* fix = FGPositioned::findNextWithPartialId(NULL, id, &fixFilter); - if (!fix) { - SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate fix = " << id ); - return false; - } - - fgApplyStartOffset(fix->geod(), fgGetDouble("/sim/presets/heading-deg")); - return true; -} - /** * Initialize vor/ndb/ils/fix list management and query systems (as * well as simple airport db list) @@ -820,199 +461,49 @@ static bool fgSetPosFromFix( const string& id ) bool fgInitNav () { - SG_LOG(SG_GENERAL, SG_INFO, "Loading Airport Database ..."); - - SGPath aptdb( globals->get_fg_root() ); - aptdb.append( "Airports/apt.dat" ); - - SGPath p_metar( globals->get_fg_root() ); - p_metar.append( "Airports/metar.dat" ); - - fgAirportDBLoad( aptdb.str(), p_metar.str() ); - - FGNavList *navlist = new FGNavList; - FGNavList *loclist = new FGNavList; - FGNavList *gslist = new FGNavList; - FGNavList *dmelist = new FGNavList; - FGNavList *tacanlist = new FGNavList; - FGNavList *carrierlist = new FGNavList; - FGTACANList *channellist = new FGTACANList; - - globals->set_navlist( navlist ); - globals->set_loclist( loclist ); - globals->set_gslist( gslist ); - globals->set_dmelist( dmelist ); - globals->set_tacanlist( tacanlist ); - globals->set_carrierlist( carrierlist ); - globals->set_channellist( channellist ); - - if ( !fgNavDBInit(navlist, loclist, gslist, dmelist, tacanlist, carrierlist, channellist) ) { - SG_LOG( SG_GENERAL, SG_ALERT, - "Problems loading one or more navigational database" ); - } - - SG_LOG(SG_GENERAL, SG_INFO, " Fixes"); - SGPath p_fix( globals->get_fg_root() ); - p_fix.append( "Navaids/fix.dat" ); - FGFixList fixlist; - fixlist.init( p_fix ); // adds fixes to the DB in positioned.cxx - - SG_LOG(SG_GENERAL, SG_INFO, " Airways"); - flightgear::Airway::load(); - - return true; + SG_LOG(SG_GENERAL, SG_INFO, "Loading Airport Database ..."); + + SGPath aptdb( globals->get_fg_root() ); + aptdb.append( "Airports/apt.dat" ); + + SGPath p_metar( globals->get_fg_root() ); + p_metar.append( "Airports/metar.dat" ); + + fgAirportDBLoad( aptdb.str(), p_metar.str() ); + + FGNavList *navlist = new FGNavList; + FGNavList *loclist = new FGNavList; + FGNavList *gslist = new FGNavList; + FGNavList *dmelist = new FGNavList; + FGNavList *tacanlist = new FGNavList; + FGNavList *carrierlist = new FGNavList; + FGTACANList *channellist = new FGTACANList; + + globals->set_navlist( navlist ); + globals->set_loclist( loclist ); + globals->set_gslist( gslist ); + globals->set_dmelist( dmelist ); + globals->set_tacanlist( tacanlist ); + globals->set_carrierlist( carrierlist ); + globals->set_channellist( channellist ); + + if ( !fgNavDBInit(navlist, loclist, gslist, dmelist, tacanlist, carrierlist, channellist) ) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Problems loading one or more navigational database" ); + } + + SG_LOG(SG_GENERAL, SG_INFO, " Fixes"); + SGPath p_fix( globals->get_fg_root() ); + p_fix.append( "Navaids/fix.dat" ); + FGFixList fixlist; + fixlist.init( p_fix ); // adds fixes to the DB in positioned.cxx + + SG_LOG(SG_GENERAL, SG_INFO, " Airways"); + flightgear::Airway::load(); + + return true; } - -// Set the initial position based on presets (or defaults) -bool fgInitPosition() { - // cout << "fgInitPosition()" << endl; - double gs = fgGetDouble("/sim/presets/glideslope-deg") - * SG_DEGREES_TO_RADIANS ; - double od = fgGetDouble("/sim/presets/offset-distance-nm"); - double alt = fgGetDouble("/sim/presets/altitude-ft"); - - bool set_pos = false; - - // If glideslope is specified, then calculate offset-distance or - // altitude relative to glide slope if either of those was not - // specified. - if ( fabs( gs ) > 0.01 ) { - fgSetDistOrAltFromGlideSlope(); - } - - - // If we have an explicit, in-range lon/lat, don't change it, just use it. - // If not, check for an airport-id and use that. - // If not, default to the middle of the KSFO field. - // The default values for lon/lat are deliberately out of range - // so that the airport-id can take effect; valid lon/lat will - // override airport-id, however. - double lon_deg = fgGetDouble("/sim/presets/longitude-deg"); - double lat_deg = fgGetDouble("/sim/presets/latitude-deg"); - if ( lon_deg >= -180.0 && lon_deg <= 180.0 - && lat_deg >= -90.0 && lat_deg <= 90.0 ) - { - set_pos = true; - } - - string apt = fgGetString("/sim/presets/airport-id"); - string rwy_no = fgGetString("/sim/presets/runway"); - bool rwy_req = fgGetBool("/sim/presets/runway-requested"); - string vor = fgGetString("/sim/presets/vor-id"); - double vor_freq = fgGetDouble("/sim/presets/vor-freq"); - string ndb = fgGetString("/sim/presets/ndb-id"); - double ndb_freq = fgGetDouble("/sim/presets/ndb-freq"); - string carrier = fgGetString("/sim/presets/carrier"); - string parkpos = fgGetString("/sim/presets/parkpos"); - string fix = fgGetString("/sim/presets/fix"); - SGPropertyNode *hdg_preset = fgGetNode("/sim/presets/heading-deg", true); - double hdg = hdg_preset->getDoubleValue(); - - // save some start parameters, so that we can later say what the - // user really requested. TODO generalize that and move it to options.cxx - static bool start_options_saved = false; - if (!start_options_saved) { - start_options_saved = true; - SGPropertyNode *opt = fgGetNode("/sim/startup/options", true); - - opt->setDoubleValue("latitude-deg", lat_deg); - opt->setDoubleValue("longitude-deg", lon_deg); - opt->setDoubleValue("heading-deg", hdg); - opt->setStringValue("airport", apt.c_str()); - opt->setStringValue("runway", rwy_no.c_str()); - } - - if (hdg > 9990.0) - hdg = fgGetDouble("/environment/config/boundary/entry/wind-from-heading-deg", 270); - - if ( !set_pos && !apt.empty() && !parkpos.empty() ) { - // An airport + parking position is requested - if ( fgSetPosFromAirportIDandParkpos( apt, parkpos ) ) { - // set tower position - fgSetString("/sim/airport/closest-airport-id", apt.c_str()); - fgSetString("/sim/tower/airport-id", apt.c_str()); - set_pos = true; - } - } - - if ( !set_pos && !apt.empty() && !rwy_no.empty() ) { - // An airport + runway is requested - if ( fgSetPosFromAirportIDandRwy( apt, rwy_no, rwy_req ) ) { - // set tower position (a little off the heading for single - // runway airports) - fgSetString("/sim/airport/closest-airport-id", apt.c_str()); - fgSetString("/sim/tower/airport-id", apt.c_str()); - set_pos = true; - } - } - - if ( !set_pos && !apt.empty() ) { - // An airport is requested (find runway closest to hdg) - if ( fgSetPosFromAirportIDandHdg( apt, hdg ) ) { - // set tower position (a little off the heading for single - // runway airports) - fgSetString("/sim/airport/closest-airport-id", apt.c_str()); - fgSetString("/sim/tower/airport-id", apt.c_str()); - set_pos = true; - } - } - - if (hdg_preset->getDoubleValue() > 9990.0) - hdg_preset->setDoubleValue(hdg); - - if ( !set_pos && !vor.empty() ) { - // a VOR is requested - if ( fgSetPosFromNAV( vor, vor_freq, FGPositioned::VOR ) ) { - set_pos = true; - } - } - - if ( !set_pos && !ndb.empty() ) { - // an NDB is requested - if ( fgSetPosFromNAV( ndb, ndb_freq, FGPositioned::NDB ) ) { - set_pos = true; - } - } - - if ( !set_pos && !carrier.empty() ) { - // an aircraft carrier is requested - if ( fgSetPosFromCarrier( carrier, parkpos ) ) { - set_pos = true; - } - } - - if ( !set_pos && !fix.empty() ) { - // a Fix is requested - if ( fgSetPosFromFix( fix ) ) { - 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); - } - - fgSetDouble( "/position/longitude-deg", - fgGetDouble("/sim/presets/longitude-deg") ); - fgSetDouble( "/position/latitude-deg", - fgGetDouble("/sim/presets/latitude-deg") ); - fgSetDouble( "/orientation/heading-deg", hdg_preset->getDoubleValue()); - - // determine if this should be an on-ground or in-air start - if ((fabs(gs) > 0.01 || fabs(od) > 0.1 || alt > 0.1) && carrier.empty()) { - fgSetBool("/sim/presets/onground", false); - } else { - fgSetBool("/sim/presets/onground", true); - } - - return true; -} - - // General house keeping initializations bool fgInitGeneral() { string root; @@ -1304,7 +795,7 @@ void fgPostInitSubsystems() // clear preset location and re-trigger position setup fgSetDouble("/sim/presets/longitude-deg", 9999); fgSetDouble("/sim/presets/latitude-deg", 9999); - fgInitPosition(); + flightgear::initPosition(); } } @@ -1349,7 +840,7 @@ void fgReInitSubsystems() globals->restoreInitialState(); // update our position based on current presets - fgInitPosition(); + flightgear::initPosition(); // Force reupdating the positions of the ai 3d models. They are used for // initializing ground level for the FDM. diff --git a/src/Main/fg_init.hxx b/src/Main/fg_init.hxx index 03e12cd32..f5215bb72 100644 --- a/src/Main/fg_init.hxx +++ b/src/Main/fg_init.hxx @@ -61,13 +61,6 @@ void fgPostInitSubsystems(); // Reset: this is what the 'reset' command (and hence, GUI) is attached to void fgReInitSubsystems(); -// Set the initial position based on presets (or defaults) -bool fgInitPosition(); - - -// Listen to /sim/tower/airport-id and set tower view position accordingly -void fgInitTowerLocationListener(); - /* * Search in the current directory, and in on directory deeper * for -set.xml configuration files and show the aircaft name diff --git a/src/Main/main.cxx b/src/Main/main.cxx index b682bafbd..31058c2fb 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -68,6 +68,7 @@ #include "fg_init.hxx" #include "fg_os.hxx" #include "fg_props.hxx" +#include "positioninit.hxx" using namespace flightgear; @@ -226,8 +227,8 @@ static void fgIdleFunction ( void ) { idle_state+=2; // based on the requested presets, calculate the true starting // lon, lat - fgInitPosition(); - fgInitTowerLocationListener(); + flightgear::initPosition(); + flightgear::initTowerLocationListener(); TimeManager* t = new TimeManager; globals->add_subsystem("time", t, SGSubsystemMgr::INIT); @@ -320,7 +321,7 @@ static void fgIdleFunction ( void ) { // the other logic is taken from former startup.nas if( hdg < 360.0 && apt.length() > 0 && strthdg > 360.0 && rwy.length() == 0 && onground && parkpos.length() == 0 ) { extern bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ); - fgSetPosFromAirportIDandHdg( apt, hdg ); + flightgear::setPosFromAirportIDandHdg( apt, hdg ); } } else { SG_LOG(SG_ENVIRONMENT, SG_INFO, diff --git a/src/Main/positioninit.cxx b/src/Main/positioninit.cxx new file mode 100644 index 000000000..3a9aaca7e --- /dev/null +++ b/src/Main/positioninit.cxx @@ -0,0 +1,549 @@ +// positioninit.cxx - helpers relating to setting initial aircraft position +// +// Copyright (C) 2012 James Turner zakalawe@mac.com +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "positioninit.hxx" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +// simgear +#include + +#include "globals.hxx" +#include "fg_props.hxx" + +#include +#include +#include +#include +#include + +using std::endl; + +namespace flightgear +{ + +// Set current tower position lon/lat given an airport id +static bool fgSetTowerPosFromAirportID( const string& id) { + const FGAirport *a = fgFindAirportID( id); + if (a) { + SGGeod tower = a->getTowerLocation(); + fgSetDouble("/sim/tower/longitude-deg", tower.getLongitudeDeg()); + fgSetDouble("/sim/tower/latitude-deg", tower.getLatitudeDeg()); + fgSetDouble("/sim/tower/altitude-ft", tower.getElevationFt()); + return true; + } else { + return false; + } + +} + +struct FGTowerLocationListener : SGPropertyChangeListener { + void valueChanged(SGPropertyNode* node) { + string id(node->getStringValue()); + if (fgGetBool("/sim/tower/auto-position",true)) + { + // enforce using closest airport when auto-positioning is enabled + const char* closest_airport = fgGetString("/sim/airport/closest-airport-id", ""); + if (closest_airport && (id != closest_airport)) + { + id = closest_airport; + node->setStringValue(id); + } + } + fgSetTowerPosFromAirportID(id); + } +}; + +struct FGClosestTowerLocationListener : SGPropertyChangeListener +{ + void valueChanged(SGPropertyNode* ) + { + // closest airport has changed + if (fgGetBool("/sim/tower/auto-position",true)) + { + // update tower position + const char* id = fgGetString("/sim/airport/closest-airport-id", ""); + if (id && *id!=0) + fgSetString("/sim/tower/airport-id", id); + } + } +}; + +void initTowerLocationListener() { + fgGetNode("/sim/tower/airport-id", true) + ->addChangeListener( new FGTowerLocationListener(), true ); + FGClosestTowerLocationListener* ntcl = new FGClosestTowerLocationListener(); + fgGetNode("/sim/airport/closest-airport-id", true) + ->addChangeListener(ntcl , true ); + fgGetNode("/sim/tower/auto-position", true) + ->addChangeListener(ntcl, true ); +} + +static void fgApplyStartOffset(const SGGeod& aStartPos, double aHeading, double aTargetHeading = HUGE_VAL) +{ + SGGeod startPos(aStartPos); + if (aTargetHeading == HUGE_VAL) { + aTargetHeading = aHeading; + } + + if ( fabs( fgGetDouble("/sim/presets/offset-distance-nm") ) > SG_EPSILON ) { + double offsetDistance = fgGetDouble("/sim/presets/offset-distance-nm"); + offsetDistance *= SG_NM_TO_METER; + double offsetAzimuth = aHeading; + if ( fabs(fgGetDouble("/sim/presets/offset-azimuth-deg")) > SG_EPSILON ) { + offsetAzimuth = fgGetDouble("/sim/presets/offset-azimuth-deg"); + aHeading = aTargetHeading; + } + + SGGeod offset; + double az2; // dummy + SGGeodesy::direct(startPos, offsetAzimuth + 180, offsetDistance, offset, az2); + startPos = offset; + } + + // presets + fgSetDouble("/sim/presets/longitude-deg", startPos.getLongitudeDeg() ); + fgSetDouble("/sim/presets/latitude-deg", startPos.getLatitudeDeg() ); + fgSetDouble("/sim/presets/heading-deg", aHeading ); + + // other code depends on the actual values being set ... + fgSetDouble("/position/longitude-deg", startPos.getLongitudeDeg() ); + fgSetDouble("/position/latitude-deg", startPos.getLatitudeDeg() ); + fgSetDouble("/orientation/heading-deg", aHeading ); +} + +// Set current_options lon/lat given an airport id and heading (degrees) +bool setPosFromAirportIDandHdg( const string& id, double tgt_hdg ) { + if ( id.empty() ) + return false; + + // set initial position from runway and heading + SG_LOG( SG_GENERAL, SG_INFO, + "Attempting to set starting position from airport code " + << id << " heading " << 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); + return true; +} + +// Set current_options lon/lat given an airport id and parkig position name +static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& parkpos ) { + if ( id.empty() ) + return false; + + // can't see an easy way around this const_cast at the moment + FGAirport* apt = const_cast(fgFindAirportID(id)); + if (!apt) { + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport " << id ); + return false; + } + FGAirportDynamics* dcs = apt->getDynamics(); + if (!dcs) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Airport " << id << "does not appear to have parking information available"); + return false; + } + + int park_index = dcs->getNrOfParkings() - 1; + bool succes; + double radius = fgGetDouble("/sim/dimensions/radius-m"); + if ((parkpos == string("AVAILABLE")) && (radius > 0)) { + double lat, lon, heading; + 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); + 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"); + + // 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"); + 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"); + acOperator = fgGetString("/sim/aircraft-operator" ); + } + + string acType; // Currently not used by findAvailable parking, so safe to leave empty. + succes = dcs->getAvailableParking(&lat, &lon, &heading, &park_index, radius, fltType, acType, acOperator); + if (succes) { + fgGetString("/sim/presets/parkpos"); + fgSetString("/sim/presets/parkpos", dcs->getParking(park_index)->getName()); + } else { + SG_LOG( SG_GENERAL, SG_ALERT, + "Failed to find a suitable parking at airport " << id ); + return false; + } + } else { + //cerr << "We shouldn't get here when AVAILABLE" << endl; + while (park_index >= 0 && dcs->getParkingName(park_index) != parkpos) park_index--; + if (park_index < 0) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Failed to find parking position " << parkpos << + " at airport " << id ); + return false; + } + } + FGParking* parking = dcs->getParking(park_index); + parking->setAvailable(false); + fgApplyStartOffset( + SGGeod::fromDeg(parking->getLongitude(), parking->getLatitude()), + parking->getHeading()); + return true; +} + + +// Set current_options lon/lat given an airport id and runway number +static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy, bool rwy_req ) { + if ( id.empty() ) + return false; + + // set initial position from airport and runway number + SG_LOG( SG_GENERAL, SG_INFO, + "Attempting to set starting position for " + << id << ":" << rwy ); + + const FGAirport* apt = fgFindAirportID(id); + if (!apt) { + 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 << + " 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; +} + + +static void fgSetDistOrAltFromGlideSlope() { + // cout << "fgSetDistOrAltFromGlideSlope()" << endl; + string apt_id = fgGetString("/sim/presets/airport-id"); + double gs = fgGetDouble("/sim/presets/glideslope-deg") + * SG_DEGREES_TO_RADIANS ; + double od = fgGetDouble("/sim/presets/offset-distance-nm"); + double alt = fgGetDouble("/sim/presets/altitude-ft"); + + double apt_elev = 0.0; + if ( ! apt_id.empty() ) { + apt_elev = fgGetAirportElev( apt_id ); + if ( apt_elev < -9990.0 ) { + apt_elev = 0.0; + } + } else { + apt_elev = 0.0; + } + + if( fabs(gs) > 0.01 && fabs(od) > 0.1 && alt < -9990 ) { + // set altitude from glideslope and offset-distance + od *= SG_NM_TO_METER * SG_METER_TO_FEET; + alt = fabs(od*tan(gs)) + apt_elev; + fgSetDouble("/sim/presets/altitude-ft", alt); + fgSetBool("/sim/presets/onground", false); + SG_LOG( SG_GENERAL, SG_INFO, "Calculated altitude as: " + << alt << " ft" ); + } else if( fabs(gs) > 0.01 && alt > 0 && fabs(od) < 0.1) { + // set offset-distance from glideslope and altitude + od = (alt - apt_elev) / tan(gs); + od *= -1*SG_FEET_TO_METER * SG_METER_TO_NM; + fgSetDouble("/sim/presets/offset-distance-nm", od); + fgSetBool("/sim/presets/onground", false); + SG_LOG( SG_GENERAL, SG_INFO, "Calculated offset distance as: " + << od << " nm" ); + } else if( fabs(gs) > 0.01 ) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Glideslope given but not altitude or offset-distance." ); + SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" ); + fgSetDouble("/sim/presets/glideslope-deg", 0); + fgSetBool("/sim/presets/onground", true); + } +} + + +// Set current_options lon/lat given an airport id and heading (degrees) +static bool fgSetPosFromNAV( const string& id, const double& freq, FGPositioned::Type type ) { + + const nav_list_type navlist + = globals->get_navlist()->findByIdentAndFreq( id.c_str(), freq, type ); + + 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; + } + + SG_LOG( SG_GENERAL, SG_ALERT, buf.str() ); + return false; + } + + FGNavRecord *nav = navlist[0]; + fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg")); + return true; +} + +// Set current_options lon/lat given an aircraft carrier id +static bool fgSetPosFromCarrier( const string& carrier, const string& posid ) { + + // set initial position from runway and heading + SGGeod geodPos; + double heading; + SGVec3d uvw; + if (FGAIManager::getStartPosition(carrier, posid, geodPos, heading, uvw)) { + double lon = geodPos.getLongitudeDeg(); + double lat = geodPos.getLatitudeDeg(); + double alt = geodPos.getElevationFt(); + + SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for " + << carrier << " at lat = " << lat << ", lon = " << lon + << ", alt = " << alt << ", heading = " << heading); + + fgSetDouble("/sim/presets/longitude-deg", lon); + fgSetDouble("/sim/presets/latitude-deg", lat); + fgSetDouble("/sim/presets/altitude-ft", alt); + fgSetDouble("/sim/presets/heading-deg", heading); + fgSetDouble("/position/longitude-deg", lon); + fgSetDouble("/position/latitude-deg", lat); + fgSetDouble("/position/altitude-ft", alt); + fgSetDouble("/orientation/heading-deg", heading); + + fgSetString("/sim/presets/speed-set", "UVW"); + fgSetDouble("/velocities/uBody-fps", uvw(0)); + fgSetDouble("/velocities/vBody-fps", uvw(1)); + fgSetDouble("/velocities/wBody-fps", uvw(2)); + fgSetDouble("/sim/presets/uBody-fps", uvw(0)); + fgSetDouble("/sim/presets/vBody-fps", uvw(1)); + fgSetDouble("/sim/presets/wBody-fps", uvw(2)); + + fgSetBool("/sim/presets/onground", true); + + return true; + } else { + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = " + << carrier ); + return false; + } +} + +// Set current_options lon/lat given an airport id and heading (degrees) +static bool fgSetPosFromFix( const string& id ) +{ + FGPositioned::TypeFilter fixFilter(FGPositioned::FIX); + FGPositioned* fix = FGPositioned::findNextWithPartialId(NULL, id, &fixFilter); + if (!fix) { + SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate fix = " << id ); + return false; + } + + fgApplyStartOffset(fix->geod(), fgGetDouble("/sim/presets/heading-deg")); + return true; +} + +// Set the initial position based on presets (or defaults) +bool initPosition() +{ + // cout << "fgInitPosition()" << endl; + double gs = fgGetDouble("/sim/presets/glideslope-deg") + * SG_DEGREES_TO_RADIANS ; + double od = fgGetDouble("/sim/presets/offset-distance-nm"); + double alt = fgGetDouble("/sim/presets/altitude-ft"); + + bool set_pos = false; + + // If glideslope is specified, then calculate offset-distance or + // altitude relative to glide slope if either of those was not + // specified. + if ( fabs( gs ) > 0.01 ) { + fgSetDistOrAltFromGlideSlope(); + } + + + // If we have an explicit, in-range lon/lat, don't change it, just use it. + // If not, check for an airport-id and use that. + // If not, default to the middle of the KSFO field. + // The default values for lon/lat are deliberately out of range + // so that the airport-id can take effect; valid lon/lat will + // override airport-id, however. + double lon_deg = fgGetDouble("/sim/presets/longitude-deg"); + double lat_deg = fgGetDouble("/sim/presets/latitude-deg"); + if ( lon_deg >= -180.0 && lon_deg <= 180.0 + && lat_deg >= -90.0 && lat_deg <= 90.0 ) + { + set_pos = true; + } + + string apt = fgGetString("/sim/presets/airport-id"); + string rwy_no = fgGetString("/sim/presets/runway"); + bool rwy_req = fgGetBool("/sim/presets/runway-requested"); + string vor = fgGetString("/sim/presets/vor-id"); + double vor_freq = fgGetDouble("/sim/presets/vor-freq"); + string ndb = fgGetString("/sim/presets/ndb-id"); + double ndb_freq = fgGetDouble("/sim/presets/ndb-freq"); + string carrier = fgGetString("/sim/presets/carrier"); + string parkpos = fgGetString("/sim/presets/parkpos"); + string fix = fgGetString("/sim/presets/fix"); + SGPropertyNode *hdg_preset = fgGetNode("/sim/presets/heading-deg", true); + double hdg = hdg_preset->getDoubleValue(); + + // save some start parameters, so that we can later say what the + // user really requested. TODO generalize that and move it to options.cxx + static bool start_options_saved = false; + if (!start_options_saved) { + start_options_saved = true; + SGPropertyNode *opt = fgGetNode("/sim/startup/options", true); + + opt->setDoubleValue("latitude-deg", lat_deg); + opt->setDoubleValue("longitude-deg", lon_deg); + opt->setDoubleValue("heading-deg", hdg); + opt->setStringValue("airport", apt.c_str()); + opt->setStringValue("runway", rwy_no.c_str()); + } + + if (hdg > 9990.0) + hdg = fgGetDouble("/environment/config/boundary/entry/wind-from-heading-deg", 270); + + if ( !set_pos && !apt.empty() && !parkpos.empty() ) { + // An airport + parking position is requested + if ( fgSetPosFromAirportIDandParkpos( apt, parkpos ) ) { + // set tower position + fgSetString("/sim/airport/closest-airport-id", apt.c_str()); + fgSetString("/sim/tower/airport-id", apt.c_str()); + set_pos = true; + } + } + + if ( !set_pos && !apt.empty() && !rwy_no.empty() ) { + // An airport + runway is requested + if ( fgSetPosFromAirportIDandRwy( apt, rwy_no, rwy_req ) ) { + // set tower position (a little off the heading for single + // runway airports) + fgSetString("/sim/airport/closest-airport-id", apt.c_str()); + fgSetString("/sim/tower/airport-id", apt.c_str()); + set_pos = true; + } + } + + if ( !set_pos && !apt.empty() ) { + // An airport is requested (find runway closest to hdg) + if ( setPosFromAirportIDandHdg( apt, hdg ) ) { + // set tower position (a little off the heading for single + // runway airports) + fgSetString("/sim/airport/closest-airport-id", apt.c_str()); + fgSetString("/sim/tower/airport-id", apt.c_str()); + set_pos = true; + } + } + + if (hdg_preset->getDoubleValue() > 9990.0) + hdg_preset->setDoubleValue(hdg); + + if ( !set_pos && !vor.empty() ) { + // a VOR is requested + if ( fgSetPosFromNAV( vor, vor_freq, FGPositioned::VOR ) ) { + set_pos = true; + } + } + + if ( !set_pos && !ndb.empty() ) { + // an NDB is requested + if ( fgSetPosFromNAV( ndb, ndb_freq, FGPositioned::NDB ) ) { + set_pos = true; + } + } + + if ( !set_pos && !carrier.empty() ) { + // an aircraft carrier is requested + if ( fgSetPosFromCarrier( carrier, parkpos ) ) { + set_pos = true; + } + } + + if ( !set_pos && !fix.empty() ) { + // a Fix is requested + if ( fgSetPosFromFix( fix ) ) { + 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); + } + + fgSetDouble( "/position/longitude-deg", + fgGetDouble("/sim/presets/longitude-deg") ); + fgSetDouble( "/position/latitude-deg", + fgGetDouble("/sim/presets/latitude-deg") ); + fgSetDouble( "/orientation/heading-deg", hdg_preset->getDoubleValue()); + + // determine if this should be an on-ground or in-air start + if ((fabs(gs) > 0.01 || fabs(od) > 0.1 || alt > 0.1) && carrier.empty()) { + fgSetBool("/sim/presets/onground", false); + } else { + fgSetBool("/sim/presets/onground", true); + } + + return true; +} + +} // of namespace flightgear diff --git a/src/Main/positioninit.hxx b/src/Main/positioninit.hxx new file mode 100644 index 000000000..9e6748bfa --- /dev/null +++ b/src/Main/positioninit.hxx @@ -0,0 +1,40 @@ +// positioninit.hxx - helpers relating to setting initial aircraft position +// +// Copyright (C) 2012 James Turner zakalawe@mac.com +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +#ifndef FG_POSITION_INIT_HXX +#define FG_POSITION_INIT_HXX + +#include + +namespace flightgear +{ + +// Set the initial position based on presets (or defaults) +bool initPosition(); + + +// Listen to /sim/tower/airport-id and set tower view position accordingly +void initTowerLocationListener(); + +// FIXME - only public becuase of the evil runway-selection hack in main.cxx +bool setPosFromAirportIDandHdg( const std::string& id, double tgt_hdg ); + +} // of namespace flightgear + +#endif // of FG_POSITION_INIT_HXX