diff --git a/src/AIModel/AIFlightPlan.cxx b/src/AIModel/AIFlightPlan.cxx index c901cbf53..41c7966be 100644 --- a/src/AIModel/AIFlightPlan.cxx +++ b/src/AIModel/AIFlightPlan.cxx @@ -46,10 +46,15 @@ using std::cerr; +FGAIFlightPlan::FGAIFlightPlan() +{ + sid = 0; +} FGAIFlightPlan::FGAIFlightPlan(const string& filename) { int i; + sid = 0; start_time = 0; leg = 10; gateId = 0; @@ -118,6 +123,7 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac, const string& acType, const string& airline) { + sid = 0; repeat = false; leg = 10; gateId=0; diff --git a/src/AIModel/AIFlightPlan.hxx b/src/AIModel/AIFlightPlan.hxx index c3a0cff0f..65e4c7907 100644 --- a/src/AIModel/AIFlightPlan.hxx +++ b/src/AIModel/AIFlightPlan.hxx @@ -58,7 +58,7 @@ public: string time; } waypoint; - + FGAIFlightPlan(); FGAIFlightPlan(const string& filename); FGAIFlightPlan(FGAIAircraft *, const std::string& p, @@ -113,8 +113,17 @@ public: void setRunway(string rwy) { activeRunway = rwy; }; string getRunwayClassFromTrafficType(string fltType); + void addWaypoint(waypoint* wpt) { waypoints.push_back(wpt); }; + + void setName(string n) { name = n; }; + string getName() { return name; }; + + void setSID(FGAIFlightPlan* fp) { sid = fp;}; + FGAIFlightPlan* getSID() { return sid; }; + private: FGRunway* rwy; + FGAIFlightPlan *sid; typedef vector <waypoint*> wpt_vector_type; typedef wpt_vector_type::const_iterator wpt_vector_iterator; @@ -131,6 +140,7 @@ private: string activeRunway; FGAirRoute airRoute; FGTaxiRoute *taxiRoute; + string name; void createPushBack(FGAIAircraft *, bool, FGAirport*, double, double, double, const string&, const string&, const string&); void createPushBackFallBack(FGAIAircraft *, bool, FGAirport*, double, double, double, const string&, const string&, const string&); @@ -151,13 +161,15 @@ private: waypoint* createOnGround(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed); waypoint* createInAir(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed); waypoint* cloneWithPos(FGAIAircraft *, waypoint* aWpt, const std::string& aName, const SGGeod& aPos); + waypoint* clone(waypoint* aWpt); //void createCruiseFallback(bool, FGAirport*, FGAirport*, double, double, double, double); void evaluateRoutePart(double deplat, double deplon, double arrlat, double arrlon); + public: + wpt_vector_iterator getFirstWayPoint() { return waypoints.begin(); }; + wpt_vector_iterator getLastWayPoint() { return waypoints.end(); }; - bool loadSID(const string& filename); - string expandICAODirs(const string in); }; #endif // _FG_AIFLIGHTPLAN_HXX diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx index 8035ae2ce..77032b3fa 100644 --- a/src/AIModel/AIFlightPlanCreate.cxx +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -148,6 +148,27 @@ FGAIFlightPlan::cloneWithPos(FGAIAircraft *ac, waypoint* aWpt, const std::string return wpt; } +FGAIFlightPlan::waypoint* +FGAIFlightPlan::clone(waypoint* aWpt) +{ + waypoint* wpt = new waypoint; + wpt->name = aWpt->name; + wpt->longitude = aWpt->longitude; + wpt->latitude = aWpt->latitude; + + wpt->altitude = aWpt->altitude; + wpt->speed = aWpt->speed; + wpt->crossat = aWpt->crossat; + wpt->gear_down = aWpt->gear_down; + wpt->flaps_down= aWpt->flaps_down; + wpt->finished = aWpt->finished; + wpt->on_ground = aWpt->on_ground; + wpt->routeIndex = 0; + + return wpt; +} + + void FGAIFlightPlan::createDefaultTakeoffTaxi(FGAIAircraft *ac, FGAirport* aAirport, FGRunway* aRunway) { SGGeod runwayTakeoff = aRunway->pointOnCenterline(5.0); @@ -415,25 +436,14 @@ void FGAIFlightPlan::createClimb(FGAIAircraft *ac, bool firstFlight, FGAirport * apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading); rwy = apt->getRunwayByIdent(activeRunway); } - if (fgGetBool("/sim/traffic-manager/use-custom-scenery-data") == true) { - string_list sc = globals->get_fg_scenery(); - char buffer[64]; - // NOTE: Currently for testing only. A slightly more elaborate naming convention - // needs to be dropped here. - snprintf(buffer, 64, "%s.SID-%s-01.xml", apt->getId().c_str(), activeRunway.c_str() ); - string airportDir = expandICAODirs(apt->getId()); - for (string_list_iterator i = sc.begin(); i != sc.end(); i++) { - SGPath aptpath( *i ); - aptpath.append( "Airports" ); - aptpath.append ( airportDir ); - aptpath.append( string(buffer) ); - if (aptpath.exists()) { - planLoaded = loadSID(aptpath.str()); - //cerr << "Reading " << aptpath.str() << endl; - } - } - } - if (!planLoaded) { + if (sid) { + for (wpt_vector_iterator i = sid->getFirstWayPoint(); + i != sid->getLastWayPoint(); + i++) { + waypoints.push_back(clone(*(i))); + //cerr << " Cloning waypoint " << endl; + } + } else { SGGeod climb1 = rwy->pointOnCenterline(10*SG_NM_TO_METER); wpt = createInAir(ac, "10000ft climb", climb1, speed, 10000); wpt->gear_down = true; @@ -447,59 +457,6 @@ void FGAIFlightPlan::createClimb(FGAIAircraft *ac, bool firstFlight, FGAirport * } } -bool FGAIFlightPlan::loadSID(const string& filename) -{ - SGPropertyNode root; - try { - readProperties(filename, &root); - } catch (const sg_exception &e) { - SG_LOG(SG_GENERAL, SG_ALERT, - "Error reading AI flight plan: " << filename); - // cout << path.str() << endl; - return false; - } - - SGPropertyNode * node = root.getNode("flightplan"); - for (int i = 0; i < node->nChildren(); i++) { - //cout << "Reading waypoint " << i << endl; - waypoint* wpt = new waypoint; - SGPropertyNode * wpt_node = node->getChild(i); - wpt->name = wpt_node->getStringValue("name", "END"); - wpt->latitude = wpt_node->getDoubleValue("lat", 0); - wpt->longitude = wpt_node->getDoubleValue("lon", 0); - wpt->altitude = wpt_node->getDoubleValue("alt", 0); - wpt->speed = wpt_node->getDoubleValue("ktas", 0); - wpt->crossat = wpt_node->getDoubleValue("crossat", -10000); - wpt->gear_down = wpt_node->getBoolValue("gear-down", false); - wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false); - wpt->on_ground = wpt_node->getBoolValue("on-ground", false); - wpt->time_sec = wpt_node->getDoubleValue("time-sec", 0); - wpt->time = wpt_node->getStringValue("time", ""); - - if (wpt->name == "END") wpt->finished = true; - else wpt->finished = false; - - waypoints.push_back( wpt ); - } - - //wpt_iterator = waypoints.begin(); - //cout << waypoints.size() << " waypoints read." << endl; - return true; -} - -// NOTE: This is just copied from Airports/readXML. -string FGAIFlightPlan::expandICAODirs(const string in){ - //cerr << "Expanding " << in << endl; - if (in.size() == 4) { - char buffer[11]; - snprintf(buffer, 11, "%c/%c/%c", in[0], in[1], in[2]); - //cerr << "result: " << buffer << endl; - return string(buffer); - } else { - return in; - } - //exit(1); -} /******************************************************************* diff --git a/src/ATC/trafficcontrol.cxx b/src/ATC/trafficcontrol.cxx index 3d3d8a3e0..c8657ba1d 100644 --- a/src/ATC/trafficcontrol.cxx +++ b/src/ATC/trafficcontrol.cxx @@ -384,6 +384,8 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m string activeRunway; string fltType; string rwyClass; + string SID; + FGAIFlightPlan *fp; switch (msgId) { case MSG_ANNOUNCE_ENGINE_START: text = sender + ". Ready to Start up"; @@ -406,19 +408,32 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading); rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway); + fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getSID(activeRunway, heading); + rec->getAircraft()->GetFlightPlan()->setSID(fp); + if (fp) { + SID = fp->getName() + " departure"; + } else { + SID = "fly runway heading "; + } //snprintf(buffer, 7, "%3.2f", heading); text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " + activeRunway - + ", AAA departure, squawk BBBB. " + + + ", " + SID + ", squawk BBBB. " + "For push-back and taxi clearance call " + taxiFreqStr + ". " + sender + " control."; break; case MSG_DENY_ENGINE_START: text = receiver + ". Standby"; break; case MSG_ACKNOWLEDGE_ENGINE_START: + fp = rec->getAircraft()->GetFlightPlan()->getSID(); + if (fp) { + SID = rec->getAircraft()->GetFlightPlan()->getSID()->getName() + " departure"; + } else { + SID = "fly runway heading "; + } taxiFreqStr = formatATCFrequency3_2(taxiFreq); activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway(); text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " + - activeRunway + ", AAA departure, squawk BBBB. " + + activeRunway + ", " + SID + ", squawk BBBB. " + "For push-back and taxi clearance call " + taxiFreqStr + ". " + sender; break; default: diff --git a/src/Airports/Makefile.am b/src/Airports/Makefile.am index 71a49a139..e78463b4b 100644 --- a/src/Airports/Makefile.am +++ b/src/Airports/Makefile.am @@ -12,6 +12,7 @@ libAirports_a_SOURCES = \ groundnetwork.cxx groundnetwork.hxx \ dynamics.cxx dynamics.hxx \ dynamicloader.cxx dynamicloader.hxx \ + sidstar.cxx sidstar.hxx \ runwayprefloader.cxx runwayprefloader.hxx \ xmlloader.cxx xmlloader.hxx \ runwaybase.cxx runwaybase.hxx diff --git a/src/Airports/dynamics.cxx b/src/Airports/dynamics.cxx index 34a6dce8a..fe8079075 100644 --- a/src/Airports/dynamics.cxx +++ b/src/Airports/dynamics.cxx @@ -52,7 +52,7 @@ using std::random_shuffle; #include "dynamics.hxx" FGAirportDynamics::FGAirportDynamics(FGAirport* ap) : - _ap(ap), rwyPrefs(ap) { + _ap(ap), rwyPrefs(ap), SIDs(ap) { lastUpdate = 0; // For testing only. This needs to be refined when we move ATIS functionality over. @@ -61,7 +61,8 @@ FGAirportDynamics::FGAirportDynamics(FGAirport* ap) : // Note that the ground network should also be copied FGAirportDynamics::FGAirportDynamics(const FGAirportDynamics& other) : - rwyPrefs(other.rwyPrefs) + rwyPrefs(other.rwyPrefs), + SIDs(other.SIDs) { for (FGParkingVecConstIterator ip= other.parkings.begin(); ip != other.parkings.end(); ip++) parkings.push_back(*(ip)); @@ -555,4 +556,9 @@ int FGAirportDynamics::getGroundFrequency(int leg) { groundFreq = freqGround[leg-2]; } return groundFreq; +} + +FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway, double heading) +{ + return SIDs.getBest(activeRunway, heading); } \ No newline at end of file diff --git a/src/Airports/dynamics.hxx b/src/Airports/dynamics.hxx index b2f1ba001..56bef8225 100644 --- a/src/Airports/dynamics.hxx +++ b/src/Airports/dynamics.hxx @@ -33,6 +33,7 @@ #include "parking.hxx" #include "groundnetwork.hxx" #include "runwayprefs.hxx" +#include "sidstar.hxx" //typedef vector<float> DoubleVec; //typedef vector<float>::iterator DoubleVecIterator; @@ -47,6 +48,7 @@ private: FGParkingVec parkings; FGRunwayPreference rwyPrefs; + FGSidStar SIDs; FGStartupController startupController; FGGroundNetwork groundNetwork; FGTowerController towerController; @@ -104,6 +106,10 @@ public: //const string &getName() const { return _name;}; // Returns degrees + // Departure / Arrival procedures + FGSidStar * getSIDs() { return &SIDs; }; + FGAIFlightPlan * getSID(string activeRunway, double heading); + // ATC related functions. FGStartupController *getStartupController() { return &startupController; }; diff --git a/src/Airports/sidstar.cxx b/src/Airports/sidstar.cxx new file mode 100644 index 000000000..cbeac9aed --- /dev/null +++ b/src/Airports/sidstar.cxx @@ -0,0 +1,116 @@ +// sidstar.cxx - Code to manage departure / arrival procedures +// Written by Durk Talsma, started March 2009. +// +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id$ + +#include <iostream> +#include <stdlib.h> + +#include <simgear/props/props.hxx> +#include <simgear/props/props_io.hxx> + + + +#include <Airports/simple.hxx> + + +#include "sidstar.hxx" + +using std::cerr; +using std::endl; + +FGSidStar::FGSidStar(FGAirport *ap) { + id = ap->getId(); + initialized = false; +} + + +FGSidStar::FGSidStar(const FGSidStar &other) { + cerr << "TODO" << endl; + exit(1); +} + +void FGSidStar::load(SGPath filename) { + SGPropertyNode root; + string runway; + string name; + try { + readProperties(filename.str(), &root); + } catch (const sg_exception &e) { + SG_LOG(SG_GENERAL, SG_ALERT, + "Error reading AI flight plan: " << filename.str()); + // cout << path.str() << endl; + return; + } + + SGPropertyNode * node = root.getNode("SIDS"); + FGAIFlightPlan *fp; + for (int i = 0; i < node->nChildren(); i++) { + fp = new FGAIFlightPlan; + SGPropertyNode * fpl_node = node->getChild(i); + name = fpl_node->getStringValue("name", "END"); + runway = fpl_node->getStringValue("runway", "27"); + //cerr << "Runway = " << runway << endl; + fp->setName(name); + SGPropertyNode * wpts_node = fpl_node->getNode("wpts"); + for (int j = 0; j < wpts_node->nChildren(); j++) { + FGAIFlightPlan::waypoint* wpt = new FGAIFlightPlan::waypoint; + SGPropertyNode * wpt_node = wpts_node->getChild(j); + //cerr << "Reading waypoint " << j << wpt_node->getStringValue("name", "END") << endl; + wpt->name = wpt_node->getStringValue("name", "END"); + wpt->latitude = wpt_node->getDoubleValue("lat", 0); + wpt->longitude = wpt_node->getDoubleValue("lon", 0); + wpt->altitude = wpt_node->getDoubleValue("alt", 0); + wpt->speed = wpt_node->getDoubleValue("ktas", 0); + wpt->crossat = wpt_node->getDoubleValue("crossat", -10000); + wpt->gear_down = wpt_node->getBoolValue("gear-down", false); + wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false); + wpt->on_ground = wpt_node->getBoolValue("on-ground", false); + wpt->time_sec = wpt_node->getDoubleValue("time-sec", 0); + wpt->time = wpt_node->getStringValue("time", ""); + + if (wpt->name == "END") wpt->finished = true; + else wpt->finished = false; + + // + fp->addWaypoint( wpt ); + } + data[runway].push_back(fp); + //cerr << "Runway = " << runway << endl; + } + + + //wpt_iterator = waypoints.begin(); + //cout << waypoints.size() << " waypoints read." << endl; +} + + +FGAIFlightPlan *FGSidStar::getBest(string activeRunway, double heading) +{ + //cerr << "Getting best procedure for " << activeRunway << endl; + for (FlightPlanVecIterator i = data[activeRunway].begin(); i != data[activeRunway].end(); i++) { + //cerr << (*i)->getName() << endl; + } + int size = data[activeRunway].size(); + //cerr << "size is " << size << endl; + if (size) { + return data[activeRunway][(rand() % size)]; + } else { + return 0; + } +} \ No newline at end of file diff --git a/src/Airports/sidstar.hxx b/src/Airports/sidstar.hxx new file mode 100644 index 000000000..ef388e49b --- /dev/null +++ b/src/Airports/sidstar.hxx @@ -0,0 +1,67 @@ +// sidstar.hxx - a class to store and maintain data for SID and STAR +// procedures. +// Written by Durk Talsma, started March 2009. +// +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id$ + + +#ifndef _SIDSTAR_HXX_ +#define _SIDSTAR_HXX_ + +#include <string> + +#include <simgear/misc/sg_path.hxx> + +#include <simgear/xml/easyxml.hxx> + +#include <ATC/trafficcontrol.hxx> +#include <AIModel/AIFlightPlan.hxx> +#include "parking.hxx" +#include "groundnetwork.hxx" +#include "runwayprefs.hxx" + + +using std::string; + +class FGAirport; + +typedef vector<FGAIFlightPlan*> FlightPlanVec; +typedef vector<FGAIFlightPlan*>::iterator FlightPlanVecIterator; + +typedef std::map < std::string, FlightPlanVec > FlightPlanVecMap; + + +class FGSidStar +{ + private: + string id; + bool initialized; + FlightPlanVecMap data; + + public: + FGSidStar(FGAirport *ap); + FGSidStar(const FGSidStar &other); + + string getId() { return id; }; + void load(SGPath path); + FGAIFlightPlan *getBest(string activeRunway, double heading); +}; + + + +#endif \ No newline at end of file diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx index 02d7025b8..7da4fa1a8 100644 --- a/src/Airports/simple.cxx +++ b/src/Airports/simple.cxx @@ -92,6 +92,9 @@ FGAirportDynamics * FGAirport::getDynamics() FGRunwayPreference rwyPrefs(this); XMLLoader::load(&rwyPrefs); _dynamics->setRwyUse(rwyPrefs); + + //FGSidStar SIDs(this); + XMLLoader::load(_dynamics->getSIDs()); } return _dynamics; } diff --git a/src/Airports/xmlloader.cxx b/src/Airports/xmlloader.cxx index e808eaf5c..7005ca52a 100644 --- a/src/Airports/xmlloader.cxx +++ b/src/Airports/xmlloader.cxx @@ -118,3 +118,28 @@ void XMLLoader::load(FGRunwayPreference* p) { } } +void XMLLoader::load(FGSidStar* p) { + //FGRunwayPreferenceXMLLoader visitor(p); + if (fgGetBool("/sim/traffic-manager/use-custom-scenery-data") == true) { + string_list sc = globals->get_fg_scenery(); + char buffer[32]; + snprintf(buffer, 32, "%s.SID.xml", p->getId().c_str() ); + string airportDir = expandICAODirs(p->getId()); + for (string_list_iterator i = sc.begin(); i != sc.end(); i++) { + SGPath sidpath( *i ); + sidpath.append( "Airports" ); + sidpath.append ( airportDir ); + sidpath.append( string(buffer) ); + if (sidpath.exists()) { + try { + //readXML(rwypath.str(), visitor); + //cerr << "Reading SID procedure : " << sidpath.str() << endl; + p->load(sidpath); + } + catch (const sg_exception &e) { + } + return; + } + } + } +} diff --git a/src/Airports/xmlloader.hxx b/src/Airports/xmlloader.hxx index 436e86994..eb066495f 100644 --- a/src/Airports/xmlloader.hxx +++ b/src/Airports/xmlloader.hxx @@ -20,6 +20,7 @@ class FGAirportDynamics; class FGRunwayPreference; +class FGSidStar; @@ -29,7 +30,8 @@ public: ~XMLLoader(); static string expandICAODirs(const string in); static void load(FGRunwayPreference* p); - static void load(FGAirportDynamics* d); + static void load(FGAirportDynamics* d); + static void load(FGSidStar* s); };