1
0
Fork 0

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:
Durk Talsma 2010-08-29 19:25:34 +02:00
parent fed62b13dd
commit 467513cbaf
16 changed files with 2396 additions and 1487 deletions

View file

@ -1,4 +1,4 @@
// // // FGAIAircraft - FGAIBase-derived class creates an AI airplane
// FGAIAircraft - FGAIBase-derived class creates an AI airplane
//
// Written by David Culp, started October 2003.
//
@ -78,6 +78,8 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) {
roll = 0;
headingChangeRate = 0.0;
headingError = 0;
minBearing = 360;
speedFraction =1.0;
holdPos = false;
needsTaxiClearance = false;
@ -257,6 +259,16 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
return;
dt_count = 0;
double distanceToDescent;
if(reachedEndOfCruise(distanceToDescent)) {
if (!loadNextLeg(distanceToDescent)) {
setDie(true);
return;
}
prev = fp->getPreviousWaypoint();
curr = fp->getCurrentWaypoint();
next = fp->getNextWaypoint();
}
if (! leadPointReached(curr)) {
controlHeading(curr);
controlSpeed(curr, next);
@ -278,7 +290,7 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
//TODO let the fp handle this (loading of next leg)
fp->IncrementWaypoint( trafficRef != 0 );
if (!(fp->getNextWaypoint()) && trafficRef != 0)
if ( ((!(fp->getNextWaypoint()))) && (trafficRef != 0) )
if (!loadNextLeg()) {
setDie(true);
return;
@ -342,7 +354,7 @@ const char * FGAIAircraft::_getTransponderCode() const {
}
bool FGAIAircraft::loadNextLeg() {
bool FGAIAircraft::loadNextLeg(double distance) {
int leg;
if ((leg = fp->getLeg()) == 10) {
@ -374,7 +386,8 @@ bool FGAIAircraft::loadNextLeg() {
trafficRef->getRadius(),
trafficRef->getFlightType(),
acType,
company);
company,
distance);
//cerr << "created leg " << leg << " for " << trafficRef->getCallSign() << endl;
}
return true;
@ -423,6 +436,7 @@ void FGAIAircraft::doGroundAltitude() {
altitude_ft = (tgt_altitude_ft + groundOffset);
else
altitude_ft += 0.1 * ((tgt_altitude_ft+groundOffset) - altitude_ft);
tgt_vs = 0;
}
@ -449,6 +463,11 @@ void FGAIAircraft::announcePositionToController() {
cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
}
break;
case 7:
if (trafficRef->getDepartureAirport()->getDynamics()) {
controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController();
}
break;
case 9: // Taxiing for parking
if (trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork()->exists())
controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork();
@ -629,13 +648,34 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) {
// << dist_to_go << ": Lead distance "
// << lead_dist << " " << curr->name
// << " Ground target speed " << groundTargetSpeed << endl;
// if (trafficRef) {
// if (trafficRef->getCallSign() == "Transavia7584") {
// cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " "
// << _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << curr->name << endl;
// }
// }
return dist_to_go < lead_dist;
double bearing;
if (speed > 50) { // don't do bearing calculations for ground traffic
bearing = getBearing(fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr));
if (bearing < minBearing) {
minBearing = bearing;
if (minBearing < 10) {
minBearing = 10;
}
if ((minBearing < 360.0) && (minBearing > 10.0)) {
speedFraction = cos(minBearing *SG_DEGREES_TO_RADIANS);
} else {
speedFraction = 1.0;
}
}
}
if (trafficRef) {
//cerr << "Tracking callsign : \"" << fgGetString("/ai/track-callsign") << "\"" << endl;
/* if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " "
<< _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << " " << curr->name << " " << vs << " " << tgt_vs << " " << bearing << " " << minBearing << " " << speedFraction << endl;
}*/
}
if ((dist_to_go < lead_dist) || (bearing > (minBearing * 1.1))) {
minBearing = 360;
return true;
} else {
return false;
}
}
@ -1024,7 +1064,7 @@ void FGAIAircraft::updateActualState() {
if (onGround())
speed = _performance->actualSpeed(this, groundTargetSpeed, dt);
else
speed = _performance->actualSpeed(this, tgt_speed, dt);
speed = _performance->actualSpeed(this, (tgt_speed *speedFraction), dt);
updateHeading();
roll = _performance->actualBankAngle(this, tgt_roll, dt);
@ -1045,3 +1085,89 @@ void FGAIAircraft::updateSecondaryTargetValues() {
//TODO calculate wind correction angle (tgt_yaw)
}
bool FGAIAircraft::reachedEndOfCruise(double &distance) {
FGAIFlightPlan::waypoint* curr = fp->getCurrentWaypoint();
if (curr->name == "BOD") {
double dist = fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr);
double descentSpeed = (getPerformance()->vDescent() * SG_NM_TO_METER) / 3600.0; // convert from kts to meter/s
double descentRate = (getPerformance()->descentRate() * SG_FEET_TO_METER) / 60.0; // convert from feet/min to meter/s
double verticalDistance = ((altitude_ft - 2000.0) - trafficRef->getArrivalAirport()->getElevation()) *SG_FEET_TO_METER;
double descentTimeNeeded = verticalDistance / descentRate;
double distanceCovered = descentSpeed * descentTimeNeeded;
//cerr << "Tracking : " << fgGetString("/ai/track-callsign");
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
cerr << "Checking for end of cruise stage for :" << trafficRef->getCallSign() << endl;
cerr << "Descent rate : " << descentRate << endl;
cerr << "Descent speed : " << descentSpeed << endl;
cerr << "VerticalDistance : " << verticalDistance << ". Altitude : " << altitude_ft << ". Elevation " << trafficRef->getArrivalAirport()->getElevation() << endl;
cerr << "DecentTimeNeeded : " << descentTimeNeeded << endl;
cerr << "DistanceCovered : " << distanceCovered << endl;
}
//cerr << "Distance = " << distance << endl;
distance = distanceCovered;
if (dist < distanceCovered) {
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
//exit(1);
}
return true;
} else {
return false;
}
} else {
return false;
}
}
void FGAIAircraft::resetPositionFromFlightPlan()
{
// the one behind you
FGAIFlightPlan::waypoint* prev = 0;
// the one ahead
FGAIFlightPlan::waypoint* curr = 0;
// the next plus 1
FGAIFlightPlan::waypoint* next = 0;
prev = fp->getPreviousWaypoint();
curr = fp->getCurrentWaypoint();
next = fp->getNextWaypoint();
setLatitude(prev->latitude);
setLongitude(prev->longitude);
double tgt_heading = fp->getBearing(curr, next);
setHeading(tgt_heading);
setAltitude(prev->altitude);
setSpeed(prev->speed);
}
double FGAIAircraft::getBearing(double crse)
{
double hdgDiff = fabs(hdg-crse);
if (hdgDiff > 180)
hdgDiff = fabs(hdgDiff - 360);
return hdgDiff;
}
time_t FGAIAircraft::checkForArrivalTime(string wptName) {
FGAIFlightPlan::waypoint* curr = 0;
curr = fp->getCurrentWaypoint();
double tracklength = fp->checkTrackLength(wptName);
if (tracklength > 0.1) {
tracklength += fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr);
} else {
return 0;
}
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
time_t arrivalTime = fp->getArrivalTime();
time_t ete = tracklength / ((speed * SG_NM_TO_METER) / 3600.0);
time_t secondsToGo = arrivalTime - now;
if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
cerr << "Checking arrival time: ete " << ete << ". Time to go : " << secondsToGo << ". Track length = " << tracklength << endl;
}
return (ete - secondsToGo); // Positive when we're too slow...
}

