1
0
Fork 0
flightgear/src/Navaids/PositionedOctree.hxx
James Turner e52e20b54f SHPParser
2015-11-27 23:02:42 +00:00

250 lines
6.5 KiB
C++

/**
* PositionedOctree - define a spatial octree containing Positioned items
* arranged by their global cartesian position.
*/
// Written by James Turner, started 2012.
//
// Copyright (C) 2012 James Turner
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef FG_POSITIONED_OCTREE_HXX
#define FG_POSITIONED_OCTREE_HXX
// std
#include <vector>
#include <set>
#include <queue>
#include <cassert>
#include <map>
#include <functional>
// SimGear
#include <simgear/math/SGGeometry.hxx>
#include <Navaids/positioned.hxx>
#include <Navaids/NavDataCache.hxx>
#include <Navaids/PolyLine.hxx>
namespace flightgear
{
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)
{
assert(!isnan(x));
}
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;
// for extracting lines, we don't care about distance ordering, since
// we're always grabbing all the lines in an area
typedef std::deque<Node*> FindLinesDeque;
extern Node* global_spatialOctree;
class Leaf;
/**
* Octree node base class, tracks its bounding box and provides various
* queries relating to it
*/
class Node
{
public:
int64_t guid() const
{ return _ident; }
const SGBoxd& bbox() const
{ return _box; }
bool contains(const SGVec3d& aPos) const
{
return intersects(aPos, _box);
}
double distToNearest(const SGVec3d& aPos) const
{
return dist(aPos, _box.getClosestPoint(aPos));
}
virtual void visit(const SGVec3d& aPos, double aCutoff,
FGPositioned::Filter* aFilter,
FindNearestResults& aResults, FindNearestPQueue&) = 0;
virtual Leaf* findLeafForPos(const SGVec3d& aPos) const = 0;
virtual void visitForLines(const SGVec3d& aPos, double aCutoff,
PolyLineList& aLines,
FindLinesDeque& aQ) const;
virtual Node* findNodeForBox(const SGBoxd& box) const;
virtual ~Node() {}
void addPolyLine(const PolyLineRef&);
protected:
Node(const SGBoxd &aBox, int64_t aIdent) :
_ident(aIdent),
_box(aBox)
{
}
const int64_t _ident;
const SGBoxd _box;
PolyLineList lines;
};
class Leaf : public Node
{
public:
Leaf(const SGBoxd& aBox, int64_t aIdent);
virtual void visit(const SGVec3d& aPos, double aCutoff,
FGPositioned::Filter* aFilter,
FindNearestResults& aResults, FindNearestPQueue&);
virtual Leaf* findLeafForPos(const SGVec3d&) const
{
return const_cast<Leaf*>(this);
}
void insertChild(FGPositioned::Type ty, PositionedID id);
private:
bool childrenLoaded;
typedef std::multimap<FGPositioned::Type, PositionedID> ChildMap;
ChildMap children;
void loadChildren();
};
class Branch : public Node
{
public:
Branch(const SGBoxd& aBox, int64_t aIdent);
virtual void visit(const SGVec3d& aPos, double aCutoff,
FGPositioned::Filter*,
FindNearestResults&, FindNearestPQueue& aQ);
virtual Leaf* findLeafForPos(const SGVec3d& aPos) const
{
loadChildren();
return childForPos(aPos)->findLeafForPos(aPos);
}
int childMask() const;
virtual void visitForLines(const SGVec3d& aPos, double aCutoff,
PolyLineList& aLines,
FindLinesDeque& aQ) const;
virtual Node* findNodeForBox(const SGBoxd& box) const;
private:
Node* childForPos(const SGVec3d& aCart) const;
Node* childAtIndex(int childIndex) const;
/**
* 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;
}
void loadChildren() const;
mutable Node* children[8];
mutable bool childrenLoaded;
};
bool findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPositioned::Filter* aFilter, FGPositionedList& aResults, int aCutoffMsec);
bool findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filter* aFilter, FGPositionedList& aResults, int aCutoffMsec);
} // of namespace Octree
} // of namespace flightgear
#endif // of FG_POSITIONED_OCTREE_HXX