X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FNavaids%2Fpositioned.cxx;h=7aa183eba02be4a831f782f39b433c4871b210fc;hb=4928886e562c04bf8a8497a6b4f70aba793e20c2;hp=bbd0443063330acacd69b9d72c22a3cc7088f3cb;hpb=992b7ca8f4e58494b0bbc5ef7e228c65879ba0e8;p=flightgear.git diff --git a/src/Navaids/positioned.cxx b/src/Navaids/positioned.cxx index bbd044306..7aa183eba 100644 --- a/src/Navaids/positioned.cxx +++ b/src/Navaids/positioned.cxx @@ -22,21 +22,30 @@ # include "config.h" #endif +#include "positioned.hxx" + #include #include #include // for sort #include +#include #include #include -#include +#include // for osg::isNaN + #include +#include #include #include -#include +#include +#include +#include -#include "positioned.hxx" +#include "PositionedBinding.hxx" +#include "Airports/simple.hxx" +#include "Main/fg_props.hxx" typedef std::multimap NamedPositionedIndex; typedef std::pair NamedIndexRange; @@ -55,27 +64,6 @@ namespace Octree const double LEAF_SIZE = SG_NM_TO_METER * 8.0; const double LEAF_SIZE_SQR = LEAF_SIZE * LEAF_SIZE; -typedef SGBox SGBoxd; - -template -inline bool -intersects(const SGVec3& v, const SGBox& box) -{ - if (v[0] < box.getMin()[0]) - return false; - if (box.getMax()[0] < v[0]) - return false; - if (v[1] < box.getMin()[1]) - return false; - if (box.getMax()[1] < v[1]) - return false; - if (v[2] < box.getMin()[2]) - return false; - if (box.getMax()[2] < v[2]) - return false; - return true; -} - /** * Decorate an object with a double value, and use that value to order * items, for the purpoises of the STL algorithms @@ -156,28 +144,11 @@ public: double distSqrToNearest(const SGVec3d& aPos) const { - return distSqr(aPos, getClosestPoint(aPos)); + return distSqr(aPos, _box.getClosestPoint(aPos)); } virtual void insert(FGPositioned* aP) = 0; - SGVec3d getClosestPoint(const SGVec3d& aPos) const - { - SGVec3d r; - - for (unsigned int i=0;i<3; ++i) { - if (aPos[i] < _box.getMin()[i]) { - r[i] = _box.getMin()[i]; - } else if (aPos[i] > _box.getMax()[i]) { - r[i] = _box.getMax()[i]; - } else { - r[i] = aPos[i]; - } - } // of axis iteration - - return r; - } - virtual void visit(const SGVec3d& aPos, double aCutoff, FGPositioned::Filter* aFilter, FindNearestResults& aResults, FindNearestPQueue&) = 0; @@ -394,13 +365,17 @@ addToIndices(FGPositioned* aPos) { assert(aPos); if (!aPos->ident().empty()) { + std::string u(boost::to_upper_copy(aPos->ident())); + global_identIndex.insert(global_identIndex.begin(), - std::make_pair(aPos->ident(), aPos)); + std::make_pair(u, aPos)); } if (!aPos->name().empty()) { + std::string u(boost::to_upper_copy(aPos->name())); + global_nameIndex.insert(global_nameIndex.begin(), - std::make_pair(aPos->name(), aPos)); + std::make_pair(u, aPos)); } if (!Octree::global_spatialOctree) { @@ -417,8 +392,9 @@ removeFromIndices(FGPositioned* aPos) assert(aPos); if (!aPos->ident().empty()) { - NamedPositionedIndex::iterator it = global_identIndex.find(aPos->ident()); - while (it != global_identIndex.end() && (it->first == aPos->ident())) { + std::string u(boost::to_upper_copy(aPos->ident())); + NamedPositionedIndex::iterator it = global_identIndex.find(u); + while (it != global_identIndex.end() && (it->first == u)) { if (it->second == aPos) { global_identIndex.erase(it); break; @@ -429,8 +405,9 @@ removeFromIndices(FGPositioned* aPos) } if (!aPos->name().empty()) { - NamedPositionedIndex::iterator it = global_nameIndex.find(aPos->name()); - while (it != global_nameIndex.end() && (it->first == aPos->name())) { + std::string u(boost::to_upper_copy(aPos->name())); + NamedPositionedIndex::iterator it = global_nameIndex.find(u); + while (it != global_nameIndex.end() && (it->first == u)) { if (it->second == aPos) { global_nameIndex.erase(it); break; @@ -441,102 +418,38 @@ removeFromIndices(FGPositioned* aPos) } } -class DistanceOrdering +////////////////////////////////////////////////////////////////////////////// + +class OrderByName { public: - DistanceOrdering(const SGGeod& aPos) : - mPos(SGVec3d::fromGeod(aPos)) - { } - - bool operator()(const FGPositionedRef& a, const FGPositionedRef& b) const + bool operator()(FGPositioned* a, FGPositioned* b) const { - if (!a || !b) { - throw sg_exception("empty reference passed to DistanceOrdering"); - } - - double dA = distSqr(a->cart(), mPos), - dB = distSqr(b->cart(), mPos); - return dA < dB; + return a->name() < b->name(); } - -private: - SGVec3d mPos; }; -static void -sortByDistance(const SGGeod& aPos, FGPositioned::List& aResult) +void findInIndex(NamedPositionedIndex& aIndex, const std::string& aFind, std::vector& aResult) { - std::sort(aResult.begin(), aResult.end(), DistanceOrdering(aPos)); -} + NamedPositionedIndex::const_iterator it = aIndex.begin(); + NamedPositionedIndex::const_iterator end = aIndex.end(); -static FGPositionedRef -namedFindClosest(const NamedPositionedIndex& aIndex, const std::string& aName, - const SGGeod& aOrigin, FGPositioned::Filter* aFilter) -{ - NamedIndexRange range = aIndex.equal_range(aName); - if (range.first == range.second) { - return NULL; - } - -// common case, only one result. looks a bit ugly because these are -// sequential iterators, not random-access ones - NamedPositionedIndex::const_iterator check = range.first; - if (++check == range.second) { - // excellent, only one match in the range - FGPositioned* r = range.first->second; - if (aFilter) { - if (aFilter->hasTypeRange() && !aFilter->passType(r->type())) { - return NULL; - } - - if (!aFilter->pass(r)) { - return NULL; - } - } // of have a filter - - return r; - } // of short-circuit logic for single-element range - -// multiple matches, we need to actually check the distance to each one - double minDist = HUGE_VAL; - FGPositionedRef result; - NamedPositionedIndex::const_iterator it = range.first; - SGVec3d cartOrigin(SGVec3d::fromGeod(aOrigin)); - - for (; it != range.second; ++it) { - FGPositioned* r = it->second; - if (aFilter) { - if (aFilter->hasTypeRange() && !aFilter->passType(r->type())) { - continue; - } - - if (!aFilter->pass(r)) { - continue; - } + bool haveFilter = !aFind.empty(); + + for (; it != end; ++it) { + FGPositioned::Type ty = it->second->type(); + if ((ty < FGPositioned::AIRPORT) || (ty > FGPositioned::SEAPORT)) { + continue; } - // find distance - double d2 = distSqr(cartOrigin, r->cart()); - if (d2 < minDist) { - minDist = d2; - result = r; + if (haveFilter && it->first.find(aFind) == std::string::npos) { + continue; } - } - - return result; + + aResult.push_back(it->second); + } // of index iteration } -////////////////////////////////////////////////////////////////////////////// - -class OrderByName -{ -public: - bool operator()(FGPositioned* a, FGPositioned* b) const - { - return a->name() < b->name(); - } -}; - /** * A special purpose helper (imported by FGAirport::searchNamesAndIdents) to * implement the AirportList dialog. It's unfortunate that it needs to reside @@ -544,43 +457,23 @@ public: */ char** searchAirportNamesAndIdents(const std::string& aFilter) { - const std::ctype &ct = std::use_facet >(std::locale()); - std::string filter(aFilter); - bool hasFilter = !filter.empty(); - if (hasFilter) { - ct.toupper((char *)filter.data(), (char *)filter.data() + filter.size()); - } - - NamedPositionedIndex::const_iterator it = global_identIndex.begin(); - NamedPositionedIndex::const_iterator end = global_identIndex.end(); - - // note this is a vector of raw pointers, not smart pointers, because it - // may get very large and smart-pointer-atomicity-locking then becomes a - // bottleneck for this case. +// note this is a vector of raw pointers, not smart pointers, because it +// may get very large and smart-pointer-atomicity-locking then becomes a +// bottleneck for this case. std::vector matches; - std::string upper; - - for (; it != end; ++it) { - FGPositioned::Type ty = it->second->type(); - if ((ty < FGPositioned::AIRPORT) || (ty > FGPositioned::SEAPORT)) { - continue; - } + if (!aFilter.empty()) { + std::string filter = boost::to_upper_copy(aFilter); + findInIndex(global_identIndex, filter, matches); + findInIndex(global_nameIndex, filter, matches); + } else { - if (hasFilter && (it->second->ident().find(aFilter) == std::string::npos)) { - upper = it->second->name(); // string copy, sadly - ct.toupper((char *)upper.data(), (char *)upper.data() + upper.size()); - if (upper.find(aFilter) == std::string::npos) { - continue; - } - } - - matches.push_back(it->second); + findInIndex(global_identIndex, std::string(), matches); } - // sort alphabetically on name +// sort alphabetically on name std::sort(matches.begin(), matches.end(), OrderByName()); - // convert results to format comptible with puaList +// convert results to format comptible with puaList unsigned int numMatches = matches.size(); char** result = new char*[numMatches + 1]; result[numMatches] = NULL; // end-of-list marker @@ -589,13 +482,14 @@ char** searchAirportNamesAndIdents(const std::string& aFilter) // We format results as follows (note whitespace!): // ' name-of-airport-chars (ident)' // so the total length is: - // 1 + strlen(name) + 4 + 4 (for the ident) + 1 + 1 (for the null) - // which gives a grand total of 11 + the length of the name. - // note the ident is sometimes only three letters for non-ICAO small strips + // 1 + strlen(name) + 4 + strlen(icao) + 1 + 1 (for the null) + // which gives a grand total of 7 + name-length + icao-length. + // note the ident can be three letters (non-ICAO local strip), four + // (default ICAO) or more (extended format ICAO) for (unsigned int i=0; iname().size(); int icaoLength = matches[i]->ident().size(); - char* entry = new char[nameLength + 11]; + char* entry = new char[7 + nameLength + icaoLength]; char* dst = entry; *dst++ = ' '; memcpy(dst, matches[i]->name().c_str(), nameLength); @@ -614,6 +508,15 @@ char** searchAirportNamesAndIdents(const std::string& aFilter) return result; } +static void validateSGGeod(const SGGeod& geod) +{ + if (osg::isNaN(geod.getLatitudeDeg()) || + osg::isNaN(geod.getLongitudeDeg())) + { + throw sg_range_exception("position is invalid, NaNs"); + } +} + /////////////////////////////////////////////////////////////////////////////// bool @@ -630,14 +533,32 @@ FGPositioned::Filter::passType(Type aTy) const return (minType() <= aTy) && (maxType() >= aTy); } -static FGPositioned::List -findAllSortedByRange(const NamedPositionedIndex& aIndex, - const std::string& aName, const SGGeod& aPos, FGPositioned::Filter* aFilter) +static FGPositioned::List +findAll(const NamedPositionedIndex& aIndex, + const std::string& aName, + FGPositioned::Filter* aFilter, + bool aExact) { FGPositioned::List result; - NamedIndexRange range = aIndex.equal_range(aName); - for (; range.first != range.second; ++range.first) { - FGPositioned* candidate = range.first->second; + if (aName.empty()) { + return result; + } + + std::string name = boost::to_upper_copy(aName); + NamedPositionedIndex::const_iterator upperBound; + + if (aExact) { + upperBound = aIndex.upper_bound(name); + } else { + std::string upperBoundId = name; + upperBoundId[upperBoundId.size()-1]++; + upperBound = aIndex.lower_bound(upperBoundId); + } + + NamedPositionedIndex::const_iterator it = aIndex.lower_bound(name); + + for (; it != upperBound; ++it) { + FGPositionedRef candidate = it->second; if (aFilter) { if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) { continue; @@ -648,70 +569,28 @@ findAllSortedByRange(const NamedPositionedIndex& aIndex, } } - result.push_back(range.first->second); + result.push_back(candidate); } - sortByDistance(aPos, result); return result; } -static FGPositionedRef -findWithPartial(const NamedPositionedIndex& aIndex, const std::string& aName, - FGPositioned::Filter* aFilter, int aOffset, bool& aNext) -{ - // see comment in findNextWithPartialId concerning upperBoundId - std::string upperBoundId = aName; - upperBoundId[upperBoundId.size()-1]++; - NamedPositionedIndex::const_iterator upperBound = aIndex.lower_bound(upperBoundId); - - NamedIndexRange range = aIndex.equal_range(aName); - FGPositionedRef result; - - while (range.first != upperBound) { - for (; range.first != range.second; ++range.first) { - FGPositionedRef candidate = range.first->second; - if (aFilter) { - if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) { - continue; - } - - if (!aFilter->pass(candidate)) { - continue; - } - } - - if (result) { - aNext = true; - return result; - } else if (aOffset == 0) { - // okay, found our result. we need to go around once more to set aNext - result = candidate; - } else { - --aOffset; // seen one more valid result, decrement the count - } - } - - // Unable to match the filter with this range - try the next range. - range = aIndex.equal_range(range.second->first); - } - - // if we fell out, we reached the end of the valid range. We might have a - // valid result, but we definitiely don't have a next result. - aNext = false; - return result; -} - /////////////////////////////////////////////////////////////////////////////// -FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos, bool aIndexed) : - mType(ty), +FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos) : mPosition(aPos), + mType(ty), mIdent(aIdent) { +} + +void FGPositioned::init(bool aIndexed) +{ SGReferenced::get(this); // hold an owning ref, for the moment + mCart = SGVec3d::fromGeod(mPosition); if (aIndexed) { - assert(ty != TAXIWAY && ty != PAVEMENT); + assert(mType != TAXIWAY && mType != PAVEMENT); addToIndices(this); } } @@ -725,19 +604,15 @@ FGPositioned::~FGPositioned() FGPositioned* FGPositioned::createUserWaypoint(const std::string& aIdent, const SGGeod& aPos) { - return new FGPositioned(WAYPOINT, aIdent, aPos, true); + FGPositioned* wpt = new FGPositioned(WAYPOINT, aIdent, aPos); + wpt->init(true); + return wpt; } -SGBucket -FGPositioned::bucket() const -{ - return SGBucket(mPosition); -} - -SGVec3d +const SGVec3d& FGPositioned::cart() const { - return SGVec3d::fromGeod(mPosition); + return mCart; } FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) @@ -759,7 +634,15 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) {"fix", FIX}, {"tacan", TACAN}, {"dme", DME}, + {"atis", FREQ_ATIS}, + {"awos", FREQ_AWOS}, + {"tower", FREQ_TOWER}, + {"ground", FREQ_GROUND}, + {"approach", FREQ_APP_DEP}, + {"departure", FREQ_APP_DEP}, // aliases + {"gnd", FREQ_GROUND}, + {"twr", FREQ_TOWER}, {"waypoint", WAYPOINT}, {"apt", AIRPORT}, {"arpt", AIRPORT}, @@ -803,23 +686,46 @@ const char* FGPositioned::nameForType(Type aTy) case WAYPOINT: return "waypoint"; case DME: return "dme"; case TACAN: return "tacan"; + case FREQ_TOWER: return "tower"; + case FREQ_ATIS: return "atis"; + case FREQ_AWOS: return "awos"; + case FREQ_GROUND: return "ground"; + case FREQ_CLEARANCE: return "clearance"; + case FREQ_UNICOM: return "unicom"; + case FREQ_APP_DEP: return "approach-departure"; default: return "unknown"; } } +flightgear::PositionedBinding* +FGPositioned::createBinding(SGPropertyNode* node) const +{ + return new flightgear::PositionedBinding(this, node); +} + /////////////////////////////////////////////////////////////////////////////// // search / query functions FGPositionedRef FGPositioned::findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter) { - return namedFindClosest(global_identIndex, aIdent, aPos, aFilter); + validateSGGeod(aPos); + + FGPositioned::List r(findAll(global_identIndex, aIdent, aFilter, true)); + if (r.empty()) { + return FGPositionedRef(); + } + + sortByRange(r, aPos); + return r.front(); } FGPositioned::List FGPositioned::findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter) { + validateSGGeod(aPos); + List result; Octree::findAllWithinRange(SGVec3d::fromGeod(aPos), aRangeNm * SG_NM_TO_METER, aFilter, result); @@ -827,32 +733,36 @@ FGPositioned::findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilt } FGPositioned::List -FGPositioned::findAllWithIdentSortedByRange(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter) +FGPositioned::findAllWithIdent(const std::string& aIdent, Filter* aFilter, bool aExact) { - return findAllSortedByRange(global_identIndex, aIdent, aPos, aFilter); + return findAll(global_identIndex, aIdent, aFilter, aExact); } FGPositioned::List -FGPositioned::findAllWithNameSortedByRange(const std::string& aName, const SGGeod& aPos, Filter* aFilter) +FGPositioned::findAllWithName(const std::string& aName, Filter* aFilter, bool aExact) { - return findAllSortedByRange(global_nameIndex, aName, aPos, aFilter); + return findAll(global_nameIndex, aName, aFilter, aExact); } FGPositionedRef FGPositioned::findClosest(const SGGeod& aPos, double aCutoffNm, Filter* aFilter) { - List l(findClosestN(aPos, 1, aCutoffNm, aFilter)); - if (l.empty()) { - return NULL; - } - - assert(l.size() == 1); - return l.front(); + validateSGGeod(aPos); + + List l(findClosestN(aPos, 1, aCutoffNm, aFilter)); + if (l.empty()) { + return NULL; + } + + assert(l.size() == 1); + return l.front(); } FGPositioned::List FGPositioned::findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter) { + validateSGGeod(aPos); + List result; Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result); return result; @@ -905,115 +815,168 @@ FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId return NULL; // Reached the end of the valid sequence with no match. } -FGPositionedRef -FGPositioned::findWithPartialId(const std::string& aId, Filter* aFilter, int aOffset, bool& aNext) +void +FGPositioned::sortByRange(List& aResult, const SGGeod& aPos) { - return findWithPartial(global_identIndex, aId, aFilter, aOffset, aNext); + validateSGGeod(aPos); + + SGVec3d cartPos(SGVec3d::fromGeod(aPos)); +// computer ordering values + Octree::FindNearestResults r; + List::iterator it = aResult.begin(), lend = aResult.end(); + for (; it != lend; ++it) { + double d2 = distSqr((*it)->cart(), cartPos); + r.push_back(Octree::OrderedPositioned(*it, d2)); + } + +// sort + std::sort(r.begin(), r.end()); + +// convert to a plain list + unsigned int count = aResult.size(); + for (unsigned int i=0; igetStringValue("type", "any")); + FGPositioned::Type ty = FGPositioned::typeFromName(sty); + double minRunwayLenFt = arg->getDoubleValue("min-runway-length-ft", -1.0); + + if ((ty == FGPositioned::AIRPORT) && (minRunwayLenFt > 0.0)) { + return new FGAirport::HardSurfaceFilter(minRunwayLenFt); + } else if (ty != FGPositioned::INVALID) { + FGPositioned::TypeFilter* tf = new FGPositioned::TypeFilter(ty); + + for (int t=1; arg->hasChild("type", t); ++t) { + sty = arg->getChild("type", t)->getStringValue(); + tf->addType(FGPositioned::typeFromName(sty)); + } + + return tf; + } + + return NULL; +} -FGPositionedRef -FGPositioned::findWithPartialName(const std::string& aName, Filter* aFilter, int aOffset, bool& aNext) +static SGGeod commandSearchPos(const SGPropertyNode* arg) +{ + if (arg->hasChild("longitude-deg") && arg->hasChild("latitude-deg")) { + return SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"), + arg->getDoubleValue("latitude-deg")); + } + + // use current viewer/aircraft position + return SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), + fgGetDouble("/position/latitude-deg")); +} + +void commandClearExisting(const SGPropertyNode* arg) { - return findWithPartial(global_nameIndex, aName, aFilter, aOffset, aNext); + if (arg->getBoolValue("clear", true)) { + // delete all existing result children from their parent + string resultPath = arg->getStringValue("results"); + SGPropertyNode* n = fgGetNode(resultPath.c_str(), 0, true); + SGPropertyNode* pr = n->getParent(); + pr->removeChildren(n->getName(), false /* keep=false, i.e delete nodes */); + } } -/** - * Wrapper filter which proxies to an inner filter, but also ensures the - * ident starts with supplied partial ident. - */ -class PartialIdentFilter : public FGPositioned::Filter +bool commandFindClosest(const SGPropertyNode* arg) { -public: - PartialIdentFilter(const std::string& ident, FGPositioned::Filter* filter) : - _inner(filter) - { - _ident = boost::to_upper_copy(ident); - } - - virtual bool pass(FGPositioned* aPos) const - { - if (!_inner->pass(aPos)) { - return false; + int n = arg->getIntValue("max-results", 1); + if ((n < 1) || (n > 100)) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: max-results invalid:" << n); + return false; } - return (boost::algorithm::starts_with(aPos->ident(), _ident)); - } + string resultPath = arg->getStringValue("results"); + if (resultPath.empty()) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: no results path defined"); + return false; + } + + std::auto_ptr filt(createSearchFilter(arg)); +// cap search range, since huge ranges will overload everything + double cutoff = arg->getDoubleValue("cutoff-nm", 400.0); + SG_CLAMP_RANGE(cutoff, 0.0, 1000.0); - virtual FGPositioned::Type minType() const - { return _inner->minType(); } + SGGeod pos = commandSearchPos(arg); + commandClearExisting(arg); - virtual FGPositioned::Type maxType() const - { return _inner->maxType(); } + FGPositioned::List results = FGPositioned::findClosestN(pos, n, cutoff, filt.get()); + for (unsigned int i=0; i= (aOffset + 2)); - return matches[aOffset]; + string resultPath = arg->getStringValue("results"); + if (resultPath.empty()) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no results path defined"); + return false; + } + + std::auto_ptr filt(createSearchFilter(arg)); + SGGeod pos = commandSearchPos(arg); + commandClearExisting(arg); + + FGPositioned::List results; + bool exact = arg->getBoolValue("exact", true); + if (arg->hasChild("name")) { + results = FGPositioned::findAllWithName(arg->getStringValue("name"), filt.get(), exact); + } else if (arg->hasChild("ident")) { + results = FGPositioned::findAllWithIdent(arg->getStringValue("ident"), filt.get(), exact); + } else { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no search term defined"); + return false; + } + + bool orderByRange = arg->getBoolValue("order-by-distance", true); + if (orderByRange) { + FGPositioned::sortByRange(results, pos); + } + + for (unsigned int i=0; iaddCommand("find-nearest", commandFindClosest); + SGCommandMgr::instance()->addCommand("find-by-ident", commandFindByIdent); } -FGPositionedRef -FGPositioned::findClosestWithPartialId(const SGGeod& aPos, const std::string& aId, Filter* aFilter, int aOffset, bool& aNext) +FGPositioned::TypeFilter::TypeFilter(Type aTy) { - PartialIdentFilter pf(aId, aFilter); - return findClosestWithPartial(aPos, &pf, aOffset, aNext); + types.push_back(aTy); } -/** - * Wrapper filter which proxies to an inner filter, but also ensures the - * name starts with supplied partial name. - */ -class PartialNameFilter : public FGPositioned::Filter +void FGPositioned::TypeFilter::addType(Type aTy) { -public: - PartialNameFilter(const std::string& nm, FGPositioned::Filter* filter) : - _inner(filter) - { - _name = nm; - } - - virtual bool pass(FGPositioned* aPos) const - { - if (!_inner->pass(aPos)) { - return false; - } - - return (boost::algorithm::istarts_with(aPos->name(), _name)); - } - - virtual FGPositioned::Type minType() const - { return _inner->minType(); } - - virtual FGPositioned::Type maxType() const - { return _inner->maxType(); } - -private: - std::string _name; - FGPositioned::Filter* _inner; -}; + types.push_back(aTy); +} -FGPositionedRef -FGPositioned::findClosestWithPartialName(const SGGeod& aPos, const std::string& aName, Filter* aFilter, int aOffset, bool& aNext) +bool +FGPositioned::TypeFilter::pass(FGPositioned* aPos) const { - PartialNameFilter pf(aName, aFilter); - return findClosestWithPartial(aPos, &pf, aOffset, aNext); + std::vector::const_iterator it = types.begin(), + end = types.end(); + for (; it != end; ++it) { + return aPos->type() == *it; + } + + return false; }