1
0
Fork 0

James Turner:

Attached patch updates the route-manager to use FGPositioned to search
for waypoints, instead of a manual airport / fix / navaid search. This
is good because it's now using the 'strictly closest' match, rather
than arbitrarily picking a distant fix over a nearby navaid. In my
case, the TLA VOR is significant to several EGPH procedures, but also
happens to be the ident of a fix a long, long way away.

Also updates the FGPositioned class to stop using Point3D, partly
because it's deprecated and partly because I had misunderstood the
interface and was using it wrong. For now, all FGPositioned distance
checks use SGGeodesy::inverse, which is accurate but inefficient. Once
FGPositioned queries are used for something on a hot path, I'll
probably store the cartesian position as well as the geodetic, to make
these checks fast.
This commit is contained in:
fredb 2008-12-03 20:03:46 +00:00
parent 7ad55be8f6
commit f3b110e565
3 changed files with 66 additions and 99 deletions

View file

@ -281,24 +281,24 @@ bool FGRouteMgr::build() {
} }
int FGRouteMgr::new_waypoint( const string& target, int n ) { void FGRouteMgr::new_waypoint( const string& target, int n ) {
SGWayPoint *wp = 0; SGWayPoint* wp = make_waypoint( target );
int type = make_waypoint( &wp, target ); if (!wp) {
return;
if (wp) { }
add_waypoint( *wp, n );
delete wp; add_waypoint( *wp, n );
delete wp;
if ( !near_ground() )
fgSetString( "/autopilot/locks/heading", "true-heading-hold" ); if ( !near_ground() ) {
fgSetString( "/autopilot/locks/heading", "true-heading-hold" );
} }
return type;
} }
int FGRouteMgr::make_waypoint( SGWayPoint **wp, const string& tgt ) { SGWayPoint* FGRouteMgr::make_waypoint(const string& tgt ) {
string target = tgt; string target = tgt;
// make upper case // make upper case
for (unsigned int i = 0; i < target.size(); i++) for (unsigned int i = 0; i < target.size(); i++)
if (target[i] >= 'a' && target[i] <= 'z') if (target[i] >= 'a' && target[i] <= 'z')
@ -321,57 +321,28 @@ int FGRouteMgr::make_waypoint( SGWayPoint **wp, const string& tgt ) {
double lat = atof( target.c_str() + pos + 1); double lat = atof( target.c_str() + pos + 1);
SG_LOG( SG_GENERAL, SG_INFO, "Adding waypoint lon = " << lon << ", lat = " << lat ); SG_LOG( SG_GENERAL, SG_INFO, "Adding waypoint lon = " << lon << ", lat = " << lat );
*wp = new SGWayPoint( lon, lat, alt, SGWayPoint::WGS84, target ); return new SGWayPoint( lon, lat, alt, SGWayPoint::WGS84, target );
return 1; }
}
// check for airport id SGGeod basePosition;
const FGAirport *apt = fgFindAirportID( target ); if (route->size() > 0) {
if (apt) { SGWayPoint wp = get_waypoint(route->size()-1);
SG_LOG( SG_GENERAL, SG_INFO, "Adding waypoint (airport) = " << target ); basePosition = SGGeod::fromDeg(wp.get_target_lon(), wp.get_target_lat());
*wp = new SGWayPoint( apt->getLongitude(), apt->getLatitude(), alt, SGWayPoint::WGS84, target );
return 2;
}
double lat, lon;
// The base lon/lat are determined by the last WP,
// or the current pos if the WP list is empty.
const int wps = this->size();
if (wps > 0) {
SGWayPoint wp = get_waypoint(wps-1);
lat = wp.get_target_lat();
lon = wp.get_target_lon();
} else { } else {
lat = fgGetNode("/position/latitude-deg")->getDoubleValue(); // route is empty, use current position
lon = fgGetNode("/position/longitude-deg")->getDoubleValue(); basePosition = SGGeod::fromDeg(
fgGetNode("/position/longitude-deg")->getDoubleValue(),
fgGetNode("/position/latitude-deg")->getDoubleValue());
} }
// check for fix id
FGFix* f;
double heading;
double dist;
if ( globals->get_fixlist()->query_and_offset( target, lon, lat, 0, f, &heading, &dist ) ) { FGPositionedRef p = FGPositioned::findClosestWithIdent(target, basePosition);
SG_LOG( SG_GENERAL, SG_INFO, "Adding waypoint (fix) = " << target ); if (!p) {
*wp = new SGWayPoint( f->get_lon(), f->get_lat(), alt, SGWayPoint::WGS84, target ); SG_LOG( SG_GENERAL, SG_INFO, "Unable to find FGPositioned with ident:" << target);
return 3; return NULL;
} }
// Try finding a nav matching the ID return new SGWayPoint(p->longitude(), p->latitude(), p->elevation(), SGWayPoint::WGS84, target);
lat *= SGD_DEGREES_TO_RADIANS;
lon *= SGD_DEGREES_TO_RADIANS;
SG_LOG( SG_GENERAL, SG_INFO, "Looking for nav " << target << " at " << lon << " " << lat);
if (FGNavRecord* nav = globals->get_navlist()->findByIdent(target.c_str(), lon, lat)) {
SG_LOG( SG_GENERAL, SG_INFO, "Adding waypoint (nav) = " << target );
*wp = new SGWayPoint( nav->get_lon(), nav->get_lat(), alt, SGWayPoint::WGS84, target );
return 4;
}
// unknown target
return 0;
} }

