-// FGAIAircraft - FGAIBase-derived class creates an AI airplane
+// // FGAIAircraft - FGAIBase-derived class creates an AI airplane
//
// Written by David Culp, started October 2003.
//
handleATCRequests(); // ATC also has a word to say
updateSecondaryTargetValues(); // target roll, vertical speed, pitch
updateActualState();
- UpdateRadar(manager);
+ // We currently have one situation in which an AIAircraft object is used that is not attached to the
+ // AI manager. In this particular case, the AIAircraft is used to shadow the user's aircraft's behavior in the AI world.
+ // Since we perhaps don't want a radar entry of our own aircraft, the following conditional should probably be adequate
+ // enough
+ if (manager)
+ UpdateRadar(manager);
checkVisibility();
}
if (! leadPointReached(curr)) {
controlHeading(curr);
controlSpeed(curr, next);
+ if (speed < 0) {
+ cerr << getCallSign()
+ << ": verifying lead distance to waypoint : "
+ << fp->getCurrentWaypoint()->name << " "
+ << fp->getLeadDistance() << ". Distance to go "
+ << (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr))
+ << ". Target speed = "
+ << tgt_speed
+ << ". Current speed = "
+ << speed
+ << ". Minimum Bearing " << minBearing
+ << endl;
+ }
} else {
if (curr->finished) //end of the flight plan
{
//cerr << "2" << endl;
double lead_dist = fp->getLeadDistance();
// experimental: Use fabs, because speed can be negative (I hope) during push_back.
-
+ if ((dist_to_go < fabs(10.0* speed)) && (speed < 0) && (tgt_speed < 0) && fp->getCurrentWaypoint()->name == string("PushBackPoint")) {
+ tgt_speed = -(dist_to_go / 10.0);
+ if (tgt_speed > -0.5) {
+ tgt_speed = -0.5;
+ }
+ if (fp->getPreviousWaypoint()->speed < tgt_speed) {
+ fp->getPreviousWaypoint()->speed = tgt_speed;
+ }
+ }
if (lead_dist < fabs(2*speed)) {
//don't skip over the waypoint
lead_dist = fabs(2*speed);
bank_sense = 1.0;
}
//if (trafficRef)
- //cerr << trafficRef->getCallSign() << " Heading "
- // << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl;
+ // cerr << trafficRef->getCallSign() << " Heading "
+ // << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl;
//if (headingDiff > 60) {
groundTargetSpeed = tgt_speed; // * cos(headingDiff * SG_DEGREES_TO_RADIANS);
//groundTargetSpeed = tgt_speed - tgt_speed * (headingDiff/180);
//}
if (sign(groundTargetSpeed) != sign(tgt_speed))
groundTargetSpeed = 0.21 * sign(tgt_speed); // to prevent speed getting stuck in 'negative' mode
-
- if (headingDiff > 30.0) {
- // invert if pushed backward
- headingChangeRate += 10.0 * dt * sign(roll);
-
- // Clamp the maximum steering rate to 30 degrees per second,
- // But only do this when the heading error is decreasing.
- if ((headingDiff < headingError)) {
- if (headingChangeRate > 30)
- headingChangeRate = 30;
- else if (headingChangeRate < -30)
- headingChangeRate = -30;
+
+ // Only update the target values when we're not moving because otherwise we might introduce an enormous target change rate while waiting a the gate, or holding.
+ if (speed != 0) {
+ if (headingDiff > 30.0) {
+ // invert if pushed backward
+ headingChangeRate += 10.0 * dt * sign(roll);
+
+ // Clamp the maximum steering rate to 30 degrees per second,
+ // But only do this when the heading error is decreasing.
+ if ((headingDiff < headingError)) {
+ if (headingChangeRate > 30)
+ headingChangeRate = 30;
+ else if (headingChangeRate < -30)
+ headingChangeRate = -30;
+ }
+ } else {
+ if (speed != 0) {
+ if (fabs(headingChangeRate) > headingDiff)
+ headingChangeRate = headingDiff*sign(roll);
+ else
+ headingChangeRate += dt * sign(roll);
+ }
}
- } else {
- if (fabs(headingChangeRate) > headingDiff)
- headingChangeRate = headingDiff*sign(roll);
- else
- headingChangeRate += dt * sign(roll);
}
-
- hdg += headingChangeRate * dt * (fabs(speed) / 15);
+ if (trafficRef)
+ //cerr << trafficRef->getCallSign() << " Heading "
+ // << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << "Heading change rate : " << headingChangeRate << " bacnk sence " << bank_sense << endl;
+ hdg += headingChangeRate * dt * sqrt(fabs(speed) / 15);
headingError = headingDiff;
} else {
if (fabs(speed) > 1.0) {
void FGAIAircraft::handleATCRequests() {
//TODO implement NullController for having no ATC to save the conditionals
if (controller) {
- controller->update(getID(),
- pos.getLatitudeDeg(),
- pos.getLongitudeDeg(),
- hdg,
- speed,
- altitude_ft, dt);
+ controller->updateAircraftInformation(getID(),
+ pos.getLatitudeDeg(),
+ pos.getLongitudeDeg(),
+ hdg,
+ speed,
+ altitude_ft, dt);
processATC(controller->getInstruction(getID()));
}
}
void setTaxiClearanceRequest(bool arg) { needsTaxiClearance = arg; };
bool getTaxiClearanceRequest() { return needsTaxiClearance; };
FGAISchedule * getTrafficRef() { return trafficRef; };
+ void setTrafficRef(FGAISchedule *ref) { trafficRef = ref; };
virtual const char* getTypeString(void) const { return "aircraft"; }
std::string atGate();
void checkTcas();
+
+ FGATCController * getATCController() { return controller; };
protected:
void Run(double dt);
SGPropertyNode *prop_root);
static bool _isNight();
+
+ string & getCallSign();
};
inline void FGAIBase::setManager(FGAIManager* mgr, SGPropertyNode* p) {
inline void FGAIBase::setCallSign(const string& s) {
_callsign = s;
}
+inline string& FGAIBase::getCallSign() {
+ return _callsign;
+}
+
inline void FGAIBase::setXoffset(double x) {
_x_offset = x;
}
-// FGAIFlightPlan - class for loading and storing AI flight plans
+// // FGAIFlightPlan - class for loading and storing AI flight plans
// Written by David Culp, started May 2004
// - davidculp2@comcast.net
//
{
sid = 0;
wpt_iterator = waypoints.begin();
+ isValid = true;
}
FGAIFlightPlan::FGAIFlightPlan(const string& filename)
}
wpt_iterator = waypoints.begin();
+ isValid = true;
//cout << waypoints.size() << " waypoints read." << endl;
}
path.append( p );
SGPropertyNode root;
-
+ isValid = true;
// This is a bit of a hack:
// Normally the value of course will be used to evaluate whether
// or not a waypoint will be used for midair initialization of
SG_LOG(SG_GENERAL, SG_INFO, "Route from " << dep->getId() << " to " << arr->getId() << ". Set leg to : " << leg << " " << ac->getTrafficRef()->getCallSign());
wpt_iterator = waypoints.begin();
bool dist = 0;
- create(ac, dep,arr, leg, alt, speed, lat, lon,
+ isValid = create(ac, dep,arr, leg, alt, speed, lat, lon,
firstLeg, radius, fltType, acType, airline, dist);
wpt_iterator = waypoints.begin();
//cerr << "after create: " << (*wpt_iterator)->name << endl;
-// FGAIFlightPlan - class for loading and storing AI flight plans
+// // FGAIFlightPlan - class for loading and storing AI flight plans
// Written by David Culp, started May 2004
// - davidculp2@comcast.net
//
time_t getStartTime() const { return start_time; }
time_t getArrivalTime() const { return arrivalTime; }
- void create(FGAIAircraft *, FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
+ bool create(FGAIAircraft *, FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
bool firstLeg, double radius, const std::string& fltType, const std::string& aircraftType, const std::string& airline, double distance);
+ bool createPushBack(FGAIAircraft *, bool, FGAirport*, double, double, double, const std::string&, const std::string&, const std::string&);
+ bool createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const std::string&);
void setLeg(int val) { leg = val;}
void setTime(time_t st) { start_time = st; }
int getGate() const { return gateId; }
+ void setGate(int id) { gateId = id; };
+
double getLeadInAngle() const { return leadInAngle; }
const std::string& getRunway() const;
std::string activeRunway;
FGTaxiRoute *taxiRoute;
std::string name;
+ bool isValid;
- void createPushBack(FGAIAircraft *, bool, FGAirport*, double, double, double, const std::string&, const std::string&, const std::string&);
void createPushBackFallBack(FGAIAircraft *, bool, FGAirport*, double, double, double, const std::string&, const std::string&, const std::string&);
- void createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const std::string&);
- void createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const std::string&);
- void createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const std::string&);
- void createDescent(FGAIAircraft *, FGAirport *, double latitude, double longitude, double speed, double alt,const std::string&, double distance);
- void createLanding(FGAIAircraft *, FGAirport *, const std::string&);
- void createParking(FGAIAircraft *, FGAirport *, double radius);
+ bool createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const std::string&);
+ bool createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const std::string&);
+ bool createDescent(FGAIAircraft *, FGAirport *, double latitude, double longitude, double speed, double alt,const std::string&, double distance);
+ bool createLanding(FGAIAircraft *, FGAirport *, const std::string&);
+ bool createParking(FGAIAircraft *, FGAirport *, double radius);
void deleteWaypoints();
void resetWaypoints();
- void createLandingTaxi(FGAIAircraft *, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
+ bool createLandingTaxi(FGAIAircraft *, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport);
void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
- void createTakeoffTaxi(FGAIAircraft *, bool firstFlight, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
+ bool createTakeoffTaxi(FGAIAircraft *, bool firstFlight, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
double getTurnRadius(double, bool);
public:
wpt_vector_iterator getFirstWayPoint() { return waypoints.begin(); };
wpt_vector_iterator getLastWayPoint() { return waypoints.end(); };
-
+ bool isValidPlan() { return isValid; };
};
#endif // _FG_AIFLIGHTPLAN_HXX
// Check lat/lon values during initialization;
-void FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
+bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
FGAirport * arr, int legNr, double alt,
double speed, double latitude,
double longitude, bool firstFlight,
const string & aircraftType,
const string & airline, double distance)
{
+ bool retVal = true;
int currWpt = wpt_iterator - waypoints.begin();
switch (legNr) {
case 1:
- createPushBack(ac, firstFlight, dep, latitude, longitude,
- radius, fltType, aircraftType, airline);
+ retVal = createPushBack(ac, firstFlight, dep, latitude, longitude,
+ radius, fltType, aircraftType, airline);
break;
case 2:
- createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
+ retVal = createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
aircraftType, airline);
break;
case 3:
- createTakeOff(ac, firstFlight, dep, speed, fltType);
+ retVal = createTakeOff(ac, firstFlight, dep, speed, fltType);
break;
case 4:
- createClimb(ac, firstFlight, dep, speed, alt, fltType);
+ retVal = createClimb(ac, firstFlight, dep, speed, alt, fltType);
break;
case 5:
- createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
+ retVal = createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
alt, fltType);
break;
case 6:
- createDescent(ac, arr, latitude, longitude, speed, alt, fltType,
+ retVal = createDescent(ac, arr, latitude, longitude, speed, alt, fltType,
distance);
break;
case 7:
- createLanding(ac, arr, fltType);
+ retVal = createLanding(ac, arr, fltType);
break;
case 8:
- createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
+ retVal = createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
break;
case 9:
- createParking(ac, arr, radius);
+ retVal = createParking(ac, arr, radius);
break;
default:
//exit(1);
}
wpt_iterator = waypoints.begin() + currWpt;
leg++;
+ return retVal;
}
FGAIFlightPlan::waypoint *
waypoints.push_back(wpt);
}
-void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
+bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
FGAirport * apt,
double radius,
const string & fltType,
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
if (!gn->exists()) {
createDefaultTakeoffTaxi(ac, apt, rwy);
- return;
+ return true;
}
intVec ids;
if (taxiRoute->empty()) {
createDefaultTakeoffTaxi(ac, apt, rwy);
- return;
+ return true;
}
taxiRoute->first();
wpt->routeIndex = route;
waypoints.push_back(wpt);
}
+ return true;
}
void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
waypoints.push_back(wpt);
}
-void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
+bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
double radius,
const string & fltType,
const string & acType,
// Find a route from runway end to parking/gate.
if (!gn->exists()) {
createDefaultLandingTaxi(ac, apt);
- return;
+ return true;
}
intVec ids;
if (taxiRoute->empty()) {
createDefaultLandingTaxi(ac, apt);
- return;
+ return true;
}
int node;
wpt->routeIndex = route;
waypoints.push_back(wpt);
}
+ return true;
}
/*******************************************************************
* more likely however.
*
******************************************************************/
-void FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
+bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
FGAirport * apt, double speed,
const string & fltType)
{
wpt = cloneWithPos(ac, wpt, "5000 ft", pt);
wpt->altitude = airportElev + 5000;
waypoints.push_back(wpt);
+ return true;
}
/*******************************************************************
* CreateClimb
* initialize the Aircraft at the parking location
******************************************************************/
-void FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
+bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
FGAirport * apt, double speed, double alt,
const string & fltType)
{
wpt->altitude = 18000;
waypoints.push_back(wpt);
}
+ return true;
}
* Generate a flight path from the last waypoint of the cruise to
* the permission to land point
******************************************************************/
-void FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
+bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
double latitude, double longitude,
double speed, double alt,
const string & fltType,
//cerr << "Repositioning to waypoint " << (*waypoints.begin())->name << endl;
ac->resetPositionFromFlightPlan();
}
-
-
+ return true;
}
/*******************************************************************
hardcoded at 5000 meters from the threshold) to the threshold, at
a standard glide slope angle of 3 degrees.
******************************************************************/
-void FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
+bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
const string & fltType)
{
double vTouchdown = ac->getPerformance()->vTouchdown();
wpt->crossat = apt->getElevation();
waypoints.push_back(wpt);
*/
+ return true;
}
/*******************************************************************
* CreateParking
* initialize the Aircraft at the parking location
******************************************************************/
-void FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
+bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
double radius)
{
waypoint *wpt;
createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev,
vTaxiReduced);
waypoints.push_back(wpt);
+ return true;
}
/**
* Note that this is the original version that does not
* do any dynamic route computation.
******************************************************************/
-void FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport *dep,
+bool FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport *dep,
FGAirport *arr, double latitude,
double longitude, double speed,
double alt, const string& fltType)
// TODO: Use James Turner's createOnGround functions.
-void FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
+bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
bool firstFlight, FGAirport *dep,
double latitude,
double longitude,
" of flight type " << fltType <<
" of airline " << airline <<
" at airport " << dep->getId());
+ return false;
char buffer[10];
snprintf (buffer, 10, "%d", gateId);
//FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
if (gateId < 0) {
createPushBackFallBack(ac, firstFlight, dep, latitude, longitude,
radius, fltType, aircraftType, airline);
- return;
+ return true;
}
//cerr << "getting parking " << gateId;
// cerr << "Waypoint Name: " << (*i)->name << endl;
//}
} else {
+ /*
+ string rwyClass = getRunwayClassFromTrafficType(fltType);
+
+ // Only set this if it hasn't been set by ATC already.
+ if (activeRunway.empty()) {
+ //cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
+ double depHeading = ac->getTrafficRef()->getCourse();
+ dep->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+ depHeading);
+ }
+ rwy = dep->getRunwayByIdent(activeRunway);
+ SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
+
+ FGGroundNetwork *gn = dep->getDynamics()->getGroundNetwork();
+ if (!gn->exists()) {
+ createDefaultTakeoffTaxi(ac, dep, rwy);
+ return true;
+ }
+ int runwayId = gn->findNearestNode(runwayTakeoff);
+ int node = 0;
+ // Find out which node to start from
+ FGParking *park = dep->getDynamics()->getParking(gateId);
+ if (park) {
+ node = park->getPushBackPoint();
+ }
+
+ if (node == -1) {
+ node = gateId;
+ }
+ // HAndle case where parking doens't have a node
+ if ((node == 0) && park) {
+ if (firstFlight) {
+ node = gateId;
+ } else {
+ node = gateId;
+ }
+ }
+ //delete taxiRoute;
+ //taxiRoute = new FGTaxiRoute;
+ FGTaxiRoute tr = gn->findShortestRoute(node, runwayId);
+ int route;
+ FGTaxiNode *tn;
+ waypoint *wpt;
+ int nr = 0;
+ cerr << "Creating taxiroute from gate: " << gateId << " at " << dep->getId() << endl;
+ while (tr.next(&node, &route) && (nr++ < 3)) {
+ char buffer[10];
+ snprintf(buffer, 10, "%d", node);
+ tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
+ wpt = createOnGround(ac, buffer, tn->getGeod(), dep->getElevation(),
+ vTaxiReduced);
+ wpt->routeIndex = route;
+ waypoints.push_back(wpt);
+ }
+ wpt->name = "PushBackPoint";
+ lastNodeVisited = tn->getIndex();
+ //FGTaxiNode *firstNode = findNode(gateId);
+ //FGTaxiNode *lastNode = findNode(runwayId);
//cerr << "Creating direct forward departure route fragment" << endl;
+ */
double lat2 = 0.0, lon2 = 0.0, az2 = 0.0;
waypoint *wpt;
geo_direct_wgs_84 ( 0, lat, lon, heading,
wpt->on_ground = true;
wpt->routeIndex = (*ts)->getIndex();
waypoints.push_back(wpt);
-
-
}
}
+ return true;
}
/*******************************************************************
* createPushBackFallBack
include(FlightGearComponent)
set(SOURCES
+ atc_mgr.cxx
trafficcontrol.cxx
CommStation.cxx
)
noinst_LIBRARIES = libATC.a
libATC_a_SOURCES = \
- CommStation.cxx CommStation.hxx \
+ atcdialog.cxx atcdialog.hxx \
+ atc_mgr.cxx atc_mgr.hxx \
+ CommStation.cxx CommStation.hxx \
trafficcontrol.cxx trafficcontrol.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
--- /dev/null
+/******************************************************************************
+ * atc_mgr.cxx
+ * Written by Durk Talsma, started August 1, 2010.
+ *
+ * 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.
+ *
+ *
+ **************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <iostream>
+
+#include <simgear/math/SGMath.hxx>
+#include <Airports/dynamics.hxx>
+#include <Airports/simple.hxx>
+#include <Scenery/scenery.hxx>
+#include "atc_mgr.hxx"
+
+
+FGATCManager::FGATCManager() {
+
+}
+
+FGATCManager::~FGATCManager() {
+
+}
+
+void FGATCManager::init() {
+ SGSubsystem::init();
+ currentATCDialog = new FGATCDialogNew;
+ currentATCDialog->init();
+
+ int leg = 0;
+
+ // find a reasonable controller for our user's aircraft..
+ // Let's start by working out the following three scenarios:
+ // Starting on ground at a parking position
+ // Starting on ground at the runway.
+ // Starting in the Air
+ bool onGround = fgGetBool("/sim/presets/onground");
+ string runway = fgGetString("/sim/atc/runway");
+ string airport = fgGetString("/sim/presets/airport-id");
+ string parking = fgGetString("/sim/presets/parkpos");
+
+
+ // Create an (invisible) AIAircraft represenation of the current
+ // Users, aircraft, that mimicks the user aircraft's behavior.
+ string callsign= fgGetString("/sim/multiplay/callsign");
+ double longitude = fgGetDouble("/position/longitude-deg");
+ double latitude = fgGetDouble("/position/latitude-deg");
+ double altitude = fgGetDouble("/position/altitude-ft");
+ double heading = fgGetDouble("/orientation/heading-deg");
+ double speed = fgGetDouble("/velocities/groundspeed-kt");
+ double aircraftRadius = 40; // note that this is currently hardcoded to a one-size-fits all JumboJet value. Should change later;
+
+
+ ai_ac.setCallSign ( callsign );
+ ai_ac.setLongitude( longitude );
+ ai_ac.setLatitude ( latitude );
+ ai_ac.setAltitude ( altitude );
+ ai_ac.setPerformance("jet_transport");
+
+ // NEXT UP: Create a traffic Schedule and fill that with appropriate information. This we can use to flight plannign.
+ FGAISchedule *trafficRef = new FGAISchedule;
+ trafficRef->setFlightType("gate");
+
+ FGScheduledFlight *flight = new FGScheduledFlight;
+ flight->setDepartureAirport(airport);
+ flight->setArrivalAirport(airport);
+ flight->initializeAirports();
+ flight->setFlightRules("IFR");
+ flight->setCallSign(callsign);
+
+ trafficRef->assign(flight);
+ FGAIFlightPlan *fp = new FGAIFlightPlan;
+ ai_ac.setTrafficRef(trafficRef);
+
+ string flightPlanName = airport + "-" + airport + ".xml";
+ double cruiseAlt = 100; // Doesn't really matter right now.
+ double courseToDest = 180; // Just use something neutral; this value might affect the runway that is used though...
+ time_t deptime = 0; // just make sure how flightplan processing is affected by this...
+
+
+ FGAirport *apt = FGAirport::findByIdent(airport);
+ FGAirportDynamics* dcs = apt->getDynamics();
+ int park_index = dcs->getNrOfParkings() - 1;
+ cerr << "found information: " << runway << " " << airport << ": parking = " << parking << endl;
+ if (onGround) {
+ while (park_index >= 0 && dcs->getParkingName(park_index) != parking) park_index--;
+ if (park_index < 0) {
+ SG_LOG( SG_GENERAL, SG_ALERT,
+ "Failed to find parking position " << parking <<
+ " at airport " << airport );
+ }
+ if (parking.empty() || (park_index < 0)) {
+ controller = apt->getDynamics()->getTowerController();
+ int stationFreq = apt->getDynamics()->getTowerFrequency(2);
+ cerr << "Setting radio frequency to in airfrequency: " << stationFreq << endl;
+ fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
+ leg = 4;
+ string fltType = "ga";
+ fp->createTakeOff(&ai_ac, false, apt, 0, fltType);
+ } else {
+ controller = apt->getDynamics()->getStartupController();
+ int stationFreq = apt->getDynamics()->getGroundFrequency(2);
+ cerr << "Setting radio frequency to : " << stationFreq << endl;
+ fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
+ leg = 2;
+ //double, lat, lon, head; // Unused variables;
+ //int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head);
+ FGParking* parking = dcs->getParking(park_index);
+ aircraftRadius = parking->getRadius();
+ string fltType = parking->getType(); // gate / ramp, ga, etc etc.
+ string aircraftType; // Unused.
+ string airline; // Currently used for gate selection, but a fallback mechanism will apply when not specified.
+ fp->setGate(park_index);
+ fp->createPushBack(&ai_ac,
+ false,
+ apt,
+ latitude,
+ longitude,
+ aircraftRadius,
+ fltType,
+ aircraftType,
+ airline);
+ }
+ } else {
+ controller = 0;
+ }
+
+ // Create an initial flightplan and assign it to the ai_ac. We won't use this flightplan, but it is necessary to
+ // keep the ATC code happy.
+
+
+ fp->restart();
+ fp->setLeg(leg);
+ ai_ac.SetFlightPlan(fp);
+ if (controller) {
+ controller->announcePosition(ai_ac.getID(), fp, fp->getCurrentWaypoint()->routeIndex,
+ ai_ac._getLatitude(), ai_ac._getLongitude(), heading, speed, altitude,
+ aircraftRadius, leg, &ai_ac);
+
+ //dialog.init();
+
+ //osg::Node* node = apt->getDynamics()->getGroundNetwork()->getRenderNode();
+ //cerr << "Adding groundnetWork to the scenegraph::init" << endl;
+ //globals->get_scenery()->get_scene_graph()->addChild(node);
+ }
+}
+
+void FGATCManager::addController(FGATCController *controller) {
+ activeStations.push_back(controller);
+}
+
+void FGATCManager::update ( double time ) {
+ //cerr << "ATC update code is running at time: " << time << endl;
+ // Test code: let my virtual co-pilot handle ATC:
+
+
+
+ FGAIFlightPlan *fp = ai_ac.GetFlightPlan();
+
+ /* test code : find out how the routing develops */
+ int size = fp->getNrOfWayPoints();
+ //cerr << "Setting pos" << pos << " ";
+ cerr << "setting intentions " ;
+ for (int i = 0; i < size; i++) {
+ int val = fp->getRouteIndex(i);
+ cerr << val << " ";
+ //if ((val) && (val != pos)) {
+ //intentions.push_back(val);
+ //cerr << "[done ] " << endl;
+ //}
+ }
+ cerr << "[done ] " << endl;
+ double longitude = fgGetDouble("/position/longitude-deg");
+ double latitude = fgGetDouble("/position/latitude-deg");
+ double heading = fgGetDouble("/orientation/heading-deg");
+ double speed = fgGetDouble("/velocities/groundspeed-kt");
+ double altitude = fgGetDouble("/position/altitude-ft");
+ ai_ac.setLatitude(latitude);
+ ai_ac.setLongitude(longitude);
+ ai_ac.setAltitude(altitude);
+ ai_ac.setHeading(heading);
+ ai_ac.setSpeed(speed);
+ ai_ac.update(time);
+ controller = ai_ac.getATCController();
+ currentATCDialog->update(time);
+ if (controller) {
+
+
+ //cerr << "Running FGATCManager::update()" << endl;
+ controller->updateAircraftInformation(ai_ac.getID(),
+ latitude,
+ longitude,
+ heading,
+ speed,
+ altitude, time);
+ //string airport = fgGetString("/sim/presets/airport-id");
+ //FGAirport *apt = FGAirport::findByIdent(airport);
+ // AT this stage we should update the flightplan, so that waypoint incrementing is conducted as well as leg loading.
+
+ controller->render();
+
+ //cerr << "Adding groundnetWork to the scenegraph::update" << endl;
+ }
+ //globals->get_scenery()->get_scene_graph()->addChild(node);
+}
--- /dev/null
+/* -*- Mode: C++ -*- *****************************************************
+ * atic.hxx
+ * Written by Durk Talsma. Started August 1, 2010; based on earlier work
+ * by David C. Luff
+ *
+ * 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.
+ *
+ *
+ **************************************************************************/
+
+/**************************************************************************
+ * The ATC Manager interfaces the users aircraft with the AI traffic system
+ * and also monitors the ongoing AI traffic patterns for potential conflicts
+ * and interferes where necessary.
+ *************************************************************************/
+
+#ifndef _ATC_MGR_HXX_
+#define _ATC_MGR_HXX_
+
+//#include <simgear/structure/SGReferenced.hxx>
+//#include <simgear/structure/SGSharedPtr.hxx>
+#include <simgear/structure/subsystem_mgr.hxx>
+
+
+#include <ATC/trafficcontrol.hxx>
+#include <ATC/atcdialog.hxx>
+
+#include <AIModel/AIAircraft.hxx>
+//class FGATCController;
+
+
+typedef vector<FGATCController*> AtcVec;
+typedef vector<FGATCController*>::iterator AtcVecIterator;
+
+class FGATCManager : public SGSubsystem
+{
+private:
+ AtcVec activeStations;
+ FGAIAircraft ai_ac;
+ FGATCController *controller; // The ATC controller that is responsible for the user's aircraft.
+ //FGATCDialogNew dialog; // note that this variable should really replace the ugly global "currentATCDialog();
+
+public:
+ FGATCManager();
+ ~FGATCManager();
+ void init();
+ void addController(FGATCController *controller);
+ void update(double time);
+ FGATCDialogNew * getATCDialog() { return currentATCDialog; };
+};
+
+#endif // _ATC_MRG_HXX_
\ No newline at end of file
--- /dev/null
+// atcdialog.cxx - classes to manage user interactions with AI traffic
+// Written by Durk Talsma, started April 3, 2011
+// Based on earlier code written by Alexander Kappes and David Luff
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+#include <Main/fg_commands.hxx>
+#include <Main/globals.hxx>
+
+#include <simgear/constants.h>
+#include <simgear/structure/commands.hxx>
+#include <simgear/compiler.h>
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
+
+#include "atcdialog.hxx"
+
+FGATCDialogNew *currentATCDialog;
+
+static bool doATCDialog(const SGPropertyNode* arg) {
+ cerr << "Running doATCDialog" << endl;
+ currentATCDialog->PopupDialog();
+ return(true);
+}
+
+FGATCDialogNew::FGATCDialogNew()
+{
+ dialogVisible = false;
+}
+
+FGATCDialogNew::~FGATCDialogNew()
+{
+}
+
+
+
+void FGATCDialogNew::init() {
+ // Add ATC-dialog to the command list
+ globals->get_commands()->addCommand("ATC-dialog", doATCDialog);
+ // Add ATC-freq-search to the command list
+ //globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
+
+ // initialize properties polled in Update()
+ //globals->get_props()->setStringValue("/sim/atc/freq-airport", "");
+ globals->get_props()->setIntValue("/sim/atc/transmission-num", -1);
+}
+
+
+
+// Display the ATC popup dialog box with options relevant to the users current situation.
+//
+// So, the first thing we need to do is check the frequency that our pilot's nav radio
+// is currently tuned to. The dialog should always contain an option to to tune the
+// to a particular frequency,
+
+// Okay, let's see, according to my interpretation of David Luff's original code,
+// his ATC subsystem wrote properties to a named node, called "transmission-choice"
+
+static SGPropertyNode *getNamedNode(SGPropertyNode *prop, const char *name) {
+ SGPropertyNode* p;
+
+ for (int i = 0; i < prop->nChildren(); i++)
+ if ((p = getNamedNode(prop->getChild(i), name)))
+ return p;
+
+ if (!strcmp(prop->getStringValue("name"), name))
+ return prop;
+ return 0;
+}
+
+void FGATCDialogNew::addEntry(int nr, string txt) {
+ commands.clear();
+ commands.push_back(txt);
+}
+
+void FGATCDialogNew::removeEntry(int nr) {
+ commands.clear();
+}
+
+
+
+void FGATCDialogNew::PopupDialog() {
+ /*double onBoardRadioFreq0 =
+ fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+ double onBoardRadioFreq1 =
+ fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+
+ const char *dialog_name = "atc-dialog";
+ _gui = (NewGUI *)globals->get_subsystem("gui");
+ SGPropertyNode_ptr dlg = _gui->getDialogProperties(dialog_name);
+ if (!dlg)
+ return;
+
+ _gui->closeDialog(dialog_name);
+ SGPropertyNode_ptr button_group = getNamedNode(dlg, "transmission-choice");
+ button_group->removeChildren("button", false);
+
+ const int bufsize = 32;
+ char buf[bufsize];
+ int commandNr = 0;
+ // loop over all entries that should fill up the dialog; use 10 items for now...
+ for (StringVecIterator i = commands.begin(); i != commands.end(); i++) {
+ snprintf(buf, bufsize, "/sim/atc/opt[%d]", commandNr);
+ fgSetBool(buf, false);
+ SGPropertyNode *entry = button_group->getNode("button", commandNr, true);
+ copyProperties(button_group->getNode("button-template", true), entry);
+ entry->removeChildren("enabled", true);
+ entry->setStringValue("property", buf);
+ entry->setIntValue("keynum", '1' + commandNr);
+ if (commandNr == 0)
+ entry->setBoolValue("default", true);
+
+ snprintf(buf, bufsize, "%d", 1 + commandNr);
+ string legend = string(buf) + (*i); //"; // + current->menuentry;
+ entry->setStringValue("legend", legend.c_str());
+ entry->setIntValue("binding/value", commandNr);
+ commandNr++;
+ //current++;
+ }
+*/
+ //if (dialogVisible) {
+ // _gui->closeDialog(dialog_name);
+ //} else {
+ // _gui->showDialog(dialog_name);
+ //}
+ dialogVisible = !dialogVisible;
+ return;
+}
+
+void FGATCDialogNew::update(double dt) {
+ double onBoardRadioFreq0 =
+ fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+ double onBoardRadioFreq1 =
+ fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+
+ const char *dialog_name = "atc-dialog";
+ _gui = (NewGUI *)globals->get_subsystem("gui");
+ SGPropertyNode_ptr dlg = _gui->getDialogProperties(dialog_name);
+ if (!dlg)
+ return;
+
+ _gui->closeDialog(dialog_name);
+ SGPropertyNode_ptr button_group = getNamedNode(dlg, "transmission-choice");
+ button_group->removeChildren("button", false);
+
+ const int bufsize = 32;
+ char buf[bufsize];
+ int commandNr = 0;
+ // loop over all entries that should fill up the dialog; use 10 items for now...
+ for (StringVecIterator i = commands.begin(); i != commands.end(); i++) {
+ snprintf(buf, bufsize, "/sim/atc/opt[%d]", commandNr);
+ fgSetBool(buf, false);
+ SGPropertyNode *entry = button_group->getNode("button", commandNr, true);
+ copyProperties(button_group->getNode("button-template", true), entry);
+ entry->removeChildren("enabled", true);
+ entry->setStringValue("property", buf);
+ entry->setIntValue("keynum", '1' + commandNr);
+ if (commandNr == 0)
+ entry->setBoolValue("default", true);
+
+ snprintf(buf, bufsize, "%d", 1 + commandNr);
+ string legend = string(buf) + (*i); //"; // + current->menuentry;
+ entry->setStringValue("legend", legend.c_str());
+ entry->setIntValue("binding/value", commandNr);
+ commandNr++;
+ //current++;
+ }
+
+ if (dialogVisible) {
+ _gui->closeDialog(dialog_name);
+ } else {
+ _gui->showDialog(dialog_name);
+ }
+ //dialogVisible = !dialogVisible;
+ return;
+ /*
+ static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
+ int n = trans_num->getIntValue();
+ if (n >= 0) {
+ trans_num->setIntValue(-1);
+ // PopupCallback(n);
+ cerr << "Selected transmission message" << n << endl;
+ } */
+}
\ No newline at end of file
--- /dev/null
+// atcdialog.hxx - classes to manage user interactions with AI traffic
+// Written by Durk Talsma, started April 3, 2011
+// Based on earlier code written by Alexander Kappes and David Luff
+//
+// 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 _ATC_DIALOG_HXX_
+#define _ATC_DIALOG_HXX_
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include <simgear/constants.h>
+#include <simgear/structure/commands.hxx>
+#include <simgear/compiler.h>
+#include <simgear/props/props.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
+
+
+#include <GUI/gui.h> // mkDialog
+#include <GUI/new_gui.hxx>
+
+typedef vector<string> StringVec;
+typedef vector<string>:: iterator StringVecIterator;
+
+static bool doATCDialog(const SGPropertyNode* arg);
+
+class FGATCDialogNew {
+private:
+ NewGUI *_gui;
+ bool dialogVisible;
+ StringVec commands;
+public:
+
+ FGATCDialogNew();
+ ~FGATCDialogNew();
+
+ void init();
+
+ void update(double dt);
+ void PopupDialog();
+ void addEntry(int, string);
+ void removeEntry(int);
+};
+
+extern FGATCDialogNew *currentATCDialog;
+
+#endif // _ATC_DIALOG_HXX_
\ No newline at end of file
#include <algorithm>
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
+
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/material/mat.hxx>
+#include <Scenery/scenery.hxx>
+
#include "trafficcontrol.hxx"
+#include "atc_mgr.hxx"
#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include <AIModel/performancedata.hxx>
#include <AIModel/performancedb.hxx>
+#include <ATC/atc_mgr.hxx>
#include <Traffic/TrafficMgr.hxx>
#include <Airports/groundnetwork.hxx>
#include <Airports/dynamics.hxx>
bool FGTrafficRecord::pushBackAllowed()
{
+ // With the user ATC / AI integration, checking whether the user's aircraft is near no longer works, because
+ // this will effectively block the user's aircraft itself from receiving pushback clearance.
+ // So, what can we do?
+ /*
double course, az2, dist;
SGGeod curr(SGGeod::fromDegM(getLongitude(),
getLatitude(), getAltitude()));
SGGeodesy::inverse(curr, user, course, az2, dist);
//cerr << "Distance to user : " << dist << endl;
return (dist > 250);
+ */
+
+ // In essence, we should check whether the pusbback route itself, as well as the associcated
+ // taxiways near the pushback point are free of traffic.
+ // To do so, we need to
+ return true;
}
FGATCController::FGATCController()
{
+ cerr << "running FGATController constructor" << endl;
dt_count = 0;
available = true;
lastTransmission = 0;
+ initialized = false;
+}
+
+FGATCController::~FGATCController()
+{
+ cerr << "running FGATController destructor" << endl;
}
string FGATCController::getGateName(FGAIAircraft * ref)
return ref->atGate();
}
+bool FGATCController::isUserAircraft(FGAIAircraft* ac)
+{
+ return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false;
+};
+
void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
- AtcMsgDir msgDir)
+ AtcMsgDir msgDir, bool audible)
{
string sender, receiver;
int stationFreq = 0;
text = text + sender + ". Transmitting unknown Message";
break;
}
- double onBoardRadioFreq0 =
- fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
- double onBoardRadioFreq1 =
- fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
- int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
- int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
- //cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
-
- // Display ATC message only when one of the radios is tuned
- // the relevant frequency.
- // Note that distance attenuation is currently not yet implemented
- if ((onBoardRadioFreqI0 == stationFreq)
- || (onBoardRadioFreqI1 == stationFreq)) {
- if (rec->allowTransmissions()) {
- fgSetString("/sim/messages/atc", text.c_str());
+ if (audible) {
+ double onBoardRadioFreq0 =
+ fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+ double onBoardRadioFreq1 =
+ fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+ int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
+ int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
+ //cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
+
+ // Display ATC message only when one of the radios is tuned
+ // the relevant frequency.
+ // Note that distance attenuation is currently not yet implemented
+ if ((onBoardRadioFreqI0 == stationFreq)
+ || (onBoardRadioFreqI1 == stationFreq)) {
+ if (rec->allowTransmissions()) {
+ fgSetString("/sim/messages/atc", text.c_str());
+ }
}
+ } else {
+ FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
+ atc->getATCDialog()->addEntry(1, text);
+
}
}
}
}
+void FGATCController::init()
+{
+ if (!initialized) {
+ FGATCManager *mgr = (FGATCManager*) globals->get_subsystem("ATC");
+ mgr->addController(this);
+ initialized = true;
+ }
+}
+
/***************************************************************************
* class FGTowerController
*
double radius, int leg,
FGAIAircraft * ref)
{
+ init();
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
}
}
-void FGTowerController::update(int id, double lat, double lon,
- double heading, double speed, double alt,
- double dt)
+void FGTowerController::updateAircraftInformation(int id, double lat, double lon,
+ double heading, double speed, double alt,
+ double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id has an entry
return FGATCInstruction();
}
+void FGTowerController::render() {
+ cerr << "FGTowerController::render function not yet implemented" << endl;
+}
+
+
/***************************************************************************
* class FGStartupController
*
**************************************************************************/
-FGStartupController::FGStartupController():
-FGATCController()
+FGStartupController::FGStartupController(FGAirportDynamics *par):
+ FGATCController()
{
+ parent = par;
}
void FGStartupController::announcePosition(int id,
double radius, int leg,
FGAIAircraft * ref)
{
+ init();
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
rec.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRunway(intendedRoute->getRunway());
rec.setLeg(leg);
+ rec.setPositionAndIntentions(currentPosition, intendedRoute);
//rec.setCallSign(callsign);
rec.setAircraft(ref);
rec.setHoldPosition(true);
activeTraffic.push_back(rec);
} else {
+ i->setPositionAndIntentions(currentPosition, intendedRoute);
i->setPositionAndHeading(lat, lon, heading, speed, alt);
}
SG_LOG(SG_GENERAL, SG_ALERT,
"AI error: Aircraft without traffic record is signing off from tower");
} else {
+ cerr << i->getAircraft()->getCallSign() << " signing off from startupcontroller" << endl;
i = activeTraffic.erase(i);
}
}
-void FGStartupController::update(int id, double lat, double lon,
- double heading, double speed, double alt,
- double dt)
+bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
+ AtcMsgDir msgDir)
+{
+ int state = i->getState();
+ if ((state == st) && available) {
+ if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
+
+ cerr << "Checking state " << st << " for " << i->getAircraft()->getCallSign() << endl;
+ static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
+ int n = trans_num->getIntValue();
+ if (n >= 0) {
+ trans_num->setIntValue(-1);
+ // PopupCallback(n);
+ cerr << "Selected transmission message" << n << endl;
+ FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
+ atc->getATCDialog()->removeEntry(1);
+ } else {
+ cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
+ transmit(&(*i), msgId, msgDir, false);
+ return false;
+ }
+ }
+ if (now > startTime) {
+ //cerr << "Transmitting startup msg" << endl;
+ transmit(&(*i), msgId, msgDir, true);
+ i->updateState();
+ lastTransmission = now;
+ available = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+void FGStartupController::updateAircraftInformation(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
}
}
// // 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");
setDt(getDt() + dt);
int state = i->getState();
- time_t startTime =
- i->getAircraft()->getTrafficRef()->getDepartureTime();
+
+ // The user controlled aircraft should have crased here, because it doesn't have a traffic reference.
+ // NOTE: if we create a traffic schedule for the user aircraft, we can use this to plan a flight.
+ time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
//cerr << i->getAircraft()->getTrafficRef()->getCallSign()
// << " is scheduled to depart in " << startTime-now << " seconds. Available = " << available
available = true;
}
- if ((state == 0) && available) {
- if (now > startTime) {
- //cerr << "Transmitting startup msg" << endl;
- 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;
- }
- }
- // Note: The next four stages are only necessesary when Startup control is
- // on a different frequency, compared to ground control
- if ((state == 4) && available) {
- if (now > startTime + 130) {
- transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
- ATC_AIR_TO_GROUND);
- i->updateState();
- i->nextFrequency();
- lastTransmission = now;
- available = false;
- }
- }
- if ((state == 5) && available) {
- if (now > startTime + 140) {
- transmit(&(*i), MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
- }
- if ((state == 6) && available) {
- if (now > startTime + 150) {
- transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT,
- ATC_GROUND_TO_AIR);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
+ checkTransmissionState(0, now, (startTime + 0 ), i, MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
+ checkTransmissionState(1, now, (startTime + 60 ), i, MSG_REQUEST_ENGINE_START, ATC_AIR_TO_GROUND);
+ checkTransmissionState(2, now, (startTime + 80 ), i, MSG_PERMIT_ENGINE_START, ATC_GROUND_TO_AIR);
+ checkTransmissionState(3, now, (startTime + 100), i, MSG_ACKNOWLEDGE_ENGINE_START, ATC_AIR_TO_GROUND);
+ if (checkTransmissionState(4, now, (startTime + 130), i, MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY, ATC_AIR_TO_GROUND)) {
+ i->nextFrequency();
}
+ checkTransmissionState(5, now, (startTime + 140), i, MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND);
+ checkTransmissionState(6, now, (startTime + 150), i, MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR);
+ checkTransmissionState(7, now, (startTime + 180), i, MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
- // TODO: Switch to APRON control and request pushback Clearance.
- // Get Push back clearance
- if ((state == 7) && available) {
- if (now > startTime + 180) {
- transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE,
- ATC_AIR_TO_GROUND);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
- }
+
+
if ((state == 8) && available) {
if (now > startTime + 200) {
if (i->pushBackAllowed()) {
i->allowRepeatedTransmissions();
transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE,
- ATC_GROUND_TO_AIR);
+ ATC_GROUND_TO_AIR, true);
i->updateState();
} else {
transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE,
- ATC_GROUND_TO_AIR);
+ ATC_GROUND_TO_AIR, true);
i->suppressRepeatedTransmissions();
}
lastTransmission = now;
}
}
+// Note that this function is copied from simgear. for maintanance purposes, it's probabtl better to make a general function out of that.
+static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
+ double lon, double elev, double hdg)
+{
+ SGGeod geod = SGGeod::fromDegM(lon, lat, elev);
+ obj_pos = geod.makeZUpFrame();
+ // hdg is not a compass heading, but a counter-clockwise rotation
+ // around the Z axis
+ obj_pos.preMult(osg::Matrix::rotate(hdg * SGD_DEGREES_TO_RADIANS,
+ 0.0, 0.0, 1.0));
+}
+
+
+void FGStartupController::render()
+{
+
+ SGMaterialLib *matlib = globals->get_matlib();
+ if (group) {
+ //int nr = ;
+ globals->get_scenery()->get_scene_graph()->removeChild(group);
+ //while (group->getNumChildren()) {
+ // cerr << "Number of children: " << group->getNumChildren() << endl;
+ simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
+ //osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
+ //geode->releaseGLObjects();
+ //group->removeChild(geode);
+ //delete geode;
+ }
+ group = new osg::Group;
+
+ //for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) {
+ double dx = 0;
+ for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
+ // Handle start point
+ int pos = i->getCurrentPosition();
+ //cerr << "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos << endl;
+ if (pos > 0) {
+ FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(pos);
+ SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
+ SGGeod end (SGGeod::fromDeg(segment->getEnd()->getLongitude(), segment->getEnd()->getLatitude()));
+
+ double length = SGGeodesy::distanceM(start, end);
+ //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
+
+ double az2, heading; //, distanceM;
+ SGGeodesy::inverse(start, end, heading, az2, length);
+ double coveredDistance = length * 0.5;
+ SGGeod center;
+ SGGeodesy::direct(start, heading, coveredDistance, center, az2);
+ //cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
+ ///////////////////////////////////////////////////////////////////////////////
+ // Make a helper function out of this
+ osg::Matrix obj_pos;
+ osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+ obj_trans->setDataVariance(osg::Object::STATIC);
+
+ WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), parent->getElevation()+8+dx, -(heading) );
+
+ obj_trans->setMatrix( obj_pos );
+ //osg::Vec3 center(0, 0, 0)
+
+ float width = length /2.0;
+ osg::Vec3 corner(-width, 0, 0.25f);
+ osg::Vec3 widthVec(2*width + 1, 0, 0);
+ osg::Vec3 heightVec(0, 1, 0);
+ osg::Geometry* geometry;
+ geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
+ simgear::EffectGeode* geode = new simgear::EffectGeode;
+ geode->setName("test");
+ geode->addDrawable(geometry);
+ //osg::Node *custom_obj;
+ SGMaterial *mat = matlib->find("UnidirectionalTaper");
+ if (mat)
+ geode->setEffect(mat->get_effect());
+ obj_trans->addChild(geode);
+ // wire as much of the scene graph together as we can
+ //->addChild( obj_trans );
+ group->addChild( obj_trans );
+ /////////////////////////////////////////////////////////////////////
+ } else {
+ cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
+ }
+ for(intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
+ osg::Matrix obj_pos;
+ int k = (*j);
+ if (k > 0) {
+ //cerr << "rendering for " << i->getAircraft()->getCallSign() << "intention = " << k << endl;
+ osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+ obj_trans->setDataVariance(osg::Object::STATIC);
+ FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(k);
+ WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), parent->getElevation()+8+dx, -(segment->getHeading()) );
+
+ obj_trans->setMatrix( obj_pos );
+ //osg::Vec3 center(0, 0, 0)
+
+ float width = segment->getLength() /2.0;
+ osg::Vec3 corner(-width, 0, 0.25f);
+ osg::Vec3 widthVec(2*width + 1, 0, 0);
+ osg::Vec3 heightVec(0, 1, 0);
+ osg::Geometry* geometry;
+ geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
+ simgear::EffectGeode* geode = new simgear::EffectGeode;
+ geode->setName("test");
+ geode->addDrawable(geometry);
+ //osg::Node *custom_obj;
+ SGMaterial *mat = matlib->find("UnidirectionalTaper");
+ if (mat)
+ geode->setEffect(mat->get_effect());
+ obj_trans->addChild(geode);
+ // wire as much of the scene graph together as we can
+ //->addChild( obj_trans );
+ group->addChild( obj_trans );
+ } else {
+ cerr << "BIG FAT WARNING: k is here : " << pos << endl;
+ }
+ }
+ //dx += 0.1;
+ }
+ globals->get_scenery()->get_scene_graph()->addChild(group);
+}
+
/***************************************************************************
* class FGApproachController
double alt, double radius,
int leg, FGAIAircraft * ref)
{
+ init();
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
}
}
-void FGApproachController::update(int id, double lat, double lon,
- double heading, double speed, double alt,
- double dt)
+void FGApproachController::updateAircraftInformation(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
}
return &(*rwy);
}
+
+void FGApproachController::render() {
+ cerr << "FGApproachController::render function not yet implemented" << endl;
+}
# error This library requires C++
#endif
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
#include <simgear/compiler.h>
// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER...
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/debug/logstream.hxx>
-
-
+#include <simgear/structure/SGReferenced.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
#include <string>
#include <vector>
class FGAIFlightPlan; // forward reference
class FGGroundNetwork; // forward reference
class FGAIAircraft; // forward reference
+class FGAirportDynamics;
/**************************************************************************************
* class FGATCInstruction
void allowRepeatedTransmissions () { allowTransmission=true; };
void nextFrequency() { frequencyId++; };
int getNextFrequency() { return frequencyId; };
+ intVec& getIntentions() { return intentions; };
+ int getCurrentPosition() { return currentPos; };
};
typedef vector<FGTrafficRecord> TrafficVector;
*************************************************************************************/
class FGATCController
{
+private:
+ bool initialized;
+
protected:
bool available;
time_t lastTransmission;
double dt_count;
-
+ osg::Group* group;
string formatATCFrequency3_2(int );
string genTransponderCode(string fltRules);
+ bool isUserAircraft(FGAIAircraft*);
public:
typedef enum {
ATC_AIR_TO_GROUND,
ATC_GROUND_TO_AIR } AtcMsgDir;
FGATCController();
- virtual ~FGATCController() {};
+ virtual ~FGATCController();
+ void init();
+
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;
+ 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 void updateAircraftInformation(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);
+ void transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir, bool audible);
string getGateName(FGAIAircraft *aircraft);
+ virtual void render() = 0;
+
+private:
+
+ AtcMsgDir lastTransmissionDirection;
};
/******************************************************************************
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,
+ virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
+ virtual void render();
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
TrafficVector &getActiveTraffic() { return activeTraffic; };
};
private:
TrafficVector activeTraffic;
//ActiveRunwayVec activeRunways;
+FGAirportDynamics *parent;
public:
- FGStartupController();
+ FGStartupController(FGAirportDynamics *parent);
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,
+ virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
+ virtual void render();
+
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
TrafficVector &getActiveTraffic() { return activeTraffic; };
+ // Hpoefully, we can move this function to the base class, but I need to verify what is needed for the other controllers before doing so.
+ bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
+ AtcMsgDir msgDir);
+
};
/******************************************************************************
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,
+ virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
+ virtual void render();
+
ActiveRunway* getRunway(string name);
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
// For the command manager - maybe eventually this should go in the built in command list
static bool do_ATC_dialog(const SGPropertyNode* arg) {
+ cerr << "Running ATCDCL do_ATC_dialog" << endl;
current_atcdialog->PopupDialog();
return(true);
}
void FGATCDialog::Init() {
// Add ATC-dialog to the command list
- globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
+ //globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
// Add ATC-freq-search to the command list
- globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
+ //globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
// initialize properties polled in Update()
- globals->get_props()->setStringValue("/sim/atc/freq-airport", "");
- globals->get_props()->setIntValue("/sim/atc/transmission-num", -1);
+ //globals->get_props()->setStringValue("/sim/atc/freq-airport", "");
+ //globals->get_props()->setIntValue("/sim/atc/transmission-num", -1);
}
void FGATCDialog::Update(double dt) {
- static SGPropertyNode_ptr airport = globals->get_props()->getNode("/sim/atc/freq-airport", true);
- string s = airport->getStringValue();
- if (!s.empty()) {
- airport->setStringValue("");
- FreqDisplay(s);
- }
-
- static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
- int n = trans_num->getIntValue();
- if (n >= 0) {
- trans_num->setIntValue(-1);
- PopupCallback(n);
- }
-
- if(_callbackPending) {
- if(_callbackTimer > _callbackWait) {
- _callbackPtr->ReceiveUserCallback(_callbackCode);
- _callbackPtr->NotifyTransmissionFinished(fgGetString("/sim/user/callsign"));
- _callbackPending = false;
- } else {
- _callbackTimer += dt;
- }
- }
+ //static SGPropertyNode_ptr airport = globals->get_props()->getNode("/sim/atc/freq-airport", true);
+ //string s = airport->getStringValue();
+ //if (!s.empty()) {
+ // airport->setStringValue("");
+ // FreqDisplay(s);
+ //}
+
+ //static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
+ //int n = trans_num->getIntValue();
+ //if (n >= 0) {
+ // trans_num->setIntValue(-1);
+ // PopupCallback(n);
+ //}
+
+ //if(_callbackPending) {
+ // if(_callbackTimer > _callbackWait) {
+ // _callbackPtr->ReceiveUserCallback(_callbackCode);
+ // _callbackPtr->NotifyTransmissionFinished(fgGetString("/sim/user/callsign"));
+ // _callbackPending = false;
+ // } else {
+ // _callbackTimer += dt;
+ // }
+ //}
}
// Add an entry
#include "dynamics.hxx"
FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
-_ap(ap), rwyPrefs(ap), SIDs(ap),
+ _ap(ap), rwyPrefs(ap), SIDs(ap),
atisSequenceIndex(-1),
- atisSequenceTimeStamp(0.0)
+ atisSequenceTimeStamp(0.0),
+ startupController(this)
{
lastUpdate = 0;
}
random_shuffle(parkings.begin(), parkings.end());
sort(parkings.begin(), parkings.end());
// add the gate positions to the ground network.
+ groundNetwork.setParent(_ap);
groundNetwork.addNodes(&parkings);
groundNetwork.init();
groundNetwork.setTowerController(&towerController);
- groundNetwork.setParent(_ap);
+
}
bool FGAirportDynamics::getAvailableParking(double *lat, double *lon,
return groundFreq;
}
+int FGAirportDynamics::getTowerFrequency(unsigned nr)
+{
+ int towerFreq = 0;
+ if (nr < 2) {
+ SG_LOG(SG_ATC, SG_ALERT,
+ "Leg value is smaller than two at " << SG_ORIGIN);
+ }
+ if (freqTower.size() == 0) {
+ return 0;
+ }
+ if ((freqTower.size() > nr - 1) && (nr > 1)) {
+ towerFreq = freqTower[nr - 1];
+ }
+ if ((freqTower.size() < nr - 1) && (nr > 1)) {
+ towerFreq =
+ (freqTower.size() <
+ (nr - 1)) ? freqTower[freqTower.size() -
+ 1] : freqTower[nr - 2];
+ }
+ if ((freqTower.size() >= nr - 1) && (nr > 1)) {
+ towerFreq = freqTower[nr - 2];
+ }
+ return towerFreq;
+}
+
+
FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway,
double heading)
{
std::string chooseRunwayFallback();
bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading);
std::string chooseRwyByHeading(stringVec rwys, double heading);
+
+ double elevation;
+
public:
FGAirportDynamics(FGAirport* ap);
~FGAirportDynamics();
FGApproachController *getApproachController() { return &approachController; };
int getGroundFrequency(unsigned leg);
+ int getTowerFrequency (unsigned nr);
/// get current ATIS sequence letter
const std::string getAtisSequence();
return value;
}
-bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b) {
- return a->hasSmallerHeadingDiff(*b);
-}
+//bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b) {
+// return a->hasSmallerHeadingDiff(*b);
+//}
bool sortByLength(FGTaxiSegment *a, FGTaxiSegment *b) {
return a->getLength() > b->getLength();
/**************************************************************************
* FGTaxiNode
*************************************************************************/
-
+void FGTaxiNode::setElevation(double val)
+{
+ geod.setElevationM(val);
+}
void FGTaxiNode::setLatitude (double val)
{
geod.setLongitudeDeg(processPosition(val));
}
-void FGTaxiNode::sortEndSegments(bool byLength)
-{
- if (byLength)
- sort(next.begin(), next.end(), sortByLength);
- else
- sort(next.begin(), next.end(), sortByHeadingDiff);
-}
+//void FGTaxiNode::sortEndSegments(bool byLength)
+//{
+// if (byLength)
+// sort(next.begin(), next.end(), sortByLength);
+// else
+// sort(next.begin(), next.end(), sortByHeadingDiff);
+//}
void setIndex(int idx) { index = idx; };
void setLatitude (double val);
void setLongitude(double val);
+ void setElevation(double val);
void setLatitude (const std::string& val);
void setLongitude(const std::string& val);
void addSegment(FGTaxiSegment *segment) { next.push_back(segment); };
double getPathScore() { return pathScore; };
double getLatitude() { return geod.getLatitudeDeg();};
double getLongitude(){ return geod.getLongitudeDeg();};
+ double getElevation() { return geod.getElevationM();};
const SGGeod& getGeod() const { return geod; }
FGTaxiSegmentVectorIterator getEndRoute() { return next.end(); };
bool operator<(const FGTaxiNode &other) const { return index < other.index; };
- void sortEndSegments(bool);
+ //void sortEndSegments(bool);
};
+
// groundnet.cxx - Implimentation of the FlightGear airport ground handling code
//
// Written by Durk Talsma, started June 2005.
#include <math.h>
#include <algorithm>
+
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
+
#include <simgear/debug/logstream.hxx>
#include <simgear/route/waypoint.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/material/mat.hxx>
#include <Airports/simple.hxx>
#include <Airports/dynamics.hxx>
#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
+#include <Scenery/scenery.hxx>
+
#include "groundnetwork.hxx"
/***************************************************************************
// There is probably a computationally cheaper way of
// doing this.
-void FGTaxiSegment::setTrackDistance()
+void FGTaxiSegment::setDimensions(double elevation)
{
length = SGGeodesy::distanceM(start->getGeod(), end->getGeod());
+ //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
+
+ double az2; //, distanceM;
+ SGGeodesy::inverse(start->getGeod(), end->getGeod(), heading, az2, length);
+ double coveredDistance = length * 0.5;
+ SGGeodesy::direct(start->getGeod(), heading, coveredDistance, center, az2);
+ //cerr << "Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
}
-void FGTaxiSegment::setCourseDiff(double crse)
-{
- headingDiff = fabs(course - crse);
+//void FGTaxiSegment::setCourseDiff(double crse)
+//{
+// headingDiff = fabs(course - crse);
- if (headingDiff > 180)
- headingDiff = fabs(headingDiff - 360);
-}
+// if (headingDiff > 180)
+// headingDiff = fabs(headingDiff - 360);
+//}
/***************************************************************************
//maxDepth = 1000;
count = 0;
currTraffic = activeTraffic.begin();
+ group = 0;
}
n.setIndex(i->getIndex());
n.setLatitude(i->getLatitude());
n.setLongitude(i->getLongitude());
+ n.setElevation(parent->getElevation());
nodes.push_back(new FGTaxiNode(n));
i++;
while (i != segments.end()) {
(*i)->setStart(&nodes);
(*i)->setEnd(&nodes);
- (*i)->setTrackDistance();
+ (*i)->setDimensions(parent->getElevation());
(*i)->setIndex(index);
if ((*i)->isPushBack()) {
pushBackNodes.push_back((*i)->getEnd());
double radius, int leg,
FGAIAircraft * aircraft)
{
+ init();
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
}
}
-void FGGroundNetwork::update(int id, double lat, double lon,
- double heading, double speed, double alt,
- double dt)
+bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
+ AtcMsgDir msgDir)
+{
+ int state = i->getState();
+ if ((state >= minState) && (state <= maxState) && available) {
+ if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
+
+ cerr << "Checking state " << state << " for " << i->getAircraft()->getCallSign() << endl;
+ static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
+ int n = trans_num->getIntValue();
+ if (n >= 0) {
+ trans_num->setIntValue(-1);
+ // PopupCallback(n);
+ cerr << "Selected transmission message" << n << endl;
+ } else {
+ cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
+ transmit(&(*i), msgId, msgDir, false);
+ return false;
+ }
+ }
+ //cerr << "Transmitting startup msg" << endl;
+ transmit(&(*i), msgId, msgDir, true);
+ i->updateState();
+ lastTransmission = now;
+ available = false;
+ return true;
+ }
+ return false;
+}
+
+void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
+ double heading, double speed, double alt,
+ double dt)
{
// Check whether aircraft are on hold due to a preceding pushback. If so, make sure to
// Transmit air-to-ground "Ready to taxi request:
if ((now - lastTransmission) > 15) {
available = true;
}
- if ((state < 3) && available) {
- transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
- current->setState(3);
- lastTransmission = now;
- available = false;
+ if (checkTransmissionState(0,2, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
+ current->setState(3);
}
- if ((state == 3) && available) {
- transmit(&(*current), MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR);
+ if (checkTransmissionState(3,3, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) {
current->setState(4);
- lastTransmission = now;
- available = false;
}
- if ((state == 4) && available) {
- transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
+ if (checkTransmissionState(4,4, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
current->setState(5);
- lastTransmission = now;
- available = false;
}
if ((state == 5) && available) {
current->setState(0);
if ((origStatus != currStatus) && available) {
//cerr << "Issueing hold short instrudtion " << currStatus << " " << available << endl;
if (currStatus == true) { // No has a hold short instruction
- transmit(&(*current), MSG_HOLD_POSITION, ATC_GROUND_TO_AIR);
+ transmit(&(*current), MSG_HOLD_POSITION, ATC_GROUND_TO_AIR, true);
//cerr << "Transmittin hold short instrudtion " << currStatus << " " << available << endl;
current->setState(1);
} else {
- transmit(&(*current), MSG_RESUME_TAXI, ATC_GROUND_TO_AIR);
+ transmit(&(*current), MSG_RESUME_TAXI, ATC_GROUND_TO_AIR, true);
//cerr << "Transmittig resume instrudtion " << currStatus << " " << available << endl;
current->setState(2);
}
//cerr << "Current state " << current->getState() << endl;
} else {
}
- int state = current->getState();
- if ((state == 1) && (available)) {
+ //int state = current->getState();
+ if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) {
+ current->setState(0);
+ current->setHoldPosition(true);
+ }
+ if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) {
+ current->setState(0);
+ current->setHoldPosition(false);
+ }
+
+ /*if ((state == 1) && (available)) {
//cerr << "ACKNOWLEDGE HOLD" << endl;
- transmit(&(*current), MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND);
+ transmit(&(*current), MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND, true);
current->setState(0);
current->setHoldPosition(true);
lastTransmission = now;
}
if ((state == 2) && (available)) {
//cerr << "ACKNOWLEDGE RESUME" << endl;
- transmit(&(*current), MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND);
+ transmit(&(*current), MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND, true);
current->setState(0);
current->setHoldPosition(false);
lastTransmission = now;
available = false;
- }
-}
+ }*/
+}
/**
* Check whether situations occur where the current aircraft is waiting for itself
}
return FGATCInstruction();
}
+
+// Note that this function is copied from simgear. for maintanance purposes, it's probabtl better to make a general function out of that.
+static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
+ double lon, double elev, double hdg)
+{
+ SGGeod geod = SGGeod::fromDegM(lon, lat, elev);
+ obj_pos = geod.makeZUpFrame();
+ // hdg is not a compass heading, but a counter-clockwise rotation
+ // around the Z axis
+ obj_pos.preMult(osg::Matrix::rotate(hdg * SGD_DEGREES_TO_RADIANS,
+ 0.0, 0.0, 1.0));
+}
+
+
+
+
+void FGGroundNetwork::render()
+{
+
+ SGMaterialLib *matlib = globals->get_matlib();
+ if (group) {
+ //int nr = ;
+ globals->get_scenery()->get_scene_graph()->removeChild(group);
+ //while (group->getNumChildren()) {
+ // cerr << "Number of children: " << group->getNumChildren() << endl;
+ simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
+ //osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
+ //geode->releaseGLObjects();
+ //group->removeChild(geode);
+ //delete geode;
+ }
+ group = new osg::Group;
+
+ //for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) {
+ double dx = 0;
+ for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
+ // Handle start point
+ int pos = i->getCurrentPosition() - 1;
+ if (pos >= 0) {
+
+ SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
+ SGGeod end (SGGeod::fromDeg(segments[pos]->getEnd()->getLongitude(), segments[pos]->getEnd()->getLatitude()));
+
+ double length = SGGeodesy::distanceM(start, end);
+ //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
+
+ double az2, heading; //, distanceM;
+ SGGeodesy::inverse(start, end, heading, az2, length);
+ double coveredDistance = length * 0.5;
+ SGGeod center;
+ SGGeodesy::direct(start, heading, coveredDistance, center, az2);
+ //cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
+ ///////////////////////////////////////////////////////////////////////////////
+ // Make a helper function out of this
+ osg::Matrix obj_pos;
+ osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+ obj_trans->setDataVariance(osg::Object::STATIC);
+
+ WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), parent->elevation()+8+dx, -(heading) );
+
+ obj_trans->setMatrix( obj_pos );
+ //osg::Vec3 center(0, 0, 0)
+
+ float width = length /2.0;
+ osg::Vec3 corner(-width, 0, 0.25f);
+ osg::Vec3 widthVec(2*width + 1, 0, 0);
+ osg::Vec3 heightVec(0, 1, 0);
+ osg::Geometry* geometry;
+ geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
+ simgear::EffectGeode* geode = new simgear::EffectGeode;
+ geode->setName("test");
+ geode->addDrawable(geometry);
+ //osg::Node *custom_obj;
+ SGMaterial *mat = matlib->find("UnidirectionalTaper");
+ if (mat)
+ geode->setEffect(mat->get_effect());
+ obj_trans->addChild(geode);
+ // wire as much of the scene graph together as we can
+ //->addChild( obj_trans );
+ group->addChild( obj_trans );
+ /////////////////////////////////////////////////////////////////////
+ } else {
+ cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
+ }
+ for(intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
+ osg::Matrix obj_pos;
+ int k = (*j)-1;
+ if (k >= 0) {
+ osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+ obj_trans->setDataVariance(osg::Object::STATIC);
+
+ WorldCoordinate( obj_pos, segments[k]->getLatitude(), segments[k]->getLongitude(), parent->elevation()+8+dx, -(segments[k]->getHeading()) );
+
+ obj_trans->setMatrix( obj_pos );
+ //osg::Vec3 center(0, 0, 0)
+
+ float width = segments[k]->getLength() /2.0;
+ osg::Vec3 corner(-width, 0, 0.25f);
+ osg::Vec3 widthVec(2*width + 1, 0, 0);
+ osg::Vec3 heightVec(0, 1, 0);
+ osg::Geometry* geometry;
+ geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
+ simgear::EffectGeode* geode = new simgear::EffectGeode;
+ geode->setName("test");
+ geode->addDrawable(geometry);
+ //osg::Node *custom_obj;
+ SGMaterial *mat = matlib->find("UnidirectionalTaper");
+ if (mat)
+ geode->setEffect(mat->get_effect());
+ obj_trans->addChild(geode);
+ // wire as much of the scene graph together as we can
+ //->addChild( obj_trans );
+ group->addChild( obj_trans );
+ }
+ }
+ //dx += 0.1;
+ }
+ globals->get_scenery()->get_scene_graph()->addChild(group);
+}
\ No newline at end of file
#ifndef _GROUNDNETWORK_HXX_
#define _GROUNDNETWORK_HXX_
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
+
+
#include <simgear/compiler.h>
#include <simgear/route/waypoint.hxx>
#include "parking.hxx"
#include <ATC/trafficcontrol.hxx>
+
class FGTaxiSegment; // forward reference
class FGAIFlightPlan; // forward reference
class FGAirport; // forward reference
int startNode;
int endNode;
double length;
- double course;
- double headingDiff;
+ double heading;
+ SGGeod center;
bool isActive;
bool isPushBackRoute;
FGTaxiNode *start;
startNode(0),
endNode(0),
length(0),
- course(0),
- headingDiff(0),
+ heading(0),
isActive(0),
isPushBackRoute(0),
start(0),
startNode (other.startNode),
endNode (other.endNode),
length (other.length),
- course (other.course),
- headingDiff (other.headingDiff),
+ heading (other.heading),
+ center (other.center),
isActive (other.isActive),
isPushBackRoute (other.isPushBackRoute),
start (other.start),
startNode = other.startNode;
endNode = other.endNode;
length = other.length;
- course = other.course;
- headingDiff = other.headingDiff;
+ heading = other.heading;
+ center = other.center;
isActive = other.isActive;
isPushBackRoute = other.isPushBackRoute;
start = other.start;
void setStart(FGTaxiNodeVector *nodes);
void setEnd (FGTaxiNodeVector *nodes);
void setPushBackType(bool val) { isPushBackRoute = val; };
- void setTrackDistance();
+ void setDimensions(double elevation);
FGTaxiNode * getEnd() { return end;};
FGTaxiNode * getStart() { return start; };
double getLength() { return length; };
int getIndex() { return index; };
-
+ double getLatitude() { return center.getLatitudeDeg(); };
+ double getLongitude() { return center.getLongitudeDeg(); };
+ double getHeading() { return heading; };
bool isPushBack() { return isPushBackRoute; };
int getPenalty(int nGates);
FGTaxiSegment *getAddress() { return this;};
bool operator<(const FGTaxiSegment &other) const { return index < other.index; };
- bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
+ //bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
FGTaxiSegment *opposite() { return oppositeDirection; };
void setCourseDiff(double crse);
routes = rts;
distance = dist;
currNode = nodes.begin();
+ currRoute = routes.begin();
// depth = dpth;
};
void checkHoldPosition(int id, double lat, double lon,
double heading, double speed, double alt);
+
+
public:
FGGroundNetwork();
~FGGroundNetwork();
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 void updateAircraftInformation(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 checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
+ AtcMsgDir msgDir);
bool checkForCircularWaits(int id);
+ virtual void render();
+
};
#include <AIModel/AIManager.hxx>
#include <ATCDCL/ATCmgr.hxx>
+#include <ATC/atc_mgr.hxx>
#include <Autopilot/route_mgr.hxx>
#include <Autopilot/autopilotgroup.hxx>
////////////////////////////////////////////////////////////////////
// Initialise the ATC Manager
+ // Note that this is old stuff, but might be necessesary for the
+ // current ATIS implementation. Therefore, leave it in here
+ // until the ATIS system is ported over to make use of the ATIS
+ // sub system infrastructure.
////////////////////////////////////////////////////////////////////
SG_LOG(SG_GENERAL, SG_INFO, " ATC Manager");
globals->set_ATC_mgr(new FGATCMgr);
globals->get_ATC_mgr()->init();
+ ////////////////////////////////////////////////////////////////////
+ // Initialize the ATC subsystem
+ ////////////////////////////////////////////////////////////////////
+ globals->add_subsystem("ATC", new FGATCManager, SGSubsystemMgr::POST_FDM);
+ ////////////////////////////////////////////////////////////////////
+ // Initialise the ATIS Subsystem
+ ////////////////////////////////////////////////////////////////////
+ //globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM);
+
+
////////////////////////////////////////////////////////////////////
// Initialize multiplayer subsystem
////////////////////////////////////////////////////////////////////
if ( tile_cache.insert_tile( t ) )
{
// Attach to scene graph
+
t->addToSceneGraph(globals->get_scenery()->get_terrain_branch());
} else
{
FGScheduledFlight::FGScheduledFlight()
{
- initialized = false;
- available = true;
+ departureTime = 0;
+ arrivalTime = 0;
+ cruiseAltitude = 0;
+ repeatPeriod = 0;
+ initialized = false;
+ available = true;
}
FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other)
time_t getDepartureTime() { return departureTime; };
time_t getArrivalTime () { return arrivalTime; };
+ void setDepartureAirport(string port) { depId = port; };
+ void setArrivalAirport (string port) { arrId = port; };
FGAirport *getDepartureAirport();
FGAirport *getArrivalAirport ();
void release() { available = true; };
bool isAvailable() { return available; };
+
+ void setCallSign(string val) { callsign = val; };
+ void setFlightRules(string val) { fltRules = val; };
};
typedef vector<FGScheduledFlight*> FGScheduledFlightVec;
radius = 0;
groundOffset = 0;
distanceToUser = 0;
+ valid = true;
//score = 0;
}
runCount = 0;
hits = 0;
initialized = false;
+ valid = true;
}
FGAISchedule::FGAISchedule(const FGAISchedule &other)
runCount = other.runCount;
hits = other.hits;
initialized = other.initialized;
+ valid = other.valid;
}
elapsedTimeEnroute,
remainingTimeEnroute,
deptime = 0;
-
+ if (!valid) {
+ return false;
+ }
scheduleFlights();
if (flights.empty()) { // No flights available for this aircraft
+ valid = false;
return false;
}
firstRun = false;
}
- FGScheduledFlight* flight = flights.front();
+ FGScheduledFlight* flight = flights.front();
if (!deptime) {
deptime = flight->getDepartureTime();
//cerr << "Settiing departure time " << deptime << endl;
aircraft->setBank(0);
courseToDest = SGGeodesy::courseDeg(position, arr->geod());
- aircraft->SetFlightPlan(new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime,
- dep, arr, true, radius,
- flight->getCruiseAlt()*100,
- position.getLatitudeDeg(),
- position.getLongitudeDeg(),
- speedKnots, flightType, acType,
- airline));
-
-
- FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
- aimgr->attach(aircraft);
- AIManagerRef = aircraft->getID();
- return true;
+ FGAIFlightPlan *fp = new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime,
+ dep, arr, true, radius,
+ flight->getCruiseAlt()*100,
+ position.getLatitudeDeg(),
+ position.getLongitudeDeg(),
+ speedKnots, flightType, acType,
+ airline);
+ if (fp->isValidPlan()) {
+ aircraft->SetFlightPlan(fp);
+ FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
+ aimgr->attach(aircraft);
+ AIManagerRef = aircraft->getID();
+ return true;
+ } else {
+ delete aircraft;
+ delete fp;
+ //hand back the flights that had already been scheduled
+ while (!flights.empty()) {
+ flights.front()->release();
+ flights.erase(flights.begin());
+ }
+ return false;
+ }
+}
+
+// Create an initial heading for user controlled aircraft.
+void FGAISchedule::setHeading()
+{
+ courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod());
}
void FGAISchedule::scheduleFlights()
bool firstRun;
double courseToDest;
bool initialized;
+ bool valid;
void scheduleFlights();
void setHits (unsigned int count) { hits = count; };
void setScore ();
double getScore () { return score; };
+ void setHeading ();
+ void assign (FGScheduledFlight *ref) { flights.push_back(ref); };
+ void setFlightType (string val ) { flightType = val; };
FGScheduledFlight*findAvailableFlight (const string ¤tDestination, const string &req);
// used to sort in decending order of score: I've probably found a better way to
// decending order sorting, but still need to test that.
bool operator< (const FGAISchedule &other) const { return (score > other.score); };
+ void taint() { valid = false; };
//void * getAiRef () { return AIManagerRef; };
//FGAISchedule* getAddress () { return this;};
}
//cerr << "Processing << " << (*currAircraft)->getRegistration() << " with score " << (*currAircraft)->getScore() << endl;
if (!((*currAircraft)->update(now, userCart))) {
+ (*currAircraft)->taint();
// NOTE: With traffic manager II, this statement below is no longer true
// after proper initialization, we shouldnt get here.
// But let's make sure