X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAIModel%2FAIFlightPlanCreate.cxx;h=47026b60ed71a826d8325e4f789ddad228b89313;hb=7c8ad455a327276e09687b380fb4147ae90b6c8c;hp=2753dc11e3d76a004f5b44b674b26982edb3ebcb;hpb=11a9bdf29ed28345e274265857c733695666cebc;p=flightgear.git diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx index 2753dc11e..47026b60e 100644 --- a/src/AIModel/AIFlightPlanCreate.cxx +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -22,6 +22,7 @@ # include #endif +#include #include "AIFlightPlan.hxx" #include @@ -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; } @@ -650,11 +655,11 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, //cerr << "Distance : " << distance << endl; //cerr << "Azimuth : " << azimuth << endl; //cerr << "Initial Lateral point: " << lateralOffset << endl; - double lat = refPoint.getLatitudeDeg(); - double lon = refPoint.getLongitudeDeg(); +// double lat = refPoint.getLatitudeDeg(); +// double lon = refPoint.getLongitudeDeg(); //cerr << "Reference point (" << lat << ", " << lon << ")." << endl; - lat = initialTarget.getLatitudeDeg(); - lon = initialTarget.getLongitudeDeg(); +// lat = initialTarget.getLatitudeDeg(); +// lon = initialTarget.getLongitudeDeg(); //cerr << "Initial Target point (" << lat << ", " << lon << ")." << endl; double ratio = initialTurnRadius / distance; @@ -723,8 +728,8 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, azimuth = SGGeodesy::courseDeg(origin, secondaryTarget); - lat = secondaryTarget.getLatitudeDeg(); - lon = secondaryTarget.getLongitudeDeg(); +// lat = secondaryTarget.getLatitudeDeg(); +// lon = secondaryTarget.getLongitudeDeg(); //cerr << "Secondary Target point (" << lat << ", " << lon << ")." << endl; //cerr << "Distance : " << distance << endl; //cerr << "Azimuth : " << azimuth << endl; @@ -748,8 +753,8 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, SGGeodesy::direct(origin, azimuth, newDistance, tertiaryTarget, dummyAz2); - lat = tertiaryTarget.getLatitudeDeg(); - lon = tertiaryTarget.getLongitudeDeg(); +// lat = tertiaryTarget.getLatitudeDeg(); +// lon = tertiaryTarget.getLongitudeDeg(); //cerr << "tertiary Target point (" << lat << ", " << lon << ")." << endl; @@ -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;