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
00050
00051
00052
00053
00054
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
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
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
00100
00101
00102
00103
00104
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
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
00152 if(bounds().contains(m->pos().toPointF())) {
00153 return rootNode()->addPoint(m,mParams);
00154 } else {
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) {
00160 _addPoint(r);
00161 }
00162
00163 }
00164 return false;
00165 }
00166
00167 QRectF QuadTree::computeMinRect()
00168 {
00169 QRectF r(0,0,0,0);
00170
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
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
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
00244 for (long i = QUADTREESIZE; i--;) {
00245 mNodes[i].~QuadTreeNode();
00246 }
00247
00248
00249 }
00250 }
00251
00252 QuadTree::~QuadTree()
00253 {
00254 reset();
00255 if(mNodes)
00256 free((void*)mNodes);
00257 }
00258
00259 }