1
0
Fork 0
* Parking on parking with right heading
* Leg 6 Descent improved (teardrop like entry)
* Inner/Outer tangents in VectorMath TODO Move to SG
This commit is contained in:
portree_kid 2022-08-29 21:05:49 +02:00
parent 3ee54cbd72
commit e85e5d2e5b
13 changed files with 611 additions and 266 deletions

View file

@ -333,7 +333,9 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
dt_count = 0; dt_count = 0;
double distanceToDescent; double distanceToDescent;
if (reachedEndOfCruise(distanceToDescent)) { // Not the best solution. Double adding of legs is possible
if (*fp->getLastWayPoint() == fp->getNextWaypoint() &&
reachedEndOfCruise(distanceToDescent)) {
if (!loadNextLeg(distanceToDescent)) { if (!loadNextLeg(distanceToDescent)) {
setDie(true); setDie(true);
return; return;
@ -591,7 +593,6 @@ bool FGAIAircraft::loadNextLeg(double distance) {
FGAirport *arr = trafficRef->getArrivalAirport(); FGAirport *arr = trafficRef->getArrivalAirport();
if (!(dep && arr)) { if (!(dep && arr)) {
setDie(true); setDie(true);
} else { } else {
double cruiseAlt = trafficRef->getCruiseAlt() * 100; double cruiseAlt = trafficRef->getCruiseAlt() * 100;
@ -1473,7 +1474,7 @@ bool FGAIAircraft::reachedEndOfCruise(double &distance) {
distance = distanceCoveredByDescent; distance = distanceCoveredByDescent;
if (dist < distanceCoveredByDescent) { if (dist < distanceCoveredByDescent) {
SG_LOG(SG_AI, SG_BULK, "End Of Cruise"); SG_LOG(SG_AI, SG_BULK, getCallSign() << "|End Of Cruise");
return true; return true;
} else { } else {
return false; return false;

View file

@ -131,16 +131,19 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename) :
} }
// This is a modified version of the constructor, /**
// Which not only reads the waypoints from a * This is a modified version of the constructor,
// Flight plan file, but also adds the current * Which not only reads the waypoints from a
// Position computed by the traffic manager, as well * Flight plan file, but also adds the current
// as setting speeds and altitude computed by the * Position computed by the traffic manager, as well
// traffic manager. * as setting speeds and altitude computed by the
* traffic manager.
*/
FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac, FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
const std::string& p, const std::string& p,
double course, double course,
time_t start, time_t start,
time_t remainingTime,
FGAirport *dep, FGAirport *dep,
FGAirport *arr, FGAirport *arr,
bool firstLeg, bool firstLeg,
@ -168,7 +171,7 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
if (parseProperties(p)) { if (parseProperties(p)) {
isValid = true; isValid = true;
} else { } else {
createWaypoints(ac, course, start, dep, arr, firstLeg, radius, createWaypoints(ac, course, start, remainingTime, dep, arr, firstLeg, radius,
alt, lat, lon, speed, fltType, acType, airline); alt, lat, lon, speed, fltType, acType, airline);
} }
} }
@ -182,6 +185,7 @@ FGAIFlightPlan::~FGAIFlightPlan()
void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac, void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac,
double course, double course,
time_t start, time_t start,
time_t remainingTime,
FGAirport *dep, FGAirport *dep,
FGAirport *arr, FGAirport *arr,
bool firstLeg, bool firstLeg,
@ -196,25 +200,22 @@ void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac,
{ {
time_t now = globals->get_time_params()->get_cur_time(); time_t now = globals->get_time_params()->get_cur_time();
time_t timeDiff = now-start; time_t timeDiff = now-start;
leg = 1; leg = AILeg::STARTUP_PUSHBACK;
if ((timeDiff > 60) && (timeDiff < 1500)) if ((timeDiff > 60) && (timeDiff < 1500))
leg = 2; leg = AILeg::TAXI;
//else if ((timeDiff >= 1200) && (timeDiff < 1500)) {
//leg = 3;
//ac->setTakeOffStatus(2);
//}
else if ((timeDiff >= 1500) && (timeDiff < 2000)) else if ((timeDiff >= 1500) && (timeDiff < 2000))
leg = 4; leg = AILeg::TAKEOFF;
else if (timeDiff >= 2000) else if (timeDiff >= 2000) {
leg = 5; if (remainingTime > 2000) {
/* leg = AILeg::CRUISE;
if (timeDiff >= 2000) } else {
leg = 5; leg = AILeg::APPROACH;
*/ }
}
SG_LOG(SG_AI, SG_DEBUG, "Route from " << dep->getId() << " to " << arr->getId() << SG_LOG(SG_AI, SG_DEBUG, ac->getTrafficRef()->getCallSign() << "|Route from " << dep->getId() << " to " << arr->getId() <<
". Set leg to : " << leg << " " << ac->getTrafficRef()->getCallSign()); ". Set leg to : " << leg << " " << remainingTime);
wpt_iterator = waypoints.begin(); wpt_iterator = waypoints.begin();
bool dist = 0; bool dist = 0;
@ -392,6 +393,8 @@ void FGAIFlightPlan::IncrementWaypoint(bool eraseWaypoints )
return; return;
if (wpt_iterator+1 == waypoints.end()) if (wpt_iterator+1 == waypoints.end())
return; return;
if (waypoints.size()<3)
return;
FGAIWaypoint* previousWP = *(wpt_iterator -1); FGAIWaypoint* previousWP = *(wpt_iterator -1);
FGAIWaypoint* currentWP = *(wpt_iterator); FGAIWaypoint* currentWP = *(wpt_iterator);
FGAIWaypoint* nextWP = *(wpt_iterator + 1); FGAIWaypoint* nextWP = *(wpt_iterator + 1);

View file

@ -137,6 +137,7 @@ public:
const std::string& p, const std::string& p,
double course, double course,
time_t start, time_t start,
time_t remainingTime,
FGAirport *dep, FGAirport *dep,
FGAirport *arr, FGAirport *arr,
bool firstLeg, bool firstLeg,
@ -276,7 +277,7 @@ private:
/**Create an arc flightplan around a center from startAngle to endAngle.*/ /**Create an arc flightplan around a center from startAngle to endAngle.*/
void createArc(FGAIAircraft *ac, const SGGeod& center, int startAngle, int endAngle, int increment, int radius, double aElev, double aSpeed, const char* pattern); void createArc(FGAIAircraft *ac, const SGGeod& center, int startAngle, int endAngle, int increment, int radius, double aElev, double aSpeed, const char* pattern);
void createLine(FGAIAircraft *ac, const SGGeod& startPoint, double azimuth, double dist, double dAlt, double vDescent); void createLine(FGAIAircraft *ac, const SGGeod& startPoint, double azimuth, double dist, double dAlt, double vDescent, const char* pattern);
bool createLandingTaxi(FGAIAircraft *, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline); bool createLandingTaxi(FGAIAircraft *, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport); void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport);
void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway); void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
@ -300,9 +301,14 @@ private:
*/ */
bool parseProperties(const std::string& filename); bool parseProperties(const std::string& filename);
/**
* Creates the waypoints for this Flightplan.
*/
void createWaypoints(FGAIAircraft *ac, void createWaypoints(FGAIAircraft *ac,
double course, double course,
time_t start, time_t start,
time_t remainingTime,
FGAirport *dep, FGAirport *dep,
FGAirport *arr, FGAirport *arr,
bool firstLeg, bool firstLeg,

View file

@ -69,9 +69,9 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
const string & aircraftType, const string & aircraftType,
const string & airline, double distance) const string & airline, double distance)
{ {
if( legNr <= 3 ) if( legNr <= AILeg::TAKEOFF )
SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " At Airport : " << dep->getId()); 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<= AILeg::APPROACH )
SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " Departure Airport : " << dep->getId() << " Arrival Airport : " << arr->getId()); 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()); SG_LOG(SG_AI, SG_BULK, "Create Leg " << legNr << " " << (firstFlight?"First":"") << " Old Leg " << getLeg() << " At Airport : " << arr->getId());
@ -79,35 +79,35 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
bool retVal = true; bool retVal = true;
int currWpt = wpt_iterator - waypoints.begin(); int currWpt = wpt_iterator - waypoints.begin();
switch (legNr) { switch (legNr) {
case 1: case AILeg::STARTUP_PUSHBACK:
retVal = createPushBack(ac, firstFlight, dep, retVal = createPushBack(ac, firstFlight, dep,
radius, fltType, aircraftType, airline); radius, fltType, aircraftType, airline);
break; break;
case 2: case AILeg::TAXI:
retVal = createTakeoffTaxi(ac, firstFlight, dep, radius, fltType, retVal = createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
aircraftType, airline); aircraftType, airline);
break; break;
case 3: case AILeg::TAKEOFF:
retVal = createTakeOff(ac, firstFlight, dep, SGGeod::fromDeg(longitude, latitude), speed, fltType); retVal = createTakeOff(ac, firstFlight, dep, SGGeod::fromDeg(longitude, latitude), speed, fltType);
break; break;
case 4: case AILeg::CLIMB:
retVal = createClimb(ac, firstFlight, dep, arr, speed, alt, fltType); retVal = createClimb(ac, firstFlight, dep, arr, speed, alt, fltType);
break; break;
case 5: case AILeg::CRUISE:
retVal = createCruise(ac, firstFlight, dep, arr, SGGeod::fromDeg(longitude, latitude), speed, retVal = createCruise(ac, firstFlight, dep, arr, SGGeod::fromDeg(longitude, latitude), speed,
alt, fltType); alt, fltType);
break; break;
case 6: case AILeg::APPROACH:
retVal = createDescent(ac, arr, SGGeod::fromDeg(longitude, latitude), speed, alt, fltType, retVal = createDescent(ac, arr, SGGeod::fromDeg(longitude, latitude), speed, alt, fltType,
distance); distance);
break; break;
case 7: case AILeg::LANDING:
retVal = createLanding(ac, arr, fltType); retVal = createLanding(ac, arr, fltType);
break; break;
case 8: case AILeg::PARKING_TAXI:
retVal = createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline); retVal = createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
break; break;
case 9: case AILeg::PARKING:
retVal = createParking(ac, arr, radius); retVal = createParking(ac, arr, radius);
break; break;
default: default:
@ -202,7 +202,7 @@ int endAngle, int increment, int radius, double aElev, double aSpeed, const char
} }
} }
void FGAIFlightPlan::createLine( FGAIAircraft *ac, const SGGeod& startPoint, double azimuth, double dist, double dAlt, double vDescent) { void FGAIFlightPlan::createLine( FGAIAircraft *ac, const SGGeod& startPoint, double azimuth, double dist, double dAlt, double vDescent, const char* pattern) {
SGGeod dummyAz2; SGGeod dummyAz2;
double nPoints = dist/(vDescent/2); double nPoints = dist/(vDescent/2);
char buffer[20]; char buffer[20];
@ -211,7 +211,7 @@ void FGAIFlightPlan::createLine( FGAIAircraft *ac, const SGGeod& startPoint, dou
double currentDist = i * (dist / nPoints); double currentDist = i * (dist / nPoints);
double currentAltitude = ac->getAltitude() - (i * (dAlt / nPoints)); double currentAltitude = ac->getAltitude() - (i * (dAlt / nPoints));
SGGeod result = SGGeodesy::direct(startPoint, azimuth, currentDist); SGGeod result = SGGeodesy::direct(startPoint, azimuth, currentDist);
snprintf(buffer, sizeof(buffer), "descent%03d", i); snprintf(buffer, sizeof(buffer), pattern, i);
FGAIWaypoint* wpt = createInAir(ac, buffer, result, currentAltitude, vDescent); FGAIWaypoint* wpt = createInAir(ac, buffer, result, currentAltitude, vDescent);
wpt->setCrossat(currentAltitude); wpt->setCrossat(currentAltitude);
wpt->setTrackLength((dist / nPoints)); wpt->setTrackLength((dist / nPoints));
@ -744,9 +744,11 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
* 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 * the permission to land point
******************************************************************/ ******************************************************************/
bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt, bool FGAIFlightPlan::createDescent(FGAIAircraft * ac,
FGAirport * apt,
const SGGeod& current, const SGGeod& current,
double speed, double alt, double speed,
double alt,
const string & fltType, const string & fltType,
double requiredDistance) double requiredDistance)
{ {
@ -762,16 +764,21 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
//Beginning of Descent //Beginning of Descent
const string& rwyClass = getRunwayClassFromTrafficType(fltType); const string& rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse(); double heading = ac->getTrueHeadingDeg();
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
heading); heading);
if (!apt->hasRunwayWithIdent(activeRunway)) if (!apt->hasRunwayWithIdent(activeRunway))
return false; return false;
FGRunwayRef rwy = apt->getRunwayByIdent(activeRunway); FGRunwayRef rwy = apt->getRunwayByIdent(activeRunway);
if (waypoints.size()==0 && ac->getTrueHeadingDeg()==0) {
// we obviously have no previous state and are free to position the aircraft
double courseTowardsThreshold = SGGeodesy::courseDeg(current, rwy->pointOnCenterlineDisplaced(0));
ac->setHeading(courseTowardsThreshold);
}
// depending on entry we differ approach (teardrop/direct/parallel) // depending on entry we differ approach (teardrop/direct/parallel)
// Create a slow descent path that ends 250 lateral to the runway.
double initialTurnRadius = getTurnRadius(vDescent, true); double initialTurnRadius = getTurnRadius(vDescent, true);
//double finalTurnRadius = getTurnRadius(vApproach, true); //double finalTurnRadius = getTurnRadius(vApproach, true);
@ -787,6 +794,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
} }
SGGeod initialTarget = rwy->pointOnCenterline(-distanceOut); SGGeod initialTarget = rwy->pointOnCenterline(-distanceOut);
SGGeod otherRwyEnd = rwy->pointOnCenterline(rwy->lengthM());
SGGeod secondaryTarget = SGGeod secondaryTarget =
rwy->pointOffCenterline(-2 * distanceOut, lateralOffset); rwy->pointOffCenterline(-2 * distanceOut, lateralOffset);
SGGeod secondHoldCenter = SGGeod secondHoldCenter =
@ -797,50 +805,204 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
double secondaryAzimuth = SGGeodesy::courseDeg(current, secondaryTarget); double secondaryAzimuth = SGGeodesy::courseDeg(current, secondaryTarget);
double initialHeadingDiff = SGMiscd::normalizePeriodic(-180, 180, azimuth-secondaryAzimuth); double initialHeadingDiff = SGMiscd::normalizePeriodic(-180, 180, azimuth-secondaryAzimuth);
double dummyAz2; double dummyAz2;
double courseTowardsThreshold = SGGeodesy::courseDeg(current, rwy->pointOnCenterlineDisplaced(0));
double courseTowardsRwyEnd = SGGeodesy::courseDeg(current, otherRwyEnd);
double headingDiffToRunwayThreshold = SGMiscd::normalizePeriodic(-180, 180, ac->getTrueHeadingDeg() - courseTowardsThreshold);
double headingDiffToRunwayEnd = SGMiscd::normalizePeriodic(-180, 180, ac->getTrueHeadingDeg() - courseTowardsRwyEnd);
SG_LOG(SG_AI, SG_BULK, " Heading Diff " << headingDiffRunway << SG_LOG(SG_AI, SG_BULK, ac->getCallSign() <<
" Distance " << distance << "| " <<
" WPs : " << waypoints.size() <<
" Heading Diff (rwy) : " << headingDiffRunway <<
" Distance : " << distance <<
" Azimuth : " << azimuth << " Azimuth : " << azimuth <<
" Heading : " << ac->getTrueHeadingDeg() << " Lateral : " << lateralOffset); " Heading : " << ac->getTrueHeadingDeg() <<
" Initial Headingdiff " << initialHeadingDiff <<
" Lateral : " << lateralOffset);
// Erase the two bogus BOD points: Note check for conflicts with scripted AI flightPlans
IncrementWaypoint(false);
IncrementWaypoint(false);
if (fabs(headingDiffRunway)>=30) { if (fabs(headingDiffRunway)>=30 && fabs(headingDiffRunway)<=150 ) {
// Entering not "straight" into runway so we do a s-curve if (distance < (2*initialTurnRadius)) {
int rightAngle = initialHeadingDiff<0?90:-90; // Too near so we pass over and enter over other side
SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius); SG_LOG(SG_AI, SG_BULK, ac->getCallSign() << "| Enter near S curve");
int firstTurnIncrement = initialHeadingDiff<0?2:-2; secondaryTarget =
const double heading = VectorMath::innerTangentsAngle(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius )[0]; rwy->pointOffCenterline(-2 * distanceOut, -lateralOffset);
createArc(ac, firstTurnCenter, ac->_getHeading()-rightAngle, heading-rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "initialturn%03d"); secondHoldCenter =
double length = VectorMath::innerTangentsLength(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius ); rwy->pointOffCenterline(-3 * distanceOut, -lateralOffset);
createLine(ac, waypoints.back()->getPos(), heading, length, 50, vDescent);
int holdsPatterns = 0; // Entering not "straight" into runway so we do a s-curve
// Length of int rightAngle = headingDiffRunway>0?90:-90;
if (holdsPatterns>0) { int firstTurnIncrement = headingDiffRunway>0?2:-2;
// Turn into hold
createArc(ac, secondaryTarget, heading+rightAngle, rwy->headingDeg()+rightAngle, firstTurnIncrement*-1, initialTurnRadius, SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
waypoints.back()->getAltitude(), vDescent, "turnintohold%03d"); SGGeod newCurrent = current;
for (int t = 0; t < holdsPatterns; t++) // If we are not far enough cross over
{ if (abs(headingDiffToRunwayThreshold)<90) {
/* newCurrent = SGGeodesy::direct(current, ac->getTrueHeadingDeg(), distance + 1000);
createArc(ac, secondaryTarget, endval, endval+180, increment, initialTurnRadius, firstTurnCenter = SGGeodesy::direct(newCurrent, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
currentAltitude, vDescent, "hold_1_%03d"); createLine(ac, current, ac->getTrueHeadingDeg(), distance + 1000, 50, vDescent, "move%03d");
createArc(ac, secondHoldCenter, endval+180, endval, increment, initialTurnRadius, }
currentAltitude, vDescent, "hold_2_%03d"); int offset = 1000;
*/ while (SGGeodesy::distanceM(firstTurnCenter, secondaryTarget) < 2*initialTurnRadius) {
newCurrent = SGGeodesy::direct(newCurrent, ac->getTrueHeadingDeg(), offset+=100);
firstTurnCenter = SGGeodesy::direct(newCurrent, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
}
const double heading = VectorMath::outerTangentsAngle(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius )[0];
createArc(ac, firstTurnCenter, ac->_getHeading()-rightAngle, heading-rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "near-initialturn%03d");
double length = VectorMath::innerTangentsLength(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius );
createLine(ac, waypoints.back()->getPos(), heading, length, 50, vDescent, "descent%03d");
int holdsPatterns = 0;
// Length of
if (holdsPatterns>0) {
// Turn into hold
createArc(ac, secondaryTarget, heading+rightAngle, rwy->headingDeg()+rightAngle, firstTurnIncrement*-1, initialTurnRadius,
waypoints.back()->getAltitude(), vDescent, "turnintohold%03d");
for (int t = 0; t < holdsPatterns; t++)
{
/*
createArc(ac, secondaryTarget, endval, endval+180, increment, initialTurnRadius,
currentAltitude, vDescent, "hold_1_%03d");
createArc(ac, secondHoldCenter, endval+180, endval, increment, initialTurnRadius,
currentAltitude, vDescent, "hold_2_%03d");
*/
}
} else {
int startVal = SGMiscd::normalizePeriodic(0, 360, heading-rightAngle);
int endVal = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg()-rightAngle);
// Turn into runway
createArc(ac, secondaryTarget, startVal ,endVal , firstTurnIncrement, initialTurnRadius,
waypoints.back()->getAltitude(), vDescent, "turn%03d");
} }
} else { } else {
int startVal = SGMiscd::normalizePeriodic(0, 360, heading+rightAngle); SG_LOG(SG_AI, SG_BULK, ac->getCallSign() << "| Enter far S curve");
int endVal = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg()+rightAngle); // Entering not "straight" into runway so we do a s-curve
// Turn into runway int rightAngle = headingDiffRunway>0?90:-90;
createArc(ac, secondaryTarget, startVal, endVal, firstTurnIncrement*-1, initialTurnRadius, int firstTurnIncrement = headingDiffRunway>0?2:-2;
waypoints.back()->getAltitude(), vDescent, "turn%03d"); SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
int innerTangent = headingDiffRunway<0?0:1;
int offset = 1000;
while (SGGeodesy::distanceM(firstTurnCenter, secondaryTarget)<2*initialTurnRadius) {
secondaryTarget = rwy->pointOffCenterline(-2 * distanceOut + (offset+=1000), lateralOffset);
}
const double heading = VectorMath::innerTangentsAngle(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius )[innerTangent];
createArc(ac, firstTurnCenter, ac->_getHeading()-rightAngle, heading-rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "far-initialturn%03d");
double length = VectorMath::innerTangentsLength(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius );
createLine(ac, waypoints.back()->getPos(), heading, length, 50, vDescent, "descent%03d");
int holdsPatterns = 0;
// Length of
if (holdsPatterns>0) {
// Turn into hold
createArc(ac, secondaryTarget, heading+rightAngle, rwy->headingDeg()+rightAngle, firstTurnIncrement*-1, initialTurnRadius,
waypoints.back()->getAltitude(), vDescent, "turnintohold%03d");
for (int t = 0; t < holdsPatterns; t++)
{
/*
createArc(ac, secondaryTarget, endval, endval+180, increment, initialTurnRadius,
currentAltitude, vDescent, "hold_1_%03d");
createArc(ac, secondHoldCenter, endval+180, endval, increment, initialTurnRadius,
currentAltitude, vDescent, "hold_2_%03d");
*/
}
} else {
int startVal = SGMiscd::normalizePeriodic(0, 360, heading+rightAngle);
int endVal = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg()+rightAngle);
// Turn into runway
createArc(ac, secondaryTarget, startVal, endVal, firstTurnIncrement*-1, initialTurnRadius,
waypoints.back()->getAltitude(), vDescent, "s-turn%03d");
}
}
} else if (fabs(headingDiffRunway)>=150 ) {
// We are entering downwind
if (distance < (2*initialTurnRadius)) {
// Too near so we pass over and enter over other side
SG_LOG(SG_AI, SG_BULK, ac->getCallSign() << "| Enter near downrunway");
secondaryTarget =
rwy->pointOffCenterline(-2 * distanceOut, -lateralOffset);
secondHoldCenter =
rwy->pointOffCenterline(-3 * distanceOut, -lateralOffset);
// Entering not "straight" into runway so we do a s-curve
int rightAngle = azimuth>0?90:-90;
int firstTurnIncrement = azimuth>0?2:-2;
SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
// rwy->headingDeg()-rightAngle
int endVal = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg()-180);
SGGeod secondTurnCenter = SGGeodesy::direct(firstTurnCenter, endVal, 2*initialTurnRadius);
createArc(ac, firstTurnCenter, ac->_getHeading()-rightAngle, endVal, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "d-near-initialturn%03d");
endVal = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg());
// int endVal2 = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg()-rightAngle);
const double endVal2 = VectorMath::outerTangentsAngle(secondTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius )[0];
createArc(ac, secondTurnCenter, endVal, endVal2+rightAngle, -firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "secondturn%03d");
//outer
double length = VectorMath::outerTangentsLength(secondTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius );
int reverseRwyHeading = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg() - 180);
createLine(ac, waypoints.back()->getPos(), endVal2, length, 50, vDescent, "descent%03d");
int holdsPatterns = 0;
// Length of
if (holdsPatterns>0) {
// Turn into hold
createArc(ac, secondaryTarget, heading+rightAngle, rwy->headingDeg()+rightAngle, firstTurnIncrement*-1, initialTurnRadius,
waypoints.back()->getAltitude(), vDescent, "turnintohold%03d");
for (int t = 0; t < holdsPatterns; t++)
{
/*
createArc(ac, secondaryTarget, endval, endval+180, increment, initialTurnRadius,
currentAltitude, vDescent, "hold_1_%03d");
createArc(ac, secondHoldCenter, endval+180, endval, increment, initialTurnRadius,
currentAltitude, vDescent, "hold_2_%03d");
*/
}
} else {
int endVal = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg()+rightAngle);
// Turn into runway
createArc(ac, secondaryTarget, endVal2+rightAngle, endVal, -firstTurnIncrement, initialTurnRadius,
waypoints.back()->getAltitude(), vDescent, "turn%03d");
}
} else {
SG_LOG(SG_AI, SG_BULK, ac->getCallSign() << "| Enter far S downrunway");
// Entering not "straight" into runway so we do a s-curve
int rightAngle = azimuth<0?90:-90;
int firstTurnIncrement = azimuth<0?2:-2;
int innerTangent = headingDiffRunway<0?0:1;
SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
const double heading = VectorMath::innerTangentsAngle(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius )[innerTangent];
createArc(ac, firstTurnCenter, ac->_getHeading()-rightAngle, heading-rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "d-far-initialturn%03d");
double length = VectorMath::innerTangentsLength(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius );
createLine(ac, waypoints.back()->getPos(), heading, length, 50, vDescent, "descent%03d");
int holdsPatterns = 0;
// Length of
if (holdsPatterns>0) {
// Turn into hold
createArc(ac, secondaryTarget, heading+rightAngle, rwy->headingDeg()+rightAngle, firstTurnIncrement*-1, initialTurnRadius,
waypoints.back()->getAltitude(), vDescent, "turnintohold%03d");
for (int t = 0; t < holdsPatterns; t++)
{
/*
createArc(ac, secondaryTarget, endval, endval+180, increment, initialTurnRadius,
currentAltitude, vDescent, "hold_1_%03d");
createArc(ac, secondHoldCenter, endval+180, endval, increment, initialTurnRadius,
currentAltitude, vDescent, "hold_2_%03d");
*/
}
} else {
int startVal = SGMiscd::normalizePeriodic(0, 360, heading+rightAngle);
int endVal = SGMiscd::normalizePeriodic(0, 360, rwy->headingDeg()+rightAngle);
// Turn into runway
createArc(ac, secondaryTarget, startVal, endVal, -firstTurnIncrement, initialTurnRadius,
waypoints.back()->getAltitude(), vDescent, "d-s-turn%03d");
}
} }
} else { } else {
SG_LOG(SG_AI, SG_BULK, ac->getCallSign() << "| Enter far straight");
// Entering "straight" into runway so only one turn // Entering "straight" into runway so only one turn
int rightAngle = headingDiffRunway>0?90:-90; int rightAngle = headingDiffRunway>0?90:-90;
SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() - rightAngle, initialTurnRadius); SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() - rightAngle, initialTurnRadius);
int firstTurnIncrement = headingDiffRunway>0?-2:2; int firstTurnIncrement = headingDiffRunway>0?-2:2;
const double heading = rwy->headingDeg(); const double heading = rwy->headingDeg();
createArc(ac, firstTurnCenter, ac->_getHeading()+rightAngle, heading+rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "initialturn_%03d"); createArc(ac, secondaryTarget, ac->_getHeading()+rightAngle, heading+rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "straight_turn_%03d");
} }
// To prevent absurdly steep approaches, compute the origin from where the approach should have started // To prevent absurdly steep approaches, compute the origin from where the approach should have started
@ -861,55 +1023,12 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
azimuth = SGGeodesy::courseDeg(origin, initialTarget); azimuth = SGGeodesy::courseDeg(origin, initialTarget);
} }
double dAlt = 0; // = alt - (apt->getElevation() + 2000);
FGTaxiNodeRef tn;
if (apt->groundNetwork()) {
tn = apt->groundNetwork()->findNearestNode(refPoint);
}
if (tn) {
dAlt = alt - ((tn->getElevationFt()) + 2000);
} else {
dAlt = alt - (apt->getElevation() + 2000);
}
//cerr << "Phase 1: Linear Descent path to runway" << rwy->name() << endl;
// Create an initial destination point on a semicircle
//cerr << "lateral offset : " << lateralOffset << endl;
//cerr << "Distance : " << distance << endl;
//cerr << "Azimuth : " << azimuth << endl;
//cerr << "Initial Lateral point: " << lateralOffset << endl;
// double lat = refPoint.getLatitudeDeg();
// double lon = refPoint.getLongitudeDeg();
//cerr << "Reference point (" << lat << ", " << lon << ")." << endl;
// lat = initialTarget.getLatitudeDeg();
// lon = initialTarget.getLongitudeDeg();
//cerr << "Initial Target point (" << lat << ", " << lon << ")." << endl;
#if 0
double ratio = initialTurnRadius / distance;
if (ratio > 1.0)
ratio = 1.0;
if (ratio < -1.0)
ratio = -1.0;
double newHeading = asin(ratio) * SG_RADIANS_TO_DEGREES;
double newDistance =
cos(newHeading * SG_DEGREES_TO_RADIANS) * distance;
//cerr << "new distance " << newDistance << ". additional Heading " << newHeading << endl;
#endif
double side = azimuth - rwy->headingDeg();
if (side < 0.0)
side += 360.0;
// Calculate the ETA at final, based on remaining distance, and approach speed. // 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 // 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" // aditionally add the amount of distance covered by making a turn of "side"
double turnDistance = (2 * M_PI * initialTurnRadius) * (side / 360.0);
time_t remaining = time_t remaining =
(turnDistance + distance) / ((vDescent * SG_NM_TO_METER) / 3600.0); (initialTurnRadius + distance) / ((vDescent * SG_NM_TO_METER) / 3600.0);
time_t now = globals->get_time_params()->get_cur_time(); time_t now = globals->get_time_params()->get_cur_time();
//if (ac->getTrafficRef()->getCallSign() == fgGetString("/ai/track-callsign")) { //if (ac->getTrafficRef()->getCallSign() == fgGetString("/ai/track-callsign")) {
@ -940,110 +1059,6 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
additionalTimeNeeded -= holdsPatterns*240; additionalTimeNeeded -= holdsPatterns*240;
double distanceCovered =
((vApproach * SG_NM_TO_METER) / 3600.0) * additionalTimeNeeded;
distanceOut += distanceCovered;
azimuth = SGGeodesy::courseDeg(origin, secondaryTarget);
distance = SGGeodesy::distanceM(origin, secondaryTarget);
double ratio = initialTurnRadius / distance;
if (ratio > 1.0)
ratio = 1.0;
if (ratio < -1.0)
ratio = -1.0;
double newHeading = asin(ratio) * SG_RADIANS_TO_DEGREES;
double newDistance = cos(newHeading * SG_DEGREES_TO_RADIANS) * distance;
//cerr << "new distance realative to secondary target: " << newDistance << ". additional Heading " << newHeading << endl;
if (side < 180) {
azimuth += newHeading;
} else {
azimuth -= newHeading;
}
SGGeod tertiaryTarget;
SGGeodesy::direct(origin, azimuth, newDistance, tertiaryTarget, dummyAz2);
// lat = tertiaryTarget.getLatitudeDeg();
// lon = tertiaryTarget.getLongitudeDeg();
//cerr << "tertiary Target point (" << lat << ", " << lon << ")." << endl;
//cerr << "Phase 2: Circle " << endl;
double initialAzimuth =
SGGeodesy::courseDeg(secondaryTarget, tertiaryTarget);
double finalAzimuth =
SGGeodesy::courseDeg(secondaryTarget, initialTarget);
//cerr << "Angles from secondary target: " << initialAzimuth << " " << finalAzimuth << endl;
int increment, startval, endval;
// circle right around secondary target if orig of position is to the right of the runway
// i.e. use negative angles; else circle leftward and use postivi
if (side < 180) {
increment = -2;
startval = floor(initialAzimuth);
endval = ceil(finalAzimuth);
if (endval > startval) {
endval -= 360;
}
} else {
increment = 2;
startval = ceil(initialAzimuth);
endval = floor(finalAzimuth);
if (endval < startval) {
endval += 360;
}
}
//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()) + 2000;
} else {
currentAltitude = apt->getElevation() + 2000;
}
// 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
IncrementWaypoint(true);
IncrementWaypoint(true);
if (reposition) {
double tempDistance = SGGeodesy::distanceM(current, initialTarget);
time_t eta2 =
tempDistance / ((vDescent * SG_NM_TO_METER) / 3600.0) + now;
SG_LOG(SG_ATC, SG_BULK, "Final 1 " << eta2);
time_t newEta2 =
apt->getDynamics()->getApproachController()->getRunway(rwy->name())->requestTimeSlot(eta2);
SG_LOG(SG_ATC, SG_BULK, "Final 1 " << eta2 << " " << newEta2);
arrivalTime = newEta2;
double newDistance2 =
((vDescent * SG_NM_TO_METER) / 3600.0) * (newEta2 - now);
IncrementWaypoint(true); // remove waypoint BOD2
while (checkTrackLength("final001") > newDistance2) {
SG_LOG(SG_ATC, SG_BULK, "Final 2 " << checkTrackLength("final001") );
IncrementWaypoint(true);
}
ac->resetPositionFromFlightPlan();
}
if (!waypoints.empty()) {
SG_LOG(SG_AI, SG_BULK, "Setting Node " << waypoints.back()->getName() << " to a leg end");
waypoints.back()->setName( (waypoints.back()->getName() + string("legend")));
}
return true; return true;
} }

