return;
}
catch (FP_Inactive) {
- return;
+ //return;
+ groundTargetSpeed = 0;
}
handleATCRequests(); // ATC also has a word to say
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;
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();
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;
}
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()) {
} 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
throw AI_OutOfSight();
}
}
+ timeElapsed = now - fp->getStartTime();
if (! fp->isActive(now)) {
throw FP_Inactive();
}
} 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) {
else
headingChangeRate += dt * sign(roll);
}
- hdg += headingChangeRate * dt;
+
+ hdg += headingChangeRate * dt * (fabs(speed) / 15);
headingError = headingDiff;
} else {
if (fabs(speed) > 1.0) {
}
}
+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) {
void announcePositionToController(); //TODO have to be public?
void processATC(FGATCInstruction instruction);
+ FGAISchedule * getTrafficRef() { return trafficRef; };
virtual const char* getTypeString(void) const { return "aircraft"; }
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);
bool _getGearDown() const;
bool reachedWaypoint;
+ time_t timeElapsed;
PerformanceData* _performance; // the performance data for this aircraft
};
radius, fltType, aircraftType, airline);
} else {
if (firstFlight) {
+
if (!(dep->getDynamics()->getAvailableParking(&lat, &lon,
&heading, &gateId,
radius, fltType,
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);
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;
--- /dev/null
+noinst_LIBRARIES = libATC.a
+
+libATC_a_SOURCES = \
+ trafficcontrol.cxx trafficcontrol.hxx
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
--- /dev/null
+// 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);
+ }
+}
--- /dev/null
+// 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
-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 \
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
FGTaxiNode taxiNode;
FGTaxiSegment taxiSegment;
int index = 0;
+ string idxStr;
taxiSegment.setIndex(index);
//cout << "Start element " << name << endl;
string attname;
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"))
- park.setIndex(std::atoi(atts.getValue(i)));
+ 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"))
//cerr << "Radius " << radius <<endl;
park.setRadius(std::atof(radius.c_str()));
}
- else if (attname == string("airlineCodes"))
+ 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"))
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) {
private:
FGAirportDynamics* _dynamics;
+ string value;
};
#endif
if (!(i->getCodes().empty()))
{
if ((i->getCodes().find(airline,0) == string::npos))
- {
- available = false;
- continue;
- }
+ {
+ available = false;
+ continue;
+ }
}
if (i->getType() != flType)
{
i->setAvailable(false);
found = true;
}
- }
+ }
// 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++)
{
}
}
-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)
#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:
FGAirport* _ap;
- FGParkingVec parkings;
- FGRunwayPreference rwyPrefs;
- FGGroundNetwork groundNetwork;
- FGTowerController towerController;
+ FGParkingVec parkings;
+ FGRunwayPreference rwyPrefs;
+ FGStartupController startupController;
+ FGGroundNetwork groundNetwork;
+ FGTowerController towerController;
time_t lastUpdate;
string prevTrafficType;
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.
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;
//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; };
- FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
- FGTowerController *getTowerController() { return &towerController; };
void setRwyUse(const FGRunwayPreference& ref);
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
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);
#include "gnnode.hxx"
#include "parking.hxx"
-#include "trafficcontrol.hxx"
+#include <ATC/trafficcontrol.hxx>
class FGTaxiSegment; // forward reference
class FGAIFlightPlan; // forward reference
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);
FGParking() :
heading(0),
radius(0),
- //parkingName(0),
- //type(0),
- //airlineCodes(0),
available(true),
- pushBackPoint(-1),
+ pushBackPoint(0),
pushBackRoute(0)
{
};
//couldn't find one so return 0;
//cerr << "Returning 0 " << endl;
}
- return string(0);
+ return string("");
}
/******************************************************************************
* RunwayList
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 \
$(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 \
Include \
Aircraft \
Airports \
+ ATC \
ATCDCL \
Autopilot \
Cockpit \