00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifndef SIMGEAR_QUADTREEBUILDER_HXX
00017 #define SIMGEAR_QUADTREEBUILDER_HXX 1
00018
00019 #include <algorithm>
00020 #include <functional>
00021 #include <vector>
00022 #include <osg/BoundingBox>
00023 #include <osg/ref_ptr>
00024 #include <osg/Node>
00025 #include <osg/Group>
00026 #include <osg/Matrix>
00027 #include <osg/Vec2>
00028 #include <osg/LOD>
00029 #include "VectorArrayAdapter.hxx"
00030
00031 namespace simgear
00032 {
00033 typedef std::map<osg::ref_ptr<osg::Node>,int> LodMap;
00034
00035
00036 template <typename LeafType, typename ObjectType, typename MakeLeaf,
00037 typename AddLeafObject, typename GetObjectLocalCoords>
00038 class QuadTreeBuilder {
00039 public:
00040 QuadTreeBuilder(const GetObjectLocalCoords& getLocalCoords,
00041 const AddLeafObject& addLeafObject, int depth = 2,
00042 const MakeLeaf& makeLeaf = MakeLeaf()) :
00043 _root(new osg::Group), _depth(depth),
00044 _dimension(1 << depth), _leafStorage(_dimension * _dimension),
00045 _leaves(_leafStorage, _dimension),
00046 _leafParents(_leafParentStorage, _dimension / 2),
00047 _getLocalCoords(getLocalCoords),
00048 _addLeafObject(addLeafObject), _makeLeaf(makeLeaf)
00049 {
00050 using namespace std;
00051 using namespace osg;
00052 vector<Group*> parentNodes(1);
00053 parentNodes[0] = _root.get();
00054 unsigned leafDim = 2;
00055 for (int i = 0; i < depth - 1; ++i, leafDim *= 2) {
00056 VectorArrayAdapter<vector<Group*> > parents(parentNodes, leafDim / 2);
00057 vector<Group*> interiorNodes(leafDim * leafDim);
00058 VectorArrayAdapter<vector<Group*> > interiors(interiorNodes, leafDim);
00059 for (unsigned j = 0; j < leafDim; ++j) {
00060 for (unsigned k = 0; k < leafDim; ++k) {
00061 interiors(j, k) = new Group;
00062 parents(j / 2, k / 2)->addChild(interiors(j, k));
00063 }
00064 }
00065 parentNodes.swap(interiorNodes);
00066 }
00067
00068 _leafParentStorage = parentNodes;
00069 }
00070 osg::Vec2 getMin() { return _min; }
00071 void setMin(const osg::Vec2& min) { _min = min; }
00072 osg::Vec2 getMax() { return _max; }
00073 void setMax(const osg::Vec2& max) { _max = max; }
00074 ~QuadTreeBuilder() {}
00075 osg::Group* getRoot() { return _root.get(); }
00076
00077 void addNode(ObjectType& obj)
00078 {
00079 using namespace osg;
00080 const Vec3 center(_getLocalCoords(obj));
00081 int x = 0;
00082 if (_max.x() != _min.x())
00083 x = (int)(_dimension * (center.x() - _min.x())
00084 / (_max.x() - _min.x()));
00085 x = clampTo(x, 0, (_dimension - 1));
00086 int y = 0;
00087 if (_max.y() != _min.y())
00088 y = (int)(_dimension * (center.y() - _min.y())
00089 / (_max.y() - _min.y()));
00090 y = clampTo(y, 0, (_dimension -1));
00091 if (!_leaves(y, x)) {
00092 _leaves(y, x) = _makeLeaf();
00093 _leafParents(y / 2, x / 2)->addChild(_leaves(y, x));
00094 }
00095 _addLeafObject(_leaves(y, x), obj);
00096 }
00097
00098 struct AddNode
00099 {
00100 AddNode(QuadTreeBuilder* qt) : _qt(qt) {}
00101 AddNode(const AddNode& rhs) : _qt(rhs._qt) {}
00102 void operator() (ObjectType& obj) const { _qt->addNode(obj); }
00103 QuadTreeBuilder *_qt;
00104 };
00105
00106 template <typename ForwardIterator>
00107 void buildQuadTree(const ForwardIterator& begin,
00108 const ForwardIterator& end)
00109 {
00110 using namespace osg;
00111 BoundingBox extents;
00112 for (ForwardIterator iter = begin; iter != end; ++iter) {
00113 const Vec3 center = _getLocalCoords(*iter);
00114 extents.expandBy(center);
00115 }
00116 _min = Vec2(extents.xMin(), extents.yMin());
00117 _max = Vec2(extents.xMax(), extents.yMax());
00118 std::for_each(begin, end, AddNode(this));
00119 }
00120
00121 protected:
00122 typedef std::vector<LeafType> LeafVector;
00123 osg::ref_ptr<osg::Group> _root;
00124 osg::Vec2 _min;
00125 osg::Vec2 _max;
00126 int _depth;
00127 int _dimension;
00128 LeafVector _leafStorage;
00129 VectorArrayAdapter<LeafVector> _leaves;
00130 std::vector<osg::Group*> _leafParentStorage;
00131 VectorArrayAdapter<std::vector<osg::Group*> > _leafParents;
00132 const GetObjectLocalCoords _getLocalCoords;
00133 const AddLeafObject _addLeafObject;
00134 const MakeLeaf _makeLeaf;
00135 };
00136
00137 }
00138 #endif