View file

@ -314,12 +314,22 @@ bool FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport
assert( rwy != NULL ); assert( rwy != NULL );
// begin descent 110km out // begin descent 110km out
double distanceOut = arr->getDynamics()->getApproachController()->getRunway(rwy->name())->getApproachDistance(); //12 * SG_NM_TO_METER; double distanceOut = arr->getDynamics()->getApproachController()->getRunway(rwy->name())->getApproachDistance(); //12 * SG_NM_TO_METER;
SGGeod beginDescentPoint = rwy->pointOnCenterline(-2*distanceOut);
SGGeod beginDescentPoint = rwy->pointOnCenterline(-3*distanceOut);
SGGeod secondaryDescentPoint = rwy->pointOnCenterline(0); SGGeod secondaryDescentPoint = rwy->pointOnCenterline(0);
wpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise); double distanceToRwy = SGGeodesy::distanceM(current, secondaryDescentPoint);
pushBackWaypoint(wpt); if (distanceToRwy>4*distanceOut) {
wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise); FGAIWaypoint *bodWpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
pushBackWaypoint(wpt); pushBackWaypoint(bodWpt);
FGAIWaypoint *bod2Wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
pushBackWaypoint(bod2Wpt);
} else {
// We are too near. The descent leg takes care of this (teardrop etc)
FGAIWaypoint *bodWpt = createInAir(ac, "BOD", SGGeodesy::direct(current, ac->getTrueHeadingDeg(), 10000), alt, vCruise);
pushBackWaypoint(bodWpt);
FGAIWaypoint *bod2Wpt = createInAir(ac, "BOD2", SGGeodesy::direct(current, ac->getTrueHeadingDeg(), 15000), alt, vCruise);
pushBackWaypoint(bod2Wpt);
}
return true; return true;
} }