View file

@ -93,7 +93,7 @@ private:
SGPropertyNode_ptr mirror; SGPropertyNode_ptr mirror;
bool altitude_set; bool altitude_set;
int make_waypoint( SGWayPoint **wp, const string& target ); SGWayPoint* make_waypoint(const string& target);
void update_mirror(); void update_mirror();
bool near_ground(); bool near_ground();
@ -110,7 +110,7 @@ public:
bool build (); bool build ();
int new_waypoint( const string& tgt_alt, int n = -1 ); void new_waypoint( const string& tgt_alt, int n = -1 );
void add_waypoint( const SGWayPoint& wp, int n = -1 ); void add_waypoint( const SGWayPoint& wp, int n = -1 );
SGWayPoint pop_waypoint( int i = 0 ); SGWayPoint pop_waypoint( int i = 0 );

View file

@ -182,38 +182,31 @@ spatialFindTyped(const SGGeod& aPos, double aRange, FGPositioned::Type aLower, F
} }
/** /**
* Cartesian range predicate. Note that for really long ranges, might need to
* to use geodetic / geocentric distance instead
*/ */
class RangePredictate class RangePredictate
{ {
public: public:
RangePredictate(const Point3D& aOrigin, double aRange) : RangePredictate(const SGGeod& aOrigin, double aRange) :
mOrigin(aOrigin), mOrigin(aOrigin),
mRangeSquared(aRange * aRange) mRange(aRange)
{ ; } { ; }
bool operator()(const FGPositionedRef& aPos) bool operator()(const FGPositionedRef& aPos)
{ {
Point3D p(Point3D::fromSGGeod(aPos->geod())); double d, az1, az2;
bool ok = (mOrigin.distance3Dsquared(p) > mRangeSquared); SGGeodesy::inverse(aPos->geod(), mOrigin, az1, az2, d);
if (ok) { return (d > mRange);
double x = sqrt(mOrigin.distance3Dsquared(p) - mRangeSquared);
x *= SG_METER_TO_NM;
//std::cout << "pos:" << aPos->ident() << " failed range check by " << x << std::endl;
}
return ok;
} }
private: private:
Point3D mOrigin; SGGeod mOrigin;
double mRangeSquared; double mRange;
}; };
static void static void
filterListByRange(const SGGeod& aPos, double aRange, FGPositioned::List& aResult) filterListByRange(const SGGeod& aPos, double aRange, FGPositioned::List& aResult)
{ {
RangePredictate pred(Point3D::fromSGGeod(aPos), aRange * SG_NM_TO_METER); RangePredictate pred(aPos, aRange * SG_NM_TO_METER);
FGPositioned::List::iterator newEnd; FGPositioned::List::iterator newEnd;
newEnd = std::remove_if(aResult.begin(), aResult.end(), pred); newEnd = std::remove_if(aResult.begin(), aResult.end(), pred);
aResult.erase(newEnd, aResult.end()); aResult.erase(newEnd, aResult.end());
@ -223,17 +216,19 @@ class DistanceOrdering
{ {
public: public:
DistanceOrdering(const SGGeod& aPos) : DistanceOrdering(const SGGeod& aPos) :
mPos(Point3D::fromSGGeod(aPos)) mPos(aPos)
{ } { }
bool operator()(const FGPositionedRef& a, const FGPositionedRef& b) const bool operator()(const FGPositionedRef& a, const FGPositionedRef& b) const
{ {
return mPos.distance3Dsquared(Point3D::fromSGGeod(a->geod())) < double dA, dB, az1, az2;
mPos.distance3Dsquared(Point3D::fromSGGeod(b->geod())); SGGeodesy::inverse(mPos, a->geod(), az1, az2, dA);
SGGeodesy::inverse(mPos, b->geod(), az1, az2, dB);
return dA < dB;
} }
private: private:
Point3D mPos; SGGeod mPos;
}; };
static void static void
@ -247,7 +242,9 @@ namedFindClosestTyped(const std::string& aIdent, const SGGeod& aOrigin,
FGPositioned::Type aLower, FGPositioned::Type aUpper) FGPositioned::Type aLower, FGPositioned::Type aUpper)
{ {
NamedIndexRange range = global_namedIndex.equal_range(aIdent); NamedIndexRange range = global_namedIndex.equal_range(aIdent);
if (range.first == range.second) return NULL; if (range.first == range.second) {
return NULL;
}
// common case, only one result. looks a bit ugly because these are // common case, only one result. looks a bit ugly because these are
// sequential iterators, not random-access ones // sequential iterators, not random-access ones
@ -265,21 +262,21 @@ namedFindClosestTyped(const std::string& aIdent, const SGGeod& aOrigin,
// multiple matches, we need to actually check the distance to each one // multiple matches, we need to actually check the distance to each one
double minDist = HUGE_VAL; double minDist = HUGE_VAL;
FGPositionedRef result; FGPositionedRef result;
Point3D origin(Point3D::fromSGGeod(aOrigin)); NamedPositionedIndex::const_iterator it = range.first;
for (; range.first != range.second; ++range.first) { for (; it != range.second; ++it) {
// filter by type // filter by type
FGPositioned::Type ty = range.first->second->type(); FGPositioned::Type ty = it->second->type();
if ((ty < aLower) || (ty > aUpper)) { if ((ty < aLower) || (ty > aUpper)) {
continue; continue;
} }
// find distance // find distance
Point3D p(Point3D::fromSGGeod(range.first->second->geod())); double d, az1, az2;
double ds = origin.distance3Dsquared(p); SGGeodesy::inverse(aOrigin, it->second->geod(), az2, az2, d);
if (ds < minDist) { if (d < minDist) {
minDist = ds; minDist = d;
result = range.first->second; result = it->second;
} }
} }
@ -340,26 +337,25 @@ FGPositioned::FGPositioned() :
FGPositioned::FGPositioned(Type ty, const std::string& aIdent, double aLat, double aLon, double aElev) : FGPositioned::FGPositioned(Type ty, const std::string& aIdent, double aLat, double aLon, double aElev) :
mType(ty), mType(ty),
mIdent(aIdent), mPosition(SGGeod::fromDegFt(aLon, aLat, aElev)),
mPosition(SGGeod::fromDegFt(aLon, aLat, aElev)) mIdent(aIdent)
{ {
//addToIndices(this); addToIndices(this);
//SGReferenced::get(this); // hold an owning ref, for the moment SGReferenced::get(this); // hold an owning ref, for the moment
} }
FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos) : FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos) :
mType(ty), mType(ty),
mIdent(aIdent), mPosition(aPos),
mPosition(aPos) mIdent(aIdent)
{ {
//addToIndices(this); addToIndices(this);
//SGReferenced::get(this); // hold an owning ref, for the moment SGReferenced::get(this); // hold an owning ref, for the moment
} }
FGPositioned::~FGPositioned() FGPositioned::~FGPositioned()
{ {
//std::cout << "~FGPositioned:" << mIdent << std::endl; removeFromIndices(this);
//removeFromIndices(this);
} }
SGBucket SGBucket