#include <Airports/airport.hxx>
#include <Airports/dynamics.hxx>
#include <AIModel/AIManager.hxx>
+#include <GUI/MessageBox.hxx>
+
using std::endl;
+using std::string;
namespace flightgear
{
}
-struct FGTowerLocationListener : SGPropertyChangeListener {
+class FGTowerLocationListener : public SGPropertyChangeListener {
+
void valueChanged(SGPropertyNode* node) {
string id(node->getStringValue());
if (fgGetBool("/sim/tower/auto-position",true))
}
};
-struct FGClosestTowerLocationListener : SGPropertyChangeListener
+class FGClosestTowerLocationListener : public SGPropertyChangeListener
{
void valueChanged(SGPropertyNode* )
{
};
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)
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;
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");
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 {
return false;
}
} else {
+
pka = dcs->getParkingByName(parkpos);
if (!pka.isValid()) {
SG_LOG( SG_GENERAL, SG_ALERT,
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;
}
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;
}
// 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
}
}
-// 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;
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();
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;
}
}
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",
}
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");
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;
}