]> rtime.felk.cvut.cz Git - hubacji1/rrts.git/blobdiff - src/rrts.cc
Do not clear opt time log
[hubacji1/rrts.git] / src / rrts.cc
index 1877ff28aeeeac62a0bb8bb1cbc2f5271ebf9fb3..6ed3d69803aa247dc229c416995ba6a155b2acb0 100644 (file)
@@ -11,8 +11,20 @@ RRTNode::RRTNode()
 {
 }
 
-RRTNode::RRTNode(const BicycleCar &bc) : BicycleCar(bc)
+RRTNode::RRTNode(const BicycleCar &bc)
 {
+    this->x(bc.x());
+    this->y(bc.y());
+    this->h(bc.h());
+    this->sp(bc.sp());
+    this->st(bc.st());
+}
+
+bool RRTNode::operator==(const RRTNode& n)
+{
+        if (this == &n)
+                return true;
+        return false;
 }
 
 Obstacle::Obstacle()
@@ -30,6 +42,36 @@ double RRTS::elapsed()
         return this->scnt_;
 }
 
+void RRTS::log_path_cost()
+{
+        if (this->log_path_cost_.size() == 0) {
+                this->log_path_cost_.push_back(this->goals().front().cc);
+        } else {
+                auto lc = this->log_path_cost_.back();
+                auto gc = this->goals().front().cc;
+                auto goal_is_better = this->goals().front().cc > 0 && lc < gc;
+                if (
+                        this->log_path_cost_.back() > 0
+                        && (
+                                this->goals().front().cc == 0
+                                || (
+                                        this->goals().front().cc > 0
+                                        && goal_is_better
+                                )
+                        )
+                ) {
+                        this->log_path_cost_.push_back(
+                                this->log_path_cost_.back()
+                        );
+                } else {
+                        this->log_path_cost_.push_back(
+                                this->goals().front().cc
+                        );
+                }
+        }
+        this->log_path_iter_ += 1;
+}
+
 bool RRTS::should_stop()
 {
         // the following counters must be updated, do not comment
@@ -45,8 +87,9 @@ bool RRTS::should_stop()
 bool RRTS::should_finish()
 {
         // decide finish conditions (maybe comment some lines)
-        //if (this->icnt_ > 999) return true;
-        if (this->scnt_ > 5) return true;
+        if (this->icnt_ > 1000) return true;
+        //if (this->scnt_ > 2) return true;
+        if (this->finishit) return true;
         if (this->gf()) return true;
         // but continue by default
         return false;
@@ -90,13 +133,21 @@ RRTS::collide(std::vector<std::tuple<double, double>> &poly)
 std::tuple<bool, unsigned int, unsigned int>
 RRTS::collide_steered_from(RRTNode &f)
 {
+        auto fbc = BicycleCar();
+        fbc.x(f.x());
+        fbc.y(f.y());
+        fbc.h(f.h());
         std::vector<std::tuple<double, double>> s;
-        s.push_back(std::make_tuple(f.x(), f.y()));
+        s.push_back(std::make_tuple(fbc.x(), fbc.y()));
         for (auto &n: this->steered()) {
-                s.push_back(std::make_tuple(n.lfx(), n.lfy()));
-                s.push_back(std::make_tuple(n.lrx(), n.lry()));
-                s.push_back(std::make_tuple(n.rrx(), n.rry()));
-                s.push_back(std::make_tuple(n.rfx(), n.rfy()));
+                auto nbc = BicycleCar();
+                nbc.x(n.x());
+                nbc.y(n.y());
+                nbc.h(n.h());
+                s.push_back(std::make_tuple(nbc.lfx(), nbc.lfy()));
+                s.push_back(std::make_tuple(nbc.lrx(), nbc.lry()));
+                s.push_back(std::make_tuple(nbc.rrx(), nbc.rry()));
+                s.push_back(std::make_tuple(nbc.rfx(), nbc.rfy()));
         }
         auto col = this->collide(s);
         auto strip_from = this->steered().size() - std::get<1>(col) / 4;
@@ -108,19 +159,32 @@ RRTS::collide_steered_from(RRTNode &f)
         }
         return col;
 }
+std::tuple<bool, unsigned int, unsigned int>
+RRTS::collide_tmp_steered_from(RRTNode &f)
+{
+        return std::make_tuple(false, 0, 0);
+}
 
 std::tuple<bool, unsigned int, unsigned int>
 RRTS::collide_two_nodes(RRTNode &f, RRTNode &t)
 {
+        auto fbc = BicycleCar();
+        fbc.x(f.x());
+        fbc.y(f.y());
+        fbc.h(f.h());
+        auto tbc = BicycleCar();
+        tbc.x(f.x());
+        tbc.y(f.y());
+        tbc.h(f.h());
         std::vector<std::tuple<double, double>> p;
-        p.push_back(std::make_tuple(f.lfx(), f.lfy()));
-        p.push_back(std::make_tuple(f.lrx(), f.lry()));
-        p.push_back(std::make_tuple(f.rrx(), f.rry()));
-        p.push_back(std::make_tuple(f.rfx(), f.rfy()));
-        p.push_back(std::make_tuple(t.lfx(), t.lfy()));
-        p.push_back(std::make_tuple(t.lrx(), t.lry()));
-        p.push_back(std::make_tuple(t.rrx(), t.rry()));
-        p.push_back(std::make_tuple(t.rfx(), t.rfy()));
+        p.push_back(std::make_tuple(fbc.lfx(), fbc.lfy()));
+        p.push_back(std::make_tuple(fbc.lrx(), fbc.lry()));
+        p.push_back(std::make_tuple(fbc.rrx(), fbc.rry()));
+        p.push_back(std::make_tuple(fbc.rfx(), fbc.rfy()));
+        p.push_back(std::make_tuple(tbc.lfx(), tbc.lfy()));
+        p.push_back(std::make_tuple(tbc.lrx(), tbc.lry()));
+        p.push_back(std::make_tuple(tbc.rrx(), tbc.rry()));
+        p.push_back(std::make_tuple(tbc.rfx(), tbc.rfy()));
         return this->collide(p);
 }
 
@@ -144,12 +208,95 @@ void RRTS::sample()
         double y = 0;
         double h = 0;
         switch (this->sample_dist_type()) {
-        case 1:
+        case 1: // uniform
                 x = this->udx_(this->gen_);
                 y = this->udy_(this->gen_);
                 h = this->udh_(this->gen_);
                 break;
-        default:
+        case 2: // uniform circle
+        {
+                // see https://stackoverflow.com/questions/5837572/generate-a-random-point-within-a-circle-uniformly/50746409#50746409
+                double R = sqrt(
+                        pow(
+                                this->nodes().front().x()
+                                - this->goals().front().x(),
+                                2
+                        )
+                        + pow(
+                                this->nodes().front().y()
+                                - this->goals().front().y(),
+                                2
+                        )
+                );
+                double a = atan2(
+                        this->goals().front().y() - this->nodes().front().y(),
+                        this->goals().front().x() - this->nodes().front().x()
+                );
+                double cx = this->goals().front().x() - R/2 * cos(a);
+                double cy = this->goals().front().y() - R/2 * sin(a);
+                double r = R * sqrt(this->udx_(this->gen_));
+                double theta = this->udy_(this->gen_) * 2 * M_PI;
+                x = cx + r * cos(theta);
+                y = cy + r * sin(theta);
+                h = this->udh_(this->gen_);
+        }
+                break;
+        case 3: {
+                if (
+                        this->steered1_.size() == 0
+                        && this->steered2_.size() == 0
+                ) {
+                        x = this->nodes().front().x();
+                        y = this->nodes().front().y();
+                        h = this->nodes().front().h();
+                        this->use_nn = &this->nodes().front();
+                } else {
+                        this->udi1_ = std::uniform_int_distribution<unsigned int>(
+                                0,
+                                this->steered1_.size() - 1
+                        );
+                        this->udi2_ = std::uniform_int_distribution<unsigned int>(
+                                0,
+                                this->steered2_.size() - 1
+                        );
+                        auto ind1 = this->udi1_(this->gen_);
+                        auto ind2 = this->udi2_(this->gen_);
+                        if (
+                                this->steered2_.size() == 0
+                        ) {
+                                auto n1 = this->steered1_[ind1];
+                                x = n1->x();
+                                y = n1->y();
+                                h = n1->h();
+                                this->use_nn = this->steered1_[ind1];
+                        } else if (
+                                this->steered1_.size() == 0
+                        ) {
+                                auto n2 = this->steered2_[ind2];
+                                x = n2->x();
+                                y = n2->y();
+                                h = n2->h();
+                                this->use_nn = this->steered2_[ind2];
+                        } else {
+                                auto n1 = this->steered1_[ind1];
+                                auto n2 = this->steered2_[ind2];
+                                auto which = this->udx_(this->gen_);
+                                if (which > 0.5) {
+                                        x = n1->x();
+                                        y = n1->y();
+                                        h = n1->h();
+                                        this->use_nn = this->steered1_[ind1];
+                                } else {
+                                        x = n2->x();
+                                        y = n2->y();
+                                        h = n2->h();
+                                        this->use_nn = this->steered2_[ind2];
+                                }
+                        }
+                }
+                break;
+                }
+        default: // normal
                 x = this->ndx_(this->gen_);
                 y = this->ndy_(this->gen_);
                 h = this->ndh_(this->gen_);
@@ -186,18 +333,19 @@ std::vector<RRTNode *> RRTS::nv(RRTNode &t)
 int cb_rs_steer(double q[4], void *user_data)
 {
         std::vector<RRTNode> *nodes = (std::vector<RRTNode> *) user_data;
-        RRTNode *ln = nullptr;
-        if (nodes->size() > 0)
-                ln = &nodes->back();
         nodes->push_back(RRTNode());
         nodes->back().x(q[0]);
         nodes->back().y(q[1]);
         nodes->back().h(q[2]);
         nodes->back().sp(q[3]);
-        if (nodes->back().sp() == 0)
+        if (nodes->back().sp() == 0) {
                 nodes->back().set_t(RRTNodeType::cusp);
-        else if (ln != nullptr && sgn(ln->sp()) != sgn(nodes->back().sp()))
-                ln->set_t(RRTNodeType::cusp);
+        } else if (nodes->size() >= 2) {
+                RRTNode* lln = nodes->back().p();
+                RRTNode* ln = &nodes->back();
+                if (lln != nullptr && ln != nullptr && sgn(lln->sp()) != sgn(ln->sp()))
+                        ln->set_t(RRTNodeType::cusp);
+        }
         return 0;
 }
 
@@ -206,8 +354,26 @@ void RRTS::steer(RRTNode &f, RRTNode &t)
         this->steered().clear();
         double q0[] = {f.x(), f.y(), f.h()};
         double q1[] = {t.x(), t.y(), t.h()};
-        ReedsSheppStateSpace rsss(f.mtr());
-        rsss.sample(q0, q1, 0.5, cb_rs_steer, &this->steered());
+        ReedsSheppStateSpace rsss(this->bc.mtr());
+        rsss.sample(q0, q1, 0.2, cb_rs_steer, &this->steered());
+}
+void RRTS::tmp_steer(RRTNode &f, RRTNode &t)
+{
+    this->tmp_steered_.clear();
+    double q0[] = {f.x(), f.y(), f.h()};
+    double q1[] = {t.x(), t.y(), t.h()};
+    ReedsSheppStateSpace rsss(this->bc.mtr());
+    rsss.sample(q0, q1, 0.2, cb_rs_steer, &this->tmp_steered_);
+}
+
+void RRTS::steer1(RRTNode &f, RRTNode &t)
+{
+    return this->steer(f, t);
+}
+
+void RRTS::steer2(RRTNode &f, RRTNode &t)
+{
+    return this->steer(f, t);
 }
 
 void RRTS::join_steered(RRTNode *f)
@@ -221,26 +387,35 @@ void RRTS::join_steered(RRTNode *f)
                 f = t;
         }
 }
