From b216658ba17877f9ff285f392a94810209c3b1f7 Mon Sep 17 00:00:00 2001 From: portree_kid Date: Sun, 13 Feb 2022 20:34:17 +0100 Subject: [PATCH] AI improved entry into parking (heading and postition) --- src/AIModel/AIFlightPlanCreate.cxx | 165 ++++++++++++++++------------- 1 file changed, 89 insertions(+), 76 deletions(-) diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx index 746e4e32e..fd33f4b58 100644 --- a/src/AIModel/AIFlightPlanCreate.cxx +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -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),