View file

@ -59,4 +59,22 @@ double VectorMath::innerTangentsLength( SGGeod m1, SGGeod m2, double r1, double
SGGeod p2 = SGGeodesy::direct(m2, angle2, r2); SGGeod p2 = SGGeodesy::direct(m2, angle2, r2);
return SGGeodesy::distanceM(p1, p2); return SGGeodesy::distanceM(p1, p2);
} }
std::array<double, 2> VectorMath::outerTangentsAngle( SGGeod m1, SGGeod m2, double r1, double r2) {
std::array<double, 2> ret;
double hypothenuse = SGGeodesy::distanceM(m1, m2);
double radiusDiff = abs(r1 - r2);
double beta = atan2( radiusDiff, hypothenuse ) * SG_RADIANS_TO_DEGREES;
double gamma = SGGeodesy::courseDeg(m1, m2);
ret[0] = SGMiscd::normalizePeriodic(0, 360, gamma - beta);
ret[1] = SGMiscd::normalizePeriodic(0, 360, gamma + beta);
return ret;
}
double VectorMath::outerTangentsLength( SGGeod m1, SGGeod m2, double r1, double r2) {
double hypothenuse = SGGeodesy::distanceM(m1, m2);
double radiusDiff = abs(r1 - r2);
double dist = sqrt(pow(hypothenuse,2)-pow(radiusDiff,2));
return dist;
}