+void RRTS::join_tmp_steered(RRTNode *f)
+{
+        while (this->tmp_steered_.size() > 0) {
+                this->store_node(this->tmp_steered_.front());
+                RRTNode *t = &this->nodes().back();
+                t->p(f);
+                t->c(this->cost_build(*f, *t));
+                this->tmp_steered_.erase(this->tmp_steered_.begin());
+                f = t;
+        }
+}
 
 bool RRTS::goal_found(RRTNode &f)
 {
-        bool found = false;
-        for (auto &g: this->goals()) {
-                double cost = this->cost_build(f, g);
-                double edist = sqrt(
-                        pow(f.x() - g.x(), 2)
-                        + pow(f.y() - g.y(), 2)
-                );
-                double adist = std::abs(f.h() - g.h());
-                if (edist < 0.05 && adist < M_PI / 32) {
-                        found = true;
-                        if (g.p() == nullptr || cc(f) + cost < cc(g)) {
-                                g.p(&f);
-                                g.c(cost);
-                        }
+        auto &g = this->goals().front();
+        double cost = this->cost_build(f, g);
+        double edist = sqrt(
+                pow(f.x() - g.x(), 2)
+                + pow(f.y() - g.y(), 2)
+        );
+        double adist = std::abs(f.h() - g.h());
+        if (edist < 0.05 && adist < M_PI / 32) {
+                if (g.p() == nullptr || f.cc + cost < g.cc) {
+                        g.p(&f);
+                        g.c(cost);
                 }
+                return true;
         }
-        return found;
+        return false;
 }
 
 // RRT* procedures
@@ -248,16 +423,36 @@ bool RRTS::connect()
 {
         RRTNode *t = &this->steered().front();
         RRTNode *f = this->nn(this->samples().back());
-        double cost = this->cost_search(*f, *t);
+        double cost = f->cc + this->cost_build(*f, *t);
         for (auto n: this->nv(*t)) {
                 if (
                         !std::get<0>(this->collide_two_nodes(*n, *t))
-                        && this->cost_search(*n, *t) < cost
+                        && n->cc + this->cost_build(*n, *t) < cost
                 ) {
                         f = n;
-                        cost = this->cost_search(*n, *t);
+                        cost = n->cc + this->cost_build(*n, *t);
                 }
         }
+        // steer from f->t and then continue with the steered.
+        this->tmp_steer(*f, *t);
+        if (this->tmp_steered_.size() > 0) {
+                auto col = this->collide_tmp_steered_from(*f);
+                if (std::get<0>(col))
+                        return false;
+                this->join_tmp_steered(f);
+                f = &this->nodes().back();
+        }
+        auto fbc = BicycleCar();
+        fbc.x(f->x());
+        fbc.y(f->y());
+        fbc.h(f->h());
+        auto tbc = BicycleCar();
+        tbc.x(t->x());
+        tbc.y(t->y());
+        tbc.h(t->h());
+        if (!tbc.drivable(fbc))
+            return false;
+        // cont.
         this->store_node(this->steered().front());
         t = &this->nodes().back();
         t->p(f);
@@ -272,8 +467,16 @@ void RRTS::rewire()
         for (auto n: this->nv(*f)) {
                 if (
                         !std::get<0>(this->collide_two_nodes(*f, *n))
-                        && cc(*f) + this->cost_search(*f, *n) < cc(*n)
+                        && f->cc + this->cost_build(*f, *n) < n->cc
                 ) {
+                        this->tmp_steer(*f, *n);
+                        if (this->tmp_steered_.size() > 0) {
+                                auto col = this->collide_tmp_steered_from(*f);
+                                if (std::get<0>(col))
+                                        continue;
+                                this->join_tmp_steered(f);
+                                f = &this->nodes().back();
+                        }
                         n->p(f);
                         n->c(this->cost_build(*f, *n));
                 }
@@ -285,6 +488,28 @@ void RRTS::init()
 {
 }
 
+void RRTS::reset()
+{
+        RRTNode init = RRTNode();
+        init.x(this->nodes().front().x());
+        init.y(this->nodes().front().y());
+        init.h(this->nodes().front().h());
+        this->nodes().clear();
+        this->store_node(RRTNode());
+        this->nodes().front().x(init.x());
+        this->nodes().front().y(init.y());
+        this->nodes().front().h(init.h());
+        this->samples().clear();
+        this->steered().clear();
+        this->path().clear();
+        this->gf(false);
+        for (auto& g: this->goals()) {
+                g.p(nullptr);
+                g.c_ = 0.0;
+                g.cc = 0.0;
+        }
+}
+
 void RRTS::deinit()
 {
         this->nodes().clear();
@@ -297,28 +522,19 @@ void RRTS::deinit()
         this->gf_ = false;
 }
 
-std::vector<RRTNode *> RRTS::path()
+void RRTS::compute_path()
 {
-        std::vector<RRTNode *> path;
         if (this->goals().size() == 0)
-                return path;
+                return;
         RRTNode *goal = &this->goals().front();
-        for (auto &n: this->goals()) {
-                if (
-                        n.p() != nullptr
-                        && (n.c() < goal->c() || goal->p() == nullptr)
-                ) {
-                        goal = &n;
-                }
-        }
         if (goal->p() == nullptr)
-                return path;
+                return;
+        this->path_.clear();
         while (goal != nullptr) {
-                path.push_back(goal);
+                this->path_.push_back(goal);
                 goal = goal->p();
         }
-        std::reverse(path.begin(), path.end());
-        return path;
+        std::reverse(this->path_.begin(), this->path_.end());
 }
 
 bool RRTS::next()
@@ -326,37 +542,77 @@ bool RRTS::next()
         if (this->icnt_ == 0)
                 this->tstart_ = std::chrono::high_resolution_clock::now();
         bool next = true;
-        if (this->should_stop())
+        if (this->should_stop()) {
+                this->log_path_cost();
                 return false;
-        this->sample();
-        this->steer(
+        }
+        if (this->samples().size() == 0) {
+                this->samples().push_back(RRTNode());
+                this->samples().back().x(this->goals().front().x());
+                this->samples().back().y(this->goals().front().y());
+                this->samples().back().h(this->goals().front().h());
+        } else {
+                this->sample();
+        }
+        this->steer1(
                 *this->nn(this->samples().back()),
                 this->samples().back()
         );
-        if (std::get<0>(this->collide_steered_from(
-                *this->nn(this->samples().back())
-        )))
+        if (this->steered().size() == 0) {
+                this->log_path_cost();
                 return next;
-        if (!this->connect())
+        }
+        auto col = this->collide_steered_from(
+                *this->nn(this->samples().back())
+        );
+        if (std::get<0>(col)) {
+                auto rcnt = this->steered().size() - std::get<1>(col);
+                while (rcnt-- > 0) {
+                        this->steered().pop_back();
+                }
+        }
+        if (!this->connect()) {
+                this->log_path_cost();
                 return next;
+        }
         this->rewire();
         unsigned scnt = this->steered().size();
-        this->steered().erase(this->steered().begin());
         this->join_steered(&this->nodes().back());
         RRTNode *just_added = &this->nodes().back();
         while (scnt > 0) {
+                // store all the steered1 nodes
+                this->steered1_.push_back(just_added);
                 scnt--;
-                for (auto &g: this->goals()) {
-                        this->steer(*just_added, g);
-                        if (std::get<0>(this->collide_steered_from(
-                                *just_added
-                        )))
-                                continue;
-                        this->join_steered(just_added);
+                auto &g = this->goals().front();
+                this->steer2(*just_added, g);
+                auto col = this->collide_steered_from(*just_added);
+                if (std::get<0>(col)) {
+                        auto rcnt = this->steered().size() - std::get<1>(col);
+                        while (rcnt-- > 0) {
+                                this->steered().pop_back();
+                        }
+                }
+                this->join_steered(just_added);
+                // store all the steered2 nodes
+                RRTNode* jap = &this->nodes().back();
+                while (jap != just_added) {
+                        this->steered2_.push_back(jap);
+                        jap = jap->p();
                 }
-                this->gf(this->goal_found(this->nodes().back()));
+                auto gf = this->goal_found(this->nodes().back());
+                this->gf(gf);
                 just_added = just_added->p();
         }
+        if (
+                this->gf()
+                && (
+                        this->path().size() == 0
+                        || this->goals().front().cc < this->path().back()->cc
+                )
+        ) {
+                this->compute_path();
+        }
+        this->log_path_cost();
         return next;
 }
 
@@ -380,6 +636,12 @@ void RRTS::set_sample_uniform(
         this->udy_ = std::uniform_real_distribution<double>(ymin,ymax);
         this->udh_ = std::uniform_real_distribution<double>(hmin,hmax);
 }
+void RRTS::set_sample_uniform_circle()
+{
+        this->udx_ = std::uniform_real_distribution<double>(0, 1);
+        this->udy_ = std::uniform_real_distribution<double>(0, 1);
+        this->udh_ = std::uniform_real_distribution<double>(0, 2 * M_PI);
+}
 void RRTS::set_sample(
         double x1, double x2,
         double y1, double y2,
@@ -387,14 +649,20 @@ void RRTS::set_sample(
 )
 {
         switch (this->sample_dist_type()) {
-        case 1:
+        case 1: // uniform
                 x1 += this->nodes().front().x();
                 x2 += this->nodes().front().x();
                 y1 += this->nodes().front().y();
                 y2 += this->nodes().front().y();
                 this->set_sample_uniform(x1, x2, y1, y2, h1, h2);
                 break;
-        default:
+        case 2: // uniform circle
+                this->set_sample_uniform_circle();
+                break;
+        case 3: // uniform index of node in nodes
+                this->set_sample_uniform_circle();
+                break;
+        default: // normal
                 this->set_sample_normal(x1, x2, y1, y2, h1, h2);
         }
 }
@@ -413,12 +681,30 @@ Json::Value RRTS::json()
                 jvo["init"][1] = this->nodes().front().y();
                 jvo["init"][2] = this->nodes().front().h();
         }
+        {
+                jvo["path_cost_before_opt"] = this->path_cost_before_opt_;
+        }
         {
                 if (this->path().size() > 0) {
-                        jvo["cost"] = cc(*this->path().back());
-                        jvo["goal"][0] = this->path().back()->x();
-                        jvo["goal"][1] = this->path().back()->y();
-                        jvo["goal"][2] = this->path().back()->h();
+                        jvo["cost"] = this->path().back()->cc;
+                        jvo["entry"][0] = this->goals().front().x();
+                        jvo["entry"][1] = this->goals().front().y();
+                        jvo["entry"][2] = this->goals().front().h();
+                        if (this->entry_set) {
+                            jvo["entry"][2] = this->entry.b;
+                            jvo["entry"][3] = this->entry.e;
+                        }
+                        if (this->entries_set) {
+                                jvo["entries"][0][0] = this->entry1.x;
+                                jvo["entries"][0][1] = this->entry1.y;
+                                jvo["entries"][0][2] = this->entry1.h;
+                                jvo["entries"][1][0] = this->entry2.x;
+                                jvo["entries"][1][1] = this->entry2.y;
+                                jvo["entries"][1][2] = this->entry2.h;
+                        }
+                        jvo["goal"][0] = this->goals().back().x();
+                        jvo["goal"][1] = this->goals().back().y();
+                        jvo["goal"][2] = this->goals().back().h();
                 }
         }
         {
@@ -462,6 +748,16 @@ Json::Value RRTS::json()
         {
                 jvo["nodes"] = (unsigned int) this->nodes().size();
         }
+        {
+                unsigned int cnt = 0;
+                for (auto i: this->log_path_cost_)
+                        jvo["log_path_cost"][cnt++] = i;
+        }
+        {
+                unsigned int cnt = 0;
+                for (auto i: this->log_opt_time_)
+                        jvo["log_opt_time"][cnt++] = i;
+        }
         //{
         //        unsigned int ncnt = 0;
         //        for (auto n: this->nodes()) {
@@ -471,13 +767,28 @@ Json::Value RRTS::json()
         //                ncnt++;
         //        }
         //}
+        //{
+        //        unsigned int ncnt = 0;
+        //        for (auto n: this->steered1_) {
+        //                jvo["steered1_x"][ncnt] = n->x();
+        //                jvo["steered1_y"][ncnt] = n->y();
+        //                //jvo["nodes_h"][ncnt] = n.h();
+        //                ncnt++;
+        //        }
+        //        ncnt = 0;
+        //        for (auto n: this->steered2_) {
+        //                jvo["steered2_x"][ncnt] = n->x();
+        //                jvo["steered2_y"][ncnt] = n->y();
+        //                //jvo["nodes_h"][ncnt] = n.h();
+        //                ncnt++;
+        //        }
+        //}
         return jvo;
 }
 
 void RRTS::json(Json::Value jvi)
 {
         assert(jvi["init"] != Json::nullValue);
-        assert(jvi["goal"] != Json::nullValue);
         assert(jvi["goals"] != Json::nullValue);
         assert(jvi["obst"] != Json::nullValue);
 
@@ -485,17 +796,41 @@ void RRTS::json(Json::Value jvi)
         this->nodes().front().y(jvi["init"][1].asDouble());
         this->nodes().front().h(jvi["init"][2].asDouble());
         {
-                RRTNode tmp_node;
-                tmp_node.x(jvi["goal"][0].asDouble());
-                tmp_node.y(jvi["goal"][1].asDouble());
-                tmp_node.h(jvi["goal"][2].asDouble());
-                this->goals().push_back(tmp_node);
+                RRTNode* gp = nullptr;
+                if (jvi["entry"] != Json::nullValue) {
+                        this->entry_set = true;
+                        this->entry.x = jvi["entry"][0].asDouble();
+                        this->entry.y = jvi["entry"][1].asDouble();
+                        this->entry.b = jvi["entry"][2].asDouble();
+                        this->entry.e = jvi["entry"][3].asDouble();
+                        RRTNode tmp_node;
+                        tmp_node.x(this->entry.x);
+                        tmp_node.y(this->entry.y);
+                        tmp_node.h((this->entry.b + this->entry.e) / 2.0);
+                        this->goals().push_back(tmp_node);
+                        this->goals().back().p(gp);
+                        gp = &this->goals().back();
+                }
+                if (jvi["entries"] != Json::nullValue) {
+                        this->entries_set = true;
+                        this->entry1.x = jvi["entries"][0][0].asDouble();
+                        this->entry1.y = jvi["entries"][0][1].asDouble();
+                        this->entry1.h = jvi["entries"][0][2].asDouble();
+                        this->entry2.x = jvi["entries"][1][0].asDouble();
+                        this->entry2.y = jvi["entries"][1][1].asDouble();
+                        this->entry2.h = jvi["entries"][1][2].asDouble();
+                }
                 for (auto g: jvi["goals"]) {
+                        RRTNode tmp_node;
                         tmp_node.x(g[0].asDouble());
                         tmp_node.y(g[1].asDouble());
                         tmp_node.h(g[2].asDouble());
                         this->goals().push_back(tmp_node);
+                        this->goals().back().p(gp);
+                        gp = &this->goals().back();
                 }
+                this->goals().front().set_t(RRTNodeType::cusp);
+                this->goals().back().set_t(RRTNodeType::cusp);
         }
         {
                 Obstacle tmp_obstacle;