ELVE  1
ELVE Logic Visualization Explorer
/home/travis/build/stdgregwar/elve/Core/System.cpp
00001 #include "System.h"
00002 #include "Damp.h"
00003 #include "LinearConstraint.h"
00004 #include "PointConstraint.h"
00005 
00006 #include <limits>
00007 #include <future>
00008 #include <QDebug>
00009 
00010 namespace Elve {
00011 
00012 using namespace std;
00013 
00014 System::System() : mGravity(75e4), mDamp(2)
00015 {
00016 
00017 }
00018 
00019 void System::tick(float dt, bool update)
00020 {
00021     static int count = 0;
00022     //qDebug() << "tick" << count++;
00023     mGravity.updateQuadTree();
00024 
00025 #ifndef NO_THREADS
00026     int nthreads = 8;
00027     vector<future<void>> futures(nthreads);
00028     int splitsize = mPoints.size() / nthreads;
00029     size_t end = 0;
00030 
00031     for(int i = 0; i < nthreads-1; i++) {
00032         end = (i+1)*splitsize;
00033         futures[i] = async(bind(&System::computeForces,this,i*splitsize,end));
00034     }
00035     futures[nthreads-1] = async(bind(&System::computeForces,this,end,mPoints.size()));
00036 
00037     for(future<void>& f : futures) {
00038         f.get();
00039     }
00040 #else
00041     computeForces(0,mPoints.size());
00042 #endif
00043 
00044     for(Point* m : mPoints) {
00045         m->tick(dt,update);
00046     }
00047 }
00048 
00049 void System::debug(QPainter* p) const {
00050     mGravity.debug(p);
00051 }
00052 
00053 void System::computeForces(size_t from,size_t until)
00054 {
00055     for(size_t i = from; i < until; i++) {
00056         mPoints[i]->resetForce();
00057         mPoints[i]->computeForce();
00058     }
00059 }
00060 
00061 const QRectF& System::sizeHint() const {
00062     return mSizeHint;
00063 }
00064 
00065 Point* System::point(const NodeID& id) {
00066     auto it = mPointsById.find(id);
00067     if(it != mPointsById.end()) {
00068         return it->second;
00069     } else {
00070         return addPoint(1,id,{0,0},3,FULL); //Fallback point, should never happen
00071     }
00072 }
00073 
00074 void System::setRepulsionForce(float f) {
00075     mGravity.setK(f);
00076 }
00077 
00078 const PointsByID& System::pinnedPoints() const {
00079     return mPinnedPoints;
00080 }
00081 
00082 const PointsByID& System::pointsByID() const {
00083     return mPointsById;
00084 }
00085 
00086 NodePositions System::positions() const
00087 {
00088     NodePositions poss;
00089     for(const Point* p : mPoints) {
00090         poss[p->boundID()] = p->pos();
00091     }
00092     return poss;
00093 }
00094 
00095 void System::clearMovables() {
00096     for(Point* p : mPoints) {
00097         p->clearMovables();
00098     }
00099 }
00100 
00101 Point* System::addPoint(qreal mass, const NodeID &id, QVector2D pos, qreal damp, GravityMode g)
00102 {
00103     mDamp.setB(damp);
00104     Point* nm = nullptr;
00105     auto it = mPointsById.find(id);
00106     if(it != mPointsById.end()) {
00107         nm = it->second;
00108         nm->setMass(mass);
00109     }else {
00110         nm = new Point(mass,id,*this);
00111         mPoints.push_back(nm);
00112         mPointsById[id] = nm;
00113     }
00114     nm->setPos(pos);
00115     //id->setMass(nm);
00116     if(g != NONE) {
00117         nm->addForce(&mGravity);
00118         if(g == FULL) {
00119             mGravity.addPoint(nm);
00120         }
00121     }
00122     nm->addForce(&mDamp);
00123     nm->addConstraint(&mBox);
00124     return nm;
00125 }
00126 
00127 void System::pin(const NodeID& id, const QVector2D& pnt) {
00128     Point* p = point(id);
00129     mPinnedPoints[p->boundID()] = p;
00130     p->removePConstraints();
00131     addPConstrain(p,pnt);
00132 }
00133 
00134 void System::unpin(const NodeID& id) {
00135     Point* p = point(id);
00136     p->removePConstraints();
00137     p->addConstraint(&mBox);
00138     mPinnedPoints.erase(id);
00139 }
00140 
00141 void System::addSpring(unsigned i, unsigned j, qreal k, qreal l0)
00142 {
00143     Point* mi = mPoints.at(i);
00144     Point* mj = mPoints.at(j);
00145     addSpring(mi,mj,k,l0);
00146 }
00147 
00148 void System::addSpring(Point* mi, Point* mj, qreal k, qreal l0)
00149 {
00150     Spring* force = new Spring(*mi,*mj,l0,k);
00151     mi->addForce(force);
00152     mj->addForce(force);
00153     mForces.push_back(force);
00154 }
00155 void System::clear()
00156 {
00157     for(Point* m : mPoints) {
00158         delete m;
00159     }
00160 
00161     mPoints.clear();
00162     for(Force* f : mForces) {
00163         delete f;
00164     }
00165     mForces.clear();
00166     mGravity.clear();
00167     mPointsById.clear();
00168     mPinnedPoints.clear();
00169 }
00170 
00171 const Point* System::nearest(const QVector2D& p) const
00172 {
00173     qreal dist = std::numeric_limits<qreal>::infinity();
00174     const Point* ml = mPoints.back();
00175     for(const Point* m : mPoints) {
00176         qreal r = (m->pos() - p).lengthSquared();
00177         if(r < dist) {
00178             dist = r;
00179             ml = m;
00180         }
00181     }
00182     return ml;
00183 }
00184 
00185 void System::setSizeHint(const QRectF& rect) {
00186     mGSizeHint = rect.adjusted(-512,-512,512,512);
00187     switch(orientationHint()) {
00188     case LEFTRIGHT:
00189     case RIGHTLEFT:
00190         mSizeHint = QRectF(mGSizeHint.top(),mGSizeHint.left(),mGSizeHint.height(),mGSizeHint.width());
00191         break;
00192     case TOPDOWN:
00193     default:
00194         mSizeHint = mGSizeHint;
00195         break;
00196     }
00197 
00198     mGravity.setQuadTreeBounds(mSizeHint);
00199     mBox.setBounds(mSizeHint);
00200 }
00201 
00202 LinearConstraint::Dir _adaptDir(OrientationHint hint, LinearConstraint::Dir dir) {
00203     switch(hint) {
00204     case RIGHTLEFT:
00205     case LEFTRIGHT:
00206         return (LinearConstraint::Dir)((dir+1)%2); //TODO explicit this
00207     case TOPDOWN:
00208     default:
00209        return dir;
00210     }
00211 }
00212 
00213 qreal _adaptPos(QVector2D transformPoint,LinearConstraint::Dir dir) {
00214     return dir == LinearConstraint::VERTICAL ? transformPoint.y() : transformPoint.x();
00215 }
00216 
00217 void System::addVConstraint(Point* m, qreal height)
00218 {
00219     qreal hardn = 0.2;
00220     LinearConstraint::Dir newDir = _adaptDir(orientationHint(),LinearConstraint::VERTICAL);
00221     qreal tpos = _adaptPos(transformPoint({0,height}),newDir);
00222     Constraint* c = new LinearConstraint(tpos,hardn,newDir);
00223     m->addConstraint(c);
00224     mConstraints.push_back(c);
00225 }
00226 
00227 void System::addHConstraint(Point* m, qreal pos) {
00228     qreal hardn = 0.2;
00229     Constraint* c = new LinearConstraint(transformPoint({pos,0}).x(),hardn,
00230                                          _adaptDir(orientationHint(),LinearConstraint::HORIZONTAL));
00231     m->addConstraint(c);
00232     mConstraints.push_back(c);
00233 }
00234 
00235 QVector2D System::transformPoint(const QVector2D& p) const {
00236     switch(orientationHint()) {
00237     case TOPDOWN:
00238         return {p.x(), mGSizeHint.bottom() - (p.y() - mGSizeHint.top())};
00239     case LEFTRIGHT:
00240         return {mGSizeHint.bottom() - (p.y() - mGSizeHint.top()),p.x()};
00241     case RIGHTLEFT:
00242         return {p.y(),p.x()};
00243     default:
00244        return p;
00245     }
00246 }
00247 
00248 void System::addForce(Point* m, Force* f) {
00249     mForces.push_back(f);
00250     m->addForce(f);
00251 }
00252 
00253 void System::addPConstrain(Point* m, const QVector2D& p)
00254 {
00255     Constraint* pc = new PointConstraint(transformPoint(p));
00256     m->addConstraint(pc);
00257     mConstraints.push_back(pc);
00258 }
00259 
00260 void System::setOrientationHint(OrientationHint hint) {
00261     mOrHint = hint;
00262 }
00263 
00264 OrientationHint System::orientationHint() const {
00265     return mOrHint;
00266 }
00267 
00268 size_t System::massCount() const
00269 {
00270     return mPoints.size();
00271 }
00272 
00273 size_t System::forceCount() const
00274 {
00275     return mForces.size();
00276 }
00277 
00278 System::~System()
00279 {
00280     clear();
00281 }
00282 
00283 }
 All Classes Functions