1
0
Fork 0

Initial attempt to establish a better integration between AI and ATC code.

Various other patches that have been lingering around for a while:
 * Moved trafficcontrol.[ch]xx from the Airports directory to ATC, where
   it really belongs.
 * AI aircraft will request startup clearance, and ground control will
   approve.
 * Starting AI Aircraft will be pushed back to a predefined holding point
   on the ground network, and wait a while before taxiing out to the runway
This commit is contained in:
durk 2008-07-13 12:51:06 +00:00
parent a0bb5b3c67
commit 17c42deae1
18 changed files with 1244 additions and 290 deletions

View file

@ -150,7 +150,8 @@ void FGAIAircraft::setPerformance(const std::string& acclass) {
return; return;
} }
catch (FP_Inactive) { catch (FP_Inactive) {
return; //return;
groundTargetSpeed = 0;
} }
handleATCRequests(); // ATC also has a word to say handleATCRequests(); // ATC also has a word to say
@ -365,7 +366,7 @@ void FGAIAircraft::getGroundElev(double dt) {
dt_elev_count += dt; dt_elev_count += dt;
// Update minimally every three secs, but add some randomness // Update minimally every three secs, but add some randomness
// to prevent all IA objects doing this in synchrony // to prevent all AI objects doing this in synchrony
if (dt_elev_count < (3.0) + (rand() % 10)) if (dt_elev_count < (3.0) + (rand() % 10))
return; return;
@ -413,10 +414,14 @@ void FGAIAircraft::announcePositionToController() {
if (trafficRef) { if (trafficRef) {
int leg = fp->getLeg(); int leg = fp->getLeg();
// Note that leg was been incremented after creating the current leg, so we should use // Note that leg has been incremented after creating the current leg, so we should use
// leg numbers here that are one higher than the number that is used to create the leg // leg numbers here that are one higher than the number that is used to create the leg
// //
switch (leg) { switch (leg) {
case 2: // Startup and Push back
if (trafficRef->getDepartureAirport()->getDynamics())
controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController();
break;
case 3: // Taxiing to runway case 3: // Taxiing to runway
if (trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork()->exists()) if (trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork()->exists())
controller = trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork(); controller = trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork();
@ -425,12 +430,14 @@ void FGAIAircraft::announcePositionToController() {
if (trafficRef->getDepartureAirport()->getDynamics()) { if (trafficRef->getDepartureAirport()->getDynamics()) {
controller = trafficRef->getDepartureAirport()->getDynamics()->getTowerController(); controller = trafficRef->getDepartureAirport()->getDynamics()->getTowerController();
//if (trafficRef->getDepartureAirport()->getId() == "EHAM") { //if (trafficRef->getDepartureAirport()->getId() == "EHAM") {
//cerr << trafficRef->getCallSign() << " at runway " << fp->getRunway() << "Ready for departure " //string trns = trafficRef->getCallSign() + " at runway " + fp->getRunway() +
// << trafficRef->getFlightType() << " to " << trafficRef->getArrivalAirport()->getId() << endl; // ". Ready for departure. " + trafficRef->getFlightType() + " to " +
// trafficRef->getArrivalAirport()->getId();
//fgSetString("/sim/messages/atc", trns.c_str());
// if (controller == 0) { // if (controller == 0) {
//cerr << "Error in assigning controller at " << trafficRef->getDepartureAirport()->getId() << endl; //cerr << "Error in assigning controller at " << trafficRef->getDepartureAirport()->getId() << endl;
//} //}
//}
} else { } else {
cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl; cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
} }
@ -446,29 +453,17 @@ void FGAIAircraft::announcePositionToController() {
if ((controller != prevController) && (prevController != 0)) { if ((controller != prevController) && (prevController != 0)) {
prevController->signOff(getID()); prevController->signOff(getID());
string callsign = trafficRef->getCallSign();
if ( trafficRef->getHeavy())
callsign += "Heavy";
switch (leg) {
case 3:
//cerr << callsign << " ready to taxi to runway " << fp->getRunway() << endl;
break;
case 4:
//cerr << callsign << " at runway " << fp->getRunway() << "Ready for take-off. "
// << trafficRef->getFlightRules() << " to " << trafficRef->getArrivalAirport()->getId()
// << "(" << trafficRef->getArrivalAirport()->getName() << ")."<< endl;
break;
}
} }
prevController = controller; prevController = controller;
if (controller) { if (controller) {
controller->announcePosition(getID(), fp, fp->getCurrentWaypoint()->routeIndex, controller->announcePosition(getID(), fp, fp->getCurrentWaypoint()->routeIndex,
_getLatitude(), _getLongitude(), hdg, speed, altitude_ft, _getLatitude(), _getLongitude(), hdg, speed, altitude_ft,
trafficRef->getRadius(), leg, trafficRef->getCallSign()); trafficRef->getRadius(), leg, this);
} }
} }
} }
// Process ATC instructions and report back
void FGAIAircraft::processATC(FGATCInstruction instruction) { void FGAIAircraft::processATC(FGATCInstruction instruction) {
if (instruction.getCheckForCircularWait()) { if (instruction.getCheckForCircularWait()) {
@ -494,7 +489,7 @@ void FGAIAircraft::processATC(FGATCInstruction instruction) {
} else { } else {
if (holdPos) { if (holdPos) {
//if (trafficRef) //if (trafficRef)
// cerr << trafficRef->getCallSign() << " Resuming Taxi " << endl; // cerr << trafficRef->getCallSign() << " Resuming Taxi." << endl;
holdPos = false; holdPos = false;
} }
// Change speed Instruction. This can only be excecuted when there is no // Change speed Instruction. This can only be excecuted when there is no
@ -760,6 +755,7 @@ void FGAIAircraft::updatePrimaryTargetValues() {
throw AI_OutOfSight(); throw AI_OutOfSight();
} }
} }
timeElapsed = now - fp->getStartTime();
if (! fp->isActive(now)) { if (! fp->isActive(now)) {
throw FP_Inactive(); throw FP_Inactive();
} }
@ -845,7 +841,7 @@ void FGAIAircraft::updateHeading() {
} else { } else {
bank_sense = 1.0; bank_sense = 1.0;
} }
if (trafficRef) //if (trafficRef)
//cerr << trafficRef->getCallSign() << " Heading " //cerr << trafficRef->getCallSign() << " Heading "
// << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl; // << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl;
//if (headingDiff > 60) { //if (headingDiff > 60) {
@ -875,7 +871,8 @@ void FGAIAircraft::updateHeading() {
else else
headingChangeRate += dt * sign(roll); headingChangeRate += dt * sign(roll);
} }
hdg += headingChangeRate * dt;
hdg += headingChangeRate * dt * (fabs(speed) / 15);
headingError = headingDiff; headingError = headingDiff;
} else { } else {
if (fabs(speed) > 1.0) { if (fabs(speed) > 1.0) {
@ -979,6 +976,20 @@ void FGAIAircraft::updatePitchAngleTarget() {
} }
} }
string FGAIAircraft::atGate() {
string tmp("");
if (fp->getLeg() < 3) {
if (trafficRef) {
if (fp->getGate() > 0) {
FGParking *park =
trafficRef->getDepartureAirport()->getDynamics()->getParking(fp->getGate());
tmp = park->getName();
}
}
}
return tmp;
}
void FGAIAircraft::handleATCRequests() { void FGAIAircraft::handleATCRequests() {
//TODO implement NullController for having no ATC to save the conditionals //TODO implement NullController for having no ATC to save the conditionals
if (controller) { if (controller) {

View file

@ -70,6 +70,7 @@ public:
void announcePositionToController(); //TODO have to be public? void announcePositionToController(); //TODO have to be public?
void processATC(FGATCInstruction instruction); void processATC(FGATCInstruction instruction);
FGAISchedule * getTrafficRef() { return trafficRef; };
virtual const char* getTypeString(void) const { return "aircraft"; } virtual const char* getTypeString(void) const { return "aircraft"; }
@ -82,6 +83,7 @@ public:
inline double getVerticalSpeed() const { return vs; }; inline double getVerticalSpeed() const { return vs; };
inline double altitudeAGL() const { return props->getFloatValue("position/altitude-agl-ft");}; inline double altitudeAGL() const { return props->getFloatValue("position/altitude-agl-ft");};
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");}; inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
string atGate();
protected: protected:
void Run(double dt); void Run(double dt);
@ -138,6 +140,7 @@ private:
bool _getGearDown() const; bool _getGearDown() const;
bool reachedWaypoint; bool reachedWaypoint;
time_t timeElapsed;
PerformanceData* _performance; // the performance data for this aircraft PerformanceData* _performance; // the performance data for this aircraft
}; };

View file

@ -41,6 +41,7 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep,
radius, fltType, aircraftType, airline); radius, fltType, aircraftType, airline);
} else { } else {
if (firstFlight) { if (firstFlight) {
if (!(dep->getDynamics()->getAvailableParking(&lat, &lon, if (!(dep->getDynamics()->getAvailableParking(&lat, &lon,
&heading, &gateId, &heading, &gateId,
radius, fltType, radius, fltType,
@ -70,6 +71,12 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep,
wpt->routeIndex = -1; wpt->routeIndex = -1;
waypoints.push_back(wpt); waypoints.push_back(wpt);
} }
//cerr << "Success : GateId = " << gateId << endl;
SG_LOG(SG_INPUT, SG_WARN, "Warning: Succesfully found a parking for a " <<
aircraftType <<
" of flight type " << fltType <<
" of airline " << airline <<
" at airport " << dep->getId());
} else { } else {
//cerr << "Push Back follow-up Flight" << endl; //cerr << "Push Back follow-up Flight" << endl;
dep->getDynamics()->getParking(gateId, &lat, &lon, &heading); dep->getDynamics()->getParking(gateId, &lat, &lon, &heading);
@ -89,61 +96,21 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep,
FGParking *parking = dep->getDynamics()->getParking(gateId); FGParking *parking = dep->getDynamics()->getParking(gateId);
int pushBackNode = parking->getPushBackPoint(); int pushBackNode = parking->getPushBackPoint();
// initialize the pushback route. Note that parts
// of this procedure should probably be done inside
// taxidraw. This code is likely to change once this
// this is fully implemented in taxidraw. Until that time,
// however, the full initialization procedure looks like this:
// 1) Build a list of all the nodes that are classified as
// pushBack hold points
// 2) For each hold point, use the dykstra algorithm to find a route
// between the gate and the pushBack hold nodes, however use only
// segments that are classified as "pushback" routes.
// 3) return the TaxiRoute class that is non empty.
// 4) store refer this route in the parking object, for future use
if (pushBackNode < 0) { pushBackRoute = parking->getPushBackRoute();
//cerr << "Initializing PushBackRoute " << endl; if ((pushBackNode > 0) && (pushBackRoute == 0)) {
intVec pushBackNodes;
int nAINodes = dep->getDynamics()->getGroundNetwork()->getNrOfNodes();
int hits = 0;
parking->setPushBackPoint(0); // default in case no network was found.
// Collect all the nodes that are classified as having pushBack hold status
for (int i = 0; i < nAINodes; i++) {
if (dep->getDynamics()->getGroundNetwork()->findNode(i)->getHoldPointType() == 3) {
pushBackNodes.push_back(i);
}
}
// For each node found in step 1, check if it can be reached
FGTaxiRoute route;
for (intVecIterator nodes = pushBackNodes.begin();
nodes != pushBackNodes.end();
nodes++) {
route = dep->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, *nodes, false);
if (!(route.empty())) {
//cerr << "Found Pushback route of size " << route.size() << endl;
hits++;
parking->setPushBackRoute(new FGTaxiRoute(route));
parking->setPushBackPoint(*nodes);
pushBackNode = *nodes;
}
}
if (hits == 0) {
SG_LOG(SG_GENERAL, SG_INFO, "No pushback route found for gate " << gateId << " at " << dep->getId());
}
if (hits > 1) {
SG_LOG(SG_GENERAL, SG_WARN, hits << " pushback routes found for gate " << gateId << " at " << dep->getId());
}
}
if (pushBackNode > 0) {
int node, rte; int node, rte;
//cerr << "Found valid pusback node " << pushBackNode << "for gate " << gateId << endl; FGTaxiRoute route;
//cerr << "Creating push-back for " << gateId << " (" << parking->getName() << ") using push-back point " << pushBackNode << endl;
route = dep->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, pushBackNode, false);
parking->setPushBackRoute(new FGTaxiRoute(route));
pushBackRoute = parking->getPushBackRoute(); pushBackRoute = parking->getPushBackRoute();
int size = pushBackRoute->size(); int size = pushBackRoute->size();
if (size < 2) { if (size < 2) {
SG_LOG(SG_GENERAL, SG_WARN, "Push back route from gate " << gateId << " has only " << size << " nodes."); SG_LOG(SG_GENERAL, SG_WARN, "Push back route from gate " << gateId << " has only " << size << " nodes.");
SG_LOG(SG_GENERAL, SG_WARN, "Using " << pushBackNode);
} }
pushBackRoute->first(); pushBackRoute->first();
waypoint *wpt; waypoint *wpt;

6
src/ATC/Makefile.am Normal file
View file

@ -0,0 +1,6 @@
noinst_LIBRARIES = libATC.a
libATC_a_SOURCES = \
trafficcontrol.cxx trafficcontrol.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

787
src/ATC/trafficcontrol.cxx Normal file
View file

@ -0,0 +1,787 @@
// trafficrecord.cxx - Implementation of AIModels ATC code.
//
// Written by Durk Talsma, started September 2006.
//
// Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "trafficcontrol.hxx"
#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include <Traffic/TrafficMgr.hxx>
/***************************************************************************
* FGTrafficRecord
**************************************************************************/
FGTrafficRecord::FGTrafficRecord() :
id(0), waitsForId(0),
currentPos(0),
leg(0),
state(0),
latitude(0),
longitude(0),
heading(0),
speed(0),
altitude(0),
radius(0) {
}
void FGTrafficRecord::setPositionAndIntentions(int pos, FGAIFlightPlan *route)
{
currentPos = pos;
if (intentions.size()) {
intVecIterator i = intentions.begin();
if ((*i) != pos) {
SG_LOG(SG_GENERAL, SG_ALERT, "Error in FGTrafficRecord::setPositionAndIntentions");
//cerr << "Pos : " << pos << " Curr " << *(intentions.begin()) << endl;
for (intVecIterator i = intentions.begin(); i != intentions.end() ; i++) {
//cerr << (*i) << " ";
}
//cerr << endl;
}
intentions.erase(i);
} else {
//int legNr, routeNr;
//FGAIFlightPlan::waypoint* const wpt= route->getCurrentWaypoint();
int size = route->getNrOfWayPoints();
//cerr << "Setting pos" << pos << " ";
//cerr << "setting intentions ";
for (int i = 0; i < size; i++) {
int val = route->getRouteIndex(i);
//cerr << val<< " ";
if ((val) && (val != pos))
{
intentions.push_back(val);
//cerr << "[set] ";
}
}
//cerr << endl;
//while (route->next(&legNr, &routeNr)) {
//intentions.push_back(routeNr);
//}
//route->rewind(currentPos);
}
//exit(1);
}
bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord &other)
{
bool result = false;
//cerr << "Start check 1" << endl;
if (currentPos == other.currentPos)
{
//cerr << callsign << ": Check Position and intentions: we are on the same taxiway" << other.callsign << "Index = " << currentPos << endl;
result = true;
}
// else if (other.intentions.size())
// {
// cerr << "Start check 2" << endl;
// intVecIterator i = other.intentions.begin();
// while (!((i == other.intentions.end()) || ((*i) == currentPos)))
// i++;
// if (i != other.intentions.end()) {
// cerr << "Check Position and intentions: current matches other.intentions" << endl;
// result = true;
// }
else if (intentions.size()) {
//cerr << "Start check 3" << endl;
intVecIterator i = intentions.begin();
//while (!((i == intentions.end()) || ((*i) == other.currentPos)))
while (i != intentions.end()) {
if ((*i) == other.currentPos) {
break;
}
i++;
}
if (i != intentions.end()) {
//cerr << callsign << ": Check Position and intentions: .other.current matches" << other.callsign << "Index = " << (*i) << endl;
result = true;
}
}
//cerr << "Done !!" << endl;
return result;
}
void FGTrafficRecord::setPositionAndHeading(double lat, double lon, double hdg,
double spd, double alt)
{
latitude = lat;
longitude = lon;
heading = hdg;
speed = spd;
altitude = alt;
}
int FGTrafficRecord::crosses(FGGroundNetwork *net, FGTrafficRecord &other)
{
if (checkPositionAndIntentions(other) || (other.checkPositionAndIntentions(*this)))
return -1;
intVecIterator i, j;
int currentTargetNode = 0, otherTargetNode = 0;
if (currentPos > 0)
currentTargetNode = net->findSegment(currentPos )->getEnd()->getIndex(); // OKAY,...
if (other.currentPos > 0)
otherTargetNode = net->findSegment(other.currentPos)->getEnd()->getIndex(); // OKAY,...
if ((currentTargetNode == otherTargetNode) && currentTargetNode > 0)
return currentTargetNode;
if (intentions.size())
{
for (i = intentions.begin(); i != intentions.end(); i++)
{
if ((*i) > 0) {
if ((currentTargetNode == net->findSegment(*i)->getEnd()->getIndex()))
{
//cerr << "Current crosses at " << currentTargetNode <<endl;
return currentTargetNode;
}
}
}
}
if (other.intentions.size())
{
for (i = other.intentions.begin(); i != other.intentions.end(); i++)
{
if ((*i) > 0) {
if (otherTargetNode == net->findSegment(*i)->getEnd()->getIndex())
{
//cerr << "Other crosses at " << currentTargetNode <<endl;
return otherTargetNode;
}
}
}
}
if (intentions.size() && other.intentions.size())
{
for (i = intentions.begin(); i != intentions.end(); i++)
{
for (j = other.intentions.begin(); j != other.intentions.end(); j++)
{
//cerr << "finding segment " << *i << " and " << *j << endl;
if (((*i) > 0) && ((*j) > 0)) {
currentTargetNode = net->findSegment(*i)->getEnd()->getIndex();
otherTargetNode = net->findSegment(*j)->getEnd()->getIndex();
if (currentTargetNode == otherTargetNode)
{
//cerr << "Routes will cross at " << currentTargetNode << endl;
return currentTargetNode;
}
}
}
}
}
return -1;
}
bool FGTrafficRecord::onRoute(FGGroundNetwork *net, FGTrafficRecord &other)
{
int node = -1, othernode = -1;
if (currentPos >0)
node = net->findSegment(currentPos)->getEnd()->getIndex();
if (other.currentPos > 0)
othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
if ((node == othernode) && (node != -1))
return true;
if (other.intentions.size())
{
for (intVecIterator i = other.intentions.begin(); i != other.intentions.end(); i++)
{
if (*i > 0)
{
othernode = net->findSegment(*i)->getEnd()->getIndex();
if ((node == othernode) && (node > -1))
return true;
}
}
}
//if (other.currentPos > 0)
// othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
//if (intentions.size())
// {
// for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
// {
// if (*i > 0)
// {
// node = net->findSegment(*i)->getEnd()->getIndex();
// if ((node == othernode) && (node > -1))
// return true;
// }
// }
// }
return false;
}
bool FGTrafficRecord::isOpposing (FGGroundNetwork *net, FGTrafficRecord &other, int node)
{
// Check if current segment is the reverse segment for the other aircraft
FGTaxiSegment *opp;
//cerr << "Current segment " << currentPos << endl;
if ((currentPos > 0) && (other.currentPos > 0))
{
opp = net->findSegment(currentPos)->opposite();
if (opp) {
if (opp->getIndex() == other.currentPos)
return true;
}
for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
{
if (opp = net->findSegment(other.currentPos)->opposite())
{
if ((*i) > 0)
if (opp->getIndex() == net->findSegment(*i)->getIndex())
{
if (net->findSegment(*i)->getStart()->getIndex() == node) {
{
//cerr << "Found the node " << node << endl;
return true;
}
}
}
}
if (other.intentions.size())
{
for (intVecIterator j = other.intentions.begin(); j != other.intentions.end(); j++)
{
// cerr << "Current segment 1 " << (*i) << endl;
if ((*i) > 0) {
if (opp = net->findSegment(*i)->opposite())
{
if (opp->getIndex() ==
net->findSegment(*j)->getIndex())
{
//cerr << "Nodes " << net->findSegment(*i)->getIndex()
// << " and " << net->findSegment(*j)->getIndex()
// << " are opposites " << endl;
if (net->findSegment(*i)->getStart()->getIndex() == node) {
{
//cerr << "Found the node " << node << endl;
return true;
}
}
}
}
}
}
}
}
}
return false;
}
void FGTrafficRecord::setSpeedAdjustment(double spd)
{
instruction.setChangeSpeed(true);
instruction.setSpeed(spd);
}
void FGTrafficRecord::setHeadingAdjustment(double heading)
{
instruction.setChangeHeading(true);
instruction.setHeading(heading);
}
/***************************************************************************
* FGATCInstruction
*
**************************************************************************/
FGATCInstruction::FGATCInstruction()
{
holdPattern = false;
holdPosition = false;
changeSpeed = false;
changeHeading = false;
changeAltitude = false;
resolveCircularWait = false;
double speed = 0;
double heading = 0;
double alt = 0;
}
bool FGATCInstruction::hasInstruction()
{
return (holdPattern || holdPosition || changeSpeed || changeHeading || changeAltitude || resolveCircularWait);
}
string FGATCController::getGateName(FGAIAircraft *ref)
{
return ref->atGate();
}
void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir)
{
string sender, receiver;
int commFreq = 0;
//double commFreqD;
switch (msgDir) {
case ATC_AIR_TO_GROUND:
sender = rec->getAircraft()->getTrafficRef()->getCallSign();
switch (rec->getLeg()) {
case 2:
commFreq =
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency();
receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
break;
case 3:
receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
break;
case 4:
receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Tower";
break;
}
break;
case ATC_GROUND_TO_AIR:
receiver = rec->getAircraft()->getTrafficRef()->getCallSign();
switch (rec->getLeg()) {
case 2:
commFreq =
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency();
sender = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
break;
case 3:
sender = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
break;
case 4:
sender = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Tower";
break;
}
break;
}
string text;
switch (msgId) {
case MSG_ANNOUNCE_ENGINE_START:
text = sender + ". Ready to Start up";
break;
case MSG_REQUEST_ENGINE_START:
text = receiver + ", This is " + sender + ". Position " +getGateName(rec->getAircraft()) +
". Information YY." +
rec->getAircraft()->getTrafficRef()->getFlightRules() + " to " +
rec->getAircraft()->getTrafficRef()->getArrivalAirport()->getName() + ". Request start-up";
break;
case MSG_PERMIT_ENGINE_START:
text = receiver + ". Start-up approved. YY correct, runway ZZ, AAA departure, squawk BBBB. " +
"For push-back and taxi clearance call CCC.CCC. " + sender + " control.";
break;
case MSG_DENY_ENGINE_START:
text = receiver + ". Standby";
break;
case MSG_ACKNOWLEDGE_ENGINE_START:
text = receiver + ". Start-up approved. YY correct, runway ZZ, AAA departure, squawk BBBB. " +
"For push-back and taxi clearance call CCC.CCC. " + sender;
break;
default:
break;
}
double currFreq = fgGetDouble("/instrumentation/comm/frequencies/selected-mhz");
int currFreqI = (int) round(currFreq * 100);
//cerr << "Using " << currFreqI << " and " << commFreq << endl;
if (currFreqI == commFreq) {
fgSetString("/sim/messages/atc", text.c_str());
//cerr << "Printing Message: " << endl;
}
}
/***************************************************************************
* class FGTowerController
*
**************************************************************************/
FGTowerController::FGTowerController() :
FGATCController()
{
}
//
void FGTowerController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
double lat, double lon, double heading,
double speed, double alt, double radius, int leg,
FGAIAircraft *ref)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id alread has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
// Add a new TrafficRecord if no one exsists for this aircraft.
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
FGTrafficRecord rec;
rec.setId(id);
rec.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRunway(intendedRoute->getRunway());
rec.setLeg(leg);
//rec.setCallSign(callsign);
rec.setAircraft(ref);
activeTraffic.push_back(rec);
} else {
i->setPositionAndHeading(lat, lon, heading, speed, alt);
}
}
void FGTowerController::update(int id, double lat, double lon, double heading, double speed, double alt,
double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
TrafficVectorIterator current, closest;
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
// // update position of the current aircraft
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: updating aircraft without traffic record");
} else {
i->setPositionAndHeading(lat, lon, heading, speed, alt);
current = i;
}
setDt(getDt() + dt);
// // see if we already have a clearance record for the currently active runway
ActiveRunwayVecIterator rwy = activeRunways.begin();
// again, a map might be more efficient here
if (activeRunways.size()) {
//while ((rwy->getRunwayName() != current->getRunway()) && (rwy != activeRunways.end())) {
while (rwy != activeRunways.end()) {
if (rwy->getRunwayName() == current->getRunway()) {
break;
}
rwy++;
}
}
if (rwy == activeRunways.end()) {
ActiveRunway aRwy(current->getRunway(), id);
activeRunways.push_back(aRwy); // Since there are no clearance records for this runway yet
current->setHoldPosition(false); // Clear the current aircraft to continue
}
else {
// Okay, we have a clearance record for this runway, so check
// whether the clearence ID matches that of the current aircraft
if (id == rwy->getCleared()) {
current->setHoldPosition(false);
} else {
current->setHoldPosition(true);
}
}
}
void FGTowerController::signOff(int id)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id alread has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
// If this aircraft has left the runway, we can clear the departure record for this runway
ActiveRunwayVecIterator rwy = activeRunways.begin();
if (activeRunways.size()) {
//while ((rwy->getRunwayName() != i->getRunway()) && (rwy != activeRunways.end())) {
while (rwy != activeRunways.end()) {
if (rwy->getRunwayName() == i->getRunway()) {
break;
}
rwy++;
}
if (rwy != activeRunways.end()) {
rwy = activeRunways.erase(rwy);
} else {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff");
}
}
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower");
} else {
i = activeTraffic.erase(i);
}
}
// NOTE:
// IF WE MAKE TRAFFICRECORD A MEMBER OF THE BASE CLASS
// THE FOLLOWING THREE FUNCTIONS: SIGNOFF, HAS INSTRUCTION AND GETINSTRUCTION CAN
// BECOME DEVIRTUALIZED AND BE A MEMBER OF THE BASE ATCCONTROLLER CLASS
// WHICH WOULD SIMPLIFY CODE MAINTENANCE.
// Note that this function is probably obsolete
bool FGTowerController::hasInstruction(int id)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
if (activeTraffic.size())
{
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: checking ATC instruction for aircraft without traffic record");
} else {
return i->hasInstruction();
}
return false;
}
FGATCInstruction FGTowerController::getInstruction(int id)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
} else {
return i->getInstruction();
}
return FGATCInstruction();
}
/***************************************************************************
* class FGStartupController
*
**************************************************************************/
FGStartupController::FGStartupController() :
FGATCController()
{
available = true;
}
void FGStartupController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
double lat, double lon, double heading,
double speed, double alt, double radius, int leg,
FGAIAircraft *ref)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id alread has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
// Add a new TrafficRecord if no one exsists for this aircraft.
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
FGTrafficRecord rec;
rec.setId(id);
rec.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRunway(intendedRoute->getRunway());
rec.setLeg(leg);
//rec.setCallSign(callsign);
rec.setAircraft(ref);
rec.setHoldPosition(true);
activeTraffic.push_back(rec);
} else {
i->setPositionAndHeading(lat, lon, heading, speed, alt);
}
}
// NOTE:
// IF WE MAKE TRAFFICRECORD A MEMBER OF THE BASE CLASS
// THE FOLLOWING THREE FUNCTIONS: SIGNOFF, HAS INSTRUCTION AND GETINSTRUCTION CAN
// BECOME DEVIRTUALIZED AND BE A MEMBER OF THE BASE ATCCONTROLLER CLASS
// WHICH WOULD SIMPLIFY CODE MAINTENANCE.
// Note that this function is probably obsolete
bool FGStartupController::hasInstruction(int id)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
if (activeTraffic.size())
{
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: checking ATC instruction for aircraft without traffic record");
} else {
return i->hasInstruction();
}
return false;
}
FGATCInstruction FGStartupController::getInstruction(int id)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
} else {
return i->getInstruction();
}
return FGATCInstruction();
}
void FGStartupController::signOff(int id)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id alread has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower");
} else {
i = activeTraffic.erase(i);
}
}
void FGStartupController::update(int id, double lat, double lon, double heading, double speed, double alt,
double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
TrafficVectorIterator current, closest;
if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
while (i != activeTraffic.end()) {
if (i->getId() == id) {
break;
}
i++;
}
}
// // update position of the current aircraft
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: updating aircraft without traffic record");
} else {
i->setPositionAndHeading(lat, lon, heading, speed, alt);
current = i;
}
setDt(getDt() + dt);
int state = i->getState();
time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
if ((now - lastTransmission) > 3 + (rand() % 15)) {
available = true;
}
if ((state == 0) && available) {
if (now > startTime) {
transmit(&(*i), MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
i->updateState();
lastTransmission = now;
available = false;
}
}
if ((state == 1) && available) {
if (now > startTime+60) {
transmit(&(*i), MSG_REQUEST_ENGINE_START, ATC_AIR_TO_GROUND);
i->updateState();
lastTransmission = now;
available = false;
}
}
if ((state == 2) && available) {
if (now > startTime+80) {
transmit(&(*i), MSG_PERMIT_ENGINE_START, ATC_GROUND_TO_AIR);
i->updateState();
lastTransmission = now;
available = false;
}
}
if ((state == 3) && available){
if (now > startTime+100) {
transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START, ATC_AIR_TO_GROUND);
i->updateState();
lastTransmission = now;
available = false;
}
}
// TODO: Switch to APRON control and request pushback Clearance.
// Get Push back clearance
if ((state == 4) && available){
i->setHoldPosition(false);
}
}