View file

@ -53,6 +53,7 @@ public:
void initializeFlightPlan();
FGAIFlightPlan* GetFlightPlan() const { return fp; };
void ProcessFlightPlan( double dt, time_t now );
time_t checkForArrivalTime(string wptName);
void AccelTo(double speed);
void PitchTo(double angle);
@ -63,7 +64,9 @@ public:
void getGroundElev(double dt); //TODO these 3 really need to be public?
void doGroundAltitude();
bool loadNextLeg ();
bool loadNextLeg (double dist=0);
void resetPositionFromFlightPlan();
double getBearing(double crse);
void setAcType(const std::string& ac) { acType = ac; };
void setCompany(const std::string& comp) { company = comp;};
@ -91,6 +94,7 @@ public:
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
std::string atGate();
protected:
void Run(double dt);
@ -104,6 +108,8 @@ private:
double dt_elev_count;
double headingChangeRate;
double headingError;
double minBearing;
double speedFraction;
double groundTargetSpeed;
double groundOffset;
double dt;
@ -118,6 +124,7 @@ private:
void handleFirstWaypoint(void);
bool leadPointReached(FGAIFlightPlan::waypoint* curr);
bool handleAirportEndPoints(FGAIFlightPlan::waypoint* prev, time_t now);
bool reachedEndOfCruise(double&);
bool aiTrafficVisible(void);
void controlHeading(FGAIFlightPlan::waypoint* curr);
void controlSpeed(FGAIFlightPlan::waypoint* curr,

View file

@ -187,8 +187,8 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
time_t timeDiff = now-start;
leg = 1;
/*
if ((timeDiff > 300) && (timeDiff < 1200))
if ((timeDiff > 60) && (timeDiff < 1200))
leg = 2;
else if ((timeDiff >= 1200) && (timeDiff < 1500))
leg = 3;
@ -196,14 +196,15 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
leg = 4;
else if (timeDiff >= 2000)
leg = 5;
*/
/*
if (timeDiff >= 2000)
leg = 5;
*/
SG_LOG(SG_GENERAL, SG_INFO, "Route from " << dep->getId() << " to " << arr->getId() << ". Set leg to : " << leg << " " << ac->getTrafficRef()->getCallSign());
wpt_iterator = waypoints.begin();
bool dist = 0;
create(ac, dep,arr, leg, alt, speed, lat, lon,
firstLeg, radius, fltType, acType, airline);
firstLeg, radius, fltType, acType, airline, dist);
wpt_iterator = waypoints.begin();
//cerr << "after create: " << (*wpt_iterator)->name << endl;
//leg++;
@ -411,6 +412,7 @@ void FGAIFlightPlan::setLeadDistance(double speed, double bearing,
//lead_distance = turn_radius * sin(leadInAngle * SG_DEGREES_TO_RADIANS);
lead_distance = turn_radius * tan((leadInAngle * SG_DEGREES_TO_RADIANS)/2);
/*
if ((lead_distance > (3*turn_radius)) && (current->on_ground == false)) {
// cerr << "Warning: Lead-in distance is large. Inbound = " << inbound
// << ". Outbound = " << outbound << ". Lead in angle = " << leadInAngle << ". Turn radius = " << turn_radius << endl;
@ -420,7 +422,7 @@ void FGAIFlightPlan::setLeadDistance(double speed, double bearing,
if ((leadInAngle > 90) && (current->on_ground == true)) {
lead_distance = turn_radius * tan((90 * SG_DEGREES_TO_RADIANS)/2);
return;
}
}*/
}
void FGAIFlightPlan::setLeadDistance(double distance_ft){
@ -493,3 +495,20 @@ int FGAIFlightPlan::getRouteIndex(int i) {
else
return 0;
}
double FGAIFlightPlan::checkTrackLength(string wptName) {
// skip the first two waypoints: first one is behind, second one is partially done;
double trackDistance = 0;
wpt_vector_iterator wptvec = waypoints.begin();
wptvec++;
wptvec++;
while ((wptvec != waypoints.end()) && ((*wptvec)->name != wptName)) {
trackDistance += (*wptvec)->trackLength;
wptvec++;
}
if (wptvec == waypoints.end()) {
trackDistance = 0; // name not found
}
return trackDistance;
}

View file

@ -55,6 +55,7 @@ public:
bool on_ground;
int routeIndex; // For AI/ATC purposes;
double time_sec;
double trackLength; // distance from previous waypoint (for AI purposes);
string time;
} waypoint;
@ -90,10 +91,12 @@ public:
double getLeadDistance( void ) const {return lead_distance;}
double getBearing(waypoint* previous, waypoint* next) const;
double getBearing(double lat, double lon, waypoint* next) const;
double checkTrackLength(string wptName);
time_t getStartTime() const { return start_time; }
time_t getArrivalTime() const { return arrivalTime; }
void create(FGAIAircraft *, FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
bool firstLeg, double radius, const string& fltType, const string& aircraftType, const string& airline);
bool firstLeg, double radius, const string& fltType, const string& aircraftType, const string& airline, double distance);
void setLeg(int val) { leg = val;}
void setTime(time_t st) { start_time = st; }
@ -128,6 +131,7 @@ private:
typedef vector <waypoint*> wpt_vector_type;
typedef wpt_vector_type::const_iterator wpt_vector_iterator;
wpt_vector_type waypoints;
wpt_vector_iterator wpt_iterator;
@ -136,6 +140,7 @@ private:
double lead_distance;
double leadInAngle;
time_t start_time;
time_t arrivalTime; // For AI/ATC purposes.
int leg;
int gateId, lastNodeVisited;
string activeRunway;
@ -148,7 +153,7 @@ private:
void createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const string&);
void createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const string&);
void createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const string&);
void createDecent(FGAIAircraft *, FGAirport *, const string&);
void createDescent(FGAIAircraft *, FGAirport *, double latitude, double longitude, double speed, double alt,const string&, double distance);
void createLanding(FGAIAircraft *, FGAirport *, const string&);
void createParking(FGAIAircraft *, FGAirport *, double radius);
void deleteWaypoints();
@ -159,6 +164,8 @@ private:
void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
void createTakeoffTaxi(FGAIAircraft *, bool firstFlight, FGAirport *apt, double radius, const string& fltType, const string& acType, const string& airline);
double getTurnRadius(double, bool);
waypoint* createOnGround(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
waypoint* createInAir(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
waypoint* cloneWithPos(FGAIAircraft *, waypoint* aWpt, const std::string& aName, const SGGeod& aPos);

View file

@ -46,21 +46,23 @@
// Check lat/lon values during initialization;
void FGAIFlightPlan::create(FGAIAircraft *ac, FGAirport *dep, FGAirport *arr, int legNr,
double alt, double speed, double latitude,
double longitude, bool firstFlight,double radius,
const string& fltType, const string& aircraftType,
const string& airline)
void FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
FGAirport * arr, int legNr, double alt,
double speed, double latitude,
double longitude, bool firstFlight,
double radius, const string & fltType,
const string & aircraftType,
const string & airline, double distance)
{
int currWpt = wpt_iterator - waypoints.begin();
switch(legNr)
{
switch (legNr) {
case 1:
createPushBack(ac, firstFlight,dep, latitude, longitude,
createPushBack(ac, firstFlight, dep, latitude, longitude,
radius, fltType, aircraftType, airline);
break;
case 2:
createTakeoffTaxi(ac, firstFlight, dep, radius, fltType, aircraftType, airline);
createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
aircraftType, airline);
break;
case 3:
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);
break;
case 5:
createCruise(ac, firstFlight, dep,arr, latitude, longitude, speed, alt, fltType);
createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
alt, fltType);
break;
case 6:
createDecent(ac, arr, fltType);
createDescent(ac, arr, latitude, longitude, speed, alt, fltType,
distance);
break;
case 7:
createLanding(ac, arr, fltType);
@ -85,53 +89,62 @@ void FGAIFlightPlan::create(FGAIAircraft *ac, FGAirport *dep, FGAirport *arr, in
break;
default:
//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");
}
wpt_iterator = waypoints.begin()+currWpt;
wpt_iterator = waypoints.begin() + currWpt;
leg++;
}
FGAIFlightPlan::waypoint*
FGAIFlightPlan::createOnGround(FGAIAircraft *ac, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed)
FGAIFlightPlan::waypoint *
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->longitude = aPos.getLongitudeDeg();
wpt->latitude = aPos.getLatitudeDeg();
wpt->altitude = aElev;
wpt->speed = aSpeed;
wpt->crossat = -10000;
wpt->crossat = -10000.1;
wpt->gear_down = true;
wpt->flaps_down= true;
wpt->flaps_down = true;
wpt->finished = false;
wpt->on_ground = true;
wpt->routeIndex= 0;
wpt->routeIndex = 0;
return wpt;
}
FGAIFlightPlan::waypoint*
FGAIFlightPlan::createInAir(FGAIAircraft *ac, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed)
FGAIFlightPlan::waypoint *
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->longitude = aPos.getLongitudeDeg();
wpt->latitude = aPos.getLatitudeDeg();
wpt->altitude = aElev;
wpt->speed = aSpeed;
wpt->crossat = -10000;
wpt->crossat = -10000.1;
wpt->gear_down = false;
wpt->flaps_down= false;
wpt->flaps_down = false;
wpt->finished = false;
wpt->on_ground = false;
wpt->routeIndex= 0;
wpt->routeIndex = 0;
return wpt;
}
FGAIFlightPlan::waypoint*
FGAIFlightPlan::cloneWithPos(FGAIAircraft *ac, waypoint* aWpt, const std::string& aName, const SGGeod& aPos)
FGAIFlightPlan::waypoint *
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->longitude = aPos.getLongitudeDeg();
wpt->latitude = aPos.getLatitudeDeg();
@ -140,7 +153,7 @@ FGAIFlightPlan::cloneWithPos(FGAIAircraft *ac, waypoint* aWpt, const std::string
wpt->speed = aWpt->speed;
wpt->crossat = aWpt->crossat;
wpt->gear_down = aWpt->gear_down;
wpt->flaps_down= aWpt->flaps_down;
wpt->flaps_down = aWpt->flaps_down;
wpt->finished = aWpt->finished;
wpt->on_ground = aWpt->on_ground;
wpt->routeIndex = 0;
@ -148,10 +161,9 @@ FGAIFlightPlan::cloneWithPos(FGAIAircraft *ac, waypoint* aWpt, const std::string
return wpt;
}
FGAIFlightPlan::waypoint*
FGAIFlightPlan::clone(waypoint* aWpt)
FGAIFlightPlan::waypoint * FGAIFlightPlan::clone(waypoint * aWpt)
{
waypoint* wpt = new waypoint;
waypoint *wpt = new waypoint;
wpt->name = aWpt->name;
wpt->longitude = aWpt->longitude;
wpt->latitude = aWpt->latitude;
@ -160,7 +172,7 @@ FGAIFlightPlan::clone(waypoint* aWpt)
wpt->speed = aWpt->speed;
wpt->crossat = aWpt->crossat;
wpt->gear_down = aWpt->gear_down;
wpt->flaps_down= aWpt->flaps_down;
wpt->flaps_down = aWpt->flaps_down;
wpt->finished = aWpt->finished;
wpt->on_ground = aWpt->on_ground;
wpt->routeIndex = 0;
@ -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);
double airportElev = aAirport->getElevation();
waypoint* wpt;
wpt = createOnGround(ac, "Airport Center", aAirport->geod(), airportElev, ac->getPerformance()->vTaxi());
waypoint *wpt;
wpt =
createOnGround(ac, "Airport Center", aAirport->geod(), airportElev,
ac->getPerformance()->vTaxi());
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);
}
void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
FGAirport *apt,
double radius, const string& fltType,
const string& acType, const string& airline)
void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
FGAirport * apt,
double radius,
const string & fltType,
const string & acType,
const string & airline)
{
double heading, lat, lon;
@ -195,8 +215,7 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
if (!(apt->getDynamics()->getAvailableParking(&lat, &lon,
&heading, &gateId,
radius, fltType,
acType, airline)))
{
acType, airline))) {
SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " <<
acType <<
" of flight type " << fltType <<
@ -211,12 +230,13 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
if (activeRunway.empty()) {
//cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
double depHeading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, depHeading);
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
depHeading);
}
rwy = apt->getRunwayByIdent(activeRunway);
SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
FGGroundNetwork* gn = apt->getDynamics()->getGroundNetwork();
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
if (!gn->exists()) {
createDefaultTakeoffTaxi(ac, apt, rwy);
return;
@ -243,7 +263,6 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
if (node == -1) {
node = gateId;
}
// HAndle case where parking doens't have a node
if ((node == 0) && park) {
if (firstFlight) {
@ -270,7 +289,7 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
int nrWaypointsToSkip = rand() % taxiRoute->size();
// but make sure we always keep two active waypoints
// to prevent a segmentation fault
for (int i = 0; i < nrWaypointsToSkip-2; i++) {
for (int i = 0; i < nrWaypointsToSkip - 3; i++) {
taxiRoute->next(&node);
}
apt->getDynamics()->releaseParking(gateId);
@ -282,45 +301,60 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight,
// push each node on the taxi route as a waypoint
int route;
while(taxiRoute->next(&node, &route)) {
while (taxiRoute->next(&node, &route)) {
char buffer[10];
snprintf (buffer, 10, "%d", node);
FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
waypoint* wpt = createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(), ac->getPerformance()->vTaxi());
snprintf(buffer, 10, "%d", node);
FGTaxiNode *tn =
apt->getDynamics()->getGroundNetwork()->findNode(node);
waypoint *wpt =
createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(),
ac->getPerformance()->vTaxi());
wpt->routeIndex = route;
waypoints.push_back(wpt);
}
}
void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft *ac, FGAirport* aAirport)
void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
FGAirport * aAirport)
{
SGGeod lastWptPos =
SGGeod::fromDeg(waypoints.back()->longitude, waypoints.back()->latitude);
SGGeod::fromDeg(waypoints.back()->longitude,
waypoints.back()->latitude);
double airportElev = aAirport->getElevation();
waypoint* wpt;
wpt = createOnGround(ac, "Runway Exit", lastWptPos, airportElev, ac->getPerformance()->vTaxi());
waypoint *wpt;
wpt =
createOnGround(ac, "Runway Exit", lastWptPos, airportElev,
ac->getPerformance()->vTaxi());
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);
double heading, lat, lon;
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);
}
void FGAIFlightPlan::createLandingTaxi(FGAIAircraft *ac, FGAirport *apt,
double radius, const string& fltType,
const string& acType, const string& airline)
void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
double radius,
const string & fltType,
const string & acType,
const string & airline)
{
double heading, lat, lon;
apt->getDynamics()->getAvailableParking(&lat, &lon, &heading,
&gateId, radius, fltType, acType, airline);
&gateId, radius, fltType,
acType, airline);
SGGeod lastWptPos =
SGGeod::fromDeg(waypoints.back()->longitude, waypoints.back()->latitude);
FGGroundNetwork* gn = apt->getDynamics()->getGroundNetwork();
SGGeod::fromDeg(waypoints.back()->longitude,
waypoints.back()->latitude);
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
// Find a route from runway end to parking/gate.
if (!gn->exists()) {
@ -353,12 +387,14 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft *ac, FGAirport *apt,
// Omit the last two waypoints, as
// those are created by createParking()
int route;
for (int i = 0; i < size-2; i++) {
for (int i = 0; i < size - 2; i++) {
taxiRoute->next(&node, &route);
char buffer[10];
snprintf (buffer, 10, "%d", node);
snprintf(buffer, 10, "%d", 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;
waypoints.push_back(wpt);
}
@ -375,7 +411,9 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft *ac, FGAirport *apt,
* 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 vTaxi = ac->getPerformance()->vTaxi();
@ -394,19 +432,21 @@ void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport
//d = (Vf^2 - Vo^2) / (2*a)
//double accelTime = (vRotate - vTaxi) / accel;
//cerr << "Using " << accelTime << " as total acceleration time" << endl;
double accelDistance = (vRotateMetric*vRotateMetric - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
cerr << "Using " << accelDistance << " " << accelMetric << " " << vRotateMetric << endl;
double accelDistance =
(vRotateMetric * vRotateMetric -
vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
//cerr << "Using " << accelDistance << " " << accelMetric << " " << vRotateMetric << endl;
waypoint *wpt;
// Get the current active runway, based on code from David Luff
// This should actually be unified and extended to include
// Preferential runway use schema's
// NOTE: DT (2009-01-18: IIRC, this is currently already the case,
// because the getActive runway function takes care of that.
if (firstFlight)
{
if (firstFlight) {
string rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
heading);
rwy = apt->getRunwayByIdent(activeRunway);
}
@ -417,28 +457,34 @@ void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport
waypoints.push_back(wpt);
accelDistance = (vTakeoffMetric*vTakeoffMetric - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
accelPoint = rwy->pointOnCenterline(105.0+accelDistance);
accelDistance =
(vTakeoffMetric * vTakeoffMetric -
vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
//cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
waypoints.push_back(wpt);
accelDistance = ((vTakeoffMetric*1.1)*(vTakeoffMetric*1.1) - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
accelPoint = rwy->pointOnCenterline(105.0+accelDistance);
wpt = createOnGround(ac, "rotate", accelPoint, airportElev+1000, vTakeoff*1.1);
accelDistance =
((vTakeoffMetric * 1.1) * (vTakeoffMetric * 1.1) -
vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
//cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
wpt =
createOnGround(ac, "rotate", accelPoint, airportElev + 1000,
vTakeoff * 1.1);
wpt->on_ground = false;
waypoints.push_back(wpt);
wpt = cloneWithPos(ac, wpt, "3000 ft", rwy->end());
wpt->altitude = airportElev+3000;
wpt->altitude = airportElev + 3000;
waypoints.push_back(wpt);
// Finally, add two more waypoints, so that aircraft will remain under
// Tower control until they have reached the 3000 ft climb point
SGGeod pt = rwy->pointOnCenterline(5000 + rwy->lengthM() * 0.5);
wpt = cloneWithPos(ac, wpt, "5000 ft", pt);
wpt->altitude = airportElev+5000;
wpt->altitude = airportElev + 5000;
waypoints.push_back(wpt);
}
@ -446,7 +492,9 @@ void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport
* CreateClimb
* 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;
// bool planLoaded = false;
@ -456,24 +504,24 @@ void FGAIFlightPlan::createClimb(FGAIAircraft *ac, bool firstFlight, FGAirport *
if (firstFlight) {
string rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
heading);
rwy = apt->getRunwayByIdent(activeRunway);
}
if (sid) {
for (wpt_vector_iterator i = sid->getFirstWayPoint();
i != sid->getLastWayPoint();
i++) {
i != sid->getLastWayPoint(); i++) {
waypoints.push_back(clone(*(i)));
//cerr << " Cloning waypoint " << endl;
}
} else {
SGGeod climb1 = rwy->pointOnCenterline(10*SG_NM_TO_METER);
SGGeod climb1 = rwy->pointOnCenterline(10 * SG_NM_TO_METER);
wpt = createInAir(ac, "10000ft climb", climb1, vClimb, 10000);
wpt->gear_down = true;
wpt->flaps_down= true;
wpt->flaps_down = true;
waypoints.push_back(wpt);
SGGeod climb2 = rwy->pointOnCenterline(20*SG_NM_TO_METER);
SGGeod climb2 = rwy->pointOnCenterline(20 * SG_NM_TO_METER);
wpt = cloneWithPos(ac, wpt, "18000ft climb", climb2);
wpt->altitude = 18000;
waypoints.push_back(wpt);
@ -483,50 +531,317 @@ void FGAIFlightPlan::createClimb(FGAIAircraft *ac, bool firstFlight, FGAirport *
/*******************************************************************
* CreateDecent
* initialize the Aircraft at the parking location
* CreateDescent
* 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;
double vDecent = ac->getPerformance()->vDescent();
double vDescent = ac->getPerformance()->vDescent();
double vApproach = ac->getPerformance()->vApproach();
//Beginning of Decent
//string name;
// allow "mil" and "gen" as well
//Beginning of Descent
string rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
heading);
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
wpt = createInAir(ac, "DEC 3000ft", descent2, apt->getElevation(), vApproach);
wpt->crossat = 3000;
wpt->gear_down = true;
wpt->flaps_down= true;
// Create a slow descent path that ends 250 lateral to the runway.
double initialTurnRadius = getTurnRadius(vDescent, true);
double finalTurnRadius = getTurnRadius(vApproach, true);
// get length of the downwind leg for the intended runway
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
* 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 vTaxi = ac->getPerformance()->vTaxi();
string rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
rwy = apt->getRunwayByIdent(activeRunway);
//string rwyClass = getRunwayClassFromTrafficType(fltType);
//double heading = ac->getTrafficRef()->getCourse();
//apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
//rwy = apt->getRunwayByIdent(activeRunway);
waypoint *wpt;
@ -536,8 +851,8 @@ void FGAIFlightPlan::createLanding(FGAIAircraft *ac, FGAirport *apt, const strin
char buffer[12];
for (int i = 1; i < 10; i++) {
snprintf(buffer, 12, "wpt%d", i);
coord = rwy->pointOnCenterline(rwy->lengthM() * (i/10.0));
wpt = createOnGround(ac, buffer, coord, aptElev, (vTouchdown/i));
coord = rwy->pointOnCenterline(rwy->lengthM() * (i / 10.0));
wpt = createOnGround(ac, buffer, coord, aptElev, (vTouchdown / i));
wpt->crossat = apt->getElevation();
waypoints.push_back(wpt);
}
@ -563,9 +878,10 @@ void FGAIFlightPlan::createLanding(FGAIAircraft *ac, FGAirport *apt, const strin
* CreateParking
* 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 lat = 0.0, lat2 = 0.0;
double lon = 0.0, lon2 = 0.0;
@ -573,25 +889,29 @@ void FGAIFlightPlan::createParking(FGAIAircraft *ac, FGAirport *apt, double radi
double heading = 0.0;
double vTaxi = ac->getPerformance()->vTaxi();
double vTaxiReduced = vTaxi * (2.0/3.0);
double vTaxiReduced = vTaxi * (2.0 / 3.0);
apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
heading += 180.0;
if (heading > 360)
heading -= 360;
geo_direct_wgs_84 ( 0, lat, lon, heading,
2.2*radius,
&lat2, &lon2, &az2 );
wpt = createOnGround(ac, "taxiStart", SGGeod::fromDeg(lon2, lat2), aptElev, vTaxiReduced);
geo_direct_wgs_84(0, lat, lon, heading,
2.2 * radius, &lat2, &lon2, &az2);
wpt =
createOnGround(ac, "taxiStart", SGGeod::fromDeg(lon2, lat2),
aptElev, vTaxiReduced);
waypoints.push_back(wpt);
geo_direct_wgs_84 ( 0, lat, lon, heading,
0.1 *radius,
&lat2, &lon2, &az2 );
geo_direct_wgs_84(0, lat, lon, heading,
0.1 * radius, &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);
wpt = createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev, vTaxiReduced);
wpt =
createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev,
vTaxiReduced);
waypoints.push_back(wpt);
}
@ -624,7 +944,7 @@ string FGAIFlightPlan::getRunwayClassFromTrafficType(string fltType)
return string("com");
}
if (fltType == "ga") {
return string ("gen");
return string("gen");
}
if (fltType == "ul") {
return string("ul");
@ -634,3 +954,15 @@ string FGAIFlightPlan::getRunwayClassFromTrafficType(string fltType)
}
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;
}

View file

@ -300,8 +300,11 @@ void FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
rwy = arr->getRunwayByIdent(activeRunway);
// begin descent 110km out
SGGeod beginDescentPoint = rwy->pointOnCenterline(-110000);
SGGeod beginDescentPoint = rwy->pointOnCenterline(0);
SGGeod secondaryDescentPoint = rwy->pointOnCenterline(-10000);
wpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
waypoints.push_back(wpt);
wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
waypoints.push_back(wpt);
}

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,8 @@
#include <simgear/compiler.h>
// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER...
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/debug/logstream.hxx>
@ -185,6 +187,9 @@ public:
typedef vector<FGTrafficRecord> TrafficVector;
typedef vector<FGTrafficRecord>::iterator TrafficVectorIterator;
typedef vector<time_t> TimeVector;
typedef vector<time_t>::iterator TimeVectorIterator;
/***********************************************************************
* Active runway, a utility class to keep track of which aircraft has
@ -195,11 +200,18 @@ class ActiveRunway
private:
string rwy;
int currentlyCleared;
double distanceToFinal;
TimeVector estimatedArrivalTimes;
public:
ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; };
ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; distanceToFinal = 6.0 * SG_NM_TO_METER; };
string getRunwayName() { return rwy; };
int getCleared () { return currentlyCleared; };
double getApproachDistance() { return distanceToFinal; };
//time_t getEstApproachTime() { return estimatedArrival; };
//void setEstApproachTime(time_t time) { estimatedArrival = time; };
time_t requestTimeSlot(time_t eta);
};
typedef vector<ActiveRunway> ActiveRunwayVec;
@ -207,7 +219,7 @@ typedef vector<ActiveRunway>::iterator ActiveRunwayVecIterator;
/**
* class FGATCController
* NOTE: this class serves as an abstraction layer for all sorts of ATC controller.
* NOTE: this class serves as an abstraction layer for all sorts of ATC controllers.
*************************************************************************************/
class FGATCController
{
@ -317,4 +329,33 @@ public:
};
/******************************************************************************
* class FGTowerControl
*****************************************************************************/
class FGApproachController : public FGATCController
{
private:
TrafficVector activeTraffic;
ActiveRunwayVec activeRunways;
public:
FGApproachController();
virtual ~FGApproachController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void update(int id, double lat, double lon,
double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
ActiveRunway* getRunway(string name);
bool hasActiveTraffic() { return activeTraffic.size() != 0; };
TrafficVector &getActiveTraffic() { return activeTraffic; };
};
#endif // _TRAFFIC_CONTROL_HXX

View file

@ -325,17 +325,21 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
takeoff.clear();
lastUpdate = dayStart;
prevTrafficType = trafficType;
/*
FGEnvironment
stationweather =
((FGEnvironmentMgr *) globals->get_subsystem("environment"))
->getEnvironment(getLatitude(), getLongitude(),
getElevation());
windSpeed = stationweather.get_wind_speed_kt();
windHeading = stationweather.get_wind_from_heading_deg();
*/
windSpeed = fgGetInt("/environment/metar/base-wind-speed-kt"); //stationweather.get_wind_speed_kt();
windHeading = fgGetInt("/environment/metar/base-wind-dir-deg");
//stationweather.get_wind_from_heading_deg();
string scheduleName;
//cerr << "finding active Runway for" << _ap->getId() << endl;
//cerr << "finding active Runway for : " << _ap->getId() << endl;
//cerr << "Wind Heading : " << windHeading << endl;
//cerr << "Wind Speed : " << windSpeed << endl;
//cerr << "Nr of seconds since day start << " << dayStart << endl;
ScheduleTime *currSched;
@ -347,7 +351,7 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
scheduleName = currSched->getName(dayStart);
maxTail = currSched->getTailWind();
maxCross = currSched->getCrossWind();
//cerr << "SChedule anme = " << scheduleName << endl;
//cerr << "Current Schedule = : " << scheduleName << endl;
if (scheduleName.empty())
return false;
//cerr << "C"<< endl;
@ -371,6 +375,13 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
currentlyActive = &ulActive;
}
//cerr << "Durrently active selection for " << trafficType << ": ";
for (stringVecIterator it = currentlyActive->begin();
it != currentlyActive->end(); it++) {
//cerr << (*it) << " ";
}
//cerr << endl;
currRunwayGroup->setActive(_ap,
windSpeed,
windHeading,

View file

@ -52,6 +52,7 @@ private:
FGStartupController startupController;
FGGroundNetwork groundNetwork;
FGTowerController towerController;
FGApproachController approachController;
time_t lastUpdate;
string prevTrafficType;
@ -115,6 +116,7 @@ public:
FGStartupController *getStartupController() { return &startupController; };
FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
FGTowerController *getTowerController() { return &towerController; };
FGApproachController *getApproachController() { return &approachController; };
const string& getAtisInformation() { return atisInformation; };
int getGroundFrequency(unsigned leg); //{ return freqGround.size() ? freqGround[0] : 0; };

View file

@ -553,19 +553,21 @@ void FGGroundNetwork::update(int id, double lat, double lon,
current->clearResolveCircularWait();
current->setWaitsForId(0);
checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
if (!needsTaxiClearance) {
checkHoldPosition(id, lat, lon, heading, speed, alt);
if (checkForCircularWaits(id)) {
i->setResolveCircularWait();
}
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
} else {
current->setHoldPosition(true);
int state = current->getState();
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
if ((now - lastTransmission) > 15) {
available = true;
}
if (needsTaxiClearance && available) {
if ((state < 3) && available) {
transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
current->getAircraft()->setTaxiClearanceRequest(false);
current->setState(3);
lastTransmission = now;
available = false;
@ -578,10 +580,19 @@ void FGGroundNetwork::update(int id, double lat, double lon,
}
if ((state == 4) && available) {
transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
current->setState(0);
current->setState(5);
lastTransmission = now;
available = false;
}
if ((state == 5) && available) {
current->setState(0);
current->getAircraft()->setTaxiClearanceRequest(false);
current->setHoldPosition(true);
available = false;
}
}
}
/**

View file

@ -73,6 +73,27 @@ SGGeod FGRunwayBase::pointOnCenterline(double aOffset) const
return result;
}
SGGeod FGRunwayBase::pointOffCenterline(double aOffset, double lateralOffset) const
{
SGGeod result;
SGGeod temp;
double dummyAz2;
double halfLengthMetres = lengthM() * 0.5;
SGGeodesy::direct(mPosition, _heading,
aOffset - halfLengthMetres,
temp, dummyAz2);
SGGeodesy::direct(temp, (_heading+90.0),
lateralOffset,
result, dummyAz2);
return result;
}
bool FGRunwayBase::isHardSurface() const
{
return ((_surface_code == 1) || (_surface_code == 2));

View file

@ -52,6 +52,7 @@ public:
* opposited direction. 0.0 corresponds to the (non-displaced) threshold
*/
SGGeod pointOnCenterline(double aOffset) const;
SGGeod pointOffCenterline(double aOffset, double lateralOffset) const;
double lengthFt() const
{ return _length; }

View file

@ -48,7 +48,7 @@ void ScheduleTime::clear()
}
ScheduleTime::ScheduleTime(const ScheduleTime &other)
ScheduleTime::ScheduleTime(const ScheduleTime & other)
{
//timeVec start;
timeVecConstIterator i;
@ -57,7 +57,8 @@ ScheduleTime::ScheduleTime(const ScheduleTime &other)
for (i = other.end.begin(); i != other.end.end(); i++)
end.push_back(*i);
stringVecConstIterator k;
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
k++)
scheduleNames.push_back(*k);
//timeVec end;
@ -67,7 +68,7 @@ ScheduleTime::ScheduleTime(const ScheduleTime &other)
}
ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
ScheduleTime & ScheduleTime::operator=(const ScheduleTime & other)
{
//timeVec start;
clear();
@ -77,7 +78,8 @@ ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
for (i = other.end.begin(); i != other.end.end(); i++)
end.push_back(*i);
stringVecConstIterator k;
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
k++)
scheduleNames.push_back(*k);
//timeVec end;
@ -86,21 +88,18 @@ ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
crssWind = other.tailWind;
return *this;
}
string ScheduleTime::getName(time_t dayStart)
{
if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
{
SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
if ((start.size() != end.size())
|| (start.size() != scheduleNames.size())) {
SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
exit(1);
}
else
{
} else {
int nrItems = start.size();
//cerr << "Nr of items to process: " << nrItems << endl;
if (nrItems > 0)
{
for (unsigned int i = 0; i < start.size(); i++)
{
if (nrItems > 0) {
for (unsigned int i = 0; i < start.size(); i++) {
//cerr << i << endl;
if ((dayStart >= start[i]) && (dayStart <= end[i]))
return scheduleNames[i];
@ -111,27 +110,32 @@ string ScheduleTime::getName(time_t dayStart)
}
return string("");
}
/******************************************************************************
* RunwayList
*****************************************************************************/
RunwayList::RunwayList(const RunwayList &other)
RunwayList::RunwayList(const RunwayList & other)
{
type = other.type;
stringVecConstIterator i;
for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
for (i = other.preferredRunways.begin();
i != other.preferredRunways.end(); i++)
preferredRunways.push_back(*i);
}
RunwayList& RunwayList::operator= (const RunwayList &other)
RunwayList & RunwayList::operator=(const RunwayList & other)
{
type = other.type;
preferredRunways.clear();
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);
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());
// timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
@ -139,12 +143,11 @@ void RunwayList::set(const string &tp, const string &lst)
type = tp;
string rwys = lst;
string rwy;
while (rwys.find(",") != string::npos)
{
rwy = rwys.substr(0, rwys.find(",",0));
while (rwys.find(",") != string::npos) {
rwy = rwys.substr(0, rwys.find(",", 0));
//cerr << "adding runway [" << rwy << "] to the list " << endl;
preferredRunways.push_back(rwy);
rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
rwys.erase(0, rwys.find(",", 0) + 1); // erase until after the first whitspace
while (rwys[0] == ' ')
rwys.erase(0, 1); // Erase any leading whitespaces.
//cerr << "Remaining runway list " << rwys;
@ -158,11 +161,12 @@ void RunwayList::clear()
type = "";
preferredRunways.clear();
}
/****************************************************************************
*
***************************************************************************/
RunwayGroup::RunwayGroup(const RunwayGroup &other)
RunwayGroup::RunwayGroup(const RunwayGroup & other)
{
name = other.name;
RunwayListVecConstIterator i;
@ -172,7 +176,8 @@ RunwayGroup::RunwayGroup(const RunwayGroup &other)
choice[1] = other.choice[1];
nrActive = other.nrActive;
}
RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
{
rwyList.clear();
name = other.name;
@ -185,15 +190,14 @@ RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
return *this;
}
void RunwayGroup::setActive(const FGAirport* airport,
void RunwayGroup::setActive(const FGAirport * airport,
double windSpeed,
double windHeading,
double maxTail,
double maxCross,
stringVec *currentlyActive)
double maxCross, stringVec * currentlyActive)
{
FGRunway* rwy;
FGRunway *rwy;
int activeRwys = rwyList.size(); // get the number of runways active
int nrOfPreferences;
// bool found = true;
@ -205,16 +209,14 @@ void RunwayGroup::setActive(const FGAirport* airport,
//stringVec names;
int bestMatch = 0, bestChoice = 0;
if (activeRwys > 0)
{
if (activeRwys > 0) {
// Now downward iterate across all the possible preferences
// starting by the least preferred choice working toward the most preferred choice
nrOfPreferences = rwyList[0].getRwyList()->size();
bool validSelection = true;
bool foundValidSelection = false;
for (int i = nrOfPreferences-1; i >= 0; i--)
{
for (int i = nrOfPreferences - 1; i >= 0; i--) {
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.
//
validSelection = true;
for (int j = 0; j < activeRwys; j++)
{
for (int j = 0; j < activeRwys; j++) {
string ident(rwyList[j].getRwyList(i));
if (!airport->hasRunwayWithIdent(ident)) {
SG_LOG(SG_GENERAL, SG_WARN, "no such runway:" << ident << " at " << airport->ident());
SG_LOG(SG_GENERAL, SG_WARN,
"no such runway:" << ident << " at " <<
airport->ident());
continue;
}
@ -236,47 +240,45 @@ void RunwayGroup::setActive(const FGAirport* airport,
//cerr << "Succes" << endl;
hdgDiff = fabs(windHeading - rwy->headingDeg());
//cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
//cerr << "Wind Speed : " << windSpeed << endl;
name = rwy->name();
if (hdgDiff > 180)
hdgDiff = 360 - hdgDiff;
//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);
tailWind = -windSpeed * cos(hdgDiff);
//cerr << "Runway : " << rwy->name() << ": " << rwy->headingDeg() << endl;
//cerr << ". Tailwind : " << tailWind;
//cerr << ". Crosswnd : " << crossWind;
if ((tailWind > maxTail) || (crossWind > maxCross))
{
if ((tailWind > maxTail) || (crossWind > maxCross)) {
//cerr << ". [Invalid] " << endl;
validSelection = false;
}
else
{
} else {
//cerr << ". [Valid] ";
}
//cerr << endl;
} // of active runways iteration
if (validSelection)
{
//cerr << "Valid selection : " << i << endl;;
foundValidSelection = true;
for (stringVecIterator it = currentlyActive->begin();
it != currentlyActive->end(); it++)
{
if ((*it) == name)
it != currentlyActive->end(); it++) {
//cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
if ((*it) == name) {
match++;
}
}
} // of active runways iteration
if (validSelection) {
//cerr << "Valid selection : " << i << endl;;
foundValidSelection = true;
if (match >= bestMatch) {
bestMatch = match;
bestChoice = i;
}
}
//cerr << "Preference " << i << " 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;
nrActive = activeRwys;
active = bestChoice;
@ -286,8 +288,7 @@ void RunwayGroup::setActive(const FGAirport* airport,
// but select only one landing and one takeoff runway.
choice[0] = 0;
choice[1] = 0;
for (int i = activeRwys-1; i; i--)
{
for (int i = activeRwys - 1; i; i--) {
if (rwyList[i].getType() == string("landing"))
choice[0] = i;
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;
nrOfPreferences = rwyList[0].getRwyList()->size();
for (int i = 0; i < nrOfPreferences; i++)
{
for (int i = 0; i < nrOfPreferences; i++) {
bool validSelection = true;
for (int j = 0; j < 2; j++)
{
for (int j = 0; j < 2; j++) {
name = rwyList[choice[j]].getRwyList(i);
rwy = airport->getRunwayByIdent(name);
@ -307,7 +306,7 @@ void RunwayGroup::setActive(const FGAirport* airport,
hdgDiff = fabs(windHeading - rwy->headingDeg());
if (hdgDiff > 180)
hdgDiff = 360 - hdgDiff;
hdgDiff *= ((2*M_PI)/360.0); // convert to radians
hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
crossWind = windSpeed * sin(hdgDiff);
tailWind = -windSpeed * cos(hdgDiff);
if ((tailWind > maxTail) || (crossWind > maxCross))
@ -315,8 +314,7 @@ void RunwayGroup::setActive(const FGAirport* airport,
}
if (validSelection)
{
if (validSelection) {
//cerr << "Valid runay selection : " << i << endl;
active = i;
nrActive = 2;
@ -328,34 +326,31 @@ void RunwayGroup::setActive(const FGAirport* airport,
nrActive = 0;
}
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;
}
if (nrActive == (int)rwyList.size())
{
if (nrActive == (int) rwyList.size()) {
name = rwyList[i].getRwyList(active);
type = rwyList[i].getType();
}
else
{
} else {
name = rwyList[choice[i]].getRwyList(active);
type = rwyList[choice[i]].getType();
}
}
/*****************************************************************************
* FGRunway preference
****************************************************************************/
FGRunwayPreference::FGRunwayPreference(FGAirport* ap) :
_ap(ap)
FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
_ap(ap)
{
//cerr << "Running default Constructor" << endl;
initialized = false;
}
FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
{
initialized = other.initialized;
@ -368,7 +363,8 @@ FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
preferences.push_back(*i);
}
FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
& other)
{
initialized = other.initialized;
@ -397,7 +393,7 @@ ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
return 0;
}
RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
RunwayGroup *FGRunwayPreference::getGroup(const string & groupName)
{
PreferenceListIterator i = preferences.begin();
if (preferences.begin() == preferences.end())
@ -410,6 +406,7 @@ RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
return 0;
}
string FGRunwayPreference::getId() {
string FGRunwayPreference::getId()
{
return _ap->getId();
};
};

View file

@ -289,7 +289,6 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
return true; // out of visual range, for the moment.
}
return createAIAircraft(flight, speed, deptime);
}

View file

@ -137,7 +137,9 @@ void FGTrafficManager::init()
void FGTrafficManager::update(double /*dt*/)
{
if (fgGetBool("/environment/metar/valid") == false) {
return;
}
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
if (scheduledAircraft.size() == 0) {
return;