X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAIModel%2FAIFlightPlanCreate.cxx;h=47026b60ed71a826d8325e4f789ddad228b89313;hb=7c8ad455a327276e09687b380fb4147ae90b6c8c;hp=e438ac4d169eef07777875d0ef7beeaa9ae65ee2;hpb=f84d9d475752879b113e373d640f18ee6267c276;p=flightgear.git diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx index e438ac4d1..47026b60e 100644 --- a/src/AIModel/AIFlightPlanCreate.cxx +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -22,6 +22,7 @@ # include #endif +#include #include "AIFlightPlan.hxx" #include @@ -36,6 +37,7 @@ #include #include +#include /* FGAIFlightPlan::create() @@ -60,8 +62,13 @@ 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) { + // waypoints.back()->setName( waypoints.back()->getName() + string("legend")); + // retVal = createTakeoffTaxi(ac, false, dep, radius, fltType, aircraftType, airline); + //} break; case 2: retVal = createTakeoffTaxi(ac, firstFlight, dep, radius, fltType, @@ -92,7 +99,7 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep, break; default: //exit(1); - SG_LOG(SG_INPUT, SG_ALERT, + SG_LOG(SG_AI, SG_ALERT, "AIFlightPlan::create() attempting to create unknown leg" " this is probably an internal program error"); } @@ -138,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; } @@ -185,11 +193,11 @@ void FGAIFlightPlan::createDefaultTakeoffTaxi(FGAIAircraft * ac, wpt = createOnGround(ac, "Airport Center", aAirport->geod(), airportElev, ac->getPerformance()->vTaxi()); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); wpt = createOnGround(ac, "Runway Takeoff", runwayTakeoff, airportElev, ac->getPerformance()->vTaxi()); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); } bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight, @@ -199,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_INPUT, 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); @@ -226,7 +233,8 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight, apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, depHeading); } - rwy = apt->getRunwayByIdent(activeRunway); + FGRunway * rwy = apt->getRunwayByIdent(activeRunway); + assert( rwy != NULL ); SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0); FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork(); @@ -236,7 +244,12 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight, } intVec ids; - int runwayId = gn->findNearestNode(runwayTakeoff); + int runwayId = 0; + if (gn->getVersion() > 0) { + runwayId = gn->findNearestNodeOnRunway(runwayTakeoff); + } else { + runwayId = gn->findNearestNode(runwayTakeoff); + } // A negative gateId indicates an overflow parking, use a // fallback mechanism for this. @@ -294,17 +307,33 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight, // push each node on the taxi route as a waypoint int route; + //cerr << "Building taxi route" << endl; while (taxiRoute->next(&node, &route)) { char buffer[10]; snprintf(buffer, 10, "%d", node); 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); - waypoints.push_back(wpt); + //cerr << "Nodes left " << taxiRoute->nodesLeft() << " "; + if (taxiRoute->nodesLeft() == 1) { + // Note that we actually have hold points in the ground network, but this is just an initial test. + //cerr << "Setting departurehold point: " << endl; + wpt->setName( wpt->getName() + string("DepartureHold")); + } + if (taxiRoute->nodesLeft() == 0) { + wpt->setName(wpt->getName() + string("Accel")); + } + pushBackWaypoint(wpt); } + // Acceleration point, 105 meters into the runway, + SGGeod accelPoint = rwy->pointOnCenterline(105.0); + FGAIWaypoint *wpt = createOnGround(ac, "accel", accelPoint, apt->getElevation(), ac->getPerformance()->vRotate()); + pushBackWaypoint(wpt); + + //cerr << "[done]" << endl; return true; } @@ -320,18 +349,18 @@ void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac, wpt = createOnGround(ac, "Runway Exit", lastWptPos, airportElev, ac->getPerformance()->vTaxi()); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); wpt = createOnGround(ac, "Airport Center", aAirport->geod(), airportElev, ac->getPerformance()->vTaxi()); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); - double heading, lat, lon; - aAirport->getDynamics()->getParking(gateId, &lat, &lon, &heading); - wpt = - createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), airportElev, - ac->getPerformance()->vTaxi()); - waypoints.push_back(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, @@ -340,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 = @@ -357,7 +384,13 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt, } intVec ids; - int runwayId = gn->findNearestNode(lastWptPos); + int runwayId = 0; + if (gn->getVersion() == 1) { + runwayId = gn->findNearestNodeOnRunway(lastWptPos); + } else { + runwayId = gn->findNearestNode(lastWptPos); + } + //cerr << "Using network node " << runwayId << endl; // A negative gateId indicates an overflow parking, use a // fallback mechanism for this. // Starting from gate 0 is a bit of a hack... @@ -387,14 +420,30 @@ 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); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); } 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: @@ -410,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 @@ -443,46 +487,36 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight, apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading); } - rwy = apt->getRunwayByIdent(activeRunway); - - - + + FGRunway * rwy = apt->getRunwayByIdent(activeRunway); + assert( rwy != NULL ); double airportElev = apt->getElevation(); - // Acceleration point, 105 meters into the runway, - SGGeod accelPoint = rwy->pointOnCenterline(105.0); - wpt = createOnGround(ac, "accel", accelPoint, airportElev, vRotate); - waypoints.push_back(wpt); - - - accelDistance = - (vTakeoffMetric * vTakeoffMetric - - vTaxiMetric * vTaxiMetric) / (2 * accelMetric); - //cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl; - 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); - waypoints.push_back(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); + pushBackWaypoint(wpt); + + 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); - waypoints.push_back(wpt); - - wpt = cloneWithPos(ac, wpt, "3000 ft", rwy->end()); - wpt->setAltitude(airportElev + 3000); - waypoints.push_back(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); - waypoints.push_back(wpt); + wpt->setGear_down(false); + pushBackWaypoint(wpt); + + 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); + + // 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; } @@ -504,25 +538,27 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight, double heading = ac->getTrafficRef()->getCourse(); apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading); - rwy = apt->getRunwayByIdent(activeRunway); } if (sid) { for (wpt_vector_iterator i = sid->getFirstWayPoint(); i != sid->getLastWayPoint(); i++) { - waypoints.push_back(clone(*(i))); + pushBackWaypoint(clone(*(i))); //cerr << " Cloning waypoint " << endl; } } else { + FGRunway * rwy = apt->getRunwayByIdent(activeRunway); + assert( rwy != NULL ); + SGGeod climb1 = rwy->pointOnCenterline(10 * SG_NM_TO_METER); - wpt = createInAir(ac, "10000ft climb", climb1, vClimb, 10000); + wpt = createInAir(ac, "10000ft climb", climb1, 10000, vClimb); wpt->setGear_down(true); wpt->setFlaps_down(true); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); SGGeod climb2 = rwy->pointOnCenterline(20 * SG_NM_TO_METER); wpt = cloneWithPos(ac, wpt, "18000ft climb", climb2); wpt->setAltitude(18000); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); } return true; } @@ -544,6 +580,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, FGAIWaypoint *wpt; double vDescent = ac->getPerformance()->vDescent(); double vApproach = ac->getPerformance()->vApproach(); + double vTouchdown = ac->getPerformance()->vTouchdown(); //Beginning of Descent @@ -551,9 +588,8 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, double heading = ac->getTrafficRef()->getCourse(); apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading); - rwy = apt->getRunwayByIdent(activeRunway); - - + FGRunway * rwy = apt->getRunwayByIdent(activeRunway); + assert( rwy != NULL ); // Create a slow descent path that ends 250 lateral to the runway. double initialTurnRadius = getTurnRadius(vDescent, true); @@ -592,7 +628,17 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, } - double dAlt = alt - (apt->getElevation() + 2000); + double dAlt = 0; // = alt - (apt->getElevation() + 2000); + FGTaxiNode * tn = 0; + if (apt->getDynamics()->getGroundNetwork()) { + int node = apt->getDynamics()->getGroundNetwork()->findNearestNode(refPoint); + tn = apt->getDynamics()->getGroundNetwork()->findNode(node); + } + if (tn) { + dAlt = alt - ((tn->getElevationFt(apt->getElevation())) + 2000); + } else { + dAlt = alt - (apt->getElevation() + 2000); + } double nPoints = 100; @@ -609,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; @@ -682,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; @@ -707,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; @@ -721,7 +767,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, wpt = createInAir(ac, buffer, result, currentAltitude, vDescent); wpt->setCrossat(currentAltitude); wpt->setTrackLength((newDistance / nPoints)); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); //cerr << "Track Length : " << wpt->trackLength; //cerr << " Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl; } @@ -754,10 +800,19 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, } //cerr << "creating circle between " << startval << " and " << endval << " using " << increment << endl; + //FGTaxiNode * tn = apt->getDynamics()->getGroundNetwork()->findNearestNode(initialTarget); + double currentAltitude = 0; + if (tn) { + currentAltitude = (tn->getElevationFt(apt->getElevation())) + 2000; + } else { + currentAltitude = apt->getElevation() + 2000; + } + double trackLength = (2 * M_PI * initialTurnRadius) / 360.0; for (int i = startval; i != endval; i += increment) { SGGeod result; - double currentAltitude = apt->getElevation() + 2000; + //double currentAltitude = apt->getElevation() + 2000; + SGGeodesy::direct(secondaryTarget, i, initialTurnRadius, result, dummyAz2); snprintf(buffer, 16, "turn%03d", i); @@ -765,31 +820,39 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, wpt->setCrossat(currentAltitude); wpt->setTrackLength(trackLength); //cerr << "Track Length : " << wpt->trackLength; - waypoints.push_back(wpt); + pushBackWaypoint(wpt); //cerr << " Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl; } - // The approach leg should bring the aircraft to approximately 4-6 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; + double tgt_speed = vApproach; distanceOut -= distanceCovered; + double touchDownPoint = 0; //(rwy->lengthM() * 0.1); for (int i = 1; i < nPoints; i++) { SGGeod result; double currentDist = i * (distanceOut / nPoints); - double currentAltitude = - apt->getElevation() + 2000 - (i * 2000 / nPoints); + //double currentAltitude = + // apt->getElevation() + 2000 - (i * 2000 / (nPoints-1)); + double alt = currentAltitude - (i * 2000 / (nPoints - 1)); snprintf(buffer, 16, "final%03d", i); - result = rwy->pointOnCenterline((-distanceOut) + currentDist); - wpt = createInAir(ac, buffer, result, currentAltitude, vApproach); - wpt->setCrossat(currentAltitude); + result = rwy->pointOnCenterline((-distanceOut) + currentDist + touchDownPoint); + if (i == nPoints - 30) { + tgt_speed = vTouchdown; + } + wpt = createInAir(ac, buffer, result, alt, tgt_speed); + wpt->setCrossat(alt); wpt->setTrackLength((distanceOut / nPoints)); // account for the extra distance due to an extended downwind leg if (i == 1) { wpt->setTrackLength(wpt->getTrackLength() + distanceCovered); } //cerr << "Track Length : " << wpt->trackLength; - waypoints.push_back(wpt); - //cerr << " Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl; + pushBackWaypoint(wpt); + //if (apt->ident() == fgGetString("/sim/presets/airport-id")) { + // cerr << " Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << " " << apt->getElevation() << " " << distanceOut << endl; + //} } //cerr << "Done" << endl; @@ -821,6 +884,8 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, //cerr << "Repositioning to waypoint " << (*waypoints.begin())->name << endl; ac->resetPositionFromFlightPlan(); } + waypoints[1]->setName( (waypoints[1]->getName() + string("legend"))); + waypoints.back()->setName(waypoints.back()->getName() + "LandingThreshold"); return true; } @@ -829,12 +894,18 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, * 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. + Position : 50.0354 8.52592 384 364 11112 ******************************************************************/ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt, const string & fltType) { double vTouchdown = ac->getPerformance()->vTouchdown(); - //double vTaxi = ac->getPerformance()->vTaxi(); + double vTaxi = ac->getPerformance()->vTaxi(); + double decel = ac->getPerformance()->deceleration() * 1.4; + + double vTouchdownMetric = (vTouchdown * SG_NM_TO_METER) / 3600; + double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600; + double decelMetric = (decel * SG_NM_TO_METER) / 3600; //string rwyClass = getRunwayClassFromTrafficType(fltType); //double heading = ac->getTrafficRef()->getCourse(); @@ -843,32 +914,95 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt, FGAIWaypoint *wpt; - double aptElev = apt->getElevation(); + //double aptElev = apt->getElevation(); + double currElev = 0; + char buffer[12]; + FGRunway * rwy = apt->getRunwayByIdent(activeRunway); + assert( rwy != NULL ); + SGGeod refPoint = rwy->pointOnCenterline(0); + FGTaxiNode *tn = 0; + if (apt->getDynamics()->getGroundNetwork()) { + int node = apt->getDynamics()->getGroundNetwork()->findNearestNode(refPoint); + tn = apt->getDynamics()->getGroundNetwork()->findNode(node); + } + if (tn) { + currElev = tn->getElevationFt(apt->getElevation()); + } else { + currElev = apt->getElevation(); + } + SGGeod coord; - char buffer[12]; - for (int i = 1; i < 10; i++) { - snprintf(buffer, 12, "wpt%d", i); - coord = rwy->pointOnCenterline(rwy->lengthM() * (i / 10.0)); - wpt = createOnGround(ac, buffer, coord, aptElev, (vTouchdown / i)); - wpt->setCrossat(apt->getElevation()); - waypoints.push_back(wpt); + + + /*double distanceOut = rwy->lengthM() * .1; + double nPoints = 20; + for (int i = 1; i < nPoints; i++) { + snprintf(buffer, 12, "flare%d", i); + double currentDist = i * (distanceOut / nPoints); + double currentAltitude = apt->getElevation() + 20 - (i * 20 / nPoints); + coord = rwy->pointOnCenterline((currentDist * (i / nPoints))); + wpt = createInAir(ac, buffer, coord, currentAltitude, (vTouchdown)); + }*/ + double rolloutDistance = + (vTouchdownMetric * vTouchdownMetric - vTaxiMetric * vTaxiMetric) / (2 * decelMetric); + //cerr << " touchdown speed = " << vTouchdown << ". Rollout distance " << rolloutDistance << endl; + int nPoints = 50; + for (int i = 1; i < nPoints; i++) { + snprintf(buffer, 12, "landing03%d", i); + + coord = rwy->pointOnCenterline((rolloutDistance * ((double) i / (double) nPoints))); + wpt = createOnGround(ac, buffer, coord, currElev, 2*vTaxi); + wpt->setCrossat(currElev); + pushBackWaypoint(wpt); + } + wpt->setSpeed(vTaxi); + double mindist = 1.1 * rolloutDistance; + double maxdist = rwy->lengthM(); + //cerr << "Finding nearest exit" << endl; + FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork(); + if (gn) { + double min = 0; + for (int i = ceil(mindist); i < floor(maxdist); i++) { + coord = rwy->pointOnCenterline(mindist); + int nodeId = 0; + if (gn->getVersion() > 0) { + nodeId = gn->findNearestNodeOnRunway(coord); + } else { + nodeId = gn->findNearestNode(coord); + } + if (tn) + tn = gn->findNode(nodeId); + if (!tn) + break; + + double dist = SGGeodesy::distanceM(coord, tn->geod()); + if (dist < (min + 0.75)) { + break; + } + min = dist; + } + if (tn) { + wpt = createOnGround(ac, buffer, tn->geod(), currElev, vTaxi); + pushBackWaypoint(wpt); + } } + //cerr << "Done. " << endl; /* //Runway Threshold wpt = createOnGround(ac, "Threshold", rwy->threshold(), aptElev, vTouchdown); wpt->crossat = apt->getElevation(); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); // Roll-out wpt = createOnGround(ac, "Center", rwy->geod(), aptElev, vTaxi*2); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); SGGeod rollOut = rwy->pointOnCenterline(rwy->lengthM() * 0.9); wpt = createOnGround(ac, "Roll Out", rollOut, aptElev, vTaxi); wpt->crossat = apt->getElevation(); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); */ return true; } @@ -882,36 +1016,35 @@ 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); - waypoints.push_back(wpt); - - geo_direct_wgs_84(0, lat, lon, heading, - 0.1 * radius, &lat2, &lon2, &az2); + FGParking* parking = apt->getDynamics()->getParking(gateId); + if (!parking) { + wpt = createOnGround(ac, "END-Parking", apt->geod(), aptElev, + vTaxiReduced); + pushBackWaypoint(wpt); - wpt = - createOnGround(ac, "taxiStart2", SGGeod::fromDeg(lon2, lat2), - aptElev, vTaxiReduced); - waypoints.push_back(wpt); - - wpt = - createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev, + 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); + + 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", parking->geod(), aptElev, vTaxiReduced); - waypoints.push_back(wpt); + pushBackWaypoint(wpt); return true; }