-#include "positioned.hxx"
-
-typedef std::multimap<std::string, FGPositioned*> NamedPositionedIndex;
-typedef std::pair<NamedPositionedIndex::const_iterator, NamedPositionedIndex::const_iterator> 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 T>
-class Ordered
-{
-public:
- Ordered(const T& v, double x) :
- _order(x),
- _inner(v)
- {
- }
-
- Ordered(const Ordered<T>& a) :
- _order(a._order),
- _inner(a._inner)
- {
- }
-
- Ordered<T>& operator=(const Ordered<T>& a)
- {
- _order = a._order;
- _inner = a._inner;
- return *this;
- }
-
- bool operator<(const Ordered<T>& other) const
- {
- return _order < other._order;
- }
-
- bool operator>(const Ordered<T>& 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<Node*> OrderedNode;
-typedef std::greater<OrderedNode> 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<OrderedNode, std::vector<OrderedNode>, FNPQCompare> FindNearestPQueue;
-
-typedef Ordered<FGPositioned*> OrderedPositioned;
-typedef std::vector<OrderedPositioned> 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
-
- ++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];
-};