-// // // FGAIAircraft - FGAIBase-derived class creates an AI airplane
+// FGAIAircraft - FGAIBase-derived class creates an AI airplane
//
// Written by David Culp, started October 2003.
//
roll = 0;
headingChangeRate = 0.0;
headingError = 0;
+ minBearing = 360;
+ speedFraction =1.0;
holdPos = false;
needsTaxiClearance = false;
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);
//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;
}
-bool FGAIAircraft::loadNextLeg() {
+bool FGAIAircraft::loadNextLeg(double distance) {
int leg;
if ((leg = fp->getLeg()) == 10) {
trafficRef->getRadius(),
trafficRef->getFlightType(),
acType,
- company);
+ company,
+ distance);
//cerr << "created leg " << leg << " for " << trafficRef->getCallSign() << endl;
}
return true;
altitude_ft = (tgt_altitude_ft + groundOffset);
else
altitude_ft += 0.1 * ((tgt_altitude_ft+groundOffset) - altitude_ft);
+ tgt_vs = 0;
}
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();
// << 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;
+ }
}
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);
//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...
+}
\ No newline at end of file
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);
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;};
inline double altitudeAGL() const { return props->getFloatValue("position/altitude-agl-ft");};
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
std::string atGate();
+
protected:
void Run(double dt);
double dt_elev_count;
double headingChangeRate;
double headingError;
+ double minBearing;
+ double speedFraction;
double groundTargetSpeed;
double groundOffset;
double dt;
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,
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;
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++;
//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;
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){
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;
+}
\ No newline at end of file
bool on_ground;
int routeIndex; // For AI/ATC purposes;
double time_sec;
+ double trackLength; // distance from previous waypoint (for AI purposes);
string time;
} waypoint;
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; }
typedef vector <waypoint*> wpt_vector_type;
typedef wpt_vector_type::const_iterator wpt_vector_iterator;
+
wpt_vector_type waypoints;
wpt_vector_iterator wpt_iterator;
double lead_distance;
double leadInAngle;
time_t start_time;
+ time_t arrivalTime; // For AI/ATC purposes.
int leg;
int gateId, lastNodeVisited;
string activeRunway;
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();
void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport);
void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
void createTakeoffTaxi(FGAIAircraft *, bool firstFlight, FGAirport *apt, double radius, const string& fltType, const string& acType, const string& airline);
+
+ double getTurnRadius(double, bool);
waypoint* createOnGround(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
waypoint* createInAir(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
*
* This is the top-level function, and the only one that is publicly available.
*
- */
+ */
// 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)
-{
- int currWpt = wpt_iterator - waypoints.begin();
- switch(legNr)
- {
- case 1:
- createPushBack(ac, firstFlight,dep, latitude, longitude,
- radius, fltType, aircraftType, airline);
- break;
- case 2:
- createTakeoffTaxi(ac, firstFlight, dep, radius, fltType, aircraftType, airline);
- break;
- case 3:
- createTakeOff(ac, firstFlight, dep, speed, fltType);
- break;
- case 4:
- createClimb(ac, firstFlight, dep, speed, alt, fltType);
- break;
- case 5:
- createCruise(ac, firstFlight, dep,arr, latitude, longitude, speed, alt, fltType);
- break;
- case 6:
- createDecent(ac, arr, fltType);
- break;
- case 7:
- createLanding(ac, arr, fltType);
- break;
- case 8:
- createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
- break;
- case 9:
- createParking(ac, arr, radius);
- break;
+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) {
+ case 1:
+ createPushBack(ac, firstFlight, dep, latitude, longitude,
+ radius, fltType, aircraftType, airline);
+ break;
+ case 2:
+ createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
+ aircraftType, airline);
+ break;
+ case 3:
+ createTakeOff(ac, firstFlight, dep, speed, fltType);
+ break;
+ case 4:
+ createClimb(ac, firstFlight, dep, speed, alt, fltType);
+ break;
+ case 5:
+ createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
+ alt, fltType);
+ break;
+ case 6:
+ createDescent(ac, arr, latitude, longitude, speed, alt, fltType,
+ distance);
+ break;
+ case 7:
+ createLanding(ac, arr, fltType);
+ break;
+ case 8:
+ createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
+ break;
+ case 9:
+ createParking(ac, arr, radius);
+ break;
default:
- //exit(1);
- SG_LOG(SG_INPUT, SG_ALERT, "AIFlightPlan::create() attempting to create unknown leg"
- " this is probably an internal program error");
+ //exit(1);
+ 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;
- leg++;
+ 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;
- wpt->name = aName;
- wpt->longitude = aPos.getLongitudeDeg();
- wpt->latitude = aPos.getLatitudeDeg();
- wpt->altitude = aElev;
- wpt->speed = aSpeed;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = true;
- wpt->routeIndex= 0;
- return wpt;
+ waypoint *wpt = new waypoint;
+ wpt->name = aName;
+ wpt->longitude = aPos.getLongitudeDeg();
+ wpt->latitude = aPos.getLatitudeDeg();
+ wpt->altitude = aElev;
+ wpt->speed = aSpeed;
+ wpt->crossat = -10000.1;
+ wpt->gear_down = true;
+ wpt->flaps_down = true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ 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;
- wpt->name = aName;
- wpt->longitude = aPos.getLongitudeDeg();
- wpt->latitude = aPos.getLatitudeDeg();
- wpt->altitude = aElev;
- wpt->speed = aSpeed;
- wpt->crossat = -10000;
- wpt->gear_down = false;
- wpt->flaps_down= false;
- wpt->finished = false;
- wpt->on_ground = false;
- wpt->routeIndex= 0;
- return wpt;
+ waypoint *wpt = new waypoint;
+ wpt->name = aName;
+ wpt->longitude = aPos.getLongitudeDeg();
+ wpt->latitude = aPos.getLatitudeDeg();
+ wpt->altitude = aElev;
+ wpt->speed = aSpeed;
+ wpt->crossat = -10000.1;
+ wpt->gear_down = false;
+ wpt->flaps_down = false;
+ wpt->finished = false;
+ wpt->on_ground = false;
+ 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;
- wpt->name = aName;
- wpt->longitude = aPos.getLongitudeDeg();
- wpt->latitude = aPos.getLatitudeDeg();
-
- wpt->altitude = aWpt->altitude;
- wpt->speed = aWpt->speed;
- wpt->crossat = aWpt->crossat;
- wpt->gear_down = aWpt->gear_down;
- wpt->flaps_down= aWpt->flaps_down;
- wpt->finished = aWpt->finished;
- wpt->on_ground = aWpt->on_ground;
- wpt->routeIndex = 0;
-
- return wpt;
+ waypoint *wpt = new waypoint;
+ wpt->name = aName;
+ wpt->longitude = aPos.getLongitudeDeg();
+ wpt->latitude = aPos.getLatitudeDeg();
+
+ wpt->altitude = aWpt->altitude;
+ wpt->speed = aWpt->speed;
+ wpt->crossat = aWpt->crossat;
+ wpt->gear_down = aWpt->gear_down;
+ wpt->flaps_down = aWpt->flaps_down;
+ wpt->finished = aWpt->finished;
+ wpt->on_ground = aWpt->on_ground;
+ wpt->routeIndex = 0;
+
+ return wpt;
}
-FGAIFlightPlan::waypoint*
-FGAIFlightPlan::clone(waypoint* aWpt)
+FGAIFlightPlan::waypoint * FGAIFlightPlan::clone(waypoint * aWpt)
{
- waypoint* wpt = new waypoint;
- wpt->name = aWpt->name;
- wpt->longitude = aWpt->longitude;
- wpt->latitude = aWpt->latitude;
-
- wpt->altitude = aWpt->altitude;
- wpt->speed = aWpt->speed;
- wpt->crossat = aWpt->crossat;
- wpt->gear_down = aWpt->gear_down;
- wpt->flaps_down= aWpt->flaps_down;
- wpt->finished = aWpt->finished;
- wpt->on_ground = aWpt->on_ground;
- wpt->routeIndex = 0;
-
- return wpt;
+ waypoint *wpt = new waypoint;
+ wpt->name = aWpt->name;
+ wpt->longitude = aWpt->longitude;
+ wpt->latitude = aWpt->latitude;
+
+ wpt->altitude = aWpt->altitude;
+ wpt->speed = aWpt->speed;
+ wpt->crossat = aWpt->crossat;
+ wpt->gear_down = aWpt->gear_down;
+ wpt->flaps_down = aWpt->flaps_down;
+ wpt->finished = aWpt->finished;
+ wpt->on_ground = aWpt->on_ground;
+ wpt->routeIndex = 0;
+
+ return wpt;
}
-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());
- waypoints.push_back(wpt);
- wpt = createOnGround(ac, "Runway Takeoff", runwayTakeoff, airportElev, ac->getPerformance()->vTaxi());
- waypoints.push_back(wpt);
+ SGGeod runwayTakeoff = aRunway->pointOnCenterline(5.0);
+ double airportElev = aAirport->getElevation();
+
+ 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());
+ 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;
-
- // If this function is called during initialization,
- // make sure we obtain a valid gate ID first
- // and place the model at the location of the gate.
- if (firstFlight) {
- if (!(apt->getDynamics()->getAvailableParking(&lat, &lon,
- &heading, &gateId,
- radius, fltType,
- acType, airline)))
- {
- SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " <<
- acType <<
- " of flight type " << fltType <<
- " of airline " << airline <<
- " at airport " << apt->getId());
- }
- }
-
- string rwyClass = getRunwayClassFromTrafficType(fltType);
-
- // Only set this if it hasn't been set by ATC already.
- if (activeRunway.empty()) {
- //cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
- double depHeading = ac->getTrafficRef()->getCourse();
- apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, depHeading);
- }
- rwy = apt->getRunwayByIdent(activeRunway);
- SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
-
- FGGroundNetwork* gn = apt->getDynamics()->getGroundNetwork();
- if (!gn->exists()) {
- createDefaultTakeoffTaxi(ac, apt, rwy);
- return;
- }
-
- intVec ids;
- int runwayId = gn->findNearestNode(runwayTakeoff);
-
- // A negative gateId indicates an overflow parking, use a
- // fallback mechanism for this.
- // Starting from gate 0 in this case is a bit of a hack
- // which requires a more proper solution later on.
- delete taxiRoute;
- taxiRoute = new FGTaxiRoute;
-
- // Determine which node to start from.
- int node = 0;
- // Find out which node to start from
- FGParking *park = apt->getDynamics()->getParking(gateId);
- if (park) {
- node = park->getPushBackPoint();
- }
-
- if (node == -1) {
- node = gateId;
- }
-
- // HAndle case where parking doens't have a node
- if ((node == 0) && park) {
+ double heading, lat, lon;
+
+ // If this function is called during initialization,
+ // make sure we obtain a valid gate ID first
+ // and place the model at the location of the gate.
if (firstFlight) {
- node = gateId;
+ if (!(apt->getDynamics()->getAvailableParking(&lat, &lon,
+ &heading, &gateId,
+ radius, fltType,
+ acType, airline))) {
+ SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " <<
+ acType <<
+ " of flight type " << fltType <<
+ " of airline " << airline <<
+ " at airport " << apt->getId());
+ }
+ }
+
+ string rwyClass = getRunwayClassFromTrafficType(fltType);
+
+ // Only set this if it hasn't been set by ATC already.
+ if (activeRunway.empty()) {
+ //cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
+ double depHeading = ac->getTrafficRef()->getCourse();
+ apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+ depHeading);
+ }
+ rwy = apt->getRunwayByIdent(activeRunway);
+ SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
+
+ FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
+ if (!gn->exists()) {
+ createDefaultTakeoffTaxi(ac, apt, rwy);
+ return;
+ }
+
+ intVec ids;
+ int runwayId = gn->findNearestNode(runwayTakeoff);
+
+ // A negative gateId indicates an overflow parking, use a
+ // fallback mechanism for this.
+ // Starting from gate 0 in this case is a bit of a hack
+ // which requires a more proper solution later on.
+ delete taxiRoute;
+ taxiRoute = new FGTaxiRoute;
+
+ // Determine which node to start from.
+ int node = 0;
+ // Find out which node to start from
+ FGParking *park = apt->getDynamics()->getParking(gateId);
+ if (park) {
+ node = park->getPushBackPoint();
+ }
+
+ if (node == -1) {
+ node = gateId;
+ }
+ // HAndle case where parking doens't have a node
+ if ((node == 0) && park) {
+ if (firstFlight) {
+ node = gateId;
+ } else {
+ node = lastNodeVisited;
+ }
+ }
+
+ *taxiRoute = gn->findShortestRoute(node, runwayId);
+ intVecIterator i;
+
+ if (taxiRoute->empty()) {
+ createDefaultTakeoffTaxi(ac, apt, rwy);
+ return;
+ }
+
+ taxiRoute->first();
+ //bool isPushBackPoint = false;
+ if (firstFlight) {
+ // If this is called during initialization, randomly
+ // skip a number of waypoints to get a more realistic
+ // taxi situation.
+ 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 - 3; i++) {
+ taxiRoute->next(&node);
+ }
+ apt->getDynamics()->releaseParking(gateId);
} else {
- node = lastNodeVisited;
- }
- }
-
- *taxiRoute = gn->findShortestRoute(node, runwayId);
- intVecIterator i;
-
- if (taxiRoute->empty()) {
- createDefaultTakeoffTaxi(ac, apt, rwy);
- return;
- }
-
- taxiRoute->first();
- //bool isPushBackPoint = false;
- if (firstFlight) {
- // If this is called during initialization, randomly
- // skip a number of waypoints to get a more realistic
- // taxi situation.
- 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++) {
- taxiRoute->next(&node);
- }
- apt->getDynamics()->releaseParking(gateId);
- } else {
- if (taxiRoute->size() > 1) {
- taxiRoute->next(&node); // chop off the first waypoint, because that is already the last of the pushback route
- }
- }
-
- // push each node on the taxi route as a waypoint
- int 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());
- wpt->routeIndex = route;
- waypoints.push_back(wpt);
- }
+ if (taxiRoute->size() > 1) {
+ taxiRoute->next(&node); // chop off the first waypoint, because that is already the last of the pushback route
+ }
+ }
+
+ // push each node on the taxi route as a waypoint
+ int 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());
+ 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);
- double airportElev = aAirport->getElevation();
-
- 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());
- 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());
- waypoints.push_back(wpt);
+ SGGeod lastWptPos =
+ SGGeod::fromDeg(waypoints.back()->longitude,
+ waypoints.back()->latitude);
+ double airportElev = aAirport->getElevation();
+
+ 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());
+ 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());
+ 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);
-
- SGGeod lastWptPos =
- 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()) {
- createDefaultLandingTaxi(ac, apt);
- return;
- }
-
- intVec ids;
- int runwayId = gn->findNearestNode(lastWptPos);
- // A negative gateId indicates an overflow parking, use a
- // fallback mechanism for this.
- // Starting from gate 0 is a bit of a hack...
- //FGTaxiRoute route;
- delete taxiRoute;
- taxiRoute = new FGTaxiRoute;
- if (gateId >= 0)
- *taxiRoute = gn->findShortestRoute(runwayId, gateId);
- else
- *taxiRoute = gn->findShortestRoute(runwayId, 0);
- intVecIterator i;
-
- if (taxiRoute->empty()) {
- createDefaultLandingTaxi(ac, apt);
- return;
- }
-
- int node;
- taxiRoute->first();
- int size = taxiRoute->size();
- // Omit the last two waypoints, as
- // those are created by createParking()
- int route;
- for (int i = 0; i < size-2; i++) {
- taxiRoute->next(&node, &route);
- char buffer[10];
- snprintf (buffer, 10, "%d", node);
- FGTaxiNode *tn = gn->findNode(node);
- waypoint* wpt = createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(), ac->getPerformance()->vTaxi());
- wpt->routeIndex = route;
- waypoints.push_back(wpt);
- }
+ double heading, lat, lon;
+ apt->getDynamics()->getAvailableParking(&lat, &lon, &heading,
+ &gateId, radius, fltType,
+ acType, airline);
+
+ SGGeod lastWptPos =
+ 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()) {
+ createDefaultLandingTaxi(ac, apt);
+ return;
+ }
+
+ intVec ids;
+ int runwayId = gn->findNearestNode(lastWptPos);
+ // A negative gateId indicates an overflow parking, use a
+ // fallback mechanism for this.
+ // Starting from gate 0 is a bit of a hack...
+ //FGTaxiRoute route;
+ delete taxiRoute;
+ taxiRoute = new FGTaxiRoute;
+ if (gateId >= 0)
+ *taxiRoute = gn->findShortestRoute(runwayId, gateId);
+ else
+ *taxiRoute = gn->findShortestRoute(runwayId, 0);
+ intVecIterator i;
+
+ if (taxiRoute->empty()) {
+ createDefaultLandingTaxi(ac, apt);
+ return;
+ }
+
+ int node;
+ taxiRoute->first();
+ int size = taxiRoute->size();
+ // Omit the last two waypoints, as
+ // those are created by createParking()
+ int route;
+ for (int i = 0; i < size - 2; i++) {
+ taxiRoute->next(&node, &route);
+ char buffer[10];
+ snprintf(buffer, 10, "%d", node);
+ FGTaxiNode *tn = gn->findNode(node);
+ waypoint *wpt =
+ createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(),
+ ac->getPerformance()->vTaxi());
+ wpt->routeIndex = route;
+ waypoints.push_back(wpt);
+ }
}
/*******************************************************************
* 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();
- double vRotate = ac->getPerformance()->vRotate();
+ double accel = ac->getPerformance()->acceleration();
+ double vTaxi = ac->getPerformance()->vTaxi();
+ double vRotate = ac->getPerformance()->vRotate();
double vTakeoff = ac->getPerformance()->vTakeoff();
- double vClimb = ac->getPerformance()->vClimb();
+ double vClimb = ac->getPerformance()->vClimb();
- double accelMetric = (accel * SG_NM_TO_METER) / 3600;
- double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600;
- double vRotateMetric = (vRotate * SG_NM_TO_METER) / 3600;
- double vTakeoffMetric = (vTakeoff * SG_NM_TO_METER) / 3600;
- double vClimbMetric = (vClimb * SG_NM_TO_METER) / 3600;
+ double accelMetric = (accel * SG_NM_TO_METER) / 3600;
+ double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600;
+ double vRotateMetric = (vRotate * SG_NM_TO_METER) / 3600;
+ double vTakeoffMetric = (vTakeoff * SG_NM_TO_METER) / 3600;
+ double vClimbMetric = (vClimb * SG_NM_TO_METER) / 3600;
// Acceleration = dV / dT
// Acceleration X dT = dV
// dT = dT / Acceleration
//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);
}
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);
}
-
+
/*******************************************************************
* 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;
+ waypoint *wpt;
// bool planLoaded = false;
- string fPLName;
- double vClimb = ac->getPerformance()->vClimb();
+ string fPLName;
+ double vClimb = ac->getPerformance()->vClimb();
- if (firstFlight) {
- string rwyClass = getRunwayClassFromTrafficType(fltType);
- double heading = ac->getTrafficRef()->getCourse();
- apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
- rwy = apt->getRunwayByIdent(activeRunway);
- }
- if (sid) {
- for (wpt_vector_iterator i = sid->getFirstWayPoint();
- i != sid->getLastWayPoint();
- i++) {
+ if (firstFlight) {
+ string rwyClass = getRunwayClassFromTrafficType(fltType);
+ double heading = ac->getTrafficRef()->getCourse();
+ apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+ heading);
+ rwy = apt->getRunwayByIdent(activeRunway);
+ }
+ if (sid) {
+ for (wpt_vector_iterator i = sid->getFirstWayPoint();
+ i != sid->getLastWayPoint(); i++) {
waypoints.push_back(clone(*(i)));
//cerr << " Cloning waypoint " << endl;
+ }
+ } else {
+ 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;
+ waypoints.push_back(wpt);
+
+ SGGeod climb2 = rwy->pointOnCenterline(20 * SG_NM_TO_METER);
+ wpt = cloneWithPos(ac, wpt, "18000ft climb", climb2);
+ wpt->altitude = 18000;
+ waypoints.push_back(wpt);
}
- } else {
- 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;
- waypoints.push_back(wpt);
-
- SGGeod climb2 = rwy->pointOnCenterline(20*SG_NM_TO_METER);
- wpt = cloneWithPos(ac, wpt, "18000ft climb", climb2);
- wpt->altitude = 18000;
- waypoints.push_back(wpt);
- }
}
/*******************************************************************
- * 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
- waypoint *wpt;
- double vDecent = ac->getPerformance()->vDescent();
- double vApproach = ac->getPerformance()->vApproach();
-
- //Beginning of Decent
- //string name;
- // allow "mil" and "gen" as well
- string rwyClass = getRunwayClassFromTrafficType(fltType);
- double heading = ac->getTrafficRef()->getCourse();
- 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;
- waypoints.push_back(wpt);
+ bool reposition = false;
+ waypoint *wpt;
+ double vDescent = ac->getPerformance()->vDescent();
+ double vApproach = ac->getPerformance()->vApproach();
+
+
+ //Beginning of Descent
+ string rwyClass = getRunwayClassFromTrafficType(fltType);
+ double heading = ac->getTrafficRef()->getCourse();
+ apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
+ heading);
+ rwy = apt->getRunwayByIdent(activeRunway);
+
+
+
+ // 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);
-
-
- waypoint *wpt;
- double aptElev = apt->getElevation();
-
- SGGeod coord;
- 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));
- wpt->crossat = apt->getElevation();
- waypoints.push_back(wpt);
- }
-
- /*
- //Runway Threshold
- wpt = createOnGround(ac, "Threshold", rwy->threshold(), aptElev, vTouchdown);
- wpt->crossat = apt->getElevation();
- waypoints.push_back(wpt);
-
- // Roll-out
- wpt = createOnGround(ac, "Center", rwy->geod(), aptElev, vTaxi*2);
- waypoints.push_back(wpt);
-
- SGGeod rollOut = rwy->pointOnCenterline(rwy->lengthM() * 0.9);
- wpt = createOnGround(ac, "Roll Out", rollOut, aptElev, vTaxi);
- wpt->crossat = apt->getElevation();
- waypoints.push_back(wpt);
- */
+ 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);
+
+
+ waypoint *wpt;
+ double aptElev = apt->getElevation();
+
+ SGGeod coord;
+ 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));
+ wpt->crossat = apt->getElevation();
+ waypoints.push_back(wpt);
+ }
+
+ /*
+ //Runway Threshold
+ wpt = createOnGround(ac, "Threshold", rwy->threshold(), aptElev, vTouchdown);
+ wpt->crossat = apt->getElevation();
+ waypoints.push_back(wpt);
+
+ // Roll-out
+ wpt = createOnGround(ac, "Center", rwy->geod(), aptElev, vTaxi*2);
+ waypoints.push_back(wpt);
+
+ SGGeod rollOut = rwy->pointOnCenterline(rwy->lengthM() * 0.9);
+ wpt = createOnGround(ac, "Roll Out", rollOut, aptElev, vTaxi);
+ wpt->crossat = apt->getElevation();
+ waypoints.push_back(wpt);
+ */
}
/*******************************************************************
* 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;
- double aptElev = apt->getElevation();
- double lat = 0.0, lat2 = 0.0;
- double lon = 0.0, lon2 = 0.0;
- double az2 = 0.0;
- double heading = 0.0;
-
- double vTaxi = ac->getPerformance()->vTaxi();
- 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);
- waypoints.push_back(wpt);
-
- geo_direct_wgs_84 ( 0, lat, lon, heading,
- 0.1 *radius,
- &lat2, &lon2, &az2 );
-
- wpt = createOnGround(ac, "taxiStart2", SGGeod::fromDeg(lon2, lat2), aptElev, vTaxiReduced);
- waypoints.push_back(wpt);
-
- wpt = createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev, vTaxiReduced);
- waypoints.push_back(wpt);
+ waypoint *wpt;
+ double aptElev = apt->getElevation();
+ double lat = 0.0, lat2 = 0.0;
+ double lon = 0.0, lon2 = 0.0;
+ double az2 = 0.0;
+ double heading = 0.0;
+
+ double vTaxi = ac->getPerformance()->vTaxi();
+ 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);
+ waypoints.push_back(wpt);
+
+ geo_direct_wgs_84(0, lat, lon, heading,
+ 0.1 * radius, &lat2, &lon2, &az2);
+
+ wpt =
+ createOnGround(ac, "taxiStart2", SGGeod::fromDeg(lon2, lat2),
+ aptElev, vTaxiReduced);
+ waypoints.push_back(wpt);
+
+ wpt =
+ createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev,
+ vTaxiReduced);
+ waypoints.push_back(wpt);
}
/**
*/
string FGAIFlightPlan::getRunwayClassFromTrafficType(string fltType)
{
- if ((fltType == "gate") || (fltType == "cargo")) {
- return string("com");
+ if ((fltType == "gate") || (fltType == "cargo")) {
+ return string("com");
}
if (fltType == "ga") {
- return string ("gen");
+ return string("gen");
}
if (fltType == "ul") {
return string("ul");
}
- if ((fltType == "mil-fighter") || (fltType == "mil-transport")) {
- return string("mil");
+ if ((fltType == "mil-fighter") || (fltType == "mil-transport")) {
+ return string("mil");
+ }
+ 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 string("com");
+ return turn_radius;
}
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
rwy = arr->getRunwayByIdent(activeRunway);
// begin descent 110km out
- SGGeod beginDescentPoint = rwy->pointOnCenterline(-110000);
+ SGGeod beginDescentPoint = rwy->pointOnCenterline(0);
+ SGGeod secondaryDescentPoint = rwy->pointOnCenterline(-10000);
- wpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
+ wpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
+ waypoints.push_back(wpt);
+ wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
waypoints.push_back(wpt);
}
# include <config.h>
#endif
+#include <algorithm>
+
#include "trafficcontrol.hxx"
#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
+#include <AIModel/performancedata.hxx>
+#include <AIModel/performancedb.hxx>
#include <Traffic/TrafficMgr.hxx>
#include <Airports/groundnetwork.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::FGTrafficRecord() :
- id(0), waitsForId(0),
- currentPos(0),
- leg(0),
- frequencyId(0),
- state(0),
- allowTransmission(true),
- latitude(0),
- longitude(0),
- heading(0),
- speed(0),
- altitude(0),
- radius(0)
-{
-}
-
-void FGTrafficRecord::setPositionAndIntentions(int pos, FGAIFlightPlan *route)
-{
-
- currentPos = pos;
- if (intentions.size()) {
- intVecIterator i = intentions.begin();
- if ((*i) != pos) {
- SG_LOG(SG_GENERAL, SG_ALERT, "Error in FGTrafficRecord::setPositionAndIntentions");
- //cerr << "Pos : " << pos << " Curr " << *(intentions.begin()) << endl;
- for (intVecIterator i = intentions.begin(); i != intentions.end() ; i++) {
- //cerr << (*i) << " ";
- }
- //cerr << endl;
- }
- intentions.erase(i);
- } else {
- //FGAIFlightPlan::waypoint* const wpt= route->getCurrentWaypoint();
- int size = route->getNrOfWayPoints();
- //cerr << "Setting pos" << pos << " ";
- //cerr << "setting intentions ";
- for (int i = 0; i < size; i++) {
- int val = route->getRouteIndex(i);
- //cerr << val<< " ";
- if ((val) && (val != pos))
- {
- intentions.push_back(val);
- //cerr << "[set] ";
- }
- }
- //cerr << endl;
- //while (route->next(&legNr, &routeNr)) {
- //intentions.push_back(routeNr);
- //}
- //route->rewind(currentPos);
- }
- //exit(1);
-}
-
-bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord &other)
-{
- bool result = false;
- //cerr << "Start check 1" << endl;
- if (currentPos == other.currentPos)
- {
- //cerr << callsign << ": Check Position and intentions: we are on the same taxiway" << other.callsign << "Index = " << currentPos << endl;
- result = true;
- }
- // else if (other.intentions.size())
- // {
- // cerr << "Start check 2" << endl;
- // intVecIterator i = other.intentions.begin();
- // while (!((i == other.intentions.end()) || ((*i) == currentPos)))
- // i++;
- // if (i != other.intentions.end()) {
- // cerr << "Check Position and intentions: current matches other.intentions" << endl;
- // result = true;
- // }
- else if (intentions.size()) {
- //cerr << "Start check 3" << endl;
- intVecIterator i = intentions.begin();
- //while (!((i == intentions.end()) || ((*i) == other.currentPos)))
- while (i != intentions.end()) {
- if ((*i) == other.currentPos) {
- break;
- }
- i++;
- }
- if (i != intentions.end()) {
- //cerr << callsign << ": Check Position and intentions: .other.current matches" << other.callsign << "Index = " << (*i) << endl;
- result = true;
- }
- }
- //cerr << "Done !!" << endl;
- return result;
-}
-
-void FGTrafficRecord::setPositionAndHeading(double lat, double lon, double hdg,
- double spd, double alt)
-{
- latitude = lat;
- longitude = lon;
- heading = hdg;
- speed = spd;
- altitude = alt;
-}
-
-int FGTrafficRecord::crosses(FGGroundNetwork *net, FGTrafficRecord &other)
-{
- if (checkPositionAndIntentions(other) || (other.checkPositionAndIntentions(*this)))
- return -1;
- intVecIterator i, j;
- int currentTargetNode = 0, otherTargetNode = 0;
- if (currentPos > 0)
- currentTargetNode = net->findSegment(currentPos )->getEnd()->getIndex(); // OKAY,...
- if (other.currentPos > 0)
- otherTargetNode = net->findSegment(other.currentPos)->getEnd()->getIndex(); // OKAY,...
- if ((currentTargetNode == otherTargetNode) && currentTargetNode > 0)
- return currentTargetNode;
- if (intentions.size())
- {
- for (i = intentions.begin(); i != intentions.end(); i++)
- {
- if ((*i) > 0) {
- if ((currentTargetNode == net->findSegment(*i)->getEnd()->getIndex()))
- {
- //cerr << "Current crosses at " << currentTargetNode <<endl;
- return currentTargetNode;
- }
- }
- }
- }
- if (other.intentions.size())
- {
- for (i = other.intentions.begin(); i != other.intentions.end(); i++)
- {
- if ((*i) > 0) {
- if (otherTargetNode == net->findSegment(*i)->getEnd()->getIndex())
- {
- //cerr << "Other crosses at " << currentTargetNode <<endl;
- return otherTargetNode;
- }
- }
- }
- }
- if (intentions.size() && other.intentions.size())
- {
- for (i = intentions.begin(); i != intentions.end(); i++)
- {
- for (j = other.intentions.begin(); j != other.intentions.end(); j++)
- {
- //cerr << "finding segment " << *i << " and " << *j << endl;
- if (((*i) > 0) && ((*j) > 0)) {
- currentTargetNode = net->findSegment(*i)->getEnd()->getIndex();
- otherTargetNode = net->findSegment(*j)->getEnd()->getIndex();
- if (currentTargetNode == otherTargetNode)
- {
- //cerr << "Routes will cross at " << currentTargetNode << endl;
- return currentTargetNode;
- }
- }
- }
- }
- }
- return -1;
-}
-
-bool FGTrafficRecord::onRoute(FGGroundNetwork *net, FGTrafficRecord &other)
-{
- int node = -1, othernode = -1;
- if (currentPos >0)
- node = net->findSegment(currentPos)->getEnd()->getIndex();
- if (other.currentPos > 0)
- othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
- if ((node == othernode) && (node != -1))
- return true;
- if (other.intentions.size())
- {
- for (intVecIterator i = other.intentions.begin(); i != other.intentions.end(); i++)
- {
- if (*i > 0)
- {
- othernode = net->findSegment(*i)->getEnd()->getIndex();
- if ((node == othernode) && (node > -1))
- return true;
- }
- }
- }
- //if (other.currentPos > 0)
- // othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
- //if (intentions.size())
- // {
- // for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
- // {
- // if (*i > 0)
- // {
- // node = net->findSegment(*i)->getEnd()->getIndex();
- // if ((node == othernode) && (node > -1))
- // return true;
- // }
- // }
- // }
- return false;
-}
-
-
-bool FGTrafficRecord::isOpposing (FGGroundNetwork *net, FGTrafficRecord &other, int node)
-{
- // Check if current segment is the reverse segment for the other aircraft
- FGTaxiSegment *opp;
- //cerr << "Current segment " << currentPos << endl;
- if ((currentPos > 0) && (other.currentPos > 0))
- {
- opp = net->findSegment(currentPos)->opposite();
- if (opp) {
- if (opp->getIndex() == other.currentPos)
- return true;
- }
-
- for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
- {
- if ((opp = net->findSegment(other.currentPos)->opposite()))
- {
- if ((*i) > 0)
- if (opp->getIndex() == net->findSegment(*i)->getIndex())
- {
- if (net->findSegment(*i)->getStart()->getIndex() == node) {
- {
- //cerr << "Found the node " << node << endl;
- return true;
- }
- }
- }
- }
- if (other.intentions.size())
- {
- for (intVecIterator j = other.intentions.begin(); j != other.intentions.end(); j++)
- {
- // cerr << "Current segment 1 " << (*i) << endl;
- if ((*i) > 0) {
- if ((opp = net->findSegment(*i)->opposite()))
- {
- if (opp->getIndex() ==
- net->findSegment(*j)->getIndex())
- {
- //cerr << "Nodes " << net->findSegment(*i)->getIndex()
- // << " and " << net->findSegment(*j)->getIndex()
- // << " are opposites " << endl;
- if (net->findSegment(*i)->getStart()->getIndex() == node) {
- {
- //cerr << "Found the node " << node << endl;
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return false;
-}
-
-void FGTrafficRecord::setSpeedAdjustment(double spd)
-{
- instruction.setChangeSpeed(true);
- instruction.setSpeed(spd);
-}
-
-void FGTrafficRecord::setHeadingAdjustment(double heading)
-{
- instruction.setChangeHeading(true);
- instruction.setHeading(heading);
-}
-
-bool FGTrafficRecord::pushBackAllowed() {
- double course, az2,dist;
- SGGeod curr(SGGeod::fromDegM(getLongitude(),
- getLatitude(),
- getAltitude()));
-
- double userLatitude = fgGetDouble("/position/latitude-deg");
- double userLongitude = fgGetDouble("/position/longitude-deg");
- SGGeod user(SGGeod::fromDeg(userLongitude,userLatitude));
- SGGeodesy::inverse(curr, user, course, az2, dist);
- //cerr << "Distance to user : " << dist << endl;
- return (dist > 250);
+FGTrafficRecord::FGTrafficRecord():
+id(0), waitsForId(0),
+currentPos(0),
+leg(0),
+frequencyId(0),
+state(0),
+allowTransmission(true),
+latitude(0), longitude(0), heading(0), speed(0), altitude(0), radius(0)
+{
+}
+
+void FGTrafficRecord::setPositionAndIntentions(int pos,
+ FGAIFlightPlan * route)
+{
+
+ currentPos = pos;
+ if (intentions.size()) {
+ intVecIterator i = intentions.begin();
+ if ((*i) != pos) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "Error in FGTrafficRecord::setPositionAndIntentions");
+ //cerr << "Pos : " << pos << " Curr " << *(intentions.begin()) << endl;
+ for (intVecIterator i = intentions.begin();
+ i != intentions.end(); i++) {
+ //cerr << (*i) << " ";
+ }
+ //cerr << endl;
+ }
+ intentions.erase(i);
+ } else {
+ //FGAIFlightPlan::waypoint* const wpt= route->getCurrentWaypoint();
+ int size = route->getNrOfWayPoints();
+ //cerr << "Setting pos" << pos << " ";
+ //cerr << "setting intentions ";
+ for (int i = 0; i < size; i++) {
+ int val = route->getRouteIndex(i);
+ //cerr << val<< " ";
+ if ((val) && (val != pos)) {
+ intentions.push_back(val);
+ //cerr << "[set] ";
+ }
+ }
+ //cerr << endl;
+ //while (route->next(&legNr, &routeNr)) {
+ //intentions.push_back(routeNr);
+ //}
+ //route->rewind(currentPos);
+ }
+ //exit(1);
+}
+
+bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other)
+{
+ bool result = false;
+ //cerr << "Start check 1" << endl;
+ if (currentPos == other.currentPos) {
+ //cerr << callsign << ": Check Position and intentions: we are on the same taxiway" << other.callsign << "Index = " << currentPos << endl;
+ result = true;
+ }
+ // else if (other.intentions.size())
+ // {
+ // cerr << "Start check 2" << endl;
+ // intVecIterator i = other.intentions.begin();
+ // while (!((i == other.intentions.end()) || ((*i) == currentPos)))
+ // i++;
+ // if (i != other.intentions.end()) {
+ // cerr << "Check Position and intentions: current matches other.intentions" << endl;
+ // result = true;
+ // }
+ else if (intentions.size()) {
+ //cerr << "Start check 3" << endl;
+ intVecIterator i = intentions.begin();
+ //while (!((i == intentions.end()) || ((*i) == other.currentPos)))
+ while (i != intentions.end()) {
+ if ((*i) == other.currentPos) {
+ break;
+ }
+ i++;
+ }
+ if (i != intentions.end()) {
+ //cerr << callsign << ": Check Position and intentions: .other.current matches" << other.callsign << "Index = " << (*i) << endl;
+ result = true;
+ }
+ }
+ //cerr << "Done !!" << endl;
+ return result;
+}
+
+void FGTrafficRecord::setPositionAndHeading(double lat, double lon,
+ double hdg, double spd,
+ double alt)
+{
+ latitude = lat;
+ longitude = lon;
+ heading = hdg;
+ speed = spd;
+ altitude = alt;
+}
+
+int FGTrafficRecord::crosses(FGGroundNetwork * net,
+ FGTrafficRecord & other)
+{
+ if (checkPositionAndIntentions(other)
+ || (other.checkPositionAndIntentions(*this)))
+ return -1;
+ intVecIterator i, j;
+ int currentTargetNode = 0, otherTargetNode = 0;
+ if (currentPos > 0)
+ currentTargetNode = net->findSegment(currentPos)->getEnd()->getIndex(); // OKAY,...
+ if (other.currentPos > 0)
+ otherTargetNode = net->findSegment(other.currentPos)->getEnd()->getIndex(); // OKAY,...
+ if ((currentTargetNode == otherTargetNode) && currentTargetNode > 0)
+ return currentTargetNode;
+ if (intentions.size()) {
+ for (i = intentions.begin(); i != intentions.end(); i++) {
+ if ((*i) > 0) {
+ if ((currentTargetNode ==
+ net->findSegment(*i)->getEnd()->getIndex())) {
+ //cerr << "Current crosses at " << currentTargetNode <<endl;
+ return currentTargetNode;
+ }
+ }
+ }
+ }
+ if (other.intentions.size()) {
+ for (i = other.intentions.begin(); i != other.intentions.end();
+ i++) {
+ if ((*i) > 0) {
+ if (otherTargetNode ==
+ net->findSegment(*i)->getEnd()->getIndex()) {
+ //cerr << "Other crosses at " << currentTargetNode <<endl;
+ return otherTargetNode;
+ }
+ }
+ }
+ }
+ if (intentions.size() && other.intentions.size()) {
+ for (i = intentions.begin(); i != intentions.end(); i++) {
+ for (j = other.intentions.begin(); j != other.intentions.end();
+ j++) {
+ //cerr << "finding segment " << *i << " and " << *j << endl;
+ if (((*i) > 0) && ((*j) > 0)) {
+ currentTargetNode =
+ net->findSegment(*i)->getEnd()->getIndex();
+ otherTargetNode =
+ net->findSegment(*j)->getEnd()->getIndex();
+ if (currentTargetNode == otherTargetNode) {
+ //cerr << "Routes will cross at " << currentTargetNode << endl;
+ return currentTargetNode;
+ }
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+bool FGTrafficRecord::onRoute(FGGroundNetwork * net,
+ FGTrafficRecord & other)
+{
+ int node = -1, othernode = -1;
+ if (currentPos > 0)
+ node = net->findSegment(currentPos)->getEnd()->getIndex();
+ if (other.currentPos > 0)
+ othernode =
+ net->findSegment(other.currentPos)->getEnd()->getIndex();
+ if ((node == othernode) && (node != -1))
+ return true;
+ if (other.intentions.size()) {
+ for (intVecIterator i = other.intentions.begin();
+ i != other.intentions.end(); i++) {
+ if (*i > 0) {
+ othernode = net->findSegment(*i)->getEnd()->getIndex();
+ if ((node == othernode) && (node > -1))
+ return true;
+ }
+ }
+ }
+ //if (other.currentPos > 0)
+ // othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
+ //if (intentions.size())
+ // {
+ // for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
+ // {
+ // if (*i > 0)
+ // {
+ // node = net->findSegment(*i)->getEnd()->getIndex();
+ // if ((node == othernode) && (node > -1))
+ // return true;
+ // }
+ // }
+ // }
+ return false;
+}
+
+
+bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
+ FGTrafficRecord & other, int node)
+{
+ // Check if current segment is the reverse segment for the other aircraft
+ FGTaxiSegment *opp;
+ //cerr << "Current segment " << currentPos << endl;
+ if ((currentPos > 0) && (other.currentPos > 0)) {
+ opp = net->findSegment(currentPos)->opposite();
+ if (opp) {
+ if (opp->getIndex() == other.currentPos)
+ return true;
+ }
+
+ for (intVecIterator i = intentions.begin(); i != intentions.end();
+ i++) {
+ if ((opp = net->findSegment(other.currentPos)->opposite())) {
+ if ((*i) > 0)
+ if (opp->getIndex() ==
+ net->findSegment(*i)->getIndex()) {
+ if (net->findSegment(*i)->getStart()->getIndex() ==
+ node) {
+ {
+ //cerr << "Found the node " << node << endl;
+ return true;
+ }
+ }
+ }
+ }
+ if (other.intentions.size()) {
+ for (intVecIterator j = other.intentions.begin();
+ j != other.intentions.end(); j++) {
+ // cerr << "Current segment 1 " << (*i) << endl;
+ if ((*i) > 0) {
+ if ((opp = net->findSegment(*i)->opposite())) {
+ if (opp->getIndex() ==
+ net->findSegment(*j)->getIndex()) {
+ //cerr << "Nodes " << net->findSegment(*i)->getIndex()
+ // << " and " << net->findSegment(*j)->getIndex()
+ // << " are opposites " << endl;
+ if (net->findSegment(*i)->getStart()->
+ getIndex() == node) {
+ {
+ //cerr << "Found the node " << node << endl;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void FGTrafficRecord::setSpeedAdjustment(double spd)
+{
+ instruction.setChangeSpeed(true);
+ instruction.setSpeed(spd);
+}
+
+void FGTrafficRecord::setHeadingAdjustment(double heading)
+{
+ instruction.setChangeHeading(true);
+ instruction.setHeading(heading);
+}
+
+bool FGTrafficRecord::pushBackAllowed()
+{
+ double course, az2, dist;
+ SGGeod curr(SGGeod::fromDegM(getLongitude(),
+ getLatitude(), getAltitude()));
+
+ double userLatitude = fgGetDouble("/position/latitude-deg");
+ double userLongitude = fgGetDouble("/position/longitude-deg");
+ SGGeod user(SGGeod::fromDeg(userLongitude, userLatitude));
+ SGGeodesy::inverse(curr, user, course, az2, dist);
+ //cerr << "Distance to user : " << dist << endl;
+ return (dist > 250);
}
**************************************************************************/
FGATCInstruction::FGATCInstruction()
{
- holdPattern = false;
- holdPosition = false;
- changeSpeed = false;
- changeHeading = false;
- changeAltitude = false;
- resolveCircularWait = false;
+ holdPattern = false;
+ holdPosition = false;
+ changeSpeed = false;
+ changeHeading = false;
+ changeAltitude = false;
+ resolveCircularWait = false;
- speed = 0;
- heading = 0;
- alt = 0;
+ speed = 0;
+ heading = 0;
+ alt = 0;
}
bool FGATCInstruction::hasInstruction()
{
- return (holdPattern || holdPosition || changeSpeed || changeHeading || changeAltitude || resolveCircularWait);
+ return (holdPattern || holdPosition || changeSpeed || changeHeading
+ || changeAltitude || resolveCircularWait);
}
/***************************************************************************
-FGATCController::FGATCController()
+FGATCController::FGATCController()
{
- dt_count = 0;
- available = true;
- lastTransmission = 0;
+ dt_count = 0;
+ available = true;
+ lastTransmission = 0;
}
-string FGATCController::getGateName(FGAIAircraft *ref)
+string FGATCController::getGateName(FGAIAircraft * ref)
{
return ref->atGate();
}
-void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir)
+void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
+ AtcMsgDir msgDir)
{
string sender, receiver;
int stationFreq = 0;
- int taxiFreq = 0;
- int freqId = 0;
+ int taxiFreq = 0;
+ int freqId = 0;
string atisInformation;
string text;
string taxiFreqStr;
sender = rec->getAircraft()->getTrafficRef()->getCallSign();
//cerr << "transmitting for: " << sender << "Leg = " << rec->getLeg() << endl;
switch (rec->getLeg()) {
- case 2:
- case 3:
- freqId = rec->getNextFrequency();
- stationFreq =
- rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency(rec->getLeg()+freqId);
- taxiFreq =
- rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency(3);
- receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
- atisInformation = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getAtisInformation();
- break;
- case 4:
- receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Tower";
- break;
+ case 2:
+ case 3:
+ freqId = rec->getNextFrequency();
+ stationFreq =
+ rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+ getDynamics()->getGroundFrequency(rec->getLeg() + freqId);
+ taxiFreq =
+ rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+ getDynamics()->getGroundFrequency(3);
+ receiver =
+ rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+ getName() + "-Ground";
+ atisInformation =
+ rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+ getDynamics()->getAtisInformation();
+ break;
+ case 4:
+ receiver =
+ rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+ getName() + "-Tower";
+ break;
}
// Swap sender and receiver value in case of a ground to air transmission
if (msgDir == ATC_GROUND_TO_AIR) {
- string tmp = sender;
- sender = receiver;
- receiver = tmp;
+ string tmp = sender;
+ sender = receiver;
+ receiver = tmp;
}
switch (msgId) {
- case MSG_ANNOUNCE_ENGINE_START:
- text = sender + ". Ready to Start up";
- break;
- case MSG_REQUEST_ENGINE_START:
- text = receiver + ", This is " + sender + ". Position " +getGateName(rec->getAircraft()) +
- ". Information " + atisInformation + ". " +
- rec->getAircraft()->getTrafficRef()->getFlightRules() + " to " +
- rec->getAircraft()->getTrafficRef()->getArrivalAirport()->getName() + ". Request start-up";
- break;
- // Acknowledge engine startup permission
- // Assign departure runway
- // Assign SID, if necessery (TODO)
- case MSG_PERMIT_ENGINE_START:
- taxiFreqStr = formatATCFrequency3_2(taxiFreq);
-
- heading = rec->getAircraft()->getTrafficRef()->getCourse();
- fltType = rec->getAircraft()->getTrafficRef()->getFlightType();
- rwyClass= rec->getAircraft()->GetFlightPlan()->getRunwayClassFromTrafficType(fltType);
-
- rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
- rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
- fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getSID(activeRunway, heading);
- rec->getAircraft()->GetFlightPlan()->setSID(fp);
- if (fp) {
- SID = fp->getName() + " departure";
- } else {
- SID = "fly runway heading ";
- }
- //snprintf(buffer, 7, "%3.2f", heading);
- fltRules = rec->getAircraft()->getTrafficRef()->getFlightRules();
- transponderCode = genTransponderCode(fltRules);
- rec->getAircraft()->SetTransponderCode(transponderCode);
- text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " + activeRunway
- + ", " + SID + ", squawk " + transponderCode + ". " +
- "For push-back and taxi clearance call " + taxiFreqStr + ". " + sender + " control.";
- break;
- case MSG_DENY_ENGINE_START:
- text = receiver + ". Standby";
- break;
- case MSG_ACKNOWLEDGE_ENGINE_START:
- fp = rec->getAircraft()->GetFlightPlan()->getSID();
- if (fp) {
- SID = rec->getAircraft()->GetFlightPlan()->getSID()->getName() + " departure";
- } else {
- SID = "fly runway heading ";
- }
- taxiFreqStr = formatATCFrequency3_2(taxiFreq);
- activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
- transponderCode = rec->getAircraft()->GetTransponderCode();
- text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " +
- activeRunway + ", " + SID + ", squawk " + transponderCode + ". " +
- "For push-back and taxi clearance call " + taxiFreqStr + ". " + sender;
- break;
- case MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY:
- taxiFreqStr = formatATCFrequency3_2(taxiFreq);
- text = receiver + ". Switching to " + taxiFreqStr + ". " + sender;
- break;
- case MSG_INITIATE_CONTACT:
- text = receiver + ". With you. " + sender;
- break;
- case MSG_ACKNOWLEDGE_INITIATE_CONTACT:
- text = receiver + ". Roger. " + sender;
- break;
- case MSG_REQUEST_PUSHBACK_CLEARANCE:
- text = receiver + ". Request push-back. " + sender;
- break;
- case MSG_PERMIT_PUSHBACK_CLEARANCE:
- text = receiver + ". Push-back approved. " + sender;
- break;
- case MSG_HOLD_PUSHBACK_CLEARANCE:
- text = receiver + ". Standby. " + sender;
- break;
- case MSG_REQUEST_TAXI_CLEARANCE:
- text = receiver + ". Ready to Taxi. " + sender;
- break;
- case MSG_ISSUE_TAXI_CLEARANCE:
- text = receiver + ". Cleared to taxi. " + sender;
- break;
- case MSG_ACKNOWLEDGE_TAXI_CLEARANCE:
- text = receiver + ". Cleared to taxi. " + sender;
- break;
- case MSG_HOLD_POSITION:
- text = receiver + ". Hold Position. " + sender;
- break;
- case MSG_ACKNOWLEDGE_HOLD_POSITION:
- text = receiver + ". Holding Position. " + sender;
- break;
- case MSG_RESUME_TAXI:
- text = receiver + ". Resume Taxiing. " + sender;
- break;
- case MSG_ACKNOWLEDGE_RESUME_TAXI:
- text = receiver + ". Continuing Taxi. " + sender;
- break;
- default:
- text = text + sender + ". Transmitting unknown Message";
- break;
+ case MSG_ANNOUNCE_ENGINE_START:
+ text = sender + ". Ready to Start up";
+ break;
+ case MSG_REQUEST_ENGINE_START:
+ text =
+ receiver + ", This is " + sender + ". Position " +
+ getGateName(rec->getAircraft()) + ". Information " +
+ atisInformation + ". " +
+ rec->getAircraft()->getTrafficRef()->getFlightRules() +
+ " to " +
+ rec->getAircraft()->getTrafficRef()->getArrivalAirport()->
+ getName() + ". Request start-up";
+ break;
+ // Acknowledge engine startup permission
+ // Assign departure runway
+ // Assign SID, if necessery (TODO)
+ case MSG_PERMIT_ENGINE_START:
+ taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+
+ heading = rec->getAircraft()->getTrafficRef()->getCourse();
+ fltType = rec->getAircraft()->getTrafficRef()->getFlightType();
+ rwyClass =
+ rec->getAircraft()->GetFlightPlan()->
+ getRunwayClassFromTrafficType(fltType);
+
+ rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+ getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+ heading);
+ rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
+ fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+ getDynamics()->getSID(activeRunway, heading);
+ rec->getAircraft()->GetFlightPlan()->setSID(fp);
+ if (fp) {
+ SID = fp->getName() + " departure";
+ } else {
+ SID = "fly runway heading ";
+ }
+ //snprintf(buffer, 7, "%3.2f", heading);
+ fltRules = rec->getAircraft()->getTrafficRef()->getFlightRules();
+ transponderCode = genTransponderCode(fltRules);
+ rec->getAircraft()->SetTransponderCode(transponderCode);
+ text =
+ receiver + ". Start-up approved. " + atisInformation +
+ " correct, runway " + activeRunway + ", " + SID + ", squawk " +
+ transponderCode + ". " +
+ "For push-back and taxi clearance call " + taxiFreqStr + ". " +
+ sender + " control.";
+ break;
+ case MSG_DENY_ENGINE_START:
+ text = receiver + ". Standby";
+ break;
+ case MSG_ACKNOWLEDGE_ENGINE_START:
+ fp = rec->getAircraft()->GetFlightPlan()->getSID();
+ if (fp) {
+ SID =
+ rec->getAircraft()->GetFlightPlan()->getSID()->getName() +
+ " departure";
+ } else {
+ SID = "fly runway heading ";
+ }
+ taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+ activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
+ transponderCode = rec->getAircraft()->GetTransponderCode();
+ text =
+ receiver + ". Start-up approved. " + atisInformation +
+ " correct, runway " + activeRunway + ", " + SID + ", squawk " +
+ transponderCode + ". " +
+ "For push-back and taxi clearance call " + taxiFreqStr + ". " +
+ sender;
+ break;
+ case MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY:
+ taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+ text = receiver + ". Switching to " + taxiFreqStr + ". " + sender;
+ break;
+ case MSG_INITIATE_CONTACT:
+ text = receiver + ". With you. " + sender;
+ break;
+ case MSG_ACKNOWLEDGE_INITIATE_CONTACT:
+ text = receiver + ". Roger. " + sender;
+ break;
+ case MSG_REQUEST_PUSHBACK_CLEARANCE:
+ text = receiver + ". Request push-back. " + sender;
+ break;
+ case MSG_PERMIT_PUSHBACK_CLEARANCE:
+ text = receiver + ". Push-back approved. " + sender;
+ break;
+ case MSG_HOLD_PUSHBACK_CLEARANCE:
+ text = receiver + ". Standby. " + sender;
+ break;
+ case MSG_REQUEST_TAXI_CLEARANCE:
+ text = receiver + ". Ready to Taxi. " + sender;
+ break;
+ case MSG_ISSUE_TAXI_CLEARANCE:
+ text = receiver + ". Cleared to taxi. " + sender;
+ break;
+ case MSG_ACKNOWLEDGE_TAXI_CLEARANCE:
+ text = receiver + ". Cleared to taxi. " + sender;
+ break;
+ case MSG_HOLD_POSITION:
+ text = receiver + ". Hold Position. " + sender;
+ break;
+ case MSG_ACKNOWLEDGE_HOLD_POSITION:
+ text = receiver + ". Holding Position. " + sender;
+ break;
+ case MSG_RESUME_TAXI:
+ text = receiver + ". Resume Taxiing. " + sender;
+ break;
+ case MSG_ACKNOWLEDGE_RESUME_TAXI:
+ text = receiver + ". Continuing Taxi. " + sender;
+ break;
+ default:
+ text = text + sender + ". Transmitting unknown Message";
+ break;
}
- double onBoardRadioFreq0 = fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
- double onBoardRadioFreq1 = fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+ double onBoardRadioFreq0 =
+ fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+ double onBoardRadioFreq1 =
+ fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
//cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
// Display ATC message only when one of the radios is tuned
// the relevant frequency.
// Note that distance attenuation is currently not yet implemented
- if ((onBoardRadioFreqI0 == stationFreq) || (onBoardRadioFreqI1 == stationFreq)) {
+ if ((onBoardRadioFreqI0 == stationFreq)
+ || (onBoardRadioFreqI1 == stationFreq)) {
if (rec->allowTransmissions()) {
fgSetString("/sim/messages/atc", text.c_str());
}
}
}
-string FGATCController::formatATCFrequency3_2(int freq) {
+string FGATCController::formatATCFrequency3_2(int freq)
+{
char buffer[7];
- snprintf(buffer, 7, "%3.2f", ( (float) freq / 100.0) );
+ snprintf(buffer, 7, "%3.2f", ((float) freq / 100.0));
return string(buffer);
}
// TODO: Set transponder codes according to real-world routes.
// 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") {
return string("1200");
} else {
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);
}
}
* class FGTowerController
*
**************************************************************************/
-FGTowerController::FGTowerController() :
- FGATCController()
+FGTowerController::FGTowerController():
+FGATCController()
{
}
//
-void FGTowerController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
- double lat, double lon, double heading,
- double speed, double alt, double radius, int leg,
- FGAIAircraft *ref)
-{
- TrafficVectorIterator i = activeTraffic.begin();
- // Search whether the current id alread has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
-
- // Add a new TrafficRecord if no one exsists for this aircraft.
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- FGTrafficRecord rec;
- rec.setId(id);
-
- rec.setPositionAndHeading(lat, lon, heading, speed, alt);
- rec.setRunway(intendedRoute->getRunway());
- rec.setLeg(leg);
- //rec.setCallSign(callsign);
- rec.setAircraft(ref);
- activeTraffic.push_back(rec);
- } else {
- i->setPositionAndHeading(lat, lon, heading, speed, alt);
- }
-}
-
-void FGTowerController::update(int id, double lat, double lon, double heading, double speed, double alt,
- double dt)
+void FGTowerController::announcePosition(int id,
+ FGAIFlightPlan * intendedRoute,
+ int currentPosition, double lat,
+ double lon, double heading,
+ double speed, double alt,
+ double radius, int leg,
+ FGAIAircraft * ref)
{
TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id has an entry
+ // 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
- TrafficVectorIterator current, closest;
if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ // Add a new TrafficRecord if no one exsists for this aircraft.
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ FGTrafficRecord rec;
+ rec.setId(id);
+
+ rec.setPositionAndHeading(lat, lon, heading, speed, alt);
+ rec.setRunway(intendedRoute->getRunway());
+ rec.setLeg(leg);
+ //rec.setCallSign(callsign);
+ rec.setAircraft(ref);
+ activeTraffic.push_back(rec);
+ } else {
+ i->setPositionAndHeading(lat, lon, heading, speed, alt);
}
+}
+void FGTowerController::update(int id, double lat, double lon,
+ double heading, double speed, double alt,
+ double dt)
+{
+ TrafficVectorIterator i = activeTraffic.begin();
+ // Search 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
+ 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");
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: updating aircraft without traffic record");
} else {
- i->setPositionAndHeading(lat, lon, heading, speed, alt);
- current = i;
+ i->setPositionAndHeading(lat, lon, heading, speed, alt);
+ current = i;
}
setDt(getDt() + dt);
ActiveRunwayVecIterator rwy = activeRunways.begin();
// again, a map might be more efficient here
if (activeRunways.size()) {
- //while ((rwy->getRunwayName() != current->getRunway()) && (rwy != activeRunways.end())) {
- while (rwy != activeRunways.end()) {
- if (rwy->getRunwayName() == current->getRunway()) {
- break;
- }
- rwy++;
- }
+ //while ((rwy->getRunwayName() != current->getRunway()) && (rwy != activeRunways.end())) {
+ while (rwy != activeRunways.end()) {
+ if (rwy->getRunwayName() == current->getRunway()) {
+ break;
+ }
+ rwy++;
+ }
}
if (rwy == activeRunways.end()) {
- ActiveRunway aRwy(current->getRunway(), id);
- activeRunways.push_back(aRwy); // Since there are no clearance records for this runway yet
- current->setHoldPosition(false); // Clear the current aircraft to continue
- }
- else {
- // Okay, we have a clearance record for this runway, so check
- // whether the clearence ID matches that of the current aircraft
- if (id == rwy->getCleared()) {
- current->setHoldPosition(false);
- } else {
- current->setHoldPosition(true);
- }
+ ActiveRunway aRwy(current->getRunway(), id);
+ activeRunways.push_back(aRwy); // Since there are no clearance records for this runway yet
+ current->setHoldPosition(false); // Clear the current aircraft to continue
+ } else {
+ // Okay, we have a clearance record for this runway, so check
+ // whether the clearence ID matches that of the current aircraft
+ if (id == rwy->getCleared()) {
+ current->setHoldPosition(false);
+ } else {
+ current->setHoldPosition(true);
+ }
}
}
-void FGTowerController::signOff(int id)
+void FGTowerController::signOff(int id)
{
- TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id alread has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ 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++;
- }
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
}
// If this aircraft has left the runway, we can clear the departure record for this runway
ActiveRunwayVecIterator rwy = activeRunways.begin();
if (activeRunways.size()) {
- //while ((rwy->getRunwayName() != i->getRunway()) && (rwy != activeRunways.end())) {
- while (rwy != activeRunways.end()) {
- if (rwy->getRunwayName() == i->getRunway()) {
- break;
- }
- rwy++;
- }
- if (rwy != activeRunways.end()) {
- rwy = activeRunways.erase(rwy);
- } else {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff");
- }
+ //while ((rwy->getRunwayName() != i->getRunway()) && (rwy != activeRunways.end())) {
+ while (rwy != activeRunways.end()) {
+ if (rwy->getRunwayName() == i->getRunway()) {
+ break;
+ }
+ rwy++;
+ }
+ if (rwy != activeRunways.end()) {
+ rwy = activeRunways.erase(rwy);
+ } else {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff");
+ }
}
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower");
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: Aircraft without traffic record is signing off from tower");
} else {
- i = activeTraffic.erase(i);
+ i = activeTraffic.erase(i);
}
}
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())
- {
+ if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
+ 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");
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: checking ATC instruction for aircraft without traffic record");
} else {
- return i->hasInstruction();
+ return i->hasInstruction();
}
- return false;
+ return false;
}
FGATCInstruction FGTowerController::getInstruction(int id)
{
- TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
- } else {
- return i->getInstruction();
- }
- return FGATCInstruction();
+ TrafficVectorIterator i = activeTraffic.begin();
+ // Search search if the current id has an entry
+ // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: requesting ATC instruction for aircraft without traffic record");
+ } else {
+ return i->getInstruction();
+ }
+ return FGATCInstruction();
}
/***************************************************************************
* class FGStartupController
*
**************************************************************************/
-FGStartupController::FGStartupController() :
- FGATCController()
-{
-}
-
-void FGStartupController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
- double lat, double lon, double heading,
- double speed, double alt, double radius, int leg,
- FGAIAircraft *ref)
-{
- TrafficVectorIterator i = activeTraffic.begin();
- // Search whether the current id alread has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
-
- // Add a new TrafficRecord if no one exsists for this aircraft.
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- FGTrafficRecord rec;
- rec.setId(id);
-
- rec.setPositionAndHeading(lat, lon, heading, speed, alt);
- rec.setRunway(intendedRoute->getRunway());
- rec.setLeg(leg);
- //rec.setCallSign(callsign);
- rec.setAircraft(ref);
- rec.setHoldPosition(true);
- activeTraffic.push_back(rec);
+FGStartupController::FGStartupController():
+FGATCController()
+{
+}
+
+void FGStartupController::announcePosition(int id,
+ FGAIFlightPlan * intendedRoute,
+ int currentPosition, double lat,
+ double lon, double heading,
+ double speed, double alt,
+ double radius, int leg,
+ FGAIAircraft * ref)
+{
+ TrafficVectorIterator i = activeTraffic.begin();
+ // Search whether the current id alread has an entry
+ // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ // Add a new TrafficRecord if no one exsists for this aircraft.
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ FGTrafficRecord rec;
+ rec.setId(id);
+
+ rec.setPositionAndHeading(lat, lon, heading, speed, alt);
+ rec.setRunway(intendedRoute->getRunway());
+ rec.setLeg(leg);
+ //rec.setCallSign(callsign);
+ rec.setAircraft(ref);
+ rec.setHoldPosition(true);
+ activeTraffic.push_back(rec);
} else {
i->setPositionAndHeading(lat, lon, heading, speed, alt);
-
- }
+
+ }
}
// NOTE:
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())
- {
+ if (activeTraffic.size()) {
//while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
+ 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");
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: checking ATC instruction for aircraft without traffic record");
} else {
- return i->hasInstruction();
+ return i->hasInstruction();
}
- return false;
+ return false;
}
FGATCInstruction FGStartupController::getInstruction(int id)
{
- TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
- } else {
- return i->getInstruction();
- }
- return FGATCInstruction();
-}
-
-void FGStartupController::signOff(int id)
-{
- TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id alread has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ 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++;
- }
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
}
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower");
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: requesting ATC instruction for aircraft without traffic record");
} else {
- i = activeTraffic.erase(i);
+ return i->getInstruction();
}
+ return FGATCInstruction();
}
-void FGStartupController::update(int id, double lat, double lon, double heading, double speed, double alt,
- double dt)
+void FGStartupController::signOff(int id)
+{
+ TrafficVectorIterator i = activeTraffic.begin();
+ // Search search if the current id alread has an entry
+ // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: Aircraft without traffic record is signing off from tower");
+ } else {
+ i = activeTraffic.erase(i);
+ }
+}
+
+void FGStartupController::update(int id, double lat, double lon,
+ double heading, double speed, double alt,
+ double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
TrafficVectorIterator current, closest;
if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
+ //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");
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: updating aircraft without traffic record");
} else {
- i->setPositionAndHeading(lat, lon, heading, speed, alt);
- current = i;
+ i->setPositionAndHeading(lat, lon, heading, speed, alt);
+ current = i;
}
setDt(getDt() + dt);
int state = i->getState();
- time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
- time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+ time_t startTime =
+ i->getAircraft()->getTrafficRef()->getDepartureTime();
+ time_t now = time(NULL) + fgGetLong("/sim/time/warp");
//cerr << i->getAircraft()->getTrafficRef()->getCallSign()
// << " is scheduled to depart in " << startTime-now << " seconds. Available = " << available
// << " at parking " << getGateName(i->getAircraft()) << endl;
if ((state == 0) && available) {
if (now > startTime) {
- //cerr << "Transmitting startup msg" << endl;
- transmit(&(*i), MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
- i->updateState();
- lastTransmission = now;
- available = false;
+ //cerr << "Transmitting startup msg" << endl;
+ transmit(&(*i), MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
+ i->updateState();
+ lastTransmission = now;
+ available = false;
}
}
if ((state == 1) && available) {
- if (now > startTime+60) {
+ if (now > startTime + 60) {
transmit(&(*i), MSG_REQUEST_ENGINE_START, ATC_AIR_TO_GROUND);
i->updateState();
lastTransmission = now;
- available = false;
+ available = false;
}
}
if ((state == 2) && available) {
- if (now > startTime+80) {
+ if (now > startTime + 80) {
transmit(&(*i), MSG_PERMIT_ENGINE_START, ATC_GROUND_TO_AIR);
i->updateState();
lastTransmission = now;
- available = false;
+ available = false;
}
}
- if ((state == 3) && available){
- if (now > startTime+100) {
- transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START, ATC_AIR_TO_GROUND);
+ if ((state == 3) && available) {
+ if (now > startTime + 100) {
+ transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START,
+ ATC_AIR_TO_GROUND);
i->updateState();
lastTransmission = now;
- available = false;
- }
- }
- // Note: The next four stages are only necessesary when Startup control is
- // on a different frequency, compared to ground control
- if ((state == 4) && available){
- if (now > startTime+130) {
- transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY, ATC_AIR_TO_GROUND);
+ available = false;
+ }
+ }
+ // Note: The next four stages are only necessesary when Startup control is
+ // on a different frequency, compared to ground control
+ if ((state == 4) && available) {
+ if (now > startTime + 130) {
+ transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
+ ATC_AIR_TO_GROUND);
i->updateState();
i->nextFrequency();
lastTransmission = now;
- available = false;
+ available = false;
}
- }
- if ((state == 5) && available){
- if (now > startTime+140) {
+ }
+ if ((state == 5) && available) {
+ if (now > startTime + 140) {
transmit(&(*i), MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND);
i->updateState();
lastTransmission = now;
- available = false;
+ available = false;
}
- }
- if ((state == 6) && available){
- if (now > startTime+150) {
- transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR);
+ }
+ if ((state == 6) && available) {
+ if (now > startTime + 150) {
+ transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT,
+ ATC_GROUND_TO_AIR);
i->updateState();
lastTransmission = now;
- available = false;
+ available = false;
}
- }
-
+ }
- // TODO: Switch to APRON control and request pushback Clearance.
- // Get Push back clearance
- if ((state == 7) && available){
- if (now > startTime+180) {
- transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
+ // TODO: Switch to APRON control and request pushback Clearance.
+ // Get Push back clearance
+ if ((state == 7) && available) {
+ if (now > startTime + 180) {
+ transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE,
+ ATC_AIR_TO_GROUND);
i->updateState();
lastTransmission = now;
- available = false;
+ available = false;
}
- }
- if ((state == 8) && available){
- if (now > startTime+200) {
+ }
+ if ((state == 8) && available) {
+ if (now > startTime + 200) {
if (i->pushBackAllowed()) {
- i->allowRepeatedTransmissions();
- transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
- i->updateState();
+ i->allowRepeatedTransmissions();
+ transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE,
+ ATC_GROUND_TO_AIR);
+ i->updateState();
} else {
- transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
- i->suppressRepeatedTransmissions();
+ transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE,
+ ATC_GROUND_TO_AIR);
+ i->suppressRepeatedTransmissions();
}
lastTransmission = now;
- available = false;
+ available = false;
+ }
+ }
+ if ((state == 9) && available) {
+ 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 ((state == 9) && available){
- i->setHoldPosition(false);
- }
+ }
+ 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);
}
#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>
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
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;
/**
* 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 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
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;
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;
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,
private:
FGAirport* _ap;
- FGParkingVec parkings;
- FGRunwayPreference rwyPrefs;
- FGSidStar SIDs;
- FGStartupController startupController;
- FGGroundNetwork groundNetwork;
- FGTowerController towerController;
+ FGParkingVec parkings;
+ FGRunwayPreference rwyPrefs;
+ FGSidStar SIDs;
+ FGStartupController startupController;
+ FGGroundNetwork groundNetwork;
+ FGTowerController towerController;
+ FGApproachController approachController;
time_t lastUpdate;
string prevTrafficType;
// ATC related functions.
- FGStartupController *getStartupController() { return &startupController; };
- FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
- FGTowerController *getTowerController() { return &towerController; };
+ FGStartupController *getStartupController() { return &startupController; };
+ FGGroundNetwork *getGroundNetwork() { return &groundNetwork; };
+ FGTowerController *getTowerController() { return &towerController; };
+ FGApproachController *getApproachController() { return &approachController; };
const string& getAtisInformation() { return atisInformation; };
int getGroundFrequency(unsigned leg); //{ return freqGround.size() ? freqGround[0] : 0; };
current->clearResolveCircularWait();
current->setWaitsForId(0);
checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
- checkHoldPosition(id, lat, lon, heading, speed, alt);
- if (checkForCircularWaits(id)) {
- i->setResolveCircularWait();
- }
bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
- int state = current->getState();
- time_t now = time(NULL) + fgGetLong("/sim/time/warp");
- if ((now - lastTransmission) > 15) {
- available = true;
- }
- if (needsTaxiClearance && available) {
- transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
- current->getAircraft()->setTaxiClearanceRequest(false);
- current->setState(3);
- lastTransmission = now;
- available = false;
- }
- if ((state == 3) && available) {
- transmit(&(*current), MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR);
- current->setState(4);
- lastTransmission = now;
- available = false;
- }
- if ((state == 4) && available) {
- transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
- current->setState(0);
- lastTransmission = now;
- available = false;
+ if (!needsTaxiClearance) {
+ checkHoldPosition(id, lat, lon, heading, speed, alt);
+ if (checkForCircularWaits(id)) {
+ i->setResolveCircularWait();
+ }
+ } else {
+ current->setHoldPosition(true);
+ int state = current->getState();
+ time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+ if ((now - lastTransmission) > 15) {
+ available = true;
+ }
+ if ((state < 3) && available) {
+ transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
+ current->setState(3);
+ lastTransmission = now;
+ available = false;
+ }
+ if ((state == 3) && available) {
+ transmit(&(*current), MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR);
+ current->setState(4);
+ lastTransmission = now;
+ available = false;
+ }
+ if ((state == 4) && available) {
+ transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
+ current->setState(5);
+ lastTransmission = now;
+ available = false;
+ }
+ if ((state == 5) && available) {
+ current->setState(0);
+ current->getAircraft()->setTaxiClearanceRequest(false);
+ current->setHoldPosition(true);
+ available = false;
+ }
+
}
+
}
/**
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));
* 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; }
* ScheduleTime
***************e*************************************************************/
void ScheduleTime::clear()
-{
- start.clear();
- end.clear();
- scheduleNames.clear();
+{
+ start.clear();
+ end.clear();
+ scheduleNames.clear();
}
-ScheduleTime::ScheduleTime(const ScheduleTime &other)
+ScheduleTime::ScheduleTime(const ScheduleTime & other)
{
- //timeVec start;
- timeVecConstIterator i;
- for (i = other.start.begin(); i != other.start.end(); i++)
- start.push_back(*i);
- for (i = other.end.begin(); i != other.end.end(); i++)
- end.push_back(*i);
- stringVecConstIterator k;
- for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
- scheduleNames.push_back(*k);
-
- //timeVec end;
- //stringVec scheduleNames;
- tailWind = other.tailWind;
- crssWind = other.tailWind;
+ //timeVec start;
+ timeVecConstIterator i;
+ for (i = other.start.begin(); i != other.start.end(); i++)
+ start.push_back(*i);
+ for (i = other.end.begin(); i != other.end.end(); i++)
+ end.push_back(*i);
+ stringVecConstIterator k;
+ for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
+ k++)
+ scheduleNames.push_back(*k);
+
+ //timeVec end;
+ //stringVec scheduleNames;
+ tailWind = other.tailWind;
+ crssWind = other.tailWind;
}
-ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
+ScheduleTime & ScheduleTime::operator=(const ScheduleTime & other)
{
- //timeVec start;
- clear();
- timeVecConstIterator i;
- for (i = other.start.begin(); i != other.start.end(); i++)
- start.push_back(*i);
- for (i = other.end.begin(); i != other.end.end(); i++)
- end.push_back(*i);
- stringVecConstIterator k;
- for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
- scheduleNames.push_back(*k);
-
- //timeVec end;
- //stringVec scheduleNames;
- tailWind = other.tailWind;
- crssWind = other.tailWind;
- return *this;
+ //timeVec start;
+ clear();
+ timeVecConstIterator i;
+ for (i = other.start.begin(); i != other.start.end(); i++)
+ start.push_back(*i);
+ for (i = other.end.begin(); i != other.end.end(); i++)
+ end.push_back(*i);
+ stringVecConstIterator k;
+ for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
+ k++)
+ scheduleNames.push_back(*k);
+
+ //timeVec end;
+ //stringVec scheduleNames;
+ tailWind = other.tailWind;
+ crssWind = other.tailWind;
+ return *this;
}
+
string ScheduleTime::getName(time_t dayStart)
{
- if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
- {
- SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
- exit(1);
- }
- else
- {
- int nrItems = start.size();
- //cerr << "Nr of items to process: " << nrItems << endl;
- if (nrItems > 0)
- {
- for (unsigned int i = 0; i < start.size(); i++)
- {
- //cerr << i << endl;
- if ((dayStart >= start[i]) && (dayStart <= end[i]))
- return scheduleNames[i];
- }
- }
- //couldn't find one so return 0;
- //cerr << "Returning 0 " << endl;
+ if ((start.size() != end.size())
+ || (start.size() != scheduleNames.size())) {
+ SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
+ exit(1);
+ } else {
+ int nrItems = start.size();
+ //cerr << "Nr of items to process: " << nrItems << endl;
+ if (nrItems > 0) {
+ for (unsigned int i = 0; i < start.size(); i++) {
+ //cerr << i << endl;
+ if ((dayStart >= start[i]) && (dayStart <= end[i]))
+ return scheduleNames[i];
+ }
+ }
+ //couldn't find one so return 0;
+ //cerr << "Returning 0 " << endl;
}
return string("");
-}
+}
+
/******************************************************************************
* RunwayList
*****************************************************************************/
-RunwayList::RunwayList(const RunwayList &other)
+RunwayList::RunwayList(const RunwayList & other)
{
- type = other.type;
- stringVecConstIterator i;
- for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
- preferredRunways.push_back(*i);
+ type = other.type;
+ stringVecConstIterator i;
+ for (i = other.preferredRunways.begin();
+ i != other.preferredRunways.end(); i++)
+ preferredRunways.push_back(*i);
}
-RunwayList& RunwayList::operator= (const RunwayList &other)
+
+RunwayList & RunwayList::operator=(const RunwayList & other)
{
- type = other.type;
- preferredRunways.clear();
- stringVecConstIterator i;
- for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
- preferredRunways.push_back(*i);
- return *this;
+ type = other.type;
+ preferredRunways.clear();
+ stringVecConstIterator i;
+ for (i = other.preferredRunways.begin();
+ i != other.preferredRunways.end(); i++)
+ preferredRunways.push_back(*i);
+ return *this;
}
-void RunwayList::set(const string &tp, const string &lst)
+
+void RunwayList::set(const string & tp, const string & lst)
{
- //weekday = atoi(timeCopy.substr(0,1).c_str());
- // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
- // timeCopy = timeCopy.substr(2,timeCopy.length());
- type = tp;
- string rwys = lst;
- string rwy;
- while (rwys.find(",") != string::npos)
- {
- rwy = rwys.substr(0, rwys.find(",",0));
- //cerr << "adding runway [" << rwy << "] to the list " << endl;
- preferredRunways.push_back(rwy);
- rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
- while (rwys[0] == ' ')
- rwys.erase(0, 1); // Erase any leading whitespaces.
- //cerr << "Remaining runway list " << rwys;
- }
- preferredRunways.push_back(rwys);
- //exit(1);
+ //weekday = atoi(timeCopy.substr(0,1).c_str());
+ // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
+ // timeCopy = timeCopy.substr(2,timeCopy.length());
+ type = tp;
+ string rwys = lst;
+ string rwy;
+ while (rwys.find(",") != string::npos) {
+ rwy = rwys.substr(0, rwys.find(",", 0));
+ //cerr << "adding runway [" << rwy << "] to the list " << endl;
+ preferredRunways.push_back(rwy);
+ rwys.erase(0, rwys.find(",", 0) + 1); // erase until after the first whitspace
+ while (rwys[0] == ' ')
+ rwys.erase(0, 1); // Erase any leading whitespaces.
+ //cerr << "Remaining runway list " << rwys;
+ }
+ preferredRunways.push_back(rwys);
+ //exit(1);
}
-void RunwayList::clear()
+void RunwayList::clear()
{
- type = "";
- preferredRunways.clear();
+ type = "";
+ preferredRunways.clear();
}
+
/****************************************************************************
*
***************************************************************************/
-RunwayGroup::RunwayGroup(const RunwayGroup &other)
+RunwayGroup::RunwayGroup(const RunwayGroup & other)
{
- name = other.name;
- RunwayListVecConstIterator i;
- for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
- rwyList.push_back(*i);
- choice[0] = other.choice[0];
- choice[1] = other.choice[1];
- nrActive = other.nrActive;
+ name = other.name;
+ RunwayListVecConstIterator i;
+ for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
+ rwyList.push_back(*i);
+ choice[0] = other.choice[0];
+ choice[1] = other.choice[1];
+ nrActive = other.nrActive;
}
-RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
-{
- rwyList.clear();
- name = other.name;
- RunwayListVecConstIterator i;
- for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
- rwyList.push_back(*i);
- choice[0] = other.choice[0];
- choice[1] = other.choice[1];
- nrActive = other.nrActive;
- return *this;
+
+RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
+{
+ rwyList.clear();
+ name = other.name;
+ RunwayListVecConstIterator i;
+ for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
+ rwyList.push_back(*i);
+ choice[0] = other.choice[0];
+ choice[1] = other.choice[1];
+ nrActive = other.nrActive;
+ return *this;
}
-void RunwayGroup::setActive(const FGAirport* airport,
- double windSpeed,
- double windHeading,
- double maxTail,
- double maxCross,
- stringVec *currentlyActive)
+void RunwayGroup::setActive(const FGAirport * airport,
+ double windSpeed,
+ double windHeading,
+ double maxTail,
+ double maxCross, stringVec * currentlyActive)
{
- FGRunway* rwy;
- int activeRwys = rwyList.size(); // get the number of runways active
- int nrOfPreferences;
- // bool found = true;
- // double heading;
- double hdgDiff;
- double crossWind;
- double tailWind;
- string name;
- //stringVec names;
- int bestMatch = 0, bestChoice = 0;
-
- if (activeRwys > 0)
- {
- // Now downward iterate across all the possible preferences
- // starting by the least preferred choice working toward the most preferred choice
-
- nrOfPreferences = rwyList[0].getRwyList()->size();
- bool validSelection = true;
- bool foundValidSelection = false;
- for (int i = nrOfPreferences-1; i >= 0; i--)
- {
- int match = 0;
-
-
- // Test each runway listed in the preference to see if it's possible to use
- // If one runway of the selection isn't allowed, we need to exclude this
- // preference, however, we don't want to stop right there, because we also
- // don't want to randomly swap runway preferences, unless there is a need to.
- //
- validSelection = true;
- for (int j = 0; j < activeRwys; j++)
- {
- string ident(rwyList[j].getRwyList(i));
- if (!airport->hasRunwayWithIdent(ident)) {
- SG_LOG(SG_GENERAL, SG_WARN, "no such runway:" << ident << " at " << airport->ident());
- continue;
- }
-
- rwy = airport->getRunwayByIdent(ident);
-
- //cerr << "Succes" << endl;
- hdgDiff = fabs(windHeading - rwy->headingDeg());
- //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
- //cerr << "Wind Speed : " << windSpeed << endl;
- if (hdgDiff > 180)
- hdgDiff = 360 - hdgDiff;
- //cerr << "Heading diff: " << hdgDiff << endl;
- hdgDiff *= ((2*M_PI)/360.0); // convert to radians
- crossWind = windSpeed * sin(hdgDiff);
- tailWind = -windSpeed * cos(hdgDiff);
- //cerr << ". Tailwind : " << tailWind;
- //cerr << ". Crosswnd : " << crossWind;
- if ((tailWind > maxTail) || (crossWind > maxCross))
- {
- //cerr << ". [Invalid] " << endl;
- validSelection = false;
- }
- else
- {
- //cerr << ". [Valid] ";
- }
- //cerr << endl;
- } // of active runways iteration
-
- if (validSelection)
- {
- //cerr << "Valid selection : " << i << endl;;
- foundValidSelection = true;
- for (stringVecIterator it = currentlyActive->begin();
- it != currentlyActive->end(); it++)
- {
- if ((*it) == name)
- match++;
- }
- if (match >= bestMatch) {
- bestMatch = match;
- bestChoice = i;
- }
- }
- //cerr << "Preference " << i << " bestMatch " << bestMatch << " choice " << bestChoice << endl;
- }
- if (foundValidSelection)
- {
- //cerr << "Valid runay selection : " << bestChoice << endl;
- nrActive = activeRwys;
- active = bestChoice;
- return;
- }
- // If this didn't work, due to heavy winds, try again
- // but select only one landing and one takeoff runway.
- choice[0] = 0;
- choice[1] = 0;
- for (int i = activeRwys-1; i; i--)
- {
- if (rwyList[i].getType() == string("landing"))
- choice[0] = i;
- if (rwyList[i].getType() == string("takeoff"))
- choice[1] = i;
- }
- //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
- nrOfPreferences = rwyList[0].getRwyList()->size();
- for (int i = 0; i < nrOfPreferences; i++)
- {
- bool validSelection = true;
- for (int j = 0; j < 2; j++)
- {
- name = rwyList[choice[j]].getRwyList(i);
- rwy = airport->getRunwayByIdent(name);
-
- //cerr << "Succes" << endl;
- hdgDiff = fabs(windHeading - rwy->headingDeg());
- if (hdgDiff > 180)
- hdgDiff = 360 - hdgDiff;
- hdgDiff *= ((2*M_PI)/360.0); // convert to radians
- crossWind = windSpeed * sin(hdgDiff);
- tailWind = -windSpeed * cos(hdgDiff);
- if ((tailWind > maxTail) || (crossWind > maxCross))
- validSelection = false;
-
-
- }
- if (validSelection)
- {
- //cerr << "Valid runay selection : " << i << endl;
- active = i;
- nrActive = 2;
- return;
- }
- }
+ FGRunway *rwy;
+ int activeRwys = rwyList.size(); // get the number of runways active
+ int nrOfPreferences;
+ // bool found = true;
+ // double heading;
+ double hdgDiff;
+ double crossWind;
+ double tailWind;
+ string name;
+ //stringVec names;
+ int bestMatch = 0, bestChoice = 0;
+
+ if (activeRwys > 0) {
+ // Now downward iterate across all the possible preferences
+ // starting by the least preferred choice working toward the most preferred choice
+
+ nrOfPreferences = rwyList[0].getRwyList()->size();
+ bool validSelection = true;
+ bool foundValidSelection = false;
+ for (int i = nrOfPreferences - 1; i >= 0; i--) {
+ int match = 0;
+
+
+ // Test each runway listed in the preference to see if it's possible to use
+ // If one runway of the selection isn't allowed, we need to exclude this
+ // preference, however, we don't want to stop right there, because we also
+ // don't want to randomly swap runway preferences, unless there is a need to.
+ //
+ validSelection = true;
+
+ for (int j = 0; j < activeRwys; j++) {
+ string ident(rwyList[j].getRwyList(i));
+ if (!airport->hasRunwayWithIdent(ident)) {
+ SG_LOG(SG_GENERAL, SG_WARN,
+ "no such runway:" << ident << " at " <<
+ airport->ident());
+ continue;
+ }
+
+ rwy = airport->getRunwayByIdent(ident);
+
+ //cerr << "Succes" << endl;
+ hdgDiff = fabs(windHeading - rwy->headingDeg());
+ name = rwy->name();
+
+
+ if (hdgDiff > 180)
+ hdgDiff = 360 - hdgDiff;
+ //cerr << "Heading diff: " << hdgDiff << endl;
+ hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
+ crossWind = windSpeed * sin(hdgDiff);
+ tailWind = -windSpeed * cos(hdgDiff);
+ //cerr << "Runway : " << rwy->name() << ": " << rwy->headingDeg() << endl;
+ //cerr << ". Tailwind : " << tailWind;
+ //cerr << ". Crosswnd : " << crossWind;
+ if ((tailWind > maxTail) || (crossWind > maxCross)) {
+ //cerr << ". [Invalid] " << endl;
+ validSelection = false;
+ } else {
+ //cerr << ". [Valid] ";
+ }
+ //cerr << endl;
+ for (stringVecIterator it = currentlyActive->begin();
+ it != currentlyActive->end(); it++) {
+ //cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
+ if ((*it) == name) {
+ match++;
+ }
+ }
+ } // of active runways iteration
+
+ if (validSelection) {
+ //cerr << "Valid selection : " << i << endl;;
+ foundValidSelection = true;
+ if (match >= bestMatch) {
+ bestMatch = match;
+ bestChoice = i;
+ }
+ }
+ //cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
+ }
+ if (foundValidSelection) {
+ //cerr << "Valid runay selection : " << bestChoice << endl;
+ nrActive = activeRwys;
+ active = bestChoice;
+ return;
+ }
+ // If this didn't work, due to heavy winds, try again
+ // but select only one landing and one takeoff runway.
+ choice[0] = 0;
+ choice[1] = 0;
+ for (int i = activeRwys - 1; i; i--) {
+ if (rwyList[i].getType() == string("landing"))
+ choice[0] = i;
+ if (rwyList[i].getType() == string("takeoff"))
+ choice[1] = i;
+ }
+ //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
+ nrOfPreferences = rwyList[0].getRwyList()->size();
+ for (int i = 0; i < nrOfPreferences; i++) {
+ bool validSelection = true;
+ for (int j = 0; j < 2; j++) {
+ name = rwyList[choice[j]].getRwyList(i);
+ rwy = airport->getRunwayByIdent(name);
+
+ //cerr << "Succes" << endl;
+ hdgDiff = fabs(windHeading - rwy->headingDeg());
+ if (hdgDiff > 180)
+ hdgDiff = 360 - hdgDiff;
+ hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
+ crossWind = windSpeed * sin(hdgDiff);
+ tailWind = -windSpeed * cos(hdgDiff);
+ if ((tailWind > maxTail) || (crossWind > maxCross))
+ validSelection = false;
+
+
+ }
+ if (validSelection) {
+ //cerr << "Valid runay selection : " << i << endl;
+ active = i;
+ nrActive = 2;
+ return;
+ }
+ }
}
- active = -1;
- nrActive = 0;
+ active = -1;
+ nrActive = 0;
}
-void RunwayGroup::getActive(int i, string &name, string &type)
+void RunwayGroup::getActive(int i, string & name, string & type)
{
- if (i == -1)
- {
- return;
- }
- if (nrActive == (int)rwyList.size())
- {
- name = rwyList[i].getRwyList(active);
- type = rwyList[i].getType();
+ if (i == -1) {
+ return;
}
- else
- {
- name = rwyList[choice[i]].getRwyList(active);
- type = rwyList[choice[i]].getType();
+ if (nrActive == (int) rwyList.size()) {
+ name = rwyList[i].getRwyList(active);
+ type = rwyList[i].getType();
+ } else {
+ name = rwyList[choice[i]].getRwyList(active);
+ type = rwyList[choice[i]].getType();
}
}
+
/*****************************************************************************
* FGRunway preference
****************************************************************************/
-FGRunwayPreference::FGRunwayPreference(FGAirport* ap) :
- _ap(ap)
+FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
+_ap(ap)
{
- //cerr << "Running default Constructor" << endl;
- initialized = false;
+ //cerr << "Running default Constructor" << endl;
+ initialized = false;
}
-FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
+FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
{
- initialized = other.initialized;
+ initialized = other.initialized;
- comTimes = other.comTimes; // Commercial Traffic;
- genTimes = other.genTimes; // General Aviation;
- milTimes = other.milTimes; // Military Traffic;
+ comTimes = other.comTimes; // Commercial Traffic;
+ genTimes = other.genTimes; // General Aviation;
+ milTimes = other.milTimes; // Military Traffic;
- PreferenceListConstIterator i;
- for (i = other.preferences.begin(); i != other.preferences.end(); i++)
- preferences.push_back(*i);
+ PreferenceListConstIterator i;
+ for (i = other.preferences.begin(); i != other.preferences.end(); i++)
+ preferences.push_back(*i);
}
-
-FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
+
+FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
+ & other)
{
- initialized = other.initialized;
-
- comTimes = other.comTimes; // Commercial Traffic;
- genTimes = other.genTimes; // General Aviation;
- milTimes = other.milTimes; // Military Traffic;
-
- PreferenceListConstIterator i;
- preferences.clear();
- for (i = other.preferences.begin(); i != other.preferences.end(); i++)
- preferences.push_back(*i);
- return *this;
+ initialized = other.initialized;
+
+ comTimes = other.comTimes; // Commercial Traffic;
+ genTimes = other.genTimes; // General Aviation;
+ milTimes = other.milTimes; // Military Traffic;
+
+ PreferenceListConstIterator i;
+ preferences.clear();
+ for (i = other.preferences.begin(); i != other.preferences.end(); i++)
+ preferences.push_back(*i);
+ return *this;
}
ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
{
- if (!(strcmp(trafficType, "com"))) {
- return &comTimes;
- }
- if (!(strcmp(trafficType, "gen"))) {
- return &genTimes;
- }
- if (!(strcmp(trafficType, "mil"))) {
- return &milTimes;
- }
- return 0;
+ if (!(strcmp(trafficType, "com"))) {
+ return &comTimes;
+ }
+ if (!(strcmp(trafficType, "gen"))) {
+ return &genTimes;
+ }
+ if (!(strcmp(trafficType, "mil"))) {
+ return &milTimes;
+ }
+ return 0;
}
-RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
+RunwayGroup *FGRunwayPreference::getGroup(const string & groupName)
{
- PreferenceListIterator i = preferences.begin();
- if (preferences.begin() == preferences.end())
- return 0;
- while (!(i == preferences.end() || i->getName() == groupName))
- i++;
- if (i != preferences.end())
- return &(*i);
- else
- return 0;
+ PreferenceListIterator i = preferences.begin();
+ if (preferences.begin() == preferences.end())
+ return 0;
+ while (!(i == preferences.end() || i->getName() == groupName))
+ i++;
+ if (i != preferences.end())
+ return &(*i);
+ else
+ return 0;
}
- string FGRunwayPreference::getId() {
- return _ap->getId();
- };
+string FGRunwayPreference::getId()
+{
+ return _ap->getId();
+};
if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
return true; // out of visual range, for the moment.
}
-
return createAIAircraft(flight, speed, deptime);
}
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;