292
src/ATC/trafficcontrol.hxx Normal file
View file

@ -0,0 +1,292 @@
// trafficcontrol.hxx - classes to manage AIModels based air traffic control
// Written by Durk Talsma, started September 2006.
//
// 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 _TRAFFIC_CONTROL_HXX_
#define _TRAFFIC_CONTROL_HXX_
#ifndef __cplusplus
# error This library requires C++
#endif
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include STL_STRING
#include <vector>
SG_USING_STD(string);
SG_USING_STD(vector);
typedef vector<int> intVec;
typedef vector<int>::iterator intVecIterator;
class FGAIFlightPlan; // forward reference
class FGGroundNetwork; // forward reference
//class FGAISchedule; // forward reference
class FGAIAircraft; // forward reference
/**************************************************************************************
* class FGATCInstruction
* like class FGATC Controller, this class definition should go into its own file
* and or directory... For now, just testing this stuff out though...
*************************************************************************************/
class FGATCInstruction
{
private:
bool holdPattern;
bool holdPosition;
bool changeSpeed;
bool changeHeading;
bool changeAltitude;
bool resolveCircularWait;
double speed;
double heading;
double alt;
public:
FGATCInstruction();
bool hasInstruction ();
bool getHoldPattern () { return holdPattern; };
bool getHoldPosition () { return holdPosition; };
bool getChangeSpeed () { return changeSpeed; };
bool getChangeHeading () { return changeHeading; };
bool getChangeAltitude() { return changeAltitude; };
double getSpeed () { return speed; };
double getHeading () { return heading; };
double getAlt () { return alt; };
bool getCheckForCircularWait() { return resolveCircularWait; };
void setHoldPattern (bool val) { holdPattern = val; };
void setHoldPosition (bool val) { holdPosition = val; };
void setChangeSpeed (bool val) { changeSpeed = val; };
void setChangeHeading (bool val) { changeHeading = val; };
void setChangeAltitude(bool val) { changeAltitude = val; };
void setResolveCircularWait (bool val) { resolveCircularWait = val; };
void setSpeed (double val) { speed = val; };
void setHeading (double val) { heading = val; };
void setAlt (double val) { alt = val; };
};
/**************************************************************************************
* class FGTrafficRecord
*************************************************************************************/
class FGTrafficRecord
{
private:
int id, waitsForId;
int currentPos;
int leg;
int state;
time_t timer;
intVec intentions;
FGATCInstruction instruction;
double latitude, longitude, heading, speed, altitude, radius;
string runway;
//FGAISchedule *trafficRef;
FGAIAircraft *aircraft;
public:
FGTrafficRecord();
void setId(int val) { id = val; };
void setRadius(double rad) { radius = rad;};
void setPositionAndIntentions(int pos, FGAIFlightPlan *route);
void setRunway(string rwy) { runway = rwy;};
void setLeg(int lg) { leg = lg;};
int getId() { return id;};
int getState() { return state;};
FGATCInstruction getInstruction() { return instruction;};
bool hasInstruction() { return instruction.hasInstruction(); };
void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt);
bool checkPositionAndIntentions(FGTrafficRecord &other);
int crosses (FGGroundNetwork *, FGTrafficRecord &other);
bool isOpposing (FGGroundNetwork *, FGTrafficRecord &other, int node);
bool onRoute(FGGroundNetwork *, FGTrafficRecord &other);
bool getSpeedAdjustment() { return instruction.getChangeSpeed(); };
double getLatitude () { return latitude ; };
double getLongitude() { return longitude; };
double getHeading () { return heading ; };
double getSpeed () { return speed ; };
double getAltitude () { return altitude ; };
double getRadius () { return radius ; };
int getWaitsForId () { return waitsForId; };
void setSpeedAdjustment(double spd);
void setHeadingAdjustment(double heading);
void clearSpeedAdjustment () { instruction.setChangeSpeed (false); };
void clearHeadingAdjustment() { instruction.setChangeHeading(false); };
bool hasHeadingAdjustment() { return instruction.getChangeHeading(); };
bool hasHoldPosition() { return instruction.getHoldPosition(); };
void setHoldPosition (bool inst) { instruction.setHoldPosition(inst); };
void setWaitsForId(int id) { waitsForId = id; };
void setResolveCircularWait() { instruction.setResolveCircularWait(true); };
void clearResolveCircularWait() { instruction.setResolveCircularWait(false); };
string getRunway() { return runway; };
//void setCallSign(string clsgn) { callsign = clsgn; };
void setAircraft(FGAIAircraft *ref) { aircraft = ref;};
void updateState() { state++;};
//string getCallSign() { return callsign; };
FGAIAircraft *getAircraft() { return aircraft;};
int getTime() { return timer; };
int getLeg() { return leg; };
void setTime(time_t time) { timer = time; };
};
typedef vector<FGTrafficRecord> TrafficVector;
typedef vector<FGTrafficRecord>::iterator TrafficVectorIterator;
/***********************************************************************
* Active runway, a utility class to keep track of which aircraft has
* clearance for a given runway.
**********************************************************************/
class ActiveRunway
{
private:
string rwy;
int currentlyCleared;
public:
ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; };
string getRunwayName() { return rwy; };
int getCleared () { return currentlyCleared; };
};
typedef vector<ActiveRunway> ActiveRunwayVec;
typedef vector<ActiveRunway>::iterator ActiveRunwayVecIterator;
/**
* class FGATCController
* NOTE: this class serves as an abstraction layer for all sorts of ATC controller.
*************************************************************************************/
class FGATCController
{
private:
double dt_count;
public:
typedef enum {
MSG_ANNOUNCE_ENGINE_START,
MSG_REQUEST_ENGINE_START,
MSG_PERMIT_ENGINE_START,
MSG_DENY_ENGINE_START,
MSG_ACKNOWLEDGE_ENGINE_START } AtcMsgId;
typedef enum {
ATC_AIR_TO_GROUND,
ATC_GROUND_TO_AIR } AtcMsgDir;
FGATCController() { dt_count = 0;};
virtual ~FGATCController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft) = 0;
virtual void signOff(int id) = 0;
virtual void update(int id, double lat, double lon,
double heading, double speed, double alt, double dt) = 0;
virtual bool hasInstruction(int id) = 0;
virtual FGATCInstruction getInstruction(int id) = 0;
double getDt() { return dt_count; };
void setDt(double dt) { dt_count = dt;};
void transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir);
string getGateName(FGAIAircraft *aircraft);
};
/******************************************************************************
* class FGTowerControl
*****************************************************************************/
class FGTowerController : public FGATCController
{
private:
TrafficVector activeTraffic;
ActiveRunwayVec activeRunways;
public:
FGTowerController();
virtual ~FGTowerController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void update(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
TrafficVector &getActiveTraffic() { return activeTraffic; };
};
/******************************************************************************
* class FGStartupController
* handle
*****************************************************************************/
class FGStartupController : public FGATCController
{
private:
TrafficVector activeTraffic;
bool available;
time_t lastTransmission;
//ActiveRunwayVec activeRunways;
public:
FGStartupController();
virtual ~FGStartupController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void update(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
TrafficVector &getActiveTraffic() { return activeTraffic; };
};
#endif // _TRAFFIC_CONTROL_HXX

View file

@ -1,6 +1,6 @@
noinst_LIBRARIES = libATC.a noinst_LIBRARIES = libATCDCL.a
libATC_a_SOURCES = \ libATCDCL_a_SOURCES = \
ATC.hxx ATC.cxx \ ATC.hxx ATC.cxx \
atis.hxx atis.cxx \ atis.hxx atis.cxx \
tower.hxx tower.cxx \ tower.hxx tower.cxx \

View file

@ -11,7 +11,6 @@ libAirports_a_SOURCES = \
gnnode.cxx gnnode.hxx \ gnnode.cxx gnnode.hxx \
groundnetwork.cxx groundnetwork.hxx \ groundnetwork.cxx groundnetwork.hxx \
dynamics.cxx dynamics.hxx \ dynamics.cxx dynamics.hxx \
trafficcontrol.cxx trafficcontrol.hxx \
dynamicloader.cxx dynamicloader.hxx \ dynamicloader.cxx dynamicloader.hxx \
runwayprefloader.cxx runwayprefloader.hxx \ runwayprefloader.cxx runwayprefloader.hxx \
xmlloader.cxx xmlloader.hxx xmlloader.cxx xmlloader.hxx

View file

@ -34,6 +34,7 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr
FGTaxiNode taxiNode; FGTaxiNode taxiNode;
FGTaxiSegment taxiSegment; FGTaxiSegment taxiSegment;
int index = 0; int index = 0;
string idxStr;
taxiSegment.setIndex(index); taxiSegment.setIndex(index);
//cout << "Start element " << name << endl; //cout << "Start element " << name << endl;
string attname; string attname;
@ -44,15 +45,19 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr
string lat; string lat;
string lon; string lon;
int holdPointType; int holdPointType;
int pushBackPoint;
if (name == string("Parking")) if (name == string("Parking"))
{ {
pushBackPoint = 0;
for (int i = 0; i < atts.size(); i++) for (int i = 0; i < atts.size(); i++)
{ {
//cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
attname = atts.getName(i); attname = atts.getName(i);
if (attname == string("index")) if (attname == string("index")) {
park.setIndex(std::atoi(atts.getValue(i))); park.setIndex(std::atoi(atts.getValue(i)));
idxStr = atts.getValue(i);
}
else if (attname == string("type")) else if (attname == string("type"))
park.setType(atts.getValue(i)); park.setType(atts.getValue(i));
else if (attname == string("name")) else if (attname == string("name"))
@ -72,10 +77,17 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr
//cerr << "Radius " << radius <<endl; //cerr << "Radius " << radius <<endl;
park.setRadius(std::atof(radius.c_str())); park.setRadius(std::atof(radius.c_str()));
} }
else if (attname == string("airlineCodes")) else if (attname == string("airlineCodes"))
park.setCodes(atts.getValue(i)); park.setCodes(atts.getValue(i));
else if (attname == string("pushBackRoute")) {
pushBackPoint = std::atoi(atts.getValue(i));
//park.setPushBackPoint(std::atoi(atts.getValue(i)));
}
} }
park.setPushBackPoint(pushBackPoint);
park.setName((gateName+gateNumber)); park.setName((gateName+gateNumber));
//cerr << "Parking " << idxStr << "( " << gateName << gateNumber << ") has pushBackPoint " << pushBackPoint << endl;
_dynamics->addParking(park); _dynamics->addParking(park);
} }
if (name == string("node")) if (name == string("node"))
@ -128,16 +140,41 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr
void FGAirportDynamicsXMLLoader::endElement (const char * name) { void FGAirportDynamicsXMLLoader::endElement (const char * name) {
//cout << "End element " << name << endl; //cout << "End element " << name << endl;
if (name == string("AWOS")) {
_dynamics->addAwosFreq(atoi(value.c_str()));
//cerr << "Adding AWOS" << value<< endl;
}
if (name == string("UNICOM")) {
_dynamics->addUnicomFreq(atoi(value.c_str()));
//cerr << "UNICOM" << value<< endl;
}
if (name == string("CLEARANCE")) {
_dynamics->addClearanceFreq(atoi(value.c_str()));
//cerr << "Adding CLEARANCE" << value<< endl;
}
if (name == string("GROUND")) {
_dynamics->addGroundFreq(atoi(value.c_str()));
//cerr << "Adding GROUND" << value<< endl;
}
if (name == string("TOWER")) {
_dynamics->addTowerFreq(atoi(value.c_str()));
//cerr << "Adding TOWER" << value<< endl;
}
if (name == string("APPROACH")) {
_dynamics->addApproachFreq(atoi(value.c_str()));
//cerr << "Adding approach" << value<< endl;
}
} }
void FGAirportDynamicsXMLLoader::data (const char * s, int len) { void FGAirportDynamicsXMLLoader::data (const char * s, int len) {
string token = string(s,len); string token = string(s,len);
//cout << "Character data " << string(s,len) << endl; //cout << "Character data " << string(s,len) << endl;
//if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos)) if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
//value += token; value += token;
//else else
//value = string(""); value = string("");
} }
void FGAirportDynamicsXMLLoader::pi (const char * target, const char * data) { void FGAirportDynamicsXMLLoader::pi (const char * target, const char * data) {

View file

@ -36,6 +36,7 @@ protected:
private: private:
FGAirportDynamics* _dynamics; FGAirportDynamics* _dynamics;
string value;
}; };
#endif #endif

