Major update to the AI code:
* New features - More realistic descent paths - Separation during descent and approach - ATC approach controller (still silent) - inbound traffic flow will start immediately * Bug fixes - Properly handle vertical speed when on ground - Departing aircraft now wait for taxiclerance before moving - Traffic manager waits for proper weather initialization - Fixed instabilities in the preferential runway usage code - Fine tuning of waypoint following code.
This commit is contained in:
parent
fed62b13dd
commit
467513cbaf
16 changed files with 2396 additions and 1487 deletions
|
@ -1,4 +1,4 @@
|
|||
// // // FGAIAircraft - FGAIBase-derived class creates an AI airplane
|
||||
// FGAIAircraft - FGAIBase-derived class creates an AI airplane
|
||||
//
|
||||
// Written by David Culp, started October 2003.
|
||||
//
|
||||
|
@ -78,6 +78,8 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) {
|
|||
roll = 0;
|
||||
headingChangeRate = 0.0;
|
||||
headingError = 0;
|
||||
minBearing = 360;
|
||||
speedFraction =1.0;
|
||||
|
||||
holdPos = false;
|
||||
needsTaxiClearance = false;
|
||||
|
@ -257,6 +259,16 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
|
|||
return;
|
||||
dt_count = 0;
|
||||
|
||||
double distanceToDescent;
|
||||
if(reachedEndOfCruise(distanceToDescent)) {
|
||||
if (!loadNextLeg(distanceToDescent)) {
|
||||
setDie(true);
|
||||
return;
|
||||
}
|
||||
prev = fp->getPreviousWaypoint();
|
||||
curr = fp->getCurrentWaypoint();
|
||||
next = fp->getNextWaypoint();
|
||||
}
|
||||
if (! leadPointReached(curr)) {
|
||||
controlHeading(curr);
|
||||
controlSpeed(curr, next);
|
||||
|
@ -278,7 +290,7 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
|
|||
|
||||
//TODO let the fp handle this (loading of next leg)
|
||||
fp->IncrementWaypoint( trafficRef != 0 );
|
||||
if (!(fp->getNextWaypoint()) && trafficRef != 0)
|
||||
if ( ((!(fp->getNextWaypoint()))) && (trafficRef != 0) )
|
||||
if (!loadNextLeg()) {
|
||||
setDie(true);
|
||||
return;
|
||||
|
@ -342,7 +354,7 @@ const char * FGAIAircraft::_getTransponderCode() const {
|
|||
}
|
||||
|
||||
|
||||
bool FGAIAircraft::loadNextLeg() {
|
||||
bool FGAIAircraft::loadNextLeg(double distance) {
|
||||
|
||||
int leg;
|
||||
if ((leg = fp->getLeg()) == 10) {
|
||||
|
@ -374,7 +386,8 @@ bool FGAIAircraft::loadNextLeg() {
|
|||
trafficRef->getRadius(),
|
||||
trafficRef->getFlightType(),
|
||||
acType,
|
||||
company);
|
||||
company,
|
||||
distance);
|
||||
//cerr << "created leg " << leg << " for " << trafficRef->getCallSign() << endl;
|
||||
}
|
||||
return true;
|
||||
|
@ -423,6 +436,7 @@ void FGAIAircraft::doGroundAltitude() {
|
|||
altitude_ft = (tgt_altitude_ft + groundOffset);
|
||||
else
|
||||
altitude_ft += 0.1 * ((tgt_altitude_ft+groundOffset) - altitude_ft);
|
||||
tgt_vs = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -449,6 +463,11 @@ void FGAIAircraft::announcePositionToController() {
|
|||
cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (trafficRef->getDepartureAirport()->getDynamics()) {
|
||||
controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController();
|
||||
}
|
||||
break;
|
||||
case 9: // Taxiing for parking
|
||||
if (trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork()->exists())
|
||||
controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork();
|
||||
|
@ -629,13 +648,34 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) {
|
|||
// << dist_to_go << ": Lead distance "
|
||||
// << lead_dist << " " << curr->name
|
||||
// << " Ground target speed " << groundTargetSpeed << endl;
|
||||
// if (trafficRef) {
|
||||
// if (trafficRef->getCallSign() == "Transavia7584") {
|
||||
// cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " "
|
||||
// << _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << curr->name << endl;
|
||||
// }
|
||||
// }
|
||||
return dist_to_go < lead_dist;
|
||||
double bearing;
|
||||
if (speed > 50) { // don't do bearing calculations for ground traffic
|
||||
bearing = getBearing(fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr));
|
||||
if (bearing < minBearing) {
|
||||
minBearing = bearing;
|
||||
if (minBearing < 10) {
|
||||
minBearing = 10;
|
||||
}
|
||||
if ((minBearing < 360.0) && (minBearing > 10.0)) {
|
||||
speedFraction = cos(minBearing *SG_DEGREES_TO_RADIANS);
|
||||
} else {
|
||||
speedFraction = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trafficRef) {
|
||||
//cerr << "Tracking callsign : \"" << fgGetString("/ai/track-callsign") << "\"" << endl;
|
||||
/* if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
|
||||
cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " "
|
||||
<< _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << " " << curr->name << " " << vs << " " << tgt_vs << " " << bearing << " " << minBearing << " " << speedFraction << endl;
|
||||
}*/
|
||||
}
|
||||
if ((dist_to_go < lead_dist) || (bearing > (minBearing * 1.1))) {
|
||||
minBearing = 360;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1024,7 +1064,7 @@ void FGAIAircraft::updateActualState() {
|
|||
if (onGround())
|
||||
speed = _performance->actualSpeed(this, groundTargetSpeed, dt);
|
||||
else
|
||||
speed = _performance->actualSpeed(this, tgt_speed, dt);
|
||||
speed = _performance->actualSpeed(this, (tgt_speed *speedFraction), dt);
|
||||
|
||||
updateHeading();
|
||||
roll = _performance->actualBankAngle(this, tgt_roll, dt);
|
||||
|
@ -1045,3 +1085,89 @@ void FGAIAircraft::updateSecondaryTargetValues() {
|
|||
|
||||
//TODO calculate wind correction angle (tgt_yaw)
|
||||
}
|
||||
|
||||
|
||||
bool FGAIAircraft::reachedEndOfCruise(double &distance) {
|
||||
FGAIFlightPlan::waypoint* curr = fp->getCurrentWaypoint();
|
||||
if (curr->name == "BOD") {
|
||||
double dist = fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr);
|
||||
double descentSpeed = (getPerformance()->vDescent() * SG_NM_TO_METER) / 3600.0; // convert from kts to meter/s
|
||||
double descentRate = (getPerformance()->descentRate() * SG_FEET_TO_METER) / 60.0; // convert from feet/min to meter/s
|
||||
|
||||
double verticalDistance = ((altitude_ft - 2000.0) - trafficRef->getArrivalAirport()->getElevation()) *SG_FEET_TO_METER;
|
||||
double descentTimeNeeded = verticalDistance / descentRate;
|
||||
double distanceCovered = descentSpeed * descentTimeNeeded;
|
||||
|
||||
//cerr << "Tracking : " << fgGetString("/ai/track-callsign");
|
||||
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
|
||||
cerr << "Checking for end of cruise stage for :" << trafficRef->getCallSign() << endl;
|
||||
cerr << "Descent rate : " << descentRate << endl;
|
||||
cerr << "Descent speed : " << descentSpeed << endl;
|
||||
cerr << "VerticalDistance : " << verticalDistance << ". Altitude : " << altitude_ft << ". Elevation " << trafficRef->getArrivalAirport()->getElevation() << endl;
|
||||
cerr << "DecentTimeNeeded : " << descentTimeNeeded << endl;
|
||||
cerr << "DistanceCovered : " << distanceCovered << endl;
|
||||
}
|
||||
//cerr << "Distance = " << distance << endl;
|
||||
distance = distanceCovered;
|
||||
if (dist < distanceCovered) {
|
||||
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
|
||||
//exit(1);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FGAIAircraft::resetPositionFromFlightPlan()
|
||||
{
|
||||
// the one behind you
|
||||
FGAIFlightPlan::waypoint* prev = 0;
|
||||
// the one ahead
|
||||
FGAIFlightPlan::waypoint* curr = 0;
|
||||
// the next plus 1
|
||||
FGAIFlightPlan::waypoint* next = 0;
|
||||
|
||||
prev = fp->getPreviousWaypoint();
|
||||
curr = fp->getCurrentWaypoint();
|
||||
next = fp->getNextWaypoint();
|
||||
|
||||
setLatitude(prev->latitude);
|
||||
setLongitude(prev->longitude);
|
||||
double tgt_heading = fp->getBearing(curr, next);
|
||||
setHeading(tgt_heading);
|
||||
setAltitude(prev->altitude);
|
||||
setSpeed(prev->speed);
|
||||
}
|
||||
|
||||
double FGAIAircraft::getBearing(double crse)
|
||||
{
|
||||
double hdgDiff = fabs(hdg-crse);
|
||||
if (hdgDiff > 180)
|
||||
hdgDiff = fabs(hdgDiff - 360);
|
||||
return hdgDiff;
|
||||
}
|
||||
|
||||
time_t FGAIAircraft::checkForArrivalTime(string wptName) {
|
||||
FGAIFlightPlan::waypoint* curr = 0;
|
||||
curr = fp->getCurrentWaypoint();
|
||||
|
||||
double tracklength = fp->checkTrackLength(wptName);
|
||||
if (tracklength > 0.1) {
|
||||
tracklength += fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||
time_t arrivalTime = fp->getArrivalTime();
|
||||
|
||||
time_t ete = tracklength / ((speed * SG_NM_TO_METER) / 3600.0);
|
||||
time_t secondsToGo = arrivalTime - now;
|
||||
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
|
||||
cerr << "Checking arrival time: ete " << ete << ". Time to go : " << secondsToGo << ". Track length = " << tracklength << endl;
|
||||
}
|
||||
return (ete - secondsToGo); // Positive when we're too slow...
|
||||
}
|
|
@ -53,6 +53,7 @@ public:
|
|||
void initializeFlightPlan();
|
||||
FGAIFlightPlan* GetFlightPlan() const { return fp; };
|
||||
void ProcessFlightPlan( double dt, time_t now );
|
||||
time_t checkForArrivalTime(string wptName);
|
||||
|
||||
void AccelTo(double speed);
|
||||
void PitchTo(double angle);
|
||||
|
@ -63,7 +64,9 @@ public:
|
|||
|
||||
void getGroundElev(double dt); //TODO these 3 really need to be public?
|
||||
void doGroundAltitude();
|
||||
bool loadNextLeg ();
|
||||
bool loadNextLeg (double dist=0);
|
||||
void resetPositionFromFlightPlan();
|
||||
double getBearing(double crse);
|
||||
|
||||
void setAcType(const std::string& ac) { acType = ac; };
|
||||
void setCompany(const std::string& comp) { company = comp;};
|
||||
|
@ -90,6 +93,7 @@ public:
|
|||
inline double altitudeAGL() const { return props->getFloatValue("position/altitude-agl-ft");};
|
||||
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
|
||||
std::string atGate();
|
||||
|
||||
|
||||
protected:
|
||||
void Run(double dt);
|
||||
|
@ -104,6 +108,8 @@ private:
|
|||
double dt_elev_count;
|
||||
double headingChangeRate;
|
||||
double headingError;
|
||||
double minBearing;
|
||||
double speedFraction;
|
||||
double groundTargetSpeed;
|
||||
double groundOffset;
|
||||
double dt;
|
||||
|
@ -118,6 +124,7 @@ private:
|
|||
void handleFirstWaypoint(void);
|
||||
bool leadPointReached(FGAIFlightPlan::waypoint* curr);
|
||||
bool handleAirportEndPoints(FGAIFlightPlan::waypoint* prev, time_t now);
|
||||
bool reachedEndOfCruise(double&);
|
||||
bool aiTrafficVisible(void);
|
||||
void controlHeading(FGAIFlightPlan::waypoint* curr);
|
||||
void controlSpeed(FGAIFlightPlan::waypoint* curr,
|
||||
|
|
|
@ -187,8 +187,8 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
|
|||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||
time_t timeDiff = now-start;
|
||||
leg = 1;
|
||||
/*
|
||||
if ((timeDiff > 300) && (timeDiff < 1200))
|
||||
|
||||
if ((timeDiff > 60) && (timeDiff < 1200))
|
||||
leg = 2;
|
||||
else if ((timeDiff >= 1200) && (timeDiff < 1500))
|
||||
leg = 3;
|
||||
|
@ -196,14 +196,15 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
|
|||
leg = 4;
|
||||
else if (timeDiff >= 2000)
|
||||
leg = 5;
|
||||
*/
|
||||
/*
|
||||
if (timeDiff >= 2000)
|
||||
leg = 5;
|
||||
|
||||
*/
|
||||
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,
|
||||
firstLeg, radius, fltType, acType, airline);
|
||||
firstLeg, radius, fltType, acType, airline, dist);
|
||||
wpt_iterator = waypoints.begin();
|
||||
//cerr << "after create: " << (*wpt_iterator)->name << endl;
|
||||
//leg++;
|
||||
|
@ -411,6 +412,7 @@ void FGAIFlightPlan::setLeadDistance(double speed, double bearing,
|
|||
|
||||
//lead_distance = turn_radius * sin(leadInAngle * SG_DEGREES_TO_RADIANS);
|
||||
lead_distance = turn_radius * tan((leadInAngle * SG_DEGREES_TO_RADIANS)/2);
|
||||
/*
|
||||
if ((lead_distance > (3*turn_radius)) && (current->on_ground == false)) {
|
||||
// cerr << "Warning: Lead-in distance is large. Inbound = " << inbound
|
||||
// << ". Outbound = " << outbound << ". Lead in angle = " << leadInAngle << ". Turn radius = " << turn_radius << endl;
|
||||
|
@ -420,7 +422,7 @@ void FGAIFlightPlan::setLeadDistance(double speed, double bearing,
|
|||
if ((leadInAngle > 90) && (current->on_ground == true)) {
|
||||
lead_distance = turn_radius * tan((90 * SG_DEGREES_TO_RADIANS)/2);
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void FGAIFlightPlan::setLeadDistance(double distance_ft){
|
||||
|
@ -493,3 +495,20 @@ int FGAIFlightPlan::getRouteIndex(int i) {
|
|||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
double FGAIFlightPlan::checkTrackLength(string wptName) {
|
||||
// skip the first two waypoints: first one is behind, second one is partially done;
|
||||
double trackDistance = 0;
|
||||
wpt_vector_iterator wptvec = waypoints.begin();
|
||||
wptvec++;
|
||||
wptvec++;
|
||||
while ((wptvec != waypoints.end()) && ((*wptvec)->name != wptName)) {
|
||||
trackDistance += (*wptvec)->trackLength;
|
||||
wptvec++;
|
||||
}
|
||||
if (wptvec == waypoints.end()) {
|
||||
trackDistance = 0; // name not found
|
||||
}
|
||||
return trackDistance;
|
||||
}
|
|
@ -55,6 +55,7 @@ public:
|
|||
bool on_ground;
|
||||
int routeIndex; // For AI/ATC purposes;
|
||||
double time_sec;
|
||||
double trackLength; // distance from previous waypoint (for AI purposes);
|
||||
string time;
|
||||
|
||||
} waypoint;
|
||||
|
@ -90,10 +91,12 @@ public:
|
|||
double getLeadDistance( void ) const {return lead_distance;}
|
||||
double getBearing(waypoint* previous, waypoint* next) const;
|
||||
double getBearing(double lat, double lon, waypoint* next) const;
|
||||
double checkTrackLength(string wptName);
|
||||
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 firstLeg, double radius, const string& fltType, const string& aircraftType, const string& airline);
|
||||
bool firstLeg, double radius, const string& fltType, const string& aircraftType, const string& airline, double distance);
|
||||
|
||||
void setLeg(int val) { leg = val;}
|
||||
void setTime(time_t st) { start_time = st; }
|
||||
|
@ -128,6 +131,7 @@ private:
|
|||
typedef vector <waypoint*> wpt_vector_type;
|
||||
typedef wpt_vector_type::const_iterator wpt_vector_iterator;
|
||||
|
||||
|
||||
wpt_vector_type waypoints;
|
||||
wpt_vector_iterator wpt_iterator;
|
||||
|
||||
|
@ -136,6 +140,7 @@ private:
|
|||
double lead_distance;
|
||||
double leadInAngle;
|
||||
time_t start_time;
|
||||
time_t arrivalTime; // For AI/ATC purposes.
|
||||
int leg;
|
||||
int gateId, lastNodeVisited;
|
||||
string activeRunway;
|
||||
|
@ -148,7 +153,7 @@ private:
|
|||
void createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const string&);
|
||||
void createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const string&);
|
||||
void createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const string&);
|
||||
void createDecent(FGAIAircraft *, FGAirport *, const string&);
|
||||
void createDescent(FGAIAircraft *, FGAirport *, double latitude, double longitude, double speed, double alt,const string&, double distance);
|
||||
void createLanding(FGAIAircraft *, FGAirport *, const string&);
|
||||
void createParking(FGAIAircraft *, FGAirport *, double radius);
|
||||
void deleteWaypoints();
|
||||
|
@ -158,6 +163,8 @@ private:
|
|||
void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport);
|
||||
void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
|
||||
void createTakeoffTaxi(FGAIAircraft *, bool firstFlight, FGAirport *apt, double radius, const string& fltType, const string& acType, const string& airline);
|
||||
|
||||
double getTurnRadius(double, bool);
|
||||
|
||||
waypoint* createOnGround(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
|
||||
waypoint* createInAir(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -300,8 +300,11 @@ void FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport
|
|||
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
|
||||
rwy = arr->getRunwayByIdent(activeRunway);
|
||||
// begin descent 110km out
|
||||
SGGeod beginDescentPoint = rwy->pointOnCenterline(-110000);
|
||||
SGGeod beginDescentPoint = rwy->pointOnCenterline(0);
|
||||
SGGeod secondaryDescentPoint = rwy->pointOnCenterline(-10000);
|
||||
|
||||
wpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
|
||||
wpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
|
||||
waypoints.push_back(wpt);
|
||||
wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
|
||||
waypoints.push_back(wpt);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,6 +28,8 @@
|
|||
|
||||
|
||||
#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>
|
||||
|
||||
|
||||
|
@ -185,6 +187,9 @@ public:
|
|||
typedef vector<FGTrafficRecord> TrafficVector;
|
||||
typedef vector<FGTrafficRecord>::iterator TrafficVectorIterator;
|
||||
|
||||
typedef vector<time_t> TimeVector;
|
||||
typedef vector<time_t>::iterator TimeVectorIterator;
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Active runway, a utility class to keep track of which aircraft has
|
||||
|
@ -195,11 +200,18 @@ class ActiveRunway
|
|||
private:
|
||||
string rwy;
|
||||
int currentlyCleared;
|
||||
double distanceToFinal;
|
||||
TimeVector estimatedArrivalTimes;
|
||||
public:
|
||||
ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; };
|
||||
ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; distanceToFinal = 6.0 * SG_NM_TO_METER; };
|
||||
|
||||
string getRunwayName() { return rwy; };
|
||||
int getCleared () { return currentlyCleared; };
|
||||
double getApproachDistance() { return distanceToFinal; };
|
||||
//time_t getEstApproachTime() { return estimatedArrival; };
|
||||
|
||||
//void setEstApproachTime(time_t time) { estimatedArrival = time; };
|
||||
time_t requestTimeSlot(time_t eta);
|
||||
};
|
||||
|
||||
typedef vector<ActiveRunway> ActiveRunwayVec;
|
||||
|
@ -207,7 +219,7 @@ typedef vector<ActiveRunway>::iterator ActiveRunwayVecIterator;
|
|||
|
||||
/**
|
||||
* class FGATCController
|
||||
* NOTE: this class serves as an abstraction layer for all sorts of ATC controller.
|
||||
* NOTE: this class serves as an abstraction layer for all sorts of ATC controllers.
|
||||
*************************************************************************************/
|
||||
class FGATCController
|
||||
{
|
||||
|
@ -317,4 +329,33 @@ public:
|
|||
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* class FGTowerControl
|
||||
*****************************************************************************/
|
||||
class FGApproachController : public FGATCController
|
||||
{
|
||||
private:
|
||||
TrafficVector activeTraffic;
|
||||
ActiveRunwayVec activeRunways;
|
||||
|
||||
public:
|
||||
FGApproachController();
|
||||
virtual ~FGApproachController() {};
|
||||
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);
|
||||
|
||||
ActiveRunway* getRunway(string name);
|
||||
|
||||
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
|
||||
TrafficVector &getActiveTraffic() { return activeTraffic; };
|
||||
};
|
||||
|
||||
|
||||
#endif // _TRAFFIC_CONTROL_HXX
|
||||
|
|
|
@ -325,17 +325,21 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
|
|||
takeoff.clear();
|
||||
lastUpdate = dayStart;
|
||||
prevTrafficType = trafficType;
|
||||
|
||||
/*
|
||||
FGEnvironment
|
||||
stationweather =
|
||||
((FGEnvironmentMgr *) globals->get_subsystem("environment"))
|
||||
->getEnvironment(getLatitude(), getLongitude(),
|
||||
getElevation());
|
||||
|
||||
windSpeed = stationweather.get_wind_speed_kt();
|
||||
windHeading = stationweather.get_wind_from_heading_deg();
|
||||
*/
|
||||
windSpeed = fgGetInt("/environment/metar/base-wind-speed-kt"); //stationweather.get_wind_speed_kt();
|
||||
windHeading = fgGetInt("/environment/metar/base-wind-dir-deg");
|
||||
//stationweather.get_wind_from_heading_deg();
|
||||
string scheduleName;
|
||||
//cerr << "finding active Runway for" << _ap->getId() << endl;
|
||||
//cerr << "finding active Runway for : " << _ap->getId() << endl;
|
||||
//cerr << "Wind Heading : " << windHeading << endl;
|
||||
//cerr << "Wind Speed : " << windSpeed << endl;
|
||||
|
||||
//cerr << "Nr of seconds since day start << " << dayStart << endl;
|
||||
|
||||
ScheduleTime *currSched;
|
||||
|
@ -347,7 +351,7 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
|
|||
scheduleName = currSched->getName(dayStart);
|
||||
maxTail = currSched->getTailWind();
|
||||
maxCross = currSched->getCrossWind();
|
||||
//cerr << "SChedule anme = " << scheduleName << endl;
|
||||
//cerr << "Current Schedule = : " << scheduleName << endl;
|
||||
if (scheduleName.empty())
|
||||
return false;
|
||||
//cerr << "C"<< endl;
|
||||
|
@ -371,6 +375,13 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
|
|||
currentlyActive = &ulActive;
|
||||
}
|
||||
|
||||
//cerr << "Durrently active selection for " << trafficType << ": ";
|
||||
for (stringVecIterator it = currentlyActive->begin();
|
||||
it != currentlyActive->end(); it++) {
|
||||
//cerr << (*it) << " ";
|
||||
}
|
||||
//cerr << endl;
|
||||
|
||||
currRunwayGroup->setActive(_ap,
|
||||
windSpeed,
|
||||
windHeading,
|
||||
|
|
|
@ -46,12 +46,13 @@ class FGAirportDynamics {
|
|||
private:
|
||||
FGAirport* _ap;
|
||||
|
||||
FGParkingVec parkings;
|
||||
FGRunwayPreference rwyPrefs;
|
||||
FGSidStar SIDs;
|
||||
FGStartupController startupController;
|
||||
FGGroundNetwork groundNetwork;
|
||||
FGTowerController towerController;
|
||||
FGParkingVec parkings;
|
||||
FGRunwayPreference rwyPrefs;
|
||||
FGSidStar SIDs;
|
||||
FGStartupController startupController;
|
||||
FGGroundNetwork groundNetwork;
|
||||
FGTowerController towerController;
|
||||
FGApproachController approachController;
|
||||
|
||||
time_t lastUpdate;
|
||||
string prevTrafficType;
|
||||
|
@ -112,9 +113,10 @@ public:
|
|||
|
||||
|
||||
// ATC related functions.
|
||||
FGStartupController *getStartupController() { return &startupController; };
|
||||
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
|
||||
FGTowerController *getTowerController() { return &towerController; };
|
||||
FGStartupController *getStartupController() { return &startupController; };
|
||||
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
|
||||
FGTowerController *getTowerController() { return &towerController; };
|
||||
FGApproachController *getApproachController() { return &approachController; };
|
||||
|
||||
const string& getAtisInformation() { return atisInformation; };
|
||||
int getGroundFrequency(unsigned leg); //{ return freqGround.size() ? freqGround[0] : 0; };
|
||||
|
|
|
@ -553,35 +553,46 @@ void FGGroundNetwork::update(int id, double lat, double lon,
|
|||
current->clearResolveCircularWait();
|
||||
current->setWaitsForId(0);
|
||||
checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
|
||||
checkHoldPosition(id, lat, lon, heading, speed, alt);
|
||||
if (checkForCircularWaits(id)) {
|
||||
i->setResolveCircularWait();
|
||||
}
|
||||
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
|
||||
int state = current->getState();
|
||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||
if ((now - lastTransmission) > 15) {
|
||||
available = true;
|
||||
}
|
||||
if (needsTaxiClearance && available) {
|
||||
transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
|
||||
current->getAircraft()->setTaxiClearanceRequest(false);
|
||||
current->setState(3);
|
||||
lastTransmission = now;
|
||||
available = false;
|
||||
}
|
||||
if ((state == 3) && available) {
|
||||
transmit(&(*current), 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);
|
||||
current->setState(0);
|
||||
lastTransmission = now;
|
||||
available = false;
|
||||
if (!needsTaxiClearance) {
|
||||
checkHoldPosition(id, lat, lon, heading, speed, alt);
|
||||
if (checkForCircularWaits(id)) {
|
||||
i->setResolveCircularWait();
|
||||
}
|
||||
} else {
|
||||
current->setHoldPosition(true);
|
||||
int state = current->getState();
|
||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||
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 ((state == 3) && available) {
|
||||
transmit(&(*current), 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);
|
||||
current->setState(5);
|
||||
lastTransmission = now;
|
||||
available = false;
|
||||
}
|
||||
if ((state == 5) && available) {
|
||||
current->setState(0);
|
||||
current->getAircraft()->setTaxiClearanceRequest(false);
|
||||
current->setHoldPosition(true);
|
||||
available = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -73,6 +73,27 @@ SGGeod FGRunwayBase::pointOnCenterline(double aOffset) const
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SGGeod FGRunwayBase::pointOffCenterline(double aOffset, double lateralOffset) const
|
||||
{
|
||||
SGGeod result;
|
||||
SGGeod temp;
|
||||
double dummyAz2;
|
||||
double halfLengthMetres = lengthM() * 0.5;
|
||||
|
||||
SGGeodesy::direct(mPosition, _heading,
|
||||
aOffset - halfLengthMetres,
|
||||
temp, dummyAz2);
|
||||
|
||||
SGGeodesy::direct(temp, (_heading+90.0),
|
||||
lateralOffset,
|
||||
result, dummyAz2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool FGRunwayBase::isHardSurface() const
|
||||
{
|
||||
return ((_surface_code == 1) || (_surface_code == 2));
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
* opposited direction. 0.0 corresponds to the (non-displaced) threshold
|
||||
*/
|
||||
SGGeod pointOnCenterline(double aOffset) const;
|
||||
SGGeod pointOffCenterline(double aOffset, double lateralOffset) const;
|
||||
|
||||
double lengthFt() const
|
||||
{ return _length; }
|
||||
|
|
|
@ -41,375 +41,372 @@
|
|||
* ScheduleTime
|
||||
***************e*************************************************************/
|
||||
void ScheduleTime::clear()
|
||||
{
|
||||
start.clear();
|
||||
end.clear();
|
||||
scheduleNames.clear();
|
||||
}
|
||||
|
||||
|
||||
ScheduleTime::ScheduleTime(const ScheduleTime &other)
|
||||
{
|
||||
//timeVec start;
|
||||
timeVecConstIterator i;
|
||||
for (i = other.start.begin(); i != other.start.end(); i++)
|
||||
start.push_back(*i);
|
||||
for (i = other.end.begin(); i != other.end.end(); i++)
|
||||
end.push_back(*i);
|
||||
stringVecConstIterator k;
|
||||
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
|
||||
scheduleNames.push_back(*k);
|
||||
|
||||
//timeVec end;
|
||||
//stringVec scheduleNames;
|
||||
tailWind = other.tailWind;
|
||||
crssWind = other.tailWind;
|
||||
start.clear();
|
||||
end.clear();
|
||||
scheduleNames.clear();
|
||||
}
|
||||
|
||||
|
||||
ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
|
||||
ScheduleTime::ScheduleTime(const ScheduleTime & other)
|
||||
{
|
||||
//timeVec start;
|
||||
clear();
|
||||
timeVecConstIterator i;
|
||||
for (i = other.start.begin(); i != other.start.end(); i++)
|
||||
start.push_back(*i);
|
||||
for (i = other.end.begin(); i != other.end.end(); i++)
|
||||
end.push_back(*i);
|
||||
stringVecConstIterator k;
|
||||
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
|
||||
scheduleNames.push_back(*k);
|
||||
|
||||
//timeVec end;
|
||||
//stringVec scheduleNames;
|
||||
tailWind = other.tailWind;
|
||||
crssWind = other.tailWind;
|
||||
return *this;
|
||||
//timeVec start;
|
||||
timeVecConstIterator i;
|
||||
for (i = other.start.begin(); i != other.start.end(); i++)
|
||||
start.push_back(*i);
|
||||
for (i = other.end.begin(); i != other.end.end(); i++)
|
||||
end.push_back(*i);
|
||||
stringVecConstIterator k;
|
||||
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
|
||||
k++)
|
||||
scheduleNames.push_back(*k);
|
||||
|
||||
//timeVec end;
|
||||
//stringVec scheduleNames;
|
||||
tailWind = other.tailWind;
|
||||
crssWind = other.tailWind;
|
||||
}
|
||||
|
||||
|
||||
ScheduleTime & ScheduleTime::operator=(const ScheduleTime & other)
|
||||
{
|
||||
//timeVec start;
|
||||
clear();
|
||||
timeVecConstIterator i;
|
||||
for (i = other.start.begin(); i != other.start.end(); i++)
|
||||
start.push_back(*i);
|
||||
for (i = other.end.begin(); i != other.end.end(); i++)
|
||||
end.push_back(*i);
|
||||
stringVecConstIterator k;
|
||||
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
|
||||
k++)
|
||||
scheduleNames.push_back(*k);
|
||||
|
||||
//timeVec end;
|
||||
//stringVec scheduleNames;
|
||||
tailWind = other.tailWind;
|
||||
crssWind = other.tailWind;
|
||||
return *this;
|
||||
}
|
||||
|
||||
string ScheduleTime::getName(time_t dayStart)
|
||||
{
|
||||
if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nrItems = start.size();
|
||||
//cerr << "Nr of items to process: " << nrItems << endl;
|
||||
if (nrItems > 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < start.size(); i++)
|
||||
{
|
||||
//cerr << i << endl;
|
||||
if ((dayStart >= start[i]) && (dayStart <= end[i]))
|
||||
return scheduleNames[i];
|
||||
}
|
||||
}
|
||||
//couldn't find one so return 0;
|
||||
//cerr << "Returning 0 " << endl;
|
||||
if ((start.size() != end.size())
|
||||
|| (start.size() != scheduleNames.size())) {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
|
||||
exit(1);
|
||||
} else {
|
||||
int nrItems = start.size();
|
||||
//cerr << "Nr of items to process: " << nrItems << endl;
|
||||
if (nrItems > 0) {
|
||||
for (unsigned int i = 0; i < start.size(); i++) {
|
||||
//cerr << i << endl;
|
||||
if ((dayStart >= start[i]) && (dayStart <= end[i]))
|
||||
return scheduleNames[i];
|
||||
}
|
||||
}
|
||||
//couldn't find one so return 0;
|
||||
//cerr << "Returning 0 " << endl;
|
||||
}
|
||||
return string("");
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* RunwayList
|
||||
*****************************************************************************/
|
||||
|
||||
RunwayList::RunwayList(const RunwayList &other)
|
||||
RunwayList::RunwayList(const RunwayList & other)
|
||||
{
|
||||
type = other.type;
|
||||
stringVecConstIterator i;
|
||||
for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
|
||||
preferredRunways.push_back(*i);
|
||||
}
|
||||
RunwayList& RunwayList::operator= (const RunwayList &other)
|
||||
{
|
||||
type = other.type;
|
||||
preferredRunways.clear();
|
||||
stringVecConstIterator i;
|
||||
for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
|
||||
preferredRunways.push_back(*i);
|
||||
return *this;
|
||||
}
|
||||
void RunwayList::set(const string &tp, const string &lst)
|
||||
{
|
||||
//weekday = atoi(timeCopy.substr(0,1).c_str());
|
||||
// timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
|
||||
// timeCopy = timeCopy.substr(2,timeCopy.length());
|
||||
type = tp;
|
||||
string rwys = lst;
|
||||
string rwy;
|
||||
while (rwys.find(",") != string::npos)
|
||||
{
|
||||
rwy = rwys.substr(0, rwys.find(",",0));
|
||||
//cerr << "adding runway [" << rwy << "] to the list " << endl;
|
||||
preferredRunways.push_back(rwy);
|
||||
rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
|
||||
while (rwys[0] == ' ')
|
||||
rwys.erase(0, 1); // Erase any leading whitespaces.
|
||||
//cerr << "Remaining runway list " << rwys;
|
||||
}
|
||||
preferredRunways.push_back(rwys);
|
||||
//exit(1);
|
||||
type = other.type;
|
||||
stringVecConstIterator i;
|
||||
for (i = other.preferredRunways.begin();
|
||||
i != other.preferredRunways.end(); i++)
|
||||
preferredRunways.push_back(*i);
|
||||
}
|
||||
|
||||
void RunwayList::clear()
|
||||
RunwayList & RunwayList::operator=(const RunwayList & other)
|
||||
{
|
||||
type = "";
|
||||
preferredRunways.clear();
|
||||
type = other.type;
|
||||
preferredRunways.clear();
|
||||
stringVecConstIterator i;
|
||||
for (i = other.preferredRunways.begin();
|
||||
i != other.preferredRunways.end(); i++)
|
||||
preferredRunways.push_back(*i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RunwayList::set(const string & tp, const string & lst)
|
||||
{
|
||||
//weekday = atoi(timeCopy.substr(0,1).c_str());
|
||||
// timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
|
||||
// timeCopy = timeCopy.substr(2,timeCopy.length());
|
||||
type = tp;
|
||||
string rwys = lst;
|
||||
string rwy;
|
||||
while (rwys.find(",") != string::npos) {
|
||||
rwy = rwys.substr(0, rwys.find(",", 0));
|
||||
//cerr << "adding runway [" << rwy << "] to the list " << endl;
|
||||
preferredRunways.push_back(rwy);
|
||||
rwys.erase(0, rwys.find(",", 0) + 1); // erase until after the first whitspace
|
||||
while (rwys[0] == ' ')
|
||||
rwys.erase(0, 1); // Erase any leading whitespaces.
|
||||
//cerr << "Remaining runway list " << rwys;
|
||||
}
|
||||
preferredRunways.push_back(rwys);
|
||||
//exit(1);
|
||||
}
|
||||
|
||||
void RunwayList::clear()
|
||||
{
|
||||
type = "";
|
||||
preferredRunways.clear();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
RunwayGroup::RunwayGroup(const RunwayGroup &other)
|
||||
RunwayGroup::RunwayGroup(const RunwayGroup & other)
|
||||
{
|
||||
name = other.name;
|
||||
RunwayListVecConstIterator i;
|
||||
for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
|
||||
rwyList.push_back(*i);
|
||||
choice[0] = other.choice[0];
|
||||
choice[1] = other.choice[1];
|
||||
nrActive = other.nrActive;
|
||||
}
|
||||
RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
|
||||
{
|
||||
rwyList.clear();
|
||||
name = other.name;
|
||||
RunwayListVecConstIterator i;
|
||||
for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
|
||||
rwyList.push_back(*i);
|
||||
choice[0] = other.choice[0];
|
||||
choice[1] = other.choice[1];
|
||||
nrActive = other.nrActive;
|
||||
return *this;
|
||||
name = other.name;
|
||||
RunwayListVecConstIterator i;
|
||||
for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
|
||||
rwyList.push_back(*i);
|
||||
choice[0] = other.choice[0];
|
||||
choice[1] = other.choice[1];
|
||||
nrActive = other.nrActive;
|
||||
}
|
||||
|
||||
void RunwayGroup::setActive(const FGAirport* airport,
|
||||
double windSpeed,
|
||||
double windHeading,
|
||||
double maxTail,
|
||||
double maxCross,
|
||||
stringVec *currentlyActive)
|
||||
RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
|
||||
{
|
||||
rwyList.clear();
|
||||
name = other.name;
|
||||
RunwayListVecConstIterator i;
|
||||
for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
|
||||
rwyList.push_back(*i);
|
||||
choice[0] = other.choice[0];
|
||||
choice[1] = other.choice[1];
|
||||
nrActive = other.nrActive;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RunwayGroup::setActive(const FGAirport * airport,
|
||||
double windSpeed,
|
||||
double windHeading,
|
||||
double maxTail,
|
||||
double maxCross, stringVec * currentlyActive)
|
||||
{
|
||||
|
||||
FGRunway* rwy;
|
||||
int activeRwys = rwyList.size(); // get the number of runways active
|
||||
int nrOfPreferences;
|
||||
// bool found = true;
|
||||
// double heading;
|
||||
double hdgDiff;
|
||||
double crossWind;
|
||||
double tailWind;
|
||||
string name;
|
||||
//stringVec names;
|
||||
int bestMatch = 0, bestChoice = 0;
|
||||
FGRunway *rwy;
|
||||
int activeRwys = rwyList.size(); // get the number of runways active
|
||||
int nrOfPreferences;
|
||||
// bool found = true;
|
||||
// double heading;
|
||||
double hdgDiff;
|
||||
double crossWind;
|
||||
double tailWind;
|
||||
string name;
|
||||
//stringVec names;
|
||||
int bestMatch = 0, bestChoice = 0;
|
||||
|
||||
if (activeRwys > 0)
|
||||
{
|
||||
// Now downward iterate across all the possible preferences
|
||||
// starting by the least preferred choice working toward the most preferred choice
|
||||
if (activeRwys > 0) {
|
||||
// Now downward iterate across all the possible preferences
|
||||
// starting by the least preferred choice working toward the most preferred choice
|
||||
|
||||
nrOfPreferences = rwyList[0].getRwyList()->size();
|
||||
bool validSelection = true;
|
||||
bool foundValidSelection = false;
|
||||
for (int i = nrOfPreferences-1; i >= 0; i--)
|
||||
{
|
||||
int match = 0;
|
||||
|
||||
nrOfPreferences = rwyList[0].getRwyList()->size();
|
||||
bool validSelection = true;
|
||||
bool foundValidSelection = false;
|
||||
for (int i = nrOfPreferences - 1; i >= 0; i--) {
|
||||
int match = 0;
|
||||
|
||||
// Test each runway listed in the preference to see if it's possible to use
|
||||
// If one runway of the selection isn't allowed, we need to exclude this
|
||||
// preference, however, we don't want to stop right there, because we also
|
||||
// don't want to randomly swap runway preferences, unless there is a need to.
|
||||
//
|
||||
validSelection = true;
|
||||
for (int j = 0; j < activeRwys; j++)
|
||||
{
|
||||
string ident(rwyList[j].getRwyList(i));
|
||||
if (!airport->hasRunwayWithIdent(ident)) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "no such runway:" << ident << " at " << airport->ident());
|
||||
continue;
|
||||
}
|
||||
|
||||
rwy = airport->getRunwayByIdent(ident);
|
||||
|
||||
//cerr << "Succes" << endl;
|
||||
hdgDiff = fabs(windHeading - rwy->headingDeg());
|
||||
//cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
|
||||
//cerr << "Wind Speed : " << windSpeed << endl;
|
||||
if (hdgDiff > 180)
|
||||
hdgDiff = 360 - hdgDiff;
|
||||
//cerr << "Heading diff: " << hdgDiff << endl;
|
||||
hdgDiff *= ((2*M_PI)/360.0); // convert to radians
|
||||
crossWind = windSpeed * sin(hdgDiff);
|
||||
tailWind = -windSpeed * cos(hdgDiff);
|
||||
//cerr << ". Tailwind : " << tailWind;
|
||||
//cerr << ". Crosswnd : " << crossWind;
|
||||
if ((tailWind > maxTail) || (crossWind > maxCross))
|
||||
{
|
||||
//cerr << ". [Invalid] " << endl;
|
||||
validSelection = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//cerr << ". [Valid] ";
|
||||
}
|
||||
//cerr << endl;
|
||||
} // of active runways iteration
|
||||
|
||||
if (validSelection)
|
||||
{
|
||||
//cerr << "Valid selection : " << i << endl;;
|
||||
foundValidSelection = true;
|
||||
for (stringVecIterator it = currentlyActive->begin();
|
||||
it != currentlyActive->end(); it++)
|
||||
{
|
||||
if ((*it) == name)
|
||||
match++;
|
||||
}
|
||||
if (match >= bestMatch) {
|
||||
bestMatch = match;
|
||||
bestChoice = i;
|
||||
}
|
||||
}
|
||||
//cerr << "Preference " << i << " bestMatch " << bestMatch << " choice " << bestChoice << endl;
|
||||
}
|
||||
if (foundValidSelection)
|
||||
{
|
||||
//cerr << "Valid runay selection : " << bestChoice << endl;
|
||||
nrActive = activeRwys;
|
||||
active = bestChoice;
|
||||
return;
|
||||
}
|
||||
// If this didn't work, due to heavy winds, try again
|
||||
// but select only one landing and one takeoff runway.
|
||||
choice[0] = 0;
|
||||
choice[1] = 0;
|
||||
for (int i = activeRwys-1; i; i--)
|
||||
{
|
||||
if (rwyList[i].getType() == string("landing"))
|
||||
choice[0] = i;
|
||||
if (rwyList[i].getType() == string("takeoff"))
|
||||
choice[1] = i;
|
||||
}
|
||||
//cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
|
||||
nrOfPreferences = rwyList[0].getRwyList()->size();
|
||||
for (int i = 0; i < nrOfPreferences; i++)
|
||||
{
|
||||
bool validSelection = true;
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
name = rwyList[choice[j]].getRwyList(i);
|
||||
rwy = airport->getRunwayByIdent(name);
|
||||
|
||||
//cerr << "Succes" << endl;
|
||||
hdgDiff = fabs(windHeading - rwy->headingDeg());
|
||||
if (hdgDiff > 180)
|
||||
hdgDiff = 360 - hdgDiff;
|
||||
hdgDiff *= ((2*M_PI)/360.0); // convert to radians
|
||||
crossWind = windSpeed * sin(hdgDiff);
|
||||
tailWind = -windSpeed * cos(hdgDiff);
|
||||
if ((tailWind > maxTail) || (crossWind > maxCross))
|
||||
validSelection = false;
|
||||
|
||||
|
||||
}
|
||||
if (validSelection)
|
||||
{
|
||||
//cerr << "Valid runay selection : " << i << endl;
|
||||
active = i;
|
||||
nrActive = 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Test each runway listed in the preference to see if it's possible to use
|
||||
// If one runway of the selection isn't allowed, we need to exclude this
|
||||
// preference, however, we don't want to stop right there, because we also
|
||||
// don't want to randomly swap runway preferences, unless there is a need to.
|
||||
//
|
||||
validSelection = true;
|
||||
|
||||
for (int j = 0; j < activeRwys; j++) {
|
||||
string ident(rwyList[j].getRwyList(i));
|
||||
if (!airport->hasRunwayWithIdent(ident)) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN,
|
||||
"no such runway:" << ident << " at " <<
|
||||
airport->ident());
|
||||
continue;
|
||||
}
|
||||
|
||||
rwy = airport->getRunwayByIdent(ident);
|
||||
|
||||
//cerr << "Succes" << endl;
|
||||
hdgDiff = fabs(windHeading - rwy->headingDeg());
|
||||
name = rwy->name();
|
||||
|
||||
|
||||
if (hdgDiff > 180)
|
||||
hdgDiff = 360 - hdgDiff;
|
||||
//cerr << "Heading diff: " << hdgDiff << endl;
|
||||
hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
|
||||
crossWind = windSpeed * sin(hdgDiff);
|
||||
tailWind = -windSpeed * cos(hdgDiff);
|
||||
//cerr << "Runway : " << rwy->name() << ": " << rwy->headingDeg() << endl;
|
||||
//cerr << ". Tailwind : " << tailWind;
|
||||
//cerr << ". Crosswnd : " << crossWind;
|
||||
if ((tailWind > maxTail) || (crossWind > maxCross)) {
|
||||
//cerr << ". [Invalid] " << endl;
|
||||
validSelection = false;
|
||||
} else {
|
||||
//cerr << ". [Valid] ";
|
||||
}
|
||||
//cerr << endl;
|
||||
for (stringVecIterator it = currentlyActive->begin();
|
||||
it != currentlyActive->end(); it++) {
|
||||
//cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
|
||||
if ((*it) == name) {
|
||||
match++;
|
||||
}
|
||||
}
|
||||
} // of active runways iteration
|
||||
|
||||
if (validSelection) {
|
||||
//cerr << "Valid selection : " << i << endl;;
|
||||
foundValidSelection = true;
|
||||
if (match >= bestMatch) {
|
||||
bestMatch = match;
|
||||
bestChoice = i;
|
||||
}
|
||||
}
|
||||
//cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
|
||||
}
|
||||
if (foundValidSelection) {
|
||||
//cerr << "Valid runay selection : " << bestChoice << endl;
|
||||
nrActive = activeRwys;
|
||||
active = bestChoice;
|
||||
return;
|
||||
}
|
||||
// If this didn't work, due to heavy winds, try again
|
||||
// but select only one landing and one takeoff runway.
|
||||
choice[0] = 0;
|
||||
choice[1] = 0;
|
||||
for (int i = activeRwys - 1; i; i--) {
|
||||
if (rwyList[i].getType() == string("landing"))
|
||||
choice[0] = i;
|
||||
if (rwyList[i].getType() == string("takeoff"))
|
||||
choice[1] = i;
|
||||
}
|
||||
//cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
|
||||
nrOfPreferences = rwyList[0].getRwyList()->size();
|
||||
for (int i = 0; i < nrOfPreferences; i++) {
|
||||
bool validSelection = true;
|
||||
for (int j = 0; j < 2; j++) {
|
||||
name = rwyList[choice[j]].getRwyList(i);
|
||||
rwy = airport->getRunwayByIdent(name);
|
||||
|
||||
//cerr << "Succes" << endl;
|
||||
hdgDiff = fabs(windHeading - rwy->headingDeg());
|
||||
if (hdgDiff > 180)
|
||||
hdgDiff = 360 - hdgDiff;
|
||||
hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
|
||||
crossWind = windSpeed * sin(hdgDiff);
|
||||
tailWind = -windSpeed * cos(hdgDiff);
|
||||
if ((tailWind > maxTail) || (crossWind > maxCross))
|
||||
validSelection = false;
|
||||
|
||||
|
||||
}
|
||||
if (validSelection) {
|
||||
//cerr << "Valid runay selection : " << i << endl;
|
||||
active = i;
|
||||
nrActive = 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
active = -1;
|
||||
nrActive = 0;
|
||||
active = -1;
|
||||
nrActive = 0;
|
||||
}
|
||||
|
||||
void RunwayGroup::getActive(int i, string &name, string &type)
|
||||
void RunwayGroup::getActive(int i, string & name, string & type)
|
||||
{
|
||||
if (i == -1)
|
||||
{
|
||||
return;
|
||||
if (i == -1) {
|
||||
return;
|
||||
}
|
||||
if (nrActive == (int)rwyList.size())
|
||||
{
|
||||
name = rwyList[i].getRwyList(active);
|
||||
type = rwyList[i].getType();
|
||||
}
|
||||
else
|
||||
{
|
||||
name = rwyList[choice[i]].getRwyList(active);
|
||||
type = rwyList[choice[i]].getType();
|
||||
if (nrActive == (int) rwyList.size()) {
|
||||
name = rwyList[i].getRwyList(active);
|
||||
type = rwyList[i].getType();
|
||||
} else {
|
||||
name = rwyList[choice[i]].getRwyList(active);
|
||||
type = rwyList[choice[i]].getType();
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* FGRunway preference
|
||||
****************************************************************************/
|
||||
FGRunwayPreference::FGRunwayPreference(FGAirport* ap) :
|
||||
_ap(ap)
|
||||
FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
|
||||
_ap(ap)
|
||||
{
|
||||
//cerr << "Running default Constructor" << endl;
|
||||
initialized = false;
|
||||
//cerr << "Running default Constructor" << endl;
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
|
||||
FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
|
||||
{
|
||||
initialized = other.initialized;
|
||||
initialized = other.initialized;
|
||||
|
||||
comTimes = other.comTimes; // Commercial Traffic;
|
||||
genTimes = other.genTimes; // General Aviation;
|
||||
milTimes = other.milTimes; // Military Traffic;
|
||||
comTimes = other.comTimes; // Commercial Traffic;
|
||||
genTimes = other.genTimes; // General Aviation;
|
||||
milTimes = other.milTimes; // Military Traffic;
|
||||
|
||||
PreferenceListConstIterator i;
|
||||
for (i = other.preferences.begin(); i != other.preferences.end(); i++)
|
||||
preferences.push_back(*i);
|
||||
PreferenceListConstIterator i;
|
||||
for (i = other.preferences.begin(); i != other.preferences.end(); i++)
|
||||
preferences.push_back(*i);
|
||||
}
|
||||
|
||||
FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
|
||||
|
||||
FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
|
||||
& other)
|
||||
{
|
||||
initialized = other.initialized;
|
||||
|
||||
comTimes = other.comTimes; // Commercial Traffic;
|
||||
genTimes = other.genTimes; // General Aviation;
|
||||
milTimes = other.milTimes; // Military Traffic;
|
||||
|
||||
PreferenceListConstIterator i;
|
||||
preferences.clear();
|
||||
for (i = other.preferences.begin(); i != other.preferences.end(); i++)
|
||||
preferences.push_back(*i);
|
||||
return *this;
|
||||
initialized = other.initialized;
|
||||
|
||||
comTimes = other.comTimes; // Commercial Traffic;
|
||||
genTimes = other.genTimes; // General Aviation;
|
||||
milTimes = other.milTimes; // Military Traffic;
|
||||
|
||||
PreferenceListConstIterator i;
|
||||
preferences.clear();
|
||||
for (i = other.preferences.begin(); i != other.preferences.end(); i++)
|
||||
preferences.push_back(*i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
|
||||
{
|
||||
if (!(strcmp(trafficType, "com"))) {
|
||||
return &comTimes;
|
||||
}
|
||||
if (!(strcmp(trafficType, "gen"))) {
|
||||
return &genTimes;
|
||||
}
|
||||
if (!(strcmp(trafficType, "mil"))) {
|
||||
return &milTimes;
|
||||
}
|
||||
return 0;
|
||||
if (!(strcmp(trafficType, "com"))) {
|
||||
return &comTimes;
|
||||
}
|
||||
if (!(strcmp(trafficType, "gen"))) {
|
||||
return &genTimes;
|
||||
}
|
||||
if (!(strcmp(trafficType, "mil"))) {
|
||||
return &milTimes;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
|
||||
RunwayGroup *FGRunwayPreference::getGroup(const string & groupName)
|
||||
{
|
||||
PreferenceListIterator i = preferences.begin();
|
||||
if (preferences.begin() == preferences.end())
|
||||
return 0;
|
||||
while (!(i == preferences.end() || i->getName() == groupName))
|
||||
i++;
|
||||
if (i != preferences.end())
|
||||
return &(*i);
|
||||
else
|
||||
return 0;
|
||||
PreferenceListIterator i = preferences.begin();
|
||||
if (preferences.begin() == preferences.end())
|
||||
return 0;
|
||||
while (!(i == preferences.end() || i->getName() == groupName))
|
||||
i++;
|
||||
if (i != preferences.end())
|
||||
return &(*i);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
string FGRunwayPreference::getId() {
|
||||
return _ap->getId();
|
||||
};
|
||||
string FGRunwayPreference::getId()
|
||||
{
|
||||
return _ap->getId();
|
||||
};
|
||||
|
|
|
@ -289,7 +289,6 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
|
|||
if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
|
||||
return true; // out of visual range, for the moment.
|
||||
}
|
||||
|
||||
return createAIAircraft(flight, speed, deptime);
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,9 @@ void FGTrafficManager::init()
|
|||
|
||||
void FGTrafficManager::update(double /*dt*/)
|
||||
{
|
||||
|
||||
if (fgGetBool("/environment/metar/valid") == false) {
|
||||
return;
|
||||
}
|
||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||
if (scheduledAircraft.size() == 0) {
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue