From: jmt Date: Sun, 27 Sep 2009 23:12:58 +0000 (+0000) Subject: Further extensions to FGPositioned to support ongoing GPS work. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=5755b7ae0e989d2059d69ea0238ba813a73df250;p=flightgear.git Further extensions to FGPositioned to support ongoing GPS work. --- diff --git a/src/Navaids/positioned.cxx b/src/Navaids/positioned.cxx index 6324578c3..93204670b 100644 --- a/src/Navaids/positioned.cxx +++ b/src/Navaids/positioned.cxx @@ -474,6 +474,10 @@ FGPositioned::cart() const FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) { + if (aName.empty() || (aName == "")) { + return INVALID; + } + typedef struct { const char* _name; Type _ty; @@ -489,7 +493,8 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) {"dme", DME}, // aliases {"waypoint", WAYPOINT}, - + {"apt", AIRPORT}, + {NULL, INVALID} }; @@ -585,55 +590,60 @@ FGPositioned::findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm return spatialGetClosest(aPos, aN, aCutoffNm, aFilter); } -/* FGPositionedRef FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId, Filter* aFilter) { + // It is essential to bound our search, to avoid iterating all the way to the end of the database. + // Do this by generating a second ID with the final character incremented by 1. + // e.g., if the partial ID is "KI", we wish to search "KIxxx" but not "KJ". + std::string upperBoundId = aId; + upperBoundId[upperBoundId.size()-1]++; + NamedPositionedIndex::const_iterator upperBound = global_namedIndex.lower_bound(upperBoundId); + NamedIndexRange range = global_namedIndex.equal_range(aId); - for (; range.first != range.second; ++range.first) { - FGPositionedRef candidate = range.first->second; - if (aCur == candidate) { - aCur = NULL; // found our start point, next match will pass - continue; - } - - if (aFilter) { - if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) { + while (range.first != upperBound) { + for (; range.first != range.second; ++range.first) { + FGPositionedRef candidate = range.first->second; + if (aCur == candidate) { + aCur = NULL; // found our start point, next match will pass continue; } - if(!aFilter->pass(candidate)) { - continue; + if (aFilter) { + if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) { + continue; + } + + if (!aFilter->pass(candidate)) { + continue; + } + } + + if (!aCur) { + return candidate; } } - - if (!aCur) { - return candidate; - } + + // Unable to match the filter with this range - try the next range. + range = global_namedIndex.equal_range(range.second->first); } - - return NULL; // fell out, no match in range -}*/ + return NULL; // Reached the end of the valid sequence with no match. +} + FGPositionedRef -FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId, Filter* aFilter) +FGPositioned::findWithPartialId(const std::string& aId, Filter* aFilter, int aOffset) { - // It is essential to bound our search, to avoid iterating all the way to the end of the database. - // Do this by generating a second ID with the final character incremented by 1. - // e.g., if the partial ID is "KI", we wish to search "KIxxx" but not "KJ". + // see comment in findNextWithPartialId concerning upperBoundId std::string upperBoundId = aId; upperBoundId[upperBoundId.size()-1]++; NamedPositionedIndex::const_iterator upperBound = global_namedIndex.lower_bound(upperBoundId); NamedIndexRange range = global_namedIndex.equal_range(aId); + while (range.first != upperBound) { for (; range.first != range.second; ++range.first) { FGPositionedRef candidate = range.first->second; - if (aCur == candidate) { - aCur = NULL; // found our start point, next match will pass - continue; - } - if (aFilter) { if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) { continue; @@ -644,8 +654,10 @@ FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId } } - if (!aCur) { + if (aOffset == 0) { return candidate; + } else { + --aOffset; // seen one more valid result, decrement the count } } @@ -655,5 +667,50 @@ FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId return NULL; // Reached the end of the valid sequence with no match. } + +/** + * Wrapper filter which proxies to an inner filter, but also ensures the + * ident starts with supplied partial ident. + */ +class PartialIdentFilter : public FGPositioned::Filter +{ +public: + PartialIdentFilter(const std::string& ident, FGPositioned::Filter* filter) : + _ident(ident), + _inner(filter) + { ; } + virtual bool pass(FGPositioned* aPos) const + { + if (!_inner->pass(aPos)) { + return false; + } + + return (::strncmp(aPos->ident().c_str(), _ident.c_str(), _ident.size()) == 0); + } + + virtual FGPositioned::Type minType() const + { return _inner->minType(); } + + virtual FGPositioned::Type maxType() const + { return _inner->maxType(); } + +private: + std::string _ident; + FGPositioned::Filter* _inner; +}; + +FGPositionedRef +FGPositioned::findClosestWithPartialId(const SGGeod& aPos, const std::string& aId, Filter* aFilter, int aOffset) +{ + PartialIdentFilter pf(aId, aFilter); + List matches = spatialGetClosest(aPos, aOffset + 1, 1000.0, &pf); + + if ((int) matches.size() <= aOffset) { + SG_LOG(SG_GENERAL, SG_INFO, "FGPositioned::findClosestWithPartialId, couldn't match enough with prefix:" << aId); + return NULL; // couldn't find a match within the cutoff distance + } + + return matches[aOffset]; +} diff --git a/src/Navaids/positioned.hxx b/src/Navaids/positioned.hxx index 4d1f6081f..b56f3b093 100644 --- a/src/Navaids/positioned.hxx +++ b/src/Navaids/positioned.hxx @@ -158,6 +158,11 @@ public: */ static FGPositionedRef findNextWithPartialId(FGPositionedRef aCur, const std::string& aId, Filter* aFilter = NULL); + /** + * As above, but searches using an offset index + */ + static FGPositionedRef findWithPartialId(const std::string& aId, Filter* aFilter, int aOffset); + /** * Find all items with the specified ident, and return then sorted by * distance from a position @@ -182,12 +187,18 @@ public: * Very large cutoff values will make this slow. * * @result The matches (possibly less than N, depending on the filter and cutoff), - * sorted by distance from the search pos + * sorted by distance from the search pos * @param aN - number of matches to find * @param aCutoffNm - maximum distance to search within, in nautical miles */ static List findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter = NULL); + /** + * Find the closest match based on partial id (with an offset to allow selecting the n-th closest). + * Cutoff distance is limited internally, to avoid making this very slow. + */ + static FGPositionedRef findClosestWithPartialId(const SGGeod& aPos, const std::string& aId, Filter* aFilter, int aOffset); + /** * Map a candidate type string to a real type. Returns INVALID if the string * does not correspond to a defined type.