View file

@ -27,4 +27,8 @@ class VectorMath {
static std::array<double, 2> innerTangentsAngle( SGGeod m1, SGGeod m2, double r1, double r2); static std::array<double, 2> innerTangentsAngle( SGGeod m1, SGGeod m2, double r1, double r2);
/**Length of inner tangent between two circles.*/ /**Length of inner tangent between two circles.*/
static double innerTangentsLength( SGGeod m1, SGGeod m2, double r1, double r2); static double innerTangentsLength( SGGeod m1, SGGeod m2, double r1, double r2);
/**Angles of outer tangent between two circles normalized to 0-360*/
static std::array<double, 2> outerTangentsAngle( SGGeod m1, SGGeod m2, double r1, double r2);
/**Length of outer tangent between two circles.*/
static double outerTangentsLength( SGGeod m1, SGGeod m2, double r1, double r2);
}; };

View file

@ -202,10 +202,10 @@ bool FGAISchedule::init()
bool FGAISchedule::update(time_t now, const SGVec3d& userCart) bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
{ {
time_t totalTimeEnroute, time_t totalTimeEnroute;
elapsedTimeEnroute, time_t elapsedTimeEnroute;
//remainingTimeEnroute, time_t remainingTimeEnroute;
deptime = 0; time_t deptime = 0;
if (!valid) { if (!valid) {
return true; // processing complete return true; // processing complete
@ -255,7 +255,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
// This flight entry is entirely in the past, do we need to // This flight entry is entirely in the past, do we need to
// push it forward in time to the next scheduled departure. // push it forward in time to the next scheduled departure.
if (flight->getArrivalTime() < now) { if (flight->getArrivalTime() < now) {
SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is in the Past"); SG_LOG (SG_AI, SG_BULK, "Traffic Manager: " << flight->getCallSign() << " is in the Past");
// Don't just update: check whether we need to load a new leg. etc. // Don't just update: check whether we need to load a new leg. etc.
// This update occurs for distant aircraft, so we can update the current leg // This update occurs for distant aircraft, so we can update the current leg
// and detach it from the current list of aircraft. // and detach it from the current list of aircraft.
@ -275,7 +275,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
totalTimeEnroute = flight->getArrivalTime() - flight->getDepartureTime(); totalTimeEnroute = flight->getArrivalTime() - flight->getDepartureTime();
if (flight->getDepartureTime() < now) { if (flight->getDepartureTime() < now) {
elapsedTimeEnroute = now - flight->getDepartureTime(); elapsedTimeEnroute = now - flight->getDepartureTime();
//remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute; remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute;
double x = elapsedTimeEnroute / (double) totalTimeEnroute; double x = elapsedTimeEnroute / (double) totalTimeEnroute;
// current pos is based on great-circle course between departure/arrival, // current pos is based on great-circle course between departure/arrival,
@ -285,21 +285,22 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
SGGeodesy::inverse(dep->geod(), arr->geod(), course, az2, distanceM); SGGeodesy::inverse(dep->geod(), arr->geod(), course, az2, distanceM);
double coveredDistance = distanceM * x; double coveredDistance = distanceM * x;
//FIXME very crude that doesn't harmonise with Legs
SGGeodesy::direct(dep->geod(), course, coveredDistance, position, az2); SGGeodesy::direct(dep->geod(), course, coveredDistance, position, az2);
SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is in progress, %=" << x); SG_LOG (SG_AI, SG_BULK, "Traffic Manager: " << flight->getCallSign() << " is in progress " << (x*100) << "%");
speed = ((distanceM - coveredDistance) * SG_METER_TO_NM) / 3600.0; speed = ((distanceM - coveredDistance) * SG_METER_TO_NM) / 3600.0;
} else { } else {
// not departed yet // not departed yet
//remainingTimeEnroute = totalTimeEnroute; remainingTimeEnroute = totalTimeEnroute;
elapsedTimeEnroute = 0; elapsedTimeEnroute = 0;
position = dep->geod(); position = dep->geod();
SG_LOG (SG_AI, SG_BULK, "Traffic Manager: Flight is pending, departure in " SG_LOG (SG_AI, SG_BULK, "Traffic Manager: " << flight->getCallSign() << " is pending, departure in "
<< flight->getDepartureTime() - now << " seconds "); << flight->getDepartureTime() - now << " seconds ");
} }
} else { } else {
// departure / arrival coincident // departure / arrival coincident
//remainingTimeEnroute = totalTimeEnroute = 0.0; remainingTimeEnroute = totalTimeEnroute = flight->getArrivalTime() - flight->getDepartureTime();
elapsedTimeEnroute = 0; elapsedTimeEnroute = 0;
position = dep->geod(); position = dep->geod();
} }
@ -320,12 +321,12 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
return true; // out of visual range, for the moment. return true; // out of visual range, for the moment.
} }
if (!createAIAircraft(flight, speed, deptime)) { if (!createAIAircraft(flight, speed, deptime, remainingTimeEnroute)) {
valid = false; valid = false;
} }
return true; // processing complete return true; // processing complete
} }
bool FGAISchedule::validModelPath(const std::string& modelPath) bool FGAISchedule::validModelPath(const std::string& modelPath)
@ -353,12 +354,13 @@ SGPath FGAISchedule::resolveModelPath(const std::string& modelPath)
return SGPath(); return SGPath();
} }
bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime) bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime, time_t remainingTime)
{ {
//FIXME The position must be set here not in update
FGAirport* dep = flight->getDepartureAirport(); FGAirport* dep = flight->getDepartureAirport();
FGAirport* arr = flight->getArrivalAirport(); FGAirport* arr = flight->getArrivalAirport();
string flightPlanName = dep->getId() + "-" + arr->getId() + ".xml"; string flightPlanName = dep->getId() + "-" + arr->getId() + ".xml";
SG_LOG(SG_AI, SG_DEBUG, "Traffic manager: Creating AIModel from:" << flightPlanName); SG_LOG(SG_AI, SG_DEBUG, flight->getCallSign() << "|Traffic manager: Creating AIModel from:" << flightPlanName);
aiAircraft = new FGAIAircraft(this); aiAircraft = new FGAIAircraft(this);
aiAircraft->setPerformance(acType, m_class); //"jet_transport"; aiAircraft->setPerformance(acType, m_class); //"jet_transport";
@ -373,8 +375,15 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
aiAircraft->setBank(0); aiAircraft->setBank(0);
courseToDest = SGGeodesy::courseDeg(position, arr->geod()); courseToDest = SGGeodesy::courseDeg(position, arr->geod());
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, flightPlanName, courseToDest, deptime, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
dep, arr, true, radius, flightPlanName,
courseToDest,
deptime,
remainingTime,
dep,
arr,
true,
radius,
flight->getCruiseAlt()*100, flight->getCruiseAlt()*100,
position.getLatitudeDeg(), position.getLatitudeDeg(),
position.getLongitudeDeg(), position.getLongitudeDeg(),
@ -409,7 +418,6 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
} }
} }
// Create an initial heading for user controlled aircraft.
void FGAISchedule::setHeading() void FGAISchedule::setHeading()
{ {
courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod()); courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod());

