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:
parent
a0bb5b3c67
commit
17c42deae1
18 changed files with 1244 additions and 290 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
6
src/ATC/Makefile.am
Normal 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
787
src/ATC/trafficcontrol.cxx
Normal 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
292
src/ATC/trafficcontrol.hxx
Normal 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
|
|
@ -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 \
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FGAirportDynamics* _dynamics;
|
FGAirportDynamics* _dynamics;
|
||||||
|
string value;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -231,7 +231,7 @@ bool FGAirportDynamics::getAvailableParking(double *lat, double *lon, double *he
|
||||||
i->setAvailable(false);
|
i->setAvailable(false);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// And finally once more if that didn't work. Now ignore the airline codes, as a last resort
|
// And finally once more if that didn't work. Now ignore the airline codes, as a last resort
|
||||||
for (i = parkings.begin(); !(i == parkings.end() || found); i++)
|
for (i = parkings.begin(); !(i == parkings.end() || found); i++)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
|
@ -2,6 +2,7 @@ SUBDIRS = \
|
||||||
Include \
|
Include \
|
||||||
Aircraft \
|
Aircraft \
|
||||||
Airports \
|
Airports \
|
||||||
|
ATC \
|
||||||
ATCDCL \
|
ATCDCL \
|
||||||
Autopilot \
|
Autopilot \
|
||||||
Cockpit \
|
Cockpit \
|
||||||
|
|
Loading…
Add table
Reference in a new issue