#endif
#include <simgear/math/point3d.hxx>
+#include <simgear/route/waypoint.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
+#include <Main/viewer.hxx>
#include <Scenery/scenery.hxx>
+#include <Scenery/tilemgr.hxx>
+
#include <string>
#include <math.h>
#include <time.h>
SG_USING_STD(string);
#include "AIAircraft.hxx"
-
+ static string tempReg;
//
// accel, decel, climb_rate, descent_rate, takeoff_speed, climb_speed,
// cruise_speed, descent_speed, land_speed
FGAIAircraft::FGAIAircraft(FGAIManager* mgr, FGAISchedule *ref) {
trafficRef = ref;
+ if (trafficRef)
+ groundOffset = trafficRef->getGroundOffset();
+ else
+ groundOffset = 0;
manager = mgr;
_type_str = "aircraft";
_otype = otAircraft;
fp = 0;
dt_count = 0;
+ dt_elev_count = 0;
use_perf_vs = true;
isTanker = false;
// set heading and altitude locks
hdg_lock = false;
alt_lock = false;
+ roll = 0;
+ headingChangeRate = 0.0;
}
if (fp)
{
- ProcessFlightPlan(dt);
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+ ProcessFlightPlan(dt, now);
if (now < fp->getStartTime())
- return;
- //ProcessFlightPlan(dt);
+ {
+ // Do execute Ground elev for inactive aircraft, so they
+ // Are repositioned to the correct ground altitude when the user flies within visibility range.
+ if (no_roll)
+ {
+ Transform(); // make sure aip is initialized.
+ getGroundElev(dt); // make sure it's exectuted first time around, so force a large dt value
+ //getGroundElev(dt); // Need to do this twice.
+ //cerr << trafficRef->getRegistration() << " Setting altitude to " << tgt_altitude << endl;
+ setAltitude(tgt_altitude);
+ }
+ return;
+ }
}
-
+
double turn_radius_ft;
double turn_circum_ft;
double speed_north_deg_sec;
double alpha;
// adjust speed
- double speed_diff = tgt_speed - speed;
+ double speed_diff; //= tgt_speed - speed;
+ if (!no_roll)
+ {
+ speed_diff = tgt_speed - speed;
+ }
+ else
+ {
+ speed_diff = groundTargetSpeed - speed;
+ }
if (fabs(speed_diff) > 0.2) {
if (speed_diff > 0.0) speed += performance->accel * dt;
if (speed_diff < 0.0) {
- if (!no_roll) {
+ if (no_roll) { // was (!no_roll) but seems more logical this way (ground brakes).
speed -= performance->decel * dt * 3;
} else {
speed -= performance->decel * dt;
// set new position
pos.setlat( pos.lat() + speed_north_deg_sec * dt);
pos.setlon( pos.lon() + speed_east_deg_sec * dt);
+ //if (!(finite(pos.lat()) && finite(pos.lon())))
+ // {
+ // cerr << "Position is not finite" << endl;
+ // cerr << "speed = " << speed << endl;
+ // cerr << "dt" << dt << endl;
+ // cerr << "heading " << hdg << endl;
+ // cerr << "speed east " << speed_east_deg_sec << endl;
+ // cerr << "speed nrth " << speed_north_deg_sec << endl;
+ // cerr << "deg_lat " << ft_per_deg_lat << endl;
+ // cerr << "deg_lon " << ft_per_deg_lon << endl;
+ // }
// adjust heading based on current bank angle
+ if (roll == 0.0)
+ roll = 0.01;
if (roll != 0.0) {
- turn_radius_ft = 0.088362 * speed * speed
- / tan( fabs(roll) / SG_RADIANS_TO_DEGREES );
- turn_circum_ft = SGD_2PI * turn_radius_ft;
- dist_covered_ft = speed * 1.686 * dt;
- alpha = dist_covered_ft / turn_circum_ft * 360.0;
- hdg += alpha * sign( roll );
- if ( hdg > 360.0 ) hdg -= 360.0;
- if ( hdg < 0.0) hdg += 360.0;
+ // double turnConstant;
+ //if (no_roll)
+ // turnConstant = 0.0088362;
+ //else
+ // turnConstant = 0.088362;
+ // If on ground, calculate heading change directly
+ if (no_roll) {
+ double headingDiff = fabs(hdg-tgt_heading);
+
+ if (headingDiff > 180)
+ headingDiff = fabs(headingDiff - 360);
+ groundTargetSpeed = tgt_speed - (tgt_speed * (headingDiff/45));
+ if (sign(groundTargetSpeed) != sign(tgt_speed))
+ groundTargetSpeed = 0.21 * sign(tgt_speed); // to prevent speed getting stuck in 'negative' mode
+ if (headingDiff > 30.0)
+ {
+
+ headingChangeRate += dt * sign(roll); // invert if pushed backward
+ // Print some debug statements to find out why aircraft may get stuck
+ // forever turning
+ //if (trafficRef->getDepartureAirport()->getId() == string("EHAM"))
+ // {
+ //cerr << "Turning : " << trafficRef->getRegistration()
+ //cerr << " Speed = " << speed << " Heading " << hdg
+ //<< " Target Heading " << tgt_heading
+ // << " Lead Distance " << fp->getLeadDistance()
+ // << " Distance to go "
+ // << fp->getDistanceToGo(pos.lat(), pos.lon(), fp->getCurrentWaypoint())
+ // << "waypoint name " << fp->getCurrentWaypoint()->name
+ // << endl;
+ //}
+ if (headingChangeRate > 30)
+ {
+ headingChangeRate = 30;
+ }
+ else if (headingChangeRate < -30)
+ {
+ headingChangeRate = -30;
+ }
+ }
+ else
+ {
+ if (fabs(headingChangeRate) > headingDiff)
+ headingChangeRate = headingDiff*sign(roll);
+ else
+ headingChangeRate += dt * sign(roll);
+ }
+ hdg += headingChangeRate * dt;
+ //cerr << "On ground. Heading: " << hdg << ". Target Heading: " << tgt_heading << ". Target speed: " << groundTargetSpeed << ". heading change rate" << headingChangeRate << endl;
+ }
+ else {
+ if (fabs(speed) > 1.0) {
+ turn_radius_ft = 0.088362 * speed * speed
+ / tan( fabs(roll) / SG_RADIANS_TO_DEGREES );
+ }
+ else
+ {
+ turn_radius_ft = 1.0; // Check if turn_radius_ft == 0; this might lead to a division by 0.
+ }
+ turn_circum_ft = SGD_2PI * turn_radius_ft;
+ dist_covered_ft = speed * 1.686 * dt;
+ alpha = dist_covered_ft / turn_circum_ft * 360.0;
+ hdg += alpha * sign(roll);
+ }
+ while ( hdg > 360.0 ) {
+ hdg -= 360.0;
+ spinCounter++;
+ }
+ while ( hdg < 0.0)
+ {
+ hdg += 360.0;
+ spinCounter--;
+ }
}
-
+
+
// adjust target bank angle if heading lock engaged
if (hdg_lock) {
double bank_sense = 0.0;
if (diff > 180) diff = fabs(diff - 360);
double sum = hdg + diff;
if (sum > 360.0) sum -= 360.0;
- if (fabs(sum - tgt_heading) < 1.0) {
+ if (fabs(sum - tgt_heading) < 1.0) {
bank_sense = 1.0; // right turn
} else {
bank_sense = -1.0; // left turn
} else {
tgt_roll = 30.0 * bank_sense;
}
+ if ((fabs((double) spinCounter) > 1) && (diff > 30))
+ {
+ tgt_speed *= 0.999; // Ugly hack: If aircraft get stuck, they will continually spin around.
+ // The only way to resolve this is to make them slow down.
+ //if (tempReg.empty())
+ // tempReg = trafficRef->getRegistration();
+ //if (trafficRef->getRegistration() == tempReg)
+ // {
+ // cerr << trafficRef->getRegistration()
+ // << " appears to be spinning: " << spinCounter << endl
+ // << " speed " << speed << endl
+ // << " heading " << hdg << endl
+ // << " lead distance " << fp->getLeadDistance() << endl
+ // << " waypoint " << fp->getCurrentWaypoint()->name
+ // << " target heading " << tgt_heading << endl
+ // << " lead in angle " << fp->getLeadInAngle()<< endl
+ // << " roll " << roll << endl
+ // << " target_roll " << tgt_roll << endl;
+
+ // }
+ }
}
// adjust bank angle, use 9 degrees per second
if (fabs(bank_diff) > 0.2) {
if (bank_diff > 0.0) roll += 9.0 * dt;
if (bank_diff < 0.0) roll -= 9.0 * dt;
+ //while (roll > 180) roll -= 360;
+ //while (roll < 180) roll += 360;
}
// adjust altitude (meters) based on current vertical speed (fpm)
pos.setelev(altitude * SG_FEET_TO_METER);
double altitude_ft = altitude;
+ // adjust target Altitude, based on ground elevation when on ground
+ if (no_roll)
+ {
+ getGroundElev(dt);
+ }
// find target vertical speed if altitude lock engaged
if (alt_lock && use_perf_vs) {
if (altitude_ft < tgt_altitude) {
fp = f;
}
-void FGAIAircraft::ProcessFlightPlan( double dt ) {
-
+void FGAIAircraft::ProcessFlightPlan( double dt, time_t now )
+{
+ bool eraseWaypoints;
+ if (trafficRef)
+ {
+// FGAirport *arr;
+// FGAirport *dep;
+ eraseWaypoints = true;
+// cerr << trafficRef->getRegistration();
+// cerr << "Departure airport " << endl;
+// dep = trafficRef->getDepartureAirport();
+// if (dep)
+// cerr << dep->getId() << endl;
+// cerr << "Arrival airport " << endl;
+// arr = trafficRef->getArrivalAirport();
+// if (arr)
+// cerr << arr->getId() <<endl << endl;;
+ }
+ else
+ eraseWaypoints = false;
+ //cerr << "Processing Flightplan" << endl;
FGAIFlightPlan::waypoint* prev = 0; // the one behind you
FGAIFlightPlan::waypoint* curr = 0; // the one ahead
FGAIFlightPlan::waypoint* next = 0; // the next plus 1
curr = fp->getCurrentWaypoint();
next = fp->getNextWaypoint();
dt_count += dt;
-
+
if (!prev) { //beginning of flightplan, do this initialization once
- fp->IncrementWaypoint();
+ //setBank(0.0);
+ spinCounter = 0;
+ tempReg = "";
+ //prev_dist_to_go = HUGE;
+ //cerr << "Before increment " << curr-> name << endl;
+ fp->IncrementWaypoint(eraseWaypoints);
+ //prev = fp->getPreviousWaypoint(); //first waypoint
+ //curr = fp->getCurrentWaypoint(); //second waypoint
+ //next = fp->getNextWaypoint(); //third waypoint (might not exist!)
+ //cerr << "After increment " << prev-> name << endl;
+ if (!(fp->getNextWaypoint()) && trafficRef)
+ {
+ loadNextLeg();
+ }
+ //cerr << "After load " << prev-> name << endl;
prev = fp->getPreviousWaypoint(); //first waypoint
curr = fp->getCurrentWaypoint(); //second waypoint
next = fp->getNextWaypoint(); //third waypoint (might not exist!)
+ //cerr << "After load " << prev-> name << endl;
setLatitude(prev->latitude);
setLongitude(prev->longitude);
setSpeed(prev->speed);
setAltitude(prev->altitude);
- setHeading(fp->getBearing(prev->latitude, prev->longitude, curr));
- if (next) fp->setLeadDistance(speed, hdg, curr, next);
+ if (prev->speed > 0.0)
+ setHeading(fp->getBearing(prev->latitude, prev->longitude, curr));
+ else
+ {
+ setHeading(fp->getBearing(curr->latitude, curr->longitude, prev));
+ }
+ // If next doesn't exist, as in incrementally created flightplans for
+ // AI/Trafficmanager created plans,
+ // Make sure lead distance is initialized otherwise
+ if (next)
+ fp->setLeadDistance(speed, hdg, curr, next);
if (curr->crossat > -1000.0) { //use a calculated descent/climb rate
- use_perf_vs = false;
- tgt_vs = (curr->crossat - prev->altitude)/
- (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/
- 6076.0/prev->speed*60.0);
+ use_perf_vs = false;
+ tgt_vs = (curr->crossat - prev->altitude)/
+ (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/
+ 6076.0/prev->speed*60.0);
tgt_altitude = curr->crossat;
} else {
- use_perf_vs = true;
- tgt_altitude = prev->altitude;
+ use_perf_vs = true;
+ tgt_altitude = prev->altitude;
}
alt_lock = hdg_lock = true;
no_roll = prev->on_ground;
+ if (no_roll)
+ {
+ Transform(); // make sure aip is initialized.
+ getGroundElev(60.1); // make sure it's exectuted first time around, so force a large dt value
+ //getGroundElev(60.1); // Need to do this twice.
+ //cerr << trafficRef->getRegistration() << " Setting altitude to " << tgt_altitude << endl;
+ setAltitude(tgt_altitude);
+ }
+ prevSpeed = 0;
//cout << "First waypoint: " << prev->name << endl;
//cout << " Target speed: " << tgt_speed << endl;
//cout << " Target altitude: " << tgt_altitude << endl;
//cout << " Target heading: " << tgt_heading << endl << endl;
+ //cerr << "Done Flightplan init" << endl;
return;
} // end of initialization
-
+
// let's only process the flight plan every 100 ms.
- if (dt_count < 0.1) {
- return;
- } else {
- dt_count = 0;
-
- // check to see if we've reached the lead point for our next turn
- double dist_to_go = fp->getDistanceToGo(pos.lat(), pos.lon(), curr);
- double lead_dist = fp->getLeadDistance();
- if (lead_dist < (2*speed)) lead_dist = 2*speed; //don't skip over the waypoint
- //cout << "dist_to_go: " << dist_to_go << ", lead_dist: " << lead_dist << endl;
-
- if ( dist_to_go < lead_dist ) {
- if (curr->finished) { //end of the flight plan, so terminate
- if (trafficRef)
- {
- delete fp;
- //time_t now = time(NULL) + fgGetLong("/sim/time/warp");
- trafficRef->next();
-
- FGAIModelEntity entity;
- entity.m_class = "jet_transport";
- //entity.path = modelPath.c_str();
- entity.flightplan = "none";
- entity.latitude = _getLatitude();
- entity.longitude = _getLongitude();
- entity.altitude = trafficRef->getCruiseAlt() * 100; // convert from FL to feet
- entity.speed = 450;
- //entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr);
- entity.fp = new FGAIFlightPlan(&entity,
- 999, // A hack
- trafficRef->getDepartureTime(),
- trafficRef->getDepartureAirport(),
- trafficRef->getArrivalAirport());
- SetFlightPlan(entity.fp);
- }
- else
- {
- setDie(true);
- return;
- }
+ if ((dt_count < 0.1) || (now < fp->getStartTime()))
+ {
+ //cerr << "done fp dt" << endl;
+ return;
+ } else {
+ dt_count = 0;
+ }
+ // check to see if we've reached the lead point for our next turn
+ double dist_to_go = fp->getDistanceToGo(pos.lat(), pos.lon(), curr);
+
+ //cerr << "2" << endl;
+ double lead_dist = fp->getLeadDistance();
+ //cerr << " Distance : " << dist_to_go << ": Lead distance " << lead_dist << endl;
+ // experimental: Use fabs, because speed can be negative (I hope) during push_back.
+ if (lead_dist < fabs(2*speed))
+ {
+ lead_dist = fabs(2*speed); //don't skip over the waypoint
+ //cerr << "Extending lead distance to " << lead_dist << endl;
+ }
+// FGAirport * apt = trafficRef->getDepartureAirport();
+// if ((dist_to_go > prev_dist_to_go) && trafficRef && apt)
+// {
+// if (apt->getId() == string("EHAM"))
+// cerr << "Alert: " << trafficRef->getRegistration() << " is moving away from waypoint " << curr->name << endl
+// << "Target heading : " << tgt_heading << "act heading " << hdg << " Tgt speed : " << tgt_speed << endl
+// << "Lead distance : " << lead_dist << endl
+// << "Distance to go: " << dist_to_go << endl;
+
+// }
+ prev_dist_to_go = dist_to_go;
+ //cerr << "2" << endl;
+ //if (no_roll)
+ // lead_dist = 10.0;
+ //cout << "Leg : " << (fp->getLeg()-1) << ". dist_to_go: " << dist_to_go << ", lead_dist: " << lead_dist << ", tgt_speed " << tgt_speed << ", tgt_heading " << tgt_heading << " speed " << speed << " hdg " << hdg << ". Altitude " << altitude << " TAget alt :" << tgt_altitude << endl;
+
+ if ( dist_to_go < lead_dist ) {
+ //prev_dist_to_go = HUGE;
+ // For traffic manager generated aircraft:
+ // check if the aircraft flies of of user range. And adjust the
+ // Current waypoint's elevation according to Terrain Elevation
+ if (curr->finished) { //end of the flight plan
+ {
+ setDie(true);
+ //cerr << "Done die end of fp" << endl;
}
- // we've reached the lead-point for the waypoint ahead
- if (next) tgt_heading = fp->getBearing(curr, next);
- fp->IncrementWaypoint();
- prev = fp->getPreviousWaypoint();
- curr = fp->getCurrentWaypoint();
- next = fp->getNextWaypoint();
- if (next) fp->setLeadDistance(speed, tgt_heading, curr, next);
- if (curr->crossat > -1000.0) {
- use_perf_vs = false;
- tgt_vs = (curr->crossat - altitude)/
- (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0);
- tgt_altitude = curr->crossat;
- } else {
- use_perf_vs = true;
- tgt_altitude = prev->altitude;
+ return;
+ }
+
+ // we've reached the lead-point for the waypoint ahead
+ //cerr << "4" << endl;
+ //cerr << "Situation after lead point" << endl;
+ //cerr << "Prviious: " << prev->name << endl;
+ //cerr << "Current : " << curr->name << endl;
+ //cerr << "Next : " << next->name << endl;
+ if (next)
+ {
+ tgt_heading = fp->getBearing(curr, next);
+ spinCounter = 0;
+ }
+ fp->IncrementWaypoint(eraseWaypoints);
+ if (!(fp->getNextWaypoint()) && trafficRef)
+ {
+ loadNextLeg();
}
- tgt_speed = prev->speed;
- hdg_lock = alt_lock = true;
- no_roll = prev->on_ground;
- //cout << "Crossing waypoint: " << prev->name << endl;
- //cout << " Target speed: " << tgt_speed << endl;
- //cout << " Target altitude: " << tgt_altitude << endl;
- //cout << " Target heading: " << tgt_heading << endl << endl;
+ prev = fp->getPreviousWaypoint();
+ curr = fp->getCurrentWaypoint();
+ next = fp->getNextWaypoint();
+ // Now that we have incremented the waypoints, excute some traffic manager specific code
+ // based on the name of the waypoint we just passed.
+ if (trafficRef)
+ {
+ double userLatitude = fgGetDouble("/position/latitude-deg");
+ double userLongitude = fgGetDouble("/position/longitude-deg");
+ double course, distance;
+ SGWayPoint current (pos.lon(),
+ pos.lat(),
+ 0);
+ SGWayPoint user ( userLongitude,
+ userLatitude,
+ 0);
+ user.CourseAndDistance(current, &course, &distance);
+ if ((distance * SG_METER_TO_NM) > TRAFFICTOAIDIST)
+ {
+ setDie(true);
+ //cerr << "done fp die out of range" << endl;
+ return;
+ }
+
+ FGAirport * dep = trafficRef->getDepartureAirport();
+ FGAirport * arr = trafficRef->getArrivalAirport();
+ // At parking the beginning of the airport
+ if (!( dep && arr))
+ {
+ setDie(true);
+ return;
+ }
+ //if ((dep->getId() == string("EHAM") || (arr->getId() == string("EHAM"))))
+ // {
+ // cerr << trafficRef->getRegistration()
+ // << " Enroute from " << dep->getId()
+ // << " to " << arr->getId()
+ // << " just crossed " << prev->name
+ // << " Assigned rwy " << fp->getRunwayId()
+ // << " " << fp->getRunway() << endl;
+ // }
+ //if ((dep->getId() == string("EHAM")) && (prev->name == "park2"))
+ // {
+ // cerr << "Schiphol ground "
+ // << trafficRef->getCallSign();
+ // if (trafficRef->getHeavy())
+ // cerr << "Heavy";
+ // cerr << ", is type "
+ // << trafficRef->getAircraft()
+ // << " ready to go. IFR to "
+ // << arr->getId() <<endl;
+ // }
+ if (prev->name == "park2")
+ dep->releaseParking(fp->getGate());
+
+ //if ((arr->getId() == string("EHAM")) && (prev->name == "Center"))
+ // {
+ //
+ // cerr << "Schiphol ground "
+ // << trafficRef->getCallSign();
+ // if (trafficRef->getHeavy())
+ // cerr << "Heavy";
+ // cerr << " landed runway "
+ // << fp->getRunway()
+ // << " request taxi to gate "
+ // << arr->getParkingName(fp->getGate())
+ // << endl;
+ // }
+ if (prev->name == "END")
+ fp->setTime(trafficRef->getDepartureTime());
+ //cerr << "5" << endl;
+ }
+ if (next)
+ {
+ //cerr << "Current waypoint" << curr->name << endl;
+ //cerr << "Next waypoint" << next->name << endl;
+ fp->setLeadDistance(speed, tgt_heading, curr, next);
+ }
+ //cerr << "5.1" << endl;
+ if (curr->crossat > -1000.0) {
+ //cerr << "5.1a" << endl;
+ use_perf_vs = false;
+ tgt_vs = (curr->crossat - altitude)/
+ (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0);
+ //cerr << "5.1b" << endl;
+ tgt_altitude = curr->crossat;
} else {
- double calc_bearing = fp->getBearing(pos.lat(), pos.lon(), curr);
- double hdg_error = calc_bearing - tgt_heading;
- if (fabs(hdg_error) > 1.0) {
- TurnTo( calc_bearing );
- }
+ //cerr << "5.1c" << endl;
+ use_perf_vs = true;
+ //cerr << "5.1d" << endl;
+ tgt_altitude = prev->altitude;
+ //cerr << "Setting target altitude : " <<tgt_altitude << endl;
}
-
- }
-
+ //cerr << "6" << endl;
+ tgt_speed = prev->speed;
+ hdg_lock = alt_lock = true;
+ no_roll = prev->on_ground;
+ //cout << "Crossing waypoint: " << prev->name << endl;
+ //cout << " Target speed: " << tgt_speed << endl;
+ //cout << " Target altitude: " << tgt_altitude << endl;
+ //cout << " Target heading: " << tgt_heading << endl << endl;
+ } else {
+
+ double calc_bearing = fp->getBearing(pos.lat(), pos.lon(), curr);
+ //cerr << "Bearing = " << calc_bearing << endl;
+ if (speed < 0)
+ {
+ calc_bearing +=180;
+ if (calc_bearing > 360)
+ calc_bearing -= 360;
+ }
+ if (finite(calc_bearing))
+ {
+ double hdg_error = calc_bearing - tgt_heading;
+ if (fabs(hdg_error) > 1.0) {
+ TurnTo( calc_bearing );
+ }
+ }
+ else
+ {
+ cerr << "calc_bearing is not a finite number : "
+ << "Speed " << speed
+ << "pos : " << pos.lat() << ", " << pos.lon()
+ << "waypoint " << curr->latitude << ", " << curr->longitude << endl;
+ cerr << "waypoint name " << curr->name;
+ exit(1);
+ }
+ double speed_diff = speed - prevSpeed;
+ // Update the lead distance calculation if speed has changed sufficiently
+ // to prevent spinning (hopefully);
+ if (fabs(speed_diff) > 10)
+ {
+ prevSpeed = speed;
+ fp->setLeadDistance(speed, tgt_heading, curr, next);
+ }
+
+ //cerr << "Done Processing FlightPlan"<< endl;
+ } // if (dt count) else
}
-
-bool FGAIAircraft::_getGearDown() const {
+ bool FGAIAircraft::_getGearDown() const {
return ((props->getFloatValue("position/altitude-agl-ft") < 900.0)
&& (props->getFloatValue("velocities/airspeed-kt")
< performance->land_speed*1.25));
}
+
+
+void FGAIAircraft::loadNextLeg()
+{
+ //delete fp;
+ //time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+
+
+ //FGAIModelEntity entity;
+ //entity.m_class = "jet_transport";
+ //entity.path = modelPath.c_str();
+ //entity.flightplan = "none";
+ //entity.latitude = _getLatitude();
+ //entity.longitude = _getLongitude();
+ //entity.altitude = trafficRef->getCruiseAlt() * 100; // convert from FL to feet
+ //entity.speed = 450; // HACK ALERT
+ //entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr);
+ int leg;
+ if ((leg = fp->getLeg()) == 10)
+ {
+ trafficRef->next();
+ leg = 1;
+ fp->setLeg(leg);
+
+ //cerr << "Resetting leg : " << leg << endl;
+ }
+ //{
+ //leg++;
+ //fp->setLeg(leg);
+ //cerr << "Creating leg number : " << leg << endl;
+ FGAirport *dep = trafficRef->getDepartureAirport();
+ FGAirport *arr = trafficRef->getArrivalAirport();
+ if (!(dep && arr))
+ {
+ setDie(true);
+ //cerr << "Failed to get airport in AIAircraft::ProcessFlightplan()" << endl;
+ //if (dep)
+ // cerr << "Departure " << dep->getId() << endl;
+ //if (arr)
+ // cerr << "Arrival " << arr->getId() << endl;
+ }
+ else
+ {
+ double cruiseAlt = trafficRef->getCruiseAlt() * 100;
+ //cerr << "Creating new leg using " << cruiseAlt << " as cruise altitude."<< endl;
+
+ fp->create (dep,
+ arr,
+ leg,
+ cruiseAlt, //(trafficRef->getCruiseAlt() * 100), // convert from FL to feet
+ trafficRef->getSpeed(),
+ _getLatitude(),
+ _getLongitude(),
+ false,
+ trafficRef->getRadius(),
+ trafficRef->getFlightType(),
+ acType,
+ company);
+ //prev = fp->getPreviousWaypoint();
+ //curr = fp->getCurrentWaypoint();
+ //next = fp->getNextWaypoint();
+ //cerr << "25" << endl;
+ //if (next)
+ // {
+ // //cerr << "Next waypoint" << next->name << endl;
+ // fp->setLeadDistance(speed, tgt_heading, curr, next);
+ // }
+ //cerr << "25.1" << endl;
+ //if (curr->crossat > -1000.0) {
+ // //cerr << "25.1a" << endl;
+ // use_perf_vs = false;
+ //
+ // tgt_vs = (curr->crossat - altitude)/
+ // (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0);
+ // //cerr << "25.1b" << endl;
+ // tgt_altitude = curr->crossat;
+ //} else {
+ // //cerr << "25.1c" << endl;
+ // use_perf_vs = true;
+ // //cerr << "25.1d" << endl;
+ // tgt_altitude = prev->altitude;
+ // //cerr << "Setting target altitude : " <<tgt_altitude << endl;
+ // }
+ //cerr << "26" << endl;
+ //tgt_speed = prev->speed;
+ //hdg_lock = alt_lock = true;
+ //no_roll = prev->on_ground;
+
+ }
+ //}
+ //else
+ //{
+ //delete entity.fp;
+ //entity.fp = new FGAIFlightPlan(&entity,
+ // 999, // A hack
+ // trafficRef->getDepartureTime(),
+ // trafficRef->getDepartureAirport(),
+ // trafficRef->getArrivalAirport(),
+ // false,
+ // acType,
+ // company);
+ //SetFlightPlan(entity.fp);
+}
+
+
+
+// Note: This code is copied from David Luff's AILocalTraffic
+// Warning - ground elev determination is CPU intensive
+// Either this function or the logic of how often it is called
+// will almost certainly change.
+
+void FGAIAircraft::getGroundElev(double dt) {
+ dt_elev_count += dt;
+ //return;
+ if (dt_elev_count < (10.0 + (rand() % 100))) // Update minimally every 10 secs, but add some randomness to prevent them all IA objects doing this synced
+ {
+ return;
+ }
+ else
+ {
+ dt_elev_count = 0;
+ }
+ // It would be nice if we could set the correct tile center here in order to get a correct
+ // answer with one call to the function, but what I tried in the two commented-out lines
+ // below only intermittently worked, and I haven't quite groked why yet.
+ //SGBucket buck(pos.lon(), pos.lat());
+ //aip.getSGLocation()->set_tile_center(Point3D(buck.get_center_lon(), buck.get_center_lat(), 0.0));
+
+ // Only do the proper hitlist stuff if we are within visible range of the viewer.
+ double visibility_meters = fgGetDouble("/environment/visibility-m");
+
+
+ FGViewer* vw = globals->get_current_view();
+ double
+ course,
+ distance;
+
+ //Point3D currView(vw->getLongitude_deg(),
+ // vw->getLatitude_deg(), 0.0);
+ SGWayPoint current (pos.lon(),
+ pos.lat(),
+ 0);
+ SGWayPoint view ( vw->getLongitude_deg(),
+ vw->getLatitude_deg(),
+ 0);
+ view.CourseAndDistance(current, &course, &distance);
+ if(distance > visibility_meters) {
+ //aip.getSGLocation()->set_cur_elev_m(aptElev);
+ return;
+ }
+
+
+ //globals->get_tile_mgr()->prep_ssg_nodes( acmodel_location,
+ globals->get_tile_mgr()->prep_ssg_nodes( aip.getSGLocation(), visibility_meters );
+ Point3D scenery_center = globals->get_scenery()->get_center();
+
+ globals->get_tile_mgr()->update( aip.getSGLocation(),
+ visibility_meters,
+ (aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
+ // save results of update in SGLocation for fdm...
+
+ //if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
+ // acmodel_location->
+ // set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
+ //}
+
+ // The need for this here means that at least 2 consecutive passes are needed :-(
+ aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
+ globals->get_tile_mgr()->prep_ssg_nodes( aip.getSGLocation(), visibility_meters );
+ //Point3D scenery_center = globals->get_scenery()->get_center();
+
+ globals->get_tile_mgr()->update( aip.getSGLocation(),
+ visibility_meters,
+ (aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
+ // save results of update in SGLocation for fdm...
+
+ //if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
+ // acmodel_location->
+ // set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
+ //}
+
+ // The need for this here means that at least 2 consecutive passes are needed :-(
+ aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
+ //cerr << "Transform Elev is " << globals->get_scenery()->get_cur_elev() << '\n';
+ tgt_altitude = (globals->get_scenery()->get_cur_elev() * SG_METER_TO_FEET) + groundOffset;
+}
+
+//globals->get_tile_mgr()->prep_ssg_nodes( _aip.getSGLocation(), visibility_meters );
+//Point3D scenery_center = globals->get_scenery()->get_center();
+//globals->get_tile_mgr()->update(_aip.getSGLocation(), visibility_meters, (_aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
+// save results of update in SGLocation for fdm...
+
+//if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
+// acmodel_location->
+// set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
+//}
+
+// The need for this here means that at least 2 consecutive passes are needed :-(
+//_aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
+
+//cout << "Transform Elev is " << globals->get_scenery()->get_cur_elev() << '\n';
+//_aip.getSGLocation()->set_cur_elev_m(globals->get_scenery()->get_cur_elev());
+//return(globals->get_scenery()->get_cur_elev());
+//}
} PERF_STRUCT;
public:
-
enum aircraft_e {LIGHT=0, WW2_FIGHTER, JET_TRANSPORT, JET_FIGHTER, TANKER};
static const PERF_STRUCT settings[];
void YawTo(double angle);
void ClimbTo(double altitude);
void TurnTo(double heading);
- void ProcessFlightPlan( double dt );
+ void ProcessFlightPlan( double dt, time_t now );
+ void getGroundElev(double dt);
+ void loadNextLeg ();
+
+ void setAcType(string ac) { acType = ac; };
+ void setCompany(string comp) { company = comp;};
+ //void setSchedule(FGAISchedule *ref) { trafficRef = ref;};
inline void SetTanker(bool setting) { isTanker = setting; };
bool hdg_lock;
bool alt_lock;
double dt_count;
+ double dt_elev_count;
+ double headingChangeRate;
+ double groundTargetSpeed;
+ double groundOffset;
double dt;
const PERF_STRUCT *performance;
void Run(double dt);
double sign(double x);
+
+ string acType;
+ string company;
+ int spinCounter;
+ double prevSpeed;
+ double prev_dist_to_go;
bool _getGearDown() const;
+ bool reachedWaypoint;
};
#include <simgear/constants.h>
#include <simgear/math/point3d.hxx>
#include <simgear/scene/model/placement.hxx>
+#include <simgear/misc/sg_path.hxx>
#include <Main/fg_props.hxx>
double radius; // used by ship ojects, in feet
double x_offset; // used by ship ojects, in meters
double y_offset; // used by ship ojects, in meters
- double z_offset; // used by ship ojects, in meters
+ double z_offset; // used by ship ojects, in meters
+ string acType; // used by aircraft objects
+ string company; // used by aircraft objects
} FGAIModelEntity;
{
int i;
start_time = 0;
+ leg = 10;
+ gateId = 0;
SGPath path( globals->get_fg_root() );
path.append( ("/Data/AI/FlightPlans/" + filename).c_str() );
SGPropertyNode root;
SG_LOG(SG_GENERAL, SG_ALERT,
"Error reading AI flight plan: " << path.str());
// cout << path.str() << endl;
- return;
+ return;
}
SGPropertyNode * node = root.getNode("flightplan");
double course,
time_t start,
FGAirport *dep,
- FGAirport *arr)
+ FGAirport *arr,
+ bool firstLeg,
+ double radius,
+ string fltType,
+ string acType,
+ string airline)
{
+ leg = 10;
+ gateId=0;
start_time = start;
bool useInitialWayPoint = true;
bool useCurrentWayPoint = false;
useCurrentWayPoint = true;
}
- try {
- readProperties(path.str(), &root);
-
- SGPropertyNode * node = root.getNode("flightplan");
-
- //waypoints.push_back( init_waypoint );
- for (int i = 0; i < node->nChildren(); i++) {
- //cout << "Reading waypoint " << i << endl;
- waypoint* wpt = new waypoint;
- SGPropertyNode * wpt_node = node->getChild(i);
- wpt->name = wpt_node->getStringValue("name", "END");
- wpt->latitude = wpt_node->getDoubleValue("lat", 0);
- wpt->longitude = wpt_node->getDoubleValue("lon", 0);
- wpt->altitude = wpt_node->getDoubleValue("alt", 0);
- wpt->speed = wpt_node->getDoubleValue("ktas", 0);
- //wpt->speed = speed;
- wpt->crossat = wpt_node->getDoubleValue("crossat", -10000);
- wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
- wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
+ if (path.exists())
+ {
+ try
+ {
+ readProperties(path.str(), &root);
+
+ SGPropertyNode * node = root.getNode("flightplan");
+
+ //waypoints.push_back( init_waypoint );
+ for (int i = 0; i < node->nChildren(); i++) {
+ //cout << "Reading waypoint " << i << endl;
+ waypoint* wpt = new waypoint;
+ SGPropertyNode * wpt_node = node->getChild(i);
+ wpt->name = wpt_node->getStringValue("name", "END");
+ wpt->latitude = wpt_node->getDoubleValue("lat", 0);
+ wpt->longitude = wpt_node->getDoubleValue("lon", 0);
+ wpt->altitude = wpt_node->getDoubleValue("alt", 0);
+ wpt->speed = wpt_node->getDoubleValue("ktas", 0);
+ //wpt->speed = speed;
+ wpt->crossat = wpt_node->getDoubleValue("crossat", -10000);
+ wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
+ wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
+
+ if (wpt->name == "END") wpt->finished = true;
+ else wpt->finished = false;
+ waypoints.push_back(wpt);
+ }
+ }
+ catch (const sg_exception &e) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "Error reading AI flight plan: ");
+ cerr << "Errno = " << errno << endl;
+ if (errno == ENOENT)
+ {
+ cerr << "Reason: No such file or directory" << endl;
+ }
+ }
+ }
+ else
+ {
+ // cout << path.str() << endl;
+ // cout << "Trying to create this plan dynamically" << endl;
+ // cout << "Route from " << dep->id << " to " << arr->id << endl;
+ time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+ time_t timeDiff = now-start;
+ leg = 1;
+ if ((timeDiff > 300) && (timeDiff < 1200))
+ leg = 2;
+ else if ((timeDiff >= 1200) && (timeDiff < 1500))
+ leg = 3;
+ else if ((timeDiff >= 1500) && (timeDiff < 2000))
+ leg = 4;
+ else if (timeDiff >= 2000)
+ leg = 5;
- if (wpt->name == "END") wpt->finished = true;
- else wpt->finished = false;
- waypoints.push_back(wpt);
+ //cerr << "Set leg to : " << leg << endl;
+ wpt_iterator = waypoints.begin();
+ create(dep,arr, leg, entity->altitude, entity->speed, entity->latitude, entity->longitude,
+ firstLeg, radius, fltType, acType, airline);
+ wpt_iterator = waypoints.begin();
+ //cerr << "after create: " << (*wpt_iterator)->name << endl;
+ //leg++;
+ // Now that we have dynamically created a flight plan,
+ // we need to add some code that pops any waypoints already past.
+ //return;
}
- }
- catch (const sg_exception &e) {
- //SG_LOG(SG_GENERAL, SG_ALERT,
- // "Error reading AI flight plan: ");
- // cout << path.str() << endl;
- // cout << "Trying to create this plan dynamically" << endl;
- // cout << "Route from " << dep->id << " to " << arr->id << endl;
- create(dep,arr, entity->altitude, entity->speed);
- // Now that we have dynamically created a flight plan,
- // we need to add some code that pops any waypoints already past.
- //return;
- }
- waypoint* init_waypoint = new waypoint;
- init_waypoint->name = string("initial position");
- init_waypoint->latitude = entity->latitude;
- init_waypoint->longitude = entity->longitude;
- init_waypoint->altitude = entity->altitude;
- init_waypoint->speed = entity->speed;
- init_waypoint->crossat = - 10000;
- init_waypoint->gear_down = false;
- init_waypoint->flaps_down = false;
- init_waypoint->finished = false;
-
- wpt_vector_iterator i = waypoints.begin();
- while (i != waypoints.end())
+ /*
+ waypoint* init_waypoint = new waypoint;
+ init_waypoint->name = string("initial position");
+ init_waypoint->latitude = entity->latitude;
+ init_waypoint->longitude = entity->longitude;
+ init_waypoint->altitude = entity->altitude;
+ init_waypoint->speed = entity->speed;
+ init_waypoint->crossat = - 10000;
+ init_waypoint->gear_down = false;
+ init_waypoint->flaps_down = false;
+ init_waypoint->finished = false;
+
+ wpt_vector_iterator i = waypoints.begin();
+ while (i != waypoints.end())
{
//cerr << "Checking status of each waypoint: " << (*i)->name << endl;
SGWayPoint first(init_waypoint->longitude,
//delete wpt;
delete *(i);
i = waypoints.erase(i);
+ }
+
}
- }
+ */
//for (i = waypoints.begin(); i != waypoints.end(); i++)
// cerr << "Using waypoint : " << (*i)->name << endl;
- wpt_iterator = waypoints.begin();
+ //wpt_iterator = waypoints.begin();
//cout << waypoints.size() << " waypoints read." << endl;
}
FGAIFlightPlan::~FGAIFlightPlan()
{
- waypoints.clear();
+ deleteWaypoints();
+ //waypoints.clear();
+ //while (waypoints.begin() != waypoints.end())
+ // {
+ // delete *(waypoints.begin());
+ // waypoints.erase (waypoints.begin());
+ // }
}
FGAIFlightPlan::waypoint*
FGAIFlightPlan::getNextWaypoint( void )
{
- if (wpt_iterator == waypoints.end()) {
+ wpt_vector_iterator i = waypoints.end();
+ i--; // end() points to one element after the last one.
+ if (wpt_iterator == i) {
return 0;
} else {
wpt_vector_iterator next = wpt_iterator;
}
}
-void FGAIFlightPlan::IncrementWaypoint( void )
+void FGAIFlightPlan::IncrementWaypoint(bool eraseWaypoints )
{
- wpt_iterator++;
+ if (eraseWaypoints)
+ {
+ if (wpt_iterator == waypoints.begin())
+ wpt_iterator++;
+ else
+ {
+ delete *(waypoints.begin());
+ waypoints.erase(waypoints.begin());
+ wpt_iterator = waypoints.begin();
+ wpt_iterator++;
+ }
+ }
+ else
+ wpt_iterator++;
}
// gives distance in feet from a position to a waypoint
double FGAIFlightPlan::getDistanceToGo(double lat, double lon, waypoint* wp){
- // get size of a degree at the present latitude
+ // get size of a degree2 at the present latitude
// this won't work over large distances
double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat / SG_RADIANS_TO_DEGREES);
double ft_per_deg_lon = 365228.16 * cos(lat / SG_RADIANS_TO_DEGREES);
// sets distance in feet from a lead point to the current waypoint
void FGAIFlightPlan::setLeadDistance(double speed, double bearing,
waypoint* current, waypoint* next){
- double turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank
+ double turn_radius;
+ if (fabs(speed) > 1)
+ turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank
+ else
+ turn_radius = 1.0;
+
double inbound = bearing;
double outbound = getBearing(current, next);
- double diff = fabs(inbound - outbound);
- if (diff > 180.0) diff = 360.0 - diff;
- lead_distance = turn_radius * sin(diff * SG_DEGREES_TO_RADIANS);
+ leadInAngle = fabs(inbound - outbound);
+ if (leadInAngle > 180.0)
+ leadInAngle = 360.0 - leadInAngle;
+ if (leadInAngle < 1.0) // To prevent lead_dist from getting so small it is skipped
+ leadInAngle = 1.0;
+
+ lead_distance = turn_radius * sin(leadInAngle * SG_DEGREES_TO_RADIANS);
+ // if ((errno == EDOM) || (errno == ERANGE) || lead_distance < 1.0)
+ // {
+ // cerr << "Lead Distance = " << lead_distance
+ // << "Diff = " << diff
+ // << "Turn Radius = " << turn_radius
+ // << "Speed = " << speed << endl;
+ // }
}
void FGAIFlightPlan::setLeadDistance(double distance_ft){
// if (!southerly && !easterly) return 270.0 + angle;
SGWayPoint sgWp(wp->longitude,wp->latitude, wp->altitude, SGWayPoint::WGS84, string("temp"));
sgWp.CourseAndDistance(lon, lat, wp->altitude, &course, &distance);
+
return course;
- // Omit a compiler warning.
-
+ // Omit a compiler warning.
+ //if ((errno == EDOM) || (errno == ERANGE))
+ // {
+ // cerr << "Lon: " << wp->longitude
+ // << "Lat = " << wp->latitude
+ // << "Tgt Lon = " <<
+ // << "TgT Lat = " << speed << endl;
+ // }
+
}
-/* FGAIFlightPlan::create()
- * dynamically create a flight plan for AI traffic, based on data provided by the
- * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10)
- *
- * Probably need to split this into separate functions for different parts of the flight
- * once the code matures a bit more.
- *
- */
-void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, double alt, double speed)
-{
-double wind_speed;
- double wind_heading;
- FGRunway rwy;
- double lat, lon, az;
- double lat2, lon2, az2;
- int direction;
-
- //waypoints.push_back(wpt);
- // Create the outbound taxi leg, for now simplified as a
- // Direct route from the airport center point to the start
- // of the runway.
- ///////////////////////////////////////////////////////////
- //cerr << "Cruise Alt << " << alt << endl;
- // Temporary code to add some small random variation to aircraft parking positions;
- direction = (rand() % 360);
-geo_direct_wgs_84 ( 0, dep->_latitude, dep->_longitude, direction,
- 100,
- &lat2, &lon2, &az2 );
- waypoint *wpt = new waypoint;
- wpt->name = dep->_id; //wpt_node->getStringValue("name", "END");
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = dep->_elevation + 19; // probably need to add some model height to it
- wpt->speed = 15;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = true;
- waypoints.push_back(wpt);
-
- // Get the current active runway, based on code from David Luff
- FGEnvironment
- stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
- ->getEnvironment(dep->_latitude, dep->_longitude, dep->_elevation);
-
- wind_speed = stationweather.get_wind_speed_kt();
- wind_heading = stationweather.get_wind_from_heading_deg();
- if (wind_speed == 0) {
- wind_heading = 270; // This forces West-facing rwys to be used in no-wind situations
- // which is consistent with Flightgear's initial setup.
- }
-
- string rwy_no = globals->get_runways()->search(dep->_id, int(wind_heading));
- if (!(globals->get_runways()->search(dep->_id, (int) wind_heading, &rwy )))
- {
- cout << "Failed to find runway for " << dep->_id << endl;
- // Hmm, how do we handle a potential error like this?
- exit(1);
- }
-
- double heading = rwy._heading;
- double azimuth = heading + 180.0;
- while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
- &lat2, &lon2, &az2 );
-
- //Add the runway startpoint;
- wpt = new waypoint;
- wpt->name = rwy._id;
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = dep->_elevation + 19;
- wpt->speed = 15;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = true;
- waypoints.push_back(wpt);
-
- //Next: The point on the runway where we begin to accelerate to take-off speed
- //100 meters down the runway seems to work. Shorter distances cause problems with
- // the turn with larger aircraft
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- rwy._length * SG_FEET_TO_METER * 0.5 - 105.0,
- &lat2, &lon2, &az2 );
- wpt = new waypoint;
- wpt->name = "accel";
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = dep->_elevation + 19;
- wpt->speed = speed;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = true;
- waypoints.push_back(wpt);
-
- lat = lat2;
- lon = lon2;
- az = az2;
-
- //Next: the Start of Climb
- geo_direct_wgs_84 ( 0, lat, lon, heading,
- 2560 * SG_FEET_TO_METER,
- &lat2, &lon2, &az2 );
-
- wpt = new waypoint;
- wpt->name = "SOC";
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = alt + 19;
- wpt->speed = speed;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = false;
- waypoints.push_back(wpt);
-
-//Next: the Top of Climb
- geo_direct_wgs_84 ( 0, lat, lon, heading,
- 20*SG_NM_TO_METER,
- &lat2, &lon2, &az2 );
- wpt = new waypoint;
- wpt->name = "10000ft climb";
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = 10000;
- wpt->speed = speed;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = false;
- waypoints.push_back(wpt);
-
-
-
- //Beginning of Decent
- stationweather = ((FGEnvironmentMgr *)globals->get_subsystem("environment"))
- ->getEnvironment(arr->_latitude, arr->_longitude, arr->_elevation);
-
- wind_speed = stationweather.get_wind_speed_kt();
- wind_heading = stationweather.get_wind_from_heading_deg();
-
- if (wind_speed == 0) {
- wind_heading = 270; // This forces West-facing rwys to be used in no-wind situations
- // which is consistent with Flightgear's initial setup.
- }
+void FGAIFlightPlan::deleteWaypoints()
+{
+ for (wpt_vector_iterator i = waypoints.begin(); i != waypoints.end();i++)
+ delete (*i);
+ waypoints.clear();
+}
- rwy_no = globals->get_runways()->search(arr->_id, int(wind_heading));
- //cout << "Using runway # " << rwy_no << " for departure at " << dep->_id << endl;
-
- if (!(globals->get_runways()->search(arr->_id, (int) wind_heading, &rwy )))
+// Delete all waypoints except the last,
+// which we will recycle as the first waypoint in the next leg;
+void FGAIFlightPlan::resetWaypoints()
+{
+ if (waypoints.begin() == waypoints.end())
+ return;
+ else
{
- cout << "Failed to find runway for " << arr->_id << endl;
- // Hmm, how do we handle a potential error like this?
- exit(1);
+ waypoint *wpt = new waypoint;
+ wpt_vector_iterator i = waypoints.end();
+ i--;
+ wpt->name = (*i)->name;
+ wpt->latitude = (*i)->latitude;
+ wpt->longitude = (*i)->longitude;
+ wpt->altitude = (*i)->altitude;
+ wpt->speed = (*i)->speed;
+ wpt->crossat = (*i)->crossat;
+ wpt->gear_down = (*i)->gear_down;
+ wpt->flaps_down= (*i)->flaps_down;
+ wpt->finished = false;
+ wpt->on_ground = (*i)->on_ground;
+ //cerr << "Recycling waypoint " << wpt->name << endl;
+ deleteWaypoints();
+ waypoints.push_back(wpt);
}
- //cerr << "Done" << endl;
- heading = rwy._heading;
- azimuth = heading + 180.0;
- while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
-
-
-
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- 100000,
- &lat2, &lon2, &az2 );
- wpt = new waypoint;
- wpt->name = "BOD"; //wpt_node->getStringValue("name", "END");
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = 10000;
- wpt->speed = speed;
- wpt->crossat = alt +19;
- wpt->gear_down = false;
- wpt->flaps_down= false;
- wpt->finished = false;
- wpt->on_ground = false;
- waypoints.push_back(wpt);
-
- // Ten thousand ft. Slowing down to 240 kts
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- 20*SG_NM_TO_METER,
- &lat2, &lon2, &az2 );
- wpt = new waypoint;
- wpt->name = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = arr->_elevation + 19;
- wpt->speed = 240;
- wpt->crossat = 10000;
- wpt->gear_down = false;
- wpt->flaps_down= false;
- wpt->finished = false;
- wpt->on_ground = false;
- waypoints.push_back(wpt);
-
- // Three thousand ft. Slowing down to 160 kts
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- 8*SG_NM_TO_METER,
- &lat2, &lon2, &az2 );
- wpt = new waypoint;
- wpt->name = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = arr->_elevation + 19;
- wpt->speed = 160;
- wpt->crossat = 3000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = false;
- waypoints.push_back(wpt);
- //Runway Threshold
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- rwy._length*0.45 * SG_FEET_TO_METER,
- &lat2, &lon2, &az2 );
- wpt = new waypoint;
- wpt->name = "Threshold"; //wpt_node->getStringValue("name", "END");
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = arr->_elevation + 19;
- wpt->speed = 15;
- wpt->crossat = arr->_elevation + 19;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = true;
- waypoints.push_back(wpt);
-
- //Full stop at the runway centerpoint
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- rwy._length*0.45,
- &lat2, &lon2, &az2 );
- wpt = new waypoint;
- wpt->name = "Center"; //wpt_node->getStringValue("name", "END");
- wpt->latitude = rwy._lat;
- wpt->longitude = rwy._lon;
- wpt->altitude = arr->_elevation + 19;
- wpt->speed = 15;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = true;
- waypoints.push_back(wpt);
-
-direction = (rand() % 360);
-geo_direct_wgs_84 ( 0, arr->_latitude, arr->_longitude, direction,
- 100,
- &lat2, &lon2, &az2 );
-
- // Add the final destination waypoint
- wpt = new waypoint;
- wpt->name = arr->_id; //wpt_node->getStringValue("name", "END");
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = arr->_elevation+19;
- wpt->speed = 15;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = false;
- wpt->on_ground = true;
- waypoints.push_back(wpt);
-
- // And finally one more named "END"
- wpt = new waypoint;
- wpt->name = "END"; //wpt_node->getStringValue("name", "END");
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = 19;
- wpt->speed = 15;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = true;
- wpt->on_ground = true;
- waypoints.push_back(wpt);
-
- // And finally one more named "EOF"
- wpt = new waypoint;
- wpt->name = "EOF"; //wpt_node->getStringValue("name", "END");
- wpt->latitude = lat2;
- wpt->longitude = lon2;
- wpt->altitude = 19;
- wpt->speed = 15;
- wpt->crossat = -10000;
- wpt->gear_down = true;
- wpt->flaps_down= true;
- wpt->finished = true;
- wpt->on_ground = true;
- waypoints.push_back(wpt);
}
#include <string>
#include <Airports/simple.hxx>
+#include <Airports/runways.hxx>
#include "AIBase.hxx"
double course,
time_t start,
FGAirport *dep,
- FGAirport *arr);
+ FGAirport *arr,
+ bool firstLeg,
+ double radius,
+ string fltType,
+ string acType,
+ string airline);
~FGAIFlightPlan();
waypoint* getPreviousWaypoint( void );
waypoint* getCurrentWaypoint( void );
waypoint* getNextWaypoint( void );
- void IncrementWaypoint( void );
+ void IncrementWaypoint( bool erase );
double getDistanceToGo(double lat, double lon, waypoint* wp);
+ int getLeg () { return leg;};
void setLeadDistance(double speed, double bearing, waypoint* current, waypoint* next);
void setLeadDistance(double distance_ft);
double getLeadDistance( void ) const {return lead_distance;}
double getBearing(double lat, double lon, waypoint* next);
time_t getStartTime() { return start_time; };
- void create(FGAirport *dep, FGAirport *arr, double alt, double speed);
+ void create(FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
+ bool firstLeg, double radius, string fltType, string aircraftType, string airline);
+ void setLeg(int val) { leg = val;};
+ void setTime(time_t st) { start_time = st; };
+ int getGate() { return gateId; };
+ double getLeadInAngle() { return leadInAngle; };
+ string getRunway() { return rwy._rwy_no; };
+ string getRunwayId() { return rwy._id; };
private:
-
+ FGRunway rwy;
typedef vector <waypoint*> wpt_vector_type;
typedef wpt_vector_type::iterator wpt_vector_iterator;
double distance_to_go;
double lead_distance;
+ double leadInAngle;
time_t start_time;
-
+ int leg;
+ int gateId;
+
+ void createPushBack(bool, FGAirport*, double, double, double, string, string, string);
+ void createTaxi(bool, int, FGAirport *, double, string, string, string);
+ void createTakeOff(bool, FGAirport *, double);
+ void createClimb(bool, FGAirport *, double, double);
+ void createCruise(bool, FGAirport*, FGAirport*, double, double, double, double);
+ void createDecent(FGAirport *);
+ void createLanding(FGAirport *);
+ void createParking(FGAirport *);
+ void deleteWaypoints();
+ void resetWaypoints();
};
--- /dev/null
+/******************************************************************************
+ * AIFlightPlanCreate.cxx
+ * Written by Durk Talsma, started May, 2004.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+#include <AIFlightPlan.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <Airports/runways.hxx>
+
+#include <Environment/environment_mgr.hxx>
+#include <Environment/environment.hxx>
+
+
+/* FGAIFlightPlan::create()
+ * dynamically create a flight plan for AI traffic, based on data provided by the
+ * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10)
+ *
+ * This is the top-level function, and the only one that publicly available.
+ *
+ */
+
+
+// Check lat/lon values during initialization;
+void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, int legNr, double alt, double speed,
+ double latitude, double longitude, bool firstFlight,
+ double radius, string fltType, string aircraftType, string airline)
+{
+ int currWpt = wpt_iterator - waypoints.begin();
+ switch(legNr)
+ {
+ case 1:
+ //cerr << "Creating Push_Back" << endl;
+ createPushBack(firstFlight,dep, latitude, longitude, radius, fltType, aircraftType, airline);
+ //cerr << "Done" << endl;
+ break;
+ case 2:
+ //cerr << "Creating Taxi" << endl;
+ createTaxi(firstFlight, 1, dep, radius, fltType, aircraftType, airline);
+ break;
+ case 3:
+ //cerr << "Creating TAkeoff" << endl;
+ createTakeOff(firstFlight, dep, speed);
+ break;
+ case 4:
+ //cerr << "Creating Climb" << endl;
+ createClimb(firstFlight, dep, speed, alt);
+ break;
+ case 5:
+ //cerr << "Creating Cruise" << endl;
+ createCruise(firstFlight, dep,arr, latitude, longitude, speed, alt);
+ break;
+ case 6:
+ //cerr << "Creating Decent" << endl;
+ createDecent(arr);
+ break;
+ case 7:
+ //cerr << "Creating Landing" << endl;
+ createLanding(arr);
+ break;
+ case 8:
+ //cerr << "Creating Taxi 2" << endl;
+ createTaxi(false, 2, arr, radius, fltType, aircraftType, airline);
+ break;
+ case 9:
+ //cerr << "Creating Parking" << endl;
+ createParking(arr);
+ break;
+ default:
+ //exit(1);
+ cerr << "Unknown case: " << legNr << endl;
+ }
+ wpt_iterator = waypoints.begin()+currWpt;
+ leg++;
+}
+
+/*******************************************************************
+ * createPushBack
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep,
+ double latitude,
+ double longitude,
+ double radius,
+ string fltType,
+ string aircraftType,
+ string airline)
+{
+ double heading;
+ double lat;
+ double lon;
+ double lat2;
+ double lon2;
+ double az2;
+
+ //int currWpt = wpt_iterator - waypoints.begin();
+ // Erase all existing waypoints.
+ //resetWaypoints();
+
+ // We only need to get a valid parking if this is the first leg.
+ // Otherwise use the current aircraft position.
+ if (firstFlight)
+ {
+ if (!(dep->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, aircraftType, airline)))
+ {
+ cerr << "Could not find parking " << endl;
+ }
+ }
+ else
+ {
+ dep->getParking(gateId, &lat, &lon, &heading);
+ //lat = latitude;
+ //lon = longitude;
+ //heading = getHeading();
+ }
+ heading += 180.0;
+ if (heading > 360)
+ heading -= 360;
+ waypoint *wpt = new waypoint;
+ wpt->name = "park";
+ wpt->latitude = lat;
+ wpt->longitude = lon;
+ wpt->altitude = dep->getElevation();
+ wpt->speed = -10;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+
+ // Add park twice, because it uses park once for initialization and once
+ // to trigger the departure ATC message
+ geo_direct_wgs_84 ( 0, lat, lon, heading,
+ 10,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "park2";
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = dep->getElevation();
+ wpt->speed = -10;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+ geo_direct_wgs_84 ( 0, lat, lon, heading,
+ 100,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "taxiStart";
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = dep->getElevation();
+ wpt->speed = 10;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+
+ //wpt = new waypoint;
+ //wpt->name = "END";
+ //wpt->finished = false;
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ //wpt_iterator = waypoints.begin();
+ //if (!firstFlight)
+ // wpt_iterator++;
+ //wpt_iterator = waypoints.begin()+currWpt;
+}
+
+/*******************************************************************
+ * createCreate Taxi.
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, double radius, string fltType, string acType, string airline)
+{
+ double wind_speed;
+ double wind_heading;
+ double heading;
+ //FGRunway rwy;
+ double lat, lon, az;
+ double lat2, lon2, az2;
+ //int direction;
+ waypoint *wpt;
+
+ // Erase all existing waypoints.
+ // wpt_vector_iterator i= waypoints.begin();
+ //resetWaypoints();
+ //int currWpt = wpt_iterator - waypoints.begin();
+ if (direction == 1)
+ {
+
+
+
+
+ // 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
+ //FGEnvironment
+ //stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
+ //->getEnvironment(apt->getLatitude(), apt->getLongitude(), apt->getElevation());
+
+ //wind_speed = stationweather.get_wind_speed_kt();
+ //wind_heading = stationweather.get_wind_from_heading_deg();
+ //if (wind_speed == 0) {
+ //wind_heading = 270; // This forces West-facing rwys to be used in no-wind situations
+ // which is consistent with Flightgear's initial setup.
+ //}
+
+ //string rwy_no = globals->get_runways()->search(apt->getId(), int(wind_heading));
+ string name;
+ apt->getActiveRunway("com", 1, &name);
+ if (!(globals->get_runways()->search(apt->getId(),
+ name,
+ &rwy)))
+ {
+ cout << "Failed to find runway for " << apt->getId() << endl;
+ // Hmm, how do we handle a potential error like this?
+ exit(1);
+ }
+ //string test;
+ //apt->getActiveRunway(string("com"), 1, &test);
+ //exit(1);
+
+ heading = rwy._heading;
+ double azimuth = heading + 180.0;
+ while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
+ &lat2, &lon2, &az2 );
+
+ //Add the runway startpoint;
+ wpt = new waypoint;
+ wpt->name = "Airport Center";
+ wpt->latitude = apt->getLatitude();
+ wpt->longitude = apt->getLongitude();
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 15;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+
+ //Add the runway startpoint;
+ wpt = new waypoint;
+ wpt->name = "Runway Takeoff";
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 15;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+ //wpt = new waypoint;
+ //wpt->finished = false;
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ }
+ else
+ {
+ //direction = (rand() % 360);
+ //geo_direct_wgs_84 ( 0, arr->getLatitude(), arr->getLongitude(), direction,
+ //100,
+ //&lat2, &lon2, &az2 );
+
+ // This next statement really requires the flight plan to be
+ // split up into smaller sections, because
+ // gate assignments will typically not be known until minutes before
+ // landing, and certainly not at the start of a 10 hour flight.
+ apt->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, acType, airline);
+ heading += 180.0;
+ if (heading > 360)
+ heading -= 360;
+ geo_direct_wgs_84 ( 0, lat, lon, heading,
+ 100,
+ &lat2, &lon2, &az2 );
+ //Add the runway center
+ wpt = new waypoint;
+ wpt->name = "Airport Center";
+ wpt->latitude = apt->getLatitude();
+ wpt->longitude = apt->getLongitude();
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 15;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+
+ // Add the final destination waypoint
+ wpt = new waypoint;
+ wpt->name = "Begin Parkingg"; //apt->getId(); //wpt_node->getStringValue("name", "END");
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 15;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+
+
+ }
+ // wpt_iterator = waypoints.begin();
+ //if (!firstFlight)
+ // wpt_iterator++;
+ //wpt_iterator = waypoints.begin()+currWpt;
+}
+
+/*******************************************************************
+ * CreateTakeOff
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double speed)
+{
+ double wind_speed;
+ double wind_heading;
+ double heading;
+ //FGRunway rwy;
+ double lat, lon, az;
+ double lat2, lon2, az2;
+ //int direction;
+ waypoint *wpt;
+
+
+ // Erase all existing waypoints.
+ // wpt_vector_iterator i= waypoints.begin();
+ //while(waypoints.begin() != waypoints.end())
+ // {
+ // delete *(i);
+ // waypoints.erase(i);
+ // }
+ //resetWaypoints();
+
+
+ // 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
+ if (firstFlight)
+ {
+ string name;
+ apt->getActiveRunway("com", 1, &name);
+ if (!(globals->get_runways()->search(apt->getId(),
+ name,
+ &rwy)))
+ {
+ cout << "Failed to find runway for " << apt->getId() << endl;
+ // Hmm, how do we handle a potential error like this?
+ exit(1);
+ }
+ //string test;
+ //apt->getActiveRunway(string("com"), 1, &test);
+ //exit(1);
+ }
+
+ heading = rwy._heading;
+ double azimuth = heading + 180.0;
+ while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ rwy._length * SG_FEET_TO_METER * 0.5 - 105.0,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "accel";
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = apt->getElevation();
+ wpt->speed = speed;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+
+ lat = lat2;
+ lon = lon2;
+ az = az2;
+
+ //Next: the Start of Climb
+ geo_direct_wgs_84 ( 0, lat, lon, heading,
+ 2560 * SG_FEET_TO_METER,
+ &lat2, &lon2, &az2 );
+
+ wpt = new waypoint;
+ wpt->name = "SOC";
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = apt->getElevation()+3000;
+ wpt->speed = speed;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = false;
+ waypoints.push_back(wpt);
+ // waypoints.push_back(wpt);
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ // wpt_iterator = waypoints.begin();
+ //if (!firstFlight)
+ // wpt_iterator++;
+}
+
+/*******************************************************************
+ * CreateClimb
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, double alt)
+{
+ double wind_speed;
+ double wind_heading;
+ double heading;
+ //FGRunway rwy;
+ double lat, lon, az;
+ double lat2, lon2, az2;
+ //int direction;
+ waypoint *wpt;
+
+ // Erase all existing waypoints.
+ // wpt_vector_iterator i= waypoints.begin();
+ //while(waypoints.begin() != waypoints.end())
+ // {
+ // delete *(i);
+ // waypoints.erase(i);
+ // }
+ //resetWaypoints();
+
+
+ // 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
+ if (firstFlight)
+ {
+ string name;
+ apt->getActiveRunway("com", 1, &name);
+ if (!(globals->get_runways()->search(apt->getId(),
+ name,
+ &rwy)))
+ {
+ cout << "Failed to find runway for " << apt->getId() << endl;
+ // Hmm, how do we handle a potential error like this?
+ exit(1);
+ }
+ //string test;
+ //apt->getActiveRunway(string("com"), 1, &test);
+ //exit(1);
+ }
+
+
+ heading = rwy._heading;
+ double azimuth = heading + 180.0;
+ while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
+ 10*SG_NM_TO_METER,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "10000ft climb";
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = 10000;
+ wpt->speed = speed;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = false;
+ waypoints.push_back(wpt);
+
+
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
+ 20*SG_NM_TO_METER,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "18000ft climb";
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = 18000;
+ wpt->speed = speed;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = false;
+ waypoints.push_back(wpt);
+ //waypoints.push_back(wpt);
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ // wpt_iterator = waypoints.begin();
+ //if (!firstFlight)
+ // wpt_iterator++;
+}
+
+
+/*******************************************************************
+ * CreateCruise
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, FGAirport *arr, double latitude, double longitude, double speed, double alt)
+{
+ double wind_speed;
+ double wind_heading;
+ double heading;
+ //FGRunway rwy;
+ double lat, lon, az;
+ double lat2, lon2, az2;
+ double azimuth;
+ //int direction;
+ waypoint *wpt;
+
+ // Erase all existing waypoints.
+ // wpt_vector_iterator i= waypoints.begin();
+ //while(waypoints.begin() != waypoints.end())
+ // {
+ // delete *(i);
+ // waypoints.erase(i);
+ // }
+ //resetWaypoints();
+
+ wpt = new waypoint;
+ wpt->name = "Cruise"; //wpt_node->getStringValue("name", "END");
+ wpt->latitude = latitude;
+ wpt->longitude = longitude;
+ wpt->altitude = alt;
+ wpt->speed = speed;
+ wpt->crossat = -10000;
+ wpt->gear_down = false;
+ wpt->flaps_down= false;
+ wpt->finished = false;
+ wpt->on_ground = false;
+ waypoints.push_back(wpt);
+ //Beginning of Decent
+
+ string name;
+ arr->getActiveRunway("com", 2, &name);
+ if (!(globals->get_runways()->search(arr->getId(),
+ name,
+ &rwy)))
+ {
+ cout << "Failed to find runway for " << arr->getId() << endl;
+ // Hmm, how do we handle a potential error like this?
+ exit(1);
+ }
+ //string test;
+ //arr->getActiveRunway(string("com"), 1, &test);
+ //exit(1);
+
+ //cerr << "Altitude = " << alt << endl;
+ //cerr << "Done" << endl;
+ //if (arr->getId() == "EHAM")
+ // {
+ // cerr << "Creating cruise to EHAM " << latitude << " " << longitude << endl;
+ // }
+ heading = rwy._heading;
+ azimuth = heading + 180.0;
+ while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+
+
+ // Note: This places us at the location of the active
+ // runway during initial cruise. This needs to be
+ // fixed later.
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ 110000,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "BOD"; //wpt_node->getStringValue("name", "END");
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = alt;
+ wpt->speed = speed;
+ wpt->crossat = alt;
+ wpt->gear_down = false;
+ wpt->flaps_down= false;
+ wpt->finished = false;
+ wpt->on_ground = false;
+ waypoints.push_back(wpt);
+ //waypoints.push_back(wpt);
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ //wpt_iterator = waypoints.begin();
+ //if (!firstFlight)
+ // wpt_iterator++;
+}
+
+/*******************************************************************
+ * CreateDecent
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createDecent(FGAirport *apt)
+{
+
+ // Ten thousand ft. Slowing down to 240 kts
+ double wind_speed;
+ double wind_heading;
+ double heading;
+ //FGRunway rwy;
+ double lat, lon, az;
+ double lat2, lon2, az2;
+ double azimuth;
+ //int direction;
+ waypoint *wpt;
+
+ //// Erase all existing waypoints.
+ // wpt_vector_iterator i= waypoints.begin();
+ //while(waypoints.begin() != waypoints.end())
+ // {
+ // delete *(i);
+ // waypoints.erase(i);
+ // }
+ //resetWaypoints();
+
+ //Beginning of Decent
+ string name;
+ apt->getActiveRunway("com", 2, &name);
+ if (!(globals->get_runways()->search(apt->getId(),
+ name,
+ &rwy)))
+ {
+ cout << "Failed to find runway for " << apt->getId() << endl;
+ // Hmm, how do we handle a potential error like this?
+ exit(1);
+ }
+ //string test;
+ //apt->getActiveRunway(string("com"), 1, &test);
+ //exit(1);
+
+ //cerr << "Done" << endl;
+ heading = rwy._heading;
+ azimuth = heading + 180.0;
+ while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+
+
+
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ 100000,
+ &lat2, &lon2, &az2 );
+
+ wpt = new waypoint;
+ wpt->name = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 240;
+ wpt->crossat = 10000;
+ wpt->gear_down = false;
+ wpt->flaps_down= false;
+ wpt->finished = false;
+ wpt->on_ground = false;
+ waypoints.push_back(wpt);
+
+ // Three thousand ft. Slowing down to 160 kts
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ 8*SG_NM_TO_METER,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 160;
+ wpt->crossat = 3000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = false;
+ waypoints.push_back(wpt);
+ //waypoints.push_back(wpt);
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ //wpt_iterator = waypoints.begin();
+ //wpt_iterator++;
+ //if (apt->getId() == "EHAM")
+ // {
+ // cerr << "Created Decend to EHAM " << lat2 << " " << lon2 << ": Runway = " << rwy._rwy_no
+ // << "heading " << heading << endl;
+ // }
+}
+/*******************************************************************
+ * CreateLanding
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createLanding(FGAirport *apt)
+{
+ // Ten thousand ft. Slowing down to 240 kts
+ double wind_speed;
+ double wind_heading;
+ double heading;
+ //FGRunway rwy;
+ double lat, lon, az;
+ double lat2, lon2, az2;
+ double azimuth;
+ //int direction;
+ waypoint *wpt;
+
+
+ heading = rwy._heading;
+ azimuth = heading + 180.0;
+ while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+
+ //Runway Threshold
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ rwy._length*0.45 * SG_FEET_TO_METER,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "Threshold"; //wpt_node->getStringValue("name", "END");
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 150;
+ wpt->crossat = apt->getElevation();
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+
+ //Full stop at the runway centerpoint
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ rwy._length*0.45,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "Center"; //wpt_node->getStringValue("name", "END");
+ wpt->latitude = rwy._lat;
+ wpt->longitude = rwy._lon;
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 30;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
+ rwy._length*0.45 * SG_FEET_TO_METER,
+ &lat2, &lon2, &az2 );
+ wpt = new waypoint;
+ wpt->name = "Threshold"; //wpt_node->getStringValue("name", "END");
+ wpt->latitude = lat2;
+ wpt->longitude = lon2;
+ wpt->altitude = apt->getElevation();
+ wpt->speed = 15;
+ wpt->crossat = apt->getElevation();
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+ //waypoints.push_back(wpt);
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ //wpt_iterator = waypoints.begin();
+ //wpt_iterator++;
+
+ //if (apt->getId() == "EHAM")
+ //{
+ // cerr << "Created Landing to EHAM " << lat2 << " " << lon2 << ": Runway = " << rwy._rwy_no
+ // << "heading " << heading << endl;
+ //}
+}
+
+/*******************************************************************
+ * CreateParking
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createParking(FGAirport *apt)
+{
+ waypoint* wpt;
+ double lat;
+ double lon;
+ double heading;
+ apt->getParking(gateId, &lat, &lon, &heading);
+ heading += 180.0;
+ if (heading > 360)
+ heading -= 360;
+
+ // Erase all existing waypoints.
+ // wpt_vector_iterator i= waypoints.begin();
+ //while(waypoints.begin() != waypoints.end())
+ // {
+ // delete *(i);
+ // waypoints.erase(i);
+ // }
+ //resetWaypoints();
+ // And finally one more named "END"
+ wpt = new waypoint;
+ wpt->name = "END"; //wpt_node->getStringValue("name", "END");
+ wpt->latitude = lat;
+ wpt->longitude = lon;
+ wpt->altitude = 19;
+ wpt->speed = 15;
+ wpt->crossat = -10000;
+ wpt->gear_down = true;
+ wpt->flaps_down= true;
+ wpt->finished = false;
+ wpt->on_ground = true;
+ waypoints.push_back(wpt);
+ //waypoints.push_back(wpt);
+ //waypoints.push_back(wpt); // add one more to prevent a segfault.
+ //wpt_iterator = waypoints.begin();
+ //wpt_iterator++;
+}
} else {
ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]);
}
+ ai_plane->setAcType(entity->acType);
+ ai_plane->setCompany(entity->company);
ai_plane->setHeading(entity->heading);
ai_plane->setSpeed(entity->speed);
ai_plane->setPath(entity->path.c_str());
AIBallistic.hxx AIBallistic.cxx \
AIStorm.hxx AIStorm.cxx \
AIThermal.hxx AIThermal.cxx \
- AIFlightPlan.hxx AIFlightPlan.cxx \
+ AIFlightPlan.hxx AIFlightPlan.cxx AIFlightPlanCreate.cxx \
AIScenario.hxx AIScenario.cxx \
AICarrier.hxx AICarrier.cxx
f_ident = file.substr(0, pos);
FGAirport a;
if(dclFindAirportID(f_ident, &a)) {
- SGBucket sgb(a._longitude, a._latitude);
+ SGBucket sgb(a.getLongitude(), a.getLatitude());
int idx = sgb.gen_index();
if(facilities.find(idx) != facilities.end()) {
facilities[idx]->push_back(f_ident);
FGAirport a;
if ( dclFindAirportID( ident, &a ) ) {
comm_list_type stations;
- int found = current_commlist->FindByPos(a._longitude, a._latitude, a._elevation, 20.0, &stations);
+ int found = current_commlist->FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 20.0, &stations);
if(found) {
ostringstream ostr;
comm_list_iterator itr = stations.begin();
//cout << "ident = " << ident << '\n';
AirportATC *a = new AirportATC;
// I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway!
- a->lon = ap._longitude;
- a->lat = ap._latitude;
- a->elev = ap._elevation;
+ a->lon = ap.getLongitude();
+ a->lat = ap.getLatitude();
+ a->elev = ap.getElevation();
a->atis_freq = GetFrequency(ident, ATIS);
//cout << "ATIS freq = " << a->atis_freq << '\n';
a->atis_active = false;
if(dclFindAirportID(ident, &ap)) {
AirportATC *a = new AirportATC;
// I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway!
- a->lon = ap._longitude;
- a->lat = ap._latitude;
- a->elev = ap._elevation;
+ a->lon = ap.getLongitude();
+ a->lat = ap.getLatitude();
+ a->elev = ap.getElevation();
a->atis_freq = GetFrequency(ident, ATIS);
a->atis_active = false;
a->tower_freq = GetFrequency(ident, TOWER);
SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id );
result = globals->get_airports()->search( id );
- if ( result._id.empty() ) {
+ if ( result.getId().empty() ) {
SG_LOG( SG_GENERAL, SG_WARN,
"Failed to find " << id << " in basic.dat.gz" );
return false;
SG_LOG( SG_GENERAL, SG_INFO,
"Position for " << id << " is ("
- << a->_longitude << ", "
- << a->_latitude << ")" );
+ << a->getLongitude() << ", "
+ << a->getLatitude() << ")" );
return true;
}
"Finding elevation for airport: " << id );
if ( dclFindAirportID( id, &a ) ) {
- return a._elevation * SG_FEET_TO_METER;
+ return a.getElevation() * SG_FEET_TO_METER;
} else {
return -9999.0;
}
"Finding position for airport: " << id );
if ( dclFindAirportID( id, &a ) ) {
- return Point3D(a._longitude, a._latitude, a._elevation);
+ return Point3D(a.getLongitude(), a.getLatitude(), a.getElevation());
} else {
return Point3D(0.0, 0.0, -9999.0);
}
FGAirport a;
if ( dclFindAirportID( ICAO, &a ) ) {
comm_list_type stations;
- int found = FindByPos(a._longitude, a._latitude, a._elevation, 10.0, &stations, tp);
+ int found = FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 10.0, &stations, tp);
if(found) {
comm_list_iterator itr = stations.begin();
while(itr != stations.end()) {
if ( ident == "#" || ident == "//" ) {
metar_in >> skipeol;
} else {
- FGAirport a = airports->search( ident );
- if ( a._id == ident ) {
+ const FGAirport &a = airports->search( ident );
+ if ( a.getId() == ident ) {
airports->has_metar( ident );
}
}
// elevation in feet.
//
// Written by Curtis Olson, started April 1998.
+// Updated by Durk Talsma, started December, 2004.
//
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
#include <math.h>
#include <simgear/compiler.h>
-
+#include <Environment/environment_mgr.hxx>
+#include <Environment/environment.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/debug/logstream.hxx>
+#include <Main/globals.hxx>
+#include <Main/fg_props.hxx>
+#include <Airports/runways.hxx>
#include STL_STRING
SG_USING_NAMESPACE(std);
+/******************************************************************************
+ * ScheduleTime
+ ***************e*************************************************************/
+void ScheduleTime::clear()
+{
+ start.clear();
+ end.clear();
+ scheduleNames.clear();
+}
+
+
+ScheduleTime::ScheduleTime(const ScheduleTime &other)
+{
+ //timeVec start;
+ timeVecConstIterator i;
+ for (i = other.start.begin(); i != other.start.end(); i++)
+ start.push_back(*i);
+ for (i = other.end.begin(); i != other.end.end(); i++)
+ end.push_back(*i);
+ stringVecConstIterator k;
+ for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
+ scheduleNames.push_back(*k);
+
+ //timeVec end;
+ //stringVec scheduleNames;
+ tailWind = other.tailWind;
+ crssWind = other.tailWind;
+}
+
+
+ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
+{
+ //timeVec start;
+ clear();
+ timeVecConstIterator i;
+ for (i = other.start.begin(); i != other.start.end(); i++)
+ start.push_back(*i);
+ for (i = other.end.begin(); i != other.end.end(); i++)
+ end.push_back(*i);
+ stringVecConstIterator k;
+ for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
+ scheduleNames.push_back(*k);
+
+ //timeVec end;
+ //stringVec scheduleNames;
+ tailWind = other.tailWind;
+ crssWind = other.tailWind;
+ return *this;
+}
+string ScheduleTime::getName(time_t dayStart)
+{
+ if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
+ {
+ cerr << "Unable to parse schedule times" << endl;
+ exit(1);
+ }
+ else
+ {
+ int nrItems = start.size();
+ //cerr << "Nr of items to process: " << nrItems << endl;
+ if (nrItems > 0)
+ {
+ for (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(0);
+ }
+}
+/******************************************************************************
+ * RunwayList
+ *****************************************************************************/
+
+RunwayList::RunwayList(const RunwayList &other)
+{
+ type = other.type;
+ stringVecConstIterator i;
+ for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
+ preferredRunways.push_back(*i);
+}
+RunwayList& RunwayList::operator= (const RunwayList &other)
+{
+ type = other.type;
+ preferredRunways.clear();
+ stringVecConstIterator i;
+ for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
+ preferredRunways.push_back(*i);
+ return *this;
+}
+void RunwayList::set(string tp, string lst)
+{
+ //weekday = atoi(timeCopy.substr(0,1).c_str());
+ // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
+ // timeCopy = timeCopy.substr(2,timeCopy.length());
+ type = tp;
+ string rwys = lst;
+ string rwy;
+ while (rwys.find(",") != string::npos)
+ {
+ rwy = rwys.substr(0, rwys.find(",",0));
+ //cerr << "adding runway [" << rwy << "] to the list " << endl;
+ preferredRunways.push_back(rwy);
+ rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
+ while (rwys[0] == ' ')
+ rwys.erase(0, 1); // Erase any leading whitespaces.
+ //cerr << "Remaining runway list " << rwys;
+ }
+ preferredRunways.push_back(rwys);
+ //exit(1);
+}
+
+void RunwayList::clear()
+{
+ type = "";
+ preferredRunways.clear();
+}
+/****************************************************************************
+ *
+ ***************************************************************************/
+
+RunwayGroup::RunwayGroup(const RunwayGroup &other)
+{
+ 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;
+}
+
+void RunwayGroup::setActive(string aptId,
+ double windSpeed,
+ double windHeading,
+ double maxTail,
+ double maxCross)
+{
+
+ 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;
+
+ if (activeRwys > 0)
+ {
+ nrOfPreferences = rwyList[0].getRwyList()->size();
+ for (int i = 0; i < nrOfPreferences; i++)
+ {
+ bool validSelection = true;
+ for (int j = 0; j < activeRwys; j++)
+ {
+ //cerr << "I J " << i << " " << j << endl;
+ name = rwyList[j].getRwyList(i);
+ //cerr << "Name of Runway: " << name << endl;
+ if (globals->get_runways()->search( aptId,
+ name,
+ &rwy))
+ {
+ //cerr << "Succes" << endl;
+ hdgDiff = fabs(windHeading - rwy._heading);
+ //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 << endl;
+ //cerr << "Crosswnd : " << crossWind << endl;
+ if ((tailWind > maxTail) || (crossWind > maxCross))
+ validSelection = false;
+ }else {
+ cerr << "Failed to find runway " << name << " at " << aptId << endl;
+ exit(1);
+ }
+
+ }
+ if (validSelection)
+ {
+ //cerr << "Valid runay selection : " << i << endl;
+ nrActive = activeRwys;
+ active = i;
+ 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++)
+ {
+ //cerr << "I J " << i << " " << j << endl;
+ name = rwyList[choice[j]].getRwyList(i);
+ //cerr << "Name of Runway: " << name << endl;
+ if (globals->get_runways()->search( aptId,
+ name,
+ &rwy))
+ {
+ //cerr << "Succes" << endl;
+ hdgDiff = fabs(windHeading - rwy._heading);
+ //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 << endl;
+ //cerr << "Crosswnd : " << crossWind << endl;
+ if ((tailWind > maxTail) || (crossWind > maxCross))
+ validSelection = false;
+ }else {
+ cerr << "Failed to find runway " << name << " at " << aptId << endl;
+ exit(1);
+ }
+
+ }
+ if (validSelection)
+ {
+ //cerr << "Valid runay selection : " << i << endl;
+ active = i;
+ nrActive = 2;
+ return;
+ }
+ }
+ }
+ active = -1;
+ //RunwayListVectorIterator i; // = rwlist.begin();
+ //stringVecIterator j;
+ //for (i = rwyList.begin(); i != rwyList.end(); i++)
+ // {
+ // cerr << i->getType();
+ // for (j = i->getRwyList()->begin(); j != i->getRwyList()->end(); j++)
+ // {
+ // cerr << (*j);
+ // }
+ // cerr << endl;
+ // }
+ //for (int
+
+}
+
+void RunwayGroup::getActive(int i, string *name, string *type)
+{
+ if (i == -1)
+ {
+ return;
+ }
+ if (nrActive == 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()
+{
+ //cerr << "Running default Constructor" << endl;
+ initialized = false;
+}
+
+FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
+{
+ initialized = other.initialized;
+ value = other.value;
+ scheduleName = other.scheduleName;
+
+ comTimes = other.comTimes; // Commercial Traffic;
+ genTimes = other.genTimes; // General Aviation;
+ milTimes = other.milTimes; // Military Traffic;
+ currTimes= other.currTimes; // Needed for parsing;
+
+ rwyList = other.rwyList;
+ rwyGroup = other.rwyGroup;
+ PreferenceListConstIterator i;
+ for (i = other.preferences.begin(); i != other.preferences.end(); i++)
+ preferences.push_back(*i);
+}
+
+FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
+{
+ initialized = other.initialized;
+ value = other.value;
+ scheduleName = other.scheduleName;
+
+ comTimes = other.comTimes; // Commercial Traffic;
+ genTimes = other.genTimes; // General Aviation;
+ milTimes = other.milTimes; // Military Traffic;
+ currTimes= other.currTimes; // Needed for parsing;
+
+ rwyList = other.rwyList;
+ rwyGroup = other.rwyGroup;
+ 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;
+ }
+}
+
+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;
+}
+
+void FGRunwayPreference::startXML () {
+ // cout << "Start XML" << endl;
+}
+
+void FGRunwayPreference::endXML () {
+ cout << "End XML" << endl;
+}
+
+void FGRunwayPreference::startElement (const char * name, const XMLAttributes &atts) {
+ //cout << "StartElement " << name << endl;
+ value = string("");
+ if (!(strcmp(name, "wind"))) {
+ //cerr << "Will be processing Wind" << endl;
+ for (int i = 0; i < atts.size(); i++)
+ {
+ //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
+ //attname = atts.getName(i);
+ if (atts.getName(i) == string("tail")) {
+ //cerr << "Tail Wind = " << atts.getValue(i) << endl;
+ currTimes.setTailWind(atof(atts.getValue(i)));
+ }
+ if (atts.getName(i) == string("cross")) {
+ //cerr << "Cross Wind = " << atts.getValue(i) << endl;
+ currTimes.setCrossWind(atof(atts.getValue(i)));
+ }
+ }
+ }
+ if (!(strcmp(name, "time"))) {
+ //cerr << "Will be processing time" << endl;
+ for (int i = 0; i < atts.size(); i++)
+ {
+ if (atts.getName(i) == string("start")) {
+ //cerr << "Start Time = " << atts.getValue(i) << endl;
+ currTimes.addStartTime(processTime(atts.getValue(i)));
+ }
+ if (atts.getName(i) == string("end")) {
+ //cerr << "End time = " << atts.getValue(i) << endl;
+ currTimes.addEndTime(processTime(atts.getValue(i)));
+ }
+ if (atts.getName(i) == string("schedule")) {
+ //cerr << "Schedule Name = " << atts.getValue(i) << endl;
+ currTimes.addScheduleName(atts.getValue(i));
+ }
+ }
+ }
+ if (!(strcmp(name, "takeoff"))) {
+ rwyList.clear();
+ }
+ if (!(strcmp(name, "landing")))
+ {
+ rwyList.clear();
+ }
+ if (!(strcmp(name, "schedule"))) {
+ for (int i = 0; i < atts.size(); i++)
+ {
+ //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
+ //attname = atts.getName(i);
+ if (atts.getName(i) == string("name")) {
+ //cerr << "Schedule name = " << atts.getValue(i) << endl;
+ scheduleName = atts.getValue(i);
+ }
+ }
+ }
+}
+
+//based on a string containing hour and minute, return nr seconds since day start.
+time_t FGRunwayPreference::processTime(string tme)
+{
+ string hour = tme.substr(0, tme.find(":",0));
+ string minute = tme.substr(tme.find(":",0)+1, tme.length());
+
+ //cerr << "hour = " << hour << " Minute = " << minute << endl;
+ return (atoi(hour.c_str()) * 3600 + atoi(minute.c_str()) * 60);
+}
+
+void FGRunwayPreference::endElement (const char * name) {
+ //cout << "End element " << name << endl;
+ if (!(strcmp(name, "rwyuse"))) {
+ initialized = true;
+ }
+ if (!(strcmp(name, "com"))) { // Commercial Traffic
+ //cerr << "Setting time table for commerical traffic" << endl;
+ comTimes = currTimes;
+ currTimes.clear();
+ }
+ if (!(strcmp(name, "gen"))) { // General Aviation
+ //cerr << "Setting time table for general aviation" << endl;
+ genTimes = currTimes;
+ currTimes.clear();
+ }
+ if (!(strcmp(name, "mil"))) { // Military Traffic
+ //cerr << "Setting time table for military traffic" << endl;
+ genTimes = currTimes;
+ currTimes.clear();
+ }
+
+ if (!(strcmp(name, "takeoff"))) {
+ //cerr << "Adding takeoff: " << value << endl;
+ rwyList.set(name, value);
+ rwyGroup.add(rwyList);
+ }
+ if (!(strcmp(name, "landing"))) {
+ //cerr << "Adding landing: " << value << endl;
+ rwyList.set(name, value);
+ rwyGroup.add(rwyList);
+ }
+ if (!(strcmp(name, "schedule"))) {
+ //cerr << "Adding schedule" << scheduleName << endl;
+ rwyGroup.setName(scheduleName);
+ //rwyGroup.addRunways(rwyList);
+ preferences.push_back(rwyGroup);
+ rwyGroup.clear();
+ //exit(1);
+ }
+}
+
+void FGRunwayPreference::data (const char * s, int len) {
+ string token = string(s,len);
+ //cout << "Character data " << string(s,len) << endl;
+ //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
+ // value += token;
+ //else
+ // value = string("");
+ value += token;
+}
+
+void FGRunwayPreference::pi (const char * target, const char * data) {
+ //cout << "Processing instruction " << target << ' ' << data << endl;
+}
+
+void FGRunwayPreference::warning (const char * message, int line, int column) {
+ cout << "Warning: " << message << " (" << line << ',' << column << ')'
+ << endl;
+}
+
+void FGRunwayPreference::error (const char * message, int line, int column) {
+ cout << "Error: " << message << " (" << line << ',' << column << ')'
+ << endl;
+}
+
+/*********************************************************************************
+ * FGParking
+ ********************************************************************************/
+FGParking::FGParking(double lat,
+ double lon,
+ double hdg,
+ double rad,
+ int idx,
+ string name,
+ string tpe,
+ string codes)
+{
+ latitude = lat;
+ longitude = lon;
+ heading = hdg;
+ parkingName = name;
+ index = idx;
+ type = tpe;
+ airlineCodes = codes;
+}
+
+double FGParking::processPosition(string pos)
+{
+ string prefix;
+ string subs;
+ string degree;
+ string decimal;
+ int sign = 1;
+ double value;
+ subs = pos;
+ prefix= subs.substr(0,1);
+ if (prefix == string("S") || (prefix == string("W")))
+ sign = -1;
+ subs = subs.substr(1, subs.length());
+ degree = subs.substr(0, subs.find(" ",0));
+ decimal = subs.substr(subs.find(" ",0), subs.length());
+
+
+ //cerr << sign << " "<< degree << " " << decimal << endl;
+ value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0);
+ //cerr << value <<endl;
+ //exit(1);
+ return value;
+}
+
+/***************************************************************************
+ * FGAirport
+ ***************************************************************************/
+FGAirport::FGAirport() : _longitude(0), _latitude(0), _elevation(0)
+{
+ lastUpdate = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ avWindHeading [i] = 0;
+ avWindSpeed [i] = 0;
+ }
+}
+
+FGAirport::FGAirport(const FGAirport& other)
+{
+ _id = other._id;
+ _longitude = other._longitude;
+ _latitude = other._latitude;
+ _elevation = other._elevation;
+ _name = other._name;
+ _has_metar = other._has_metar;
+ for (FGParkingVecConstIterator i= other.parkings.begin(); i != other.parkings.end(); i++)
+ parkings.push_back(*(i));
+ rwyPrefs = other.rwyPrefs;
+ lastUpdate = other.lastUpdate;
+
+ stringVecConstIterator i;
+ for (i = other.landing.begin(); i != other.landing.end(); i++)
+ landing.push_back(*i);
+ for (i = other.takeoff.begin(); i != other.takeoff.end(); i++)
+ takeoff.push_back(*i);
+ lastUpdate = other.lastUpdate;
+ for (int i = 0; i < 10; i++)
+ {
+ avWindHeading [i] = other.avWindHeading[i];
+ avWindSpeed [i] = other.avWindSpeed [i];
+ }
+}
+
+FGAirport::FGAirport(string id, double lon, double lat, double elev, string name, bool has_metar)
+{
+ _id = id;
+ _longitude = lon;
+ _latitude = lat;
+ _elevation = elev;
+ _name = name;
+ _has_metar = has_metar;
+ lastUpdate = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ avWindHeading [i] = 0;
+ avWindSpeed [i] = 0;
+ }
+
+}
+
+bool FGAirport::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, string flType, string acType, string airline)
+{
+ bool found = false;
+ bool available = false;
+ //string gateType;
+
+ FGParkingVecIterator i;
+// if (flType == "cargo")
+// {
+// gateType = "RAMP_CARGO";
+// }
+// else if (flType == "ga")
+// {
+// gateType = "RAMP_GA";
+// }
+// else gateType = "GATE";
+
+ if (parkings.begin() == parkings.end())
+ {
+ //cerr << "Could not find parking spot at " << _id << endl;
+ *lat = _latitude;
+ *lon = _longitude;
+ *heading = 0;
+ found = true;
+ }
+ else
+ {
+ // First try finding a parking with a designated airline code
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++)
+ {
+ //cerr << "Gate Id: " << i->getIndex()
+ // << " Type : " << i->getType()
+ // << " Codes : " << i->getCodes()
+ // << " Radius: " << i->getRadius()
+ // << " Name : " << i->getName()
+ // << " Available: " << i->isAvailable() << endl;
+ available = true;
+ // Taken by another aircraft
+ if (!(i->isAvailable()))
+ {
+ available = false;
+ continue;
+ }
+ // No airline codes, so skip
+ if (i->getCodes().empty())
+ {
+ available = false;
+ continue;
+ }
+ else // Airline code doesn't match
+ if (i->getCodes().find(airline, 0) == string::npos)
+ {
+ available = false;
+ continue;
+ }
+ // Type doesn't match
+ if (i->getType() != flType)
+ {
+ available = false;
+ continue;
+ }
+ // too small
+ if (i->getRadius() < rad)
+ {
+ available = false;
+ continue;
+ }
+
+ if (available)
+ {
+ *lat = i->getLatitude ();
+ *lon = i->getLongitude();
+ *heading = i->getHeading ();
+ *gateId = i->getIndex ();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
+ // then try again for those without codes.
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++)
+ {
+ available = true;
+ if (!(i->isAvailable()))
+ {
+ available = false;
+ continue;
+ }
+ if (!(i->getCodes().empty()))
+ {
+ if ((i->getCodes().find(airline,0) == string::npos))
+ {
+ available = false;
+ continue;
+ }
+ }
+ if (i->getType() != flType)
+ {
+ available = false;
+ continue;
+ }
+
+ if (i->getRadius() < rad)
+ {
+ available = false;
+ continue;
+ }
+
+ if (available)
+ {
+ *lat = i->getLatitude ();
+ *lon = i->getLongitude();
+ *heading = i->getHeading ();
+ *gateId = i->getIndex ();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
+ // And finally once more if that didn't work. Now ignore the airline codes, as a last resort
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++)
+ {
+ available = true;
+ if (!(i->isAvailable()))
+ {
+ available = false;
+ continue;
+ }
+ if (i->getType() != flType)
+ {
+ available = false;
+ continue;
+ }
+
+ if (i->getRadius() < rad)
+ {
+ available = false;
+ continue;
+ }
+
+ if (available)
+ {
+ *lat = i->getLatitude ();
+ *lon = i->getLongitude();
+ *heading = i->getHeading ();
+ *gateId = i->getIndex ();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
+ }
+ if (!found)
+ {
+ //cerr << "Traffic overflow at" << _id
+ // << ". flType = " << flType
+ // << ". airline = " << airline
+ // << " Radius = " <<rad
+ // << endl;
+ *lat = _latitude;
+ *lon = _longitude;
+ *heading = 0;
+ *gateId = -1;
+ //exit(1);
+ }
+ return found;
+}
+
+void FGAirport::getParking (int id, double *lat, double* lon, double *heading)
+{
+ if (id < 0)
+ {
+ *lat = _latitude;
+ *lon = _longitude;
+ *heading = 0;
+ }
+ else
+ {
+ FGParkingVecIterator i = parkings.begin();
+ for (i = parkings.begin(); i != parkings.end(); i++)
+ {
+ if (id == i->getIndex())
+ {
+ *lat = i->getLatitude();
+ *lon = i->getLongitude();
+ *heading = i->getLongitude();
+ }
+ }
+ }
+}
+
+FGParking *FGAirport::getParking(int i)
+{
+ if (i < parkings.size())
+ return &(parkings[i]);
+ else
+ return 0;
+}
+string FGAirport::getParkingName(int i)
+{
+ if (i < parkings.size() && i >= 0)
+ return (parkings[i].getName());
+ else
+ return string("overflow");
+}
+void FGAirport::releaseParking(int id)
+{
+ if (id >= 0)
+ {
+
+ FGParkingVecIterator i = parkings.begin();
+ for (i = parkings.begin(); i != parkings.end(); i++)
+ {
+ if (id == i->getIndex())
+ {
+ i -> setAvailable(true);
+ }
+ }
+ }
+}
+
+void FGAirport::startXML () {
+ //cout << "Start XML" << endl;
+}
+
+void FGAirport::endXML () {
+ //cout << "End XML" << endl;
+}
+
+void FGAirport::startElement (const char * name, const XMLAttributes &atts) {
+ const char * attval;
+ FGParking park;
+ //cout << "Start element " << name << endl;
+ string attname;
+ string value;
+ string gateName;
+ string gateNumber;
+ string lat;
+ string lon;
+ if (name == string("Parking"))
+ {
+ for (int i = 0; i < atts.size(); i++)
+ {
+ //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
+ attname = atts.getName(i);
+ if (attname == string("index"))
+ park.setIndex(atoi(atts.getValue(i)));
+ else if (attname == string("type"))
+ park.setType(atts.getValue(i));
+ else if (attname == string("name"))
+ gateName = atts.getValue(i);
+ else if (attname == string("number"))
+ gateNumber = atts.getValue(i);
+ else if (attname == string("lat"))
+ park.setLatitude(atts.getValue(i));
+ else if (attname == string("lon"))
+ park.setLongitude(atts.getValue(i));
+ else if (attname == string("heading"))
+ park.setHeading(atof(atts.getValue(i)));
+ else if (attname == string("radius")) {
+ string radius = atts.getValue(i);
+ if (radius.find("M") != string::npos)
+ radius = radius.substr(0, radius.find("M",0));
+ //cerr << "Radius " << radius <<endl;
+ park.setRadius(atof(radius.c_str()));
+ }
+ else if (attname == string("airlineCodes"))
+ park.setCodes(atts.getValue(i));
+ }
+ park.setName((gateName+gateNumber));
+ parkings.push_back(park);
+ }
+ // sort by radius, in asending order, so that smaller gates are first in the list
+ sort(parkings.begin(), parkings.end());
+}
+
+void FGAirport::endElement (const char * name) {
+ //cout << "End element " << name << endl;
+
+}
+
+void FGAirport::data (const char * s, int len) {
+ string token = string(s,len);
+ //cout << "Character data " << string(s,len) << endl;
+ //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
+ //value += token;
+ //else
+ //value = string("");
+}
+
+void FGAirport::pi (const char * target, const char * data) {
+ //cout << "Processing instruction " << target << ' ' << data << endl;
+}
+
+void FGAirport::warning (const char * message, int line, int column) {
+ cout << "Warning: " << message << " (" << line << ',' << column << ')'
+ << endl;
+}
+
+void FGAirport::error (const char * message, int line, int column) {
+ cout << "Error: " << message << " (" << line << ',' << column << ')'
+ << endl;
+}
+
+void FGAirport::setRwyUse(FGRunwayPreference& ref)
+{
+ rwyPrefs = ref;
+ //cerr << "Exiting due to not implemented yet" << endl;
+ //exit(1);
+}
+void FGAirport::getActiveRunway(string trafficType, int action, string *runway)
+{
+ double windSpeed;
+ double windHeading;
+ double maxTail;
+ double maxCross;
+ string name;
+ string type;
+
+ if (!(rwyPrefs.available()))
+ {
+ chooseRunwayFallback(runway);
+ return; // generic fall back goes here
+ }
+ else
+ {
+ RunwayGroup *currRunwayGroup = 0;
+ int nrActiveRunways = 0;
+ time_t dayStart = fgGetLong("/sim/time/utc/day-seconds");
+ if (((dayStart - lastUpdate) > 600) || trafficType != prevTrafficType)
+ {
+ landing.clear();
+ 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();
+ double averageWindSpeed = 0;
+ double averageWindHeading = 0;
+ double cosHeading = 0;
+ double sinHeading = 0;
+ // Initialize at the beginning of the next day or startup
+ if ((lastUpdate == 0) || (dayStart < lastUpdate))
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ avWindHeading [i] = windHeading;
+ avWindSpeed [i] = windSpeed;
+ }
+ }
+ else
+ {
+ if (windSpeed != avWindSpeed[9]) // update if new metar data
+ {
+ // shift the running average
+ for (int i = 0; i < 9 ; i++)
+ {
+ avWindHeading[i] = avWindHeading[i+1];
+ avWindSpeed [i] = avWindSpeed [i+1];
+ }
+ }
+ avWindHeading[9] = windHeading;
+ avWindSpeed [9] = windSpeed;
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ averageWindSpeed += avWindSpeed [i];
+ //averageWindHeading += avWindHeading [i];
+ cosHeading += cos(avWindHeading[i] * SG_DEGREES_TO_RADIANS);
+ sinHeading += sin(avWindHeading[i] * SG_DEGREES_TO_RADIANS);
+ }
+ averageWindSpeed /= 10;
+ //averageWindHeading /= 10;
+ cosHeading /= 10;
+ sinHeading /= 10;
+ averageWindHeading = atan2(sinHeading, cosHeading) *SG_RADIANS_TO_DEGREES;
+ if (averageWindHeading < 0)
+ averageWindHeading += 360.0;
+ //cerr << "Wind Heading " << windHeading << " average " << averageWindHeading << endl;
+ //cerr << "Wind Speed " << windSpeed << " average " << averageWindSpeed << endl;
+ lastUpdate = dayStart;
+ //if (wind_speed == 0) {
+ // wind_heading = 270; This forces West-facing rwys to be used in no-wind situations
+ // which is consistent with Flightgear's initial setup.
+ //}
+
+ //string rwy_no = globals->get_runways()->search(apt->getId(), int(wind_heading));
+ string scheduleName;
+ //cerr << "finding active Runway for" << _id << endl;
+ //cerr << "Nr of seconds since day start << " << dayStart << endl;
+ ScheduleTime *currSched;
+ //cerr << "A"<< endl;
+ currSched = rwyPrefs.getSchedule(trafficType.c_str());
+ if (!(currSched))
+ return;
+ //cerr << "B"<< endl;
+ scheduleName = currSched->getName(dayStart);
+ maxTail = currSched->getTailWind ();
+ maxCross = currSched->getCrossWind ();
+ //cerr << "SChedule anme = " << scheduleName << endl;
+ if (scheduleName.empty())
+ return;
+ //cerr << "C"<< endl;
+ currRunwayGroup = rwyPrefs.getGroup(scheduleName);
+ //cerr << "D"<< endl;
+ if (!(currRunwayGroup))
+ return;
+ nrActiveRunways = currRunwayGroup->getNrActiveRunways();
+ //cerr << "Nr of Active Runways = " << nrActiveRunways << endl;
+ currRunwayGroup->setActive(_id, averageWindSpeed, averageWindHeading, maxTail, maxCross);
+ nrActiveRunways = currRunwayGroup->getNrActiveRunways();
+ for (int i = 0; i < nrActiveRunways; i++)
+ {
+ type = "unknown"; // initialize to something other than landing or takeoff
+ currRunwayGroup->getActive(i, &name, &type);
+ if (type == "landing")
+ {
+ landing.push_back(name);
+ //cerr << "Landing " << name << endl;
+ }
+ if (type == "takeoff")
+ {
+ takeoff.push_back(name);
+ //cerr << "takeoff " << name << endl;
+ }
+ }
+ }
+ if (action == 1) // takeoff
+ {
+ int nr = takeoff.size();
+ if (nr)
+ {
+ *runway = takeoff[(rand() % nr)];
+ }
+ else
+ { // Fallback
+ chooseRunwayFallback(runway);
+ }
+ }
+ if (action == 2) // landing
+ {
+ int nr = landing.size();
+ if (nr)
+ {
+ *runway = landing[(rand() % nr)];
+ }
+ else
+ { //fallback
+ chooseRunwayFallback(runway);
+ }
+ }
+
+ //*runway = globals->get_runways()->search(_id, int(windHeading));
+ //cerr << "Seleceted runway: " << *runway << endl;
+ }
+}
+
+void FGAirport::chooseRunwayFallback(string *runway)
+{
+ FGEnvironment
+ stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
+ ->getEnvironment(getLatitude(),
+ getLongitude(),
+ getElevation());
+
+ double windSpeed = stationweather.get_wind_speed_kt();
+ double windHeading = stationweather.get_wind_from_heading_deg();
+ if (windSpeed == 0) {
+ windHeading = 270; // This forces West-facing rwys to be used in no-wind situations
+ //which is consistent with Flightgear's initial setup.
+ }
+
+ *runway = globals->get_runways()->search(_id, int(windHeading));
+ return; // generic fall back goes here
+}
+
+/******************************************************************************
+ * FGAirportList
+ *****************************************************************************/
+
// add an entry to the list
void FGAirportList::add( const string id, const double longitude,
const double latitude, const double elevation,
const string name, const bool has_metar )
{
- FGAirport a;
- a._id = id;
- a._longitude = longitude;
- a._latitude = latitude;
- a._elevation = elevation;
- a._name = name;
- a._has_metar = has_metar;
- airports_by_id[a._id] = a;
- airports_array.push_back( &airports_by_id[a._id] );
+ FGRunwayPreference rwyPrefs;
+ FGAirport a(id, longitude, latitude, elevation, name, has_metar);
+ //a._id = id;
+ //a._longitude = longitude;
+ //a._latitude = latitude;
+ //a._elevation = elevation;
+ //a._name = name;
+ //a._has_metar = has_metar;
+ SGPath parkpath( globals->get_fg_root() );
+ parkpath.append( "/Airports/AI/" );
+ parkpath.append(id);
+ parkpath.append("parking.xml");
+
+ SGPath rwyPrefPath( globals->get_fg_root() );
+ rwyPrefPath.append( "/Airports/AI/" );
+ rwyPrefPath.append(id);
+ rwyPrefPath.append("rwyuse.xml");
+ if (parkpath.exists())
+ {
+ try {
+ readXML(parkpath.str(),a);
+ }
+ catch (const sg_exception &e) {
+ //cerr << "unable to read " << parkpath.str() << endl;
+ }
+ }
+ if (rwyPrefPath.exists())
+ {
+ try {
+ readXML(rwyPrefPath.str(), rwyPrefs);
+ a.setRwyUse(rwyPrefs);
+ }
+ catch (const sg_exception &e) {
+ //cerr << "unable to read " << rwyPrefPath.str() << endl;
+ //exit(1);
+ }
+ }
+
+ airports_by_id[a.getId()] = a;
+ // try and read in an auxilary file
+
+ airports_array.push_back( &airports_by_id[a.getId()] );
SG_LOG( SG_GENERAL, SG_BULK, "Adding " << id << " pos = " << longitude
<< ", " << latitude << " elev = " << elevation );
}
return airports_by_id[id];
}
+// search for the specified id and return a pointer
+FGAirport* FGAirportList::search( const string& id, FGAirport *result) {
+ FGAirport* retval = airports_by_id[id].getAddress();
+ //cerr << "Returning Airport of string " << id << " results in " << retval->getId();
+ return retval;
+}
// search for the airport nearest the specified position
FGAirport FGAirportList::search( double lon_deg, double lat_deg,
unsigned int i;
for ( i = 0; i < airports_array.size(); ++i ) {
// crude manhatten distance based on lat/lon difference
- double d = fabs(lon_deg - airports_array[i]->_longitude)
- + fabs(lat_deg - airports_array[i]->_latitude);
+ double d = fabs(lon_deg - airports_array[i]->getLongitude())
+ + fabs(lat_deg - airports_array[i]->getLatitude());
if ( d < min_dist ) {
- if ( !with_metar || (with_metar&&airports_array[i]->_has_metar) ) {
+ if ( !with_metar || (with_metar&&airports_array[i]->getMetar()) ) {
closest = i;
min_dist = d;
}
* Mark the specified airport record as not having metar
*/
void FGAirportList::no_metar( const string &id ) {
- airports_by_id[id]._has_metar = false;
+ airports_by_id[id].setMetar(false);
}
* Mark the specified airport record as (yes) having metar
*/
void FGAirportList::has_metar( const string &id ) {
- airports_by_id[id]._has_metar = true;
+ airports_by_id[id].setMetar(true);
}
// elevation in feet.
//
// Written by Curtis Olson, started April 1998.
+// Updated by Durk Talsma, started December 2004.
//
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
#endif
#include <simgear/compiler.h>
+#include <simgear/xml/easyxml.hxx>
#include STL_STRING
#include <map>
SG_USING_STD(map);
SG_USING_STD(vector);
+typedef vector<string> stringVec;
+typedef vector<string>::iterator stringVecIterator;
+typedef vector<string>::const_iterator stringVecConstIterator;
-struct FGAirport {
- string _id;
- double _longitude;
- double _latitude;
- double _elevation;
- string _code; // depricated and can be removed
- string _name;
- bool _has_metar;
+typedef vector<time_t> timeVec;
+typedef vector<time_t>::const_iterator timeVecConstIterator;
+/***************************************************************************/
+class ScheduleTime {
+private:
+ timeVec start;
+ timeVec end;
+ stringVec scheduleNames;
+ double tailWind;
+ double crssWind;
+public:
+ ScheduleTime() {};
+ ScheduleTime(const ScheduleTime &other);
+ ScheduleTime &operator= (const ScheduleTime &other);
+ string getName(time_t dayStart);
+
+ void clear();
+ void addStartTime(time_t time) { start.push_back(time); };
+ void addEndTime (time_t time) { end. push_back(time); };
+ void addScheduleName(string sched) { scheduleNames.push_back(sched); };
+ void setTailWind(double wnd) { tailWind = wnd; };
+ void setCrossWind(double wnd) { tailWind = wnd; };
+
+ double getTailWind() { return tailWind; };
+ double getCrossWind() { return crssWind; };
+};
+
+//typedef vector<ScheduleTime> ScheduleTimes;
+/*****************************************************************************/
+
+class RunwayList
+{
+private:
+ string type;
+ stringVec preferredRunways;
+public:
+ RunwayList() {};
+ RunwayList(const RunwayList &other);
+ RunwayList& operator= (const RunwayList &other);
+
+ void set(string, string);
+ void clear();
+
+ string getType() { return type; };
+ stringVec *getRwyList() { return &preferredRunways; };
+ string getRwyList(int j) { return preferredRunways[j]; };
+};
+
+typedef vector<RunwayList> RunwayListVec;
+typedef vector<RunwayList>::iterator RunwayListVectorIterator;
+typedef vector<RunwayList>::const_iterator RunwayListVecConstIterator;
+
+
+/*****************************************************************************/
+
+class RunwayGroup
+{
+private:
+ string name;
+ RunwayListVec rwyList;
+ int active;
+ //stringVec runwayNames;
+ int choice[2];
+ int nrActive;
+public:
+ RunwayGroup() {};
+ RunwayGroup(const RunwayGroup &other);
+ RunwayGroup &operator= (const RunwayGroup &other);
+
+ void setName(string nm) { name = nm; };
+ void add(RunwayList list) { rwyList.push_back(list);};
+ void setActive(string aptId, double windSpeed, double windHeading, double maxTail, double maxCross);
+
+ int getNrActiveRunways() { return nrActive;};
+ void getActive(int i, string *name, string *type);
+
+ string getName() { return name; };
+ void clear() { rwyList.clear(); };
+ //void add(string, string);
+};
+
+typedef vector<RunwayGroup> PreferenceList;
+typedef vector<RunwayGroup>::iterator PreferenceListIterator;
+typedef vector<RunwayGroup>::const_iterator PreferenceListConstIterator;
+/******************************************************************************/
- FGAirport() : _longitude(0), _latitude(0), _elevation(0) {}
+class FGRunwayPreference : public XMLVisitor {
+private:
+ string value;
+ string scheduleName;
+
+ ScheduleTime comTimes; // Commercial Traffic;
+ ScheduleTime genTimes; // General Aviation;
+ ScheduleTime milTimes; // Military Traffic;
+ ScheduleTime currTimes; // Needed for parsing;
+
+ RunwayList rwyList;
+ RunwayGroup rwyGroup;
+ PreferenceList preferences;
+
+ time_t processTime(string);
+ bool initialized;
+
+public:
+ FGRunwayPreference();
+ FGRunwayPreference(const FGRunwayPreference &other);
+
+ FGRunwayPreference & operator= (const FGRunwayPreference &other);
+ ScheduleTime *getSchedule(const char *trafficType);
+ RunwayGroup *getGroup(const string groupName);
+ bool available() { return initialized; };
+
+ // Some overloaded virtual XMLVisitor members
+ virtual void startXML ();
+ virtual void endXML ();
+ virtual void startElement (const char * name, const XMLAttributes &atts);
+ virtual void endElement (const char * name);
+ virtual void data (const char * s, int len);
+ virtual void pi (const char * target, const char * data);
+ virtual void warning (const char * message, int line, int column);
+ virtual void error (const char * message, int line, int column);
+};
+
+class FGParking {
+private:
+ double latitude;
+ double longitude;
+ double heading;
+ double radius;
+ int index;
+ string parkingName;
+ string type;
+ string airlineCodes;
+
+
+ bool available;
+
+ double processPosition(string pos);
+
+public:
+ FGParking() { available = true;};
+ //FGParking(FGParking &other);
+ FGParking(double lat,
+ double lon,
+ double hdg,
+ double rad,
+ int idx,
+ string name,
+ string tpe,
+ string codes);
+ void setLatitude (string lat) { latitude = processPosition(lat); };
+ void setLongitude(string lon) { longitude = processPosition(lon); };
+ void setHeading (double hdg) { heading = hdg; };
+ void setRadius (double rad) { radius = rad; };
+ void setIndex (int idx) { index = idx; };
+ void setName (string name) { parkingName = name; };
+ void setType (string tpe) { type = tpe; };
+ void setCodes (string codes){ airlineCodes= codes;};
+
+ bool isAvailable () { return available;};
+ void setAvailable(bool val) { available = val; };
+
+ double getLatitude () { return latitude; };
+ double getLongitude() { return longitude; };
+ double getHeading () { return heading; };
+ double getRadius () { return radius; };
+ int getIndex () { return index; };
+ string getType () { return type; };
+ string getCodes () { return airlineCodes;};
+ string getName () { return parkingName; };
+
+ bool operator< (const FGParking &other) const {return radius < other.radius; };
+};
+
+typedef vector<FGParking> FGParkingVec;
+typedef vector<FGParking>::iterator FGParkingVecIterator;
+typedef vector<FGParking>::const_iterator FGParkingVecConstIterator;
+
+
+class FGAirport : public XMLVisitor{
+private:
+ string _id;
+ double _longitude;
+ double _latitude;
+ double _elevation;
+ string _code; // depricated and can be removed
+ string _name;
+ bool _has_metar;
+ FGParkingVec parkings;
+ FGRunwayPreference rwyPrefs;
+
+ time_t lastUpdate;
+ string prevTrafficType;
+ stringVec landing;
+ stringVec takeoff;
+
+ // Experimental keep a running average of wind dir and speed to prevent
+ // Erratic runway changes.
+ // Note: I should add these to the copy constructor and assigment operator to be
+ // constistent
+ double avWindHeading [10];
+ double avWindSpeed [10];
+
+public:
+ FGAirport();
+ FGAirport(const FGAirport &other);
+ //operator= (FGAirport &other);
+ FGAirport(string id, double lon, double lat, double elev, string name, bool has_metar);
+ void getActiveRunway(string trafficType, int action, string *runway);
+ void chooseRunwayFallback(string *runway);
+ bool getAvailableParking(double *lat, double *lon, double *heading, int *gate, double rad, string fltype,
+ string acType, string airline);
+ void getParking (int id, double *lat, double* lon, double *heading);
+ FGParking *getParking(int i); // { if (i < parkings.size()) return parkings[i]; else return 0;};
+ void releaseParking(int id);
+ string getParkingName(int i);
+ const string getId() const { return _id;};
+ const string &getName() const { return _name;};
+ FGAirport *getAddress() { return this; };
+ double getLongitude() { return _longitude;};
+ double getLatitude() { return _latitude; };
+ double getElevation() { return _elevation;};
+ bool getMetar() { return _has_metar;};
+
+
+ void setId(string id) { _id = id;};
+ void setMetar(bool value) { _has_metar = value; };
+
+ void setRwyUse(FGRunwayPreference& ref);
+
+ // Some overloaded virtual XMLVisitor members
+ virtual void startXML ();
+ virtual void endXML ();
+ virtual void startElement (const char * name, const XMLAttributes &atts);
+ virtual void endElement (const char * name);
+ virtual void data (const char * s, int len);
+ virtual void pi (const char * target, const char * data);
+ virtual void warning (const char * message, int line, int column);
+ virtual void error (const char * message, int line, int column);
};
typedef map < string, FGAirport > airport_map;
// return station id's marked as having metar data.
FGAirport search( double lon_deg, double lat_deg, bool with_metar );
+ // search and return a pointer;
+ FGAirport* search( const string& id, FGAirport *result);
/**
* Return the number of airports in the list.
sprintf( NewTgtAirportId, "%s", TgtAptId.c_str() );
- SGWayPoint wp( a._longitude, a._latitude, alt,
+ SGWayPoint wp( a.getLongitude(), a.getLatitude(), alt,
SGWayPoint::WGS84, TgtAptId );
rm->add_waypoint( wp );
->search( longitude->getDoubleValue(),
latitude->getDoubleValue(),
true );
- FGMetarResult result = fetch_data( a._id );
+ FGMetarResult result = fetch_data( a.getId() );
if ( result.m != NULL ) {
- SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a._id);
+ SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.getId());
last_apt = a;
- _icao = a._id;
+ _icao = a.getId();
search_elapsed = 0.0;
fetch_elapsed = 0.0;
update_metar_properties( result.m );
} else {
// mark as no metar so it doesn't show up in subsequent
// searches.
- SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a._id );
- globals->get_airports()->no_metar( a._id );
+ SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a.getId() );
+ globals->get_airports()->no_metar( a.getId() );
}
}
}
->search( longitude->getDoubleValue(),
latitude->getDoubleValue(),
true );
- if ( last_apt._id != a._id
+ if ( last_apt.getId() != a.getId()
|| fetch_elapsed > same_station_interval_sec )
{
- SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a._id);
- request_queue.push( a._id );
+ SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.getId());
+ request_queue.push( a.getId() );
last_apt = a;
- _icao = a._id;
+ _icao = a.getId();
search_elapsed = 0.0;
fetch_elapsed = 0.0;
} else {
// fetch station elevation if exists
FGAirport a = globals->get_airports()->search( icao );
- station_elevation_ft = a._elevation;
+ station_elevation_ft = a.getElevation();
// fetch current metar data
try {
for (int i = 0; i < _nAirports; i++) {
const FGAirport *airport = _airports->getAirport(i);
snprintf(buf, 1023, "%s %s",
- airport->_id.c_str(),
- airport->_name.c_str());
+ airport->getId().c_str(),
+ airport->getName().c_str());
unsigned int buf_len = (strlen(buf) > 1023) ? 1023 : strlen(buf);
char *
AirportList::getListStringValue ()
{
- return (char *)_airports->getAirport(getListIntegerValue())->_id.c_str();
+ return (char *)_airports->getAirport(getListIntegerValue())->getId().c_str();
}
// end of AirportList.cxx
layout_test_LDADD = libGUI.a \
-lsgprops -lsgdebug -lsgstructure -lsgmisc -lsgxml \
- -lplibpw -lplibpu -lplibfnt -lplibul $(opengl_LIBS)
\ No newline at end of file
+ -lplibpw -lplibpu -lplibfnt -lplibul $(opengl_LIBS)
FGAirport a;
//cout << "Airport found" << endl;
a = globals->get_airports()->search(longitude_deg, latitude_deg, false);
- _wp1_ID_node->setStringValue(a._id.c_str());
- wp1_longitude_deg = a._longitude;
- wp1_latitude_deg = a._latitude;
- _wp1_name_node->setStringValue(a._name.c_str());
+ _wp1_ID_node->setStringValue(a.getId().c_str());
+ wp1_longitude_deg = a.getLongitude();
+ wp1_latitude_deg = a.getLatitude();
+ _wp1_name_node->setStringValue(a.getName().c_str());
_get_nearest_airport_node->setBoolValue(false);
- _last_wp1_ID = wp1_ID = a._id.c_str();
+ _last_wp1_ID = wp1_ID = a.getId().c_str();
}
// If the waypoint 0 ID has changed, try to find the new ID
if (waypont_type == "airport") {
FGAirport a;
a = globals->get_airports()->search( wp0_ID );
- if ( a._id == wp0_ID ) {
+ if ( a.getId() == wp0_ID ) {
//cout << "Airport found" << endl;
- wp0_longitude_deg = a._longitude;
- wp0_latitude_deg = a._latitude;
- _wp0_name_node->setStringValue(a._name.c_str());
+ wp0_longitude_deg = a.getLongitude();
+ wp0_latitude_deg = a.getLatitude();
+ _wp0_name_node->setStringValue(a.getName().c_str());
}
}
else if (waypont_type == "nav") {
if (waypont_type == "airport") {
FGAirport a;
a = globals->get_airports()->search( wp1_ID );
- if ( a._id == wp1_ID ) {
+ if ( a.getId() == wp1_ID ) {
//cout << "Airport found" << endl;
- wp1_longitude_deg = a._longitude;
- wp1_latitude_deg = a._latitude;
- _wp1_name_node->setStringValue(a._name.c_str());
+ wp1_longitude_deg = a.getLongitude();
+ wp1_latitude_deg = a.getLatitude();
+ _wp1_name_node->setStringValue(a.getName().c_str());
}
}
else if (waypont_type == "nav") {
result = globals->get_airports()->search( id );
- if ( result._id.empty() ) {
+ if ( result.getId().empty() ) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Failed to find " << id << " in basic.dat.gz" );
return false;
SG_LOG( SG_GENERAL, SG_INFO,
"Position for " << id << " is ("
- << a->_longitude << ", "
- << a->_latitude << ")" );
+ << a->getLongitude() << ", "
+ << a->getLatitude() << ")" );
return true;
}
"Finding elevation for airport: " << id );
if ( fgFindAirportID( id, &a ) ) {
- return a._elevation;
+ return a.getElevation();
} else {
return -9999.0;
}
float fudge_lat = .003f - fudge_lon;
if ( fgFindAirportID( id, &a ) ) {
- fgSetDouble("/sim/tower/longitude-deg", a._longitude + fudge_lon);
- fgSetDouble("/sim/tower/latitude-deg", a._latitude + fudge_lat);
- fgSetDouble("/sim/tower/altitude-ft", a._elevation + towerheight);
+ fgSetDouble("/sim/tower/longitude-deg", a.getLongitude() + fudge_lon);
+ fgSetDouble("/sim/tower/latitude-deg", a.getLatitude() + fudge_lat);
+ fgSetDouble("/sim/tower/altitude-ft", a.getElevation() + towerheight);
return true;
} else {
return false;
globals->add_subsystem("Traffic Manager", new FGTrafficManager);
FGTrafficManager *dispatcher =
(FGTrafficManager*) globals->get_subsystem("Traffic Manager");
- SGPath path =globals->get_fg_root();
- path.append("Traffic/fgtraffic.xml");
+ SGPath path = globals->get_fg_root();
+ path.append("/Traffic/fgtraffic.xml");
readXML(path.str(),
- *dispatcher);
- globals->get_subsystem("Traffic Manager")->init();
+ *dispatcher);
+ //globals->get_subsystem("Traffic Manager")->init();
globals->add_subsystem("instrumentation", new FGInstrumentMgr);
globals->add_subsystem("systems", new FGSystemMgr);
// cout << r->get_type() << " " << r->get_apt_id() << " zero elev"
// << endl;
FGAirport a = airports->search( r->get_apt_id() );
- if ( a._id == r->get_apt_id() ) {
- r->set_elev_ft( a._elevation );
+ if ( a.getId() == r->get_apt_id() ) {
+ r->set_elev_ft( a.getElevation() );
// cout << " setting to " << a.elevation << endl;
}
}
callsign = other.callsign;
fltRules = other.fltRules;
departurePort = other.departurePort;
+ depId = other.depId;
+ arrId = other.arrId;
departureTime = other.departureTime;
cruiseAltitude = other.cruiseAltitude;
arrivalPort = other.arrivalPort;
{
callsign = cs;
fltRules = fr;
- departurePort._id = depPrt;
- arrivalPort._id = arrPrt;
+ //departurePort.setId(depPrt);
+ //arrivalPort.setId(arrPrt);
+ depId = depPrt;
+ arrId = arrPrt;
+ //cerr << "Constructor: departure " << depId << ". arrival " << arrId << endl;
//departureTime = processTimeString(deptime);
//arrivalTime = processTimeString(arrtime);
cruiseAltitude = cruiseAlt;
{
initializeAirports();
}
- return &departurePort;
+ if (initialized)
+ return departurePort;
+ else
+ return 0;
}
FGAirport * FGScheduledFlight::getArrivalAirport ()
{
{
initializeAirports();
}
- return &arrivalPort;
+ if (initialized)
+ return arrivalPort;
+ else
+ return 0;
}
// Upon the first time of requesting airport information
// but we should improve that. The best idea is probably to cancel
// this flight entirely by removing it from the schedule, if one
// of the airports cannot be found.
-void FGScheduledFlight::initializeAirports()
+bool FGScheduledFlight::initializeAirports()
{
- if(!(fgFindAirportID(arrivalPort._id, &arrivalPort )))
+ //cerr << "Initializing using : " << depId << " " << arrId << endl;
+ departurePort = globals->get_airports()->search( depId, departurePort );
+ if(departurePort->getId().empty())
{
- //cerr << ": Could not find " << arrivalPort.id << endl;
+ cerr << "Could not find " << depId << endl;
+ return false;
}
- if(!(fgFindAirportID(departurePort._id, &departurePort)))
+ arrivalPort = globals->get_airports()->search(arrId, arrivalPort);
+ if(arrivalPort->getId().empty())
{
- //cerr << ": Could not find " << departurePort.id << endl;
+ cerr << "Could not find " << arrId << endl;
+ return false;
}
+
+ //cerr << "Found : " << departurePort->getId() << endl;
+ //cerr << "Found : " << arrivalPort->getId() << endl;
initialized = true;
+ return true;
}
private:
string callsign;
string fltRules;
- FGAirport departurePort;
- FGAirport arrivalPort;
+ FGAirport *departurePort;
+ FGAirport *arrivalPort;
+ string depId;
+ string arrId;
time_t departureTime;
time_t arrivalTime;
time_t repeatPeriod;
int cruiseAltitude;
bool initialized;
- void initializeAirports();
+
public:
FGScheduledFlight();
~FGScheduledFlight();
void update();
+ bool initializeAirports();
void adjustTime(time_t now);
};
time_t processTimeString(string time);
-
+ string getCallSign() {return callsign; };
};
typedef vector<FGScheduledFlight> FGScheduledFlightVec;
string liv,
string reg,
bool hvy,
+ string act,
+ string arln,
+ string mclass,
+ string fltpe,
+ double rad,
+ double grnd,
FGScheduledFlightVec flt)
{
modelPath = mdl;
livery = liv;
registration = reg;
+ acType = act;
+ airline = arln;
+ m_class = mclass;
+ flightType = fltpe;
+ radius = rad;
+ groundOffset = grnd;
heavy = hvy;
for (FGScheduledFlightVecIterator i = flt.begin();
i != flt.end();
lat = other.lat;
lon = other.lon;
AIManagerRef = other.AIManagerRef;
+ acType = other.acType;
+ airline = other.airline;
+ m_class = other.m_class;
firstRun = other.firstRun;
+ radius = other.radius;
+ groundOffset = other.groundOffset;
+ flightType = other.flightType;
+ distanceToUser = other.distanceToUser;
}
+
FGAISchedule::~FGAISchedule()
{
}
-void FGAISchedule::update(time_t now)
+bool FGAISchedule::init()
+{
+ //tm targetTimeDate;
+ //SGTime* currTimeDate = globals->get_time_params();
+
+ //tm *temp = currTimeDate->getGmt();
+ //char buffer[512];
+ //sgTimeFormatTime(&targetTimeDate, buffer);
+ //cout << "Scheduled Time " << buffer << endl;
+ //cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
+ for (FGScheduledFlightVecIterator i = flights.begin();
+ i != flights.end();
+ i++)
+ {
+ //i->adjustTime(now);
+ if (!(i->initializeAirports()))
+ return false;
+ }
+ //sort(flights.begin(), flights.end());
+ // Since time isn't initialized yet when this function is called,
+ // Find the closest possible airport.
+ // This should give a reasonable initialization order.
+ setClosestDistanceToUser();
+ return true;
+}
+
+bool FGAISchedule::update(time_t now)
{
FGAirport *dep;
FGAirport *arr;
string airport;
double courseToUser, courseToDest;
- double distanceToUser, distanceToDest;
+ double distanceToDest;
double speed;
Point3D temp;
userLongitude;
if (fgGetBool("/sim/traffic-manager/enabled") == false)
- return;
+ return true;
aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
// Before the flight status of this traffic entity is updated
if (firstRun)
{
for (FGScheduledFlightVecIterator i = flights.begin();
- i != flights.end();
- i++)
- {
- i->adjustTime(now);
- }
+ i != flights.end();
+ i++)
+ {
+ i->adjustTime(now);
+ }
firstRun = false;
}
userLatitude = fgGetDouble("/position/latitude-deg");
userLongitude = fgGetDouble("/position/longitude-deg");
-
+ //cerr << "Estimated minimum distance to user: " << distanceToUser << endl;
// This flight entry is entirely in the past, do we need to
// push it forward in time to the next scheduled departure.
if ((i->getDepartureTime() < now) && (i->getArrivalTime() < now))
{
i->update();
- return;
+ return true;
}
// Departure time in the past and arrival time in the future.
{
dep = i->getDepartureAirport();
arr = i->getArrivalAirport ();
+ if (!(dep && arr))
+ return false;
- temp = sgPolarToCart3d(Point3D(dep->_longitude *
+ temp = sgPolarToCart3d(Point3D(dep->getLongitude() *
SG_DEGREES_TO_RADIANS,
- dep->_latitude *
+ dep->getLatitude() *
SG_DEGREES_TO_RADIANS,
1.0));
a[0] = temp.x();
a[1] = temp.y();
a[2] = temp.z();
- temp = sgPolarToCart3d(Point3D(arr->_longitude *
+ temp = sgPolarToCart3d(Point3D(arr->getLongitude() *
SG_DEGREES_TO_RADIANS,
- arr->_latitude *
+ arr->getLatitude() *
SG_DEGREES_TO_RADIANS,
1.0));
b[0] = temp.x();
// total time enroute and elapsed time enroute.
totalTimeEnroute = i->getArrivalTime() - i->getDepartureTime();
- elapsedTimeEnroute = now - i->getDepartureTime();
- remainingTimeEnroute = i->getArrivalTime() - now;
-
+ if (now > i->getDepartureTime())
+ {
+ //err << "Lat = " << lat << ", lon = " << lon << endl;
+ //cerr << "Time diff: " << now-i->getDepartureTime() << endl;
+ elapsedTimeEnroute = now - i->getDepartureTime();
+ remainingTimeEnroute = i->getArrivalTime() - now;
+ }
+ else
+ {
+ lat = dep->getLatitude();
+ lon = dep->getLongitude();
+ elapsedTimeEnroute = 0;
+ remainingTimeEnroute = totalTimeEnroute;
+ }
+
angle *= ( (double) elapsedTimeEnroute/ (double) totalTimeEnroute);
newPos[j] += matrix[j][k]*a[k];
}
}
-
+
temp = sgCartToPolar3d(Point3D(newPos[0], newPos[1],newPos[2]));
-
if (now > i->getDepartureTime())
{
//cerr << "Lat = " << lat << ", lon = " << lon << endl;
//cerr << "Time diff: " << now-i->getDepartureTime() << endl;
lat = temp.lat() * SG_RADIANS_TO_DEGREES;
lon = temp.lon() * SG_RADIANS_TO_DEGREES;
- //err << "Lat = " << lat << ", lon = " << lon << endl;
- //cerr << "Time diff: " << now-i->getDepartureTime() << endl;
}
else
{
- lat = dep->_latitude;
- lon = dep->_longitude;
+ lat = dep->getLatitude();
+ lon = dep->getLongitude();
}
+
SGWayPoint current (lon,
lat,
i->getCruiseAlt());
SGWayPoint user ( userLongitude,
userLatitude,
i->getCruiseAlt());
- SGWayPoint dest ( arr->_longitude,
- arr->_latitude,
+ SGWayPoint dest ( arr->getLongitude(),
+ arr->getLatitude(),
i->getCruiseAlt());
// We really only need distance to user
// and course to destination
//cerr << registration << " is currently enroute from "
// << dep->_id << " to " << arr->_id << "distance : "
// << distanceToUser*SG_METER_TO_NM << endl;
- if ((distanceToUser*SG_METER_TO_NM) < 500.0)
+ if ((distanceToUser*SG_METER_TO_NM) < TRAFFICTOAIDIST)
{
- string flightPlanName = dep->_id + string("-") + arr->_id +
+ string flightPlanName = dep->getId() + string("-") + arr->getId() +
string(".xml");
int alt;
//if ((i->getDepartureTime() < now))
FGAIModelEntity entity;
- entity.m_class = "jet_transport";
+ entity.m_class = m_class; //"jet_transport";
+ entity.company = airline; //i->getAirline();
+ entity.acType = acType; //i->getAcType();
entity.path = modelPath.c_str();
entity.flightplan = flightPlanName.c_str();
entity.latitude = lat;
entity.longitude = lon;
entity.altitude = i->getCruiseAlt() *100; // convert from FL to feet
- entity.speed = 450;
- entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr);
-
+ entity.speed = speed;
+ entity.roll = 0.0;
+ entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep,
+ arr,true, radius, flightType, acType, airline);
+
// Fixme: A non-existent model path results in an
// abort, due to an unhandled exeption, in fg main loop.
AIManagerRef = aimgr->createAircraft( &entity, this);
- //cerr << "Created: " << AIManagerRef << endl;
+ //cerr << "Class: " << m_class << ". acType: " << acType << ". Airline: " << airline << ". Speed = " << speed << ". From " << dep->getId() << " to " << arr->getId() << ". Time Fraction = " << (remainingTimeEnroute/(double) totalTimeEnroute) << endl;
+ //cerr << "Latitude : " << lat << ". Longitude : " << lon << endl;
+ //cerr << "Dep : " << dep->getLatitude()<< ", "<< dep->getLongitude() << endl;
+ //cerr << "Arr : " << arr->getLatitude()<< ", "<< arr->getLongitude() << endl;
+ //cerr << "Time remaining = " << (remainingTimeEnroute/3600.0) << endl;
+ //cerr << "Total time = " << (totalTimeEnroute/3600.0) << endl;
+ //cerr << "Distance remaining = " << distanceToDest*SG_METER_TO_NM << endl;
+
}
- return;
- }
+ return true;
+ }
// Both departure and arrival time are in the future, so this
// the aircraft is parked at the departure airport.
// Currently this status is mostly ignored, but in future
// versions, code should go here that -if within user range-
// positions these aircraft at parking locations at the airport.
- if ((i->getDepartureTime() > now) && (i->getArrivalTime() > now))
+ if ((i->getDepartureTime() > now) && (i->getArrivalTime() > now))
{
dep = i->getDepartureAirport();
- return;
+ return true;
}
}
}
sort(flights.begin(), flights.end());
}
+double FGAISchedule::getSpeed()
+{
+ double courseToUser, courseToDest;
+ double distanceToUser, distanceToDest;
+ double speed, remainingTimeEnroute;
+ FGAirport *dep, *arr;
+
+ FGScheduledFlightVecIterator i = flights.begin();
+ dep = i->getDepartureAirport();
+ arr = i->getArrivalAirport ();
+ if (!(dep && arr))
+ return 0;
+
+ SGWayPoint dest ( dep->getLongitude(),
+ dep->getLatitude(),
+ i->getCruiseAlt());
+ SGWayPoint curr ( arr->getLongitude(),
+ arr->getLatitude(),
+ i->getCruiseAlt());
+ remainingTimeEnroute = i->getArrivalTime() - i->getDepartureTime();
+ dest.CourseAndDistance(curr, &courseToDest, &distanceToDest);
+ speed = (distanceToDest*SG_METER_TO_NM) /
+ ((double) remainingTimeEnroute/3600.0);
+ return speed;
+}
+
+
+void FGAISchedule::setClosestDistanceToUser()
+{
+
+
+ double course;
+ double dist;
+
+ Point3D temp;
+ time_t
+ totalTimeEnroute,
+ elapsedTimeEnroute;
+
+ double userLatitude = fgGetDouble("/position/latitude-deg");
+ double userLongitude = fgGetDouble("/position/longitude-deg");
+
+ FGAirport *dep;
+
+ distanceToUser = HUGE;
+ FGScheduledFlightVecIterator i = flights.begin();
+ while (i != flights.end())
+ {
+ dep = i->getDepartureAirport();
+ //if (!(dep))
+ //return HUGE;
+
+ SGWayPoint user ( userLongitude,
+ userLatitude,
+ i->getCruiseAlt());
+ SGWayPoint current (dep->getLongitude(),
+ dep->getLatitude(),
+ 0);
+ user.CourseAndDistance(current, &course, &dist);
+ if (dist < distanceToUser)
+ {
+ distanceToUser = dist;
+ //cerr << "Found closest distance to user for " << registration << " to be " << distanceToUser << " at airport " << dep->getId() << endl;
+ }
+ i++;
+ }
+ //return distToUser;
+}
#ifndef _FGSCHEDULE_HXX_
#define _FGSCHEDULE_HXX_
+#define TRAFFICTOAIDIST 150.0
class FGAISchedule
string modelPath;
string livery;
string registration;
+ string airline;
+ string acType;
+ string m_class;
+ string flightType;
bool heavy;
FGScheduledFlightVec flights;
float lat;
float lon;
+ double radius;
+ double groundOffset;
+ double distanceToUser;
void* AIManagerRef;
bool firstRun;
public:
FGAISchedule(); // constructor
- FGAISchedule(string, string, string, bool, FGScheduledFlightVec); // construct & init
+ FGAISchedule(string, string, string, bool, string, string, string, string, double, double, FGScheduledFlightVec); // construct & init
FGAISchedule(const FGAISchedule &other); // copy constructor
~FGAISchedule(); //destructor
- void update(time_t now);
+ bool update(time_t now);
+ bool init();
+
+ double getSpeed ();
+ void setClosestDistanceToUser();
void next(); // forces the schedule to move on to the next flight.
time_t getDepartureTime () { return flights.begin()->getDepartureTime (); };
FGAirport * getDepartureAirport () { return flights.begin()->getDepartureAirport(); };
FGAirport * getArrivalAirport () { return flights.begin()->getArrivalAirport (); };
int getCruiseAlt () { return flights.begin()->getCruiseAlt (); };
+ double getRadius () { return radius; };
+ double getGroundOffset () { return groundOffset;};
+ string getFlightType () { return flightType;};
+ string getAirline () { return airline; };
+ string getAircraft () { return acType; };
+ string getCallSign () { return flights.begin()->getCallSign (); };
+ string getRegistration () { return registration;};
+ bool getHeavy () { return heavy; };
+ bool operator< (const FGAISchedule &other) const { return (distanceToUser < other.distanceToUser); };
+ //void * getAiRef () { return AIManagerRef; };
+ //FGAISchedule* getAddress () { return this;};
// More member functions follow later
};
-typedef vector<FGAISchedule> ScheduleVector;
-typedef vector<FGAISchedule>::iterator ScheduleVectorIterator;
+typedef vector<FGAISchedule > ScheduleVector;
+typedef vector<FGAISchedule >::iterator ScheduleVectorIterator;
#endif
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/xml/easyxml.hxx>
+#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include <AIModel/AIBase.hxx>
#include <Airports/simple.hxx>
void FGTrafficManager::init()
-{
+{
+ //cerr << "Initializing Schedules" << endl;
+ time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+ currAircraft = scheduledAircraft.begin();
+ while (currAircraft != scheduledAircraft.end())
+ {
+ if (!(currAircraft->init()))
+ {
+ currAircraft=scheduledAircraft.erase(currAircraft);
+ //cerr << "Erasing " << currAircraft->getRegistration() << endl;
+ currAircraft--;
+ }
+ else
+ {
+ currAircraft++;
+ }
+ }
+ //cerr << "Sorting by distance " << endl;
+ sort(scheduledAircraft.begin(), scheduledAircraft.end());
currAircraft = scheduledAircraft.begin();
+ currAircraftClosest = scheduledAircraft.begin();
+ //cerr << "Done initializing schedules" << endl;
}
void FGTrafficManager::update(double something)
{
-
- //static const SGPropertyNode *warp = globals->get_props()->getNode("/sim/time/warp");
-
- //time_t now = time(NULL) + globals->get_warp();
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
- // cerr << "TrafficManager update" << globals->get_warp() << endl;
- if(currAircraft == scheduledAircraft.end())
+ if(currAircraft == scheduledAircraft.end())
+ {
+ //cerr << "resetting schedule " << endl;
currAircraft = scheduledAircraft.begin();
- currAircraft->update(now);
- currAircraft++;
+ }
+ if (!(currAircraft->update(now)))
+ {
+ // after proper initialization, we shouldnt get here.
+ // But let's make sure
+ cerr << "Failed to update aircraft schedule in traffic manager" << endl;
+ }
+ currAircraft++;
}
void FGTrafficManager::release(void *id)
livery = value;
else if (element == string("registration"))
registration = value;
+ else if (element == string("airline"))
+ airline = value;
+ else if (element == string("actype"))
+ acType = value;
+ else if (element == string("flighttype"))
+ flighttype = value;
+ else if (element == string("radius"))
+ radius = atoi(value.c_str());
+ else if (element == string("offset"))
+ offset = atoi(value.c_str());
+ else if (element == string("performance-class"))
+ m_class = value;
else if (element == string("heavy"))
{
if(value == string("true"))
{
//cerr << "Pushing back aircraft " << registration << endl;
scheduledAircraft.push_back(FGAISchedule(mdl,
- livery,
- registration,
- heavy,
- flights));
+ livery,
+ registration,
+ heavy,
+ acType,
+ airline,
+ m_class,
+ flighttype,
+ radius,
+ offset,
+ flights));
while(flights.begin() != flights.end())
flights.pop_back();
}
{
private:
ScheduleVector scheduledAircraft;
- ScheduleVectorIterator currAircraft;
+ ScheduleVectorIterator currAircraft, currAircraftClosest;
string value;
string mdl, livery, registration, callsign, fltrules,
port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
- repeat;
+ repeat, acType, airline, m_class, flighttype;
int cruiseAlt;
+ double radius, offset;
bool heavy;
IdList releaseList;