View file

@ -23,7 +23,7 @@
* This file contains the definition of the class Schedule. * This file contains the definition of the class Schedule.
* *
* A schedule is basically a number of scheduled flights, which can be * A schedule is basically a number of scheduled flights, which can be
* assigned to an AI aircraft. * assigned to an AI aircraft.
**************************************************************************/ **************************************************************************/
#ifndef _FGSCHEDULE_HXX_ #ifndef _FGSCHEDULE_HXX_
@ -69,13 +69,13 @@ class FGAISchedule
bool scheduleFlights(time_t now); bool scheduleFlights(time_t now);
int groundTimeFromRadius(); int groundTimeFromRadius();
/** /**
* Transition this schedule from distant mode to AI mode; * Transition this schedule from distant mode to AI mode;
* create the AIAircraft (and flight plan) and register with the AIManager * create the AIAircraft (and flight plan) and register with the AIManager
*/ */
bool createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime); bool createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime, time_t remainingTime);
// the aiAircraft associated with us // the aiAircraft associated with us
SGSharedPtr<FGAIAircraft> aiAircraft; SGSharedPtr<FGAIAircraft> aiAircraft;
public: public:
@ -85,12 +85,12 @@ class FGAISchedule
const std::string& homePort, const std::string& homePort,
const std::string& registration, const std::string& registration,
const std::string& flightId, const std::string& flightId,
bool heavy, bool heavy,
const std::string& acType, const std::string& acType,
const std::string& airline, const std::string& airline,
const std::string& m_class, const std::string& m_class,
const std::string& flight_type, const std::string& flight_type,
double radius, double radius,
double offset); // construct & init double offset); // construct & init
FGAISchedule(const FGAISchedule &other); // copy constructor FGAISchedule(const FGAISchedule &other); // copy constructor
@ -100,7 +100,7 @@ class FGAISchedule
static bool validModelPath(const std::string& model); static bool validModelPath(const std::string& model);
static SGPath resolveModelPath(const std::string& model); static SGPath resolveModelPath(const std::string& model);
bool update(time_t now, const SGVec3d& userCart); bool update(time_t now, const SGVec3d& userCart);
bool init(); bool init();
@ -130,7 +130,8 @@ class FGAISchedule
void setHits (unsigned int count) { hits = count; }; void setHits (unsigned int count) { hits = count; };
void setScore (); void setScore ();
double getScore () { return score; }; double getScore () { return score; };
void setHeading (); /**Create an initial heading for user controlled aircraft.*/
void setHeading ();
void assign (FGScheduledFlight *ref); void assign (FGScheduledFlight *ref);
void clearAllFlights(); void clearAllFlights();
void setFlightType (const std::string& val) { flightType = val; }; void setFlightType (const std::string& val) { flightType = val; };

