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()
* 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.
*
@ -68,11 +68,11 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
const string & aircraftType,
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());
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());
else
else
SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " At Airport : " << arr->getId());
bool retVal = true;
@ -107,7 +107,7 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
retVal = createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
break;
case 9:
retVal = createParking(ac, arr, radius);
retVal = createParking(ac, arr, radius);
break;
default:
//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.
// to do so, mark the last waypoint with a special status flag
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)
}
return retVal;
@ -199,7 +199,7 @@ FGAIWaypoint * FGAIFlightPlan::createInAir(FGAIAircraft * ac,
wpt->setSpeedBrakes(0.0f );
wpt->setOn_ground (false );
wpt->setCrossat (aElev );
if (aPos.getElevationFt() < 10000.0f) {
wpt->setApproachLights();
} else {
@ -222,9 +222,9 @@ FGAIWaypoint * FGAIFlightPlan::clone(FGAIWaypoint * aWpt)
wpt->setFinished ( aWpt->isFinished() );
wpt->setOn_ground ( aWpt->getOn_ground() );
wpt->setLandingLight (aWpt->getLandingLight() );
wpt->setNavLight (aWpt->getNavLight() );
wpt->setNavLight (aWpt->getNavLight() );
wpt->setStrobeLight (aWpt->getStrobeLight() );
wpt->setTaxiLight (aWpt->getTaxiLight() );
wpt->setTaxiLight (aWpt->getTaxiLight() );
wpt->setRouteIndex ( 0 );
return wpt;
@ -322,7 +322,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
}
// 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
// which requires a more proper solution later on.
// delete taxiRoute;
@ -347,7 +347,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
} else {
SG_LOG(SG_AI, SG_WARN, "Taxiroute could not be constructed no parking." << (apt?apt->getId():"????"));
}
FGTaxiRoute taxiRoute;
if (runwayNode && node) {
taxiRoute = gn->findShortestRoute(node, runwayNode);
@ -375,7 +375,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
for (int i = 0; i < nrWaypointsToSkip - 3; i++) {
taxiRoute.next(skipNode, &route);
}
gate.release(); // free up our gate as required
} else {
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
//cerr << "Building taxi route" << endl;
// Note that the line wpt->setRouteIndex was commented out by revision [afcdbd] 2012-01-01,
// which breaks the rendering functions.
// These can probably be generated on the fly however.
// which breaks the rendering functions.
// These can probably be generated on the fly however.
while (taxiRoute.next(node, &route)) {
char buffer[10];
snprintf(buffer, sizeof(buffer), "%d", node->getIndex());
@ -464,7 +464,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac,
{
int route;
gate = apt->getDynamics()->getAvailableParking(radius, fltType,
acType, airline);
acType, airline);
SGGeod lastWptPos = waypoints.back()->getPos();
FGGroundNetwork *gn = apt->groundNetwork();
@ -483,7 +483,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac,
}
//cerr << "Using network node " << runwayId << endl;
// 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
FGTaxiRoute taxiRoute;
if (runwayNode && gate.isValid()) {
@ -509,7 +509,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac,
FGAIWaypoint *wpt =
createOnGround(ac, buffer, node->geod(), apt->getElevation(),
ac->getPerformance()->vTaxi());
wpt->setRouteIndex(route);
// next WPT must be far enough
if (!waypoints.back() || SGGeodesy::distanceM(waypoints.back()->getPos(), wpt->getPos()) > 0 ) {
@ -546,15 +546,15 @@ static double pitchDistance(double pitchAngleDeg, double altGainM)
}
/*******************************************************************
* CreateTakeOff
* A note on units:
* CreateTakeOff
* A note on units:
* - Speed -> knots -> nm/hour
* - distance along runway =-> meters
* - distance along runway =-> meters
* - 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
* more likely however.
*
* more likely however.
*
******************************************************************/
bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
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
// value is pretty sane
const double INITIAL_PITCH_ANGLE = 10.0;
double accel = ac->getPerformance()->acceleration();
double vTaxi = ac->getPerformance()->vTaxi();
double vRotate = ac->getPerformance()->vRotate();
@ -578,12 +578,12 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
double vTaxiMetric = vTaxi * SG_KT_TO_MPS;
double vRotateMetric = vRotate * SG_KT_TO_MPS;
double vTakeoffMetric = vTakeoff * SG_KT_TO_MPS;
FGAIWaypoint *wpt;
// Get the current active runway, based on code from David Luff
// This should actually be unified and extended to include
// Preferential runway use schema's
// NOTE: DT (2009-01-18: IIRC, this is currently already the case,
// This should actually be unified and extended to include
// Preferential runway use schema's
// NOTE: DT (2009-01-18: IIRC, this is currently already the case,
// because the getActive runway function takes care of that.
if (firstFlight) {
const string& rwyClass = getRunwayClassFromTrafficType(fltType);
@ -599,11 +599,11 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
return false;
}
SG_LOG(SG_AI, SG_BULK, "Takeoff from airport " << apt->getId() << "/" << activeRunway);
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
if (!rwy)
return false;
double airportElev = apt->getElevation();
if (pos.isValid()) {
@ -633,18 +633,18 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
double vRef = vTakeoff + 20; // climb-out at v2 + 20kts
// 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,
// 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);
SGGeod gearUpPoint = rwy->pointOnCenterlineDisplaced(gearUpDist);
SGGeod gearUpPoint = rwy->pointOnCenterlineDisplaced(gearUpDist);
wpt = createInAir(ac, "gear-up", gearUpPoint, airportElev + 400, vRef);
wpt->setFlaps(0.5f);
pushBackWaypoint(wpt);
// limit climbout speed to 240kts below 10000'
double vClimbBelow10000 = std::min(240.0, ac->getPerformance()->vClimb());
// 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
// commence that turn below 2000'
@ -652,7 +652,7 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac,
SGGeod climbOutPoint = rwy->pointOnCenterlineDisplaced(climbOut);
wpt = createInAir(ac, "2000'", climbOutPoint, airportElev + 2000, vClimbBelow10000);
pushBackWaypoint(wpt);
climbOut = t + 2*vClimbBelow10000*SG_FEET_TO_METER + pitchDistance(INITIAL_PITCH_ANGLE, 2500 * SG_FEET_TO_METER);
SGGeod climbOutPoint2 = rwy->pointOnCenterlineDisplaced(climbOut);
wpt = createInAir(ac, "2500'", climbOutPoint2, airportElev + 2500, vClimbBelow10000);
@ -671,7 +671,7 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
const string & fltType)
{
double vClimb = ac->getPerformance()->vClimb();
if (firstFlight) {
const string& rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
@ -692,10 +692,10 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
if (!waypoints.empty()) {
cur = waypoints.back()->getPos();
}
// compute course towards destination
double course = SGGeodesy::courseDeg(cur, arrival->geod());
SGGeod climb1 = SGGeodesy::direct(cur, course, 10 * SG_NM_TO_METER);
FGAIWaypoint *wpt = createInAir(ac, "10000ft climb", climb1, 10000, vClimb);
pushBackWaypoint(wpt);
@ -710,7 +710,7 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
/*******************************************************************
* 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
******************************************************************/
bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
@ -724,7 +724,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
double vDescent = ac->getPerformance()->vDescent();
double vApproach = ac->getPerformance()->vApproach();
//Beginning of Descent
//Beginning of Descent
const string& rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
@ -773,13 +773,13 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
if (apt->groundNetwork()) {
tn = apt->groundNetwork()->findNearestNode(refPoint);
}
if (tn) {
dAlt = alt - ((tn->getElevationFt()) + 2000);
} else {
dAlt = alt - (apt->getElevation() + 2000);
}
double nPoints = 100;
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.
// 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
// aditionally add the amount of distance covered by making a turn of "side"
double turnDistance = (2 * M_PI * initialTurnRadius) * (side / 360.0);
@ -942,7 +942,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
} else {
currentAltitude = apt->getElevation() + 2000;
}
// Length of
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 << "Done" << endl;
// 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");
waypoints[1]->setName( (waypoints[1]->getName() + string("legend")));
waypoints[1]->setName( (waypoints[1]->getName() + string("legend")));
return true;
}
@ -1006,12 +1006,12 @@ static double runwayGlideslopeTouchdownDistance(FGRunway* rwy)
if (!gs) {
return -1;
}
SGVec3d runwayPosCart = SGVec3d::fromGeod(rwy->pointOnCenterline(0.0));
// compute a unit vector in ECF cartesian space, from the runway beginning to the end
SGVec3d runwayDirectionVec = normalize(SGVec3d::fromGeod(rwy->end()) - runwayPosCart);
SGVec3d gsTransmitterVec = gs->cart() - runwayPosCart;
// project the gsTransmitterVec along the runwayDirctionVec to get out
// final value (in metres)
double dist = dot(runwayDirectionVec, gsTransmitterVec);
@ -1022,7 +1022,7 @@ static double runwayGlideslopeTouchdownDistance(FGRunway* rwy)
* CreateLanding (Leg 7)
* Create a flight path from the "permision to land" point (currently
hardcoded at 5000 meters from the threshold) to the threshold, at
a standard glide slope angle of 3 degrees.
a standard glide slope angle of 3 degrees.
Position : 50.0354 8.52592 384 364 11112
******************************************************************/
bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
@ -1032,7 +1032,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
double vTaxi = ac->getPerformance()->vTaxi();
double decel = ac->getPerformance()->decelerationOnGround();
double vApproach = ac->getPerformance()->vApproach();
double vTouchdownMetric = vTouchdown * SG_KT_TO_MPS;
double vTaxiMetric = vTaxi * 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);
if (!rwy)
return false;
SGGeod threshold = rwy->threshold();
double currElev = threshold.getElevationFt();
double touchdownDistance = runwayGlideslopeTouchdownDistance(rwy);
if (touchdownDistance < 0.0) {
double landingLength = rwy->lengthM() - (rwy->displacedThresholdM());
// touchdown 25% of the way along the landing area
touchdownDistance = rwy->displacedThresholdM() + (landingLength * 0.25);
}
SGGeod coord;
// find glideslope entry point, 2000' above touchdown elevation
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->setSpeedBrakes(1.0f);
pushBackWaypoint(wpt);
// deceleration point, 500' above touchdown elevation - slow from approach speed
// to touchdown speed
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->setSpeedBrakes(1.0f);
pushBackWaypoint(wpt);
// compute elevation above the runway start, based on a 3-degree glideslope
double heightAboveRunwayStart = touchdownDistance *
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->setSpeedBrakes(1.0f);
pushBackWaypoint(wpt);
double rolloutDistance = accelDistance(vTouchdownMetric, vTaxiMetric, decelMetric);
int nPoints = (int)(rolloutDistance/60);
for (int i = 1; i <= nPoints; i++) {
snprintf(buffer, sizeof(buffer), "rollout%03d", i);
@ -1102,7 +1102,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
wpt->setCrossat(currElev);
pushBackWaypoint(wpt);
}
wpt->setSpeed(vTaxi);
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.");
return true;
}
coord = rwy->pointOnCenterline(mindist);
FGTaxiNodeRef tn;
if (gn->getVersion() > 0) {
@ -1119,7 +1119,7 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
} else {
tn = gn->findNearestNode(coord);
}
if (tn) {
wpt = createOnRunway(ac, buffer, tn->geod(), currElev, vTaxi);
wpt->setFlaps(1.0f);
@ -1148,35 +1148,48 @@ bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
pushBackWaypoint(wpt);
return true;
}
FGParking* parking = gate.parking();
double reverseHeading = SGMiscd::normalizePeriodic(0, 360, parking->getHeading() + 180.0);
double az; // unused
SGGeod pos;
SGGeodesy::direct(parking->geod(), reverseHeading, 2 * parking->getRadius(),
pos, az);
wpt = createOnGround(ac, "parking", pos, aptElev, vTaxiReduced/2);
wpt = createOnGround(ac, "parking1", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt);
SGGeodesy::direct(parking->geod(), reverseHeading, 1.5 * parking->getRadius(),
SGGeodesy::direct(parking->geod(), reverseHeading, 1 * parking->getRadius(),
pos, az);
wpt = createOnGround(ac, "parking2", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt);
SGGeodesy::direct(parking->geod(), reverseHeading, parking->getRadius(),
SGGeodesy::direct(parking->geod(), reverseHeading, 0.6 * parking->getRadius(),
pos, az);
wpt = createOnGround(ac, "parking3", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt);
char buffer[30];
snprintf(buffer, 30, "Parking%s", parking->getName().c_str());
wpt = createOnGround(ac, buffer, parking->geod(), aptElev,
2);
SGGeodesy::direct(parking->geod(), reverseHeading, 0.3 * parking->getRadius(),
pos, az);
wpt = createOnGround(ac, "parking4", pos, aptElev, vTaxiReduced/3);
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);
wpt = createOnGround(ac, "END-Parking", pos, aptElev, vTaxiReduced/3);
pushBackWaypoint(wpt);
@ -1191,7 +1204,7 @@ bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
* preference schedule to be used at aircraft having
* a preferential runway schedule implemented (i.e.
* having a rwyprefs.xml file
*
*
* Currently valid traffic types for gate assignment:
* - gate (commercial gate)
* - cargo (commercial gargo),