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;
}
catch (FP_Inactive) {
return;
//return;
groundTargetSpeed = 0;
}
handleATCRequests(); // ATC also has a word to say
@ -365,7 +366,7 @@ void FGAIAircraft::getGroundElev(double dt) {
dt_elev_count += dt;
// 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))
return;
@ -413,10 +414,14 @@ void FGAIAircraft::announcePositionToController() {
if (trafficRef) {
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
//
switch (leg) {
case 2: // Startup and Push back
if (trafficRef->getDepartureAirport()->getDynamics())
controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController();
break;
case 3: // Taxiing to runway
if (trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork()->exists())
controller = trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork();
@ -425,12 +430,14 @@ void FGAIAircraft::announcePositionToController() {
if (trafficRef->getDepartureAirport()->getDynamics()) {
controller = trafficRef->getDepartureAirport()->getDynamics()->getTowerController();
//if (trafficRef->getDepartureAirport()->getId() == "EHAM") {
//cerr << trafficRef->getCallSign() << " at runway " << fp->getRunway() << "Ready for departure "
// << trafficRef->getFlightType() << " to " << trafficRef->getArrivalAirport()->getId() << endl;
//string trns = trafficRef->getCallSign() + " at runway " + fp->getRunway() +
// ". Ready for departure. " + trafficRef->getFlightType() + " to " +
// trafficRef->getArrivalAirport()->getId();
//fgSetString("/sim/messages/atc", trns.c_str());
// if (controller == 0) {
//cerr << "Error in assigning controller at " << trafficRef->getDepartureAirport()->getId() << endl;
//}
//}
} else {
cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
}
@ -446,29 +453,17 @@ void FGAIAircraft::announcePositionToController() {
if ((controller != prevController) && (prevController != 0)) {
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;
if (controller) {
controller->announcePosition(getID(), fp, fp->getCurrentWaypoint()->routeIndex,
_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) {
if (instruction.getCheckForCircularWait()) {
@ -494,7 +489,7 @@ void FGAIAircraft::processATC(FGATCInstruction instruction) {
} else {
if (holdPos) {
//if (trafficRef)
// cerr << trafficRef->getCallSign() << " Resuming Taxi " << endl;
// cerr << trafficRef->getCallSign() << " Resuming Taxi." << endl;
holdPos = false;
}
// Change speed Instruction. This can only be excecuted when there is no
@ -760,6 +755,7 @@ void FGAIAircraft::updatePrimaryTargetValues() {
throw AI_OutOfSight();
}
}
timeElapsed = now - fp->getStartTime();
if (! fp->isActive(now)) {
throw FP_Inactive();
}
@ -845,7 +841,7 @@ void FGAIAircraft::updateHeading() {
} else {
bank_sense = 1.0;
}
if (trafficRef)
//if (trafficRef)
//cerr << trafficRef->getCallSign() << " Heading "
// << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl;
//if (headingDiff > 60) {
@ -875,7 +871,8 @@ void FGAIAircraft::updateHeading() {
else
headingChangeRate += dt * sign(roll);
}
hdg += headingChangeRate * dt;
hdg += headingChangeRate * dt * (fabs(speed) / 15);
headingError = headingDiff;
} else {
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() {
//TODO implement NullController for having no ATC to save the conditionals
if (controller) {

View file

@ -70,6 +70,7 @@ public:
void announcePositionToController(); //TODO have to be public?
void processATC(FGATCInstruction instruction);
FGAISchedule * getTrafficRef() { return trafficRef; };
virtual const char* getTypeString(void) const { return "aircraft"; }
@ -82,6 +83,7 @@ public:
inline double getVerticalSpeed() const { return vs; };
inline double altitudeAGL() const { return props->getFloatValue("position/altitude-agl-ft");};
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
string atGate();
protected:
void Run(double dt);
@ -138,6 +140,7 @@ private:
bool _getGearDown() const;
bool reachedWaypoint;
time_t timeElapsed;
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);
} else {
if (firstFlight) {
if (!(dep->getDynamics()->getAvailableParking(&lat, &lon,
&heading, &gateId,
radius, fltType,
@ -70,6 +71,12 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep,
wpt->routeIndex = -1;
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 {
//cerr << "Push Back follow-up Flight" << endl;
dep->getDynamics()->getParking(gateId, &lat, &lon, &heading);
@ -89,61 +96,21 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep,
FGParking *parking = dep->getDynamics()->getParking(gateId);
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) {
//cerr << "Initializing PushBackRoute " << endl;
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) {
pushBackRoute = parking->getPushBackRoute();
if ((pushBackNode > 0) && (pushBackRoute == 0)) {
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();
int size = pushBackRoute->size();
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, "Using " << pushBackNode);
}
pushBackRoute->first();
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 \
atis.hxx atis.cxx \
tower.hxx tower.cxx \

View file

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

View file

@ -34,6 +34,7 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr
FGTaxiNode taxiNode;
FGTaxiSegment taxiSegment;
int index = 0;
string idxStr;
taxiSegment.setIndex(index);
//cout << "Start element " << name << endl;
string attname;
@ -44,15 +45,19 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr
string lat;
string lon;
int holdPointType;
int pushBackPoint;
if (name == string("Parking"))
{
pushBackPoint = 0;
for (int i = 0; i < atts.size(); i++)
{
//cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
attname = atts.getName(i);
if (attname == string("index"))
if (attname == string("index")) {
park.setIndex(std::atoi(atts.getValue(i)));
idxStr = atts.getValue(i);
}
else if (attname == string("type"))
park.setType(atts.getValue(i));
else if (attname == string("name"))
@ -74,8 +79,15 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr
}
else if (attname == string("airlineCodes"))
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));
//cerr << "Parking " << idxStr << "( " << gateName << gateNumber << ") has pushBackPoint " << pushBackPoint << endl;
_dynamics->addParking(park);
}
if (name == string("node"))
@ -128,16 +140,41 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr
void FGAirportDynamicsXMLLoader::endElement (const char * name) {
//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) {
string token = string(s,len);
//cout << "Character data " << string(s,len) << endl;
//if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
//value += token;
//else
//value = string("");
if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
value += token;
else
value = string("");
}
void FGAirportDynamicsXMLLoader::pi (const char * target, const char * data) {

View file

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

View file

@ -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))
return &(parkings[i]);
else
FGParkingVecIterator i = parkings.begin();
for (i = parkings.begin(); i != parkings.end(); i++)
{
if (id == i->getIndex()) {
return &(*i);
}
}
return 0;
}
string FGAirportDynamics::getParkingName(int i)
string FGAirportDynamics::getParkingName(int id)
{
if (i < (int)parkings.size() && i >= 0)
return (parkings[i].getName());
else
FGParkingVecIterator i = parkings.begin();
for (i = parkings.begin(); i != parkings.end(); i++)
{
if (id == i->getIndex()) {
return i->getName();
}
}
return string("overflow");
}
void FGAirportDynamics::releaseParking(int id)

View file

@ -29,13 +29,17 @@
#include <simgear/xml/easyxml.hxx>
#include <ATC/trafficcontrol.hxx>
#include "parking.hxx"
#include "groundnetwork.hxx"
#include "runwayprefs.hxx"
#include "trafficcontrol.hxx"
//typedef vector<float> DoubleVec;
//typedef vector<float>::iterator DoubleVecIterator;
class FGAirport;
class FGAirportDynamics {
private:
@ -43,6 +47,7 @@ private:
FGParkingVec parkings;
FGRunwayPreference rwyPrefs;
FGStartupController startupController;
FGGroundNetwork groundNetwork;
FGTowerController towerController;
@ -52,6 +57,12 @@ private:
stringVec takeoff;
stringVec milActive, comActive, genActive, ulActive;
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
// Erratic runway changes.
@ -67,6 +78,12 @@ public:
FGAirportDynamics(const FGAirportDynamics &other);
~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();
double getLongitude() const;
@ -90,11 +107,14 @@ public:
//FGAirport *getAddress() { return this; };
//const string &getName() const { return _name;};
// Returns degrees
int getGroundFrequency() { return freqGround.size() ? freqGround[0] : 0; };
FGStartupController *getStartupController() { return &startupController; };
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
FGTowerController *getTowerController() { return &towerController; };
void setRwyUse(const FGRunwayPreference& ref);
};

View file

@ -476,189 +476,12 @@ int FGTaxiSegment::getPenalty(int nGates) {
return penalty;
}
// void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance)
// {
// // 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);
}
*/
/* ATC Related Functions */
void FGGroundNetwork::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
double lat, double lon, double heading,
double speed, double alt, double radius, int leg,
string callsign)
FGAIAircraft *aircraft)
{
TrafficVectorIterator i = activeTraffic.begin();
// 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.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRadius(radius); // only need to do this when creating the record.
rec.setCallSign(callsign);
rec.setAircraft(aircraft);
activeTraffic.push_back(rec);
} else {
i->setPositionAndIntentions(currentPosition, intendedRoute);

View file

@ -35,7 +35,7 @@ SG_USING_STD(vector);
#include "gnnode.hxx"
#include "parking.hxx"
#include "trafficcontrol.hxx"
#include <ATC/trafficcontrol.hxx>
class FGTaxiSegment; // forward reference
class FGAIFlightPlan; // forward reference
@ -265,7 +265,7 @@ public:
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
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 update(int id, double lat, double lon, double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);

View file

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

View file

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

View file

@ -70,7 +70,7 @@ fgfs_SOURCES = bootstrap.cxx
fgfs_LDADD = \
$(top_builddir)/src/Main/libMain.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/built_in/libBuilt_in.a \
$(top_builddir)/src/FDM/libFlight.a \
@ -97,6 +97,7 @@ fgfs_LDADD = \
$(top_builddir)/src/Airports/libAirports.a \
$(MPLAYER_LIBS) \
$(top_builddir)/src/AIModel/libAIModel.a \
$(top_builddir)/src/ATC/libATC.a \
$(top_builddir)/src/Systems/libSystems.a \
$(top_builddir)/src/Time/libTime.a \
$(top_builddir)/src/Traffic/libTraffic.a \

View file

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