View file

@ -67,4 +67,18 @@ void VectorMathTests::testInnerTangent2()
auto angles = VectorMath::innerTangentsAngle(m1, m2, r1, r2); auto angles = VectorMath::innerTangentsAngle(m1, m2, r1, r2);
CPPUNIT_ASSERT_DOUBLES_EQUAL( 330, angles[0], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL( 330, angles[0], 0.1);
CPPUNIT_ASSERT_DOUBLES_EQUAL( 30, angles[1], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL( 30, angles[1], 0.1);
} }
void VectorMathTests::testOuterTanget()
{
double r1 = 10;
double r2 = 50;
// when the circles are dist appart the angle will be 45°
double dist = 40;
SGGeod m1 = SGGeod::fromDeg(9,51);
SGGeod m2 = SGGeodesy::direct(m1, 90, dist);
auto angles = VectorMath::outerTangentsAngle(m1, m2, r1, r2);
CPPUNIT_ASSERT_DOUBLES_EQUAL( 45, angles[0], 0.1);
CPPUNIT_ASSERT_DOUBLES_EQUAL( 135, angles[1], 0.1);
}

View file

@ -35,6 +35,7 @@ class VectorMathTests : public CppUnit::TestFixture
CPPUNIT_TEST_SUITE(VectorMathTests); CPPUNIT_TEST_SUITE(VectorMathTests);
CPPUNIT_TEST(testInnerTanget); CPPUNIT_TEST(testInnerTanget);
CPPUNIT_TEST(testInnerTangent2); CPPUNIT_TEST(testInnerTangent2);
CPPUNIT_TEST(testOuterTanget);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
@ -49,4 +50,5 @@ public:
// The tests. // The tests.
void testInnerTanget(); void testInnerTanget();
void testInnerTangent2(); void testInnerTangent2();
void testOuterTanget();
}; };

