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

View file

@ -137,6 +137,7 @@ public:
const std::string& p,
double course,
time_t start,
time_t remainingTime,
FGAirport *dep,
FGAirport *arr,
bool firstLeg,
@ -276,7 +277,7 @@ private:
/**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 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);
void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport);
void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
@ -300,9 +301,14 @@ private:
*/
bool parseProperties(const std::string& filename);
/**
* Creates the waypoints for this Flightplan.
*/
void createWaypoints(FGAIAircraft *ac,
double course,
time_t start,
time_t remainingTime,
FGAirport *dep,
FGAirport *arr,
bool firstLeg,

View file

@ -69,9 +69,9 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
const string & aircraftType,
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());
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());
else
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;
int currWpt = wpt_iterator - waypoints.begin();
switch (legNr) {
case 1:
case AILeg::STARTUP_PUSHBACK:
retVal = createPushBack(ac, firstFlight, dep,
radius, fltType, aircraftType, airline);
break;
case 2:
case AILeg::TAXI:
retVal = createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
aircraftType, airline);
break;
case 3:
case AILeg::TAKEOFF:
retVal = createTakeOff(ac, firstFlight, dep, SGGeod::fromDeg(longitude, latitude), speed, fltType);
break;
case 4:
case AILeg::CLIMB:
retVal = createClimb(ac, firstFlight, dep, arr, speed, alt, fltType);
break;
case 5:
case AILeg::CRUISE:
retVal = createCruise(ac, firstFlight, dep, arr, SGGeod::fromDeg(longitude, latitude), speed,
alt, fltType);
break;
case 6:
case AILeg::APPROACH:
retVal = createDescent(ac, arr, SGGeod::fromDeg(longitude, latitude), speed, alt, fltType,
distance);
break;
case 7:
case AILeg::LANDING:
retVal = createLanding(ac, arr, fltType);
break;
case 8:
case AILeg::PARKING_TAXI:
retVal = createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
break;
case 9:
case AILeg::PARKING:
retVal = createParking(ac, arr, radius);
break;
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;
double nPoints = dist/(vDescent/2);
char buffer[20];
@ -211,7 +211,7 @@ void FGAIFlightPlan::createLine( FGAIAircraft *ac, const SGGeod& startPoint, dou
double currentDist = i * (dist / nPoints);
double currentAltitude = ac->getAltitude() - (i * (dAlt / nPoints));
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);
wpt->setCrossat(currentAltitude);
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
* the permission to land point
******************************************************************/
bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
bool FGAIFlightPlan::createDescent(FGAIAircraft * ac,
FGAirport * apt,
const SGGeod& current,
double speed, double alt,
double speed,
double alt,
const string & fltType,
double requiredDistance)
{
@ -762,16 +764,21 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
//Beginning of Descent
const string& rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
double heading = ac->getTrueHeadingDeg();
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
heading);
if (!apt->hasRunwayWithIdent(activeRunway))
return false;
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)
// Create a slow descent path that ends 250 lateral to the runway.
double initialTurnRadius = getTurnRadius(vDescent, true);
//double finalTurnRadius = getTurnRadius(vApproach, true);
@ -787,6 +794,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
}
SGGeod initialTarget = rwy->pointOnCenterline(-distanceOut);
SGGeod otherRwyEnd = rwy->pointOnCenterline(rwy->lengthM());
SGGeod secondaryTarget =
rwy->pointOffCenterline(-2 * distanceOut, lateralOffset);
SGGeod secondHoldCenter =
@ -797,50 +805,204 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
double secondaryAzimuth = SGGeodesy::courseDeg(current, secondaryTarget);
double initialHeadingDiff = SGMiscd::normalizePeriodic(-180, 180, azimuth-secondaryAzimuth);
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 <<
" Distance " << distance <<
SG_LOG(SG_AI, SG_BULK, ac->getCallSign() <<
"| " <<
" WPs : " << waypoints.size() <<
" Heading Diff (rwy) : " << headingDiffRunway <<
" Distance : " << distance <<
" 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) {
// Entering not "straight" into runway so we do a s-curve
int rightAngle = initialHeadingDiff<0?90:-90;
SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
int firstTurnIncrement = initialHeadingDiff<0?2:-2;
const double heading = VectorMath::innerTangentsAngle(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius )[0];
createArc(ac, firstTurnCenter, ac->_getHeading()-rightAngle, heading-rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), vDescent, "initialturn%03d");
double length = VectorMath::innerTangentsLength(firstTurnCenter, secondaryTarget, initialTurnRadius, initialTurnRadius );
createLine(ac, waypoints.back()->getPos(), heading, length, 50, vDescent);
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");
*/
if (fabs(headingDiffRunway)>=30 && fabs(headingDiffRunway)<=150 ) {
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 S curve");
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 = headingDiffRunway>0?90:-90;
int firstTurnIncrement = headingDiffRunway>0?2:-2;
SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
SGGeod newCurrent = current;
// If we are not far enough cross over
if (abs(headingDiffToRunwayThreshold)<90) {
newCurrent = SGGeodesy::direct(current, ac->getTrueHeadingDeg(), distance + 1000);
firstTurnCenter = SGGeodesy::direct(newCurrent, ac->getTrueHeadingDeg() + rightAngle, initialTurnRadius);
createLine(ac, current, ac->getTrueHeadingDeg(), distance + 1000, 50, vDescent, "move%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 {
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, "turn%03d");
SG_LOG(SG_AI, SG_BULK, ac->getCallSign() << "| Enter far S curve");
// Entering not "straight" into runway so we do a s-curve
int rightAngle = headingDiffRunway>0?90:-90;
int firstTurnIncrement = headingDiffRunway>0?2:-2;
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 {
SG_LOG(SG_AI, SG_BULK, ac->getCallSign() << "| Enter far straight");
// Entering "straight" into runway so only one turn
int rightAngle = headingDiffRunway>0?90:-90;
SGGeod firstTurnCenter = SGGeodesy::direct(current, ac->getTrueHeadingDeg() - rightAngle, initialTurnRadius);
int firstTurnIncrement = headingDiffRunway>0?-2:2;
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
@ -861,55 +1023,12 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
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.
// distance should really consist of flying time to terniary target, plus circle
// but the distance to secondary target should work as a reasonable approximation
// aditionally add the amount of distance covered by making a turn of "side"
double turnDistance = (2 * M_PI * initialTurnRadius) * (side / 360.0);
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();
//if (ac->getTrafficRef()->getCallSign() == fgGetString("/ai/track-callsign")) {
@ -940,110 +1059,6 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
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;
}

View file

@ -314,12 +314,22 @@ bool FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport
assert( rwy != NULL );
// begin descent 110km out
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);
wpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
pushBackWaypoint(wpt);
wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
pushBackWaypoint(wpt);
double distanceToRwy = SGGeodesy::distanceM(current, secondaryDescentPoint);
if (distanceToRwy>4*distanceOut) {
FGAIWaypoint *bodWpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
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;
}

View file

@ -59,4 +59,22 @@ double VectorMath::innerTangentsLength( SGGeod m1, SGGeod m2, double r1, double
SGGeod p2 = SGGeodesy::direct(m2, angle2, r2);
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);
/**Length of inner tangent between two circles.*/
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)
{
time_t totalTimeEnroute,
elapsedTimeEnroute,
//remainingTimeEnroute,
deptime = 0;
time_t totalTimeEnroute;
time_t elapsedTimeEnroute;
time_t remainingTimeEnroute;
time_t deptime = 0;
if (!valid) {
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
// push it forward in time to the next scheduled departure.
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.
// This update occurs for distant aircraft, so we can update the current leg
// 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();
if (flight->getDepartureTime() < now) {
elapsedTimeEnroute = now - flight->getDepartureTime();
//remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute;
remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute;
double x = elapsedTimeEnroute / (double) totalTimeEnroute;
// 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);
double coveredDistance = distanceM * x;
//FIXME very crude that doesn't harmonise with Legs
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;
} else {
// not departed yet
//remainingTimeEnroute = totalTimeEnroute;
remainingTimeEnroute = totalTimeEnroute;
elapsedTimeEnroute = 0;
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 ");
}
} else {
// departure / arrival coincident
//remainingTimeEnroute = totalTimeEnroute = 0.0;
remainingTimeEnroute = totalTimeEnroute = flight->getArrivalTime() - flight->getDepartureTime();
elapsedTimeEnroute = 0;
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.
}
if (!createAIAircraft(flight, speed, deptime)) {
if (!createAIAircraft(flight, speed, deptime, remainingTimeEnroute)) {
valid = false;
}
return true; // processing complete
return true; // processing complete
}
bool FGAISchedule::validModelPath(const std::string& modelPath)
@ -353,12 +354,13 @@ SGPath FGAISchedule::resolveModelPath(const std::string& modelPath)
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* arr = flight->getArrivalAirport();
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->setPerformance(acType, m_class); //"jet_transport";
@ -373,8 +375,15 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
aiAircraft->setBank(0);
courseToDest = SGGeodesy::courseDeg(position, arr->geod());
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft, flightPlanName, courseToDest, deptime,
dep, arr, true, radius,
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName,
courseToDest,
deptime,
remainingTime,
dep,
arr,
true,
radius,
flight->getCruiseAlt()*100,
position.getLatitudeDeg(),
position.getLongitudeDeg(),
@ -409,7 +418,6 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
}
}
// Create an initial heading for user controlled aircraft.
void FGAISchedule::setHeading()
{
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.
*
* 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_
@ -69,13 +69,13 @@ class FGAISchedule
bool scheduleFlights(time_t now);
int groundTimeFromRadius();
/**
* Transition this schedule from distant mode to AI mode;
* 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
SGSharedPtr<FGAIAircraft> aiAircraft;
public:
@ -85,12 +85,12 @@ class FGAISchedule
const std::string& homePort,
const std::string& registration,
const std::string& flightId,
bool heavy,
bool heavy,
const std::string& acType,
const std::string& airline,
const std::string& m_class,
const std::string& flight_type,
double radius,
double radius,
double offset); // construct & init
FGAISchedule(const FGAISchedule &other); // copy constructor
@ -100,7 +100,7 @@ class FGAISchedule
static bool validModelPath(const std::string& model);
static SGPath resolveModelPath(const std::string& model);
bool update(time_t now, const SGVec3d& userCart);
bool init();
@ -130,7 +130,8 @@ class FGAISchedule
void setHits (unsigned int count) { hits = count; };
void setScore ();
double getScore () { return score; };
void setHeading ();
/**Create an initial heading for user controlled aircraft.*/
void setHeading ();
void assign (FGScheduledFlight *ref);
void clearAllFlights();
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);
CPPUNIT_ASSERT_DOUBLES_EQUAL( 330, angles[0], 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(testInnerTanget);
CPPUNIT_TEST(testInnerTangent2);
CPPUNIT_TEST(testOuterTanget);
CPPUNIT_TEST_SUITE_END();
@ -49,4 +50,5 @@ public:
// The tests.
void testInnerTanget();
void testInnerTangent2();
void testOuterTanget();
};

