-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
-
- ++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<Node*>(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<Node*>(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<numResults; ++r) {
- aResults[r] = results[r].get();
- }
-}
-
-void findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults)
-{
- aResults.clear();
- FindNearestPQueue pq;
- FindNearestResults results;
- pq.push(Ordered<Node*>(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; r<numResults; ++r) {
- aResults[r] = results[r].get();
- }
-}
-
-} // of namespace Octree
-
-//////////////////////////////////////////////////////////////////////////////
-
-static void
-addToIndices(FGPositioned* aPos)
-{
- assert(aPos);
- if (!aPos->ident().empty()) {
- global_identIndex.insert(global_identIndex.begin(),
- std::make_pair(aPos->ident(), aPos));
- }
-
- if (!aPos->name().empty()) {
- global_nameIndex.insert(global_nameIndex.begin(),
- std::make_pair(aPos->name(), 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<double>(-earthExtent, earthExtent));
- }
- Octree::global_spatialOctree->insert(aPos);
-}
-
-static void
-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())) {
- if (it->second == aPos) {
- global_identIndex.erase(it);
- break;
- }
-
- ++it;
- } // of multimap walk
- }
-
- if (!aPos->name().empty()) {
- NamedPositionedIndex::iterator it = global_nameIndex.find(aPos->name());
- while (it != global_nameIndex.end() && (it->first == aPos->name())) {
- if (it->second == aPos) {
- global_nameIndex.erase(it);
- break;
- }
-
- ++it;
- } // of multimap walk
- }
-}
-
-class DistanceOrdering
-{
-public:
- DistanceOrdering(const SGGeod& aPos) :
- mPos(SGVec3d::fromGeod(aPos))
- { }
-
- bool operator()(const FGPositionedRef& a, const FGPositionedRef& b) const