X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FNavaids%2Fpositioned.cxx;h=bdc7d17a55bcb596cc07706e712a8b64a4d9d205;hb=9575783491783bfdb6f6dcbfa59ba750a3cf0da6;hp=7aa183eba02be4a831f782f39b433c4871b210fc;hpb=348ff2ec23298db4db3b3f2b12d301dec73ec8e1;p=flightgear.git diff --git a/src/Navaids/positioned.cxx b/src/Navaids/positioned.cxx index 7aa183eba..bdc7d17a5 100644 --- a/src/Navaids/positioned.cxx +++ b/src/Navaids/positioned.cxx @@ -33,582 +33,65 @@ #include #include -#include // for osg::isNaN - #include -#include #include #include #include #include -#include - -#include "PositionedBinding.hxx" -#include "Airports/simple.hxx" -#include "Main/fg_props.hxx" - -typedef std::multimap NamedPositionedIndex; -typedef std::pair NamedIndexRange; - -using std::lower_bound; -using std::upper_bound; - -static NamedPositionedIndex global_identIndex; -static NamedPositionedIndex global_nameIndex; - -////////////////////////////////////////////////////////////////////////////// - -namespace Octree -{ - -const double LEAF_SIZE = SG_NM_TO_METER * 8.0; -const double LEAF_SIZE_SQR = LEAF_SIZE * LEAF_SIZE; - -/** - * Decorate an object with a double value, and use that value to order - * items, for the purpoises of the STL algorithms - */ -template -class Ordered -{ -public: - Ordered(const T& v, double x) : - _order(x), - _inner(v) - { - } - - Ordered(const Ordered& a) : - _order(a._order), - _inner(a._inner) - { - } - - Ordered& operator=(const Ordered& a) - { - _order = a._order; - _inner = a._inner; - return *this; - } - - bool operator<(const Ordered& other) const - { - return _order < other._order; - } - - bool operator>(const Ordered& other) const - { - return _order > other._order; - } - - const T& get() const - { return _inner; } - - double order() const - { return _order; } - -private: - double _order; - T _inner; -}; - -class Node; -typedef Ordered OrderedNode; -typedef std::greater FNPQCompare; - -/** - * the priority queue is fundamental to our search algorithm. When searching, - * we know the front of the queue is the nearest unexpanded node (to the search - * location). The default STL pqueue returns the 'largest' item from top(), so - * to get the smallest, we need to replace the default Compare functor (less<>) - * with greater<>. - */ -typedef std::priority_queue, FNPQCompare> FindNearestPQueue; - -typedef Ordered OrderedPositioned; -typedef std::vector FindNearestResults; - -Node* global_spatialOctree = NULL; - -/** - * Octree node base class, tracks its bounding box and provides various - * queries relating to it - */ -class Node -{ -public: - bool contains(const SGVec3d& aPos) const - { - return intersects(aPos, _box); - } - - double distSqrToNearest(const SGVec3d& aPos) const - { - return distSqr(aPos, _box.getClosestPoint(aPos)); - } - - virtual void insert(FGPositioned* aP) = 0; - - virtual void visit(const SGVec3d& aPos, double aCutoff, - FGPositioned::Filter* aFilter, - FindNearestResults& aResults, FindNearestPQueue&) = 0; -protected: - Node(const SGBoxd &aBox) : - _box(aBox) - { - } - - const SGBoxd _box; -}; -class Leaf : public Node -{ -public: - Leaf(const SGBoxd& aBox) : - Node(aBox) - { - } - - const FGPositioned::List& members() const - { return _members; } - - virtual void insert(FGPositioned* aP) - { - _members.push_back(aP); - } - - virtual void visit(const SGVec3d& aPos, double aCutoff, - FGPositioned::Filter* aFilter, - FindNearestResults& aResults, FindNearestPQueue&) - { - int previousResultsSize = aResults.size(); - int addedCount = 0; - - for (unsigned int i=0; i<_members.size(); ++i) { - FGPositioned* p = _members[i]; - double d2 = distSqr(aPos, p->cart()); - if (d2 > aCutoff) { - continue; - } - - if (aFilter) { - if (aFilter->hasTypeRange() && !aFilter->passType(p->type())) { - continue; - } - - if (!aFilter->pass(p)) { - continue; - } - } // of have a filter +#include "Navaids/PositionedOctree.hxx" - ++addedCount; - aResults.push_back(OrderedPositioned(p, d2)); - } - - if (addedCount == 0) { - return; - } - - // keep aResults sorted - // sort the new items, usually just one or two items - std::sort(aResults.begin() + previousResultsSize, aResults.end()); - - // merge the two sorted ranges together - in linear time - std::inplace_merge(aResults.begin(), - aResults.begin() + previousResultsSize, aResults.end()); - } -private: - FGPositioned::List _members; -}; - -class Branch : public Node -{ -public: - Branch(const SGBoxd& aBox) : - Node(aBox) - { - memset(children, 0, sizeof(Node*) * 8); - } - - virtual void insert(FGPositioned* aP) - { - SGVec3d cart(aP->cart()); - assert(contains(cart)); - int childIndex = 0; - - SGVec3d center(_box.getCenter()); - // tests must match indices in SGbox::getCorner - if (cart.x() < center.x()) { - childIndex += 1; - } - - if (cart.y() < center.y()) { - childIndex += 2; - } - - if (cart.z() < center.z()) { - childIndex += 4; - } - - Node* child = children[childIndex]; - if (!child) { // lazy building of children - SGBoxd cb(boxForChild(childIndex)); - double d2 = dot(cb.getSize(), cb.getSize()); - if (d2 < LEAF_SIZE_SQR) { - child = new Leaf(cb); - } else { - child = new Branch(cb); - } - - children[childIndex] = child; - } - - child->insert(aP); - } - - virtual void visit(const SGVec3d& aPos, double aCutoff, - FGPositioned::Filter*, - FindNearestResults&, FindNearestPQueue& aQ) - { - for (unsigned int i=0; i<8; ++i) { - if (!children[i]) { - continue; - } - - double d2 = children[i]->distSqrToNearest(aPos); - if (d2 > aCutoff) { - continue; // exceeded cutoff - } - - aQ.push(Ordered(children[i], d2)); - } // of child iteration - } - - -private: - /** - * Return the box for a child touching the specified corner - */ - SGBoxd boxForChild(unsigned int aCorner) const - { - SGBoxd r(_box.getCenter()); - r.expandBy(_box.getCorner(aCorner)); - return r; - } - - Node* children[8]; -}; - -void findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults) -{ - aResults.clear(); - FindNearestPQueue pq; - FindNearestResults results; - pq.push(Ordered(global_spatialOctree, 0)); - double cut = aCutoffM * aCutoffM; - - while (!pq.empty()) { - if (!results.empty()) { - // terminate the search if we have sufficent results, and we are - // sure no node still on the queue contains a closer match - double furthestResultOrder = results.back().order(); - if ((results.size() >= aN) && (furthestResultOrder < pq.top().order())) { - break; - } - } - - Node* nd = pq.top().get(); - pq.pop(); - - nd->visit(aPos, cut, aFilter, results, pq); - } // of queue iteration - - // depending on leaf population, we may have (slighty) more results - // than requested - unsigned int numResults = std::min((unsigned int) results.size(), aN); - // copy results out - aResults.resize(numResults); - for (unsigned int r=0; r(global_spatialOctree, 0)); - double rng = aRangeM * aRangeM; - - while (!pq.empty()) { - Node* nd = pq.top().get(); - pq.pop(); - - nd->visit(aPos, rng, aFilter, results, pq); - } // of queue iteration - - unsigned int numResults = results.size(); - // copy results out - aResults.resize(numResults); - for (unsigned int r=0; rident().empty()) { - std::string u(boost::to_upper_copy(aPos->ident())); - - global_identIndex.insert(global_identIndex.begin(), - 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(u, aPos)); - } - - if (!Octree::global_spatialOctree) { - double RADIUS_EARTH_M = 7000 * 1000.0; // 7000km is plenty - SGVec3d earthExtent(RADIUS_EARTH_M, RADIUS_EARTH_M, RADIUS_EARTH_M); - Octree::global_spatialOctree = new Octree::Branch(SGBox(-earthExtent, earthExtent)); - } - Octree::global_spatialOctree->insert(aPos); -} - -static void -removeFromIndices(FGPositioned* aPos) -{ - assert(aPos); - - if (!aPos->ident().empty()) { - 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; - } - - ++it; - } // of multimap walk - } - - if (!aPos->name().empty()) { - 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; - } - - ++it; - } // of multimap walk - } -} - -////////////////////////////////////////////////////////////////////////////// - -class OrderByName -{ -public: - bool operator()(FGPositioned* a, FGPositioned* b) const - { - return a->name() < b->name(); - } -}; - -void findInIndex(NamedPositionedIndex& aIndex, const std::string& aFind, std::vector& aResult) -{ - NamedPositionedIndex::const_iterator it = aIndex.begin(); - NamedPositionedIndex::const_iterator end = aIndex.end(); - - bool haveFilter = !aFind.empty(); - - for (; it != end; ++it) { - FGPositioned::Type ty = it->second->type(); - if ((ty < FGPositioned::AIRPORT) || (ty > FGPositioned::SEAPORT)) { - continue; - } - - if (haveFilter && it->first.find(aFind) == std::string::npos) { - continue; - } - - aResult.push_back(it->second); - } // of index iteration -} - -/** - * A special purpose helper (imported by FGAirport::searchNamesAndIdents) to - * implement the AirportList dialog. It's unfortunate that it needs to reside - * here, but for now it's least ugly solution. - */ -char** searchAirportNamesAndIdents(const std::string& aFilter) -{ -// 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; - if (!aFilter.empty()) { - std::string filter = boost::to_upper_copy(aFilter); - findInIndex(global_identIndex, filter, matches); - findInIndex(global_nameIndex, filter, matches); - } else { - - findInIndex(global_identIndex, std::string(), matches); - } - -// sort alphabetically on name - std::sort(matches.begin(), matches.end(), OrderByName()); - -// 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 - - // nasty code to avoid excessive string copying and allocations. - // We format results as follows (note whitespace!): - // ' name-of-airport-chars (ident)' - // so the total length is: - // 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[7 + nameLength + icaoLength]; - char* dst = entry; - *dst++ = ' '; - memcpy(dst, matches[i]->name().c_str(), nameLength); - dst += nameLength; - *dst++ = ' '; - *dst++ = ' '; - *dst++ = ' '; - *dst++ = '('; - memcpy(dst, matches[i]->ident().c_str(), icaoLength); - dst += icaoLength; - *dst++ = ')'; - *dst++ = 0; - result[i] = entry; - } - - return result; -} +using std::string; +using namespace flightgear; static void validateSGGeod(const SGGeod& geod) { - if (osg::isNaN(geod.getLatitudeDeg()) || - osg::isNaN(geod.getLongitudeDeg())) + if (SGMisc::isNaN(geod.getLatitudeDeg()) || + SGMisc::isNaN(geod.getLongitudeDeg())) { throw sg_range_exception("position is invalid, NaNs"); } } -/////////////////////////////////////////////////////////////////////////////// - -bool -FGPositioned::Filter::hasTypeRange() const -{ - assert(minType() <= maxType()); - return (minType() != INVALID) && (maxType() != INVALID); -} - -bool -FGPositioned::Filter::passType(Type aTy) const -{ - assert(hasTypeRange()); - return (minType() <= aTy) && (maxType() >= aTy); -} - -static FGPositioned::List -findAll(const NamedPositionedIndex& aIndex, - const std::string& aName, - FGPositioned::Filter* aFilter, - bool aExact) -{ - FGPositioned::List result; - 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; - } - - if (!aFilter->pass(candidate)) { - continue; - } - } - - result.push_back(candidate); - } - - return result; -} /////////////////////////////////////////////////////////////////////////////// -FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos) : +FGPositioned::FGPositioned(PositionedID aGuid, Type ty, const std::string& aIdent, const SGGeod& aPos) : + mGuid(aGuid), mPosition(aPos), + mCart(SGVec3d::fromGeod(mPosition)), 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(mType != TAXIWAY && mType != PAVEMENT); - addToIndices(this); - } -} - FGPositioned::~FGPositioned() { - //std::cout << "destroying:" << mIdent << "/" << nameForType(mType) << std::endl; - removeFromIndices(this); +// std::cout << "destroying:" << mIdent << "/" << nameForType(mType) << std::endl; } FGPositioned* FGPositioned::createUserWaypoint(const std::string& aIdent, const SGGeod& aPos) { - FGPositioned* wpt = new FGPositioned(WAYPOINT, aIdent, aPos); - wpt->init(true); - return wpt; + NavDataCache* cache = NavDataCache::instance(); + TypeFilter filter(WAYPOINT); + FGPositionedList existing = cache->findAllWithIdent(aIdent, &filter, true); + if (!existing.empty()) { + SG_LOG(SG_NAVAID, SG_WARN, "attempt to insert duplicate WAYPOINT:" << aIdent); + return existing.front().ptr(); + } + + PositionedID id = cache->createPOI(WAYPOINT, aIdent, aPos); + return cache->loadById(id); +} + +void FGPositioned::deleteUserWaypoint(const std::string& aIdent) +{ + NavDataCache* cache = NavDataCache::instance(); + cache->removePOI(WAYPOINT, aIdent); } + const SGVec3d& FGPositioned::cart() const { @@ -629,6 +112,9 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) const NameTypeEntry names[] = { {"airport", AIRPORT}, {"vor", VOR}, + {"loc", LOC}, + {"ils", ILS}, + {"gs", GS}, {"ndb", NDB}, {"wpt", WAYPOINT}, {"fix", FIX}, @@ -640,12 +126,21 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) {"ground", FREQ_GROUND}, {"approach", FREQ_APP_DEP}, {"departure", FREQ_APP_DEP}, + {"runway", RUNWAY}, + {"helipad", HELIPAD}, + {"country", COUNTRY}, + {"city", CITY}, + {"town", TOWN}, + {"village", VILLAGE}, + // aliases + {"localizer", LOC}, {"gnd", FREQ_GROUND}, {"twr", FREQ_TOWER}, {"waypoint", WAYPOINT}, {"apt", AIRPORT}, {"arpt", AIRPORT}, + {"rwy", RUNWAY}, {"any", INVALID}, {"all", INVALID}, @@ -660,7 +155,7 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) } } - SG_LOG(SG_GENERAL, SG_WARN, "FGPositioned::typeFromName: couldn't match:" << aName); + SG_LOG(SG_NAVAID, SG_WARN, "FGPositioned::typeFromName: couldn't match:" << aName); return INVALID; } @@ -668,14 +163,15 @@ const char* FGPositioned::nameForType(Type aTy) { switch (aTy) { case RUNWAY: return "runway"; + case HELIPAD: return "helipad"; case TAXIWAY: return "taxiway"; case PAVEMENT: return "pavement"; - case PARK_STAND: return "parking stand"; + case PARKING: return "parking stand"; case FIX: return "fix"; case VOR: return "VOR"; case NDB: return "NDB"; case ILS: return "ILS"; - case LOC: return "localiser"; + case LOC: return "localizer"; case GS: return "glideslope"; case OM: return "outer-marker"; case MM: return "middle-marker"; @@ -693,55 +189,76 @@ const char* FGPositioned::nameForType(Type aTy) case FREQ_CLEARANCE: return "clearance"; case FREQ_UNICOM: return "unicom"; case FREQ_APP_DEP: return "approach-departure"; + case TAXI_NODE: return "taxi-node"; + case COUNTRY: return "country"; + case CITY: return "city"; + case TOWN: return "town"; + case VILLAGE: return "village"; 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) { - validateSGGeod(aPos); + validateSGGeod(aPos); + return NavDataCache::instance()->findClosestWithIdent(aIdent, aPos, aFilter); +} - FGPositioned::List r(findAll(global_identIndex, aIdent, aFilter, true)); +FGPositionedRef +FGPositioned::findFirstWithIdent(const std::string& aIdent, Filter* aFilter) +{ + if (aIdent.empty()) { + return NULL; + } + + FGPositionedList r = + NavDataCache::instance()->findAllWithIdent(aIdent, aFilter, true); if (r.empty()) { - return FGPositionedRef(); + return NULL; } - sortByRange(r, aPos); return r.front(); } -FGPositioned::List +FGPositionedList FGPositioned::findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter) { validateSGGeod(aPos); - List result; + FGPositionedList result; Octree::findAllWithinRange(SGVec3d::fromGeod(aPos), - aRangeNm * SG_NM_TO_METER, aFilter, result); + aRangeNm * SG_NM_TO_METER, aFilter, result, 0xffffff); + return result; +} + +FGPositionedList +FGPositioned::findWithinRangePartial(const SGGeod& aPos, double aRangeNm, Filter* aFilter, bool& aPartial) +{ + validateSGGeod(aPos); + + int limitMsec = 32; + FGPositionedList result; + aPartial = Octree::findAllWithinRange(SGVec3d::fromGeod(aPos), + aRangeNm * SG_NM_TO_METER, aFilter, result, + limitMsec); return result; } -FGPositioned::List +FGPositionedList FGPositioned::findAllWithIdent(const std::string& aIdent, Filter* aFilter, bool aExact) { - return findAll(global_identIndex, aIdent, aFilter, aExact); + return NavDataCache::instance()->findAllWithIdent(aIdent, aFilter, aExact); } -FGPositioned::List +FGPositionedList FGPositioned::findAllWithName(const std::string& aName, Filter* aFilter, bool aExact) { - return findAll(global_nameIndex, aName, aFilter, aExact); + return NavDataCache::instance()->findAllWithName(aName, aFilter, aExact); } FGPositionedRef @@ -749,7 +266,7 @@ FGPositioned::findClosest(const SGGeod& aPos, double aCutoffNm, Filter* aFilter) { validateSGGeod(aPos); - List l(findClosestN(aPos, 1, aCutoffNm, aFilter)); + FGPositionedList l(findClosestN(aPos, 1, aCutoffNm, aFilter)); if (l.empty()) { return NULL; } @@ -758,72 +275,38 @@ FGPositioned::findClosest(const SGGeod& aPos, double aCutoffNm, Filter* aFilter) return l.front(); } -FGPositioned::List +FGPositionedList 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); + FGPositionedList result; + int limitMsec = 0xffff; + Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result, limitMsec); return result; } -FGPositionedRef -FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId, Filter* aFilter) +FGPositionedList +FGPositioned::findClosestNPartial(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter, bool &aPartial) { - if (aId.empty()) { - return NULL; - } - - std::string id(boost::to_upper_copy(aId)); - - // 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 = id; - upperBoundId[upperBoundId.size()-1]++; - NamedPositionedIndex::const_iterator upperBound = global_identIndex.lower_bound(upperBoundId); - - NamedIndexRange range = global_identIndex.equal_range(id); - 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; - } - - if (!aFilter->pass(candidate)) { - continue; - } - } - - if (!aCur) { - return candidate; - } - } - - // Unable to match the filter with this range - try the next range. - range = global_identIndex.equal_range(range.second->first); - } - - return NULL; // Reached the end of the valid sequence with no match. + validateSGGeod(aPos); + + FGPositionedList result; + int limitMsec = 32; + aPartial = Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result, + limitMsec); + return result; } - + void -FGPositioned::sortByRange(List& aResult, const SGGeod& aPos) +FGPositioned::sortByRange(FGPositionedList& aResult, const SGGeod& aPos) { validateSGGeod(aPos); SGVec3d cartPos(SGVec3d::fromGeod(aPos)); // computer ordering values Octree::FindNearestResults r; - List::iterator it = aResult.begin(), lend = aResult.end(); + FGPositionedList::iterator it = aResult.begin(), lend = aResult.end(); for (; it != lend; ++it) { double d2 = distSqr((*it)->cart(), cartPos); r.push_back(Octree::OrderedPositioned(*it, d2)); @@ -839,142 +322,49 @@ FGPositioned::sortByRange(List& aResult, const SGGeod& aPos) } } -FGPositioned::Filter* createSearchFilter(const SGPropertyNode* arg) +void FGPositioned::modifyPosition(const SGGeod& newPos) { - string sty(arg->getStringValue("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; + const_cast(mPosition) = newPos; + const_cast(mCart) = SGVec3d::fromGeod(newPos); } -static SGGeod commandSearchPos(const SGPropertyNode* arg) +//------------------------------------------------------------------------------ +FGPositionedRef FGPositioned::loadByIdImpl(PositionedID id) { - 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")); + return flightgear::NavDataCache::instance()->loadById(id); } -void commandClearExisting(const SGPropertyNode* arg) +FGPositioned::TypeFilter::TypeFilter(Type aTy) : + mMinType(aTy), + mMaxType(aTy) { - 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 */); - } -} - -bool commandFindClosest(const SGPropertyNode* arg) -{ - 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; - } - - 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); - - SGGeod pos = commandSearchPos(arg); - commandClearExisting(arg); - - FGPositioned::List results = FGPositioned::findClosestN(pos, n, cutoff, filt.get()); - for (unsigned int i=0; igetStringValue("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); -} - -FGPositioned::TypeFilter::TypeFilter(Type aTy) -{ - types.push_back(aTy); + addType(aTy); } void FGPositioned::TypeFilter::addType(Type aTy) { - types.push_back(aTy); + if (aTy == INVALID) { + return; + } + + types.push_back(aTy); + mMinType = std::min(mMinType, aTy); + mMaxType = std::max(mMaxType, aTy); } bool FGPositioned::TypeFilter::pass(FGPositioned* aPos) const { + if (types.empty()) { + return true; + } + std::vector::const_iterator it = types.begin(), end = types.end(); for (; it != end; ++it) { - return aPos->type() == *it; + if (aPos->type() == *it) { + return true; + } } return false;