View file

@ -156,7 +156,8 @@ void TrafficTests::testPushback()
departureTime = departureTime + 90;
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime,
flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
@ -214,7 +215,8 @@ void TrafficTests::testPushbackCargo()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime,
flightPlanName, crs,
departureTime, departureTime+3000,
egph, egpf, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
@ -230,6 +232,253 @@ void TrafficTests::testPushbackCargo()
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()
{
FGAirportRef departureAirport = FGAirport::getByIdent("EGPH");
@ -274,7 +523,8 @@ void TrafficTests::testChangeRunway()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime,
flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
@ -287,7 +537,7 @@ void TrafficTests::testChangeRunway()
aiAircraft->FGAIBase::setFlightPlan(std::move(fp));
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,
flightPlanName, crs, departureTime,
flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
@ -389,7 +640,8 @@ void TrafficTests::testPushforwardSpeedy()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime,
flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
@ -447,7 +699,8 @@ void TrafficTests::testPushforwardParkYBBN()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime,
flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
@ -528,7 +781,7 @@ void TrafficTests::testPushforwardParkYBBNRepeatGa()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime,
flightPlanName, crs, departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
@ -604,7 +857,8 @@ void TrafficTests::testPushforwardParkYBBNRepeatGaDelayed()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime,
flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),
@ -700,7 +954,8 @@ void TrafficTests::testPushforwardParkYBBNRepeatGate()
std::unique_ptr<FGAIFlightPlan> fp(new FGAIFlightPlan(aiAircraft,
flightPlanName, crs, departureTime,
flightPlanName, crs,
departureTime, departureTime+3000,
departureAirport, arrivalAirport, true, radius,
cruiseAltFt, // cruise alt
position.getLatitudeDeg(),

View file

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