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
00012
00013 QuadTreeNode::QuadTreeNode()
00014 {
00015 reset();
00016 mPoints.reserve(100);
00017 for(int i = 0; i < 4; i++)
00018 mChildren[i] = nullptr;
00019
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
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 ¶ms)
00046 {
00047 if(contain(m)) {
00048
00049 mCount++;
00050
00051 if(mCount < params.maxMasses || !mChildren[0]) {
00052
00053 mPoints.push_back(m);
00054 m->setContainerData(this);
00055 } else {
00056
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++) {
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 ¶ms)
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) {
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
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
00144
00145
00146
00147
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 }