View file

@ -156,7 +156,8 @@ void TrafficTests::testPushback()
departureTime = departureTime + 90; departureTime = departureTime + 90;
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius, departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),
@ -214,7 +215,8 @@ void TrafficTests::testPushbackCargo()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs,
departureTime, departureTime+3000,
egph, egpf, true, radius, egph, egpf, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),
@ -230,6 +232,253 @@ void TrafficTests::testPushbackCargo()
aiAircraft = flyAI(aiAircraft, "flight_cargo_EGPH_EGPF_" + std::to_string(departureTime)); aiAircraft = flyAI(aiAircraft, "flight_cargo_EGPH_EGPF_" + std::to_string(departureTime));
} }
void TrafficTests::testPushbackCargoInProgress()
{
FGAirportRef egph = FGAirport::getByIdent("EGPH");
FGAirportRef egpf = FGAirport::getByIdent("EGPF");
fgSetString("/sim/presets/airport-id", "EGPH");
// Time to depart
std::string dep = getTimeString(-100);
// Time to arrive
std::string arr = getTimeString(190);
FGAISchedule* schedule = new FGAISchedule(
"B737", "KLM", "EGPH", "G-BLA", "ID", false, "B737", "KLM", "N", "cargo", 24, 8);
FGScheduledFlight* flight = new FGScheduledFlight("testPushbackCargo", "", "EGPH", "EGPF", 24, dep, arr, "WEEK", "HBR_BN_2");
schedule->assign(flight);
SGSharedPtr<FGAIAircraft> aiAircraft = new FGAIAircraft{schedule};
const SGGeod position = SGGeodesy::direct(egph->geod(), 270, 50000);
const double crs = SGGeodesy::courseDeg(position, egpf->geod()); // direct course
ParkingAssignment parking = egph->getDynamics()->getParkingByName("north-cargo208");
FGTestApi::setPositionAndStabilise(egph->getDynamics()->getParkingByName("ga206").parking()->geod());
aiAircraft->setPerformance("jet_transport", "");
aiAircraft->setCompany("KLM");
aiAircraft->setAcType("B737");
aiAircraft->setSpeed(0);
aiAircraft->setBank(0);
aiAircraft->setHeading(crs);
const string flightPlanName = egph->getId() + "-" + egpf->getId() + ".xml";
const int radius = 16.0;
const int cruiseAltFt = 32000;
const int cruiseSpeedKnots = 80;
time_t departureTime = globals->get_time_params()->get_cur_time();
departureTime = departureTime - 6000;
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs,
departureTime, 100,
egph, egpf, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
position.getLongitudeDeg(),
cruiseSpeedKnots, "cargo",
aiAircraft->getAcType(),
aiAircraft->getCompany()));
CPPUNIT_ASSERT_EQUAL(fp->isValidPlan(), true);
aiAircraft->FGAIBase::setFlightPlan(std::move(fp));
globals->get_subsystem<FGAIManager>()->attach(aiAircraft);
aiAircraft = flyAI(aiAircraft, "flight_cargo_in_progress_EGPH_EGPF_" + std::to_string(departureTime));
}
void TrafficTests::testPushbackCargoInProgressDownWind()
{
FGAirportRef egph = FGAirport::getByIdent("EGPH");
FGAirportRef egpf = FGAirport::getByIdent("EGPF");
fgSetString("/sim/presets/airport-id", "EGPH");
// Time to depart
std::string dep = getTimeString(-100);
// Time to arrive
std::string arr = getTimeString(190);
FGAISchedule* schedule = new FGAISchedule(
"B737", "KLM", "EGPH", "G-BLA", "ID", false, "B737", "KLM", "N", "cargo", 24, 8);
FGScheduledFlight* flight = new FGScheduledFlight("testPushbackCargoInProgressDownWind", "", "EGPH", "EGPF", 24, dep, arr, "WEEK", "HBR_BN_2");
schedule->assign(flight);
SGSharedPtr<FGAIAircraft> aiAircraft = new FGAIAircraft{schedule};
const SGGeod position = SGGeodesy::direct(egph->geod(), 0, 50000);
const double crs = SGGeodesy::courseDeg(position, egpf->geod()); // direct course
ParkingAssignment parking = egph->getDynamics()->getParkingByName("north-cargo208");
FGTestApi::setPositionAndStabilise(egph->getDynamics()->getParkingByName("ga206").parking()->geod());
aiAircraft->setPerformance("jet_transport", "");
aiAircraft->setCompany("KLM");
aiAircraft->setAcType("B737");
aiAircraft->setSpeed(0);
aiAircraft->setBank(0);
aiAircraft->setHeading(crs);
const string flightPlanName = egph->getId() + "-" + egpf->getId() + ".xml";
const int radius = 16.0;
const int cruiseAltFt = 32000;
const int cruiseSpeedKnots = 80;
time_t departureTime = globals->get_time_params()->get_cur_time();
departureTime = departureTime - 6000;
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs,
departureTime, 100,
egph, egpf, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
position.getLongitudeDeg(),
cruiseSpeedKnots, "cargo",
aiAircraft->getAcType(),
aiAircraft->getCompany()));
CPPUNIT_ASSERT_EQUAL(fp->isValidPlan(), true);
aiAircraft->FGAIBase::setFlightPlan(std::move(fp));
globals->get_subsystem<FGAIManager>()->attach(aiAircraft);
aiAircraft = flyAI(aiAircraft, "flight_cargo_in_progress_downwind_EGPH_EGPF_" + std::to_string(departureTime));
}
void TrafficTests::testPushbackCargoInProgressNotBeyond()
{
FGAirportRef egph = FGAirport::getByIdent("EGPH");
FGAirportRef egpf = FGAirport::getByIdent("EGPF");
fgSetString("/sim/presets/airport-id", "EGPH");
// Time to depart
std::string dep = getTimeString(-100);
// Time to arrive
std::string arr = getTimeString(190);
FGAISchedule* schedule = new FGAISchedule(
"B737", "KLM", "EGPH", "G-BLA", "ID", false, "B737", "KLM", "N", "cargo", 24, 8);
FGScheduledFlight* flight = new FGScheduledFlight("testPushbackCargo", "", "EGPH", "EGPF", 24, dep, arr, "WEEK", "HBR_BN_2");
schedule->assign(flight);
SGSharedPtr<FGAIAircraft> aiAircraft = new FGAIAircraft{schedule};
// Position west of runway
const SGGeod position = SGGeodesy::direct(egpf->geod(), 270, 5000);
const double crs = SGGeodesy::courseDeg(position, egpf->geod()); // direct course
ParkingAssignment parking = egph->getDynamics()->getParkingByName("north-cargo208");
FGTestApi::setPositionAndStabilise(egph->getDynamics()->getParkingByName("ga206").parking()->geod());
aiAircraft->setPerformance("jet_transport", "");
aiAircraft->setCompany("KLM");
aiAircraft->setAcType("B737");
aiAircraft->setSpeed(0);
aiAircraft->setBank(0);
aiAircraft->setHeading(crs);
const string flightPlanName = egph->getId() + "-" + egpf->getId() + ".xml";
const int radius = 16.0;
const int cruiseAltFt = 32000;
const int cruiseSpeedKnots = 80;
time_t departureTime = globals->get_time_params()->get_cur_time();
departureTime = departureTime - 6000;
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs,
departureTime, 100,
egph, egpf, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
position.getLongitudeDeg(),
cruiseSpeedKnots, "cargo",
aiAircraft->getAcType(),
aiAircraft->getCompany()));
CPPUNIT_ASSERT_EQUAL(fp->isValidPlan(), true);
aiAircraft->FGAIBase::setFlightPlan(std::move(fp));
globals->get_subsystem<FGAIManager>()->attach(aiAircraft);
aiAircraft = flyAI(aiAircraft, "flight_cargo_in_progress_not_beyond_EGPH_EGPF_" + std::to_string(departureTime));
}
void TrafficTests::testPushbackCargoInProgressBeyond()
{
FGAirportRef egph = FGAirport::getByIdent("EGPH");
FGAirportRef egpf = FGAirport::getByIdent("EGPF");
fgSetString("/sim/presets/airport-id", "EGPH");
// Time to depart
std::string dep = getTimeString(-100);
// Time to arrive
std::string arr = getTimeString(190);
FGAISchedule* schedule = new FGAISchedule(
"B737", "KLM", "EGPH", "G-BLA", "ID", false, "B737", "KLM", "N", "cargo", 24, 8);
FGScheduledFlight* flight = new FGScheduledFlight("testPushbackCargo", "", "EGPH", "EGPF", 24, dep, arr, "WEEK", "HBR_BN_2");
schedule->assign(flight);
SGSharedPtr<FGAIAircraft> aiAircraft = new FGAIAircraft{schedule};
// Position east of runway pointing away from runway
const SGGeod position = SGGeodesy::direct(egpf->geod(), 90, 5000);
const double crs = SGMiscd::normalizePeriodic(0, 360, SGGeodesy::courseDeg(position, egpf->geod()));
ParkingAssignment parking = egph->getDynamics()->getParkingByName("north-cargo208");
FGTestApi::setPositionAndStabilise(egph->getDynamics()->getParkingByName("ga206").parking()->geod());
aiAircraft->setPerformance("jet_transport", "");
aiAircraft->setCompany("KLM");
aiAircraft->setAcType("B737");
aiAircraft->setSpeed(0);
aiAircraft->setBank(0);
aiAircraft->setHeading(crs);
const string flightPlanName = egph->getId() + "-" + egpf->getId() + ".xml";
const int radius = 16.0;
const int cruiseAltFt = 32000;
const int cruiseSpeedKnots = 80;
time_t departureTime = globals->get_time_params()->get_cur_time();
departureTime = departureTime - 6000;
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs,
departureTime, 100,
egph, egpf, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
position.getLongitudeDeg(),
cruiseSpeedKnots, "cargo",
aiAircraft->getAcType(),
aiAircraft->getCompany()));
CPPUNIT_ASSERT_EQUAL(fp->isValidPlan(), true);
aiAircraft->FGAIBase::setFlightPlan(std::move(fp));
globals->get_subsystem<FGAIManager>()->attach(aiAircraft);
aiAircraft = flyAI(aiAircraft, "flight_cargo_in_progress_beyond_EGPH_EGPF_" + std::to_string(departureTime));
}
void TrafficTests::testChangeRunway() void TrafficTests::testChangeRunway()
{ {
FGAirportRef departureAirport = FGAirport::getByIdent("EGPH"); FGAirportRef departureAirport = FGAirport::getByIdent("EGPH");
@ -274,7 +523,8 @@ void TrafficTests::testChangeRunway()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius, departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),
@ -287,7 +537,7 @@ void TrafficTests::testChangeRunway()
aiAircraft->FGAIBase::setFlightPlan(std::move(fp)); aiAircraft->FGAIBase::setFlightPlan(std::move(fp));
globals->get_subsystem<FGAIManager>()->attach(aiAircraft); globals->get_subsystem<FGAIManager>()->attach(aiAircraft);
aiAircraft = flyAI(aiAircraft, "flight_runway_EGPH_EGPF_" + std::to_string(departureTime)); aiAircraft = flyAI(aiAircraft, "flight_change_runway_EGPH_EGPF_" + std::to_string(departureTime));
} }
@ -332,7 +582,8 @@ void TrafficTests::testPushforward()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius, departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),
@ -389,7 +640,8 @@ void TrafficTests::testPushforwardSpeedy()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius, departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),
@ -447,7 +699,8 @@ void TrafficTests::testPushforwardParkYBBN()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius, departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),
@ -528,7 +781,7 @@ void TrafficTests::testPushforwardParkYBBNRepeatGa()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs, departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius, departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),
@ -604,7 +857,8 @@ void TrafficTests::testPushforwardParkYBBNRepeatGaDelayed()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius, departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),
@ -700,7 +954,8 @@ void TrafficTests::testPushforwardParkYBBNRepeatGate()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime, flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius, departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt cruiseAltFt, // cruise alt
position.getLatitudeDeg(), position.getLatitudeDeg(),

