ELVE  1
ELVE Logic Visualization Explorer
/home/travis/build/stdgregwar/elve/Core/QuadTreeNode.cpp
00001 #include "QuadTreeNode.h"
00002 #include <QDebug>
00003 
00004 #include <QPen>
00005 #include <QPainter>
00006 
00007 namespace Elve {
00008 
00009 using namespace std;
00010 
00011 //#define DEBUG_QUAD
00012 
00013 QuadTreeNode::QuadTreeNode()
00014 {
00015     reset();
00016     mPoints.reserve(100); //Should be enough
00017     for(int i = 0; i < 4; i++)
00018         mChildren[i] = nullptr;
00019     //pen().setColor(Qt::red);
00020 }
00021 
00022 void QuadTreeNode::setCenterAndRadius(const QVector2D& pos, float radius)
00023 {
00024     mCenter = pos;
00025     mRadius = radius;
00026 }
00027 
00028 void QuadTreeNode::setChild(unsigned index, QuadTreeNode* node)
00029 {
00030     node->setParent(this);
00031     mChildren[index] = node;
00032 }
00033 
00034 void QuadTreeNode::debug(QPainter* p) const
00035 {
00036     if(leaf() && mPoints.size()) {
00037         p->drawRect(mCenter.x()-mRadius,mCenter.y()-mRadius,2*mRadius,2*mRadius);
00038         QPointF c = CoM().toPointF();
00039         //p->drawEllipse(c,4096,4096);
00040         p->drawEllipse(c,32,32);
00041         p->drawText(c,QString::number(mMass));
00042     }
00043 }
00044 
00045 bool QuadTreeNode::addPoint(const Point *m, const QuadTreeParams &params)
00046 {
00047     if(contain(m)) {
00048         //qDebug() << mCenter << mRadius << "Contains!" << m->pos();
00049         mCount++;
00050         //qDebug() << "count" << mCount << "masses" << mMasses.size();
00051         if(mCount < params.maxMasses || !mChildren[0]) {
00052             //qDebug() << "inserting it";
00053             mPoints.push_back(m);
00054             m->setContainerData(this);
00055         } else {
00056             //qDebug() << "no more space splitting";
00057             for(const Point* om : mPoints) {
00058                 for(int i = 0; i < 4; i++) {
00059                     mChildren[i]->addPoint(om,params);
00060                 }
00061             }
00062             mPoints.clear();
00063             for(int i = 0; i < 4; i++) { //Add new mass
00064                 mChildren[i]->addPoint(m,params);
00065             }
00066         }
00067         mMC += m->pos()*m->mass();
00068         mMass += m->mass();
00069         return true;
00070     } else {
00071         return false;
00072     }
00073 }
00074 
00075 std::vector<const Point *> &QuadTreeNode::givePoints()
00076 {
00077     mCount = 0;
00078     mMass = 0;
00079     mMC = {0,0};
00080     return mPoints;
00081 }
00082 
00083 void QuadTreeNode::remPoint(const Point *m, const QuadTreeParams &params)
00084 {
00085     mCount--;
00086     mPoints.erase(remove(mPoints.begin(),mPoints.end(),m),mPoints.end());
00087     mMass -= m->mass();
00088     mMC -= m->pos();
00089 
00090     if(mCount <= params.maxMasses) { //call masses one level up
00091         for(int i = 0; i < 4 && mChildren[i]; i++) {
00092             vector<const Point*>& mset = mChildren[i]->givePoints();
00093             for(const Point* ms : mset) {
00094                 ms->setContainerData(this);
00095             }
00096             mPoints.insert(mPoints.end(),mset.begin(),mset.end());
00097             mset.clear();
00098             //qDebug() << "hiding" << mChildren[i];
00099         }
00100     }
00101     if(mParent) {
00102         mParent->remPoint(m,params);
00103     }
00104 }
00105 
00106 void QuadTreeNode::setParent(QuadTreeNode *parent)
00107 {
00108     mParent = parent;
00109 }
00110 
00111 void QuadTreeNode::reset()
00112 {
00113     mCount = 0;
00114     mMass = 0;
00115     mMC = {0,0};
00116     mParent = nullptr;
00117     mPoints.clear();
00118 }
00119 
00120 const QVector2D& QuadTreeNode::getCenter() const
00121 {
00122     return mCenter;
00123 }
00124 
00125 const qreal& QuadTreeNode::getRadius() const
00126 {
00127     return mRadius;
00128 }
00129 
00130 const qreal& QuadTreeNode::mass() const
00131 {
00132     return mMass;
00133 }
00134 
00135 QVector2D QuadTreeNode::gravityFor(const Point& m, const QuadTreeParams& params) const
00136 {
00137     QVector2D f;
00138     QVector2D r = (CoM() - m.pos());
00139     qreal l = r.length();
00140 
00141     qreal ratio = (mRadius*2) / l;
00142     if(ratio < params.theta) {
00143         /*if(leaf()) {
00144             return r.normalized() * ((mMass*m.mass()) / lr);
00145         } else {
00146             for(int i = 0; i < 4; i++) {
00147                 f += mChildren[i]->gravityFor(m,params);
00148             }
00149         }*/
00150         qreal lr = l*l;
00151         return -(r / l) * ((mMass*m.mass()) / lr);
00152     } else {
00153         if(leaf()) {
00154             return trueGravity(m);
00155         } else {
00156             for(int i = 0; i < 4; i++) {
00157                 f += mChildren[i]->gravityFor(m,params);
00158             }
00159         }
00160     }
00161     return f;
00162 }
00163 
00164 QVector2D QuadTreeNode::CoM() const {
00165     if(mMass) {
00166         return mMC / mMass;
00167     } else {
00168         return mCenter;
00169     }
00170 
00171 }
00172 
00173 QVector2D QuadTreeNode::trueGravity(const Point &m) const {
00174     QVector2D f{0,0};
00175     for(const Point* const& ms : mPoints) {
00176         if(ms != &m) {
00177             QVector2D r = ms->pos() - m.pos();
00178             qreal lr = r.lengthSquared();
00179             if(lr > 1e-2) {
00180                 f += -r.normalized() * ((ms->mass()*m.mass()) / lr);
00181             }
00182         }
00183     }
00184     return f;
00185 }
00186 
00187 bool QuadTreeNode::contain(const Point *o) const
00188 {
00189     const QVector2D& pos = o->pos();
00190     return (
00191                 mCenter.x() - mRadius <= pos.x() &&
00192                 mCenter.y() - mRadius <= pos.y() &&
00193                 mCenter.x() + mRadius > pos.x() &&
00194                 mCenter.y() + mRadius > pos.y()
00195                 );
00196 }
00197 
00198 bool QuadTreeNode::leaf() const {
00199     return mCount == mPoints.size() || !mChildren[0];
00200 }
00201 
00202 QuadTreeNode::~QuadTreeNode()
00203 {
00204     reset();
00205 }
00206 
00207 }
 All Classes Functions