From 4be621fbe96114a246ed74aefe9b9a98bbf99b44 Mon Sep 17 00:00:00 2001 From: ehofman Date: Thu, 29 Dec 2005 13:58:21 +0000 Subject: [PATCH] =?UTF-8?q?Durk=20Talsma,=20Olaf=20Flebbe=20&=20Mathias=20?= =?UTF-8?q?Fr=F6hlich:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split up simple.cxx --- src/AIModel/AIAircraft.cxx | 6 +- src/AIModel/AIFlightPlanCreate.cxx | 41 +- src/ATC/AIGAVFRTraffic.cxx | 18 +- src/ATC/AILocalTraffic.cxx | 6 +- src/ATC/AIMgr.cxx | 23 +- src/ATC/ATCDialog.cxx | 6 +- src/ATC/ATCmgr.cxx | 21 +- src/ATC/ATCutils.cxx | 61 - src/ATC/ATCutils.hxx | 19 - src/ATC/commlist.cxx | 10 +- src/ATC/tower.cxx | 2 +- src/Airports/Makefile.am | 6 +- src/Airports/dynamics.cxx | 630 +++++++++++ src/Airports/dynamics.hxx | 101 ++ src/Airports/groundnetwork.cxx | 337 ++++++ src/Airports/groundnetwork.hxx | 164 +++ src/Airports/parking.cxx | 102 ++ src/Airports/parking.hxx | 97 ++ src/Airports/runwayprefs.cxx | 558 ++++++++++ src/Airports/runwayprefs.hxx | 159 +++ src/Airports/simple.cxx | 1550 ++------------------------ src/Airports/simple.hxx | 383 +------ src/Autopilot/auto_gui.cxx | 7 +- src/Environment/environment_ctrl.cxx | 9 +- src/Environment/environment_ctrl.hxx | 2 +- src/Main/fg_init.cxx | 70 +- 26 files changed, 2386 insertions(+), 2002 deletions(-) create mode 100644 src/Airports/dynamics.cxx create mode 100644 src/Airports/dynamics.hxx create mode 100644 src/Airports/groundnetwork.cxx create mode 100644 src/Airports/groundnetwork.hxx create mode 100644 src/Airports/parking.cxx create mode 100644 src/Airports/parking.hxx create mode 100644 src/Airports/runwayprefs.cxx create mode 100644 src/Airports/runwayprefs.hxx diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index bbc5b9bfa..997fcad57 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -664,8 +664,10 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) // << arr->getId() <name == "park2") - dep->releaseParking(fp->getGate()); - + { + dep->getDynamics()->releaseParking(fp->getGate()); + } + // Some debug messages, specific to TESTING THE Logical networks. //if ((arr->getId() == string("EHAM")) && (prev->name == "Center")) // { // diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx index 5c0aa56e3..62ae72da1 100644 --- a/src/AIModel/AIFlightPlanCreate.cxx +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -115,14 +115,17 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep, // Otherwise use the current aircraft position. if (firstFlight) { - if (!(dep->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, aircraftType, airline))) + if (!(dep->getDynamics()->getAvailableParking(&lat, &lon, + &heading, &gateId, + radius, fltType, + aircraftType, airline))) { cerr << "Could not find parking " << endl; } } else { - dep->getParking(gateId, &lat, &lon, &heading); + dep->getDynamics()->getParking(gateId, &lat, &lon, &heading); //lat = latitude; //lon = longitude; //heading = getHeading(); @@ -204,7 +207,7 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, // "NOTE: this is currently fixed to "com" for commercial traffic // Should be changed to be used dynamically to allow "gen" and "mil" // as well - apt->getActiveRunway("com", 1, activeRunway); + apt->getDynamics()->getActiveRunway("com", 1, activeRunway); if (!(globals->get_runways()->search(apt->getId(), activeRunway, &rwy))) @@ -223,10 +226,10 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, rwy._length * SG_FEET_TO_METER * 0.5 - 5.0, &lat2, &lon2, &az2 ); - if (apt->getGroundNetwork()->exists()) + if (apt->getDynamics()->getGroundNetwork()->exists()) { intVec ids; - int runwayId = apt->getGroundNetwork()->findNearestNode(lat2, lon2); + int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat2, lon2); //int currId = apt->getGroundNetwork()->findNearestNode(latitude,longitude); //exit(1); @@ -235,9 +238,9 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, // Starting from gate 0 is a bit of a hack... FGTaxiRoute route; if (gateId >= 0) - route = apt->getGroundNetwork()->findShortestRoute(gateId, runwayId); + route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, runwayId); else - route = apt->getGroundNetwork()->findShortestRoute(0, runwayId); + route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(0, runwayId); intVecIterator i; //cerr << "creating route : "; // No route found: go from gate directly to runway @@ -276,7 +279,7 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, { //i = ids.end()-1; //cerr << "Creating Node: " << node << endl; - FGTaxiNode *tn = apt->getGroundNetwork()->findNode(node); + FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node); //ids.pop_back(); wpt = new waypoint; wpt->name = "taxiway"; // fixme: should be the name of the taxiway @@ -354,7 +357,7 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, //geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, // rwy._length * SG_FEET_TO_METER * 0.5 - 5.0, // &lat2, &lon2, &az2 ); - apt->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, acType, airline); + apt->getDynamics()->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, acType, airline); heading += 180.0; if (heading > 360) heading -= 360; @@ -364,10 +367,10 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, double lat3 = (*(waypoints.end()-1))->latitude; double lon3 = (*(waypoints.end()-1))->longitude; cerr << (*(waypoints.end()-1))->name << endl; - if (apt->getGroundNetwork()->exists()) + if (apt->getDynamics()->getGroundNetwork()->exists()) { intVec ids; - int runwayId = apt->getGroundNetwork()->findNearestNode(lat3, lon3); + int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat3, lon3); //int currId = apt->getGroundNetwork()->findNearestNode(latitude,longitude); //exit(1); @@ -376,9 +379,9 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, // Starting from gate 0 is a bit of a hack... FGTaxiRoute route; if (gateId >= 0) - route = apt->getGroundNetwork()->findShortestRoute(runwayId, gateId); + route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, gateId); else - route = apt->getGroundNetwork()->findShortestRoute(runwayId, 0); + route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, 0); intVecIterator i; //cerr << "creating route : "; // No route found: go from gate directly to runway @@ -417,7 +420,7 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, { //i = ids.end()-1; //cerr << "Creating Node: " << node << endl; - FGTaxiNode *tn = apt->getGroundNetwork()->findNode(node); + FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node); //ids.pop_back(); wpt = new waypoint; wpt->name = "taxiway"; // fixme: should be the name of the taxiway @@ -514,7 +517,7 @@ void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double spee // "NOTE: this is currently fixed to "com" for commercial traffic // Should be changed to be used dynamically to allow "gen" and "mil" // as well - apt->getActiveRunway("com", 1, activeRunway); + apt->getDynamics()->getActiveRunway("com", 1, activeRunway); if (!(globals->get_runways()->search(apt->getId(), activeRunway, &rwy))) @@ -609,7 +612,7 @@ void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, // "NOTE: this is currently fixed to "com" for commercial traffic // Should be changed to be used dynamically to allow "gen" and "mil" // as well - apt->getActiveRunway("com", 1, activeRunway); + apt->getDynamics()->getActiveRunway("com", 1, activeRunway); if (!(globals->get_runways()->search(apt->getId(), activeRunway, &rwy))) @@ -708,7 +711,7 @@ void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, FGAirport *a //string name; // should be changed dynamically to allow "gen" and "mil" - arr->getActiveRunway("com", 2, activeRunway); + arr->getDynamics()->getActiveRunway("com", 2, activeRunway); if (!(globals->get_runways()->search(arr->getId(), activeRunway, &rwy))) @@ -787,7 +790,7 @@ void FGAIFlightPlan::createDecent(FGAirport *apt) //Beginning of Decent //string name; // allow "mil" and "gen" as well - apt->getActiveRunway("com", 2, activeRunway); + apt->getDynamics()->getActiveRunway("com", 2, activeRunway); if (!(globals->get_runways()->search(apt->getId(), activeRunway, &rwy))) @@ -943,7 +946,7 @@ void FGAIFlightPlan::createParking(FGAirport *apt) double lat; double lon; double heading; - apt->getParking(gateId, &lat, &lon, &heading); + apt->getDynamics()->getParking(gateId, &lat, &lon, &heading); heading += 180.0; if (heading > 360) heading -= 360; diff --git a/src/ATC/AIGAVFRTraffic.cxx b/src/ATC/AIGAVFRTraffic.cxx index 72c7685a5..c5df6d240 100644 --- a/src/ATC/AIGAVFRTraffic.cxx +++ b/src/ATC/AIGAVFRTraffic.cxx @@ -79,7 +79,7 @@ bool FGAIGAVFRTraffic::Init(const Point3D& pt, const string& destID, const strin _enroute = true; _destID = destID; _pos = pt; - _destPos = dclGetAirportPos(destID); // TODO - check if we are within the tower catchment area already. + _destPos = fgGetAirportPos(destID); // TODO - check if we are within the tower catchment area already. _cruise_alt = (_destPos.elev() + 2500.0) * SG_FEET_TO_METER; // TODO look at terrain elevation as well _pos.setelev(_cruise_alt); // initially set waypoint as airport location @@ -218,7 +218,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) { slope = atan((_wp.elev() - _pos.elev()) / dclGetHorizontalSeparation(_wp, _pos)) * DCL_RADIANS_TO_DEGREES; double thesh_offset = 0.0; Point3D opos = ortho.ConvertToLocal(_pos); - double angToApt = atan((_pos.elev() - dclGetAirportElev(airportID)) / (opos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES; + double angToApt = atan((_pos.elev() - fgGetAirportElev(airportID)) / (opos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES; //cout << "angToApt = " << angToApt << ' '; slope = (angToApt > -5.0 ? 0.0 : angToApt); //cout << "slope = " << slope << '\n'; @@ -246,7 +246,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) { ConditionalTransmit(4); } } - if(_pos.elev() < (dclGetAirportElev(airportID) + (1000.0 * SG_FEET_TO_METER))) slope = 0.0; + if(_pos.elev() < (fgGetAirportElev(airportID) + (1000.0 * SG_FEET_TO_METER))) slope = 0.0; } } if(_incoming) { @@ -254,7 +254,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) { Point3D orthopos = ortho.ConvertToLocal(_pos); // TODO - Check whether to start descent // become _local after the 3 mile report. - if(_pos.elev() < (dclGetAirportElev(airportID) + (1000.0 * SG_FEET_TO_METER))) slope = 0.0; + if(_pos.elev() < (fgGetAirportElev(airportID) + (1000.0 * SG_FEET_TO_METER))) slope = 0.0; // TODO - work out why I needed to add the above line to stop the plane going underground!!! // (Although it's worth leaving it in as a robustness check anyway). if(_straightIn) { @@ -265,9 +265,9 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) { //cout << "Established at " << orthopos << '\n'; } double thesh_offset = 30.0; - //cout << "orthopos.y = " << orthopos.y() << " alt = " << _pos.elev() - dclGetAirportElev(airportID) << '\n'; + //cout << "orthopos.y = " << orthopos.y() << " alt = " << _pos.elev() - fgGetAirportElev(airportID) << '\n'; if(_established && (orthopos.y() > -5400.0)) { - slope = atan((_pos.elev() - dclGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES; + slope = atan((_pos.elev() - fgGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES; //cout << "slope0 = " << slope << '\n'; } //cout << "slope1 = " << slope << '\n'; @@ -437,20 +437,20 @@ Point3D FGAIGAVFRTraffic::GetPatternApproachPos() { if((orthopos.x() * patternDirection) > 0.0) { // 45 deg entry tmp.setx(2000 * patternDirection); tmp.sety((rwy.end2ortho.y() / 2.0) + 2000); - tmp.setelev(dclGetAirportElev(airportID) + (1000 * SG_FEET_TO_METER)); + tmp.setelev(fgGetAirportElev(airportID) + (1000 * SG_FEET_TO_METER)); _e45 = true; //cout << "45 deg entry... "; } else { tmp.setx(1000 * patternDirection * -1); tmp.sety(rwy.end2ortho.y()); - tmp.setelev(dclGetAirportElev(airportID) + (1000 * SG_FEET_TO_METER)); + tmp.setelev(fgGetAirportElev(airportID) + (1000 * SG_FEET_TO_METER)); _e45 = false; //cout << "90 deg entry... "; } } else { tmp.setx(0); tmp.sety(-5400); - tmp.setelev((5400.0 / 6.0) + dclGetAirportElev(airportID) + 10.0); + tmp.setelev((5400.0 / 6.0) + fgGetAirportElev(airportID) + 10.0); //cout << "Straight in... "; } //cout << "Waypoint is " << tmp << '\n'; diff --git a/src/ATC/AILocalTraffic.cxx b/src/ATC/AILocalTraffic.cxx index c8caac821..997db2a94 100644 --- a/src/ATC/AILocalTraffic.cxx +++ b/src/ATC/AILocalTraffic.cxx @@ -156,7 +156,7 @@ void FGAILocalTraffic::GetAirportDetails(const string& id) { _controlled = false; } // Get the airport elevation - aptElev = dclGetAirportElev(airportID.c_str()); + aptElev = fgGetAirportElev(airportID.c_str()); //cout << "Airport elev in AILocalTraffic = " << aptElev << '\n'; // WARNING - we use this elev for the whole airport - some assumptions in the code // might fall down with very slopey airports. @@ -1069,8 +1069,8 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) { if(descending) { if(orthopos.y() < -50.0) { double thesh_offset = 30.0; - slope = atan((_pos.elev() - dclGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES; - //cout << "slope = " << slope << ", elev = " << _pos.elev() << ", apt_elev = " << dclGetAirportElev(airportID) << ", op.y = " << orthopos.y() << '\n'; + slope = atan((_pos.elev() - fgGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES; + //cout << "slope = " << slope << ", elev = " << _pos.elev() << ", apt_elev = " << fgGetAirportElev(airportID) << ", op.y = " << orthopos.y() << '\n'; if(slope < -10.0) slope = -10.0; _savedSlope = slope; _pitch = -4.0; diff --git a/src/ATC/AIMgr.cxx b/src/ATC/AIMgr.cxx index 3c36cde91..022e09487 100644 --- a/src/ATC/AIMgr.cxx +++ b/src/ATC/AIMgr.cxx @@ -24,7 +24,6 @@ #include
#include
#include - #include #ifdef _MSC_VER @@ -131,9 +130,9 @@ void FGAIMgr::init() { ext = file.substr(pos + 1); if(ext == "taxi") { f_ident = file.substr(0, pos); - FGAirport a; - if(dclFindAirportID(f_ident, &a)) { - SGBucket sgb(a.getLongitude(), a.getLatitude()); + const FGAirport *a = fgFindAirportID( f_ident); + if(a){ + SGBucket sgb(a->getLongitude(), a->getLatitude()); int idx = sgb.gen_index(); if(facilities.find(idx) != facilities.end()) { facilities[idx]->push_back(f_ident); @@ -159,7 +158,7 @@ void FGAIMgr::init() { /* // TESTING FGATCAlignedProjection ortho; - ortho.Init(dclGetAirportPos("KEMT"), 205.0); // Guess of rwy19 heading + ortho.Init(fgGetAirportPos("KEMT"), 205.0); // Guess of rwy19 heading //Point3D ip = ortho.ConvertFromLocal(Point3D(6000, 1000, 1000)); // 90 deg entry //Point3D ip = ortho.ConvertFromLocal(Point3D(-7000, 3000, 1000)); // 45 deg entry Point3D ip = ortho.ConvertFromLocal(Point3D(1000, -7000, 1000)); // straight-in @@ -209,7 +208,7 @@ void FGAIMgr::update(double dt) { ai_activated_map_iterator apt_itr = activated.begin(); while(apt_itr != activated.end()) { //cout << "FIRST IS " << (*apt_itr).first << '\n'; - if(dclGetHorizontalSeparation(userPos, dclGetAirportPos((*apt_itr).first)) > (35.0 * 1600.0)) { + if(dclGetHorizontalSeparation(userPos, fgGetAirportPos((*apt_itr).first)) > (35.0 * 1600.0)) { // Then get rid of it and make sure the iterator is left pointing to the next one! string s = (*apt_itr).first; if(traffic.find(s) != traffic.end()) { @@ -237,14 +236,14 @@ void FGAIMgr::update(double dt) { //cout << "s = " << s << " size = " << (*it).second.size() << '\n'; // Only generate extra traffic if within a certain distance of the user, // TODO - maybe take users's tuned freq into account as well. - double d = dclGetHorizontalSeparation(userPos, dclGetAirportPos(s)); + double d = dclGetHorizontalSeparation(userPos, fgGetAirportPos(s)); if(d < (15.0 * 1600.0)) { double cd = 0.0; bool gen = false; //cout << "Size of list is " << (*it).second.size() << " at " << s << '\n'; if((*it).second.size()) { FGAIEntity* e = *((*it).second.rbegin()); // Get the last airplane currently scheduled to arrive at this airport. - cd = dclGetHorizontalSeparation(e->GetPos(), dclGetAirportPos(s)); + cd = dclGetHorizontalSeparation(e->GetPos(), fgGetAirportPos(s)); if(cd < (d < 5000 ? 10000 : d + 5000)) { gen = true; } @@ -331,8 +330,8 @@ void FGAIMgr::GenerateSimpleAirportTraffic(const string& ident, double min_dist) /* // TODO - check for military airports - this should be in the current data. // UGGH - there's no point at the moment - everything is labelled civil in basic.dat! - FGAirport a; - if(dclFindAirportID(ident, &a)) { + FGAirport a = fgFindAirportID(ident, &a); + if(a) { cout << "CODE IS " << a.code << '\n'; } else { // UG - can't find the airport! @@ -340,7 +339,7 @@ void FGAIMgr::GenerateSimpleAirportTraffic(const string& ident, double min_dist) } */ - Point3D aptpos = dclGetAirportPos(ident); // TODO - check for elev of -9999 + Point3D aptpos = fgGetAirportPos(ident); // TODO - check for elev of -9999 //cout << "ident = " << ident << ", elev = " << aptpos.elev() << '\n'; // Operate from airports at 3000ft and below only to avoid the default cloud layers and since we don't degrade AI performance with altitude. @@ -554,7 +553,7 @@ void FGAIMgr::SearchByPos(double range) { for(twd_itr = towered.begin(); twd_itr != towered.end(); twd_itr++) { // Only activate the closest airport not already activated each time. if(activated.find(twd_itr->ident) == activated.end()) { - double sep = dclGetHorizontalSeparation(Point3D(lon, lat, elev), dclGetAirportPos(twd_itr->ident)); + double sep = dclGetHorizontalSeparation(Point3D(lon, lat, elev), fgGetAirportPos(twd_itr->ident)); if(sep < closest) { closest = sep; s = twd_itr->ident; diff --git a/src/ATC/ATCDialog.cxx b/src/ATC/ATCDialog.cxx index 0f1bc8e65..b54679d5c 100644 --- a/src/ATC/ATCDialog.cxx +++ b/src/ATC/ATCDialog.cxx @@ -365,8 +365,8 @@ void FGATCDialog::FreqDisplay(string& ident) { atcUppercase(ident); string label; - FGAirport a; - if (!dclFindAirportID(ident, &a)) { + const FGAirport *a = fgFindAirportID(ident); + if (!a) { label = "Airport " + ident + " not found in database."; mkDialog(label.c_str()); return; @@ -379,7 +379,7 @@ void FGATCDialog::FreqDisplay(string& ident) { int n = 0; // Number of ATC frequencies at this airport comm_list_type stations; - int found = current_commlist->FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 20.0, &stations); + int found = current_commlist->FindByPos(a->getLongitude(), a->getLatitude(), a->getElevation(), 20.0, &stations); if(found) { ostringstream ostr; comm_list_iterator itr = stations.begin(); diff --git a/src/ATC/ATCmgr.cxx b/src/ATC/ATCmgr.cxx index 6aa95a547..ff348c2ce 100644 --- a/src/ATC/ATCmgr.cxx +++ b/src/ATC/ATCmgr.cxx @@ -21,7 +21,6 @@ #include #include #include - #include "ATCmgr.hxx" #include "commlist.hxx" #include "ATCdisplay.hxx" @@ -216,14 +215,14 @@ bool FGATCMgr::AIRegisterAirport(const string& ident) { airport_atc_map[ident]->numAI++; return(true); } else { - FGAirport ap; - if(dclFindAirportID(ident, &ap)) { + const FGAirport *ap = fgFindAirportID(ident); + if (ap) { //cout << "ident = " << ident << '\n'; AirportATC *a = new AirportATC; // I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway! - a->lon = ap.getLongitude(); - a->lat = ap.getLatitude(); - a->elev = ap.getElevation(); + a->lon = ap->getLongitude(); + a->lat = ap->getLatitude(); + a->elev = ap->getElevation(); a->atis_freq = GetFrequency(ident, ATIS); //cout << "ATIS freq = " << a->atis_freq << '\n'; a->atis_active = false; @@ -266,13 +265,13 @@ bool FGATCMgr::CommRegisterAirport(const string& ident, int chan, const atc_type return(true); } else { //cout << "NOT IN MAP - creating new..." << endl; - FGAirport ap; - if(dclFindAirportID(ident, &ap)) { + const FGAirport *ap = fgFindAirportID(ident); + if (ap) { AirportATC *a = new AirportATC; // I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway! - a->lon = ap.getLongitude(); - a->lat = ap.getLatitude(); - a->elev = ap.getElevation(); + a->lon = ap->getLongitude(); + a->lat = ap->getLatitude(); + a->elev = ap->getElevation(); a->atis_freq = GetFrequency(ident, ATIS); a->atis_active = false; a->tower_freq = GetFrequency(ident, TOWER); diff --git a/src/ATC/ATCutils.cxx b/src/ATC/ATCutils.cxx index 5387880c7..ab561acb3 100644 --- a/src/ATC/ATCutils.cxx +++ b/src/ATC/ATCutils.cxx @@ -291,67 +291,6 @@ double GetAngleDiff_deg( const double &a1, const double &a2) { return a3; } -//================================================================================================================ - -// Airport stuff. The next two functions are straight copies of their fg.... equivalents -// in fg_init.cxx, and are just here temporarily until some rationalisation occurs. -// find basic airport location info from airport database -bool dclFindAirportID( const string& id, FGAirport *a ) { - const FGAirport* result; - - if ( id.length() ) { - SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id ); - - result = globals->get_airports()->search(id); - if ( result == NULL ) { - SG_LOG( SG_GENERAL, SG_WARN, - "Failed to find " << id << " in apt.dat.gz" ); - return false; - } - } else { - return false; - } - - *a = *result; - - SG_LOG( SG_GENERAL, SG_INFO, - "Position for " << id << " is (" - << a->getLongitude() << ", " - << a->getLatitude() << ")" ); - - return true; -} - -// get airport elevation -double dclGetAirportElev( const string& id ) { - FGAirport a; - // double lon, lat; - - SG_LOG( SG_ATC, SG_INFO, - "Finding elevation for airport: " << id ); - - if ( dclFindAirportID( id, &a ) ) { - return a.getElevation() * SG_FEET_TO_METER; - } else { - return -9999.0; - } -} - -// get airport position -Point3D dclGetAirportPos( const string& id ) { - FGAirport a; - // double lon, lat; - - SG_LOG( SG_ATC, SG_INFO, - "Finding position for airport: " << id ); - - if ( dclFindAirportID( id, &a ) ) { - return Point3D(a.getLongitude(), a.getLatitude(), a.getElevation()); - } else { - return Point3D(0.0, 0.0, -9999.0); - } -} - // Runway stuff // Given a Point3D (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway bool OnRunway(const Point3D& pt, const FGRunway& rwy) { diff --git a/src/ATC/ATCutils.hxx b/src/ATC/ATCutils.hxx index 2acfc9d18..85cb65841 100644 --- a/src/ATC/ATCutils.hxx +++ b/src/ATC/ATCutils.hxx @@ -92,25 +92,6 @@ void dclBoundHeading(double &hdg); // difference is negative if a1 > a2 and positive if a2 > a1 double GetAngleDiff_deg( const double &a1, const double &a2); - -/******************************* -* -* Airport-related functions -* -********************************/ - -// The next two functions are straight copies of their fg.... equivalents -// in fg_init.cxx, and are just here temporarily until some rationalisation occurs. - -// find basic airport location info from airport database -bool dclFindAirportID( const string& id, FGAirport *a ); - -// get airport elevation IN METERS -double dclGetAirportElev( const string& id ); - -// get airport position (elev portion in FEET) -Point3D dclGetAirportPos( const string& id ); - /**************** * * Runways diff --git a/src/ATC/commlist.cxx b/src/ATC/commlist.cxx index af2da4117..6e9771493 100644 --- a/src/ATC/commlist.cxx +++ b/src/ATC/commlist.cxx @@ -246,8 +246,8 @@ double FGCommList::FindClosest( double lon, double lat, double elev, ATCData& ad ATCData ad2 = *itr; //Point3D p1(*itr.lon, *itr.lat, *itr.elev); Point3D p1(ad2.lon, ad2.lat, ad2.elev); - FGAirport a; - if(dclFindAirportID(ad2.ident, &a)) { + const FGAirport *a = fgFindAirportID(ad2.ident); + if (a) { Point3D p2(lon, lat, elev); tmp = dclGetHorizontalSeparation(p1, p2); if(tmp <= closest) { @@ -273,10 +273,10 @@ double FGCommList::FindClosest( double lon, double lat, double elev, ATCData& ad // This is basically a wrapper for a call to the airport database to get the airport // position followed by a call to FindByPos(...) bool FGCommList::FindByCode( const string& ICAO, ATCData& ad, atc_type tp ) { - FGAirport a; - if ( dclFindAirportID( ICAO, &a ) ) { + const FGAirport *a = fgFindAirportID( ICAO); + if ( a) { comm_list_type stations; - int found = FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 10.0, &stations, tp); + int found = FindByPos(a->getLongitude(), a->getLatitude(), a->getElevation(), 10.0, &stations, tp); if(found) { comm_list_iterator itr = stations.begin(); while(itr != stations.end()) { diff --git a/src/ATC/tower.cxx b/src/ATC/tower.cxx index 4b8115df6..17aeb9ab0 100644 --- a/src/ATC/tower.cxx +++ b/src/ATC/tower.cxx @@ -291,7 +291,7 @@ void FGTower::Init() { // TODO - attempt to get a departure control pointer to see if we need to hand off departing traffic to departure. // Get the airport elevation - aptElev = dclGetAirportElev(ident.c_str()); + aptElev = fgGetAirportElev(ident.c_str()); // TODO - this function only assumes one active rwy. DoRwyDetails(); diff --git a/src/Airports/Makefile.am b/src/Airports/Makefile.am index 7a92691f9..bb9e960f7 100644 --- a/src/Airports/Makefile.am +++ b/src/Airports/Makefile.am @@ -5,7 +5,11 @@ noinst_PROGRAMS = calc_loc libAirports_a_SOURCES = \ apt_loader.cxx apt_loader.hxx \ runways.cxx runways.hxx \ - simple.cxx simple.hxx + simple.cxx simple.hxx \ + runwayprefs.cxx runwayprefs.hxx \ + parking.cxx parking.hxx \ + groundnetwork.cxx groundnetwork.hxx \ + dynamics.cxx dynamics.hxx calc_loc_SOURCES = calc_loc.cxx calc_loc_LDADD = -lsgmath -lsgdebug -lsgmisc -lz $(base_LIBS) diff --git a/src/Airports/dynamics.cxx b/src/Airports/dynamics.cxx new file mode 100644 index 000000000..e8eb6f6e3 --- /dev/null +++ b/src/Airports/dynamics.cxx @@ -0,0 +1,630 @@ +// dynamics.cxx - Code to manage the higher order airport ground activities +// Written by Durk Talsma, started December 2004. +// +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _MSC_VER +# define _USE_MATH_DEFINES +#endif +//#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include
+#include
+#include +#include + +#include STL_STRING +#include + +SG_USING_STD(string); +SG_USING_STD(vector); +SG_USING_STD(sort); +SG_USING_STD(random_shuffle); + +#include "parking.hxx" +#include "groundnetwork.hxx" +#include "runwayprefs.hxx" +#include "dynamics.hxx" + +/********** FGAirport Dynamics *********************************************/ + +FGAirportDynamics::FGAirportDynamics(double lat, double lon, double elev, string id) : + _latitude(lat), + _longitude(lon), + _elevation(elev), + _id(id) +{ + lastUpdate = 0; + for (int i = 0; i < 10; i++) + { + avWindHeading [i] = 0; + avWindSpeed [i] = 0; + } +} + + +// Note that the ground network should also be copied +FGAirportDynamics::FGAirportDynamics(const FGAirportDynamics& other) +{ + for (FGParkingVecConstIterator ip= other.parkings.begin(); ip != other.parkings.end(); ip++) + parkings.push_back(*(ip)); + rwyPrefs = other.rwyPrefs; + lastUpdate = other.lastUpdate; + + stringVecConstIterator il; + for (il = other.landing.begin(); il != other.landing.end(); il++) + landing.push_back(*il); + for (il = other.takeoff.begin(); il != other.takeoff.end(); il++) + takeoff.push_back(*il); + lastUpdate = other.lastUpdate; + for (int i = 0; i < 10; i++) + { + avWindHeading [i] = other.avWindHeading[i]; + avWindSpeed [i] = other.avWindSpeed [i]; + } +} + +// Destructor +FGAirportDynamics::~FGAirportDynamics() +{ + +} + + +// Initialization required after XMLRead +void FGAirportDynamics::init() +{ + // This may seem a bit weird to first randomly shuffle the parkings + // and then sort them again. However, parkings are sorted here by ascending + // radius. Since many parkings have similar radii, with each radius class they will + // still be allocated relatively systematically. Randomizing prior to sorting will + // prevent any initial orderings to be destroyed, leading (hopefully) to a more + // naturalistic gate assignment. + random_shuffle(parkings.begin(), parkings.end()); + sort(parkings.begin(), parkings.end()); + // add the gate positions to the ground network. + groundNetwork.addNodes(&parkings); + groundNetwork.init(); +} + +bool FGAirportDynamics::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, const string &flType, const string &acType, const string &airline) +{ + bool found = false; + bool available = false; + //string gateType; + + FGParkingVecIterator i; +// if (flType == "cargo") +// { +// gateType = "RAMP_CARGO"; +// } +// else if (flType == "ga") +// { +// gateType = "RAMP_GA"; +// } +// else gateType = "GATE"; + + if (parkings.begin() == parkings.end()) + { + //cerr << "Could not find parking spot at " << _id << endl; + *lat = _latitude; + *lon = _longitude; + *heading = 0; + found = true; + } + else + { + // First try finding a parking with a designated airline code + for (i = parkings.begin(); !(i == parkings.end() || found); i++) + { + //cerr << "Gate Id: " << i->getIndex() + // << " Type : " << i->getType() + // << " Codes : " << i->getCodes() + // << " Radius: " << i->getRadius() + // << " Name : " << i->getName() + // << " Available: " << i->isAvailable() << endl; + available = true; + // Taken by another aircraft + if (!(i->isAvailable())) + { + available = false; + continue; + } + // No airline codes, so skip + if (i->getCodes().empty()) + { + available = false; + continue; + } + else // Airline code doesn't match + if (i->getCodes().find(airline, 0) == string::npos) + { + available = false; + continue; + } + // Type doesn't match + if (i->getType() != flType) + { + available = false; + continue; + } + // too small + if (i->getRadius() < rad) + { + available = false; + continue; + } + + if (available) + { + *lat = i->getLatitude (); + *lon = i->getLongitude(); + *heading = i->getHeading (); + *gateId = i->getIndex (); + i->setAvailable(false); + found = true; + } + } + // then try again for those without codes. + for (i = parkings.begin(); !(i == parkings.end() || found); i++) + { + available = true; + if (!(i->isAvailable())) + { + available = false; + continue; + } + if (!(i->getCodes().empty())) + { + if ((i->getCodes().find(airline,0) == string::npos)) + { + available = false; + continue; + } + } + if (i->getType() != flType) + { + available = false; + continue; + } + + if (i->getRadius() < rad) + { + available = false; + continue; + } + + if (available) + { + *lat = i->getLatitude (); + *lon = i->getLongitude(); + *heading = i->getHeading (); + *gateId = i->getIndex (); + i->setAvailable(false); + found = true; + } + } + // And finally once more if that didn't work. Now ignore the airline codes, as a last resort + for (i = parkings.begin(); !(i == parkings.end() || found); i++) + { + available = true; + if (!(i->isAvailable())) + { + available = false; + continue; + } + if (i->getType() != flType) + { + available = false; + continue; + } + + if (i->getRadius() < rad) + { + available = false; + continue; + } + + if (available) + { + *lat = i->getLatitude (); + *lon = i->getLongitude(); + *heading = i->getHeading (); + *gateId = i->getIndex (); + i->setAvailable(false); + found = true; + } + } + } + if (!found) + { + //cerr << "Traffic overflow at" << _id + // << ". flType = " << flType + // << ". airline = " << airline + // << " Radius = " <getIndex()) + { + *lat = i->getLatitude(); + *lon = i->getLongitude(); + *heading = i->getLongitude(); + } + } + } +} + +FGParking *FGAirportDynamics::getParking(int i) +{ + if (i < (int)parkings.size()) + return &(parkings[i]); + else + return 0; +} +string FGAirportDynamics::getParkingName(int i) +{ + if (i < (int)parkings.size() && i >= 0) + return (parkings[i].getName()); + else + return string("overflow"); +} +void FGAirportDynamics::releaseParking(int id) +{ + if (id >= 0) + { + + FGParkingVecIterator i = parkings.begin(); + for (i = parkings.begin(); i != parkings.end(); i++) + { + if (id == i->getIndex()) + { + i -> setAvailable(true); + } + } + } +} + +void FGAirportDynamics::startXML () { + //cout << "Start XML" << endl; +} + +void FGAirportDynamics::endXML () { + //cout << "End XML" << endl; +} + +void FGAirportDynamics::startElement (const char * name, const XMLAttributes &atts) { + // const char *attval; + FGParking park; + FGTaxiNode taxiNode; + FGTaxiSegment taxiSegment; + int index = 0; + taxiSegment.setIndex(index); + //cout << "Start element " << name << endl; + string attname; + string value; + string gateName; + string gateNumber; + string lat; + string lon; + if (name == string("Parking")) + { + for (int i = 0; i < atts.size(); i++) + { + //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; + attname = atts.getName(i); + if (attname == string("index")) + park.setIndex(atoi(atts.getValue(i))); + else if (attname == string("type")) + park.setType(atts.getValue(i)); + else if (attname == string("name")) + gateName = atts.getValue(i); + else if (attname == string("number")) + gateNumber = atts.getValue(i); + else if (attname == string("lat")) + park.setLatitude(atts.getValue(i)); + else if (attname == string("lon")) + park.setLongitude(atts.getValue(i)); + else if (attname == string("heading")) + park.setHeading(atof(atts.getValue(i))); + else if (attname == string("radius")) { + string radius = atts.getValue(i); + if (radius.find("M") != string::npos) + radius = radius.substr(0, radius.find("M",0)); + //cerr << "Radius " << radius < 600) || trafficType != prevTrafficType) + { + landing.clear(); + takeoff.clear(); + //lastUpdate = dayStart; + prevTrafficType = trafficType; + + FGEnvironment + stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) + ->getEnvironment(getLatitude(), + getLongitude(), + getElevation()); + + windSpeed = stationweather.get_wind_speed_kt(); + windHeading = stationweather.get_wind_from_heading_deg(); + double averageWindSpeed = 0; + double averageWindHeading = 0; + double cosHeading = 0; + double sinHeading = 0; + // Initialize at the beginning of the next day or startup + if ((lastUpdate == 0) || (dayStart < lastUpdate)) + { + for (int i = 0; i < 10; i++) + { + avWindHeading [i] = windHeading; + avWindSpeed [i] = windSpeed; + } + } + else + { + if (windSpeed != avWindSpeed[9]) // update if new metar data + { + // shift the running average + for (int i = 0; i < 9 ; i++) + { + avWindHeading[i] = avWindHeading[i+1]; + avWindSpeed [i] = avWindSpeed [i+1]; + } + } + avWindHeading[9] = windHeading; + avWindSpeed [9] = windSpeed; + } + + for (int i = 0; i < 10; i++) + { + averageWindSpeed += avWindSpeed [i]; + //averageWindHeading += avWindHeading [i]; + cosHeading += cos(avWindHeading[i] * SG_DEGREES_TO_RADIANS); + sinHeading += sin(avWindHeading[i] * SG_DEGREES_TO_RADIANS); + } + averageWindSpeed /= 10; + //averageWindHeading /= 10; + cosHeading /= 10; + sinHeading /= 10; + averageWindHeading = atan2(sinHeading, cosHeading) *SG_RADIANS_TO_DEGREES; + if (averageWindHeading < 0) + averageWindHeading += 360.0; + //cerr << "Wind Heading " << windHeading << " average " << averageWindHeading << endl; + //cerr << "Wind Speed " << windSpeed << " average " << averageWindSpeed << endl; + lastUpdate = dayStart; + //if (wind_speed == 0) { + // wind_heading = 270; This forces West-facing rwys to be used in no-wind situations + // which is consistent with Flightgear's initial setup. + //} + + //string rwy_no = globals->get_runways()->search(apt->getId(), int(wind_heading)); + string scheduleName; + //cerr << "finding active Runway for" << _id << endl; + //cerr << "Nr of seconds since day start << " << dayStart << endl; + ScheduleTime *currSched; + //cerr << "A"<< endl; + currSched = rwyPrefs.getSchedule(trafficType.c_str()); + if (!(currSched)) + return; + //cerr << "B"<< endl; + scheduleName = currSched->getName(dayStart); + maxTail = currSched->getTailWind (); + maxCross = currSched->getCrossWind (); + //cerr << "SChedule anme = " << scheduleName << endl; + if (scheduleName.empty()) + return; + //cerr << "C"<< endl; + currRunwayGroup = rwyPrefs.getGroup(scheduleName); + //cerr << "D"<< endl; + if (!(currRunwayGroup)) + return; + nrActiveRunways = currRunwayGroup->getNrActiveRunways(); + //cerr << "Nr of Active Runways = " << nrActiveRunways << endl; + currRunwayGroup->setActive(_id, averageWindSpeed, averageWindHeading, maxTail, maxCross); + nrActiveRunways = currRunwayGroup->getNrActiveRunways(); + for (int i = 0; i < nrActiveRunways; i++) + { + type = "unknown"; // initialize to something other than landing or takeoff + currRunwayGroup->getActive(i, name, type); + if (type == "landing") + { + landing.push_back(name); + //cerr << "Landing " << name << endl; + } + if (type == "takeoff") + { + takeoff.push_back(name); + //cerr << "takeoff " << name << endl; + } + } + } + if (action == 1) // takeoff + { + int nr = takeoff.size(); + if (nr) + { + runway = takeoff[(rand() % nr)]; + } + else + { // Fallback + runway = chooseRunwayFallback(); + } + } + if (action == 2) // landing + { + int nr = landing.size(); + if (nr) + { + runway = landing[(rand() % nr)]; + } + else + { //fallback + runway = chooseRunwayFallback(); + } + } + + //runway = globals->get_runways()->search(_id, int(windHeading)); + //cerr << "Seleceted runway: " << runway << endl; + } +} + +string FGAirportDynamics::chooseRunwayFallback() +{ + FGEnvironment + stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) + ->getEnvironment(getLatitude(), + getLongitude(), + getElevation()); + + double windSpeed = stationweather.get_wind_speed_kt(); + double windHeading = stationweather.get_wind_from_heading_deg(); + if (windSpeed == 0) { + windHeading = 270; // This forces West-facing rwys to be used in no-wind situations + //which is consistent with Flightgear's initial setup. + } + + return globals->get_runways()->search(_id, int(windHeading)); +} diff --git a/src/Airports/dynamics.hxx b/src/Airports/dynamics.hxx new file mode 100644 index 000000000..3c787a934 --- /dev/null +++ b/src/Airports/dynamics.hxx @@ -0,0 +1,101 @@ +// dynamics.hxx - a class to manage the higher order airport ground activities +// Written by Durk Talsma, started December 2004. +// +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#ifndef _AIRPORT_DYNAMICS_HXX_ +#define _AIRPORT_DYNAMICS_HXX_ + + +#ifndef __cplusplus +# error This library requires C++ +#endif + + + +class FGAirportDynamics : public XMLVisitor { + +private: + double _longitude; // degrees + double _latitude; // degrees + double _elevation; // ft + string _id; + + FGParkingVec parkings; + FGRunwayPreference rwyPrefs; + FGGroundNetwork groundNetwork; + + time_t lastUpdate; + string prevTrafficType; + stringVec landing; + stringVec takeoff; + + // Experimental keep a running average of wind dir and speed to prevent + // Erratic runway changes. + // Note: I should add these to the copy constructor and assigment operator to be + // constistent + double avWindHeading [10]; + double avWindSpeed [10]; + + string chooseRunwayFallback(); + +public: + FGAirportDynamics(double, double, double, string); + FGAirportDynamics(const FGAirportDynamics &other); + ~FGAirportDynamics(); + + + void init(); + double getLongitude() const { return _longitude;}; + // Returns degrees + double getLatitude() const { return _latitude; }; + // Returns ft + double getElevation() const { return _elevation;}; + + void getActiveRunway(const string& trafficType, int action, string& runway); + bool getAvailableParking(double *lat, double *lon, + double *heading, int *gate, double rad, const string& fltype, + const string& acType, const string& airline); + void getParking (int id, double *lat, double* lon, double *heading); + FGParking *getParking(int i); + void releaseParking(int id); + string getParkingName(int i); + //FGAirport *getAddress() { return this; }; + //const string &getName() const { return _name;}; + // Returns degrees + + FGGroundNetwork* getGroundNetwork() { return &groundNetwork; }; + + + void setRwyUse(const FGRunwayPreference& ref); + + // Some overloaded virtual XMLVisitor members + virtual void startXML (); + virtual void endXML (); + virtual void startElement (const char * name, const XMLAttributes &atts); + virtual void endElement (const char * name); + virtual void data (const char * s, int len); + virtual void pi (const char * target, const char * data); + virtual void warning (const char * message, int line, int column); + virtual void error (const char * message, int line, int column); +}; + + + +#endif diff --git a/src/Airports/groundnetwork.cxx b/src/Airports/groundnetwork.cxx new file mode 100644 index 000000000..fd41d8a58 --- /dev/null +++ b/src/Airports/groundnetwork.cxx @@ -0,0 +1,337 @@ +// groundnet.cxx - Implimentation of the FlightGear airport ground handling code +// +// Written by Durk Talsma, started June 2005. +// +// Copyright (C) 2004 Durk Talsma. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _MSC_VER +# define _USE_MATH_DEFINES +#endif +#include +#include + +#include + +//#include +//#include + +//#include +//#include +//#include +//#include +//#include +#include +#include +//#include
+//#include
+//#include + +//#include STL_STRING + +#include "groundnetwork.hxx" + +SG_USING_STD(sort); + +/************************************************************************** + * FGTaxiNode + *************************************************************************/ +FGTaxiNode::FGTaxiNode() +{ +} + +/*************************************************************************** + * FGTaxiSegment + **************************************************************************/ +FGTaxiSegment::FGTaxiSegment() +{ +} + +void FGTaxiSegment::setStart(FGTaxiNodeVector *nodes) +{ + FGTaxiNodeVectorIterator i = nodes->begin(); + while (i != nodes->end()) + { + if (i->getIndex() == startNode) + { + start = i->getAddress(); + i->addSegment(this); + return; + } + i++; + } +} + +void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes) +{ + FGTaxiNodeVectorIterator i = nodes->begin(); + while (i != nodes->end()) + { + if (i->getIndex() == endNode) + { + end = i->getAddress(); + return; + } + i++; + } +} + +// There is probably a computationally cheaper way of +// doing this. +void FGTaxiSegment::setTrackDistance() +{ + double course; + SGWayPoint first (start->getLongitude(), + start->getLatitude(), + 0); + SGWayPoint second (end->getLongitude(), + end->getLatitude(), + 0); + first.CourseAndDistance(second, &course, &length); + +} + +bool FGTaxiRoute::next(int *val) +{ + //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++) + // cerr << "FGTaxiRoute contains : " << *(i) << endl; + //cerr << "Offset from end: " << nodes.end() - currNode << endl; + //if (currNode != nodes.end()) + // cerr << "true" << endl; + //else + // cerr << "false" << endl; + + if (currNode == nodes.end()) + return false; + *val = *(currNode); + currNode++; + return true; +}; +/*************************************************************************** + * FGGroundNetwork() + **************************************************************************/ + +FGGroundNetwork::FGGroundNetwork() +{ + hasNetwork = false; + foundRoute = false; + totalDistance = 0; + maxDistance = 0; +} + +void FGGroundNetwork::addSegment(const FGTaxiSegment &seg) +{ + segments.push_back(seg); +} + +void FGGroundNetwork::addNode(const FGTaxiNode &node) +{ + nodes.push_back(node); +} + +void FGGroundNetwork::addNodes(FGParkingVec *parkings) +{ + FGTaxiNode n; + FGParkingVecIterator i = parkings->begin(); + while (i != parkings->end()) + { + n.setIndex(i->getIndex()); + n.setLatitude(i->getLatitude()); + n.setLongitude(i->getLongitude()); + nodes.push_back(n); + + i++; + } +} + + + +void FGGroundNetwork::init() +{ + hasNetwork = true; + FGTaxiSegmentVectorIterator i = segments.begin(); + while(i != segments.end()) { + //cerr << "initializing node " << i->getIndex() << endl; + i->setStart(&nodes); + i->setEnd (&nodes); + i->setTrackDistance(); + //cerr << "Track distance = " << i->getLength() << endl; + //cerr << "Track ends at" << i->getEnd()->getIndex() << endl; + i++; + } + //exit(1); +} + +int FGGroundNetwork::findNearestNode(double lat, double lon) +{ + double minDist = HUGE_VAL; + double course, dist; + int index; + SGWayPoint first (lon, + lat, + 0); + + for (FGTaxiNodeVectorIterator + itr = nodes.begin(); + itr != nodes.end(); itr++) + { + double course; + SGWayPoint second (itr->getLongitude(), + itr->getLatitude(), + 0); + first.CourseAndDistance(second, &course, &dist); + if (dist < minDist) + { + minDist = dist; + index = itr->getIndex(); + //cerr << "Minimum distance of " << minDist << " for index " << index << endl; + } + } + return index; +} + +FGTaxiNode *FGGroundNetwork::findNode(int idx) +{ + for (FGTaxiNodeVectorIterator + itr = nodes.begin(); + itr != nodes.end(); itr++) + { + if (itr->getIndex() == idx) + return itr->getAddress(); + } + return 0; +} + +FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end) +{ + foundRoute = false; + totalDistance = 0; + FGTaxiNode *firstNode = findNode(start); + FGTaxiNode *lastNode = findNode(end); + //prevNode = prevPrevNode = -1; + //prevNode = start; + routes.clear(); + traceStack.clear(); + trace(firstNode, end, 0, 0); + FGTaxiRoute empty; + + if (!foundRoute) + { + SG_LOG( SG_GENERAL, SG_INFO, "Failed to find route from waypoint " << start << " to " << end ); + exit(1); + } + sort(routes.begin(), routes.end()); + //for (intVecIterator i = route.begin(); i != route.end(); i++) + // { + // rte->push_back(*i); + // } + + if (routes.begin() != routes.end()) + return *(routes.begin()); + else + return empty; +} + + +void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance) +{ + traceStack.push_back(currNode->getIndex()); + totalDistance += distance; + //cerr << "Starting trace " << depth << " total distance: " << totalDistance<< endl; + //<< currNode->getIndex() << endl; + + // If the current route matches the required end point we found a valid route + // So we can add this to the routing table + if (currNode->getIndex() == end) + { + //cerr << "Found route : " << totalDistance << "" << " " << *(traceStack.end()-1) << endl; + routes.push_back(FGTaxiRoute(traceStack,totalDistance)); + traceStack.pop_back(); + if (!(foundRoute)) + maxDistance = totalDistance; + else + if (totalDistance < maxDistance) + maxDistance = totalDistance; + foundRoute = true; + totalDistance -= distance; + return; + } + + + // search if the currentNode has been encountered before + // if so, we should step back one level, because it is + // rather rediculous to proceed further from here. + // if the current node has not been encountered before, + // i should point to traceStack.end()-1; and we can continue + // if i is not traceStack.end, the previous node was found, + // and we should return. + // This only works at trace levels of 1 or higher though + if (depth > 0) { + intVecIterator i = traceStack.begin(); + while ((*i) != currNode->getIndex()) { + //cerr << "Route so far : " << (*i) << endl; + i++; + } + if (i != traceStack.end()-1) { + traceStack.pop_back(); + totalDistance -= distance; + return; + } + // If the total distance from start to the current waypoint + // is longer than that of a route we can also stop this trace + // and go back one level. + if ((totalDistance > maxDistance) && foundRoute) + { + //cerr << "Stopping rediculously long trace: " << totalDistance << endl; + traceStack.pop_back(); + totalDistance -= distance; + return; + } + } + + //cerr << "2" << endl; + if (currNode->getBeginRoute() != currNode->getEndRoute()) + { + //cerr << "3" << endl; + for (FGTaxiSegmentPointerVectorIterator + i = currNode->getBeginRoute(); + i != currNode->getEndRoute(); + i++) + { + //cerr << (*i)->getLenght() << endl; + trace((*i)->getEnd(), end, depth+1, (*i)->getLength()); + // { + // // cerr << currNode -> getIndex() << " "; + // route.push_back(currNode->getIndex()); + // return true; + // } + } + } + else + { + SG_LOG( SG_GENERAL, SG_DEBUG, "4" ); + } + traceStack.pop_back(); + totalDistance -= distance; + return; +} + diff --git a/src/Airports/groundnetwork.hxx b/src/Airports/groundnetwork.hxx new file mode 100644 index 000000000..8cf1baa77 --- /dev/null +++ b/src/Airports/groundnetwork.hxx @@ -0,0 +1,164 @@ +// groundnet.hxx - A number of classes to handle taxiway +// assignments by the AI code +// +// Written by Durk Talsma, started June 2005. +// +// Copyright (C) 2004 Durk Talsma. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _GROUNDNETWORK_HXX_ +#define _GROUNDNETWORK_HXX_ + +#include STL_STRING +#include + +SG_USING_STD(string); +SG_USING_STD(vector); + +#include "parking.hxx" + +class FGTaxiSegment; // forward reference + +typedef vector FGTaxiSegmentVector; +typedef vector FGTaxiSegmentPointerVector; +typedef vector::iterator FGTaxiSegmentVectorIterator; +typedef vector::iterator FGTaxiSegmentPointerVectorIterator; + +/************************************************************************************** + * class FGTaxiNode + *************************************************************************************/ +class FGTaxiNode +{ +private: + double lat; + double lon; + int index; + FGTaxiSegmentPointerVector next; // a vector to all the segments leaving from this node + +public: + FGTaxiNode(); + FGTaxiNode(double, double, int); + + void setIndex(int idx) { index = idx;}; + void setLatitude (double val) { lat = val;}; + void setLongitude(double val) { lon = val;}; + void setLatitude (const string& val) { lat = processPosition(val); }; + void setLongitude(const string& val) { lon = processPosition(val); }; + void addSegment(FGTaxiSegment *segment) { next.push_back(segment); }; + + double getLatitude() { return lat;}; + double getLongitude(){ return lon;}; + + int getIndex() { return index; }; + FGTaxiNode *getAddress() { return this;}; + FGTaxiSegmentPointerVectorIterator getBeginRoute() { return next.begin(); }; + FGTaxiSegmentPointerVectorIterator getEndRoute() { return next.end(); }; +}; + +typedef vector FGTaxiNodeVector; +typedef vector::iterator FGTaxiNodeVectorIterator; + +/*************************************************************************************** + * class FGTaxiSegment + **************************************************************************************/ +class FGTaxiSegment +{ +private: + int startNode; + int endNode; + double length; + FGTaxiNode *start; + FGTaxiNode *end; + int index; + +public: + FGTaxiSegment(); + FGTaxiSegment(FGTaxiNode *, FGTaxiNode *, int); + + void setIndex (int val) { index = val; }; + void setStartNodeRef (int val) { startNode = val; }; + void setEndNodeRef (int val) { endNode = val; }; + + void setStart(FGTaxiNodeVector *nodes); + void setEnd (FGTaxiNodeVector *nodes); + void setTrackDistance(); + + FGTaxiNode * getEnd() { return end;}; + double getLength() { return length; }; + int getIndex() { return index; }; + + +}; + + +typedef vector intVec; +typedef vector::iterator intVecIterator; + +class FGTaxiRoute +{ +private: + intVec nodes; + double distance; + intVecIterator currNode; + +public: + FGTaxiRoute() { distance = 0; currNode = nodes.begin(); }; + FGTaxiRoute(intVec nds, double dist) { nodes = nds; distance = dist; currNode = nodes.begin();}; + bool operator< (const FGTaxiRoute &other) const {return distance < other.distance; }; + bool empty () { return nodes.begin() == nodes.end(); }; + bool next(int *val); + + void first() { currNode = nodes.begin(); }; +}; + +typedef vector TaxiRouteVector; +typedef vector::iterator TaxiRouteVectorIterator; + +/************************************************************************************** + * class FGGroundNetWork + *************************************************************************************/ +class FGGroundNetwork +{ +private: + bool hasNetwork; + FGTaxiNodeVector nodes; + FGTaxiSegmentVector segments; + //intVec route; + intVec traceStack; + TaxiRouteVector routes; + + bool foundRoute; + double totalDistance, maxDistance; + +public: + FGGroundNetwork(); + + void addNode (const FGTaxiNode& node); + void addNodes (FGParkingVec *parkings); + void addSegment(const FGTaxiSegment& seg); + + void init(); + bool exists() { return hasNetwork; }; + int findNearestNode(double lat, double lon); + FGTaxiNode *findNode(int idx); + FGTaxiRoute findShortestRoute(int start, int end); + void trace(FGTaxiNode *, int, int, double dist); + +}; + +#endif diff --git a/src/Airports/parking.cxx b/src/Airports/parking.cxx new file mode 100644 index 000000000..b846a1375 --- /dev/null +++ b/src/Airports/parking.cxx @@ -0,0 +1,102 @@ +// parking.cxx - Implementation of a class to manage aircraft parking in +// FlightGear. This code is intended to be used by AI code and +// initial user-startup location selection. +// +// Written by Durk Talsma, started December 2004. +// +// Copyright (C) 2004 Durk Talsma. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _MSC_VER +# define _USE_MATH_DEFINES +#endif +//#include +//#include + +#include + +//#include +//#include + +//#include +//#include +//#include +//#include +//#include +//#include +//#include
+//#include
+//#include + +#include STL_STRING + +#include "parking.hxx" + + +/***************************************************************************** + * Helper function for parsing position string + ****************************************************************************/ +double processPosition(const string &pos) +{ + string prefix; + string subs; + string degree; + string decimal; + int sign = 1; + double value; + subs = pos; + prefix= subs.substr(0,1); + if (prefix == string("S") || (prefix == string("W"))) + sign = -1; + subs = subs.substr(1, subs.length()); + degree = subs.substr(0, subs.find(" ",0)); + decimal = subs.substr(subs.find(" ",0), subs.length()); + + + //cerr << sign << " "<< degree << " " << decimal << endl; + value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0); + //cerr << value < + + + + +SG_USING_STD(string); +SG_USING_STD(vector); + +double processPosition(const string& pos); + +class FGParking { +private: + double latitude; + double longitude; + double heading; + double radius; + int index; + string parkingName; + string type; + string airlineCodes; + + bool available; + + + +public: + FGParking() { available = true;}; + //FGParking(FGParking &other); + FGParking(double lat, + double lon, + double hdg, + double rad, + int idx, + const string& name, + const string& tpe, + const string& codes); + void setLatitude (const string& lat) { latitude = processPosition(lat); }; + void setLongitude(const string& lon) { longitude = processPosition(lon); }; + void setHeading (double hdg) { heading = hdg; }; + void setRadius (double rad) { radius = rad; }; + void setIndex (int idx) { index = idx; }; + void setName (const string& name) { parkingName = name; }; + void setType (const string& tpe) { type = tpe; }; + void setCodes (const string& codes){ airlineCodes= codes;}; + + bool isAvailable () { return available;}; + void setAvailable(bool val) { available = val; }; + + double getLatitude () { return latitude; }; + double getLongitude() { return longitude; }; + double getHeading () { return heading; }; + double getRadius () { return radius; }; + int getIndex () { return index; }; + string getType () { return type; }; + string getCodes () { return airlineCodes;}; + string getName () { return parkingName; }; + + bool operator< (const FGParking &other) const {return radius < other.radius; }; +}; + +typedef vector FGParkingVec; +typedef vector::iterator FGParkingVecIterator; +typedef vector::const_iterator FGParkingVecConstIterator; + +#endif diff --git a/src/Airports/runwayprefs.cxx b/src/Airports/runwayprefs.cxx new file mode 100644 index 000000000..f98e965bf --- /dev/null +++ b/src/Airports/runwayprefs.cxx @@ -0,0 +1,558 @@ +// runwayprefs.cxx - class implementations corresponding to runwayprefs.hxx +// assignments by the AI code +// +// Written by Durk Talsma, started January 2005. +// +// Copyright (C) 2004 Durk Talsma. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _MSC_VER +# define _USE_MATH_DEFINES +#endif +#include +//#include + +#include + +//#include +//#include + +//#include +//#include +//#include +//#include +//#include +#include +#include
+//#include
+#include + +#include "runwayprefs.hxx" + +/****************************************************************************** + * ScheduleTime + ***************e*************************************************************/ +void ScheduleTime::clear() +{ + start.clear(); + end.clear(); + scheduleNames.clear(); +} + + +ScheduleTime::ScheduleTime(const ScheduleTime &other) +{ + //timeVec start; + timeVecConstIterator i; + for (i = other.start.begin(); i != other.start.end(); i++) + start.push_back(*i); + for (i = other.end.begin(); i != other.end.end(); i++) + end.push_back(*i); + stringVecConstIterator k; + for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++) + scheduleNames.push_back(*k); + + //timeVec end; + //stringVec scheduleNames; + tailWind = other.tailWind; + crssWind = other.tailWind; +} + + +ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other) +{ + //timeVec start; + clear(); + timeVecConstIterator i; + for (i = other.start.begin(); i != other.start.end(); i++) + start.push_back(*i); + for (i = other.end.begin(); i != other.end.end(); i++) + end.push_back(*i); + stringVecConstIterator k; + for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++) + scheduleNames.push_back(*k); + + //timeVec end; + //stringVec scheduleNames; + tailWind = other.tailWind; + crssWind = other.tailWind; + return *this; +} +string ScheduleTime::getName(time_t dayStart) +{ + if ((start.size() != end.size()) || (start.size() != scheduleNames.size())) + { + SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" ); + exit(1); + } + else + { + int nrItems = start.size(); + //cerr << "Nr of items to process: " << nrItems << endl; + if (nrItems > 0) + { + for (unsigned int i = 0; i < start.size(); i++) + { + //cerr << i << endl; + if ((dayStart >= start[i]) && (dayStart <= end[i])) + return scheduleNames[i]; + } + } + //couldn't find one so return 0; + //cerr << "Returning 0 " << endl; + } + return string(0); +} +/****************************************************************************** + * RunwayList + *****************************************************************************/ + +RunwayList::RunwayList(const RunwayList &other) +{ + type = other.type; + stringVecConstIterator i; + for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++) + preferredRunways.push_back(*i); +} +RunwayList& RunwayList::operator= (const RunwayList &other) +{ + type = other.type; + preferredRunways.clear(); + stringVecConstIterator i; + for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++) + preferredRunways.push_back(*i); + return *this; +} +void RunwayList::set(const string &tp, const string &lst) +{ + //weekday = atoi(timeCopy.substr(0,1).c_str()); + // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday; + // timeCopy = timeCopy.substr(2,timeCopy.length()); + type = tp; + string rwys = lst; + string rwy; + while (rwys.find(",") != string::npos) + { + rwy = rwys.substr(0, rwys.find(",",0)); + //cerr << "adding runway [" << rwy << "] to the list " << endl; + preferredRunways.push_back(rwy); + rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace + while (rwys[0] == ' ') + rwys.erase(0, 1); // Erase any leading whitespaces. + //cerr << "Remaining runway list " << rwys; + } + preferredRunways.push_back(rwys); + //exit(1); +} + +void RunwayList::clear() +{ + type = ""; + preferredRunways.clear(); +} +/**************************************************************************** + * + ***************************************************************************/ + +RunwayGroup::RunwayGroup(const RunwayGroup &other) +{ + name = other.name; + RunwayListVecConstIterator i; + for (i = other.rwyList.begin(); i != other.rwyList.end(); i++) + rwyList.push_back(*i); + choice[0] = other.choice[0]; + choice[1] = other.choice[1]; + nrActive = other.nrActive; +} +RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other) +{ + rwyList.clear(); + name = other.name; + RunwayListVecConstIterator i; + for (i = other.rwyList.begin(); i != other.rwyList.end(); i++) + rwyList.push_back(*i); + choice[0] = other.choice[0]; + choice[1] = other.choice[1]; + nrActive = other.nrActive; + return *this; +} + +void RunwayGroup::setActive(const string &aptId, + double windSpeed, + double windHeading, + double maxTail, + double maxCross) +{ + + FGRunway rwy; + int activeRwys = rwyList.size(); // get the number of runways active + int nrOfPreferences; + // bool found = true; + // double heading; + double hdgDiff; + double crossWind; + double tailWind; + string name; + + if (activeRwys > 0) + { + nrOfPreferences = rwyList[0].getRwyList()->size(); + for (int i = 0; i < nrOfPreferences; i++) + { + bool validSelection = true; + for (int j = 0; j < activeRwys; j++) + { + //cerr << "I J " << i << " " << j << endl; + name = rwyList[j].getRwyList(i); + //cerr << "Name of Runway: " << name << endl; + if (globals->get_runways()->search( aptId, + name, + &rwy)) + { + //cerr << "Succes" << endl; + hdgDiff = fabs(windHeading - rwy._heading); + //cerr << "Wind Heading: " << windHeading << "Runway Heading: " < 180) + hdgDiff = 360 - hdgDiff; + //cerr << "Heading diff: " << hdgDiff << endl; + hdgDiff *= ((2*M_PI)/360.0); // convert to radians + crossWind = windSpeed * sin(hdgDiff); + tailWind = -windSpeed * cos(hdgDiff); + //cerr << "Tailwind : " << tailWind << endl; + //cerr << "Crosswnd : " << crossWind << endl; + if ((tailWind > maxTail) || (crossWind > maxCross)) + validSelection = false; + }else { + SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId ); + exit(1); + } + + } + if (validSelection) + { + //cerr << "Valid runay selection : " << i << endl; + nrActive = activeRwys; + active = i; + return; + } + } + // If this didn't work, due to heavy winds, try again + // but select only one landing and one takeoff runway. + choice[0] = 0; + choice[1] = 0; + for (int i = activeRwys-1; i; i--) + { + if (rwyList[i].getType() == string("landing")) + choice[0] = i; + if (rwyList[i].getType() == string("takeoff")) + choice[1] = i; + } + //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl; + nrOfPreferences = rwyList[0].getRwyList()->size(); + for (int i = 0; i < nrOfPreferences; i++) + { + bool validSelection = true; + for (int j = 0; j < 2; j++) + { + //cerr << "I J " << i << " " << j << endl; + name = rwyList[choice[j]].getRwyList(i); + //cerr << "Name of Runway: " << name << endl; + if (globals->get_runways()->search( aptId, + name, + &rwy)) + { + //cerr << "Succes" << endl; + hdgDiff = fabs(windHeading - rwy._heading); + //cerr << "Wind Heading: " << windHeading << "Runway Heading: " < 180) + hdgDiff = 360 - hdgDiff; + //cerr << "Heading diff: " << hdgDiff << endl; + hdgDiff *= ((2*M_PI)/360.0); // convert to radians + crossWind = windSpeed * sin(hdgDiff); + tailWind = -windSpeed * cos(hdgDiff); + //cerr << "Tailwind : " << tailWind << endl; + //cerr << "Crosswnd : " << crossWind << endl; + if ((tailWind > maxTail) || (crossWind > maxCross)) + validSelection = false; + }else { + SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId ); + exit(1); + } + + } + if (validSelection) + { + //cerr << "Valid runay selection : " << i << endl; + active = i; + nrActive = 2; + return; + } + } + } + active = -1; + //RunwayListVectorIterator i; // = rwlist.begin(); + //stringVecIterator j; + //for (i = rwyList.begin(); i != rwyList.end(); i++) + // { + // cerr << i->getType(); + // for (j = i->getRwyList()->begin(); j != i->getRwyList()->end(); j++) + // { + // cerr << (*j); + // } + // cerr << endl; + // } + //for (int + +} + +void RunwayGroup::getActive(int i, string &name, string &type) +{ + if (i == -1) + { + return; + } + if (nrActive == (int)rwyList.size()) + { + name = rwyList[i].getRwyList(active); + type = rwyList[i].getType(); + } + else + { + name = rwyList[choice[i]].getRwyList(active); + type = rwyList[choice[i]].getType(); + } +} +/***************************************************************************** + * FGRunway preference + ****************************************************************************/ +FGRunwayPreference::FGRunwayPreference() +{ + //cerr << "Running default Constructor" << endl; + initialized = false; +} + +FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other) +{ + initialized = other.initialized; + value = other.value; + scheduleName = other.scheduleName; + + comTimes = other.comTimes; // Commercial Traffic; + genTimes = other.genTimes; // General Aviation; + milTimes = other.milTimes; // Military Traffic; + currTimes= other.currTimes; // Needed for parsing; + + rwyList = other.rwyList; + rwyGroup = other.rwyGroup; + PreferenceListConstIterator i; + for (i = other.preferences.begin(); i != other.preferences.end(); i++) + preferences.push_back(*i); +} + +FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other) +{ + initialized = other.initialized; + value = other.value; + scheduleName = other.scheduleName; + + comTimes = other.comTimes; // Commercial Traffic; + genTimes = other.genTimes; // General Aviation; + milTimes = other.milTimes; // Military Traffic; + currTimes= other.currTimes; // Needed for parsing; + + rwyList = other.rwyList; + rwyGroup = other.rwyGroup; + PreferenceListConstIterator i; + preferences.clear(); + for (i = other.preferences.begin(); i != other.preferences.end(); i++) + preferences.push_back(*i); + return *this; +} + +ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType) +{ + if (!(strcmp(trafficType, "com"))) { + return &comTimes; + } + if (!(strcmp(trafficType, "gen"))) { + return &genTimes; + } + if (!(strcmp(trafficType, "mil"))) { + return &milTimes; + } + return 0; +} + +RunwayGroup *FGRunwayPreference::getGroup(const string &groupName) +{ + PreferenceListIterator i = preferences.begin(); + if (preferences.begin() == preferences.end()) + return 0; + while (!(i == preferences.end() || i->getName() == groupName)) + i++; + if (i != preferences.end()) + return &(*i); + else + return 0; +} + +void FGRunwayPreference::startXML () { + // cout << "Start XML" << endl; +} + +void FGRunwayPreference::endXML () { + cout << "End XML" << endl; +} + +void FGRunwayPreference::startElement (const char * name, const XMLAttributes &atts) { + //cout << "StartElement " << name << endl; + value = string(""); + if (!(strcmp(name, "wind"))) { + //cerr << "Will be processing Wind" << endl; + for (int i = 0; i < atts.size(); i++) + { + //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; + //attname = atts.getName(i); + if (atts.getName(i) == string("tail")) { + //cerr << "Tail Wind = " << atts.getValue(i) << endl; + currTimes.setTailWind(atof(atts.getValue(i))); + } + if (atts.getName(i) == string("cross")) { + //cerr << "Cross Wind = " << atts.getValue(i) << endl; + currTimes.setCrossWind(atof(atts.getValue(i))); + } + } + } + if (!(strcmp(name, "time"))) { + //cerr << "Will be processing time" << endl; + for (int i = 0; i < atts.size(); i++) + { + if (atts.getName(i) == string("start")) { + //cerr << "Start Time = " << atts.getValue(i) << endl; + currTimes.addStartTime(processTime(atts.getValue(i))); + } + if (atts.getName(i) == string("end")) { + //cerr << "End time = " << atts.getValue(i) << endl; + currTimes.addEndTime(processTime(atts.getValue(i))); + } + if (atts.getName(i) == string("schedule")) { + //cerr << "Schedule Name = " << atts.getValue(i) << endl; + currTimes.addScheduleName(atts.getValue(i)); + } + } + } + if (!(strcmp(name, "takeoff"))) { + rwyList.clear(); + } + if (!(strcmp(name, "landing"))) + { + rwyList.clear(); + } + if (!(strcmp(name, "schedule"))) { + for (int i = 0; i < atts.size(); i++) + { + //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; + //attname = atts.getName(i); + if (atts.getName(i) == string("name")) { + //cerr << "Schedule name = " << atts.getValue(i) << endl; + scheduleName = atts.getValue(i); + } + } + } +} + +//based on a string containing hour and minute, return nr seconds since day start. +time_t FGRunwayPreference::processTime(const string &tme) +{ + string hour = tme.substr(0, tme.find(":",0)); + string minute = tme.substr(tme.find(":",0)+1, tme.length()); + + //cerr << "hour = " << hour << " Minute = " << minute << endl; + return (atoi(hour.c_str()) * 3600 + atoi(minute.c_str()) * 60); +} + +void FGRunwayPreference::endElement (const char * name) { + //cout << "End element " << name << endl; + if (!(strcmp(name, "rwyuse"))) { + initialized = true; + } + if (!(strcmp(name, "com"))) { // Commercial Traffic + //cerr << "Setting time table for commerical traffic" << endl; + comTimes = currTimes; + currTimes.clear(); + } + if (!(strcmp(name, "gen"))) { // General Aviation + //cerr << "Setting time table for general aviation" << endl; + genTimes = currTimes; + currTimes.clear(); + } + if (!(strcmp(name, "mil"))) { // Military Traffic + //cerr << "Setting time table for military traffic" << endl; + genTimes = currTimes; + currTimes.clear(); + } + + if (!(strcmp(name, "takeoff"))) { + //cerr << "Adding takeoff: " << value << endl; + rwyList.set(name, value); + rwyGroup.add(rwyList); + } + if (!(strcmp(name, "landing"))) { + //cerr << "Adding landing: " << value << endl; + rwyList.set(name, value); + rwyGroup.add(rwyList); + } + if (!(strcmp(name, "schedule"))) { + //cerr << "Adding schedule" << scheduleName << endl; + rwyGroup.setName(scheduleName); + //rwyGroup.addRunways(rwyList); + preferences.push_back(rwyGroup); + rwyGroup.clear(); + //exit(1); + } +} + +void FGRunwayPreference::data (const char * s, int len) { + string token = string(s,len); + //cout << "Character data " << string(s,len) << endl; + //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos)) + // value += token; + //else + // value = string(""); + value += token; +} + +void FGRunwayPreference::pi (const char * target, const char * data) { + //cout << "Processing instruction " << target << ' ' << data << endl; +} + +void FGRunwayPreference::warning (const char * message, int line, int column) { + cout << "Warning: " << message << " (" << line << ',' << column << ')' + << endl; +} + +void FGRunwayPreference::error (const char * message, int line, int column) { + cout << "Error: " << message << " (" << line << ',' << column << ')' + << endl; +} diff --git a/src/Airports/runwayprefs.hxx b/src/Airports/runwayprefs.hxx new file mode 100644 index 000000000..17148de2b --- /dev/null +++ b/src/Airports/runwayprefs.hxx @@ -0,0 +1,159 @@ +// runwayprefs.hxx - A number of classes to configure runway +// assignments by the AI code +// +// Written by Durk Talsma, started January 2005. +// +// Copyright (C) 2004 Durk Talsma. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _RUNWAYPREFS_HXX_ +#define _RUNWAYPREFS_HXX_ + +#include + +typedef vector timeVec; +typedef vector::const_iterator timeVecConstIterator; + +typedef vector stringVec; +typedef vector::iterator stringVecIterator; +typedef vector::const_iterator stringVecConstIterator; + + +/***************************************************************************/ +class ScheduleTime { +private: + timeVec start; + timeVec end; + stringVec scheduleNames; + double tailWind; + double crssWind; +public: + ScheduleTime() : tailWind(0), crssWind(0) {}; + ScheduleTime(const ScheduleTime &other); + ScheduleTime &operator= (const ScheduleTime &other); + string getName(time_t dayStart); + + void clear(); + void addStartTime(time_t time) { start.push_back(time); }; + void addEndTime (time_t time) { end. push_back(time); }; + void addScheduleName(const string& sched) { scheduleNames.push_back(sched); }; + void setTailWind(double wnd) { tailWind = wnd; }; + void setCrossWind(double wnd) { tailWind = wnd; }; + + double getTailWind() { return tailWind; }; + double getCrossWind() { return crssWind; }; +}; + +//typedef vector ScheduleTimes; +/*****************************************************************************/ + +class RunwayList +{ +private: + string type; + stringVec preferredRunways; +public: + RunwayList() {}; + RunwayList(const RunwayList &other); + RunwayList& operator= (const RunwayList &other); + + void set(const string&, const string&); + void clear(); + + string getType() { return type; }; + stringVec *getRwyList() { return &preferredRunways; }; + string getRwyList(int j) { return preferredRunways[j]; }; +}; + +typedef vector RunwayListVec; +typedef vector::iterator RunwayListVectorIterator; +typedef vector::const_iterator RunwayListVecConstIterator; + + +/*****************************************************************************/ + +class RunwayGroup +{ +private: + string name; + RunwayListVec rwyList; + int active; + //stringVec runwayNames; + int choice[2]; + int nrActive; +public: + RunwayGroup() {}; + RunwayGroup(const RunwayGroup &other); + RunwayGroup &operator= (const RunwayGroup &other); + + void setName(const string& nm) { name = nm; }; + void add(const RunwayList& list) { rwyList.push_back(list);}; + void setActive(const string& aptId, double windSpeed, double windHeading, double maxTail, double maxCross); + + int getNrActiveRunways() { return nrActive;}; + void getActive(int i, string& name, string& type); + + string getName() { return name; }; + void clear() { rwyList.clear(); }; + //void add(string, string); +}; + +typedef vector PreferenceList; +typedef vector::iterator PreferenceListIterator; +typedef vector::const_iterator PreferenceListConstIterator; + +/******************************************************************************/ + +class FGRunwayPreference : public XMLVisitor { +private: + string value; + string scheduleName; + + ScheduleTime comTimes; // Commercial Traffic; + ScheduleTime genTimes; // General Aviation; + ScheduleTime milTimes; // Military Traffic; + ScheduleTime currTimes; // Needed for parsing; + + RunwayList rwyList; + RunwayGroup rwyGroup; + PreferenceList preferences; + + time_t processTime(const string&); + bool initialized; + +public: + FGRunwayPreference(); + FGRunwayPreference(const FGRunwayPreference &other); + + FGRunwayPreference & operator= (const FGRunwayPreference &other); + ScheduleTime *getSchedule(const char *trafficType); + RunwayGroup *getGroup(const string& groupName); + bool available() { return initialized; }; + + // Some overloaded virtual XMLVisitor members + virtual void startXML (); + virtual void endXML (); + virtual void startElement (const char * name, const XMLAttributes &atts); + virtual void endElement (const char * name); + virtual void data (const char * s, int len); + virtual void pi (const char * target, const char * data); + virtual void warning (const char * message, int line, int column); + virtual void error (const char * message, int line, int column); +}; + +#endif diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx index 464c32fea..36459fd16 100644 --- a/src/Airports/simple.cxx +++ b/src/Airports/simple.cxx @@ -44,6 +44,7 @@ #include #include #include +//#include #include #include
#include
@@ -57,563 +58,8 @@ SG_USING_STD(sort); SG_USING_STD(random_shuffle); -/****************************************************************************** - * ScheduleTime - ***************e*************************************************************/ -void ScheduleTime::clear() -{ - start.clear(); - end.clear(); - scheduleNames.clear(); -} -ScheduleTime::ScheduleTime(const ScheduleTime &other) -{ - //timeVec start; - timeVecConstIterator i; - for (i = other.start.begin(); i != other.start.end(); i++) - start.push_back(*i); - for (i = other.end.begin(); i != other.end.end(); i++) - end.push_back(*i); - stringVecConstIterator k; - for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++) - scheduleNames.push_back(*k); - - //timeVec end; - //stringVec scheduleNames; - tailWind = other.tailWind; - crssWind = other.tailWind; -} - - -ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other) -{ - //timeVec start; - clear(); - timeVecConstIterator i; - for (i = other.start.begin(); i != other.start.end(); i++) - start.push_back(*i); - for (i = other.end.begin(); i != other.end.end(); i++) - end.push_back(*i); - stringVecConstIterator k; - for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++) - scheduleNames.push_back(*k); - - //timeVec end; - //stringVec scheduleNames; - tailWind = other.tailWind; - crssWind = other.tailWind; - return *this; -} -string ScheduleTime::getName(time_t dayStart) -{ - if ((start.size() != end.size()) || (start.size() != scheduleNames.size())) - { - SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" ); - exit(1); - } - else - { - int nrItems = start.size(); - //cerr << "Nr of items to process: " << nrItems << endl; - if (nrItems > 0) - { - for (unsigned int i = 0; i < start.size(); i++) - { - //cerr << i << endl; - if ((dayStart >= start[i]) && (dayStart <= end[i])) - return scheduleNames[i]; - } - } - //couldn't find one so return 0; - //cerr << "Returning 0 " << endl; - } - return string(0); -} -/****************************************************************************** - * RunwayList - *****************************************************************************/ - -RunwayList::RunwayList(const RunwayList &other) -{ - type = other.type; - stringVecConstIterator i; - for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++) - preferredRunways.push_back(*i); -} -RunwayList& RunwayList::operator= (const RunwayList &other) -{ - type = other.type; - preferredRunways.clear(); - stringVecConstIterator i; - for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++) - preferredRunways.push_back(*i); - return *this; -} -void RunwayList::set(const string &tp, const string &lst) -{ - //weekday = atoi(timeCopy.substr(0,1).c_str()); - // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday; - // timeCopy = timeCopy.substr(2,timeCopy.length()); - type = tp; - string rwys = lst; - string rwy; - while (rwys.find(",") != string::npos) - { - rwy = rwys.substr(0, rwys.find(",",0)); - //cerr << "adding runway [" << rwy << "] to the list " << endl; - preferredRunways.push_back(rwy); - rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace - while (rwys[0] == ' ') - rwys.erase(0, 1); // Erase any leading whitespaces. - //cerr << "Remaining runway list " << rwys; - } - preferredRunways.push_back(rwys); - //exit(1); -} - -void RunwayList::clear() -{ - type = ""; - preferredRunways.clear(); -} -/**************************************************************************** - * - ***************************************************************************/ - -RunwayGroup::RunwayGroup(const RunwayGroup &other) -{ - name = other.name; - RunwayListVecConstIterator i; - for (i = other.rwyList.begin(); i != other.rwyList.end(); i++) - rwyList.push_back(*i); - choice[0] = other.choice[0]; - choice[1] = other.choice[1]; - nrActive = other.nrActive; -} -RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other) -{ - rwyList.clear(); - name = other.name; - RunwayListVecConstIterator i; - for (i = other.rwyList.begin(); i != other.rwyList.end(); i++) - rwyList.push_back(*i); - choice[0] = other.choice[0]; - choice[1] = other.choice[1]; - nrActive = other.nrActive; - return *this; -} - -void RunwayGroup::setActive(const string &aptId, - double windSpeed, - double windHeading, - double maxTail, - double maxCross) -{ - - FGRunway rwy; - int activeRwys = rwyList.size(); // get the number of runways active - int nrOfPreferences; - // bool found = true; - // double heading; - double hdgDiff; - double crossWind; - double tailWind; - string name; - - if (activeRwys > 0) - { - nrOfPreferences = rwyList[0].getRwyList()->size(); - for (int i = 0; i < nrOfPreferences; i++) - { - bool validSelection = true; - for (int j = 0; j < activeRwys; j++) - { - //cerr << "I J " << i << " " << j << endl; - name = rwyList[j].getRwyList(i); - //cerr << "Name of Runway: " << name << endl; - if (globals->get_runways()->search( aptId, - name, - &rwy)) - { - //cerr << "Succes" << endl; - hdgDiff = fabs(windHeading - rwy._heading); - //cerr << "Wind Heading: " << windHeading << "Runway Heading: " < 180) - hdgDiff = 360 - hdgDiff; - //cerr << "Heading diff: " << hdgDiff << endl; - hdgDiff *= ((2*M_PI)/360.0); // convert to radians - crossWind = windSpeed * sin(hdgDiff); - tailWind = -windSpeed * cos(hdgDiff); - //cerr << "Tailwind : " << tailWind << endl; - //cerr << "Crosswnd : " << crossWind << endl; - if ((tailWind > maxTail) || (crossWind > maxCross)) - validSelection = false; - }else { - SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId ); - exit(1); - } - - } - if (validSelection) - { - //cerr << "Valid runay selection : " << i << endl; - nrActive = activeRwys; - active = i; - return; - } - } - // If this didn't work, due to heavy winds, try again - // but select only one landing and one takeoff runway. - choice[0] = 0; - choice[1] = 0; - for (int i = activeRwys-1; i; i--) - { - if (rwyList[i].getType() == string("landing")) - choice[0] = i; - if (rwyList[i].getType() == string("takeoff")) - choice[1] = i; - } - //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl; - nrOfPreferences = rwyList[0].getRwyList()->size(); - for (int i = 0; i < nrOfPreferences; i++) - { - bool validSelection = true; - for (int j = 0; j < 2; j++) - { - //cerr << "I J " << i << " " << j << endl; - name = rwyList[choice[j]].getRwyList(i); - //cerr << "Name of Runway: " << name << endl; - if (globals->get_runways()->search( aptId, - name, - &rwy)) - { - //cerr << "Succes" << endl; - hdgDiff = fabs(windHeading - rwy._heading); - //cerr << "Wind Heading: " << windHeading << "Runway Heading: " < 180) - hdgDiff = 360 - hdgDiff; - //cerr << "Heading diff: " << hdgDiff << endl; - hdgDiff *= ((2*M_PI)/360.0); // convert to radians - crossWind = windSpeed * sin(hdgDiff); - tailWind = -windSpeed * cos(hdgDiff); - //cerr << "Tailwind : " << tailWind << endl; - //cerr << "Crosswnd : " << crossWind << endl; - if ((tailWind > maxTail) || (crossWind > maxCross)) - validSelection = false; - }else { - SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId ); - exit(1); - } - - } - if (validSelection) - { - //cerr << "Valid runay selection : " << i << endl; - active = i; - nrActive = 2; - return; - } - } - } - active = -1; - //RunwayListVectorIterator i; // = rwlist.begin(); - //stringVecIterator j; - //for (i = rwyList.begin(); i != rwyList.end(); i++) - // { - // cerr << i->getType(); - // for (j = i->getRwyList()->begin(); j != i->getRwyList()->end(); j++) - // { - // cerr << (*j); - // } - // cerr << endl; - // } - //for (int - -} - -void RunwayGroup::getActive(int i, string &name, string &type) -{ - if (i == -1) - { - return; - } - if (nrActive == (int)rwyList.size()) - { - name = rwyList[i].getRwyList(active); - type = rwyList[i].getType(); - } - else - { - name = rwyList[choice[i]].getRwyList(active); - type = rwyList[choice[i]].getType(); - } -} -/***************************************************************************** - * FGRunway preference - ****************************************************************************/ -FGRunwayPreference::FGRunwayPreference() -{ - //cerr << "Running default Constructor" << endl; - initialized = false; -} - -FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other) -{ - initialized = other.initialized; - value = other.value; - scheduleName = other.scheduleName; - - comTimes = other.comTimes; // Commercial Traffic; - genTimes = other.genTimes; // General Aviation; - milTimes = other.milTimes; // Military Traffic; - currTimes= other.currTimes; // Needed for parsing; - - rwyList = other.rwyList; - rwyGroup = other.rwyGroup; - PreferenceListConstIterator i; - for (i = other.preferences.begin(); i != other.preferences.end(); i++) - preferences.push_back(*i); -} - -FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other) -{ - initialized = other.initialized; - value = other.value; - scheduleName = other.scheduleName; - - comTimes = other.comTimes; // Commercial Traffic; - genTimes = other.genTimes; // General Aviation; - milTimes = other.milTimes; // Military Traffic; - currTimes= other.currTimes; // Needed for parsing; - - rwyList = other.rwyList; - rwyGroup = other.rwyGroup; - PreferenceListConstIterator i; - preferences.clear(); - for (i = other.preferences.begin(); i != other.preferences.end(); i++) - preferences.push_back(*i); - return *this; -} - -ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType) -{ - if (!(strcmp(trafficType, "com"))) { - return &comTimes; - } - if (!(strcmp(trafficType, "gen"))) { - return &genTimes; - } - if (!(strcmp(trafficType, "mil"))) { - return &milTimes; - } - return 0; -} - -RunwayGroup *FGRunwayPreference::getGroup(const string &groupName) -{ - PreferenceListIterator i = preferences.begin(); - if (preferences.begin() == preferences.end()) - return 0; - while (!(i == preferences.end() || i->getName() == groupName)) - i++; - if (i != preferences.end()) - return &(*i); - else - return 0; -} - -void FGRunwayPreference::startXML () { - // cout << "Start XML" << endl; -} - -void FGRunwayPreference::endXML () { - cout << "End XML" << endl; -} - -void FGRunwayPreference::startElement (const char * name, const XMLAttributes &atts) { - //cout << "StartElement " << name << endl; - value = string(""); - if (!(strcmp(name, "wind"))) { - //cerr << "Will be processing Wind" << endl; - for (int i = 0; i < atts.size(); i++) - { - //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; - //attname = atts.getName(i); - if (atts.getName(i) == string("tail")) { - //cerr << "Tail Wind = " << atts.getValue(i) << endl; - currTimes.setTailWind(atof(atts.getValue(i))); - } - if (atts.getName(i) == string("cross")) { - //cerr << "Cross Wind = " << atts.getValue(i) << endl; - currTimes.setCrossWind(atof(atts.getValue(i))); - } - } - } - if (!(strcmp(name, "time"))) { - //cerr << "Will be processing time" << endl; - for (int i = 0; i < atts.size(); i++) - { - if (atts.getName(i) == string("start")) { - //cerr << "Start Time = " << atts.getValue(i) << endl; - currTimes.addStartTime(processTime(atts.getValue(i))); - } - if (atts.getName(i) == string("end")) { - //cerr << "End time = " << atts.getValue(i) << endl; - currTimes.addEndTime(processTime(atts.getValue(i))); - } - if (atts.getName(i) == string("schedule")) { - //cerr << "Schedule Name = " << atts.getValue(i) << endl; - currTimes.addScheduleName(atts.getValue(i)); - } - } - } - if (!(strcmp(name, "takeoff"))) { - rwyList.clear(); - } - if (!(strcmp(name, "landing"))) - { - rwyList.clear(); - } - if (!(strcmp(name, "schedule"))) { - for (int i = 0; i < atts.size(); i++) - { - //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; - //attname = atts.getName(i); - if (atts.getName(i) == string("name")) { - //cerr << "Schedule name = " << atts.getValue(i) << endl; - scheduleName = atts.getValue(i); - } - } - } -} - -//based on a string containing hour and minute, return nr seconds since day start. -time_t FGRunwayPreference::processTime(const string &tme) -{ - string hour = tme.substr(0, tme.find(":",0)); - string minute = tme.substr(tme.find(":",0)+1, tme.length()); - - //cerr << "hour = " << hour << " Minute = " << minute << endl; - return (atoi(hour.c_str()) * 3600 + atoi(minute.c_str()) * 60); -} - -void FGRunwayPreference::endElement (const char * name) { - //cout << "End element " << name << endl; - if (!(strcmp(name, "rwyuse"))) { - initialized = true; - } - if (!(strcmp(name, "com"))) { // Commercial Traffic - //cerr << "Setting time table for commerical traffic" << endl; - comTimes = currTimes; - currTimes.clear(); - } - if (!(strcmp(name, "gen"))) { // General Aviation - //cerr << "Setting time table for general aviation" << endl; - genTimes = currTimes; - currTimes.clear(); - } - if (!(strcmp(name, "mil"))) { // Military Traffic - //cerr << "Setting time table for military traffic" << endl; - genTimes = currTimes; - currTimes.clear(); - } - - if (!(strcmp(name, "takeoff"))) { - //cerr << "Adding takeoff: " << value << endl; - rwyList.set(name, value); - rwyGroup.add(rwyList); - } - if (!(strcmp(name, "landing"))) { - //cerr << "Adding landing: " << value << endl; - rwyList.set(name, value); - rwyGroup.add(rwyList); - } - if (!(strcmp(name, "schedule"))) { - //cerr << "Adding schedule" << scheduleName << endl; - rwyGroup.setName(scheduleName); - //rwyGroup.addRunways(rwyList); - preferences.push_back(rwyGroup); - rwyGroup.clear(); - //exit(1); - } -} - -void FGRunwayPreference::data (const char * s, int len) { - string token = string(s,len); - //cout << "Character data " << string(s,len) << endl; - //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos)) - // value += token; - //else - // value = string(""); - value += token; -} - -void FGRunwayPreference::pi (const char * target, const char * data) { - //cout << "Processing instruction " << target << ' ' << data << endl; -} - -void FGRunwayPreference::warning (const char * message, int line, int column) { - cout << "Warning: " << message << " (" << line << ',' << column << ')' - << endl; -} - -void FGRunwayPreference::error (const char * message, int line, int column) { - cout << "Error: " << message << " (" << line << ',' << column << ')' - << endl; -} - -/***************************************************************************** - * Helper function for parsing position string - ****************************************************************************/ -double processPosition(const string &pos) -{ - string prefix; - string subs; - string degree; - string decimal; - int sign = 1; - double value; - subs = pos; - prefix= subs.substr(0,1); - if (prefix == string("S") || (prefix == string("W"))) - sign = -1; - subs = subs.substr(1, subs.length()); - degree = subs.substr(0, subs.find(" ",0)); - decimal = subs.substr(subs.find(" ",0), subs.length()); - - - //cerr << sign << " "<< degree << " " << decimal << endl; - value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0); - //cerr << value <get_fg_root() ); + parkpath.append( "/Airports/AI/" ); + parkpath.append(_id); + parkpath.append("parking.xml"); + + SGPath rwyPrefPath( globals->get_fg_root() ); + rwyPrefPath.append( "/Airports/AI/" ); + rwyPrefPath.append(_id); + rwyPrefPath.append("rwyuse.xml"); + //if (ai_dirs.find(id.c_str()) != ai_dirs.end() + // && parkpath.exists()) + if (parkpath.exists()) { - //cerr << "Gate Id: " << i->getIndex() - // << " Type : " << i->getType() - // << " Codes : " << i->getCodes() - // << " Radius: " << i->getRadius() - // << " Name : " << i->getName() - // << " Available: " << i->isAvailable() << endl; - available = true; - // Taken by another aircraft - if (!(i->isAvailable())) - { - available = false; - continue; - } - // No airline codes, so skip - if (i->getCodes().empty()) - { - available = false; - continue; - } - else // Airline code doesn't match - if (i->getCodes().find(airline, 0) == string::npos) - { - available = false; - continue; - } - // Type doesn't match - if (i->getType() != flType) - { - available = false; - continue; - } - // too small - if (i->getRadius() < rad) - { - available = false; - continue; - } - - if (available) - { - *lat = i->getLatitude (); - *lon = i->getLongitude(); - *heading = i->getHeading (); - *gateId = i->getIndex (); - i->setAvailable(false); - found = true; - } - } - // then try again for those without codes. - for (i = parkings.begin(); !(i == parkings.end() || found); i++) - { - available = true; - if (!(i->isAvailable())) - { - available = false; - continue; - } - if (!(i->getCodes().empty())) - { - if ((i->getCodes().find(airline,0) == string::npos)) - { - available = false; - continue; + try { + readXML(parkpath.str(),*dynamics); + dynamics->init(); + } + catch (const sg_exception &e) { + //cerr << "unable to read " << parkpath.str() << endl; + } + } + //if (ai_dirs.find(id.c_str()) != ai_dirs.end() + // && rwyPrefPath.exists()) + if (rwyPrefPath.exists()) + { + try { + readXML(rwyPrefPath.str(), rwyPrefs); + dynamics->setRwyUse(rwyPrefs); + } + catch (const sg_exception &e) { + //cerr << "unable to read " << rwyPrefPath.str() << endl; + //exit(1); } - } - if (i->getType() != flType) - { - available = false; - continue; - } - - if (i->getRadius() < rad) - { - available = false; - continue; - } - - if (available) - { - *lat = i->getLatitude (); - *lon = i->getLongitude(); - *heading = i->getHeading (); - *gateId = i->getIndex (); - i->setAvailable(false); - found = true; - } - } - // And finally once more if that didn't work. Now ignore the airline codes, as a last resort - for (i = parkings.begin(); !(i == parkings.end() || found); i++) - { - available = true; - if (!(i->isAvailable())) - { - available = false; - continue; - } - if (i->getType() != flType) - { - available = false; - continue; - } - - if (i->getRadius() < rad) - { - available = false; - continue; - } - - if (available) - { - *lat = i->getLatitude (); - *lon = i->getLongitude(); - *heading = i->getHeading (); - *gateId = i->getIndex (); - i->setAvailable(false); - found = true; - } } - } - if (!found) - { - //cerr << "Traffic overflow at" << _id - // << ". flType = " << flType - // << ". airline = " << airline - // << " Radius = " <getIndex()) - { - *lat = i->getLatitude(); - *lon = i->getLongitude(); - *heading = i->getLongitude(); - } - } - } -} - -FGParking *FGAirport::getParking(int i) -{ - if (i < (int)parkings.size()) - return &(parkings[i]); - else - return 0; -} -string FGAirport::getParkingName(int i) -{ - if (i < (int)parkings.size() && i >= 0) - return (parkings[i].getName()); - else - return string("overflow"); -} -void FGAirport::releaseParking(int id) -{ - if (id >= 0) - { - - FGParkingVecIterator i = parkings.begin(); - for (i = parkings.begin(); i != parkings.end(); i++) - { - if (id == i->getIndex()) - { - i -> setAvailable(true); - } - } - } -} - -void FGAirport::startXML () { - //cout << "Start XML" << endl; -} - -void FGAirport::endXML () { - //cout << "End XML" << endl; -} - -void FGAirport::startElement (const char * name, const XMLAttributes &atts) { - // const char *attval; - FGParking park; - FGTaxiNode taxiNode; - FGTaxiSegment taxiSegment; - int index = 0; - taxiSegment.setIndex(index); - //cout << "Start element " << name << endl; - string attname; - string value; - string gateName; - string gateNumber; - string lat; - string lon; - if (name == string("Parking")) - { - for (int i = 0; i < atts.size(); i++) - { - //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; - attname = atts.getName(i); - if (attname == string("index")) - park.setIndex(atoi(atts.getValue(i))); - else if (attname == string("type")) - park.setType(atts.getValue(i)); - else if (attname == string("name")) - gateName = atts.getValue(i); - else if (attname == string("number")) - gateNumber = atts.getValue(i); - else if (attname == string("lat")) - park.setLatitude(atts.getValue(i)); - else if (attname == string("lon")) - park.setLongitude(atts.getValue(i)); - else if (attname == string("heading")) - park.setHeading(atof(atts.getValue(i))); - else if (attname == string("radius")) { - string radius = atts.getValue(i); - if (radius.find("M") != string::npos) - radius = radius.substr(0, radius.find("M",0)); - //cerr << "Radius " << radius < 600) || trafficType != prevTrafficType) - { - landing.clear(); - takeoff.clear(); - //lastUpdate = dayStart; - prevTrafficType = trafficType; - - FGEnvironment - stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) - ->getEnvironment(getLatitude(), - getLongitude(), - getElevation()); - - windSpeed = stationweather.get_wind_speed_kt(); - windHeading = stationweather.get_wind_from_heading_deg(); - double averageWindSpeed = 0; - double averageWindHeading = 0; - double cosHeading = 0; - double sinHeading = 0; - // Initialize at the beginning of the next day or startup - if ((lastUpdate == 0) || (dayStart < lastUpdate)) - { - for (int i = 0; i < 10; i++) - { - avWindHeading [i] = windHeading; - avWindSpeed [i] = windSpeed; - } - } - else - { - if (windSpeed != avWindSpeed[9]) // update if new metar data - { - // shift the running average - for (int i = 0; i < 9 ; i++) - { - avWindHeading[i] = avWindHeading[i+1]; - avWindSpeed [i] = avWindSpeed [i+1]; - } - } - avWindHeading[9] = windHeading; - avWindSpeed [9] = windSpeed; - } - - for (int i = 0; i < 10; i++) - { - averageWindSpeed += avWindSpeed [i]; - //averageWindHeading += avWindHeading [i]; - cosHeading += cos(avWindHeading[i] * SG_DEGREES_TO_RADIANS); - sinHeading += sin(avWindHeading[i] * SG_DEGREES_TO_RADIANS); - } - averageWindSpeed /= 10; - //averageWindHeading /= 10; - cosHeading /= 10; - sinHeading /= 10; - averageWindHeading = atan2(sinHeading, cosHeading) *SG_RADIANS_TO_DEGREES; - if (averageWindHeading < 0) - averageWindHeading += 360.0; - //cerr << "Wind Heading " << windHeading << " average " << averageWindHeading << endl; - //cerr << "Wind Speed " << windSpeed << " average " << averageWindSpeed << endl; - lastUpdate = dayStart; - //if (wind_speed == 0) { - // wind_heading = 270; This forces West-facing rwys to be used in no-wind situations - // which is consistent with Flightgear's initial setup. - //} - - //string rwy_no = globals->get_runways()->search(apt->getId(), int(wind_heading)); - string scheduleName; - //cerr << "finding active Runway for" << _id << endl; - //cerr << "Nr of seconds since day start << " << dayStart << endl; - ScheduleTime *currSched; - //cerr << "A"<< endl; - currSched = rwyPrefs.getSchedule(trafficType.c_str()); - if (!(currSched)) - return; - //cerr << "B"<< endl; - scheduleName = currSched->getName(dayStart); - maxTail = currSched->getTailWind (); - maxCross = currSched->getCrossWind (); - //cerr << "SChedule anme = " << scheduleName << endl; - if (scheduleName.empty()) - return; - //cerr << "C"<< endl; - currRunwayGroup = rwyPrefs.getGroup(scheduleName); - //cerr << "D"<< endl; - if (!(currRunwayGroup)) - return; - nrActiveRunways = currRunwayGroup->getNrActiveRunways(); - //cerr << "Nr of Active Runways = " << nrActiveRunways << endl; - currRunwayGroup->setActive(_id, averageWindSpeed, averageWindHeading, maxTail, maxCross); - nrActiveRunways = currRunwayGroup->getNrActiveRunways(); - for (int i = 0; i < nrActiveRunways; i++) - { - type = "unknown"; // initialize to something other than landing or takeoff - currRunwayGroup->getActive(i, name, type); - if (type == "landing") - { - landing.push_back(name); - //cerr << "Landing " << name << endl; - } - if (type == "takeoff") - { - takeoff.push_back(name); - //cerr << "takeoff " << name << endl; - } - } - } - if (action == 1) // takeoff - { - int nr = takeoff.size(); - if (nr) - { - runway = takeoff[(rand() % nr)]; - } - else - { // Fallback - runway = chooseRunwayFallback(); - } - } - if (action == 2) // landing - { - int nr = landing.size(); - if (nr) - { - runway = landing[(rand() % nr)]; - } - else - { //fallback - runway = chooseRunwayFallback(); - } - } - - //runway = globals->get_runways()->search(_id, int(windHeading)); - //cerr << "Seleceted runway: " << runway << endl; - } -} - -string FGAirport::chooseRunwayFallback() -{ - FGEnvironment - stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) - ->getEnvironment(getLatitude(), - getLongitude(), - getElevation()); - - double windSpeed = stationweather.get_wind_speed_kt(); - double windHeading = stationweather.get_wind_from_heading_deg(); - if (windSpeed == 0) { - windHeading = 270; // This forces West-facing rwys to be used in no-wind situations - //which is consistent with Flightgear's initial setup. - } - - return globals->get_runways()->search(_id, int(windHeading)); + return dynamics; } -/************************************************************************** - * FGTaxiNode - *************************************************************************/ -FGTaxiNode::FGTaxiNode() -{ -} - -/*************************************************************************** - * FGTaxiSegment - **************************************************************************/ -FGTaxiSegment::FGTaxiSegment() -{ -} - -void FGTaxiSegment::setStart(FGTaxiNodeVector *nodes) -{ - FGTaxiNodeVectorIterator i = nodes->begin(); - while (i != nodes->end()) - { - if (i->getIndex() == startNode) - { - start = i->getAddress(); - i->addSegment(this); - return; - } - i++; - } -} - -void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes) -{ - FGTaxiNodeVectorIterator i = nodes->begin(); - while (i != nodes->end()) - { - if (i->getIndex() == endNode) - { - end = i->getAddress(); - return; - } - i++; - } -} - -// There is probably a computationally cheaper way of -// doing this. -void FGTaxiSegment::setTrackDistance() -{ - double course; - SGWayPoint first (start->getLongitude(), - start->getLatitude(), - 0); - SGWayPoint second (end->getLongitude(), - end->getLatitude(), - 0); - first.CourseAndDistance(second, &course, &length); - -} - -bool FGTaxiRoute::next(int *val) -{ - //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++) - // cerr << "FGTaxiRoute contains : " << *(i) << endl; - //cerr << "Offset from end: " << nodes.end() - currNode << endl; - //if (currNode != nodes.end()) - // cerr << "true" << endl; - //else - // cerr << "false" << endl; - - if (currNode == nodes.end()) - return false; - *val = *(currNode); - currNode++; - return true; -}; -/*************************************************************************** - * FGGroundNetwork() - **************************************************************************/ - -FGGroundNetwork::FGGroundNetwork() -{ - hasNetwork = false; - foundRoute = false; - totalDistance = 0; - maxDistance = 0; -} - -void FGGroundNetwork::addSegment(const FGTaxiSegment &seg) -{ - segments.push_back(seg); -} - -void FGGroundNetwork::addNode(const FGTaxiNode &node) -{ - nodes.push_back(node); -} - -void FGGroundNetwork::addNodes(FGParkingVec *parkings) -{ - FGTaxiNode n; - FGParkingVecIterator i = parkings->begin(); - while (i != parkings->end()) - { - n.setIndex(i->getIndex()); - n.setLatitude(i->getLatitude()); - n.setLongitude(i->getLongitude()); - nodes.push_back(n); - - i++; - } -} - - - -void FGGroundNetwork::init() -{ - hasNetwork = true; - FGTaxiSegmentVectorIterator i = segments.begin(); - while(i != segments.end()) { - //cerr << "initializing node " << i->getIndex() << endl; - i->setStart(&nodes); - i->setEnd (&nodes); - i->setTrackDistance(); - //cerr << "Track distance = " << i->getLength() << endl; - //cerr << "Track ends at" << i->getEnd()->getIndex() << endl; - i++; - } - //exit(1); -} - -int FGGroundNetwork::findNearestNode(double lat, double lon) -{ - double minDist = HUGE_VAL; - double course, dist; - int index; - SGWayPoint first (lon, - lat, - 0); - - for (FGTaxiNodeVectorIterator - itr = nodes.begin(); - itr != nodes.end(); itr++) - { - double course; - SGWayPoint second (itr->getLongitude(), - itr->getLatitude(), - 0); - first.CourseAndDistance(second, &course, &dist); - if (dist < minDist) - { - minDist = dist; - index = itr->getIndex(); - //cerr << "Minimum distance of " << minDist << " for index " << index << endl; - } - } - return index; -} - -FGTaxiNode *FGGroundNetwork::findNode(int idx) -{ - for (FGTaxiNodeVectorIterator - itr = nodes.begin(); - itr != nodes.end(); itr++) - { - if (itr->getIndex() == idx) - return itr->getAddress(); - } - return 0; -} - -FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end) -{ - foundRoute = false; - totalDistance = 0; - FGTaxiNode *firstNode = findNode(start); - FGTaxiNode *lastNode = findNode(end); - //prevNode = prevPrevNode = -1; - //prevNode = start; - routes.clear(); - traceStack.clear(); - trace(firstNode, end, 0, 0); - FGTaxiRoute empty; - - if (!foundRoute) - { - SG_LOG( SG_GENERAL, SG_INFO, "Failed to find route from waypoint " << start << " to " << end ); - exit(1); - } - sort(routes.begin(), routes.end()); - //for (intVecIterator i = route.begin(); i != route.end(); i++) - // { - // rte->push_back(*i); - // } - - if (routes.begin() != routes.end()) - return *(routes.begin()); - else - return empty; -} - - -void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance) -{ - traceStack.push_back(currNode->getIndex()); - totalDistance += distance; - //cerr << "Starting trace " << depth << " total distance: " << totalDistance<< endl; - //<< currNode->getIndex() << endl; - - // If the current route matches the required end point we found a valid route - // So we can add this to the routing table - if (currNode->getIndex() == end) - { - //cerr << "Found route : " << totalDistance << "" << " " << *(traceStack.end()-1) << endl; - routes.push_back(FGTaxiRoute(traceStack,totalDistance)); - traceStack.pop_back(); - if (!(foundRoute)) - maxDistance = totalDistance; - else - if (totalDistance < maxDistance) - maxDistance = totalDistance; - foundRoute = true; - totalDistance -= distance; - return; - } - - - // search if the currentNode has been encountered before - // if so, we should step back one level, because it is - // rather rediculous to proceed further from here. - // if the current node has not been encountered before, - // i should point to traceStack.end()-1; and we can continue - // if i is not traceStack.end, the previous node was found, - // and we should return. - // This only works at trace levels of 1 or higher though - if (depth > 0) { - intVecIterator i = traceStack.begin(); - while ((*i) != currNode->getIndex()) { - //cerr << "Route so far : " << (*i) << endl; - i++; - } - if (i != traceStack.end()-1) { - traceStack.pop_back(); - totalDistance -= distance; - return; - } - // If the total distance from start to the current waypoint - // is longer than that of a route we can also stop this trace - // and go back one level. - if ((totalDistance > maxDistance) && foundRoute) - { - //cerr << "Stopping rediculously long trace: " << totalDistance << endl; - traceStack.pop_back(); - totalDistance -= distance; - return; - } - } - - //cerr << "2" << endl; - if (currNode->getBeginRoute() != currNode->getEndRoute()) - { - //cerr << "3" << endl; - for (FGTaxiSegmentPointerVectorIterator - i = currNode->getBeginRoute(); - i != currNode->getEndRoute(); - i++) - { - //cerr << (*i)->getLenght() << endl; - trace((*i)->getEnd(), end, depth+1, (*i)->getLength()); - // { - // // cerr << currNode -> getIndex() << " "; - // route.push_back(currNode->getIndex()); - // return true; - // } - } - } - else - { - SG_LOG( SG_GENERAL, SG_DEBUG, "4" ); - } - traceStack.pop_back(); - totalDistance -= distance; - return; -} - /****************************************************************************** @@ -1495,19 +152,22 @@ void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double dis // code to free this list after parsing of apt.dat is finished; // non-issue at the moment, however, as there are no AI subdirectories // in the base package. +// +// Note: 2005/12/23: This is probably not necessary anymore, because I'm +// Switching to runtime airport dynamics loading (DT). FGAirportList::FGAirportList() { - ulDir* d; - ulDirEnt* dent; - SGPath aid( globals->get_fg_root() ); - aid.append( "/Airports/AI" ); - if((d = ulOpenDir(aid.c_str())) == NULL) - return; - while((dent = ulReadDir(d)) != NULL) { - SG_LOG( SG_GENERAL, SG_DEBUG, "Dent: " << dent->d_name ); - ai_dirs.insert(dent->d_name); - } - ulCloseDir(d); +// ulDir* d; +// ulDirEnt* dent; +// SGPath aid( globals->get_fg_root() ); +// aid.append( "/Airports/AI" ); +// if((d = ulOpenDir(aid.c_str())) == NULL) +// return; +// while((dent = ulReadDir(d)) != NULL) { +// SG_LOG( SG_GENERAL, SG_DEBUG, "Dent: " << dent->d_name ); +// ai_dirs.insert(dent->d_name); +// } +// ulCloseDir(d); } @@ -1525,38 +185,7 @@ void FGAirportList::add( const string &id, const double longitude, { FGRunwayPreference rwyPrefs; FGAirport* a = new FGAirport(id, longitude, latitude, elevation, name, has_metar); - SGPath parkpath( globals->get_fg_root() ); - parkpath.append( "/Airports/AI/" ); - parkpath.append(id); - parkpath.append("parking.xml"); - - SGPath rwyPrefPath( globals->get_fg_root() ); - rwyPrefPath.append( "/Airports/AI/" ); - rwyPrefPath.append(id); - rwyPrefPath.append("rwyuse.xml"); - if (ai_dirs.find(id.c_str()) != ai_dirs.end() - && parkpath.exists()) - { - try { - readXML(parkpath.str(),*a); - a->init(); - } - catch (const sg_exception &e) { - //cerr << "unable to read " << parkpath.str() << endl; - } - } - if (ai_dirs.find(id.c_str()) != ai_dirs.end() - && rwyPrefPath.exists()) - { - try { - readXML(rwyPrefPath.str(), rwyPrefs); - a->setRwyUse(rwyPrefs); - } - catch (const sg_exception &e) { - //cerr << "unable to read " << rwyPrefPath.str() << endl; - //exit(1); - } - } + airports_by_id[a->getId()] = a; // try and read in an auxilary file @@ -1646,3 +275,60 @@ void FGAirportList::has_metar( const string &id ) { airports_by_id[id]->setMetar(true); } } + +// find basic airport location info from airport database +const FGAirport *fgFindAirportID( const string& id) { + const FGAirport* result = NULL; + if ( id.length() ) { + SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id ); + + result = globals->get_airports()->search( id ); + + if ( result == NULL ) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Failed to find " << id << " in apt.dat.gz" ); + return NULL; + } + } else { + return NULL; + } + SG_LOG( SG_GENERAL, SG_INFO, + "Position for " << id << " is (" + << result->getLongitude() << ", " + << result->getLatitude() << ")" ); + + return result; +} + + +// get airport elevation +double fgGetAirportElev( const string& id ) { + + // double lon, lat; + + SG_LOG( SG_GENERAL, SG_INFO, + "Finding elevation for airport: " << id ); + + const FGAirport *a=fgFindAirportID( id); + if (a) { + return a->getElevation(); + } else { + return -9999.0; + } +} + +// get airport position +Point3D fgGetAirportPos( const string& id ) { + // double lon, lat; + + SG_LOG( SG_ATC, SG_INFO, + "Finding position for airport: " << id ); + + const FGAirport *a = fgFindAirportID( id); + + if (a) { + return Point3D(a->getLongitude(), a->getLatitude(), a->getElevation()); + } else { + return Point3D(0.0, 0.0, -9999.0); + } +} diff --git a/src/Airports/simple.hxx b/src/Airports/simple.hxx index 774f69118..b6b255fef 100644 --- a/src/Airports/simple.hxx +++ b/src/Airports/simple.hxx @@ -37,406 +37,63 @@ # include #endif #include -#include + #include -#include +//#include #include STL_STRING #include #include #include +#include "runwayprefs.hxx" +#include "parking.hxx" +#include "groundnetwork.hxx" +#include "dynamics.hxx" + SG_USING_STD(string); SG_USING_STD(map); SG_USING_STD(set); SG_USING_STD(vector); -typedef vector stringVec; -typedef vector::iterator stringVecIterator; -typedef vector::const_iterator stringVecConstIterator; - -typedef vector timeVec; -typedef vector::const_iterator timeVecConstIterator; -/***************************************************************************/ -class ScheduleTime { -private: - timeVec start; - timeVec end; - stringVec scheduleNames; - double tailWind; - double crssWind; -public: - ScheduleTime() : tailWind(0), crssWind(0) {}; - ScheduleTime(const ScheduleTime &other); - ScheduleTime &operator= (const ScheduleTime &other); - string getName(time_t dayStart); - - void clear(); - void addStartTime(time_t time) { start.push_back(time); }; - void addEndTime (time_t time) { end. push_back(time); }; - void addScheduleName(const string& sched) { scheduleNames.push_back(sched); }; - void setTailWind(double wnd) { tailWind = wnd; }; - void setCrossWind(double wnd) { tailWind = wnd; }; - - double getTailWind() { return tailWind; }; - double getCrossWind() { return crssWind; }; -}; - -//typedef vector ScheduleTimes; -/*****************************************************************************/ - -class RunwayList -{ -private: - string type; - stringVec preferredRunways; -public: - RunwayList() {}; - RunwayList(const RunwayList &other); - RunwayList& operator= (const RunwayList &other); - - void set(const string&, const string&); - void clear(); - - string getType() { return type; }; - stringVec *getRwyList() { return &preferredRunways; }; - string getRwyList(int j) { return preferredRunways[j]; }; -}; - -typedef vector RunwayListVec; -typedef vector::iterator RunwayListVectorIterator; -typedef vector::const_iterator RunwayListVecConstIterator; - - -/*****************************************************************************/ - -class RunwayGroup -{ -private: - string name; - RunwayListVec rwyList; - int active; - //stringVec runwayNames; - int choice[2]; - int nrActive; -public: - RunwayGroup() {}; - RunwayGroup(const RunwayGroup &other); - RunwayGroup &operator= (const RunwayGroup &other); - - void setName(string nm) { name = nm; }; - void add(RunwayList list) { rwyList.push_back(list);}; - void setActive(const string& aptId, double windSpeed, double windHeading, double maxTail, double maxCross); - - int getNrActiveRunways() { return nrActive;}; - void getActive(int i, string& name, string& type); - - string getName() { return name; }; - void clear() { rwyList.clear(); }; - //void add(string, string); -}; - -typedef vector PreferenceList; -typedef vector::iterator PreferenceListIterator; -typedef vector::const_iterator PreferenceListConstIterator; -/******************************************************************************/ - -class FGRunwayPreference : public XMLVisitor { -private: - string value; - string scheduleName; - - ScheduleTime comTimes; // Commercial Traffic; - ScheduleTime genTimes; // General Aviation; - ScheduleTime milTimes; // Military Traffic; - ScheduleTime currTimes; // Needed for parsing; - - RunwayList rwyList; - RunwayGroup rwyGroup; - PreferenceList preferences; - - time_t processTime(const string&); - bool initialized; - -public: - FGRunwayPreference(); - FGRunwayPreference(const FGRunwayPreference &other); - - FGRunwayPreference & operator= (const FGRunwayPreference &other); - ScheduleTime *getSchedule(const char *trafficType); - RunwayGroup *getGroup(const string& groupName); - bool available() { return initialized; }; - - // Some overloaded virtual XMLVisitor members - virtual void startXML (); - virtual void endXML (); - virtual void startElement (const char * name, const XMLAttributes &atts); - virtual void endElement (const char * name); - virtual void data (const char * s, int len); - virtual void pi (const char * target, const char * data); - virtual void warning (const char * message, int line, int column); - virtual void error (const char * message, int line, int column); -}; - -double processPosition(const string& pos); - -class FGParking { -private: - double latitude; - double longitude; - double heading; - double radius; - int index; - string parkingName; - string type; - string airlineCodes; - - bool available; - - - -public: - FGParking() { available = true;}; - //FGParking(FGParking &other); - FGParking(double lat, - double lon, - double hdg, - double rad, - int idx, - const string& name, - const string& tpe, - const string& codes); - void setLatitude (const string& lat) { latitude = processPosition(lat); }; - void setLongitude(const string& lon) { longitude = processPosition(lon); }; - void setHeading (double hdg) { heading = hdg; }; - void setRadius (double rad) { radius = rad; }; - void setIndex (int idx) { index = idx; }; - void setName (const string& name) { parkingName = name; }; - void setType (const string& tpe) { type = tpe; }; - void setCodes (const string& codes){ airlineCodes= codes;}; - - bool isAvailable () { return available;}; - void setAvailable(bool val) { available = val; }; - - double getLatitude () { return latitude; }; - double getLongitude() { return longitude; }; - double getHeading () { return heading; }; - double getRadius () { return radius; }; - int getIndex () { return index; }; - string getType () { return type; }; - string getCodes () { return airlineCodes;}; - string getName () { return parkingName; }; - - bool operator< (const FGParking &other) const {return radius < other.radius; }; -}; - -typedef vector FGParkingVec; -typedef vector::iterator FGParkingVecIterator; -typedef vector::const_iterator FGParkingVecConstIterator; - -class FGTaxiSegment; // forward reference - -typedef vector FGTaxiSegmentVector; -typedef vector FGTaxiSegmentPointerVector; -typedef vector::iterator FGTaxiSegmentVectorIterator; -typedef vector::iterator FGTaxiSegmentPointerVectorIterator; - -/************************************************************************************** - * class FGTaxiNode - *************************************************************************************/ -class FGTaxiNode -{ -private: - double lat; - double lon; - int index; - FGTaxiSegmentPointerVector next; // a vector to all the segments leaving from this node - -public: - FGTaxiNode(); - FGTaxiNode(double, double, int); - - void setIndex(int idx) { index = idx;}; - void setLatitude (double val) { lat = val;}; - void setLongitude(double val) { lon = val;}; - void setLatitude (const string& val) { lat = processPosition(val); }; - void setLongitude(const string& val) { lon = processPosition(val); }; - void addSegment(FGTaxiSegment *segment) { next.push_back(segment); }; - - double getLatitude() { return lat;}; - double getLongitude(){ return lon;}; - - int getIndex() { return index; }; - FGTaxiNode *getAddress() { return this;}; - FGTaxiSegmentPointerVectorIterator getBeginRoute() { return next.begin(); }; - FGTaxiSegmentPointerVectorIterator getEndRoute() { return next.end(); }; -}; - -typedef vector FGTaxiNodeVector; -typedef vector::iterator FGTaxiNodeVectorIterator; - -/*************************************************************************************** - * class FGTaxiSegment - **************************************************************************************/ -class FGTaxiSegment -{ -private: - int startNode; - int endNode; - double length; - FGTaxiNode *start; - FGTaxiNode *end; - int index; - -public: - FGTaxiSegment(); - FGTaxiSegment(FGTaxiNode *, FGTaxiNode *, int); - - void setIndex (int val) { index = val; }; - void setStartNodeRef (int val) { startNode = val; }; - void setEndNodeRef (int val) { endNode = val; }; - - void setStart(FGTaxiNodeVector *nodes); - void setEnd (FGTaxiNodeVector *nodes); - void setTrackDistance(); - - FGTaxiNode * getEnd() { return end;}; - double getLength() { return length; }; - int getIndex() { return index; }; - - -}; - - -typedef vector intVec; -typedef vector::iterator intVecIterator; - -class FGTaxiRoute -{ -private: - intVec nodes; - double distance; - intVecIterator currNode; - -public: - FGTaxiRoute() { distance = 0; currNode = nodes.begin(); }; - FGTaxiRoute(intVec nds, double dist) { nodes = nds; distance = dist; currNode = nodes.begin();}; - bool operator< (const FGTaxiRoute &other) const {return distance < other.distance; }; - bool empty () { return nodes.begin() == nodes.end(); }; - bool next(int *val); - - void first() { currNode = nodes.begin(); }; -}; - -typedef vector TaxiRouteVector; -typedef vector::iterator TaxiRouteVectorIterator; - -/************************************************************************************** - * class FGGroundNetWork - *************************************************************************************/ -class FGGroundNetwork -{ -private: - bool hasNetwork; - FGTaxiNodeVector nodes; - FGTaxiSegmentVector segments; - //intVec route; - intVec traceStack; - TaxiRouteVector routes; - - bool foundRoute; - double totalDistance, maxDistance; - -public: - FGGroundNetwork(); - - void addNode (const FGTaxiNode& node); - void addNodes (FGParkingVec *parkings); - void addSegment(const FGTaxiSegment& seg); - - void init(); - bool exists() { return hasNetwork; }; - int findNearestNode(double lat, double lon); - FGTaxiNode *findNode(int idx); - FGTaxiRoute findShortestRoute(int start, int end); - void trace(FGTaxiNode *, int, int, double dist); - -}; /*************************************************************************************** * **************************************************************************************/ -class FGAirport : public XMLVisitor{ +class FGAirport { private: string _id; double _longitude; // degrees double _latitude; // degrees double _elevation; // ft - string _code; // depricated and can be removed string _name; bool _has_metar; - FGParkingVec parkings; - FGRunwayPreference rwyPrefs; - FGGroundNetwork groundNetwork; - - time_t lastUpdate; - string prevTrafficType; - stringVec landing; - stringVec takeoff; - - // Experimental keep a running average of wind dir and speed to prevent - // Erratic runway changes. - // Note: I should add these to the copy constructor and assigment operator to be - // constistent - double avWindHeading [10]; - double avWindSpeed [10]; - - string chooseRunwayFallback(); + FGAirportDynamics *dynamics; public: FGAirport(); - FGAirport(const FGAirport &other); - //operator= (FGAirport &other); + // FGAirport(const FGAirport &other); FGAirport(const string& id, double lon, double lat, double elev, const string& name, bool has_metar); + ~FGAirport(); - void init(); - void getActiveRunway(const string& trafficType, int action, string& runway); - bool getAvailableParking(double *lat, double *lon, double *heading, int *gate, double rad, const string& fltype, - const string& acType, const string& airline); - void getParking (int id, double *lat, double* lon, double *heading); - FGParking *getParking(int i); // { if (i < parkings.size()) return parkings[i]; else return 0;}; - void releaseParking(int id); - string getParkingName(int i); string getId() const { return _id;}; const string &getName() const { return _name;}; - //FGAirport *getAddress() { return this; }; - //const string &getName() const { return _name;}; - // Returns degrees double getLongitude() const { return _longitude;}; // Returns degrees double getLatitude() const { return _latitude; }; // Returns ft double getElevation() const { return _elevation;}; bool getMetar() const { return _has_metar;}; - FGGroundNetwork* getGroundNetwork() { return &groundNetwork; }; - void setId(const string& id) { _id = id;}; void setMetar(bool value) { _has_metar = value; }; - void setRwyUse(const FGRunwayPreference& ref); - - // Some overloaded virtual XMLVisitor members - virtual void startXML (); - virtual void endXML (); - virtual void startElement (const char * name, const XMLAttributes &atts); - virtual void endElement (const char * name); - virtual void data (const char * s, int len); - virtual void pi (const char * target, const char * data); - virtual void warning (const char * message, int line, int column); - virtual void error (const char * message, int line, int column); + FGAirportDynamics *getDynamics(); +private: + FGAirport operator=(FGAirport &other); + FGAirport(const FGAirport&); }; typedef map < string, FGAirport* > airport_map; @@ -454,7 +111,7 @@ private: airport_map airports_by_id; airport_list airports_array; - set < string > ai_dirs; + //set < string > ai_dirs; public: @@ -514,6 +171,14 @@ public: }; +// find basic airport location info from airport database +const FGAirport *fgFindAirportID( const string& id); + +// get airport elevation +double fgGetAirportElev( const string& id ); + +// get airport position +Point3D fgGetAirportPos( const string& id ); #endif // _FG_SIMPLE_HXX diff --git a/src/Autopilot/auto_gui.cxx b/src/Autopilot/auto_gui.cxx index e7ae0a45d..ce88be341 100644 --- a/src/Autopilot/auto_gui.cxx +++ b/src/Autopilot/auto_gui.cxx @@ -644,7 +644,6 @@ void TgtAptDialog_OK (puObject *) int NewWaypoint( const string& Tgt_Alt ) { string TgtAptId; - FGAirport a; FGFix f; double alt = 0.0; @@ -661,15 +660,15 @@ int NewWaypoint( const string& Tgt_Alt ) } FGRouteMgr *rm = (FGRouteMgr *)globals->get_subsystem("route-manager"); - - if ( fgFindAirportID( TgtAptId, &a ) ) { + const FGAirport *a = fgFindAirportID( TgtAptId); + if (a) { SG_LOG( SG_GENERAL, SG_INFO, "Adding waypoint (airport) = " << TgtAptId ); sprintf( NewTgtAirportId, "%s", TgtAptId.c_str() ); - SGWayPoint wp( a.getLongitude(), a.getLatitude(), alt, + SGWayPoint wp( a->getLongitude(), a->getLatitude(), alt, SGWayPoint::WGS84, TgtAptId ); rm->add_waypoint( wp ); diff --git a/src/Environment/environment_ctrl.cxx b/src/Environment/environment_ctrl.cxx index 87b79544a..310ba7d72 100644 --- a/src/Environment/environment_ctrl.cxx +++ b/src/Environment/environment_ctrl.cxx @@ -328,7 +328,8 @@ FGMetarEnvironmentCtrl::FGMetarEnvironmentCtrl () _error_count( 0 ), _stale_count( 0 ), _dt( 0.0 ), - _error_dt( 0.0 ) + _error_dt( 0.0 ), + last_apt(0) { #if defined(ENABLE_THREADS) thread = new MetarThread(this); @@ -412,7 +413,7 @@ FGMetarEnvironmentCtrl::init () if ( result.m != NULL ) { SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a->getId()); - last_apt = *a; + last_apt = a; _icao = a->getId(); search_elapsed = 0.0; fetch_elapsed = 0.0; @@ -470,13 +471,13 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec) latitude->getDoubleValue(), true ); if ( a ) { - if ( last_apt.getId() != a->getId() + if ( !last_apt || last_apt->getId() != a->getId() || fetch_elapsed > same_station_interval_sec ) { SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a->getId()); request_queue.push( a->getId() ); - last_apt = *a; + last_apt = a; _icao = a->getId(); search_elapsed = 0.0; fetch_elapsed = 0.0; diff --git a/src/Environment/environment_ctrl.hxx b/src/Environment/environment_ctrl.hxx index c38e033fc..879c902bb 100644 --- a/src/Environment/environment_ctrl.hxx +++ b/src/Environment/environment_ctrl.hxx @@ -173,7 +173,7 @@ private: float same_station_interval_sec; float search_elapsed; float fetch_elapsed; - FGAirport last_apt; + const FGAirport *last_apt; SGPropertyNode *proxy_host; SGPropertyNode *proxy_port; SGPropertyNode *proxy_auth; diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 6e292a0c2..834c2dc6c 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -35,7 +35,6 @@ #include #include // strcmp() - #if defined( unix ) || defined( __CYGWIN__ ) # include // for gethostname() #endif @@ -625,48 +624,7 @@ bool fgInitConfig ( int argc, char **argv ) { } -// find basic airport location info from airport database -bool fgFindAirportID( const string& id, FGAirport *a ) { - const FGAirport* result; - if ( id.length() ) { - SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id ); - result = globals->get_airports()->search( id ); - - if ( result == NULL ) { - SG_LOG( SG_GENERAL, SG_ALERT, - "Failed to find " << id << " in apt.dat.gz" ); - return false; - } - } else { - return false; - } - - *a = *result; - - SG_LOG( SG_GENERAL, SG_INFO, - "Position for " << id << " is (" - << a->getLongitude() << ", " - << a->getLatitude() << ")" ); - - return true; -} - - -// get airport elevation -static double fgGetAirportElev( const string& id ) { - FGAirport a; - // double lon, lat; - - SG_LOG( SG_GENERAL, SG_INFO, - "Finding elevation for airport: " << id ); - - if ( fgFindAirportID( id, &a ) ) { - return a.getElevation(); - } else { - return -9999.0; - } -} #if 0 @@ -676,7 +634,7 @@ static double fgGetAirportElev( const string& id ) { // Preset lon/lat given an airport id static bool fgSetPosFromAirportID( const string& id ) { - FGAirport a; + FGAirport *a; // double lon, lat; SG_LOG( SG_GENERAL, SG_INFO, @@ -684,17 +642,17 @@ static bool fgSetPosFromAirportID( const string& id ) { if ( fgFindAirportID( id, &a ) ) { // presets - fgSetDouble("/sim/presets/longitude-deg", a.longitude ); - fgSetDouble("/sim/presets/latitude-deg", a.latitude ); + fgSetDouble("/sim/presets/longitude-deg", a->longitude ); + fgSetDouble("/sim/presets/latitude-deg", a->latitude ); // other code depends on the actual postition being set so set // that as well - fgSetDouble("/position/longitude-deg", a.longitude ); - fgSetDouble("/position/latitude-deg", a.latitude ); + fgSetDouble("/position/longitude-deg", a->longitude ); + fgSetDouble("/position/latitude-deg", a->latitude ); SG_LOG( SG_GENERAL, SG_INFO, - "Position for " << id << " is (" << a.longitude - << ", " << a.latitude << ")" ); + "Position for " << id << " is (" << a->longitude + << ", " << a->latitude << ")" ); return true; } else { @@ -706,7 +664,7 @@ static bool fgSetPosFromAirportID( const string& id ) { // Set current tower position lon/lat given an airport id static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) { - FGAirport a; + // tower height hard coded for now... float towerheight=50.0f; @@ -714,10 +672,11 @@ static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) { float fudge_lon = fabs(sin(hdg)) * .003f; float fudge_lat = .003f - fudge_lon; - if ( fgFindAirportID( id, &a ) ) { - fgSetDouble("/sim/tower/longitude-deg", a.getLongitude() + fudge_lon); - fgSetDouble("/sim/tower/latitude-deg", a.getLatitude() + fudge_lat); - fgSetDouble("/sim/tower/altitude-ft", a.getElevation() + towerheight); + const FGAirport *a = fgFindAirportID( id); + if ( a) { + fgSetDouble("/sim/tower/longitude-deg", a->getLongitude() + fudge_lon); + fgSetDouble("/sim/tower/latitude-deg", a->getLatitude() + fudge_lat); + fgSetDouble("/sim/tower/altitude-ft", a->getElevation() + towerheight); return true; } else { return false; @@ -1578,7 +1537,6 @@ bool fgInitSubsystems() { // = fgGetNode("/sim/presets/latitude-deg"); // static const SGPropertyNode *altitude // = fgGetNode("/sim/presets/altitude-ft"); - SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems"); SG_LOG( SG_GENERAL, SG_INFO, "========== =========="); @@ -1879,7 +1837,7 @@ bool fgInitSubsystems() { // Save the initial state for future // reference. globals->saveInitialState(); - + return true; }