View file

@ -37,12 +37,16 @@ class TrafficTests : public CppUnit::TestFixture
CPPUNIT_TEST_SUITE(TrafficTests); CPPUNIT_TEST_SUITE(TrafficTests);
CPPUNIT_TEST(testPushback); CPPUNIT_TEST(testPushback);
CPPUNIT_TEST(testPushbackCargo); CPPUNIT_TEST(testPushbackCargo);
CPPUNIT_TEST(testPushbackCargoInProgress);
CPPUNIT_TEST(testPushbackCargoInProgressDownWind);
CPPUNIT_TEST(testPushbackCargoInProgressNotBeyond);
CPPUNIT_TEST(testPushbackCargoInProgressBeyond);
CPPUNIT_TEST(testChangeRunway); CPPUNIT_TEST(testChangeRunway);
CPPUNIT_TEST(testPushforward); CPPUNIT_TEST(testPushforward);
CPPUNIT_TEST(testPushforwardSpeedy); CPPUNIT_TEST(testPushforwardSpeedy);
CPPUNIT_TEST(testPushforwardParkYBBN); CPPUNIT_TEST(testPushforwardParkYBBN);
CPPUNIT_TEST(testPushforwardParkYBBNRepeatGa); CPPUNIT_TEST(testPushforwardParkYBBNRepeatGa);
CPPUNIT_TEST(testPushforwardParkYBBNRepeatGaDelayed); CPPUNIT_TEST(testPushforwardParkYBBNRepeatGaDelayed);
CPPUNIT_TEST(testPushforwardParkYBBNRepeatGate); CPPUNIT_TEST(testPushforwardParkYBBNRepeatGate);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
public: public:
@ -55,6 +59,10 @@ public:
// Pushback Tests // Pushback Tests
void testPushback(); void testPushback();
void testPushbackCargo(); void testPushbackCargo();
void testPushbackCargoInProgress();
void testPushbackCargoInProgressDownWind();
void testPushbackCargoInProgressNotBeyond();
void testPushbackCargoInProgressBeyond();
void testChangeRunway(); void testChangeRunway();
//GA Tests with forward push //GA Tests with forward push
void testPushforward(); void testPushforward();