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.
|
// Written by David Culp, started October 2003.
|
||||||
//
|
//
|
||||||
|
@ -78,6 +78,8 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) {
|
||||||
roll = 0;
|
roll = 0;
|
||||||
headingChangeRate = 0.0;
|
headingChangeRate = 0.0;
|
||||||
headingError = 0;
|
headingError = 0;
|
||||||
|
minBearing = 360;
|
||||||
|
speedFraction =1.0;
|
||||||
|
|
||||||
holdPos = false;
|
holdPos = false;
|
||||||
needsTaxiClearance = false;
|
needsTaxiClearance = false;
|
||||||
|
@ -257,6 +259,16 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
|
||||||
return;
|
return;
|
||||||
dt_count = 0;
|
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)) {
|
if (! leadPointReached(curr)) {
|
||||||
controlHeading(curr);
|
controlHeading(curr);
|
||||||
controlSpeed(curr, next);
|
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)
|
//TODO let the fp handle this (loading of next leg)
|
||||||
fp->IncrementWaypoint( trafficRef != 0 );
|
fp->IncrementWaypoint( trafficRef != 0 );
|
||||||
if (!(fp->getNextWaypoint()) && trafficRef != 0)
|
if ( ((!(fp->getNextWaypoint()))) && (trafficRef != 0) )
|
||||||
if (!loadNextLeg()) {
|
if (!loadNextLeg()) {
|
||||||
setDie(true);
|
setDie(true);
|
||||||
return;
|
return;
|
||||||
|
@ -342,7 +354,7 @@ const char * FGAIAircraft::_getTransponderCode() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FGAIAircraft::loadNextLeg() {
|
bool FGAIAircraft::loadNextLeg(double distance) {
|
||||||
|
|
||||||
int leg;
|
int leg;
|
||||||
if ((leg = fp->getLeg()) == 10) {
|
if ((leg = fp->getLeg()) == 10) {
|
||||||
|
@ -374,7 +386,8 @@ bool FGAIAircraft::loadNextLeg() {
|
||||||
trafficRef->getRadius(),
|
trafficRef->getRadius(),
|
||||||
trafficRef->getFlightType(),
|
trafficRef->getFlightType(),
|
||||||
acType,
|
acType,
|
||||||
company);
|
company,
|
||||||
|
distance);
|
||||||
//cerr << "created leg " << leg << " for " << trafficRef->getCallSign() << endl;
|
//cerr << "created leg " << leg << " for " << trafficRef->getCallSign() << endl;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -423,6 +436,7 @@ void FGAIAircraft::doGroundAltitude() {
|
||||||
altitude_ft = (tgt_altitude_ft + groundOffset);
|
altitude_ft = (tgt_altitude_ft + groundOffset);
|
||||||
else
|
else
|
||||||
altitude_ft += 0.1 * ((tgt_altitude_ft+groundOffset) - altitude_ft);
|
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;
|
cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 7:
|
||||||
|
if (trafficRef->getDepartureAirport()->getDynamics()) {
|
||||||
|
controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 9: // Taxiing for parking
|
case 9: // Taxiing for parking
|
||||||
if (trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork()->exists())
|
if (trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork()->exists())
|
||||||
controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork();
|
controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork();
|
||||||
|
@ -629,13 +648,34 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) {
|
||||||
// << dist_to_go << ": Lead distance "
|
// << dist_to_go << ": Lead distance "
|
||||||
// << lead_dist << " " << curr->name
|
// << lead_dist << " " << curr->name
|
||||||
// << " Ground target speed " << groundTargetSpeed << endl;
|
// << " Ground target speed " << groundTargetSpeed << endl;
|
||||||
// if (trafficRef) {
|
double bearing;
|
||||||
// if (trafficRef->getCallSign() == "Transavia7584") {
|
if (speed > 50) { // don't do bearing calculations for ground traffic
|
||||||
// cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " "
|
bearing = getBearing(fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr));
|
||||||
// << _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << curr->name << endl;
|
if (bearing < minBearing) {
|
||||||
// }
|
minBearing = bearing;
|
||||||
// }
|
if (minBearing < 10) {
|
||||||
return dist_to_go < lead_dist;
|
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())
|
if (onGround())
|
||||||
speed = _performance->actualSpeed(this, groundTargetSpeed, dt);
|
speed = _performance->actualSpeed(this, groundTargetSpeed, dt);
|
||||||
else
|
else
|
||||||
speed = _performance->actualSpeed(this, tgt_speed, dt);
|
speed = _performance->actualSpeed(this, (tgt_speed *speedFraction), dt);
|
||||||
|
|
||||||
updateHeading();
|
updateHeading();
|
||||||
roll = _performance->actualBankAngle(this, tgt_roll, dt);
|
roll = _performance->actualBankAngle(this, tgt_roll, dt);
|
||||||
|
@ -1045,3 +1085,89 @@ void FGAIAircraft::updateSecondaryTargetValues() {
|
||||||
|
|
||||||
//TODO calculate wind correction angle (tgt_yaw)
|
//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();
|
void initializeFlightPlan();
|
||||||
FGAIFlightPlan* GetFlightPlan() const { return fp; };
|
FGAIFlightPlan* GetFlightPlan() const { return fp; };
|
||||||
void ProcessFlightPlan( double dt, time_t now );
|
void ProcessFlightPlan( double dt, time_t now );
|
||||||
|
time_t checkForArrivalTime(string wptName);
|
||||||
|
|
||||||
void AccelTo(double speed);
|
void AccelTo(double speed);
|
||||||
void PitchTo(double angle);
|
void PitchTo(double angle);
|
||||||
|
@ -63,7 +64,9 @@ public:
|
||||||
|
|
||||||
void getGroundElev(double dt); //TODO these 3 really need to be public?
|
void getGroundElev(double dt); //TODO these 3 really need to be public?
|
||||||
void doGroundAltitude();
|
void doGroundAltitude();
|
||||||
bool loadNextLeg ();
|
bool loadNextLeg (double dist=0);
|
||||||
|
void resetPositionFromFlightPlan();
|
||||||
|
double getBearing(double crse);
|
||||||
|
|
||||||
void setAcType(const std::string& ac) { acType = ac; };
|
void setAcType(const std::string& ac) { acType = ac; };
|
||||||
void setCompany(const std::string& comp) { company = comp;};
|
void setCompany(const std::string& comp) { company = comp;};
|
||||||
|
@ -91,6 +94,7 @@ public:
|
||||||
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
|
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
|
||||||
std::string atGate();
|
std::string atGate();
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Run(double dt);
|
void Run(double dt);
|
||||||
|
|
||||||
|
@ -104,6 +108,8 @@ private:
|
||||||
double dt_elev_count;
|
double dt_elev_count;
|
||||||
double headingChangeRate;
|
double headingChangeRate;
|
||||||
double headingError;
|
double headingError;
|
||||||
|
double minBearing;
|
||||||
|
double speedFraction;
|
||||||
double groundTargetSpeed;
|
double groundTargetSpeed;
|
||||||
double groundOffset;
|
double groundOffset;
|
||||||
double dt;
|
double dt;
|
||||||
|
@ -118,6 +124,7 @@ private:
|
||||||
void handleFirstWaypoint(void);
|
void handleFirstWaypoint(void);
|
||||||
bool leadPointReached(FGAIFlightPlan::waypoint* curr);
|
bool leadPointReached(FGAIFlightPlan::waypoint* curr);
|
||||||
bool handleAirportEndPoints(FGAIFlightPlan::waypoint* prev, time_t now);
|
bool handleAirportEndPoints(FGAIFlightPlan::waypoint* prev, time_t now);
|
||||||
|
bool reachedEndOfCruise(double&);
|
||||||
bool aiTrafficVisible(void);
|
bool aiTrafficVisible(void);
|
||||||
void controlHeading(FGAIFlightPlan::waypoint* curr);
|
void controlHeading(FGAIFlightPlan::waypoint* curr);
|
||||||
void controlSpeed(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 now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||||
time_t timeDiff = now-start;
|
time_t timeDiff = now-start;
|
||||||
leg = 1;
|
leg = 1;
|
||||||
/*
|
|
||||||
if ((timeDiff > 300) && (timeDiff < 1200))
|
if ((timeDiff > 60) && (timeDiff < 1200))
|
||||||
leg = 2;
|
leg = 2;
|
||||||
else if ((timeDiff >= 1200) && (timeDiff < 1500))
|
else if ((timeDiff >= 1200) && (timeDiff < 1500))
|
||||||
leg = 3;
|
leg = 3;
|
||||||
|
@ -196,14 +196,15 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
|
||||||
leg = 4;
|
leg = 4;
|
||||||
else if (timeDiff >= 2000)
|
else if (timeDiff >= 2000)
|
||||||
leg = 5;
|
leg = 5;
|
||||||
*/
|
/*
|
||||||
if (timeDiff >= 2000)
|
if (timeDiff >= 2000)
|
||||||
leg = 5;
|
leg = 5;
|
||||||
|
*/
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Route from " << dep->getId() << " to " << arr->getId() << ". Set leg to : " << leg << " " << ac->getTrafficRef()->getCallSign());
|
SG_LOG(SG_GENERAL, SG_INFO, "Route from " << dep->getId() << " to " << arr->getId() << ". Set leg to : " << leg << " " << ac->getTrafficRef()->getCallSign());
|
||||||
wpt_iterator = waypoints.begin();
|
wpt_iterator = waypoints.begin();
|
||||||
|
bool dist = 0;
|
||||||
create(ac, dep,arr, leg, alt, speed, lat, lon,
|
create(ac, dep,arr, leg, alt, speed, lat, lon,
|
||||||
firstLeg, radius, fltType, acType, airline);
|
firstLeg, radius, fltType, acType, airline, dist);
|
||||||
wpt_iterator = waypoints.begin();
|
wpt_iterator = waypoints.begin();
|
||||||
//cerr << "after create: " << (*wpt_iterator)->name << endl;
|
//cerr << "after create: " << (*wpt_iterator)->name << endl;
|
||||||
//leg++;
|
//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 * sin(leadInAngle * SG_DEGREES_TO_RADIANS);
|
||||||
lead_distance = turn_radius * tan((leadInAngle * SG_DEGREES_TO_RADIANS)/2);
|
lead_distance = turn_radius * tan((leadInAngle * SG_DEGREES_TO_RADIANS)/2);
|
||||||
|
/*
|
||||||
if ((lead_distance > (3*turn_radius)) && (current->on_ground == false)) {
|
if ((lead_distance > (3*turn_radius)) && (current->on_ground == false)) {
|
||||||
// cerr << "Warning: Lead-in distance is large. Inbound = " << inbound
|
// cerr << "Warning: Lead-in distance is large. Inbound = " << inbound
|
||||||
// << ". Outbound = " << outbound << ". Lead in angle = " << leadInAngle << ". Turn radius = " << turn_radius << endl;
|
// << ". 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)) {
|
if ((leadInAngle > 90) && (current->on_ground == true)) {
|
||||||
lead_distance = turn_radius * tan((90 * SG_DEGREES_TO_RADIANS)/2);
|
lead_distance = turn_radius * tan((90 * SG_DEGREES_TO_RADIANS)/2);
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIFlightPlan::setLeadDistance(double distance_ft){
|
void FGAIFlightPlan::setLeadDistance(double distance_ft){
|
||||||
|
@ -493,3 +495,20 @@ int FGAIFlightPlan::getRouteIndex(int i) {
|
||||||
else
|
else
|
||||||
return 0;
|
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;
|
bool on_ground;
|
||||||
int routeIndex; // For AI/ATC purposes;
|
int routeIndex; // For AI/ATC purposes;
|
||||||
double time_sec;
|
double time_sec;
|
||||||
|
double trackLength; // distance from previous waypoint (for AI purposes);
|
||||||
string time;
|
string time;
|
||||||
|
|
||||||
} waypoint;
|
} waypoint;
|
||||||
|
@ -90,10 +91,12 @@ public:
|
||||||
double getLeadDistance( void ) const {return lead_distance;}
|
double getLeadDistance( void ) const {return lead_distance;}
|
||||||
double getBearing(waypoint* previous, waypoint* next) const;
|
double getBearing(waypoint* previous, waypoint* next) const;
|
||||||
double getBearing(double lat, double lon, 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 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,
|
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 setLeg(int val) { leg = val;}
|
||||||
void setTime(time_t st) { start_time = st; }
|
void setTime(time_t st) { start_time = st; }
|
||||||
|
@ -128,6 +131,7 @@ private:
|
||||||
typedef vector <waypoint*> wpt_vector_type;
|
typedef vector <waypoint*> wpt_vector_type;
|
||||||
typedef wpt_vector_type::const_iterator wpt_vector_iterator;
|
typedef wpt_vector_type::const_iterator wpt_vector_iterator;
|
||||||
|
|
||||||
|
|
||||||
wpt_vector_type waypoints;
|
wpt_vector_type waypoints;
|
||||||
wpt_vector_iterator wpt_iterator;
|
wpt_vector_iterator wpt_iterator;
|
||||||
|
|
||||||
|
@ -136,6 +140,7 @@ private:
|
||||||
double lead_distance;
|
double lead_distance;
|
||||||
double leadInAngle;
|
double leadInAngle;
|
||||||
time_t start_time;
|
time_t start_time;
|
||||||
|
time_t arrivalTime; // For AI/ATC purposes.
|
||||||
int leg;
|
int leg;
|
||||||
int gateId, lastNodeVisited;
|
int gateId, lastNodeVisited;
|
||||||
string activeRunway;
|
string activeRunway;
|
||||||
|
@ -148,7 +153,7 @@ private:
|
||||||
void createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const string&);
|
void createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const string&);
|
||||||
void createClimb(FGAIAircraft *, bool, FGAirport *, double, 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 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 createLanding(FGAIAircraft *, FGAirport *, const string&);
|
||||||
void createParking(FGAIAircraft *, FGAirport *, double radius);
|
void createParking(FGAIAircraft *, FGAirport *, double radius);
|
||||||
void deleteWaypoints();
|
void deleteWaypoints();
|
||||||
|
@ -159,6 +164,8 @@ private:
|
||||||
void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
|
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);
|
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* 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);
|
waypoint* createInAir(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
|
||||||
waypoint* cloneWithPos(FGAIAircraft *, waypoint* aWpt, const std::string& aName, const SGGeod& aPos);
|
waypoint* cloneWithPos(FGAIAircraft *, waypoint* aWpt, const std::string& aName, const SGGeod& aPos);
|
||||||
|
|
|
@ -46,21 +46,23 @@
|
||||||
|
|
||||||
|
|
||||||
// Check lat/lon values during initialization;
|
// Check lat/lon values during initialization;
|
||||||
void FGAIFlightPlan::create(FGAIAircraft *ac, FGAirport *dep, FGAirport *arr, int legNr,
|
void FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
|
||||||
double alt, double speed, double latitude,
|
FGAirport * arr, int legNr, double alt,
|
||||||
double longitude, bool firstFlight,double radius,
|
double speed, double latitude,
|
||||||
const string& fltType, const string& aircraftType,
|
double longitude, bool firstFlight,
|
||||||
const string& airline)
|
double radius, const string & fltType,
|
||||||
|
const string & aircraftType,
|
||||||
|
const string & airline, double distance)
|
||||||
{
|
{
|
||||||
int currWpt = wpt_iterator - waypoints.begin();
|
int currWpt = wpt_iterator - waypoints.begin();
|
||||||
switch(legNr)
|
switch (legNr) {
|
||||||
{
|
|
||||||
case 1:
|
case 1:
|
||||||
createPushBack(ac, firstFlight, dep, latitude, longitude,
|
createPushBack(ac, firstFlight, dep, latitude, longitude,
|
||||||
radius, fltType, aircraftType, airline);
|
radius, fltType, aircraftType, airline);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
createTakeoffTaxi(ac, firstFlight, dep, radius, fltType, aircraftType, airline);
|
createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
|
||||||
|
aircraftType, airline);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
createTakeOff(ac, firstFlight, dep, speed, fltType);
|
createTakeOff(ac, firstFlight, dep, speed, fltType);
|
||||||
|
@ -69,10 +71,12 @@ void FGAIFlightPlan::create(FGAIAircraft *ac, FGAirport *dep, FGAirport *arr, in
|
||||||
createClimb(ac, firstFlight, dep, speed, alt, fltType);
|
createClimb(ac, firstFlight, dep, speed, alt, fltType);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
createCruise(ac, firstFlight, dep,arr, latitude, longitude, speed, alt, fltType);
|
createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
|
||||||
|
alt, fltType);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
createDecent(ac, arr, fltType);
|
createDescent(ac, arr, latitude, longitude, speed, alt, fltType,
|
||||||
|
distance);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
createLanding(ac, arr, fltType);
|
createLanding(ac, arr, fltType);
|
||||||
|
@ -85,7 +89,8 @@ void FGAIFlightPlan::create(FGAIAircraft *ac, FGAirport *dep, FGAirport *arr, in
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//exit(1);
|
//exit(1);
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "AIFlightPlan::create() attempting to create unknown leg"
|
SG_LOG(SG_INPUT, SG_ALERT,
|
||||||
|
"AIFlightPlan::create() attempting to create unknown leg"
|
||||||
" this is probably an internal program error");
|
" this is probably an internal program error");
|
||||||
}
|
}
|
||||||
wpt_iterator = waypoints.begin() + currWpt;
|
wpt_iterator = waypoints.begin() + currWpt;
|
||||||
|
@ -93,7 +98,10 @@ void FGAIFlightPlan::create(FGAIAircraft *ac, FGAirport *dep, FGAirport *arr, in
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAIFlightPlan::waypoint *
|
FGAIFlightPlan::waypoint *
|
||||||
FGAIFlightPlan::createOnGround(FGAIAircraft *ac, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed)
|
FGAIFlightPlan::createOnGround(FGAIAircraft * ac,
|
||||||
|
const std::string & aName,
|
||||||
|
const SGGeod & aPos, double aElev,
|
||||||
|
double aSpeed)
|
||||||
{
|
{
|
||||||
waypoint *wpt = new waypoint;
|
waypoint *wpt = new waypoint;
|
||||||
wpt->name = aName;
|
wpt->name = aName;
|
||||||
|
@ -101,7 +109,7 @@ FGAIFlightPlan::createOnGround(FGAIAircraft *ac, const std::string& aName, const
|
||||||
wpt->latitude = aPos.getLatitudeDeg();
|
wpt->latitude = aPos.getLatitudeDeg();
|
||||||
wpt->altitude = aElev;
|
wpt->altitude = aElev;
|
||||||
wpt->speed = aSpeed;
|
wpt->speed = aSpeed;
|
||||||
wpt->crossat = -10000;
|
wpt->crossat = -10000.1;
|
||||||
wpt->gear_down = true;
|
wpt->gear_down = true;
|
||||||
wpt->flaps_down = true;
|
wpt->flaps_down = true;
|
||||||
wpt->finished = false;
|
wpt->finished = false;
|
||||||
|
@ -111,7 +119,10 @@ FGAIFlightPlan::createOnGround(FGAIAircraft *ac, const std::string& aName, const
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAIFlightPlan::waypoint *
|
FGAIFlightPlan::waypoint *
|
||||||
FGAIFlightPlan::createInAir(FGAIAircraft *ac, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed)
|
FGAIFlightPlan::createInAir(FGAIAircraft * ac,
|
||||||
|
const std::string & aName,
|
||||||
|
const SGGeod & aPos, double aElev,
|
||||||
|
double aSpeed)
|
||||||
{
|
{
|
||||||
waypoint *wpt = new waypoint;
|
waypoint *wpt = new waypoint;
|
||||||
wpt->name = aName;
|
wpt->name = aName;
|
||||||
|
@ -119,7 +130,7 @@ FGAIFlightPlan::createInAir(FGAIAircraft *ac, const std::string& aName, const SG
|
||||||
wpt->latitude = aPos.getLatitudeDeg();
|
wpt->latitude = aPos.getLatitudeDeg();
|
||||||
wpt->altitude = aElev;
|
wpt->altitude = aElev;
|
||||||
wpt->speed = aSpeed;
|
wpt->speed = aSpeed;
|
||||||
wpt->crossat = -10000;
|
wpt->crossat = -10000.1;
|
||||||
wpt->gear_down = false;
|
wpt->gear_down = false;
|
||||||
wpt->flaps_down = false;
|
wpt->flaps_down = false;
|
||||||
wpt->finished = false;
|
wpt->finished = false;
|
||||||
|
@ -129,7 +140,9 @@ FGAIFlightPlan::createInAir(FGAIAircraft *ac, const std::string& aName, const SG
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAIFlightPlan::waypoint *
|
FGAIFlightPlan::waypoint *
|
||||||
FGAIFlightPlan::cloneWithPos(FGAIAircraft *ac, waypoint* aWpt, const std::string& aName, const SGGeod& aPos)
|
FGAIFlightPlan::cloneWithPos(FGAIAircraft * ac, waypoint * aWpt,
|
||||||
|
const std::string & aName,
|
||||||
|
const SGGeod & aPos)
|
||||||
{
|
{
|
||||||
waypoint *wpt = new waypoint;
|
waypoint *wpt = new waypoint;
|
||||||
wpt->name = aName;
|
wpt->name = aName;
|
||||||
|
@ -148,8 +161,7 @@ FGAIFlightPlan::cloneWithPos(FGAIAircraft *ac, waypoint* aWpt, const std::string
|
||||||
return wpt;
|
return wpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAIFlightPlan::waypoint*
|
FGAIFlightPlan::waypoint * FGAIFlightPlan::clone(waypoint * aWpt)
|
||||||
FGAIFlightPlan::clone(waypoint* aWpt)
|
|
||||||
{
|
{
|
||||||
waypoint *wpt = new waypoint;
|
waypoint *wpt = new waypoint;
|
||||||
wpt->name = aWpt->name;
|
wpt->name = aWpt->name;
|
||||||
|
@ -169,22 +181,30 @@ FGAIFlightPlan::clone(waypoint* aWpt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FGAIFlightPlan::createDefaultTakeoffTaxi(FGAIAircraft *ac, FGAirport* aAirport, FGRunway* aRunway)
|
void FGAIFlightPlan::createDefaultTakeoffTaxi(FGAIAircraft * ac,
|
||||||
|
FGAirport * aAirport,
|
||||||
|
FGRunway * aRunway)
|
||||||
{
|
{
|
||||||
SGGeod runwayTakeoff = aRunway->pointOnCenterline(5.0);
|
SGGeod runwayTakeoff = aRunway->pointOnCenterline(5.0);
|
||||||
double airportElev = aAirport->getElevation();
|
double airportElev = aAirport->getElevation();
|
||||||
|
|
||||||
waypoint *wpt;
|
waypoint *wpt;
|
||||||
wpt = createOnGround(ac, "Airport Center", aAirport->geod(), airportElev, ac->getPerformance()->vTaxi());
|
wpt =
|
||||||
|
createOnGround(ac, "Airport Center", aAirport->geod(), airportElev,
|
||||||
|
ac->getPerformance()->vTaxi());
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
wpt = createOnGround(ac, "Runway Takeoff", runwayTakeoff, airportElev, ac->getPerformance()->vTaxi());
|
wpt =
|
||||||
|
createOnGround(ac, "Runway Takeoff", runwayTakeoff, airportElev,
|
||||||
|
ac->getPerformance()->vTaxi());
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
|
void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
|
||||||
FGAirport * apt,
|
FGAirport * apt,
|
||||||
double radius, const string& fltType,
|
double radius,
|
||||||
const string& acType, const string& airline)
|
const string & fltType,
|
||||||
|
const string & acType,
|
||||||
|
const string & airline)
|
||||||
{
|
{
|
||||||
double heading, lat, lon;
|
double heading, lat, lon;
|
||||||
|
|
||||||
|
@ -195,8 +215,7 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
|
||||||
if (!(apt->getDynamics()->getAvailableParking(&lat, &lon,
|
if (!(apt->getDynamics()->getAvailableParking(&lat, &lon,
|
||||||
&heading, &gateId,
|
&heading, &gateId,
|
||||||
radius, fltType,
|
radius, fltType,
|
||||||
acType, airline)))
|
acType, airline))) {
|
||||||
{
|
|
||||||
SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " <<
|
SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " <<
|
||||||
acType <<
|
acType <<
|
||||||
" of flight type " << fltType <<
|
" of flight type " << fltType <<
|
||||||
|
@ -211,7 +230,8 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
|
||||||
if (activeRunway.empty()) {
|
if (activeRunway.empty()) {
|
||||||
//cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
|
//cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
|
||||||
double depHeading = ac->getTrafficRef()->getCourse();
|
double depHeading = ac->getTrafficRef()->getCourse();
|
||||||
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, depHeading);
|
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
|
||||||
|
depHeading);
|
||||||
}
|
}
|
||||||
rwy = apt->getRunwayByIdent(activeRunway);
|
rwy = apt->getRunwayByIdent(activeRunway);
|
||||||
SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
|
SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
|
||||||
|
@ -243,7 +263,6 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
|
||||||
if (node == -1) {
|
if (node == -1) {
|
||||||
node = gateId;
|
node = gateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HAndle case where parking doens't have a node
|
// HAndle case where parking doens't have a node
|
||||||
if ((node == 0) && park) {
|
if ((node == 0) && park) {
|
||||||
if (firstFlight) {
|
if (firstFlight) {
|
||||||
|
@ -270,7 +289,7 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
|
||||||
int nrWaypointsToSkip = rand() % taxiRoute->size();
|
int nrWaypointsToSkip = rand() % taxiRoute->size();
|
||||||
// but make sure we always keep two active waypoints
|
// but make sure we always keep two active waypoints
|
||||||
// to prevent a segmentation fault
|
// to prevent a segmentation fault
|
||||||
for (int i = 0; i < nrWaypointsToSkip-2; i++) {
|
for (int i = 0; i < nrWaypointsToSkip - 3; i++) {
|
||||||
taxiRoute->next(&node);
|
taxiRoute->next(&node);
|
||||||
}
|
}
|
||||||
apt->getDynamics()->releaseParking(gateId);
|
apt->getDynamics()->releaseParking(gateId);
|
||||||
|
@ -285,41 +304,56 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
|
||||||
while (taxiRoute->next(&node, &route)) {
|
while (taxiRoute->next(&node, &route)) {
|
||||||
char buffer[10];
|
char buffer[10];
|
||||||
snprintf(buffer, 10, "%d", node);
|
snprintf(buffer, 10, "%d", node);
|
||||||
FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
|
FGTaxiNode *tn =
|
||||||
waypoint* wpt = createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(), ac->getPerformance()->vTaxi());
|
apt->getDynamics()->getGroundNetwork()->findNode(node);
|
||||||
|
waypoint *wpt =
|
||||||
|
createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(),
|
||||||
|
ac->getPerformance()->vTaxi());
|
||||||
wpt->routeIndex = route;
|
wpt->routeIndex = route;
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft *ac, FGAirport* aAirport)
|
void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
|
||||||
|
FGAirport * aAirport)
|
||||||
{
|
{
|
||||||
SGGeod lastWptPos =
|
SGGeod lastWptPos =
|
||||||
SGGeod::fromDeg(waypoints.back()->longitude, waypoints.back()->latitude);
|
SGGeod::fromDeg(waypoints.back()->longitude,
|
||||||
|
waypoints.back()->latitude);
|
||||||
double airportElev = aAirport->getElevation();
|
double airportElev = aAirport->getElevation();
|
||||||
|
|
||||||
waypoint *wpt;
|
waypoint *wpt;
|
||||||
wpt = createOnGround(ac, "Runway Exit", lastWptPos, airportElev, ac->getPerformance()->vTaxi());
|
wpt =
|
||||||
|
createOnGround(ac, "Runway Exit", lastWptPos, airportElev,
|
||||||
|
ac->getPerformance()->vTaxi());
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
wpt = createOnGround(ac, "Airport Center", aAirport->geod(), airportElev, ac->getPerformance()->vTaxi());
|
wpt =
|
||||||
|
createOnGround(ac, "Airport Center", aAirport->geod(), airportElev,
|
||||||
|
ac->getPerformance()->vTaxi());
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
|
|
||||||
double heading, lat, lon;
|
double heading, lat, lon;
|
||||||
aAirport->getDynamics()->getParking(gateId, &lat, &lon, &heading);
|
aAirport->getDynamics()->getParking(gateId, &lat, &lon, &heading);
|
||||||
wpt = createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), airportElev, ac->getPerformance()->vTaxi());
|
wpt =
|
||||||
|
createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), airportElev,
|
||||||
|
ac->getPerformance()->vTaxi());
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
|
void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
|
||||||
double radius, const string& fltType,
|
double radius,
|
||||||
const string& acType, const string& airline)
|
const string & fltType,
|
||||||
|
const string & acType,
|
||||||
|
const string & airline)
|
||||||
{
|
{
|
||||||
double heading, lat, lon;
|
double heading, lat, lon;
|
||||||
apt->getDynamics()->getAvailableParking(&lat, &lon, &heading,
|
apt->getDynamics()->getAvailableParking(&lat, &lon, &heading,
|
||||||
&gateId, radius, fltType, acType, airline);
|
&gateId, radius, fltType,
|
||||||
|
acType, airline);
|
||||||
|
|
||||||
SGGeod lastWptPos =
|
SGGeod lastWptPos =
|
||||||
SGGeod::fromDeg(waypoints.back()->longitude, waypoints.back()->latitude);
|
SGGeod::fromDeg(waypoints.back()->longitude,
|
||||||
|
waypoints.back()->latitude);
|
||||||
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
|
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
|
||||||
|
|
||||||
// Find a route from runway end to parking/gate.
|
// Find a route from runway end to parking/gate.
|
||||||
|
@ -358,7 +392,9 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft *ac, FGAirport *apt,
|
||||||
char buffer[10];
|
char buffer[10];
|
||||||
snprintf(buffer, 10, "%d", node);
|
snprintf(buffer, 10, "%d", node);
|
||||||
FGTaxiNode *tn = gn->findNode(node);
|
FGTaxiNode *tn = gn->findNode(node);
|
||||||
waypoint* wpt = createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(), ac->getPerformance()->vTaxi());
|
waypoint *wpt =
|
||||||
|
createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(),
|
||||||
|
ac->getPerformance()->vTaxi());
|
||||||
wpt->routeIndex = route;
|
wpt->routeIndex = route;
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
}
|
}
|
||||||
|
@ -375,7 +411,9 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft *ac, FGAirport *apt,
|
||||||
* more likely however.
|
* more likely however.
|
||||||
*
|
*
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport *apt, double speed, const string &fltType)
|
void FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
|
||||||
|
FGAirport * apt, double speed,
|
||||||
|
const string & fltType)
|
||||||
{
|
{
|
||||||
double accel = ac->getPerformance()->acceleration();
|
double accel = ac->getPerformance()->acceleration();
|
||||||
double vTaxi = ac->getPerformance()->vTaxi();
|
double vTaxi = ac->getPerformance()->vTaxi();
|
||||||
|
@ -394,19 +432,21 @@ void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport
|
||||||
//d = (Vf^2 - Vo^2) / (2*a)
|
//d = (Vf^2 - Vo^2) / (2*a)
|
||||||
//double accelTime = (vRotate - vTaxi) / accel;
|
//double accelTime = (vRotate - vTaxi) / accel;
|
||||||
//cerr << "Using " << accelTime << " as total acceleration time" << endl;
|
//cerr << "Using " << accelTime << " as total acceleration time" << endl;
|
||||||
double accelDistance = (vRotateMetric*vRotateMetric - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
|
double accelDistance =
|
||||||
cerr << "Using " << accelDistance << " " << accelMetric << " " << vRotateMetric << endl;
|
(vRotateMetric * vRotateMetric -
|
||||||
|
vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
|
||||||
|
//cerr << "Using " << accelDistance << " " << accelMetric << " " << vRotateMetric << endl;
|
||||||
waypoint *wpt;
|
waypoint *wpt;
|
||||||
// Get the current active runway, based on code from David Luff
|
// Get the current active runway, based on code from David Luff
|
||||||
// This should actually be unified and extended to include
|
// This should actually be unified and extended to include
|
||||||
// Preferential runway use schema's
|
// Preferential runway use schema's
|
||||||
// NOTE: DT (2009-01-18: IIRC, this is currently already the case,
|
// NOTE: DT (2009-01-18: IIRC, this is currently already the case,
|
||||||
// because the getActive runway function takes care of that.
|
// because the getActive runway function takes care of that.
|
||||||
if (firstFlight)
|
if (firstFlight) {
|
||||||
{
|
|
||||||
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
||||||
double heading = ac->getTrafficRef()->getCourse();
|
double heading = ac->getTrafficRef()->getCourse();
|
||||||
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
|
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
|
||||||
|
heading);
|
||||||
rwy = apt->getRunwayByIdent(activeRunway);
|
rwy = apt->getRunwayByIdent(activeRunway);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,16 +457,22 @@ void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
|
|
||||||
|
|
||||||
accelDistance = (vTakeoffMetric*vTakeoffMetric - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
|
accelDistance =
|
||||||
cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
|
(vTakeoffMetric * vTakeoffMetric -
|
||||||
|
vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
|
||||||
|
//cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
|
||||||
accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
|
accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
|
||||||
wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
|
wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
|
|
||||||
accelDistance = ((vTakeoffMetric*1.1)*(vTakeoffMetric*1.1) - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
|
accelDistance =
|
||||||
cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
|
((vTakeoffMetric * 1.1) * (vTakeoffMetric * 1.1) -
|
||||||
|
vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
|
||||||
|
//cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
|
||||||
accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
|
accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
|
||||||
wpt = createOnGround(ac, "rotate", accelPoint, airportElev+1000, vTakeoff*1.1);
|
wpt =
|
||||||
|
createOnGround(ac, "rotate", accelPoint, airportElev + 1000,
|
||||||
|
vTakeoff * 1.1);
|
||||||
wpt->on_ground = false;
|
wpt->on_ground = false;
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
|
|
||||||
|
@ -446,7 +492,9 @@ void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport
|
||||||
* CreateClimb
|
* CreateClimb
|
||||||
* initialize the Aircraft at the parking location
|
* initialize the Aircraft at the parking location
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
void FGAIFlightPlan::createClimb(FGAIAircraft *ac, bool firstFlight, FGAirport *apt, double speed, double alt, const string &fltType)
|
void FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
|
||||||
|
FGAirport * apt, double speed, double alt,
|
||||||
|
const string & fltType)
|
||||||
{
|
{
|
||||||
waypoint *wpt;
|
waypoint *wpt;
|
||||||
// bool planLoaded = false;
|
// bool planLoaded = false;
|
||||||
|
@ -456,13 +504,13 @@ void FGAIFlightPlan::createClimb(FGAIAircraft *ac, bool firstFlight, FGAirport *
|
||||||
if (firstFlight) {
|
if (firstFlight) {
|
||||||
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
||||||
double heading = ac->getTrafficRef()->getCourse();
|
double heading = ac->getTrafficRef()->getCourse();
|
||||||
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
|
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
|
||||||
|
heading);
|
||||||
rwy = apt->getRunwayByIdent(activeRunway);
|
rwy = apt->getRunwayByIdent(activeRunway);
|
||||||
}
|
}
|
||||||
if (sid) {
|
if (sid) {
|
||||||
for (wpt_vector_iterator i = sid->getFirstWayPoint();
|
for (wpt_vector_iterator i = sid->getFirstWayPoint();
|
||||||
i != sid->getLastWayPoint();
|
i != sid->getLastWayPoint(); i++) {
|
||||||
i++) {
|
|
||||||
waypoints.push_back(clone(*(i)));
|
waypoints.push_back(clone(*(i)));
|
||||||
//cerr << " Cloning waypoint " << endl;
|
//cerr << " Cloning waypoint " << endl;
|
||||||
}
|
}
|
||||||
|
@ -483,50 +531,317 @@ void FGAIFlightPlan::createClimb(FGAIAircraft *ac, bool firstFlight, FGAirport *
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* CreateDecent
|
* CreateDescent
|
||||||
* initialize the Aircraft at the parking location
|
* Generate a flight path from the last waypoint of the cruise to
|
||||||
|
* the permission to land point
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
void FGAIFlightPlan::createDecent(FGAIAircraft *ac, FGAirport *apt, const string &fltType)
|
void FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
|
||||||
|
double latitude, double longitude,
|
||||||
|
double speed, double alt,
|
||||||
|
const string & fltType,
|
||||||
|
double requiredDistance)
|
||||||
{
|
{
|
||||||
// Ten thousand ft. Slowing down to 240 kts
|
bool reposition = false;
|
||||||
waypoint *wpt;
|
waypoint *wpt;
|
||||||
double vDecent = ac->getPerformance()->vDescent();
|
double vDescent = ac->getPerformance()->vDescent();
|
||||||
double vApproach = ac->getPerformance()->vApproach();
|
double vApproach = ac->getPerformance()->vApproach();
|
||||||
|
|
||||||
//Beginning of Decent
|
|
||||||
//string name;
|
//Beginning of Descent
|
||||||
// allow "mil" and "gen" as well
|
|
||||||
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
||||||
double heading = ac->getTrafficRef()->getCourse();
|
double heading = ac->getTrafficRef()->getCourse();
|
||||||
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
|
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
|
||||||
|
heading);
|
||||||
rwy = apt->getRunwayByIdent(activeRunway);
|
rwy = apt->getRunwayByIdent(activeRunway);
|
||||||
|
|
||||||
SGGeod descent1 = rwy->pointOnCenterline(-100000); // 100km out
|
|
||||||
wpt = createInAir(ac, "Dec 10000ft", descent1, apt->getElevation(), vDecent);
|
|
||||||
wpt->crossat = 10000;
|
|
||||||
waypoints.push_back(wpt);
|
|
||||||
|
|
||||||
// Three thousand ft. Slowing down to 160 kts
|
|
||||||
SGGeod descent2 = rwy->pointOnCenterline(-8*SG_NM_TO_METER); // 8nm out
|
// Create a slow descent path that ends 250 lateral to the runway.
|
||||||
wpt = createInAir(ac, "DEC 3000ft", descent2, apt->getElevation(), vApproach);
|
double initialTurnRadius = getTurnRadius(vDescent, true);
|
||||||
wpt->crossat = 3000;
|
double finalTurnRadius = getTurnRadius(vApproach, true);
|
||||||
wpt->gear_down = true;
|
|
||||||
wpt->flaps_down= true;
|
// get length of the downwind leg for the intended runway
|
||||||
waypoints.push_back(wpt);
|
double distanceOut = apt->getDynamics()->getApproachController()->getRunway(rwy->name())->getApproachDistance(); //12 * SG_NM_TO_METER;
|
||||||
|
//time_t previousArrivalTime= apt->getDynamics()->getApproachController()->getRunway(rwy->name())->getEstApproachTime();
|
||||||
|
|
||||||
|
|
||||||
|
SGGeod current = SGGeod::fromDegM(longitude, latitude, 0);
|
||||||
|
SGGeod initialTarget = rwy->pointOnCenterline(-distanceOut);
|
||||||
|
SGGeod refPoint = rwy->pointOnCenterline(0);
|
||||||
|
double distance = SGGeodesy::distanceM(current, initialTarget);
|
||||||
|
double azimuth = SGGeodesy::courseDeg(current, initialTarget);
|
||||||
|
double dummyAz2;
|
||||||
|
|
||||||
|
// To prevent absurdly steep approaches, compute the origin from where the approach should have started
|
||||||
|
SGGeod origin;
|
||||||
|
|
||||||
|
if (ac->getTrafficRef()->getCallSign() ==
|
||||||
|
fgGetString("/ai/track-callsign")) {
|
||||||
|
//cerr << "Reposition information: Actual distance " << distance << ". required distance " << requiredDistance << endl;
|
||||||
|
//exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (distance < requiredDistance * 0.8) {
|
||||||
|
reposition = true;
|
||||||
|
SGGeodesy::direct(initialTarget, azimuth,
|
||||||
|
-requiredDistance, origin, dummyAz2);
|
||||||
|
|
||||||
|
distance = SGGeodesy::distanceM(current, initialTarget);
|
||||||
|
azimuth = SGGeodesy::courseDeg(current, initialTarget);
|
||||||
|
} else {
|
||||||
|
origin = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double dAlt = alt - (apt->getElevation() + 2000);
|
||||||
|
|
||||||
|
double nPoints = 100;
|
||||||
|
|
||||||
|
char buffer[16];
|
||||||
|
|
||||||
|
// The descent path contains the following phases:
|
||||||
|
// 1) a linear glide path from the initial position to
|
||||||
|
// 2) a semi circle turn to final
|
||||||
|
// 3) approach
|
||||||
|
|
||||||
|
//cerr << "Phase 1: Linear Descent path to runway" << rwy->name() << endl;
|
||||||
|
// Create an initial destination point on a semicircle
|
||||||
|
//cerr << "lateral offset : " << lateralOffset << endl;
|
||||||
|
//cerr << "Distance : " << distance << endl;
|
||||||
|
//cerr << "Azimuth : " << azimuth << endl;
|
||||||
|
//cerr << "Initial Lateral point: " << lateralOffset << endl;
|
||||||
|
double lat = refPoint.getLatitudeDeg();
|
||||||
|
double lon = refPoint.getLongitudeDeg();
|
||||||
|
//cerr << "Reference point (" << lat << ", " << lon << ")." << endl;
|
||||||
|
lat = initialTarget.getLatitudeDeg();
|
||||||
|
lon = initialTarget.getLongitudeDeg();
|
||||||
|
//cerr << "Initial Target point (" << lat << ", " << lon << ")." << endl;
|
||||||
|
|
||||||
|
double ratio = initialTurnRadius / distance;
|
||||||
|
if (ratio > 1.0)
|
||||||
|
ratio = 1.0;
|
||||||
|
if (ratio < -1.0)
|
||||||
|
ratio = -1.0;
|
||||||
|
|
||||||
|
double newHeading = asin(ratio) * SG_RADIANS_TO_DEGREES;
|
||||||
|
double newDistance =
|
||||||
|
cos(newHeading * SG_DEGREES_TO_RADIANS) * distance;
|
||||||
|
//cerr << "new distance " << newDistance << ". additional Heading " << newHeading << endl;
|
||||||
|
double side = azimuth - rwy->headingDeg();
|
||||||
|
double lateralOffset = initialTurnRadius;
|
||||||
|
if (side < 0)
|
||||||
|
side += 360;
|
||||||
|
if (side < 180) {
|
||||||
|
lateralOffset *= -1;
|
||||||
|
}
|
||||||
|
// Calculate the ETA at final, based on remaining distance, and approach speed.
|
||||||
|
// distance should really consist of flying time to terniary target, plus circle
|
||||||
|
// but the distance to secondary target should work as a reasonable approximation
|
||||||
|
// aditionally add the amount of distance covered by making a turn of "side"
|
||||||
|
double turnDistance = (2 * M_PI * initialTurnRadius) * (side / 360.0);
|
||||||
|
time_t remaining =
|
||||||
|
(turnDistance + distance) / ((vDescent * SG_NM_TO_METER) / 3600.0);
|
||||||
|
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||||
|
//if (ac->getTrafficRef()->getCallSign() == fgGetString("/ai/track-callsign")) {
|
||||||
|
// cerr << " Arrival time estimation: turn angle " << side << ". Turn distance " << turnDistance << ". Linear distance " << distance << ". Time to go " << remaining << endl;
|
||||||
|
// //exit(1);
|
||||||
|
//}
|
||||||
|
|
||||||
|
time_t eta = now + remaining;
|
||||||
|
//choose a distance to the runway such that it will take at least 60 seconds more
|
||||||
|
// time to get there than the previous aircraft.
|
||||||
|
// Don't bother when aircraft need to be repositioned, because that marks the initialization phased...
|
||||||
|
|
||||||
|
time_t newEta;
|
||||||
|
|
||||||
|
if (reposition == false) {
|
||||||
|
newEta =
|
||||||
|
apt->getDynamics()->getApproachController()->getRunway(rwy->
|
||||||
|
name
|
||||||
|
())->
|
||||||
|
requestTimeSlot(eta);
|
||||||
|
} else {
|
||||||
|
newEta = eta;
|
||||||
|
}
|
||||||
|
//if ((eta < (previousArrivalTime+60)) && (reposition == false)) {
|
||||||
|
arrivalTime = newEta;
|
||||||
|
time_t additionalTimeNeeded = newEta - eta;
|
||||||
|
double distanceCovered =
|
||||||
|
((vApproach * SG_NM_TO_METER) / 3600.0) * additionalTimeNeeded;
|
||||||
|
distanceOut += distanceCovered;
|
||||||
|
//apt->getDynamics()->getApproachController()->getRunway(rwy->name())->setEstApproachTime(eta+additionalTimeNeeded);
|
||||||
|
//cerr << "Adding additional distance: " << distanceCovered << " to allow " << additionalTimeNeeded << " seconds of flying time" << endl << endl;
|
||||||
|
//} else {
|
||||||
|
//apt->getDynamics()->getApproachController()->getRunway(rwy->name())->setEstApproachTime(eta);
|
||||||
|
//}
|
||||||
|
//cerr << "Timing information : Previous eta: " << previousArrivalTime << ". Current ETA : " << eta << endl;
|
||||||
|
|
||||||
|
SGGeod secondaryTarget =
|
||||||
|
rwy->pointOffCenterline(-distanceOut, lateralOffset);
|
||||||
|
initialTarget = rwy->pointOnCenterline(-distanceOut);
|
||||||
|
distance = SGGeodesy::distanceM(origin, secondaryTarget);
|
||||||
|
azimuth = SGGeodesy::courseDeg(origin, secondaryTarget);
|
||||||
|
|
||||||
|
|
||||||
|
lat = secondaryTarget.getLatitudeDeg();
|
||||||
|
lon = secondaryTarget.getLongitudeDeg();
|
||||||
|
//cerr << "Secondary Target point (" << lat << ", " << lon << ")." << endl;
|
||||||
|
//cerr << "Distance : " << distance << endl;
|
||||||
|
//cerr << "Azimuth : " << azimuth << endl;
|
||||||
|
|
||||||
|
|
||||||
|
ratio = initialTurnRadius / distance;
|
||||||
|
if (ratio > 1.0)
|
||||||
|
ratio = 1.0;
|
||||||
|
if (ratio < -1.0)
|
||||||
|
ratio = -1.0;
|
||||||
|
newHeading = asin(ratio) * SG_RADIANS_TO_DEGREES;
|
||||||
|
newDistance = cos(newHeading * SG_DEGREES_TO_RADIANS) * distance;
|
||||||
|
//cerr << "new distance realative to secondary target: " << newDistance << ". additional Heading " << newHeading << endl;
|
||||||
|
if (side < 180) {
|
||||||
|
azimuth += newHeading;
|
||||||
|
} else {
|
||||||
|
azimuth -= newHeading;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGGeod tertiaryTarget;
|
||||||
|
SGGeodesy::direct(origin, azimuth,
|
||||||
|
newDistance, tertiaryTarget, dummyAz2);
|
||||||
|
|
||||||
|
lat = tertiaryTarget.getLatitudeDeg();
|
||||||
|
lon = tertiaryTarget.getLongitudeDeg();
|
||||||
|
//cerr << "tertiary Target point (" << lat << ", " << lon << ")." << endl;
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 1; i < nPoints; i++) {
|
||||||
|
SGGeod result;
|
||||||
|
double currentDist = i * (newDistance / nPoints);
|
||||||
|
double currentAltitude = alt - (i * (dAlt / nPoints));
|
||||||
|
SGGeodesy::direct(origin, azimuth, currentDist, result, dummyAz2);
|
||||||
|
snprintf(buffer, 16, "descent%03d", i);
|
||||||
|
wpt = createInAir(ac, buffer, result, currentAltitude, vDescent);
|
||||||
|
wpt->crossat = currentAltitude;
|
||||||
|
wpt->trackLength = (newDistance / nPoints);
|
||||||
|
waypoints.push_back(wpt);
|
||||||
|
//cerr << "Track Length : " << wpt->trackLength;
|
||||||
|
//cerr << " Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cerr << "Phase 2: Circle " << endl;
|
||||||
|
double initialAzimuth =
|
||||||
|
SGGeodesy::courseDeg(secondaryTarget, tertiaryTarget);
|
||||||
|
double finalAzimuth =
|
||||||
|
SGGeodesy::courseDeg(secondaryTarget, initialTarget);
|
||||||
|
|
||||||
|
//cerr << "Angles from secondary target: " << initialAzimuth << " " << finalAzimuth << endl;
|
||||||
|
int increment, startval, endval;
|
||||||
|
// circle right around secondary target if orig of position is to the right of the runway
|
||||||
|
// i.e. use negative angles; else circle leftward and use postivi
|
||||||
|
if (side < 180) {
|
||||||
|
increment = -1;
|
||||||
|
startval = floor(initialAzimuth);
|
||||||
|
endval = ceil(finalAzimuth);
|
||||||
|
if (endval > startval) {
|
||||||
|
endval -= 360;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
increment = 1;
|
||||||
|
startval = ceil(initialAzimuth);
|
||||||
|
endval = floor(finalAzimuth);
|
||||||
|
if (endval < startval) {
|
||||||
|
endval += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//cerr << "creating circle between " << startval << " and " << endval << " using " << increment << endl;
|
||||||
|
double trackLength = (2 * M_PI * initialTurnRadius) / 360.0;
|
||||||
|
for (int i = startval; i != endval; i += increment) {
|
||||||
|
SGGeod result;
|
||||||
|
double currentAltitude = apt->getElevation() + 2000;
|
||||||
|
SGGeodesy::direct(secondaryTarget, i,
|
||||||
|
initialTurnRadius, result, dummyAz2);
|
||||||
|
snprintf(buffer, 16, "turn%03d", i);
|
||||||
|
wpt = createInAir(ac, buffer, result, currentAltitude, vDescent);
|
||||||
|
wpt->crossat = currentAltitude;
|
||||||
|
wpt->trackLength = trackLength;
|
||||||
|
//cerr << "Track Length : " << wpt->trackLength;
|
||||||
|
waypoints.push_back(wpt);
|
||||||
|
//cerr << " Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The approach leg should bring the aircraft to approximately 4-6 out, after which the landing phase should take over.
|
||||||
|
//cerr << "Phase 3: Approach" << endl;
|
||||||
|
distanceOut -= distanceCovered;
|
||||||
|
for (int i = 1; i < nPoints; i++) {
|
||||||
|
SGGeod result;
|
||||||
|
double currentDist = i * (distanceOut / nPoints);
|
||||||
|
double currentAltitude =
|
||||||
|
apt->getElevation() + 2000 - (i * 2000 / nPoints);
|
||||||
|
snprintf(buffer, 16, "final%03d", i);
|
||||||
|
result = rwy->pointOnCenterline((-distanceOut) + currentDist);
|
||||||
|
wpt = createInAir(ac, buffer, result, currentAltitude, vApproach);
|
||||||
|
wpt->crossat = currentAltitude;
|
||||||
|
wpt->trackLength = (distanceOut / nPoints);
|
||||||
|
// account for the extra distance due to an extended downwind leg
|
||||||
|
if (i == 1) {
|
||||||
|
wpt->trackLength += distanceCovered;
|
||||||
|
}
|
||||||
|
//cerr << "Track Length : " << wpt->trackLength;
|
||||||
|
waypoints.push_back(wpt);
|
||||||
|
//cerr << " Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cerr << "Done" << endl;
|
||||||
|
|
||||||
|
// Erase the two bogus BOD points: Note check for conflicts with scripted AI flightPlans
|
||||||
|
IncrementWaypoint(true);
|
||||||
|
IncrementWaypoint(true);
|
||||||
|
|
||||||
|
if (reposition) {
|
||||||
|
double tempDistance;
|
||||||
|
double minDistance = HUGE_VAL;
|
||||||
|
string wptName;
|
||||||
|
tempDistance = SGGeodesy::distanceM(current, initialTarget);
|
||||||
|
time_t eta =
|
||||||
|
tempDistance / ((vDescent * SG_NM_TO_METER) / 3600.0) + now;
|
||||||
|
time_t newEta =
|
||||||
|
apt->getDynamics()->getApproachController()->getRunway(rwy->
|
||||||
|
name
|
||||||
|
())->
|
||||||
|
requestTimeSlot(eta);
|
||||||
|
arrivalTime = newEta;
|
||||||
|
double newDistance =
|
||||||
|
((vDescent * SG_NM_TO_METER) / 3600.0) * (newEta - now);
|
||||||
|
//cerr << "Repositioning information : eta" << eta << ". New ETA " << newEta << ". Diff = " << (newEta - eta) << ". Distance = " << tempDistance << ". New distance = " << newDistance << endl;
|
||||||
|
IncrementWaypoint(true); // remove waypoint BOD2
|
||||||
|
while (checkTrackLength("final001") > newDistance) {
|
||||||
|
IncrementWaypoint(true);
|
||||||
|
}
|
||||||
|
//cerr << "Repositioning to waypoint " << (*waypoints.begin())->name << endl;
|
||||||
|
ac->resetPositionFromFlightPlan();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* CreateLanding
|
* CreateLanding
|
||||||
* initialize the Aircraft at the parking location
|
* Create a flight path from the "permision to land" point (currently
|
||||||
|
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, const string &fltType)
|
void FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
|
||||||
|
const string & fltType)
|
||||||
{
|
{
|
||||||
double vTouchdown = ac->getPerformance()->vTouchdown();
|
double vTouchdown = ac->getPerformance()->vTouchdown();
|
||||||
double vTaxi = ac->getPerformance()->vTaxi();
|
double vTaxi = ac->getPerformance()->vTaxi();
|
||||||
|
|
||||||
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
//string rwyClass = getRunwayClassFromTrafficType(fltType);
|
||||||
double heading = ac->getTrafficRef()->getCourse();
|
//double heading = ac->getTrafficRef()->getCourse();
|
||||||
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
|
//apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
|
||||||
rwy = apt->getRunwayByIdent(activeRunway);
|
//rwy = apt->getRunwayByIdent(activeRunway);
|
||||||
|
|
||||||
|
|
||||||
waypoint *wpt;
|
waypoint *wpt;
|
||||||
|
@ -563,7 +878,8 @@ void FGAIFlightPlan::createLanding(FGAIAircraft *ac, FGAirport *apt, const strin
|
||||||
* CreateParking
|
* CreateParking
|
||||||
* initialize the Aircraft at the parking location
|
* initialize the Aircraft at the parking location
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
void FGAIFlightPlan::createParking(FGAIAircraft *ac, FGAirport *apt, double radius)
|
void FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
|
||||||
|
double radius)
|
||||||
{
|
{
|
||||||
waypoint *wpt;
|
waypoint *wpt;
|
||||||
double aptElev = apt->getElevation();
|
double aptElev = apt->getElevation();
|
||||||
|
@ -579,19 +895,23 @@ void FGAIFlightPlan::createParking(FGAIAircraft *ac, FGAirport *apt, double radi
|
||||||
if (heading > 360)
|
if (heading > 360)
|
||||||
heading -= 360;
|
heading -= 360;
|
||||||
geo_direct_wgs_84(0, lat, lon, heading,
|
geo_direct_wgs_84(0, lat, lon, heading,
|
||||||
2.2*radius,
|
2.2 * radius, &lat2, &lon2, &az2);
|
||||||
&lat2, &lon2, &az2 );
|
wpt =
|
||||||
wpt = createOnGround(ac, "taxiStart", SGGeod::fromDeg(lon2, lat2), aptElev, vTaxiReduced);
|
createOnGround(ac, "taxiStart", SGGeod::fromDeg(lon2, lat2),
|
||||||
|
aptElev, vTaxiReduced);
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
|
|
||||||
geo_direct_wgs_84(0, lat, lon, heading,
|
geo_direct_wgs_84(0, lat, lon, heading,
|
||||||
0.1 *radius,
|
0.1 * radius, &lat2, &lon2, &az2);
|
||||||
&lat2, &lon2, &az2 );
|
|
||||||
|
|
||||||
wpt = createOnGround(ac, "taxiStart2", SGGeod::fromDeg(lon2, lat2), aptElev, vTaxiReduced);
|
wpt =
|
||||||
|
createOnGround(ac, "taxiStart2", SGGeod::fromDeg(lon2, lat2),
|
||||||
|
aptElev, vTaxiReduced);
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
|
|
||||||
wpt = createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev, vTaxiReduced);
|
wpt =
|
||||||
|
createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev,
|
||||||
|
vTaxiReduced);
|
||||||
waypoints.push_back(wpt);
|
waypoints.push_back(wpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,3 +954,15 @@ string FGAIFlightPlan::getRunwayClassFromTrafficType(string fltType)
|
||||||
}
|
}
|
||||||
return string("com");
|
return string("com");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double FGAIFlightPlan::getTurnRadius(double speed, bool inAir)
|
||||||
|
{
|
||||||
|
double turn_radius;
|
||||||
|
if (inAir == false) {
|
||||||
|
turn_radius = ((360 / 30) * fabs(speed)) / (2 * M_PI);
|
||||||
|
} else {
|
||||||
|
turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank
|
||||||
|
}
|
||||||
|
return turn_radius;
|
||||||
|
}
|
||||||
|
|
|
@ -300,8 +300,11 @@ void FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport
|
||||||
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
|
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
|
||||||
rwy = arr->getRunwayByIdent(activeRunway);
|
rwy = arr->getRunwayByIdent(activeRunway);
|
||||||
// begin descent 110km out
|
// 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);
|
waypoints.push_back(wpt);
|
||||||
|
wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
|
||||||
|
waypoints.push_back(wpt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,110 @@
|
||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "trafficcontrol.hxx"
|
#include "trafficcontrol.hxx"
|
||||||
#include <AIModel/AIAircraft.hxx>
|
#include <AIModel/AIAircraft.hxx>
|
||||||
#include <AIModel/AIFlightPlan.hxx>
|
#include <AIModel/AIFlightPlan.hxx>
|
||||||
|
#include <AIModel/performancedata.hxx>
|
||||||
|
#include <AIModel/performancedb.hxx>
|
||||||
#include <Traffic/TrafficMgr.hxx>
|
#include <Traffic/TrafficMgr.hxx>
|
||||||
#include <Airports/groundnetwork.hxx>
|
#include <Airports/groundnetwork.hxx>
|
||||||
#include <Airports/dynamics.hxx>
|
#include <Airports/dynamics.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
using std::sort;
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* ActiveRunway
|
||||||
|
**************************************************************************/
|
||||||
|
time_t ActiveRunway::requestTimeSlot(time_t eta)
|
||||||
|
{
|
||||||
|
time_t newEta;
|
||||||
|
time_t separation = 90;
|
||||||
|
bool found = false;
|
||||||
|
if (estimatedArrivalTimes.size() == 0) {
|
||||||
|
estimatedArrivalTimes.push_back(eta);
|
||||||
|
return eta;
|
||||||
|
} else {
|
||||||
|
TimeVectorIterator i = estimatedArrivalTimes.begin();
|
||||||
|
//cerr << "Checking eta slots " << eta << ": " << endl;
|
||||||
|
for (i = estimatedArrivalTimes.begin();
|
||||||
|
i != estimatedArrivalTimes.end(); i++) {
|
||||||
|
//cerr << "Stored time : " << (*i) << endl;
|
||||||
|
}
|
||||||
|
i = estimatedArrivalTimes.begin();
|
||||||
|
if ((eta + separation) < (*i)) {
|
||||||
|
newEta = eta;
|
||||||
|
found = true;
|
||||||
|
//cerr << "Storing at beginning" << endl;
|
||||||
|
}
|
||||||
|
while ((i != estimatedArrivalTimes.end()) && (!found)) {
|
||||||
|
TimeVectorIterator j = i + 1;
|
||||||
|
if (j == estimatedArrivalTimes.end()) {
|
||||||
|
if (((*i) + separation) < eta) {
|
||||||
|
//cerr << "Storing at end" << endl;
|
||||||
|
newEta = eta;
|
||||||
|
} else {
|
||||||
|
newEta = (*i) + separation;
|
||||||
|
//cerr << "Storing at end + separation" << endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((((*j) - (*i)) > (separation * 2))) { // found a potential slot
|
||||||
|
// now check whether this slow is usable:
|
||||||
|
// 1) eta should fall between the two points
|
||||||
|
// i.e. eta > i AND eta < j
|
||||||
|
//
|
||||||
|
//cerr << "Found potential slot after " << (*i) << endl;
|
||||||
|
if (eta > (*i) && (eta < (*j))) {
|
||||||
|
found = true;
|
||||||
|
if (eta < ((*i) + separation)) {
|
||||||
|
newEta = (*i) + separation;
|
||||||
|
//cerr << "Using original" << (*i) << " + separation " << endl;
|
||||||
|
} else {
|
||||||
|
newEta = eta;
|
||||||
|
//cerr << "Using original after " << (*i) << endl;
|
||||||
|
}
|
||||||
|
} else if (eta < (*i)) {
|
||||||
|
found = true;
|
||||||
|
newEta = (*i) + separation;
|
||||||
|
//cerr << "Using delayed slot after " << (*i) << endl;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if (((*j) - separation) < eta) {
|
||||||
|
found = true;
|
||||||
|
if (((*i) + separation) < eta) {
|
||||||
|
newEta = eta;
|
||||||
|
cerr << "Using original after " << (*i) << endl;
|
||||||
|
} else {
|
||||||
|
newEta = (*i) + separation;
|
||||||
|
cerr << "Using " << (*i) << " + separation " << endl;
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//cerr << ". done. New ETA : " << newEta << endl;
|
||||||
|
|
||||||
|
estimatedArrivalTimes.push_back(newEta);
|
||||||
|
sort(estimatedArrivalTimes.begin(), estimatedArrivalTimes.end());
|
||||||
|
// do some housekeeping : remove any timestamps that are past
|
||||||
|
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||||
|
TimeVectorIterator i = estimatedArrivalTimes.begin();
|
||||||
|
while (i != estimatedArrivalTimes.end()) {
|
||||||
|
if ((*i) < now) {
|
||||||
|
//cerr << "Deleting timestamp " << (*i) << " (now = " << now << "). " << endl;
|
||||||
|
estimatedArrivalTimes.erase(i);
|
||||||
|
i = estimatedArrivalTimes.begin();
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newEta;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* FGTrafficRecord
|
* FGTrafficRecord
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
@ -41,25 +138,23 @@ FGTrafficRecord::FGTrafficRecord() :
|
||||||
frequencyId(0),
|
frequencyId(0),
|
||||||
state(0),
|
state(0),
|
||||||
allowTransmission(true),
|
allowTransmission(true),
|
||||||
latitude(0),
|
latitude(0), longitude(0), heading(0), speed(0), altitude(0), radius(0)
|
||||||
longitude(0),
|
|
||||||
heading(0),
|
|
||||||
speed(0),
|
|
||||||
altitude(0),
|
|
||||||
radius(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGTrafficRecord::setPositionAndIntentions(int pos, FGAIFlightPlan *route)
|
void FGTrafficRecord::setPositionAndIntentions(int pos,
|
||||||
|
FGAIFlightPlan * route)
|
||||||
{
|
{
|
||||||
|
|
||||||
currentPos = pos;
|
currentPos = pos;
|
||||||
if (intentions.size()) {
|
if (intentions.size()) {
|
||||||
intVecIterator i = intentions.begin();
|
intVecIterator i = intentions.begin();
|
||||||
if ((*i) != pos) {
|
if ((*i) != pos) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "Error in FGTrafficRecord::setPositionAndIntentions");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"Error in FGTrafficRecord::setPositionAndIntentions");
|
||||||
//cerr << "Pos : " << pos << " Curr " << *(intentions.begin()) << endl;
|
//cerr << "Pos : " << pos << " Curr " << *(intentions.begin()) << endl;
|
||||||
for (intVecIterator i = intentions.begin(); i != intentions.end() ; i++) {
|
for (intVecIterator i = intentions.begin();
|
||||||
|
i != intentions.end(); i++) {
|
||||||
//cerr << (*i) << " ";
|
//cerr << (*i) << " ";
|
||||||
}
|
}
|
||||||
//cerr << endl;
|
//cerr << endl;
|
||||||
|
@ -73,8 +168,7 @@ void FGTrafficRecord::setPositionAndIntentions(int pos, FGAIFlightPlan *route)
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
int val = route->getRouteIndex(i);
|
int val = route->getRouteIndex(i);
|
||||||
//cerr << val<< " ";
|
//cerr << val<< " ";
|
||||||
if ((val) && (val != pos))
|
if ((val) && (val != pos)) {
|
||||||
{
|
|
||||||
intentions.push_back(val);
|
intentions.push_back(val);
|
||||||
//cerr << "[set] ";
|
//cerr << "[set] ";
|
||||||
}
|
}
|
||||||
|
@ -92,8 +186,7 @@ bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord &other)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
//cerr << "Start check 1" << endl;
|
//cerr << "Start check 1" << endl;
|
||||||
if (currentPos == other.currentPos)
|
if (currentPos == other.currentPos) {
|
||||||
{
|
|
||||||
//cerr << callsign << ": Check Position and intentions: we are on the same taxiway" << other.callsign << "Index = " << currentPos << endl;
|
//cerr << callsign << ": Check Position and intentions: we are on the same taxiway" << other.callsign << "Index = " << currentPos << endl;
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
@ -126,8 +219,9 @@ bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord &other)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGTrafficRecord::setPositionAndHeading(double lat, double lon, double hdg,
|
void FGTrafficRecord::setPositionAndHeading(double lat, double lon,
|
||||||
double spd, double alt)
|
double hdg, double spd,
|
||||||
|
double alt)
|
||||||
{
|
{
|
||||||
latitude = lat;
|
latitude = lat;
|
||||||
longitude = lon;
|
longitude = lon;
|
||||||
|
@ -136,9 +230,11 @@ void FGTrafficRecord::setPositionAndHeading(double lat, double lon, double hdg,
|
||||||
altitude = alt;
|
altitude = alt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FGTrafficRecord::crosses(FGGroundNetwork *net, FGTrafficRecord &other)
|
int FGTrafficRecord::crosses(FGGroundNetwork * net,
|
||||||
|
FGTrafficRecord & other)
|
||||||
{
|
{
|
||||||
if (checkPositionAndIntentions(other) || (other.checkPositionAndIntentions(*this)))
|
if (checkPositionAndIntentions(other)
|
||||||
|
|| (other.checkPositionAndIntentions(*this)))
|
||||||
return -1;
|
return -1;
|
||||||
intVecIterator i, j;
|
intVecIterator i, j;
|
||||||
int currentTargetNode = 0, otherTargetNode = 0;
|
int currentTargetNode = 0, otherTargetNode = 0;
|
||||||
|
@ -148,44 +244,40 @@ int FGTrafficRecord::crosses(FGGroundNetwork *net, FGTrafficRecord &other)
|
||||||
otherTargetNode = net->findSegment(other.currentPos)->getEnd()->getIndex(); // OKAY,...
|
otherTargetNode = net->findSegment(other.currentPos)->getEnd()->getIndex(); // OKAY,...
|
||||||
if ((currentTargetNode == otherTargetNode) && currentTargetNode > 0)
|
if ((currentTargetNode == otherTargetNode) && currentTargetNode > 0)
|
||||||
return currentTargetNode;
|
return currentTargetNode;
|
||||||
if (intentions.size())
|
if (intentions.size()) {
|
||||||
{
|
for (i = intentions.begin(); i != intentions.end(); i++) {
|
||||||
for (i = intentions.begin(); i != intentions.end(); i++)
|
|
||||||
{
|
|
||||||
if ((*i) > 0) {
|
if ((*i) > 0) {
|
||||||
if ((currentTargetNode == net->findSegment(*i)->getEnd()->getIndex()))
|
if ((currentTargetNode ==
|
||||||
{
|
net->findSegment(*i)->getEnd()->getIndex())) {
|
||||||
//cerr << "Current crosses at " << currentTargetNode <<endl;
|
//cerr << "Current crosses at " << currentTargetNode <<endl;
|
||||||
return currentTargetNode;
|
return currentTargetNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (other.intentions.size())
|
if (other.intentions.size()) {
|
||||||
{
|
for (i = other.intentions.begin(); i != other.intentions.end();
|
||||||
for (i = other.intentions.begin(); i != other.intentions.end(); i++)
|
i++) {
|
||||||
{
|
|
||||||
if ((*i) > 0) {
|
if ((*i) > 0) {
|
||||||
if (otherTargetNode == net->findSegment(*i)->getEnd()->getIndex())
|
if (otherTargetNode ==
|
||||||
{
|
net->findSegment(*i)->getEnd()->getIndex()) {
|
||||||
//cerr << "Other crosses at " << currentTargetNode <<endl;
|
//cerr << "Other crosses at " << currentTargetNode <<endl;
|
||||||
return otherTargetNode;
|
return otherTargetNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (intentions.size() && other.intentions.size())
|
if (intentions.size() && other.intentions.size()) {
|
||||||
{
|
for (i = intentions.begin(); i != intentions.end(); i++) {
|
||||||
for (i = intentions.begin(); i != intentions.end(); i++)
|
for (j = other.intentions.begin(); j != other.intentions.end();
|
||||||
{
|
j++) {
|
||||||
for (j = other.intentions.begin(); j != other.intentions.end(); j++)
|
|
||||||
{
|
|
||||||
//cerr << "finding segment " << *i << " and " << *j << endl;
|
//cerr << "finding segment " << *i << " and " << *j << endl;
|
||||||
if (((*i) > 0) && ((*j) > 0)) {
|
if (((*i) > 0) && ((*j) > 0)) {
|
||||||
currentTargetNode = net->findSegment(*i)->getEnd()->getIndex();
|
currentTargetNode =
|
||||||
otherTargetNode = net->findSegment(*j)->getEnd()->getIndex();
|
net->findSegment(*i)->getEnd()->getIndex();
|
||||||
if (currentTargetNode == otherTargetNode)
|
otherTargetNode =
|
||||||
{
|
net->findSegment(*j)->getEnd()->getIndex();
|
||||||
|
if (currentTargetNode == otherTargetNode) {
|
||||||
//cerr << "Routes will cross at " << currentTargetNode << endl;
|
//cerr << "Routes will cross at " << currentTargetNode << endl;
|
||||||
return currentTargetNode;
|
return currentTargetNode;
|
||||||
}
|
}
|
||||||
|
@ -196,21 +288,21 @@ int FGTrafficRecord::crosses(FGGroundNetwork *net, FGTrafficRecord &other)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FGTrafficRecord::onRoute(FGGroundNetwork *net, FGTrafficRecord &other)
|
bool FGTrafficRecord::onRoute(FGGroundNetwork * net,
|
||||||
|
FGTrafficRecord & other)
|
||||||
{
|
{
|
||||||
int node = -1, othernode = -1;
|
int node = -1, othernode = -1;
|
||||||
if (currentPos > 0)
|
if (currentPos > 0)
|
||||||
node = net->findSegment(currentPos)->getEnd()->getIndex();
|
node = net->findSegment(currentPos)->getEnd()->getIndex();
|
||||||
if (other.currentPos > 0)
|
if (other.currentPos > 0)
|
||||||
othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
|
othernode =
|
||||||
|
net->findSegment(other.currentPos)->getEnd()->getIndex();
|
||||||
if ((node == othernode) && (node != -1))
|
if ((node == othernode) && (node != -1))
|
||||||
return true;
|
return true;
|
||||||
if (other.intentions.size())
|
if (other.intentions.size()) {
|
||||||
{
|
for (intVecIterator i = other.intentions.begin();
|
||||||
for (intVecIterator i = other.intentions.begin(); i != other.intentions.end(); i++)
|
i != other.intentions.end(); i++) {
|
||||||
{
|
if (*i > 0) {
|
||||||
if (*i > 0)
|
|
||||||
{
|
|
||||||
othernode = net->findSegment(*i)->getEnd()->getIndex();
|
othernode = net->findSegment(*i)->getEnd()->getIndex();
|
||||||
if ((node == othernode) && (node > -1))
|
if ((node == othernode) && (node > -1))
|
||||||
return true;
|
return true;
|
||||||
|
@ -235,27 +327,27 @@ bool FGTrafficRecord::onRoute(FGGroundNetwork *net, FGTrafficRecord &other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FGTrafficRecord::isOpposing (FGGroundNetwork *net, FGTrafficRecord &other, int node)
|
bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
|
||||||
|
FGTrafficRecord & other, int node)
|
||||||
{
|
{
|
||||||
// Check if current segment is the reverse segment for the other aircraft
|
// Check if current segment is the reverse segment for the other aircraft
|
||||||
FGTaxiSegment *opp;
|
FGTaxiSegment *opp;
|
||||||
//cerr << "Current segment " << currentPos << endl;
|
//cerr << "Current segment " << currentPos << endl;
|
||||||
if ((currentPos > 0) && (other.currentPos > 0))
|
if ((currentPos > 0) && (other.currentPos > 0)) {
|
||||||
{
|
|
||||||
opp = net->findSegment(currentPos)->opposite();
|
opp = net->findSegment(currentPos)->opposite();
|
||||||
if (opp) {
|
if (opp) {
|
||||||
if (opp->getIndex() == other.currentPos)
|
if (opp->getIndex() == other.currentPos)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
|
for (intVecIterator i = intentions.begin(); i != intentions.end();
|
||||||
{
|
i++) {
|
||||||
if ((opp = net->findSegment(other.currentPos)->opposite()))
|
if ((opp = net->findSegment(other.currentPos)->opposite())) {
|
||||||
{
|
|
||||||
if ((*i) > 0)
|
if ((*i) > 0)
|
||||||
if (opp->getIndex() == net->findSegment(*i)->getIndex())
|
if (opp->getIndex() ==
|
||||||
{
|
net->findSegment(*i)->getIndex()) {
|
||||||
if (net->findSegment(*i)->getStart()->getIndex() == node) {
|
if (net->findSegment(*i)->getStart()->getIndex() ==
|
||||||
|
node) {
|
||||||
{
|
{
|
||||||
//cerr << "Found the node " << node << endl;
|
//cerr << "Found the node " << node << endl;
|
||||||
return true;
|
return true;
|
||||||
|
@ -263,21 +355,19 @@ bool FGTrafficRecord::isOpposing (FGGroundNetwork *net, FGTrafficRecord &other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (other.intentions.size())
|
if (other.intentions.size()) {
|
||||||
{
|
for (intVecIterator j = other.intentions.begin();
|
||||||
for (intVecIterator j = other.intentions.begin(); j != other.intentions.end(); j++)
|
j != other.intentions.end(); j++) {
|
||||||
{
|
|
||||||
// cerr << "Current segment 1 " << (*i) << endl;
|
// cerr << "Current segment 1 " << (*i) << endl;
|
||||||
if ((*i) > 0) {
|
if ((*i) > 0) {
|
||||||
if ((opp = net->findSegment(*i)->opposite()))
|
if ((opp = net->findSegment(*i)->opposite())) {
|
||||||
{
|
|
||||||
if (opp->getIndex() ==
|
if (opp->getIndex() ==
|
||||||
net->findSegment(*j)->getIndex())
|
net->findSegment(*j)->getIndex()) {
|
||||||
{
|
|
||||||
//cerr << "Nodes " << net->findSegment(*i)->getIndex()
|
//cerr << "Nodes " << net->findSegment(*i)->getIndex()
|
||||||
// << " and " << net->findSegment(*j)->getIndex()
|
// << " and " << net->findSegment(*j)->getIndex()
|
||||||
// << " are opposites " << endl;
|
// << " are opposites " << endl;
|
||||||
if (net->findSegment(*i)->getStart()->getIndex() == node) {
|
if (net->findSegment(*i)->getStart()->
|
||||||
|
getIndex() == node) {
|
||||||
{
|
{
|
||||||
//cerr << "Found the node " << node << endl;
|
//cerr << "Found the node " << node << endl;
|
||||||
return true;
|
return true;
|
||||||
|
@ -305,11 +395,11 @@ void FGTrafficRecord::setHeadingAdjustment(double heading)
|
||||||
instruction.setHeading(heading);
|
instruction.setHeading(heading);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FGTrafficRecord::pushBackAllowed() {
|
bool FGTrafficRecord::pushBackAllowed()
|
||||||
|
{
|
||||||
double course, az2, dist;
|
double course, az2, dist;
|
||||||
SGGeod curr(SGGeod::fromDegM(getLongitude(),
|
SGGeod curr(SGGeod::fromDegM(getLongitude(),
|
||||||
getLatitude(),
|
getLatitude(), getAltitude()));
|
||||||
getAltitude()));
|
|
||||||
|
|
||||||
double userLatitude = fgGetDouble("/position/latitude-deg");
|
double userLatitude = fgGetDouble("/position/latitude-deg");
|
||||||
double userLongitude = fgGetDouble("/position/longitude-deg");
|
double userLongitude = fgGetDouble("/position/longitude-deg");
|
||||||
|
@ -343,7 +433,8 @@ FGATCInstruction::FGATCInstruction()
|
||||||
|
|
||||||
bool FGATCInstruction::hasInstruction()
|
bool FGATCInstruction::hasInstruction()
|
||||||
{
|
{
|
||||||
return (holdPattern || holdPosition || changeSpeed || changeHeading || changeAltitude || resolveCircularWait);
|
return (holdPattern || holdPosition || changeSpeed || changeHeading
|
||||||
|
|| changeAltitude || resolveCircularWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
@ -366,7 +457,8 @@ string FGATCController::getGateName(FGAIAircraft *ref)
|
||||||
return ref->atGate();
|
return ref->atGate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir)
|
void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
|
||||||
|
AtcMsgDir msgDir)
|
||||||
{
|
{
|
||||||
string sender, receiver;
|
string sender, receiver;
|
||||||
int stationFreq = 0;
|
int stationFreq = 0;
|
||||||
|
@ -392,14 +484,22 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
|
||||||
case 3:
|
case 3:
|
||||||
freqId = rec->getNextFrequency();
|
freqId = rec->getNextFrequency();
|
||||||
stationFreq =
|
stationFreq =
|
||||||
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency(rec->getLeg()+freqId);
|
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
|
||||||
|
getDynamics()->getGroundFrequency(rec->getLeg() + freqId);
|
||||||
taxiFreq =
|
taxiFreq =
|
||||||
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency(3);
|
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
|
||||||
receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
|
getDynamics()->getGroundFrequency(3);
|
||||||
atisInformation = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getAtisInformation();
|
receiver =
|
||||||
|
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
|
||||||
|
getName() + "-Ground";
|
||||||
|
atisInformation =
|
||||||
|
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
|
||||||
|
getDynamics()->getAtisInformation();
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Tower";
|
receiver =
|
||||||
|
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
|
||||||
|
getName() + "-Tower";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Swap sender and receiver value in case of a ground to air transmission
|
// Swap sender and receiver value in case of a ground to air transmission
|
||||||
|
@ -413,10 +513,14 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
|
||||||
text = sender + ". Ready to Start up";
|
text = sender + ". Ready to Start up";
|
||||||
break;
|
break;
|
||||||
case MSG_REQUEST_ENGINE_START:
|
case MSG_REQUEST_ENGINE_START:
|
||||||
text = receiver + ", This is " + sender + ". Position " +getGateName(rec->getAircraft()) +
|
text =
|
||||||
". Information " + atisInformation + ". " +
|
receiver + ", This is " + sender + ". Position " +
|
||||||
rec->getAircraft()->getTrafficRef()->getFlightRules() + " to " +
|
getGateName(rec->getAircraft()) + ". Information " +
|
||||||
rec->getAircraft()->getTrafficRef()->getArrivalAirport()->getName() + ". Request start-up";
|
atisInformation + ". " +
|
||||||
|
rec->getAircraft()->getTrafficRef()->getFlightRules() +
|
||||||
|
" to " +
|
||||||
|
rec->getAircraft()->getTrafficRef()->getArrivalAirport()->
|
||||||
|
getName() + ". Request start-up";
|
||||||
break;
|
break;
|
||||||
// Acknowledge engine startup permission
|
// Acknowledge engine startup permission
|
||||||
// Assign departure runway
|
// Assign departure runway
|
||||||
|
@ -426,11 +530,16 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
|
||||||
|
|
||||||
heading = rec->getAircraft()->getTrafficRef()->getCourse();
|
heading = rec->getAircraft()->getTrafficRef()->getCourse();
|
||||||
fltType = rec->getAircraft()->getTrafficRef()->getFlightType();
|
fltType = rec->getAircraft()->getTrafficRef()->getFlightType();
|
||||||
rwyClass= rec->getAircraft()->GetFlightPlan()->getRunwayClassFromTrafficType(fltType);
|
rwyClass =
|
||||||
|
rec->getAircraft()->GetFlightPlan()->
|
||||||
|
getRunwayClassFromTrafficType(fltType);
|
||||||
|
|
||||||
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
|
rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
|
||||||
|
getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
|
||||||
|
heading);
|
||||||
rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
|
rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
|
||||||
fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getSID(activeRunway, heading);
|
fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
|
||||||
|
getDynamics()->getSID(activeRunway, heading);
|
||||||
rec->getAircraft()->GetFlightPlan()->setSID(fp);
|
rec->getAircraft()->GetFlightPlan()->setSID(fp);
|
||||||
if (fp) {
|
if (fp) {
|
||||||
SID = fp->getName() + " departure";
|
SID = fp->getName() + " departure";
|
||||||
|
@ -441,9 +550,12 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
|
||||||
fltRules = rec->getAircraft()->getTrafficRef()->getFlightRules();
|
fltRules = rec->getAircraft()->getTrafficRef()->getFlightRules();
|
||||||
transponderCode = genTransponderCode(fltRules);
|
transponderCode = genTransponderCode(fltRules);
|
||||||
rec->getAircraft()->SetTransponderCode(transponderCode);
|
rec->getAircraft()->SetTransponderCode(transponderCode);
|
||||||
text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " + activeRunway
|
text =
|
||||||
+ ", " + SID + ", squawk " + transponderCode + ". " +
|
receiver + ". Start-up approved. " + atisInformation +
|
||||||
"For push-back and taxi clearance call " + taxiFreqStr + ". " + sender + " control.";
|
" correct, runway " + activeRunway + ", " + SID + ", squawk " +
|
||||||
|
transponderCode + ". " +
|
||||||
|
"For push-back and taxi clearance call " + taxiFreqStr + ". " +
|
||||||
|
sender + " control.";
|
||||||
break;
|
break;
|
||||||
case MSG_DENY_ENGINE_START:
|
case MSG_DENY_ENGINE_START:
|
||||||
text = receiver + ". Standby";
|
text = receiver + ". Standby";
|
||||||
|
@ -451,16 +563,21 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
|
||||||
case MSG_ACKNOWLEDGE_ENGINE_START:
|
case MSG_ACKNOWLEDGE_ENGINE_START:
|
||||||
fp = rec->getAircraft()->GetFlightPlan()->getSID();
|
fp = rec->getAircraft()->GetFlightPlan()->getSID();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
SID = rec->getAircraft()->GetFlightPlan()->getSID()->getName() + " departure";
|
SID =
|
||||||
|
rec->getAircraft()->GetFlightPlan()->getSID()->getName() +
|
||||||
|
" departure";
|
||||||
} else {
|
} else {
|
||||||
SID = "fly runway heading ";
|
SID = "fly runway heading ";
|
||||||
}
|
}
|
||||||
taxiFreqStr = formatATCFrequency3_2(taxiFreq);
|
taxiFreqStr = formatATCFrequency3_2(taxiFreq);
|
||||||
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
|
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
|
||||||
transponderCode = rec->getAircraft()->GetTransponderCode();
|
transponderCode = rec->getAircraft()->GetTransponderCode();
|
||||||
text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " +
|
text =
|
||||||
activeRunway + ", " + SID + ", squawk " + transponderCode + ". " +
|
receiver + ". Start-up approved. " + atisInformation +
|
||||||
"For push-back and taxi clearance call " + taxiFreqStr + ". " + sender;
|
" correct, runway " + activeRunway + ", " + SID + ", squawk " +
|
||||||
|
transponderCode + ". " +
|
||||||
|
"For push-back and taxi clearance call " + taxiFreqStr + ". " +
|
||||||
|
sender;
|
||||||
break;
|
break;
|
||||||
case MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY:
|
case MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY:
|
||||||
taxiFreqStr = formatATCFrequency3_2(taxiFreq);
|
taxiFreqStr = formatATCFrequency3_2(taxiFreq);
|
||||||
|
@ -506,8 +623,10 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
|
||||||
text = text + sender + ". Transmitting unknown Message";
|
text = text + sender + ". Transmitting unknown Message";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
double onBoardRadioFreq0 = fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
|
double onBoardRadioFreq0 =
|
||||||
double onBoardRadioFreq1 = fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
|
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 onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
|
||||||
int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
|
int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
|
||||||
//cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
|
//cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
|
||||||
|
@ -515,14 +634,16 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
|
||||||
// Display ATC message only when one of the radios is tuned
|
// Display ATC message only when one of the radios is tuned
|
||||||
// the relevant frequency.
|
// the relevant frequency.
|
||||||
// Note that distance attenuation is currently not yet implemented
|
// Note that distance attenuation is currently not yet implemented
|
||||||
if ((onBoardRadioFreqI0 == stationFreq) || (onBoardRadioFreqI1 == stationFreq)) {
|
if ((onBoardRadioFreqI0 == stationFreq)
|
||||||
|
|| (onBoardRadioFreqI1 == stationFreq)) {
|
||||||
if (rec->allowTransmissions()) {
|
if (rec->allowTransmissions()) {
|
||||||
fgSetString("/sim/messages/atc", text.c_str());
|
fgSetString("/sim/messages/atc", text.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string FGATCController::formatATCFrequency3_2(int freq) {
|
string FGATCController::formatATCFrequency3_2(int freq)
|
||||||
|
{
|
||||||
char buffer[7];
|
char buffer[7];
|
||||||
snprintf(buffer, 7, "%3.2f", ((float) freq / 100.0));
|
snprintf(buffer, 7, "%3.2f", ((float) freq / 100.0));
|
||||||
return string(buffer);
|
return string(buffer);
|
||||||
|
@ -530,12 +651,14 @@ string FGATCController::formatATCFrequency3_2(int freq) {
|
||||||
|
|
||||||
// TODO: Set transponder codes according to real-world routes.
|
// TODO: Set transponder codes according to real-world routes.
|
||||||
// The current version just returns a random string of four octal numbers.
|
// The current version just returns a random string of four octal numbers.
|
||||||
string FGATCController::genTransponderCode(string fltRules) {
|
string FGATCController::genTransponderCode(string fltRules)
|
||||||
|
{
|
||||||
if (fltRules == "VFR") {
|
if (fltRules == "VFR") {
|
||||||
return string("1200");
|
return string("1200");
|
||||||
} else {
|
} else {
|
||||||
char buffer[5];
|
char buffer[5];
|
||||||
snprintf(buffer, 5, "%d%d%d%d", rand() % 8, rand() % 8,rand() % 8, rand() % 8);
|
snprintf(buffer, 5, "%d%d%d%d", rand() % 8, rand() % 8, rand() % 8,
|
||||||
|
rand() % 8);
|
||||||
return string(buffer);
|
return string(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -550,9 +673,12 @@ FGTowerController::FGTowerController() :
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
void FGTowerController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
|
void FGTowerController::announcePosition(int id,
|
||||||
double lat, double lon, double heading,
|
FGAIFlightPlan * intendedRoute,
|
||||||
double speed, double alt, double radius, int leg,
|
int currentPosition, double lat,
|
||||||
|
double lon, double heading,
|
||||||
|
double speed, double alt,
|
||||||
|
double radius, int leg,
|
||||||
FGAIAircraft * ref)
|
FGAIAircraft * ref)
|
||||||
{
|
{
|
||||||
TrafficVectorIterator i = activeTraffic.begin();
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
@ -567,7 +693,6 @@ void FGTowerController::announcePosition(int id, FGAIFlightPlan *intendedRoute,
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new TrafficRecord if no one exsists for this aircraft.
|
// Add a new TrafficRecord if no one exsists for this aircraft.
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
FGTrafficRecord rec;
|
FGTrafficRecord rec;
|
||||||
|
@ -584,11 +709,12 @@ void FGTowerController::announcePosition(int id, FGAIFlightPlan *intendedRoute,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGTowerController::update(int id, double lat, double lon, double heading, double speed, double alt,
|
void FGTowerController::update(int id, double lat, double lon,
|
||||||
|
double heading, double speed, double alt,
|
||||||
double dt)
|
double dt)
|
||||||
{
|
{
|
||||||
TrafficVectorIterator i = activeTraffic.begin();
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
// Search search if the current id has an entry
|
// Search whether the current id has an entry
|
||||||
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||||
TrafficVectorIterator current, closest;
|
TrafficVectorIterator current, closest;
|
||||||
if (activeTraffic.size()) {
|
if (activeTraffic.size()) {
|
||||||
|
@ -600,10 +726,10 @@ void FGTowerController::update(int id, double lat, double lon, double heading, d
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // update position of the current aircraft
|
// // update position of the current aircraft
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: updating aircraft without traffic record");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: updating aircraft without traffic record");
|
||||||
} else {
|
} else {
|
||||||
i->setPositionAndHeading(lat, lon, heading, speed, alt);
|
i->setPositionAndHeading(lat, lon, heading, speed, alt);
|
||||||
current = i;
|
current = i;
|
||||||
|
@ -626,8 +752,7 @@ void FGTowerController::update(int id, double lat, double lon, double heading, d
|
||||||
ActiveRunway aRwy(current->getRunway(), id);
|
ActiveRunway aRwy(current->getRunway(), id);
|
||||||
activeRunways.push_back(aRwy); // Since there are no clearance records for this runway yet
|
activeRunways.push_back(aRwy); // Since there are no clearance records for this runway yet
|
||||||
current->setHoldPosition(false); // Clear the current aircraft to continue
|
current->setHoldPosition(false); // Clear the current aircraft to continue
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Okay, we have a clearance record for this runway, so check
|
// Okay, we have a clearance record for this runway, so check
|
||||||
// whether the clearence ID matches that of the current aircraft
|
// whether the clearence ID matches that of the current aircraft
|
||||||
if (id == rwy->getCleared()) {
|
if (id == rwy->getCleared()) {
|
||||||
|
@ -666,11 +791,13 @@ void FGTowerController::signOff(int id)
|
||||||
if (rwy != activeRunways.end()) {
|
if (rwy != activeRunways.end()) {
|
||||||
rwy = activeRunways.erase(rwy);
|
rwy = activeRunways.erase(rwy);
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: Aircraft without traffic record is signing off from tower");
|
||||||
} else {
|
} else {
|
||||||
i = activeTraffic.erase(i);
|
i = activeTraffic.erase(i);
|
||||||
}
|
}
|
||||||
|
@ -687,8 +814,7 @@ bool FGTowerController::hasInstruction(int id)
|
||||||
TrafficVectorIterator i = activeTraffic.begin();
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
// Search search if the current id has an entry
|
// Search search if the current id has an entry
|
||||||
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||||
if (activeTraffic.size())
|
if (activeTraffic.size()) {
|
||||||
{
|
|
||||||
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
||||||
while (i != activeTraffic.end()) {
|
while (i != activeTraffic.end()) {
|
||||||
if (i->getId() == id) {
|
if (i->getId() == id) {
|
||||||
|
@ -698,7 +824,8 @@ bool FGTowerController::hasInstruction(int id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: checking ATC instruction for aircraft without traffic record");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: checking ATC instruction for aircraft without traffic record");
|
||||||
} else {
|
} else {
|
||||||
return i->hasInstruction();
|
return i->hasInstruction();
|
||||||
}
|
}
|
||||||
|
@ -721,7 +848,8 @@ FGATCInstruction FGTowerController::getInstruction(int id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: requesting ATC instruction for aircraft without traffic record");
|
||||||
} else {
|
} else {
|
||||||
return i->getInstruction();
|
return i->getInstruction();
|
||||||
}
|
}
|
||||||
|
@ -737,9 +865,12 @@ FGStartupController::FGStartupController() :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGStartupController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
|
void FGStartupController::announcePosition(int id,
|
||||||
double lat, double lon, double heading,
|
FGAIFlightPlan * intendedRoute,
|
||||||
double speed, double alt, double radius, int leg,
|
int currentPosition, double lat,
|
||||||
|
double lon, double heading,
|
||||||
|
double speed, double alt,
|
||||||
|
double radius, int leg,
|
||||||
FGAIAircraft * ref)
|
FGAIAircraft * ref)
|
||||||
{
|
{
|
||||||
TrafficVectorIterator i = activeTraffic.begin();
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
@ -754,7 +885,6 @@ void FGStartupController::announcePosition(int id, FGAIFlightPlan *intendedRoute
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new TrafficRecord if no one exsists for this aircraft.
|
// Add a new TrafficRecord if no one exsists for this aircraft.
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
FGTrafficRecord rec;
|
FGTrafficRecord rec;
|
||||||
|
@ -784,8 +914,7 @@ bool FGStartupController::hasInstruction(int id)
|
||||||
TrafficVectorIterator i = activeTraffic.begin();
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
// Search search if the current id has an entry
|
// Search search if the current id has an entry
|
||||||
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||||
if (activeTraffic.size())
|
if (activeTraffic.size()) {
|
||||||
{
|
|
||||||
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
||||||
while (i != activeTraffic.end()) {
|
while (i != activeTraffic.end()) {
|
||||||
if (i->getId() == id) {
|
if (i->getId() == id) {
|
||||||
|
@ -795,7 +924,8 @@ bool FGStartupController::hasInstruction(int id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: checking ATC instruction for aircraft without traffic record");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: checking ATC instruction for aircraft without traffic record");
|
||||||
} else {
|
} else {
|
||||||
return i->hasInstruction();
|
return i->hasInstruction();
|
||||||
}
|
}
|
||||||
|
@ -818,7 +948,8 @@ FGATCInstruction FGStartupController::getInstruction(int id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: requesting ATC instruction for aircraft without traffic record");
|
||||||
} else {
|
} else {
|
||||||
return i->getInstruction();
|
return i->getInstruction();
|
||||||
}
|
}
|
||||||
|
@ -840,13 +971,15 @@ void FGStartupController::signOff(int id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: Aircraft without traffic record is signing off from tower");
|
||||||
} else {
|
} else {
|
||||||
i = activeTraffic.erase(i);
|
i = activeTraffic.erase(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGStartupController::update(int id, double lat, double lon, double heading, double speed, double alt,
|
void FGStartupController::update(int id, double lat, double lon,
|
||||||
|
double heading, double speed, double alt,
|
||||||
double dt)
|
double dt)
|
||||||
{
|
{
|
||||||
TrafficVectorIterator i = activeTraffic.begin();
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
@ -862,10 +995,10 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // update position of the current aircraft
|
// // update position of the current aircraft
|
||||||
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: updating aircraft without traffic record");
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: updating aircraft without traffic record");
|
||||||
} else {
|
} else {
|
||||||
i->setPositionAndHeading(lat, lon, heading, speed, alt);
|
i->setPositionAndHeading(lat, lon, heading, speed, alt);
|
||||||
current = i;
|
current = i;
|
||||||
|
@ -873,7 +1006,8 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
|
||||||
setDt(getDt() + dt);
|
setDt(getDt() + dt);
|
||||||
|
|
||||||
int state = i->getState();
|
int state = i->getState();
|
||||||
time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
|
time_t startTime =
|
||||||
|
i->getAircraft()->getTrafficRef()->getDepartureTime();
|
||||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||||
//cerr << i->getAircraft()->getTrafficRef()->getCallSign()
|
//cerr << i->getAircraft()->getTrafficRef()->getCallSign()
|
||||||
// << " is scheduled to depart in " << startTime-now << " seconds. Available = " << available
|
// << " is scheduled to depart in " << startTime-now << " seconds. Available = " << available
|
||||||
|
@ -910,7 +1044,8 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
|
||||||
}
|
}
|
||||||
if ((state == 3) && available) {
|
if ((state == 3) && available) {
|
||||||
if (now > startTime + 100) {
|
if (now > startTime + 100) {
|
||||||
transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START, ATC_AIR_TO_GROUND);
|
transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START,
|
||||||
|
ATC_AIR_TO_GROUND);
|
||||||
i->updateState();
|
i->updateState();
|
||||||
lastTransmission = now;
|
lastTransmission = now;
|
||||||
available = false;
|
available = false;
|
||||||
|
@ -920,7 +1055,8 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
|
||||||
// on a different frequency, compared to ground control
|
// on a different frequency, compared to ground control
|
||||||
if ((state == 4) && available) {
|
if ((state == 4) && available) {
|
||||||
if (now > startTime + 130) {
|
if (now > startTime + 130) {
|
||||||
transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY, ATC_AIR_TO_GROUND);
|
transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
|
||||||
|
ATC_AIR_TO_GROUND);
|
||||||
i->updateState();
|
i->updateState();
|
||||||
i->nextFrequency();
|
i->nextFrequency();
|
||||||
lastTransmission = now;
|
lastTransmission = now;
|
||||||
|
@ -937,19 +1073,20 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
|
||||||
}
|
}
|
||||||
if ((state == 6) && available) {
|
if ((state == 6) && available) {
|
||||||
if (now > startTime + 150) {
|
if (now > startTime + 150) {
|
||||||
transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR);
|
transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT,
|
||||||
|
ATC_GROUND_TO_AIR);
|
||||||
i->updateState();
|
i->updateState();
|
||||||
lastTransmission = now;
|
lastTransmission = now;
|
||||||
available = false;
|
available = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Switch to APRON control and request pushback Clearance.
|
// TODO: Switch to APRON control and request pushback Clearance.
|
||||||
// Get Push back clearance
|
// Get Push back clearance
|
||||||
if ((state == 7) && available) {
|
if ((state == 7) && available) {
|
||||||
if (now > startTime + 180) {
|
if (now > startTime + 180) {
|
||||||
transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
|
transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE,
|
||||||
|
ATC_AIR_TO_GROUND);
|
||||||
i->updateState();
|
i->updateState();
|
||||||
lastTransmission = now;
|
lastTransmission = now;
|
||||||
available = false;
|
available = false;
|
||||||
|
@ -959,10 +1096,12 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
|
||||||
if (now > startTime + 200) {
|
if (now > startTime + 200) {
|
||||||
if (i->pushBackAllowed()) {
|
if (i->pushBackAllowed()) {
|
||||||
i->allowRepeatedTransmissions();
|
i->allowRepeatedTransmissions();
|
||||||
transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
|
transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE,
|
||||||
|
ATC_GROUND_TO_AIR);
|
||||||
i->updateState();
|
i->updateState();
|
||||||
} else {
|
} else {
|
||||||
transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
|
transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE,
|
||||||
|
ATC_GROUND_TO_AIR);
|
||||||
i->suppressRepeatedTransmissions();
|
i->suppressRepeatedTransmissions();
|
||||||
}
|
}
|
||||||
lastTransmission = now;
|
lastTransmission = now;
|
||||||
|
@ -973,3 +1112,194 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
|
||||||
i->setHoldPosition(false);
|
i->setHoldPosition(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* class FGApproachController
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
FGApproachController::FGApproachController():
|
||||||
|
FGATCController()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
void FGApproachController::announcePosition(int id,
|
||||||
|
FGAIFlightPlan * intendedRoute,
|
||||||
|
int currentPosition,
|
||||||
|
double lat, double lon,
|
||||||
|
double heading, double speed,
|
||||||
|
double alt, double radius,
|
||||||
|
int leg, FGAIAircraft * ref)
|
||||||
|
{
|
||||||
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
// Search whether the current id alread has an entry
|
||||||
|
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||||
|
if (activeTraffic.size()) {
|
||||||
|
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
||||||
|
while (i != activeTraffic.end()) {
|
||||||
|
if (i->getId() == id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add a new TrafficRecord if no one exsists for this aircraft.
|
||||||
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
|
FGTrafficRecord rec;
|
||||||
|
rec.setId(id);
|
||||||
|
|
||||||
|
rec.setPositionAndHeading(lat, lon, heading, speed, alt);
|
||||||
|
rec.setRunway(intendedRoute->getRunway());
|
||||||
|
rec.setLeg(leg);
|
||||||
|
//rec.setCallSign(callsign);
|
||||||
|
rec.setAircraft(ref);
|
||||||
|
activeTraffic.push_back(rec);
|
||||||
|
} else {
|
||||||
|
i->setPositionAndHeading(lat, lon, heading, speed, alt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGApproachController::update(int id, double lat, double lon,
|
||||||
|
double heading, double speed, double alt,
|
||||||
|
double dt)
|
||||||
|
{
|
||||||
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
// Search search if the current id has an entry
|
||||||
|
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||||
|
TrafficVectorIterator current, closest;
|
||||||
|
if (activeTraffic.size()) {
|
||||||
|
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
||||||
|
while (i != activeTraffic.end()) {
|
||||||
|
if (i->getId() == id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// // update position of the current aircraft
|
||||||
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: updating aircraft without traffic record");
|
||||||
|
} else {
|
||||||
|
i->setPositionAndHeading(lat, lon, heading, speed, alt);
|
||||||
|
current = i;
|
||||||
|
//cerr << "ApproachController: checking for speed" << endl;
|
||||||
|
time_t time_diff =
|
||||||
|
current->getAircraft()->
|
||||||
|
checkForArrivalTime(string("final001"));
|
||||||
|
if (time_diff > 15) {
|
||||||
|
current->setSpeedAdjustment(current->getAircraft()->
|
||||||
|
getPerformance()->vDescent() *
|
||||||
|
1.35);
|
||||||
|
} else if (time_diff > 5) {
|
||||||
|
current->setSpeedAdjustment(current->getAircraft()->
|
||||||
|
getPerformance()->vDescent() *
|
||||||
|
1.2);
|
||||||
|
} else if (time_diff < -15) {
|
||||||
|
current->setSpeedAdjustment(current->getAircraft()->
|
||||||
|
getPerformance()->vDescent() *
|
||||||
|
0.65);
|
||||||
|
} else if (time_diff < -5) {
|
||||||
|
current->setSpeedAdjustment(current->getAircraft()->
|
||||||
|
getPerformance()->vDescent() *
|
||||||
|
0.8);
|
||||||
|
} else {
|
||||||
|
current->clearSpeedAdjustment();
|
||||||
|
}
|
||||||
|
//current->setSpeedAdjustment(current->getAircraft()->getPerformance()->vDescent() + time_diff);
|
||||||
|
}
|
||||||
|
setDt(getDt() + dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGApproachController::signOff(int id)
|
||||||
|
{
|
||||||
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
// Search search if the current id alread has an entry
|
||||||
|
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||||
|
if (activeTraffic.size()) {
|
||||||
|
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
||||||
|
while (i != activeTraffic.end()) {
|
||||||
|
if (i->getId() == id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: Aircraft without traffic record is signing off from approach");
|
||||||
|
} else {
|
||||||
|
i = activeTraffic.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool FGApproachController::hasInstruction(int id)
|
||||||
|
{
|
||||||
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
// Search search if the current id has an entry
|
||||||
|
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||||
|
if (activeTraffic.size()) {
|
||||||
|
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
||||||
|
while (i != activeTraffic.end()) {
|
||||||
|
if (i->getId() == id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: checking ATC instruction for aircraft without traffic record");
|
||||||
|
} else {
|
||||||
|
return i->hasInstruction();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FGATCInstruction FGApproachController::getInstruction(int id)
|
||||||
|
{
|
||||||
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
// Search search if the current id has an entry
|
||||||
|
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||||
|
if (activeTraffic.size()) {
|
||||||
|
//while ((i->getId() != id) && i != activeTraffic.end()) {
|
||||||
|
while (i != activeTraffic.end()) {
|
||||||
|
if (i->getId() == id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
|
"AI error: requesting ATC instruction for aircraft without traffic record");
|
||||||
|
} else {
|
||||||
|
return i->getInstruction();
|
||||||
|
}
|
||||||
|
return FGATCInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ActiveRunway *FGApproachController::getRunway(string name)
|
||||||
|
{
|
||||||
|
ActiveRunwayVecIterator rwy = activeRunways.begin();
|
||||||
|
if (activeRunways.size()) {
|
||||||
|
while (rwy != activeRunways.end()) {
|
||||||
|
if (rwy->getRunwayName() == name) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rwy++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rwy == activeRunways.end()) {
|
||||||
|
ActiveRunway aRwy(name, 0);
|
||||||
|
activeRunways.push_back(aRwy);
|
||||||
|
rwy = activeRunways.end() - 1;
|
||||||
|
}
|
||||||
|
return &(*rwy);
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#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/debug/logstream.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,6 +187,9 @@ public:
|
||||||
typedef vector<FGTrafficRecord> TrafficVector;
|
typedef vector<FGTrafficRecord> TrafficVector;
|
||||||
typedef vector<FGTrafficRecord>::iterator TrafficVectorIterator;
|
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
|
* Active runway, a utility class to keep track of which aircraft has
|
||||||
|
@ -195,11 +200,18 @@ class ActiveRunway
|
||||||
private:
|
private:
|
||||||
string rwy;
|
string rwy;
|
||||||
int currentlyCleared;
|
int currentlyCleared;
|
||||||
|
double distanceToFinal;
|
||||||
|
TimeVector estimatedArrivalTimes;
|
||||||
public:
|
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; };
|
string getRunwayName() { return rwy; };
|
||||||
int getCleared () { return currentlyCleared; };
|
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;
|
typedef vector<ActiveRunway> ActiveRunwayVec;
|
||||||
|
@ -207,7 +219,7 @@ typedef vector<ActiveRunway>::iterator ActiveRunwayVecIterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class FGATCController
|
* 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
|
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
|
#endif // _TRAFFIC_CONTROL_HXX
|
||||||
|
|
|
@ -325,17 +325,21 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
|
||||||
takeoff.clear();
|
takeoff.clear();
|
||||||
lastUpdate = dayStart;
|
lastUpdate = dayStart;
|
||||||
prevTrafficType = trafficType;
|
prevTrafficType = trafficType;
|
||||||
|
/*
|
||||||
FGEnvironment
|
FGEnvironment
|
||||||
stationweather =
|
stationweather =
|
||||||
((FGEnvironmentMgr *) globals->get_subsystem("environment"))
|
((FGEnvironmentMgr *) globals->get_subsystem("environment"))
|
||||||
->getEnvironment(getLatitude(), getLongitude(),
|
->getEnvironment(getLatitude(), getLongitude(),
|
||||||
getElevation());
|
getElevation());
|
||||||
|
*/
|
||||||
windSpeed = stationweather.get_wind_speed_kt();
|
windSpeed = fgGetInt("/environment/metar/base-wind-speed-kt"); //stationweather.get_wind_speed_kt();
|
||||||
windHeading = stationweather.get_wind_from_heading_deg();
|
windHeading = fgGetInt("/environment/metar/base-wind-dir-deg");
|
||||||
|
//stationweather.get_wind_from_heading_deg();
|
||||||
string scheduleName;
|
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;
|
//cerr << "Nr of seconds since day start << " << dayStart << endl;
|
||||||
|
|
||||||
ScheduleTime *currSched;
|
ScheduleTime *currSched;
|
||||||
|
@ -347,7 +351,7 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
|
||||||
scheduleName = currSched->getName(dayStart);
|
scheduleName = currSched->getName(dayStart);
|
||||||
maxTail = currSched->getTailWind();
|
maxTail = currSched->getTailWind();
|
||||||
maxCross = currSched->getCrossWind();
|
maxCross = currSched->getCrossWind();
|
||||||
//cerr << "SChedule anme = " << scheduleName << endl;
|
//cerr << "Current Schedule = : " << scheduleName << endl;
|
||||||
if (scheduleName.empty())
|
if (scheduleName.empty())
|
||||||
return false;
|
return false;
|
||||||
//cerr << "C"<< endl;
|
//cerr << "C"<< endl;
|
||||||
|
@ -371,6 +375,13 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
|
||||||
currentlyActive = &ulActive;
|
currentlyActive = &ulActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//cerr << "Durrently active selection for " << trafficType << ": ";
|
||||||
|
for (stringVecIterator it = currentlyActive->begin();
|
||||||
|
it != currentlyActive->end(); it++) {
|
||||||
|
//cerr << (*it) << " ";
|
||||||
|
}
|
||||||
|
//cerr << endl;
|
||||||
|
|
||||||
currRunwayGroup->setActive(_ap,
|
currRunwayGroup->setActive(_ap,
|
||||||
windSpeed,
|
windSpeed,
|
||||||
windHeading,
|
windHeading,
|
||||||
|
|
|
@ -52,6 +52,7 @@ private:
|
||||||
FGStartupController startupController;
|
FGStartupController startupController;
|
||||||
FGGroundNetwork groundNetwork;
|
FGGroundNetwork groundNetwork;
|
||||||
FGTowerController towerController;
|
FGTowerController towerController;
|
||||||
|
FGApproachController approachController;
|
||||||
|
|
||||||
time_t lastUpdate;
|
time_t lastUpdate;
|
||||||
string prevTrafficType;
|
string prevTrafficType;
|
||||||
|
@ -115,6 +116,7 @@ public:
|
||||||
FGStartupController *getStartupController() { return &startupController; };
|
FGStartupController *getStartupController() { return &startupController; };
|
||||||
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
|
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
|
||||||
FGTowerController *getTowerController() { return &towerController; };
|
FGTowerController *getTowerController() { return &towerController; };
|
||||||
|
FGApproachController *getApproachController() { return &approachController; };
|
||||||
|
|
||||||
const string& getAtisInformation() { return atisInformation; };
|
const string& getAtisInformation() { return atisInformation; };
|
||||||
int getGroundFrequency(unsigned leg); //{ return freqGround.size() ? freqGround[0] : 0; };
|
int getGroundFrequency(unsigned leg); //{ return freqGround.size() ? freqGround[0] : 0; };
|
||||||
|
|
|
@ -553,19 +553,21 @@ void FGGroundNetwork::update(int id, double lat, double lon,
|
||||||
current->clearResolveCircularWait();
|
current->clearResolveCircularWait();
|
||||||
current->setWaitsForId(0);
|
current->setWaitsForId(0);
|
||||||
checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
|
checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
|
||||||
|
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
|
||||||
|
if (!needsTaxiClearance) {
|
||||||
checkHoldPosition(id, lat, lon, heading, speed, alt);
|
checkHoldPosition(id, lat, lon, heading, speed, alt);
|
||||||
if (checkForCircularWaits(id)) {
|
if (checkForCircularWaits(id)) {
|
||||||
i->setResolveCircularWait();
|
i->setResolveCircularWait();
|
||||||
}
|
}
|
||||||
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
|
} else {
|
||||||
|
current->setHoldPosition(true);
|
||||||
int state = current->getState();
|
int state = current->getState();
|
||||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||||
if ((now - lastTransmission) > 15) {
|
if ((now - lastTransmission) > 15) {
|
||||||
available = true;
|
available = true;
|
||||||
}
|
}
|
||||||
if (needsTaxiClearance && available) {
|
if ((state < 3) && available) {
|
||||||
transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
|
transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
|
||||||
current->getAircraft()->setTaxiClearanceRequest(false);
|
|
||||||
current->setState(3);
|
current->setState(3);
|
||||||
lastTransmission = now;
|
lastTransmission = now;
|
||||||
available = false;
|
available = false;
|
||||||
|
@ -578,10 +580,19 @@ void FGGroundNetwork::update(int id, double lat, double lon,
|
||||||
}
|
}
|
||||||
if ((state == 4) && available) {
|
if ((state == 4) && available) {
|
||||||
transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
|
transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
|
||||||
current->setState(0);
|
current->setState(5);
|
||||||
lastTransmission = now;
|
lastTransmission = now;
|
||||||
available = false;
|
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;
|
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
|
bool FGRunwayBase::isHardSurface() const
|
||||||
{
|
{
|
||||||
return ((_surface_code == 1) || (_surface_code == 2));
|
return ((_surface_code == 1) || (_surface_code == 2));
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
* opposited direction. 0.0 corresponds to the (non-displaced) threshold
|
* opposited direction. 0.0 corresponds to the (non-displaced) threshold
|
||||||
*/
|
*/
|
||||||
SGGeod pointOnCenterline(double aOffset) const;
|
SGGeod pointOnCenterline(double aOffset) const;
|
||||||
|
SGGeod pointOffCenterline(double aOffset, double lateralOffset) const;
|
||||||
|
|
||||||
double lengthFt() const
|
double lengthFt() const
|
||||||
{ return _length; }
|
{ return _length; }
|
||||||
|
|
|
@ -57,7 +57,8 @@ ScheduleTime::ScheduleTime(const ScheduleTime &other)
|
||||||
for (i = other.end.begin(); i != other.end.end(); i++)
|
for (i = other.end.begin(); i != other.end.end(); i++)
|
||||||
end.push_back(*i);
|
end.push_back(*i);
|
||||||
stringVecConstIterator k;
|
stringVecConstIterator k;
|
||||||
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
|
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
|
||||||
|
k++)
|
||||||
scheduleNames.push_back(*k);
|
scheduleNames.push_back(*k);
|
||||||
|
|
||||||
//timeVec end;
|
//timeVec end;
|
||||||
|
@ -77,7 +78,8 @@ ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
|
||||||
for (i = other.end.begin(); i != other.end.end(); i++)
|
for (i = other.end.begin(); i != other.end.end(); i++)
|
||||||
end.push_back(*i);
|
end.push_back(*i);
|
||||||
stringVecConstIterator k;
|
stringVecConstIterator k;
|
||||||
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
|
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
|
||||||
|
k++)
|
||||||
scheduleNames.push_back(*k);
|
scheduleNames.push_back(*k);
|
||||||
|
|
||||||
//timeVec end;
|
//timeVec end;
|
||||||
|
@ -86,21 +88,18 @@ ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
|
||||||
crssWind = other.tailWind;
|
crssWind = other.tailWind;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ScheduleTime::getName(time_t dayStart)
|
string ScheduleTime::getName(time_t dayStart)
|
||||||
{
|
{
|
||||||
if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
|
if ((start.size() != end.size())
|
||||||
{
|
|| (start.size() != scheduleNames.size())) {
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
|
SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
int nrItems = start.size();
|
int nrItems = start.size();
|
||||||
//cerr << "Nr of items to process: " << nrItems << endl;
|
//cerr << "Nr of items to process: " << nrItems << endl;
|
||||||
if (nrItems > 0)
|
if (nrItems > 0) {
|
||||||
{
|
for (unsigned int i = 0; i < start.size(); i++) {
|
||||||
for (unsigned int i = 0; i < start.size(); i++)
|
|
||||||
{
|
|
||||||
//cerr << i << endl;
|
//cerr << i << endl;
|
||||||
if ((dayStart >= start[i]) && (dayStart <= end[i]))
|
if ((dayStart >= start[i]) && (dayStart <= end[i]))
|
||||||
return scheduleNames[i];
|
return scheduleNames[i];
|
||||||
|
@ -111,6 +110,7 @@ string ScheduleTime::getName(time_t dayStart)
|
||||||
}
|
}
|
||||||
return string("");
|
return string("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* RunwayList
|
* RunwayList
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
@ -119,18 +119,22 @@ RunwayList::RunwayList(const RunwayList &other)
|
||||||
{
|
{
|
||||||
type = other.type;
|
type = other.type;
|
||||||
stringVecConstIterator i;
|
stringVecConstIterator i;
|
||||||
for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
|
for (i = other.preferredRunways.begin();
|
||||||
|
i != other.preferredRunways.end(); i++)
|
||||||
preferredRunways.push_back(*i);
|
preferredRunways.push_back(*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
RunwayList & RunwayList::operator=(const RunwayList & other)
|
RunwayList & RunwayList::operator=(const RunwayList & other)
|
||||||
{
|
{
|
||||||
type = other.type;
|
type = other.type;
|
||||||
preferredRunways.clear();
|
preferredRunways.clear();
|
||||||
stringVecConstIterator i;
|
stringVecConstIterator i;
|
||||||
for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
|
for (i = other.preferredRunways.begin();
|
||||||
|
i != other.preferredRunways.end(); i++)
|
||||||
preferredRunways.push_back(*i);
|
preferredRunways.push_back(*i);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunwayList::set(const string & tp, const string & lst)
|
void RunwayList::set(const string & tp, const string & lst)
|
||||||
{
|
{
|
||||||
//weekday = atoi(timeCopy.substr(0,1).c_str());
|
//weekday = atoi(timeCopy.substr(0,1).c_str());
|
||||||
|
@ -139,8 +143,7 @@ void RunwayList::set(const string &tp, const string &lst)
|
||||||
type = tp;
|
type = tp;
|
||||||
string rwys = lst;
|
string rwys = lst;
|
||||||
string rwy;
|
string rwy;
|
||||||
while (rwys.find(",") != string::npos)
|
while (rwys.find(",") != string::npos) {
|
||||||
{
|
|
||||||
rwy = rwys.substr(0, rwys.find(",", 0));
|
rwy = rwys.substr(0, rwys.find(",", 0));
|
||||||
//cerr << "adding runway [" << rwy << "] to the list " << endl;
|
//cerr << "adding runway [" << rwy << "] to the list " << endl;
|
||||||
preferredRunways.push_back(rwy);
|
preferredRunways.push_back(rwy);
|
||||||
|
@ -158,6 +161,7 @@ void RunwayList::clear()
|
||||||
type = "";
|
type = "";
|
||||||
preferredRunways.clear();
|
preferredRunways.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
@ -172,6 +176,7 @@ RunwayGroup::RunwayGroup(const RunwayGroup &other)
|
||||||
choice[1] = other.choice[1];
|
choice[1] = other.choice[1];
|
||||||
nrActive = other.nrActive;
|
nrActive = other.nrActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
|
RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
|
||||||
{
|
{
|
||||||
rwyList.clear();
|
rwyList.clear();
|
||||||
|
@ -189,8 +194,7 @@ void RunwayGroup::setActive(const FGAirport* airport,
|
||||||
double windSpeed,
|
double windSpeed,
|
||||||
double windHeading,
|
double windHeading,
|
||||||
double maxTail,
|
double maxTail,
|
||||||
double maxCross,
|
double maxCross, stringVec * currentlyActive)
|
||||||
stringVec *currentlyActive)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
FGRunway *rwy;
|
FGRunway *rwy;
|
||||||
|
@ -205,16 +209,14 @@ void RunwayGroup::setActive(const FGAirport* airport,
|
||||||
//stringVec names;
|
//stringVec names;
|
||||||
int bestMatch = 0, bestChoice = 0;
|
int bestMatch = 0, bestChoice = 0;
|
||||||
|
|
||||||
if (activeRwys > 0)
|
if (activeRwys > 0) {
|
||||||
{
|
|
||||||
// Now downward iterate across all the possible preferences
|
// Now downward iterate across all the possible preferences
|
||||||
// starting by the least preferred choice working toward the most preferred choice
|
// starting by the least preferred choice working toward the most preferred choice
|
||||||
|
|
||||||
nrOfPreferences = rwyList[0].getRwyList()->size();
|
nrOfPreferences = rwyList[0].getRwyList()->size();
|
||||||
bool validSelection = true;
|
bool validSelection = true;
|
||||||
bool foundValidSelection = false;
|
bool foundValidSelection = false;
|
||||||
for (int i = nrOfPreferences-1; i >= 0; i--)
|
for (int i = nrOfPreferences - 1; i >= 0; i--) {
|
||||||
{
|
|
||||||
int match = 0;
|
int match = 0;
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,11 +226,13 @@ void RunwayGroup::setActive(const FGAirport* airport,
|
||||||
// don't want to randomly swap runway preferences, unless there is a need to.
|
// don't want to randomly swap runway preferences, unless there is a need to.
|
||||||
//
|
//
|
||||||
validSelection = true;
|
validSelection = true;
|
||||||
for (int j = 0; j < activeRwys; j++)
|
|
||||||
{
|
for (int j = 0; j < activeRwys; j++) {
|
||||||
string ident(rwyList[j].getRwyList(i));
|
string ident(rwyList[j].getRwyList(i));
|
||||||
if (!airport->hasRunwayWithIdent(ident)) {
|
if (!airport->hasRunwayWithIdent(ident)) {
|
||||||
SG_LOG(SG_GENERAL, SG_WARN, "no such runway:" << ident << " at " << airport->ident());
|
SG_LOG(SG_GENERAL, SG_WARN,
|
||||||
|
"no such runway:" << ident << " at " <<
|
||||||
|
airport->ident());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,47 +240,45 @@ void RunwayGroup::setActive(const FGAirport* airport,
|
||||||
|
|
||||||
//cerr << "Succes" << endl;
|
//cerr << "Succes" << endl;
|
||||||
hdgDiff = fabs(windHeading - rwy->headingDeg());
|
hdgDiff = fabs(windHeading - rwy->headingDeg());
|
||||||
//cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
|
name = rwy->name();
|
||||||
//cerr << "Wind Speed : " << windSpeed << endl;
|
|
||||||
|
|
||||||
if (hdgDiff > 180)
|
if (hdgDiff > 180)
|
||||||
hdgDiff = 360 - hdgDiff;
|
hdgDiff = 360 - hdgDiff;
|
||||||
//cerr << "Heading diff: " << hdgDiff << endl;
|
//cerr << "Heading diff: " << hdgDiff << endl;
|
||||||
hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
|
hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
|
||||||
crossWind = windSpeed * sin(hdgDiff);
|
crossWind = windSpeed * sin(hdgDiff);
|
||||||
tailWind = -windSpeed * cos(hdgDiff);
|
tailWind = -windSpeed * cos(hdgDiff);
|
||||||
|
//cerr << "Runway : " << rwy->name() << ": " << rwy->headingDeg() << endl;
|
||||||
//cerr << ". Tailwind : " << tailWind;
|
//cerr << ". Tailwind : " << tailWind;
|
||||||
//cerr << ". Crosswnd : " << crossWind;
|
//cerr << ". Crosswnd : " << crossWind;
|
||||||
if ((tailWind > maxTail) || (crossWind > maxCross))
|
if ((tailWind > maxTail) || (crossWind > maxCross)) {
|
||||||
{
|
|
||||||
//cerr << ". [Invalid] " << endl;
|
//cerr << ". [Invalid] " << endl;
|
||||||
validSelection = false;
|
validSelection = false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
//cerr << ". [Valid] ";
|
//cerr << ". [Valid] ";
|
||||||
}
|
}
|
||||||
//cerr << endl;
|
//cerr << endl;
|
||||||
} // of active runways iteration
|
|
||||||
|
|
||||||
if (validSelection)
|
|
||||||
{
|
|
||||||
//cerr << "Valid selection : " << i << endl;;
|
|
||||||
foundValidSelection = true;
|
|
||||||
for (stringVecIterator it = currentlyActive->begin();
|
for (stringVecIterator it = currentlyActive->begin();
|
||||||
it != currentlyActive->end(); it++)
|
it != currentlyActive->end(); it++) {
|
||||||
{
|
//cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
|
||||||
if ((*it) == name)
|
if ((*it) == name) {
|
||||||
match++;
|
match++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} // of active runways iteration
|
||||||
|
|
||||||
|
if (validSelection) {
|
||||||
|
//cerr << "Valid selection : " << i << endl;;
|
||||||
|
foundValidSelection = true;
|
||||||
if (match >= bestMatch) {
|
if (match >= bestMatch) {
|
||||||
bestMatch = match;
|
bestMatch = match;
|
||||||
bestChoice = i;
|
bestChoice = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//cerr << "Preference " << i << " bestMatch " << bestMatch << " choice " << bestChoice << endl;
|
//cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
|
||||||
}
|
}
|
||||||
if (foundValidSelection)
|
if (foundValidSelection) {
|
||||||
{
|
|
||||||
//cerr << "Valid runay selection : " << bestChoice << endl;
|
//cerr << "Valid runay selection : " << bestChoice << endl;
|
||||||
nrActive = activeRwys;
|
nrActive = activeRwys;
|
||||||
active = bestChoice;
|
active = bestChoice;
|
||||||
|
@ -286,8 +288,7 @@ void RunwayGroup::setActive(const FGAirport* airport,
|
||||||
// but select only one landing and one takeoff runway.
|
// but select only one landing and one takeoff runway.
|
||||||
choice[0] = 0;
|
choice[0] = 0;
|
||||||
choice[1] = 0;
|
choice[1] = 0;
|
||||||
for (int i = activeRwys-1; i; i--)
|
for (int i = activeRwys - 1; i; i--) {
|
||||||
{
|
|
||||||
if (rwyList[i].getType() == string("landing"))
|
if (rwyList[i].getType() == string("landing"))
|
||||||
choice[0] = i;
|
choice[0] = i;
|
||||||
if (rwyList[i].getType() == string("takeoff"))
|
if (rwyList[i].getType() == string("takeoff"))
|
||||||
|
@ -295,11 +296,9 @@ void RunwayGroup::setActive(const FGAirport* airport,
|
||||||
}
|
}
|
||||||
//cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
|
//cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
|
||||||
nrOfPreferences = rwyList[0].getRwyList()->size();
|
nrOfPreferences = rwyList[0].getRwyList()->size();
|
||||||
for (int i = 0; i < nrOfPreferences; i++)
|
for (int i = 0; i < nrOfPreferences; i++) {
|
||||||
{
|
|
||||||
bool validSelection = true;
|
bool validSelection = true;
|
||||||
for (int j = 0; j < 2; j++)
|
for (int j = 0; j < 2; j++) {
|
||||||
{
|
|
||||||
name = rwyList[choice[j]].getRwyList(i);
|
name = rwyList[choice[j]].getRwyList(i);
|
||||||
rwy = airport->getRunwayByIdent(name);
|
rwy = airport->getRunwayByIdent(name);
|
||||||
|
|
||||||
|
@ -315,8 +314,7 @@ void RunwayGroup::setActive(const FGAirport* airport,
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if (validSelection)
|
if (validSelection) {
|
||||||
{
|
|
||||||
//cerr << "Valid runay selection : " << i << endl;
|
//cerr << "Valid runay selection : " << i << endl;
|
||||||
active = i;
|
active = i;
|
||||||
nrActive = 2;
|
nrActive = 2;
|
||||||
|
@ -330,21 +328,18 @@ void RunwayGroup::setActive(const FGAirport* airport,
|
||||||
|
|
||||||
void RunwayGroup::getActive(int i, string & name, string & type)
|
void RunwayGroup::getActive(int i, string & name, string & type)
|
||||||
{
|
{
|
||||||
if (i == -1)
|
if (i == -1) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nrActive == (int)rwyList.size())
|
if (nrActive == (int) rwyList.size()) {
|
||||||
{
|
|
||||||
name = rwyList[i].getRwyList(active);
|
name = rwyList[i].getRwyList(active);
|
||||||
type = rwyList[i].getType();
|
type = rwyList[i].getType();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
name = rwyList[choice[i]].getRwyList(active);
|
name = rwyList[choice[i]].getRwyList(active);
|
||||||
type = rwyList[choice[i]].getType();
|
type = rwyList[choice[i]].getType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* FGRunway preference
|
* FGRunway preference
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -368,7 +363,8 @@ FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
|
||||||
preferences.push_back(*i);
|
preferences.push_back(*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
|
FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
|
||||||
|
& other)
|
||||||
{
|
{
|
||||||
initialized = other.initialized;
|
initialized = other.initialized;
|
||||||
|
|
||||||
|
@ -410,6 +406,7 @@ RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
string FGRunwayPreference::getId() {
|
string FGRunwayPreference::getId()
|
||||||
|
{
|
||||||
return _ap->getId();
|
return _ap->getId();
|
||||||
};
|
};
|
||||||
|
|
|
@ -289,7 +289,6 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
|
||||||
if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
|
if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
|
||||||
return true; // out of visual range, for the moment.
|
return true; // out of visual range, for the moment.
|
||||||
}
|
}
|
||||||
|
|
||||||
return createAIAircraft(flight, speed, deptime);
|
return createAIAircraft(flight, speed, deptime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,9 @@ void FGTrafficManager::init()
|
||||||
|
|
||||||
void FGTrafficManager::update(double /*dt*/)
|
void FGTrafficManager::update(double /*dt*/)
|
||||||
{
|
{
|
||||||
|
if (fgGetBool("/environment/metar/valid") == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||||
if (scheduledAircraft.size() == 0) {
|
if (scheduledAircraft.size() == 0) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Add table
Reference in a new issue