View file

@ -205,10 +205,10 @@ bool FGAirportDynamics::getAvailableParking(double *lat, double *lon, double *he
if (!(i->getCodes().empty())) if (!(i->getCodes().empty()))
{ {
if ((i->getCodes().find(airline,0) == string::npos)) if ((i->getCodes().find(airline,0) == string::npos))
{ {
available = false; available = false;
continue; continue;
} }
} }
if (i->getType() != flType) if (i->getType() != flType)
{ {
@ -303,18 +303,27 @@ void FGAirportDynamics::getParking (int id, double *lat, double* lon, double *he
} }
} }
FGParking *FGAirportDynamics::getParking(int i) FGParking *FGAirportDynamics::getParking(int id)
{ {
if (i < (int)parkings.size() && (i >= 0)) FGParkingVecIterator i = parkings.begin();
return &(parkings[i]); for (i = parkings.begin(); i != parkings.end(); i++)
else {
if (id == i->getIndex()) {
return &(*i);
}
}
return 0; return 0;
} }
string FGAirportDynamics::getParkingName(int i) string FGAirportDynamics::getParkingName(int id)
{ {
if (i < (int)parkings.size() && i >= 0) FGParkingVecIterator i = parkings.begin();
return (parkings[i].getName()); for (i = parkings.begin(); i != parkings.end(); i++)
else {
if (id == i->getIndex()) {
return i->getName();
}
}
return string("overflow"); return string("overflow");
} }
void FGAirportDynamics::releaseParking(int id) void FGAirportDynamics::releaseParking(int id)

View file

@ -29,22 +29,27 @@
#include <simgear/xml/easyxml.hxx> #include <simgear/xml/easyxml.hxx>
#include <ATC/trafficcontrol.hxx>
#include "parking.hxx" #include "parking.hxx"
#include "groundnetwork.hxx" #include "groundnetwork.hxx"
#include "runwayprefs.hxx" #include "runwayprefs.hxx"
#include "trafficcontrol.hxx"
//typedef vector<float> DoubleVec;
//typedef vector<float>::iterator DoubleVecIterator;
class FGAirport; class FGAirport;
class FGAirportDynamics { class FGAirportDynamics {
private: private:
FGAirport* _ap; FGAirport* _ap;
FGParkingVec parkings; FGParkingVec parkings;
FGRunwayPreference rwyPrefs; FGRunwayPreference rwyPrefs;
FGGroundNetwork groundNetwork; FGStartupController startupController;
FGTowerController towerController; FGGroundNetwork groundNetwork;
FGTowerController towerController;
time_t lastUpdate; time_t lastUpdate;
string prevTrafficType; string prevTrafficType;
@ -52,6 +57,12 @@ private:
stringVec takeoff; stringVec takeoff;
stringVec milActive, comActive, genActive, ulActive; stringVec milActive, comActive, genActive, ulActive;
stringVec *currentlyActive; stringVec *currentlyActive;
intVec freqAwos; // </AWOS>
intVec freqUnicom; // </UNICOM>
intVec freqClearance;// </CLEARANCE>
intVec freqGround; // </GROUND>
intVec freqTower; // </TOWER>
intVec freqApproach; // </APPROACH>
// Experimental keep a running average of wind dir and speed to prevent // Experimental keep a running average of wind dir and speed to prevent
// Erratic runway changes. // Erratic runway changes.
@ -67,6 +78,12 @@ public:
FGAirportDynamics(const FGAirportDynamics &other); FGAirportDynamics(const FGAirportDynamics &other);
~FGAirportDynamics(); ~FGAirportDynamics();
void addAwosFreq (int val) { freqAwos.push_back(val); };
void addUnicomFreq (int val) { freqUnicom.push_back(val); };
void addClearanceFreq(int val) { freqClearance.push_back(val); };
void addGroundFreq (int val) { freqGround.push_back(val); };
void addTowerFreq (int val) { freqTower.push_back(val); };
void addApproachFreq (int val) { freqApproach.push_back(val); };
void init(); void init();
double getLongitude() const; double getLongitude() const;
@ -90,9 +107,12 @@ public:
//FGAirport *getAddress() { return this; }; //FGAirport *getAddress() { return this; };
//const string &getName() const { return _name;}; //const string &getName() const { return _name;};
// Returns degrees // Returns degrees
int getGroundFrequency() { return freqGround.size() ? freqGround[0] : 0; };
FGStartupController *getStartupController() { return &startupController; };
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
FGTowerController *getTowerController() { return &towerController; };
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
FGTowerController *getTowerController() { return &towerController; };
void setRwyUse(const FGRunwayPreference& ref); void setRwyUse(const FGRunwayPreference& ref);

View file

@ -476,189 +476,12 @@ int FGTaxiSegment::getPenalty(int nGates) {
return penalty; return penalty;
} }
// void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance) /* ATC Related Functions */
// {
// // Just check some preconditions of the trace algorithm
// if (nodesStack.size() != routesStack.size())
// {
// SG_LOG(SG_GENERAL, SG_ALERT, "size of nodesStack and routesStack is not equal. NodesStack :"
// << nodesStack.size() << ". RoutesStack : " << routesStack.size());
// }
// nodesStack.push_back(currNode->getIndex());
// totalDistance += distance;
// //cerr << "Starting trace " << currNode->getIndex() << " " << "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)
// {
// maxDepth = depth;
// //cerr << "Found route : " << totalDistance << "" << " " << *(nodesStack.end()-1) << " Depth = " << depth << endl;
// routes.push_back(FGTaxiRoute(nodesStack,routesStack,totalDistance, depth));
// if (nodesStack.empty() || routesStack.empty())
// {
// printRoutingError(string("while finishing route"));
// }
// nodesStack.pop_back();
// routesStack.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 nodesStack.end()-1; and we can continue
// // if i is not nodesStack.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 = nodesStack.begin();
// while ((*i) != currNode->getIndex()) {
// //cerr << "Route so far : " << (*i) << endl;
// i++;
// }
// if (i != nodesStack.end()-1) {
// if (nodesStack.empty() || routesStack.empty())
// {
// printRoutingError(string("while returning from an already encountered node"));
// }
// nodesStack.pop_back();
// routesStack.pop_back();
// totalDistance -= distance;
// return;
// }
// if (depth >= maxDepth) {
// count++;
// if (!(count % 100000)) {
// maxDepth--; // Gradually decrease maxdepth, to prevent "eternal searches"
// //cerr << "Reducing maxdepth to " << maxDepth << endl;
// }
// nodesStack.pop_back();
// routesStack.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)
// //if (foundRoute)
// {
// //cerr << "Stopping rediculously long trace: " << totalDistance << endl;
// if (nodesStack.empty() || routesStack.empty())
// {
// printRoutingError(string("while returning from finding a rediculously long route"));
// }
// nodesStack.pop_back();
// routesStack.pop_back();
// totalDistance -= distance;
// return;
// }
// }
/*
//cerr << "2" << endl;
if (currNode->getBeginRoute() != currNode->getEndRoute())
{
double course, length;
//cerr << "3" << endl;
// calculate distance and heading "as the crow flies" between starn and end points"
SGWayPoint first(currNode->getLongitude(),
currNode->getLatitude(),
0);
//SGWayPoint second (lastNode->getLongitude(),
// lastNode->getLatitude(),
// 0);
first.CourseAndDistance(destination, &course, &length);
//for (FGTaxiSegmentVectorIterator
// itr = segments.begin();
// itr != segments.end(); itr++)
// {
// (*itr)->setCourseDiff(course);
// }
//FGTaxiNodeVectorIterator nde = nodes.begin();
//while (nde != nodes.end()) {
//(*nde)->sortEndSegments();
//nde++;
for (FGTaxiSegmentVectorIterator
i = currNode->getBeginRoute();
i != currNode->getEndRoute();
i++)
{
(*i)->setCourseDiff(course);
}
currNode->sortEndSegments(foundRoute);
for (FGTaxiSegmentVectorIterator
i = currNode->getBeginRoute();
i != currNode->getEndRoute();
i++)
{
//cerr << (*i)->getLength() << endl;
//cerr << (*i)->getIndex() << endl;
int idx = (*i)->getIndex();
routesStack.push_back((*i)->getIndex());
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" );
}
if (nodesStack.empty())
{
printRoutingError(string("while finishing trace"));
}
nodesStack.pop_back();
// Make sure not to dump the level-zero routesStack entry, because that was never created.
if (depth)
{
routesStack.pop_back();
//cerr << "leaving trace " << routesStack.size() << endl;
}
totalDistance -= distance;
return;
}*/
/*
void FGGroundNetwork::printRoutingError(string mess)
{
SG_LOG(SG_GENERAL, SG_ALERT, "Error in ground network trace algorithm " << mess);
if (nodesStack.empty())
{
SG_LOG(SG_GENERAL, SG_ALERT, " nodesStack is empty. Dumping routesStack");
for (intVecIterator i = routesStack.begin() ; i != routesStack.end(); i++)
SG_LOG(SG_GENERAL, SG_ALERT, "Route " << (*i));
}
if (routesStack.empty())
{
SG_LOG(SG_GENERAL, SG_ALERT, " routesStack is empty. Dumping nodesStack");
for (intVecIterator i = nodesStack.begin() ; i != nodesStack.end(); i++)
SG_LOG(SG_GENERAL, SG_ALERT, "Node " << (*i));
}
//exit(1);
}
*/
void FGGroundNetwork::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition, void FGGroundNetwork::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
double lat, double lon, double heading, double lat, double lon, double heading,
double speed, double alt, double radius, int leg, double speed, double alt, double radius, int leg,
string callsign) FGAIAircraft *aircraft)
{ {
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id alread has an entry // Search search if the current id alread has an entry
@ -679,7 +502,7 @@ void FGGroundNetwork::announcePosition(int id, FGAIFlightPlan *intendedRoute, in
rec.setPositionAndIntentions(currentPosition, intendedRoute); rec.setPositionAndIntentions(currentPosition, intendedRoute);
rec.setPositionAndHeading(lat, lon, heading, speed, alt); rec.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRadius(radius); // only need to do this when creating the record. rec.setRadius(radius); // only need to do this when creating the record.
rec.setCallSign(callsign); rec.setAircraft(aircraft);
activeTraffic.push_back(rec); activeTraffic.push_back(rec);
} else { } else {
i->setPositionAndIntentions(currentPosition, intendedRoute); i->setPositionAndIntentions(currentPosition, intendedRoute);

View file

@ -35,7 +35,7 @@ SG_USING_STD(vector);
#include "gnnode.hxx" #include "gnnode.hxx"
#include "parking.hxx" #include "parking.hxx"
#include "trafficcontrol.hxx" #include <ATC/trafficcontrol.hxx>
class FGTaxiSegment; // forward reference class FGTaxiSegment; // forward reference
class FGAIFlightPlan; // forward reference class FGAIFlightPlan; // forward reference
@ -265,7 +265,7 @@ public:
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double hdg, double spd, double alt, double lat, double lon, double hdg, double spd, double alt,
double radius, int leg, string callsign); double radius, int leg, FGAIAircraft *aircraft);
virtual void signOff(int id); virtual void signOff(int id);
virtual void update(int id, double lat, double lon, double heading, double speed, double alt, double dt); virtual void update(int id, double lat, double lon, double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id); virtual bool hasInstruction(int id);

View file

@ -58,11 +58,8 @@ public:
FGParking() : FGParking() :
heading(0), heading(0),
radius(0), radius(0),
//parkingName(0),
//type(0),
//airlineCodes(0),
available(true), available(true),
pushBackPoint(-1), pushBackPoint(0),
pushBackRoute(0) pushBackRoute(0)
{ {
}; };

View file

@ -118,7 +118,7 @@ string ScheduleTime::getName(time_t dayStart)
//couldn't find one so return 0; //couldn't find one so return 0;
//cerr << "Returning 0 " << endl; //cerr << "Returning 0 " << endl;
} }
return string(0); return string("");
} }
/****************************************************************************** /******************************************************************************
* RunwayList * RunwayList

View file

@ -70,7 +70,7 @@ fgfs_SOURCES = bootstrap.cxx
fgfs_LDADD = \ fgfs_LDADD = \
$(top_builddir)/src/Main/libMain.a \ $(top_builddir)/src/Main/libMain.a \
$(top_builddir)/src/Aircraft/libAircraft.a \ $(top_builddir)/src/Aircraft/libAircraft.a \
$(top_builddir)/src/ATCDCL/libATC.a \ $(top_builddir)/src/ATCDCL/libATCDCL.a \
$(top_builddir)/src/Cockpit/libCockpit.a \ $(top_builddir)/src/Cockpit/libCockpit.a \
$(top_builddir)/src/Cockpit/built_in/libBuilt_in.a \ $(top_builddir)/src/Cockpit/built_in/libBuilt_in.a \
$(top_builddir)/src/FDM/libFlight.a \ $(top_builddir)/src/FDM/libFlight.a \
@ -97,6 +97,7 @@ fgfs_LDADD = \
$(top_builddir)/src/Airports/libAirports.a \ $(top_builddir)/src/Airports/libAirports.a \
$(MPLAYER_LIBS) \ $(MPLAYER_LIBS) \
$(top_builddir)/src/AIModel/libAIModel.a \ $(top_builddir)/src/AIModel/libAIModel.a \
$(top_builddir)/src/ATC/libATC.a \
$(top_builddir)/src/Systems/libSystems.a \ $(top_builddir)/src/Systems/libSystems.a \
$(top_builddir)/src/Time/libTime.a \ $(top_builddir)/src/Time/libTime.a \
$(top_builddir)/src/Traffic/libTraffic.a \ $(top_builddir)/src/Traffic/libTraffic.a \

View file

@ -2,6 +2,7 @@ SUBDIRS = \
Include \ Include \
Aircraft \ Aircraft \
Airports \ Airports \
ATC \
ATCDCL \ ATCDCL \
Autopilot \ Autopilot \
Cockpit \ Cockpit \