ELVE  1
ELVE Logic Visualization Explorer
/home/travis/build/stdgregwar/elve/Core/QuadTree.cpp
00001 #include "QuadTree.h"
00002 #include <cmath>
00003 #include <assert.h>
00004 #include <algorithm>
00005 #include <QDebug>
00006 #include <limits>
00007 
00008 namespace Elve {
00009 
00010 using namespace std;
00011 #define THRESHOLD 512
00012 
00013 QuadTree::QuadTree(const QRectF &bounds) : mParams{0.5,6,10}
00014 {
00015     mNodes = nullptr;
00016     init(bounds);
00017 }
00018 
00019 QuadTree& QuadTree::operator=(QuadTree&& other) {
00020     mNodes = other.mNodes;
00021     other.mNodes = nullptr;
00022     init(other.bounds());
00023 }
00024 
00025 void QuadTree::setBounds(const QRectF& bounds) {
00026     initLite(bounds);
00027     reinsertAll();
00028 }
00029 
00030 bool QuadTree::init(const QRectF &bounds)
00031 {
00032     reset();
00033 
00034     if(!mNodes) {
00035         mNodes = reinterpret_cast<QuadTreeNode*>(new unsigned char[QUADTREESIZE*sizeof(QuadTreeNode)]);
00036     }
00037 
00038     if(!mNodes) {return false;}
00039     QuadTreeNode* root = rootNode();
00040 
00041     for(long i = QUADTREESIZE;i--;)
00042     {
00043         new (&root[i])QuadTreeNode();
00044     }
00045     return initLite(bounds);
00046 }
00047 
00048 bool QuadTree::initLite(const QRectF& bounds) {
00049     // Nodes are stored so that all nodes in a level are sequential in memory until
00050     //  the next level.  Within each level, the nodes are 2D arrays of equal width
00051     //  and height, double the previous layer.  There are 8 layers, with the first
00052     //  being 1-by-1 and the last being 128-by-128.
00053     //
00054     // This loop goes over each level
00055 
00056     mRadius = max(bounds.width()*0.5f,bounds.height()*0.5f);
00057 
00058     mInverseRadius = 255.f / (2*mRadius);
00059     mPos = {bounds.left() + bounds.width()*0.5f, bounds.top() + bounds.height()*0.5f};;
00060 
00061     QuadTreeNode* root = rootNode();
00062     float radius = mRadius;
00063     QuadTreeNode* pqtnThis = root, *pqtnLast = nullptr;
00064     float fFull = radius*2.f;
00065 
00066     QVector2D vOffset( -radius, -radius);
00067     for (unsigned I = 0UL; I < mParams.depth; ++I ) {
00068         mLevels[I] = pqtnThis;
00069         // For each node at this level.
00070         for (unsigned Y = (1UL << I); Y--; ) {
00071             QuadTreeNode* pqtnRow = &pqtnThis[Y*(1UL<<I)];
00072             float fYPos = float( Y ) / float( 1UL << I ) * fFull + radius + mPos.y();
00073             for ( unsigned X = (1UL << I); X--; ) {
00074                 pqtnRow[X].setCenterAndRadius(QVector2D(float( X ) / float( 1UL << I ) * fFull + radius + mPos.x(), fYPos ) + vOffset,
00075                     radius);
00076 
00077                 if ( pqtnLast ) {
00078                     // There is a parent.  Get its index.
00079                     unsigned ui32ParentX = X >> 1UL;
00080                     unsigned ui32ParentY = Y >> 1UL;
00081                     unsigned ui32ParentIndex = (ui32ParentY * (1UL << (I - 1UL))) + ui32ParentX;
00082                     unsigned ui32X = X & 1UL;
00083                     unsigned ui32Y = Y & 1UL;
00084                     pqtnLast[ui32ParentIndex].setChild((ui32Y << 1UL) + ui32X, &pqtnRow[X] );
00085                 }
00086             }
00087         }
00088 
00089         pqtnLast = pqtnThis;
00090         pqtnThis += (1UL << I) * (1UL << I);
00091         radius *= 0.5f;
00092     }
00093 
00094     return true;
00095 }
00096 
00097 bool QuadTree::initNodesPos(const QRectF& bounds)
00098 {
00099     // Nodes are stored so that all nodes in a level are sequential in memory until
00100     //  the next level.  Within each level, the nodes are 2D arrays of equal width
00101     //  and height, double the previous layer.  There are 8 layers, with the first
00102     //  being 1-by-1 and the last being 128-by-128.
00103     //
00104     // This loop goes over each level
00105 
00106     mRadius = max(bounds.width()*0.5f,bounds.height()*0.5f);
00107     mInverseRadius = 255.f / (2*mRadius);
00108     mPos = {bounds.left() + bounds.width()*0.5f, bounds.top() + bounds.height()*0.5f};;
00109 
00110     QuadTreeNode* root = rootNode();
00111     float radius = mRadius;
00112     QuadTreeNode* pqtnThis = root, *pqtnLast = nullptr;
00113     float fFull = radius*2.f;
00114 
00115     QVector2D vOffset( -radius, -radius);
00116     for (unsigned I = 0UL; I < mParams.depth; ++I ) {
00117         mLevels[I] = pqtnThis;
00118         // For each node at this level.
00119         for (unsigned Y = (1UL << I); Y--; ) {
00120             QuadTreeNode* pqtnRow = &pqtnThis[Y*(1UL<<I)];
00121             float fYPos = float( Y ) / float( 1UL << I ) * fFull + radius + mPos.y();
00122             for ( unsigned X = (1UL << I); X--; ) {
00123                 pqtnRow[X].setCenterAndRadius(QVector2D(float( X ) / float( 1UL << I ) * fFull + radius + mPos.x(), fYPos ) + vOffset,
00124                     radius);
00125             }
00126         }
00127         pqtnLast = pqtnThis;
00128         pqtnThis += (1UL << I) * (1UL << I);
00129         radius *= 0.5f;
00130     }
00131     return true;
00132 }
00133 
00134 QRectF QuadTree::bounds() const {
00135     return QRectF{
00136               mPos.x() - mRadius,
00137               mPos.y() - mRadius,
00138               mRadius*2,
00139               mRadius*2
00140     };
00141 }
00142 
00143 bool QuadTree::addPoint(const Point *m)
00144 {
00145     mPoints.insert(m);
00146     return _addPoint(m);
00147 }
00148 
00149 bool QuadTree::_addPoint(const Point *m)
00150 {
00151     //qDebug() << "bounds" << bounds();
00152     if(bounds().contains(m->pos().toPointF())) {
00153         return rootNode()->addPoint(m,mParams);
00154     } else { //Trigger resizing of the quadtree
00155         qDebug() << "resizing quad tree!!! because of" << m->pos();
00156         QRectF newRect = unionRectVec(bounds(),m->pos());
00157         newRect.adjust(-100,-100,100,100);
00158         initNodesPos(newRect);
00159         for(const Point* r : mPoints) { //Re add all objects
00160             _addPoint(r);
00161         }
00162         //addObject(obj); //Finaly add obj
00163     }
00164     return false;
00165 }
00166 
00167 QRectF QuadTree::computeMinRect()
00168 {
00169     QRectF r(0,0,0,0);
00170     //qDebug() << "mass count : " << mMasses.size();
00171     for(const Point* m : mPoints) {
00172         r = unionRectVec(r,m->pos());
00173     }
00174     return r.adjusted(-100,-100,100,100);
00175 }
00176 
00177 void QuadTree::reinsertAll()
00178 {
00179     //qDebug() << "Reinserting all";
00180     static int count = 0;
00181     count++;
00182     for(long i = QUADTREESIZE; i--;) {
00183         mNodes[i].reset();
00184     }
00185 
00186     if(count > 400) {
00187         QRectF rect = computeMinRect();
00188         initNodesPos(computeMinRect());
00189         count = 0;
00190     }
00191 
00192     for(const Point* m : mPoints) {
00193         _addPoint(m);
00194     }
00195     //qDebug() << "Reinserting all end";
00196 }
00197 
00198 void QuadTree::removePoint(const Point *m)
00199 {
00200     QuadTreeNode* node = static_cast<QuadTreeNode*>(m->containerData());
00201     if(node) {
00202         node->remPoint(m,mParams);
00203     }
00204 }
00205 
00206 void QuadTree::clear()
00207 {
00208     for(long i = QUADTREESIZE; i--;) {
00209         mNodes[i].reset();
00210     }
00211     mPoints.clear();
00212 }
00213 
00214 void QuadTree::movePoint(const Point *m)
00215 {
00216     QuadTreeNode* node = static_cast<QuadTreeNode*>(m->containerData());
00217     if(node && !node->contain(m)) {
00218         removePoint(m);
00219         addPoint(m);
00220     } else {
00221         addPoint(m);
00222     }
00223 }
00224 
00225 QuadTreeNode* QuadTree::rootNode() const
00226 {
00227     return mNodes;
00228 }
00229 
00230 void QuadTree::debug(QPainter *p) const
00231 {
00232     for_each(mNodes,mNodes+unsigned(pow(4,mParams.depth)),[&p](const QuadTreeNode& n){n.debug(p);});
00233 }
00234 
00235 QVector2D QuadTree::gravityFor(const Point& m) const
00236 {
00237     return rootNode()->gravityFor(m,mParams);
00238 }
00239 
00240 void QuadTree::reset()
00241 {
00242     if(mNodes) {
00243         // The number of nodes is fixed.
00244         for (long i = QUADTREESIZE; i--;) {
00245             mNodes[i].~QuadTreeNode();
00246         }
00247         //free((void*)mNodes);
00248         //mNodes = nullptr;
00249     }
00250 }
00251 
00252 QuadTree::~QuadTree()
00253 {
00254     reset();
00255     if(mNodes)
00256         free((void*)mNodes);
00257 }
00258 
00259 }
 All Classes Functions