1
0
Fork 0

A set of additions related to allow the use of SID and STAR procedures.

The current code still has some rough edges, in particular memory still
needs to be deallocated where possible, and the actual use of the code
needs more testing. This code has been running without noticable problems,
so I think it's ready for some wider exposure. Detailed changes include:
- Finetuning of the SID/STAR data concept.
- Preloading of all SIDs, from one xml file.
- ATC determines which SID should be used and echoes this over the com1 or
  com2 radio.
This commit is contained in:
durk 2009-03-08 17:14:05 +00:00 committed by Tim Moore
parent 19331f2813
commit 9cc92035b1
12 changed files with 296 additions and 80 deletions

View file

@ -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;

View file

@ -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

View file

@ -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);
}
/*******************************************************************

View file

@ -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:

View file

@ -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

View file

@ -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);
}

View file

@ -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; };

116
src/Airports/sidstar.cxx Normal file
View file

@ -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;
}
}

67
src/Airports/sidstar.hxx Normal file
View file

@ -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

View file

@ -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;
}

View file

@ -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;
}
}
}
}

View file

@ -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);
};