1
0
Fork 0

AI improved entry into parking (heading and postition)

This commit is contained in:
portree_kid 2022-02-13 20:34:17 +01:00
parent 49eeb6627c
commit b216658ba1

View file

@ -52,7 +52,7 @@ using std::string;
/* FGAIFlightPlan::create() /* FGAIFlightPlan::create()
* dynamically create a flight plan for AI traffic, based on data provided by the * dynamically create a flight plan for AI traffic, based on data provided by the
* Traffic Manager, when reading a filed flightplan fails. (DT, 2004/07/10) * Traffic Manager, when reading a filed flightplan fails. (DT, 2004/07/10)
* *
* This is the top-level function, and the only one that is publicly available. * This is the top-level function, and the only one that is publicly available.
* *
@ -68,11 +68,11 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
const string & aircraftType, const string & aircraftType,
const string & airline, double distance) const string & airline, double distance)
{ {
if( legNr <= 3 ) if( legNr <= 3 )
SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " At Airport : " << dep->getId()); SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " At Airport : " << dep->getId());
else if( legNr<= 6 ) else if( legNr<= 6 )
SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " Departure Airport : " << dep->getId() << " Arrival Airport : " << arr->getId()); SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " Departure Airport : " << dep->getId() << " Arrival Airport : " << arr->getId());
else else
SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " At Airport : " << arr->getId()); SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " At Airport : " << arr->getId());
bool retVal = true; bool retVal = true;
@ -107,7 +107,7 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
retVal = createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline); retVal = createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
break; break;
case 9: case 9:
retVal = createParking(ac, arr, radius); retVal = createParking(ac, arr, radius);
break; break;
default: default:
//exit(1); //exit(1);
@ -120,7 +120,7 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
//don't increment leg right away, but only once we pass the actual last waypoint that was created. //don't increment leg right away, but only once we pass the actual last waypoint that was created.
// to do so, mark the last waypoint with a special status flag // to do so, mark the last waypoint with a special status flag
if (retVal) { if (retVal) {
waypoints.back()->setName( waypoints.back()->getName() + string("legend")); waypoints.back()->setName( waypoints.back()->getName() + string("legend"));
// "It's pronounced Leg-end" (Roger Glover (Deep Purple): come Hell or High Water DvD, 1993) // "It's pronounced Leg-end" (Roger Glover (Deep Purple): come Hell or High Water DvD, 1993)
} }
return retVal; return retVal;
@ -199,7 +199,7 @@ FGAIWaypoint * FGAIFlightPlan::createInAir(FGAIAircraft * ac,
wpt->setSpeedBrakes(0.0f ); wpt->setSpeedBrakes(0.0f );
wpt->setOn_ground (false ); wpt->setOn_ground (false );
wpt->setCrossat (aElev ); wpt->setCrossat (aElev );
if (aPos.getElevationFt() < 10000.0f) { if (aPos.getElevationFt() < 10000.0f) {
wpt->setApproachLights(); wpt->setApproachLights();
} else { } else {
@ -222,9 +222,9 @@ FGAIWaypoint * FGAIFlightPlan::clone(FGAIWaypoint * aWpt)
wpt->setFinished ( aWpt->isFinished() ); wpt->setFinished ( aWpt->isFinished() );
wpt->setOn_ground ( aWpt->getOn_ground() ); wpt->setOn_ground ( aWpt->getOn_ground() );
wpt->setLandingLight (aWpt->getLandingLight() ); wpt->setLandingLight (aWpt->getLandingLight() );
wpt->setNavLight (aWpt->getNavLight() ); wpt->setNavLight (aWpt->getNavLight() );
wpt->setStrobeLight (aWpt->getStrobeLight() ); wpt->setStrobeLight (aWpt->getStrobeLight() );
wpt->setTaxiLight (aWpt->getTaxiLight() ); wpt->setTaxiLight (aWpt->getTaxiLight() );
wpt->setRouteIndex ( 0 ); wpt->setRouteIndex ( 0 );
return wpt; return wpt;
@ -322,7 +322,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
} }
// A negative gateId indicates an overflow parking, use a // A negative gateId indicates an overflow parking, use a
// fallback mechanism for this. // fallback mechanism for this.
// Starting from gate 0 in this case is a bit of a hack // Starting from gate 0 in this case is a bit of a hack
// which requires a more proper solution later on. // which requires a more proper solution later on.
// delete taxiRoute; // delete taxiRoute;
@ -347,7 +347,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
} else { } else {
SG_LOG(SG_AI, SG_WARN, "Taxiroute could not be constructed no parking." << (apt?apt->getId():"????")); SG_LOG(SG_AI, SG_WARN, "Taxiroute could not be constructed no parking." << (apt?apt->getId():"????"));
} }
FGTaxiRoute taxiRoute; FGTaxiRoute taxiRoute;
if (runwayNode && node) { if (runwayNode && node) {
taxiRoute = gn->findShortestRoute(node, runwayNode); taxiRoute = gn->findShortestRoute(node, runwayNode);
@ -375,7 +375,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
for (int i = 0; i < nrWaypointsToSkip - 3; i++) { for (int i = 0; i < nrWaypointsToSkip - 3; i++) {
taxiRoute.next(skipNode, &route); taxiRoute.next(skipNode, &route);
} }
gate.release(); // free up our gate as required gate.release(); // free up our gate as required
} else { } else {
if (taxiRoute.size() > 1) { if (taxiRoute.size() > 1) {
@ -384,12 +384,12 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
} }
// push each node on the taxi route as a waypoint // push each node on the taxi route as a waypoint
//cerr << "Building taxi route" << endl; //cerr << "Building taxi route" << endl;
// Note that the line wpt->setRouteIndex was commented out by revision [afcdbd] 2012-01-01, // Note that the line wpt->setRouteIndex was commented out by revision [afcdbd] 2012-01-01,
// which breaks the rendering functions. // which breaks the rendering functions.
// These can probably be generated on the fly however. // These can probably be generated on the fly however.
while (taxiRoute.next(node, &route)) { while (taxiRoute.next(node, &route)) {
char buffer[10]; char buffer[10];
snprintf(buffer, sizeof(buffer), "%d", node->getIndex()); snprintf(buffer, sizeof(buffer), "%d", node->getIndex());
@ -464,7 +464,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac,
{ {
int route; int route;
gate = apt->getDynamics()->getAvailableParking(radius, fltType, gate = apt->getDynamics()->getAvailableParking(radius, fltType,
acType, airline); acType, airline);
SGGeod lastWptPos = waypoints.back()->getPos(); SGGeod lastWptPos = waypoints.back()->getPos();
FGGroundNetwork *gn = apt->groundNetwork(); FGGroundNetwork *gn = apt->groundNetwork();
@ -483,7 +483,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac,
} }
//cerr << "Using network node " << runwayId << endl; //cerr << "Using network node " << runwayId << endl;
// A negative gateId indicates an overflow parking, use a // A negative gateId indicates an overflow parking, use a
// fallback mechanism for this. // fallback mechanism for this.
// Starting from gate 0 doesn't work, so don't try it // Starting from gate 0 doesn't work, so don't try it
FGTaxiRoute taxiRoute; FGTaxiRoute taxiRoute;
if (runwayNode && gate.isValid()) { if (runwayNode && gate.isValid()) {
@ -509,7 +509,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac,
FGAIWaypoint *wpt = FGAIWaypoint *wpt =
createOnGround(ac, buffer, node->geod(), apt->getElevation(), createOnGround(ac, buffer, node->geod(), apt->getElevation(),
ac->getPerformance()->vTaxi()); ac->getPerformance()->vTaxi());
wpt->setRouteIndex(route); wpt->setRouteIndex(route);
// next WPT must be far enough // next WPT must be far enough
if (!waypoints.back() || SGGeodesy::distanceM(waypoints.back()->getPos(), wpt->getPos()) > 0 ) { if (!waypoints.back() || SGGeodesy::distanceM(waypoints.back()->getPos(), wpt->getPos()) > 0 ) {
@ -546,15 +546,15 @@ static double pitchDistance(double pitchAngleDeg, double altGainM)
} }
/******************************************************************* /*******************************************************************
* CreateTakeOff * CreateTakeOff
* A note on units: * A note on units:
* - Speed -> knots -> nm/hour * - Speed -> knots -> nm/hour
* - distance along runway =-> meters * - distance along runway =-> meters
* - accel / decel -> is given as knots/hour, but this is highly questionable: * - accel / decel -> is given as knots/hour, but this is highly questionable:
* for a jet_transport performance class, a accel / decel rate of 5 / 2 is * for a jet_transport performance class, a accel / decel rate of 5 / 2 is
* given respectively. According to performance data.cxx, a value of kts / second seems * given respectively. According to performance data.cxx, a value of kts / second seems
* more likely however. * more likely however.
* *
******************************************************************/ ******************************************************************/
bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
bool firstFlight, bool firstFlight,
@ -568,7 +568,7 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
// climb-out angle in degrees. could move this to the perf-db but this // climb-out angle in degrees. could move this to the perf-db but this
// value is pretty sane // value is pretty sane
const double INITIAL_PITCH_ANGLE = 10.0; const double INITIAL_PITCH_ANGLE = 10.0;
double accel = ac->getPerformance()->acceleration(); double accel = ac->getPerformance()->acceleration();
double vTaxi = ac->getPerformance()->vTaxi(); double vTaxi = ac->getPerformance()->vTaxi();
double vRotate = ac->getPerformance()->vRotate(); double vRotate = ac->getPerformance()->vRotate();
@ -578,12 +578,12 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
double vTaxiMetric = vTaxi * SG_KT_TO_MPS; double vTaxiMetric = vTaxi * SG_KT_TO_MPS;
double vRotateMetric = vRotate * SG_KT_TO_MPS; double vRotateMetric = vRotate * SG_KT_TO_MPS;
double vTakeoffMetric = vTakeoff * SG_KT_TO_MPS; double vTakeoffMetric = vTakeoff * SG_KT_TO_MPS;
FGAIWaypoint *wpt; FGAIWaypoint *wpt;
// Get the current active runway, based on code from David Luff // Get the current active runway, based on code from David Luff
// This should actually be unified and extended to include // This should actually be unified and extended to include
// Preferential runway use schema's // Preferential runway use schema's
// NOTE: DT (2009-01-18: IIRC, this is currently already the case, // NOTE: DT (2009-01-18: IIRC, this is currently already the case,
// because the getActive runway function takes care of that. // because the getActive runway function takes care of that.
if (firstFlight) { if (firstFlight) {
const string& rwyClass = getRunwayClassFromTrafficType(fltType); const string& rwyClass = getRunwayClassFromTrafficType(fltType);
@ -599,11 +599,11 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
return false; return false;
} }
SG_LOG(SG_AI, SG_BULK, "Takeoff from airport " << apt->getId() << "/" << activeRunway); SG_LOG(SG_AI, SG_BULK, "Takeoff from airport " << apt->getId() << "/" << activeRunway);
FGRunway * rwy = apt->getRunwayByIdent(activeRunway); FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
if (!rwy) if (!rwy)
return false; return false;
double airportElev = apt->getElevation(); double airportElev = apt->getElevation();
if (pos.isValid()) { if (pos.isValid()) {
@ -633,18 +633,18 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
double vRef = vTakeoff + 20; // climb-out at v2 + 20kts double vRef = vTakeoff + 20; // climb-out at v2 + 20kts
// We want gear-up to take place at ~400ft AGL. However, the flightplan // We want gear-up to take place at ~400ft AGL. However, the flightplan
// will move onto the next leg once it gets within 2xspeed of the next waypoint. // will move onto the next leg once it gets within 2xspeed of the next waypoint.
// With closely spaced waypoints on climb-out this can occur almost immediately, // With closely spaced waypoints on climb-out this can occur almost immediately,
// so we put the waypoint further away. // so we put the waypoint further away.
double gearUpDist = t + 2*vRef*SG_FEET_TO_METER + pitchDistance(INITIAL_PITCH_ANGLE, 400 * SG_FEET_TO_METER); double gearUpDist = t + 2*vRef*SG_FEET_TO_METER + pitchDistance(INITIAL_PITCH_ANGLE, 400 * SG_FEET_TO_METER);
SGGeod gearUpPoint = rwy->pointOnCenterlineDisplaced(gearUpDist); SGGeod gearUpPoint = rwy->pointOnCenterlineDisplaced(gearUpDist);
wpt = createInAir(ac, "gear-up", gearUpPoint, airportElev + 400, vRef); wpt = createInAir(ac, "gear-up", gearUpPoint, airportElev + 400, vRef);
wpt->setFlaps(0.5f); wpt->setFlaps(0.5f);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
// limit climbout speed to 240kts below 10000' // limit climbout speed to 240kts below 10000'
double vClimbBelow10000 = std::min(240.0, ac->getPerformance()->vClimb()); double vClimbBelow10000 = std::min(240.0, ac->getPerformance()->vClimb());
// create two climb-out points. This is important becuase the first climb point will // create two climb-out points. This is important becuase the first climb point will
// be a (sometimes large) turn towards the destination, and we don't want to // be a (sometimes large) turn towards the destination, and we don't want to
// commence that turn below 2000' // commence that turn below 2000'
@ -652,7 +652,7 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
SGGeod climbOutPoint = rwy->pointOnCenterlineDisplaced(climbOut); SGGeod climbOutPoint = rwy->pointOnCenterlineDisplaced(climbOut);
wpt = createInAir(ac, "2000'", climbOutPoint, airportElev + 2000, vClimbBelow10000); wpt = createInAir(ac, "2000'", climbOutPoint, airportElev + 2000, vClimbBelow10000);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
climbOut = t + 2*vClimbBelow10000*SG_FEET_TO_METER + pitchDistance(INITIAL_PITCH_ANGLE, 2500 * SG_FEET_TO_METER); climbOut = t + 2*vClimbBelow10000*SG_FEET_TO_METER + pitchDistance(INITIAL_PITCH_ANGLE, 2500 * SG_FEET_TO_METER);
SGGeod climbOutPoint2 = rwy->pointOnCenterlineDisplaced(climbOut); SGGeod climbOutPoint2 = rwy->pointOnCenterlineDisplaced(climbOut);
wpt = createInAir(ac, "2500'", climbOutPoint2, airportElev + 2500, vClimbBelow10000); wpt = createInAir(ac, "2500'", climbOutPoint2, airportElev + 2500, vClimbBelow10000);
@ -671,7 +671,7 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
const string & fltType) const string & fltType)
{ {
double vClimb = ac->getPerformance()->vClimb(); double vClimb = ac->getPerformance()->vClimb();
if (firstFlight) { if (firstFlight) {
const string& rwyClass = getRunwayClassFromTrafficType(fltType); const string& rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse(); double heading = ac->getTrafficRef()->getCourse();
@ -692,10 +692,10 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
if (!waypoints.empty()) { if (!waypoints.empty()) {
cur = waypoints.back()->getPos(); cur = waypoints.back()->getPos();
} }
// compute course towards destination // compute course towards destination
double course = SGGeodesy::courseDeg(cur, arrival->geod()); double course = SGGeodesy::courseDeg(cur, arrival->geod());
SGGeod climb1 = SGGeodesy::direct(cur, course, 10 * SG_NM_TO_METER); SGGeod climb1 = SGGeodesy::direct(cur, course, 10 * SG_NM_TO_METER);
FGAIWaypoint *wpt = createInAir(ac, "10000ft climb", climb1, 10000, vClimb); FGAIWaypoint *wpt = createInAir(ac, "10000ft climb", climb1, 10000, vClimb);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
@ -710,7 +710,7 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
/******************************************************************* /*******************************************************************
* CreateDescent * CreateDescent
* Generate a flight path from the last waypoint of the cruise to * Generate a flight path from the last waypoint of the cruise to
* the permission to land point * the permission to land point
******************************************************************/ ******************************************************************/
bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
@ -724,7 +724,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
double vDescent = ac->getPerformance()->vDescent(); double vDescent = ac->getPerformance()->vDescent();
double vApproach = ac->getPerformance()->vApproach(); double vApproach = ac->getPerformance()->vApproach();
//Beginning of Descent //Beginning of Descent
const string& rwyClass = getRunwayClassFromTrafficType(fltType); const string& rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse(); double heading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
@ -773,13 +773,13 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
if (apt->groundNetwork()) { if (apt->groundNetwork()) {
tn = apt->groundNetwork()->findNearestNode(refPoint); tn = apt->groundNetwork()->findNearestNode(refPoint);
} }
if (tn) { if (tn) {
dAlt = alt - ((tn->getElevationFt()) + 2000); dAlt = alt - ((tn->getElevationFt()) + 2000);
} else { } else {
dAlt = alt - (apt->getElevation() + 2000); dAlt = alt - (apt->getElevation() + 2000);
} }
double nPoints = 100; double nPoints = 100;
char buffer[16]; char buffer[16];
@ -824,7 +824,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
} }
// Calculate the ETA at final, based on remaining distance, and approach speed. // Calculate the ETA at final, based on remaining distance, and approach speed.
// distance should really consist of flying time to terniary target, plus circle // distance should really consist of flying time to terniary target, plus circle
// but the distance to secondary target should work as a reasonable approximation // but the distance to secondary target should work as a reasonable approximation
// aditionally add the amount of distance covered by making a turn of "side" // aditionally add the amount of distance covered by making a turn of "side"
double turnDistance = (2 * M_PI * initialTurnRadius) * (side / 360.0); double turnDistance = (2 * M_PI * initialTurnRadius) * (side / 360.0);
@ -942,7 +942,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
} else { } else {
currentAltitude = apt->getElevation() + 2000; currentAltitude = apt->getElevation() + 2000;
} }
// Length of // Length of
if (holdsPatterns>0) { if (holdsPatterns>0) {
@ -962,9 +962,9 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
} }
// The approach leg should bring the aircraft to approximately 4-6 nm out, after which the landing phase should take over. // The approach leg should bring the aircraft to approximately 4-6 nm out, after which the landing phase should take over.
//cerr << "Phase 3: Approach" << endl; //cerr << "Phase 3: Approach" << endl;
//cerr << "Done" << endl; //cerr << "Done" << endl;
// Erase the two bogus BOD points: Note check for conflicts with scripted AI flightPlans // Erase the two bogus BOD points: Note check for conflicts with scripted AI flightPlans
@ -991,7 +991,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
} }
SG_LOG(SG_AI, SG_BULK, "Setting Node " << waypoints[1]->getName() << " to a leg end"); SG_LOG(SG_AI, SG_BULK, "Setting Node " << waypoints[1]->getName() << " to a leg end");
waypoints[1]->setName( (waypoints[1]->getName() + string("legend"))); waypoints[1]->setName( (waypoints[1]->getName() + string("legend")));
return true; return true;
} }
@ -1006,12 +1006,12 @@ static double runwayGlideslopeTouchdownDistance(FGRunway* rwy)
if (!gs) { if (!gs) {
return -1; return -1;
} }
SGVec3d runwayPosCart = SGVec3d::fromGeod(rwy->pointOnCenterline(0.0)); SGVec3d runwayPosCart = SGVec3d::fromGeod(rwy->pointOnCenterline(0.0));
// compute a unit vector in ECF cartesian space, from the runway beginning to the end // compute a unit vector in ECF cartesian space, from the runway beginning to the end
SGVec3d runwayDirectionVec = normalize(SGVec3d::fromGeod(rwy->end()) - runwayPosCart); SGVec3d runwayDirectionVec = normalize(SGVec3d::fromGeod(rwy->end()) - runwayPosCart);
SGVec3d gsTransmitterVec = gs->cart() - runwayPosCart; SGVec3d gsTransmitterVec = gs->cart() - runwayPosCart;
// project the gsTransmitterVec along the runwayDirctionVec to get out // project the gsTransmitterVec along the runwayDirctionVec to get out
// final value (in metres) // final value (in metres)
double dist = dot(runwayDirectionVec, gsTransmitterVec); double dist = dot(runwayDirectionVec, gsTransmitterVec);
@ -1022,7 +1022,7 @@ static double runwayGlideslopeTouchdownDistance(FGRunway* rwy)
* CreateLanding (Leg 7) * CreateLanding (Leg 7)
* Create a flight path from the "permision to land" point (currently * Create a flight path from the "permision to land" point (currently
hardcoded at 5000 meters from the threshold) to the threshold, at hardcoded at 5000 meters from the threshold) to the threshold, at
a standard glide slope angle of 3 degrees. a standard glide slope angle of 3 degrees.
Position : 50.0354 8.52592 384 364 11112 Position : 50.0354 8.52592 384 364 11112
******************************************************************/ ******************************************************************/
bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt, bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
@ -1032,7 +1032,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
double vTaxi = ac->getPerformance()->vTaxi(); double vTaxi = ac->getPerformance()->vTaxi();
double decel = ac->getPerformance()->decelerationOnGround(); double decel = ac->getPerformance()->decelerationOnGround();
double vApproach = ac->getPerformance()->vApproach(); double vApproach = ac->getPerformance()->vApproach();
double vTouchdownMetric = vTouchdown * SG_KT_TO_MPS; double vTouchdownMetric = vTouchdown * SG_KT_TO_MPS;
double vTaxiMetric = vTaxi * SG_KT_TO_MPS; double vTaxiMetric = vTaxi * SG_KT_TO_MPS;
double decelMetric = decel * SG_KT_TO_MPS; double decelMetric = decel * SG_KT_TO_MPS;
@ -1046,17 +1046,17 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
FGRunway * rwy = apt->getRunwayByIdent(activeRunway); FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
if (!rwy) if (!rwy)
return false; return false;
SGGeod threshold = rwy->threshold(); SGGeod threshold = rwy->threshold();
double currElev = threshold.getElevationFt(); double currElev = threshold.getElevationFt();
double touchdownDistance = runwayGlideslopeTouchdownDistance(rwy); double touchdownDistance = runwayGlideslopeTouchdownDistance(rwy);
if (touchdownDistance < 0.0) { if (touchdownDistance < 0.0) {
double landingLength = rwy->lengthM() - (rwy->displacedThresholdM()); double landingLength = rwy->lengthM() - (rwy->displacedThresholdM());
// touchdown 25% of the way along the landing area // touchdown 25% of the way along the landing area
touchdownDistance = rwy->displacedThresholdM() + (landingLength * 0.25); touchdownDistance = rwy->displacedThresholdM() + (landingLength * 0.25);
} }
SGGeod coord; SGGeod coord;
// find glideslope entry point, 2000' above touchdown elevation // find glideslope entry point, 2000' above touchdown elevation
double glideslopeEntry = -((2000 * SG_FEET_TO_METER) / tan(3.0)) + touchdownDistance; double glideslopeEntry = -((2000 * SG_FEET_TO_METER) / tan(3.0)) + touchdownDistance;
@ -1066,7 +1066,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
wpt->setFlaps(1.0f); wpt->setFlaps(1.0f);
wpt->setSpeedBrakes(1.0f); wpt->setSpeedBrakes(1.0f);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
// deceleration point, 500' above touchdown elevation - slow from approach speed // deceleration point, 500' above touchdown elevation - slow from approach speed
// to touchdown speed // to touchdown speed
double decelPoint = -((500 * SG_FEET_TO_METER) / tan(3.0)) + touchdownDistance; double decelPoint = -((500 * SG_FEET_TO_METER) / tan(3.0)) + touchdownDistance;
@ -1076,7 +1076,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
wpt->setFlaps(1.0f); wpt->setFlaps(1.0f);
wpt->setSpeedBrakes(1.0f); wpt->setSpeedBrakes(1.0f);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
// compute elevation above the runway start, based on a 3-degree glideslope // compute elevation above the runway start, based on a 3-degree glideslope
double heightAboveRunwayStart = touchdownDistance * double heightAboveRunwayStart = touchdownDistance *
tan(3.0 * SG_DEGREES_TO_RADIANS) * SG_METER_TO_FEET; tan(3.0 * SG_DEGREES_TO_RADIANS) * SG_METER_TO_FEET;
@ -1086,9 +1086,9 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
wpt->setFlaps(1.0f); wpt->setFlaps(1.0f);
wpt->setSpeedBrakes(1.0f); wpt->setSpeedBrakes(1.0f);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
double rolloutDistance = accelDistance(vTouchdownMetric, vTaxiMetric, decelMetric); double rolloutDistance = accelDistance(vTouchdownMetric, vTaxiMetric, decelMetric);
int nPoints = (int)(rolloutDistance/60); int nPoints = (int)(rolloutDistance/60);
for (int i = 1; i <= nPoints; i++) { for (int i = 1; i <= nPoints; i++) {
snprintf(buffer, sizeof(buffer), "rollout%03d", i); snprintf(buffer, sizeof(buffer), "rollout%03d", i);
@ -1102,7 +1102,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
wpt->setCrossat(currElev); wpt->setCrossat(currElev);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
} }
wpt->setSpeed(vTaxi); wpt->setSpeed(vTaxi);
double mindist = (1.1 * rolloutDistance) + touchdownDistance; double mindist = (1.1 * rolloutDistance) + touchdownDistance;
@ -1111,7 +1111,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
SG_LOG(SG_AI, SG_DEBUG, "No groundnet " << apt->getId() << " no landing created."); SG_LOG(SG_AI, SG_DEBUG, "No groundnet " << apt->getId() << " no landing created.");
return true; return true;
} }
coord = rwy->pointOnCenterline(mindist); coord = rwy->pointOnCenterline(mindist);
FGTaxiNodeRef tn; FGTaxiNodeRef tn;
if (gn->getVersion() > 0) { if (gn->getVersion() > 0) {
@ -1119,7 +1119,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
} else { } else {
tn = gn->findNearestNode(coord); tn = gn->findNearestNode(coord);
} }
if (tn) { if (tn) {
wpt = createOnRunway(ac, buffer, tn->geod(), currElev, vTaxi); wpt = createOnRunway(ac, buffer, tn->geod(), currElev, vTaxi);
wpt->setFlaps(1.0f); wpt->setFlaps(1.0f);
@ -1148,35 +1148,48 @@ bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
return true; return true;
} }
FGParking* parking = gate.parking(); FGParking* parking = gate.parking();
double reverseHeading = SGMiscd::normalizePeriodic(0, 360, parking->getHeading() + 180.0); double reverseHeading = SGMiscd::normalizePeriodic(0, 360, parking->getHeading() + 180.0);
double az; // unused double az; // unused
SGGeod pos; SGGeod pos;
SGGeodesy::direct(parking->geod(), reverseHeading, 2 * parking->getRadius(), SGGeodesy::direct(parking->geod(), reverseHeading, 2 * parking->getRadius(),
pos, az); pos, az);
wpt = createOnGround(ac, "parking", pos, aptElev, vTaxiReduced/2); wpt = createOnGround(ac, "parking1", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
SGGeodesy::direct(parking->geod(), reverseHeading, 1.5 * parking->getRadius(), SGGeodesy::direct(parking->geod(), reverseHeading, 1 * parking->getRadius(),
pos, az); pos, az);
wpt = createOnGround(ac, "parking2", pos, aptElev, vTaxiReduced/3); wpt = createOnGround(ac, "parking2", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
SGGeodesy::direct(parking->geod(), reverseHeading, parking->getRadius(), SGGeodesy::direct(parking->geod(), reverseHeading, 0.6 * parking->getRadius(),
pos, az); pos, az);
wpt = createOnGround(ac, "parking3", pos, aptElev, vTaxiReduced/3); wpt = createOnGround(ac, "parking3", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
char buffer[30]; SGGeodesy::direct(parking->geod(), reverseHeading, 0.3 * parking->getRadius(),
snprintf(buffer, 30, "Parking%s", parking->getName().c_str()); pos, az);
wpt = createOnGround(ac, "parking4", pos, aptElev, vTaxiReduced/3);
wpt = createOnGround(ac, buffer, parking->geod(), aptElev,
2);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
SGGeodesy::direct(parking->geod(), parking->getHeading(), 1,
SGGeodesy::direct(parking->geod(), reverseHeading, 0.2 * parking->getRadius(),
pos, az);
wpt = createOnGround(ac, "parking5", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt);
char buffer[30];
snprintf(buffer, sizeof(buffer), "Parking%s", parking->getName().c_str());
wpt = createOnGround(ac, buffer, parking->geod(), aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt);
SGGeodesy::direct(parking->geod(), parking->getHeading(), 2,
pos, az);
wpt = createOnGround(ac, "Beyond-Parking", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt);
SGGeodesy::direct(parking->geod(), parking->getHeading(), 3,
pos, az); pos, az);
wpt = createOnGround(ac, "END-Parking", pos, aptElev, vTaxiReduced/3); wpt = createOnGround(ac, "END-Parking", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt); pushBackWaypoint(wpt);
@ -1191,7 +1204,7 @@ bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
* preference schedule to be used at aircraft having * preference schedule to be used at aircraft having
* a preferential runway schedule implemented (i.e. * a preferential runway schedule implemented (i.e.
* having a rwyprefs.xml file * having a rwyprefs.xml file
* *
* Currently valid traffic types for gate assignment: * Currently valid traffic types for gate assignment:
* - gate (commercial gate) * - gate (commercial gate)
* - cargo (commercial gargo), * - cargo (commercial gargo),