Fix auto-routing by airways.
When the from and to points are not on the enroute structure, check the initial and final legs for large turns (more than 90-degrees) from the overall route course. If found, kill the leg, to generate more natural route and avoid very sharp turns in the terminal area.
This commit is contained in:
parent
44a44a0246
commit
d0e9503766
2 changed files with 45 additions and 8 deletions
|
@ -190,6 +190,13 @@ void Airway::Network::addEdge(int aWay, const SGGeod& aStartPos,
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static double headingDiffDeg(double a, double b)
|
||||||
|
{
|
||||||
|
double rawDiff = b - a;
|
||||||
|
SG_NORMALIZE_RANGE(rawDiff, -180.0, 180.0);
|
||||||
|
return rawDiff;
|
||||||
|
}
|
||||||
|
|
||||||
bool Airway::Network::inNetwork(PositionedID posID) const
|
bool Airway::Network::inNetwork(PositionedID posID) const
|
||||||
{
|
{
|
||||||
NetworkMembershipDict::iterator it = _inNetworkCache.find(posID);
|
NetworkMembershipDict::iterator it = _inNetworkCache.find(posID);
|
||||||
|
@ -228,17 +235,44 @@ bool Airway::Network::route(WayptRef aFrom, WayptRef aTo,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exactTo) {
|
return cleanGeneratedPath(aFrom, aTo, aPath, exactTo, exactFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Airway::Network::cleanGeneratedPath(WayptRef aFrom, WayptRef aTo, WayptVec& aPath,
|
||||||
|
bool exactTo, bool exactFrom)
|
||||||
|
{
|
||||||
|
// path cleaning phase : various cases to handle here.
|
||||||
|
// if either the TO or FROM waypoints were 'exact', i.e part of the enroute
|
||||||
|
// structure, we don't want to duplicate them. This happens frequently with
|
||||||
|
// published SIDs and STARs.
|
||||||
|
// secondly, if the waypoints are NOT on the enroute structure, the course to
|
||||||
|
// them may be a significant dog-leg. Check how the leg course deviates
|
||||||
|
// from the direct course FROM->TO, and delete the first/last leg if it's more
|
||||||
|
// than 90 degrees out.
|
||||||
|
// note we delete a maximum of one leg, and no more. This is a heuristic - we
|
||||||
|
// could check the next (previous) legs, but at some point we'll end up
|
||||||
|
// deleting too much.
|
||||||
|
|
||||||
|
const double MAX_DOG_LEG = 90.0;
|
||||||
|
double enrouteCourse = SGGeodesy::courseDeg(aFrom->position(), aTo->position()),
|
||||||
|
finalLegCourse = SGGeodesy::courseDeg(aPath.back()->position(), aTo->position());
|
||||||
|
|
||||||
|
bool isDogLeg = fabs(headingDiffDeg(enrouteCourse, finalLegCourse)) > MAX_DOG_LEG;
|
||||||
|
if (exactTo || isDogLeg) {
|
||||||
aPath.pop_back();
|
aPath.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exactFrom) {
|
// edge case - if from and to are equal, which can happen, don't
|
||||||
// edge case - if from and to are equal, which can happen, don't
|
// crash here. This happens routing EGPH -> EGCC; 'DCS' is common
|
||||||
// crash here. This happens routing EGPH -> EGCC; 'DCS' is common
|
// to the EGPH departure and EGCC STAR.
|
||||||
// to the EGPH departure and EGCC STAR.
|
if (aPath.empty()) {
|
||||||
if (!aPath.empty()) {
|
return true;
|
||||||
aPath.erase(aPath.begin());
|
}
|
||||||
}
|
|
||||||
|
double initialLegCourse = SGGeodesy::courseDeg(aFrom->position(), aPath.front()->position());
|
||||||
|
isDogLeg = fabs(headingDiffDeg(enrouteCourse, initialLegCourse)) > MAX_DOG_LEG;
|
||||||
|
if (exactFrom || isDogLeg) {
|
||||||
|
aPath.erase(aPath.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -71,6 +71,9 @@ public:
|
||||||
|
|
||||||
int findAirway(const std::string& aName, double aTop, double aBase);
|
int findAirway(const std::string& aName, double aTop, double aBase);
|
||||||
|
|
||||||
|
bool cleanGeneratedPath(WayptRef aFrom, WayptRef aTo, WayptVec& aPath,
|
||||||
|
bool exactTo, bool exactFrom);
|
||||||
|
|
||||||
bool search2(FGPositionedRef aStart, FGPositionedRef aDest, WayptVec& aRoute);
|
bool search2(FGPositionedRef aStart, FGPositionedRef aDest, WayptVec& aRoute);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue