]> git.mxchange.org Git - flightgear.git/blobdiff - src/AIModel/AIFlightPlanCreate.cxx
PerformanceDB improvements.
[flightgear.git] / src / AIModel / AIFlightPlanCreate.cxx
index 63ae6f5000cfa81765b2a0af39944ead15f5998c..47026b60ed71a826d8325e4f789ddad228b89313 100644 (file)
@@ -22,6 +22,7 @@
 #  include <config.h>
 #endif
 
+#include <cstdlib>
 
 #include "AIFlightPlan.hxx"
 #include <simgear/math/sg_geodesy.hxx>
@@ -61,7 +62,7 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
     int currWpt = wpt_iterator - waypoints.begin();
     switch (legNr) {
     case 1:
-        retVal = createPushBack(ac, firstFlight, dep, latitude, longitude,
+        retVal = createPushBack(ac, firstFlight, dep,
                                 radius, fltType, aircraftType, airline);
         // Pregenerate the taxi leg.
         //if (retVal) {
@@ -144,6 +145,7 @@ FGAIWaypoint *    FGAIFlightPlan::createInAir(FGAIAircraft * ac,
     wpt->setGear_down  (false                   );
     wpt->setFlaps_down (false                   );
     wpt->setOn_ground  (false                   );
+    wpt->setCrossat    (aElev                   );
     return wpt;
 }
 
@@ -205,22 +207,21 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
                                        const string & acType,
                                        const string & airline)
 {
-    double heading, lat, lon;
 
     // If this function is called during initialization,
     // make sure we obtain a valid gate ID first
     // and place the model at the location of the gate.
-    if (firstFlight) {
-        if (!(apt->getDynamics()->getAvailableParking(&lat, &lon,
-                                                      &heading, &gateId,
-                                                      radius, fltType,
-                                                      acType, airline))) {
-            SG_LOG(SG_AI, SG_WARN, "Could not find parking for a " <<
-                   acType <<
-                   " of flight type " << fltType <<
-                   " of airline     " << airline <<
-                   " at airport     " << apt->getId());
-        }
+    if (firstFlight)
+    {
+      gateId =  apt->getDynamics()->getAvailableParking(radius, fltType,
+                                                        acType, airline);
+      if (gateId < 0) {
+        SG_LOG(SG_AI, SG_WARN, "Could not find parking for a " <<
+               acType <<
+               " of flight type " << fltType <<
+               " of airline     " << airline <<
+               " at airport     " << apt->getId());
+      }
     }
 
     string rwyClass = getRunwayClassFromTrafficType(fltType);
@@ -313,7 +314,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
         FGTaxiNode *tn =
             apt->getDynamics()->getGroundNetwork()->findNode(node);
         FGAIWaypoint *wpt =
-            createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(),
+            createOnGround(ac, buffer, tn->geod(), apt->getElevation(),
                            ac->getPerformance()->vTaxi());
         wpt->setRouteIndex(route);
         //cerr << "Nodes left " << taxiRoute->nodesLeft() << " ";
@@ -354,12 +355,12 @@ void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
                        ac->getPerformance()->vTaxi());
     pushBackWaypoint(wpt);
 
-    double heading, lat, lon;
-    aAirport->getDynamics()->getParking(gateId, &lat, &lon, &heading);
-    wpt =
-        createOnGround(ac, "ENDtaxi", SGGeod::fromDeg(lon, lat), airportElev,
-                       ac->getPerformance()->vTaxi());
-    pushBackWaypoint(wpt);
+    FGParking* parkPos = aAirport->getDynamics()->getParking(gateId);
+    if (parkPos) {
+        wpt = createOnGround(ac, "ENDtaxi", parkPos->geod(), airportElev,
+                         ac->getPerformance()->vTaxi());
+        pushBackWaypoint(wpt);
+    }
 }
 
 bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
@@ -368,9 +369,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
                                        const string & acType,
                                        const string & airline)
 {
-    double heading, lat, lon;
-    apt->getDynamics()->getAvailableParking(&lat, &lon, &heading,
-                                            &gateId, radius, fltType,
+    gateId = apt->getDynamics()->getAvailableParking(radius, fltType,
                                             acType, airline);
 
     SGGeod lastWptPos =
@@ -421,7 +420,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
         snprintf(buffer, 10, "%d", node);
         FGTaxiNode *tn = gn->findNode(node);
         FGAIWaypoint *wpt =
-            createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(),
+            createOnGround(ac, buffer, tn->geod(), apt->getElevation(),
                            ac->getPerformance()->vTaxi());
         wpt->setRouteIndex(route);
         pushBackWaypoint(wpt);
@@ -429,6 +428,22 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
     return true;
 }
 
+static double accelDistance(double v0, double v1, double accel)
+{
+  double t = fabs(v1 - v0) / accel; // time in seconds to change velocity
+  // area under the v/t graph: (t * v0) + (dV / 2t) where (dV = v1 - v0)
+  return t * 0.5 * (v1 + v0); 
+}
+
+// find the horizontal distance to gain the specific altiude, holding
+// a constant pitch angle. Used to compute distance based on standard FD/AP
+// PITCH mode prior to VS or CLIMB engaging. Visually, we want to avoid
+// a dip in the nose angle after rotation, during initial climb-out.
+static double pitchDistance(double pitchAngleDeg, double altGainM)
+{
+  return altGainM / tan(pitchAngleDeg * SG_DEGREES_TO_RADIANS);
+}
+
 /*******************************************************************
  * CreateTakeOff 
  * A note on units: 
@@ -444,27 +459,22 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
                                    FGAirport * apt, double speed,
                                    const string & fltType)
 {
+    const double ACCEL_POINT = 105.0;
+    const double KNOTS_HOUR_TO_MSEC = SG_NM_TO_METER / 3600.0;
+  // climb-out angle in degrees. could move this to the perf-db but this
+  // value is pretty sane
+    const double INITIAL_PITCH_ANGLE = 12.5;
+  
     double accel = ac->getPerformance()->acceleration();
     double vTaxi = ac->getPerformance()->vTaxi();
     double vRotate = ac->getPerformance()->vRotate();
     double vTakeoff = ac->getPerformance()->vTakeoff();
-    //double vClimb = ac->getPerformance()->vClimb();
-
-    double accelMetric = (accel * SG_NM_TO_METER) / 3600;
-    double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600;
-    double vRotateMetric = (vRotate * SG_NM_TO_METER) / 3600;
-    double vTakeoffMetric = (vTakeoff * SG_NM_TO_METER) / 3600;
-    //double vClimbMetric = (vClimb * SG_NM_TO_METER) / 3600;
-    // Acceleration = dV / dT
-    // Acceleration X dT = dV
-    // dT = dT / Acceleration
-    //d = (Vf^2 - Vo^2) / (2*a)
-    //double accelTime = (vRotate - vTaxi) / accel;
-    //cerr << "Using " << accelTime << " as total acceleration time" << endl;
-    double accelDistance =
-        (vRotateMetric * vRotateMetric -
-         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
-    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vRotateMetric << endl;
+
+    double accelMetric = accel * KNOTS_HOUR_TO_MSEC;
+    double vTaxiMetric = vTaxi * KNOTS_HOUR_TO_MSEC;
+    double vRotateMetric = vRotate * KNOTS_HOUR_TO_MSEC;
+    double vTakeoffMetric = vTakeoff * KNOTS_HOUR_TO_MSEC;
+   
     FGAIWaypoint *wpt;
     // Get the current active runway, based on code from David Luff
     // This should actually be unified and extended to include 
@@ -477,41 +487,36 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
         apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
                                             heading);
     }
+  
     FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
     assert( rwy != NULL );
-
     double airportElev = apt->getElevation();
     
-
-    accelDistance =
-        (vTakeoffMetric * vTakeoffMetric -
-         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
-    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
-    SGGeod accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
+    double d = accelDistance(vTaxiMetric, vRotateMetric, accelMetric) + ACCEL_POINT;
+  
+    SGGeod accelPoint = rwy->pointOnCenterline(d);
     wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
     pushBackWaypoint(wpt);
 
-    accelDistance =
-        ((vTakeoffMetric * 1.1) * (vTakeoffMetric * 1.1) -
-         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
-    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
-    accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
-    wpt =
-        createOnGround(ac, "rotate", accelPoint, airportElev + 1000,
-                       vTakeoff * 1.1);
+    double vRef = vTakeoffMetric + 20; // climb-out at v2 + 20kts
+    double gearUpDist = d + pitchDistance(INITIAL_PITCH_ANGLE, 400 * SG_FEET_TO_METER);
+    accelPoint = rwy->pointOnCenterline(gearUpDist);
+    
+    wpt = cloneWithPos(ac, wpt, "gear-up", accelPoint);
+    wpt->setSpeed(vRef);
+    wpt->setCrossat(airportElev + 400);
     wpt->setOn_ground(false);
+    wpt->setGear_down(false);
     pushBackWaypoint(wpt);
-
-    wpt = cloneWithPos(ac, wpt, "3000 ft", rwy->end());
-    wpt->setAltitude(airportElev + 3000);
+  
+    double climbOut = d + pitchDistance(INITIAL_PITCH_ANGLE, 2000 * SG_FEET_TO_METER);
+    accelPoint = rwy->pointOnCenterline(climbOut);
+    wpt = createInAir(ac, "2000'", accelPoint, airportElev + 2000, vRef);
     pushBackWaypoint(wpt);
 
-    // Finally, add two more waypoints, so that aircraft will remain under
-    // Tower control until they have reached the 3000 ft climb point
-    SGGeod pt = rwy->pointOnCenterline(5000 + rwy->lengthM() * 0.5);
-    wpt = cloneWithPos(ac, wpt, "5000 ft", pt);
-    wpt->setAltitude(airportElev + 5000);
-    pushBackWaypoint(wpt);
+  // as soon as we pass 2000', hand off to departure so the next acft can line up
+  // ideally the next aircraft would be able to line-up + hold but that's tricky
+  // with the current design.
     return true;
 }
 
@@ -971,14 +976,14 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
             if (!tn)
                 break;
             
-            double dist = SGGeodesy::distanceM(coord, tn->getGeod());
+            double dist = SGGeodesy::distanceM(coord, tn->geod());
             if (dist < (min + 0.75)) {
                 break;
             }
             min = dist;
         }
         if (tn) {
-            wpt = createOnGround(ac, buffer, tn->getGeod(), currElev, vTaxi);
+            wpt = createOnGround(ac, buffer, tn->geod(), currElev, vTaxi);
             pushBackWaypoint(wpt);
         }
     }
@@ -1011,34 +1016,33 @@ bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
 {
     FGAIWaypoint *wpt;
     double aptElev = apt->getElevation();
-    double lat = 0.0, lat2 = 0.0;
-    double lon = 0.0, lon2 = 0.0;
-    double az2 = 0.0;
-    double heading = 0.0;
-
     double vTaxi = ac->getPerformance()->vTaxi();
     double vTaxiReduced = vTaxi * (2.0 / 3.0);
-    apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
-    heading += 180.0;
-    if (heading > 360)
-        heading -= 360;
-    geo_direct_wgs_84(0, lat, lon, heading,
-                      2.2 * radius, &lat2, &lon2, &az2);
-    wpt =
-        createOnGround(ac, "taxiStart", SGGeod::fromDeg(lon2, lat2),
-                       aptElev, vTaxiReduced);
-    pushBackWaypoint(wpt);
+    FGParking* parking = apt->getDynamics()->getParking(gateId);
+    if (!parking) {
+      wpt = createOnGround(ac, "END-Parking", apt->geod(), aptElev,
+                           vTaxiReduced);
+      pushBackWaypoint(wpt);
 
-    geo_direct_wgs_84(0, lat, lon, heading,
-                      0.1 * radius, &lat2, &lon2, &az2);
+      return true;
+    }
+  
+    double heading = SGMiscd::normalizePeriodic(0, 360, parking->getHeading() + 180.0);
+    double az; // unused
+    SGGeod pos;
+  
+    SGGeodesy::direct(parking->geod(), heading, 2.2 * parking->getRadius(),
+                      pos, az);
+  
+    wpt = createOnGround(ac, "taxiStart", pos, aptElev, vTaxiReduced);
+    pushBackWaypoint(wpt);
 
-    wpt =
-        createOnGround(ac, "taxiStart2", SGGeod::fromDeg(lon2, lat2),
-                       aptElev, vTaxiReduced);
+    SGGeodesy::direct(parking->geod(), heading, 0.1 * parking->getRadius(),
+                    pos, az);
+    wpt = createOnGround(ac, "taxiStart2", pos, aptElev, vTaxiReduced);
     pushBackWaypoint(wpt);
 
-    wpt =
-        createOnGround(ac, "END-Parking", SGGeod::fromDeg(lon, lat), aptElev,
+    wpt = createOnGround(ac, "END-Parking", parking->geod(), aptElev,
                        vTaxiReduced);
     pushBackWaypoint(wpt);
     return true;