]> rtime.felk.cvut.cz Git - hubacji1/iamcar.git/blobdiff - decision_control/slotplanner.cc
Protect usage of `n` when it is `nullptr`
[hubacji1/iamcar.git] / decision_control / slotplanner.cc
index 976aea55ccf3297ed7244f32f25bc6ad2323b4b6..3f903aa6527a8a2a0be99d78de7bf80c6e3b26de 100644 (file)
@@ -15,14 +15,29 @@ You should have received a copy of the GNU General Public License
 along with I am car. If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <algorithm>
 #include <cmath>
-#include "bcar.h"
+#include <list>
+#include <queue>
 #include "slotplanner.h"
 
 ParallelSlot::ParallelSlot()
 {}
 
 // getter
+std::vector<RRTNode *> &ParallelSlot::goals()
+{
+        return this->goals_;
+}
+
+RRTNode *ParallelSlot::getMidd()
+{
+        if (this->cusp().size() > 0)
+                return this->cusp().front().front();
+        else
+                return nullptr;
+}
+
 std::vector<std::vector<RRTNode *>> &ParallelSlot::cusp()
 {
         return this->cusp_;
@@ -38,20 +53,457 @@ PolygonObstacle &ParallelSlot::slot()
         return this->slot_;
 }
 
+float ParallelSlot::slotHeading()
+{
+        return this->slotHeading_;
+}
+
+SlotSide ParallelSlot::slotSide()
+{
+        return this->slotSide_;
+}
+
+SlotType ParallelSlot::slotType()
+{
+        return this->slotType_;
+}
+
+float ParallelSlot::poseHeading()
+{
+        return this->poseHeading_;
+}
+
 // setter
 void ParallelSlot::DH(float dh)
 {
         this->DH_ = dh;
 }
 
+void ParallelSlot::setAll()
+{
+        // slot heading
+        float y0 = this->slot().bnodes()[0]->y();
+        float x0 = this->slot().bnodes()[0]->x();
+        float y3 = this->slot().bnodes()[3]->y();
+        float x3 = this->slot().bnodes()[3]->x();
+        float dy = y3 - y0;
+        float dx = x3 - x0;
+        this->slotHeading_ = atan2(dy, dx);
+        // pose heading
+        float y1 = this->slot().bnodes()[1]->y();
+        float x1 = this->slot().bnodes()[1]->x();
+        dy = y0 - y1;
+        dx = x0 - x1;
+        this->poseHeading_ = atan2(dy, dx);
+        // slot side
+        if (sgn((x1 - x0) * (y3 - y0) - (y1 - y0) * (x3 - x0)) < 0)
+                this->slotSide_ = LEFT;
+        else
+                this->slotSide_ = RIGHT;
+        // slot type
+        float d1 = EDIST(
+                this->slot().bnodes()[0],
+                this->slot().bnodes()[1]
+        );
+        float d2 = EDIST(
+                this->slot().bnodes()[1],
+                this->slot().bnodes()[2]
+        );
+        if (d1 > d2)
+                this->slotType_ = PERPENDICULAR;
+        else
+                this->slotType_ = PARALLEL;
+}
+
 // other
-RRTNode *ParallelSlot::fposecenter()
+void ParallelSlot::fip(
+        std::vector<CircleObstacle>& co,
+        std::vector<SegmentObstacle>& so
+)
+{
+        this->setAll();
+        if (this->slotType() == PERPENDICULAR) {
+                std::vector<RRTNode *> tmpc;
+                BicycleCar *tmpf = this->getFP();
+                BicycleCar *tmpb = this->getISPP(tmpf);
+                RRTNode *cc;
+                if (this->slotSide() == LEFT)
+                        cc = tmpb->ccl();
+                else
+                        cc = tmpb->ccr();
+                if (this->slotSide() == LEFT)
+                        this->DH(1 * 0.5 / tmpb->out_radi());
+                else
+                        this->DH(-1 * 0.5 / tmpb->out_radi());
+                BicycleCar *p;
+                int i = 1;
+                p = tmpb->move(cc, i * this->DH());
+                while (
+                        !this->slot().collide(p->frame())
+                        && ((
+                                this->slotSide() == LEFT
+                                && p->h() < this->slotHeading()
+                        ) || (
+                                this->slotSide() == RIGHT
+                                && (
+                                        p->h() > this->slotHeading()
+                                        || p->h() < 0
+                                )
+                        ))
+                ) {
+                        if (tmpc.size() == 0) {
+                                i = 0;
+                                p = this->getFP();
+                        }
+                        bool end = false;
+                        std::vector<RRTEdge *> eds = p->frame();
+                        for (auto o: co)
+                                if (o.collide(eds))
+                                        end = true;
+                        for (auto o: so)
+                                if (o.collide(eds))
+                                        end = true;
+                        for (auto e: eds)
+                                delete e;
+                        if (end)
+                                break;
+                        this->goals_.push_back(p);
+                        tmpc.push_back(p);
+                        i += 1;
+                        p = tmpb->move(cc, i * this->DH());
+                }
+                if (tmpc.size() > 0)
+                        this->cusp().push_back(tmpc);
+                return;
+        }
+        // see https://courses.cs.washington.edu/courses/cse326/03su/homework/hw3/bfs.html
+        // RRTNode.s() works as iteration level
+        std::queue<BicycleCar *, std::list<BicycleCar *>> q;
+        std::queue<BicycleCar *, std::list<BicycleCar *>> empty;
+        int di = -1;
+        if (this->slotSide() == LEFT)
+                di = 1;
+        BicycleCar *CC = this->getEPC();
+        BicycleCar *B = this->getEP();
+        this->DH(di * 0.01 / CC->out_radi());
+        BicycleCar *c;
+        int i = 0;
+        c = B->move(CC, -i * di * 0.01 / CC->diag_radi());
+        while (!this->slot().collide(c->frame())) {
+                bool end = false;
+                std::vector<RRTEdge *> eds = c->frame();
+                for (auto o: co)
+                        if (o.collide(eds))
+                                end = true;
+                for (auto o: so)
+                        if (o.collide(eds))
+                                end = true;
+                for (auto e: eds)
+                        delete e;
+                if (!end)
+                        q.push(c);
+                c = B->move(CC, -i * di * 0.01 / CC->diag_radi());
+                i += 1;
+        }
+        delete c; // not in q and collide
+        while (!q.empty()) {
+                c = q.front();
+                q.pop();
+                if (this->isInside(c)) {
+                        goto createcuspandfinish;
+                } else if (c->s() < 9) {
+                        BicycleCar *cc = this->flnc(c, co, so);
+                        cc->s(c->s() + 1);
+                        cc->bcparent(c);
+                        q.push(cc);
+                } else {
+                        delete c; // not in q and collide
+                }
+        }
+        std::swap(q, empty);
+        return;
+createcuspandfinish:
+        std::vector<RRTNode *> cusp;
+        while (c) {
+                cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
+                c = c->bcparent();
+        }
+        std::reverse(cusp.begin(), cusp.end());
+        this->cusp().push_back(cusp);
+        std::swap(q, empty);
+}
+
+void ParallelSlot::fipf(
+        std::vector<CircleObstacle>& co,
+        std::vector<SegmentObstacle>& so
+)
 {
-        if (this->slot().bnodes().front()->y() >
-                        this->slot().bnodes().back()->y())
-                return this->slot().bnodes().front();
+        this->setAll();
+        std::vector<RRTNode *> tmpc;
+        BicycleCar *tmpf = this->getFPf();
+        BicycleCar *tmpb = this->getISPPf(tmpf);
+        RRTNode *cc;
+        if (this->slotSide() == LEFT)
+                cc = tmpb->ccl();
         else
-                return this->slot().bnodes().back();
+                cc = tmpb->ccr();
+        if (this->slotSide() == LEFT)
+                this->DH(-1 * 0.5 / tmpb->out_radi());
+        else
+                this->DH(1 * 0.5 / tmpb->out_radi());
+        BicycleCar *p;
+        int i = 1;
+        p = tmpb->move(cc, i * this->DH());
+        while (
+                !this->slot().collide(p->frame())
+                && ((
+                        this->slotSide() == LEFT
+                        && p->h() > this->slotHeading()
+                ) || (
+                        this->slotSide() == RIGHT
+                        && p->h() < this->slotHeading()
+                ))
+        ) {
+                if (tmpc.size() == 0) {
+                        i = 0;
+                        p = this->getFPf();
+                }
+                bool end = false;
+                std::vector<RRTEdge *> eds = p->frame();
+                for (auto o: co)
+                        if (o.collide(eds))
+                                end = true;
+                for (auto o: so)
+                        if (o.collide(eds))
+                                end = true;
+                for (auto e: eds)
+                        delete e;
+                if (end)
+                        break;
+                this->goals_.push_back(p);
+                tmpc.push_back(p);
+                i += 1;
+                p = tmpb->move(cc, i * this->DH());
+        }
+        if (tmpc.size() > 0)
+                this->cusp().push_back(tmpc);
+        return;
+}
+
+BicycleCar *ParallelSlot::flnc(
+        BicycleCar *B,
+        std::vector<CircleObstacle>& co,
+        std::vector<SegmentObstacle>& so
+)
+{
+        RRTNode *cc;
+        if (this->slotSide() == LEFT) {
+                if (int(B->s()) % 2 == 0)
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
+                else
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
+        } else {
+                if (int(B->s()) % 2 == 0)
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
+                else
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
+        }
+        BicycleCar *p;
+        int i = 1;
+        p = B->move(cc, i * this->DH());
+        while (
+                !this->slot().collide(p->frame())
+                && std::abs(this->slotHeading() - p->h()) < M_PI / 2
+        ) {
+                delete p;
+                i += 10;
+                p = B->move(cc, i * this->DH());
+                bool end = false;
+                std::vector<RRTEdge *> eds = p->frame();
+                for (auto o: co)
+                        if (o.collide(eds))
+                                end = true;
+                for (auto o: so)
+                        if (o.collide(eds))
+                                end = true;
+                for (auto e: eds)
+                        delete e;
+                if (end)
+                        break;
+        }
+        i -= 10;
+        p = B->move(cc, i * this->DH());
+        while (
+                !this->slot().collide(p->frame())
+                && std::abs(this->slotHeading() - p->h()) < M_PI / 2
+        ) {
+                if (this->isInside(p)) {
+                        i += 1;
+                        break;
+                }
+                delete p;
+                i += 1;
+                p = B->move(cc, i * this->DH());
+                bool end = false;
+                std::vector<RRTEdge *> eds = p->frame();
+                for (auto o: co)
+                        if (o.collide(eds))
+                                end = true;
+                for (auto o: so)
+                        if (o.collide(eds))
+                                end = true;
+                for (auto e: eds)
+                        delete e;
+                if (end)
+                        break;
+        }
+        delete p;
+        return B->move(cc, (i - 1) * this->DH());
+}
+
+void ParallelSlot::fipr(RRTNode *n)
+{
+        return this->fipr(new BicycleCar(n->x(), n->y(), n->h()));
+}
+
+void ParallelSlot::fipr(BicycleCar *B)
+{
+        std::vector<RRTNode *> cusp;
+        cusp.push_back(new RRTNode(B->x(), B->y(), B->h()));
+        int di = 1;
+        if (this->slotSide() == LEFT)
+                di = -1;
+        if (this->slotType() == PERPENDICULAR) {
+                this->DH(di * 0.01 / B->out_radi()); // TODO car in slot h()
+                RRTNode *cc;
+                if (this->slotSide() == LEFT)
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
+                else
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
+                BicycleCar *p;
+                int i = 1;
+                p = B->move(cc, i * this->DH());
+                while (
+                        !this->slot().collide(p->frame())
+                        && this->slot().collide(p)
+                ) {
+                        delete p;
+                        i += 10;
+                        p = B->move(cc, i * this->DH());
+                }
+                i -= 10;
+                p = B->move(cc, i * this->DH());
+                while (
+                        !this->slot().collide(p->frame())
+                        && this->slot().collide(p)
+                ) {
+                        delete p;
+                        i += 1;
+                        p = B->move(cc, i * this->DH());
+                }
+                i -= 1;
+                p = B->move(cc, i * this->DH());
+                cusp.push_back(new RRTNode(p->x(), p->y(), p->h()));
+                std::reverse(cusp.begin(), cusp.end());
+                this->cusp().push_back(cusp);
+                return;
+        }
+        this->DH(di * 0.01 / B->out_radi());
+        BicycleCar *c;
+        c = this->flncr(B);
+        c->s(B->s() + 1);
+        while ((
+                this->slotSide() == LEFT
+                && this->slot().collide(new RRTNode(c->lfx(), c->lfy(), 0))
+        ) || (
+                this->slotSide() == RIGHT
+                && this->slot().collide(new RRTNode(c->rfx(), c->rfy(), 0))
+        )) {
+                cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
+                BicycleCar *cc = this->flncr(c);
+                cc->s(c->s() + 1);
+                delete c;
+                c = cc;
+        }
+        cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
+        std::reverse(cusp.begin(), cusp.end());
+        this->cusp().push_back(cusp);
+}
+
+BicycleCar *ParallelSlot::flncr(BicycleCar *B)
+{
+        RRTNode *cc;
+        if (this->slotSide() == LEFT) {
+                if (int(B->s()) % 2 == 0)
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
+                else
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
+        } else {
+                if (int(B->s()) % 2 == 0)
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
+                else
+                        cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
+        }
+        BicycleCar *p;
+        int i = 1;
+        p = B->move(cc, i * this->DH());
+        while (
+                !this->slot().collide(p->frame())
+                && ((
+                        this->slotSide() == LEFT
+                        && this->slot().collide(new RRTNode(
+                                p->lfx(),
+                                p->lfy(),
+                                0
+                        ))
+                ) || (
+                        this->slotSide() == RIGHT
+                        && this->slot().collide(new RRTNode(
+                                p->rfx(),
+                                p->rfy(),
+                                0
+                        ))
+                ))
+        ) {
+                delete p;
+                i += 10;
+                p = B->move(cc, i * this->DH());
+        }
+        i -= 10;
+        p = B->move(cc, i * this->DH());
+        while (!this->slot().collide(p->frame())) {
+                if(
+                        this->slotSide() == LEFT
+                        && !this->slot().collide(new RRTNode(
+                                p->lfx(),
+                                p->lfy(),
+                                0
+                        ))
+                ) {
+                        i += 1;
+                        break;
+                }
+                if(
+                        this->slotSide() == RIGHT
+                        && !this->slot().collide(new RRTNode(
+                                p->rfx(),
+                                p->rfy(),
+                                0
+                        ))
+                ) {
+                        i += 1;
+                        break;
+                }
+                i += 1;
+                p = B->move(cc, i * this->DH());
+        }
+        delete p;
+        return B->move(cc, (i - 1) * this->DH());
+}
+
+RRTNode *ParallelSlot::fposecenter()
+{
+        return this->slot().bnodes().back();
 }
 
 bool ParallelSlot::flast(
@@ -70,6 +522,17 @@ bool ParallelSlot::flast(
         BicycleCar *p;
         int i = 1;
         p = B->move(cc, i * this->DH());
+        while (!this->slot().collide(p->frame())
+                        && (
+                                (this->DH() > 0 && p->x() <= 0)
+                                || (this->DH() < 0 && p->x() >= 0)
+                        )) {
+                delete p;
+                i += 10;
+                p = B->move(cc, i * this->DH());
+        }
+        i -= 10;
+        p = B->move(cc, i * this->DH());
         while (!this->slot().collide(p->frame())
                         && (
                                 (this->DH() > 0 && p->x() <= 0)
@@ -83,8 +546,8 @@ bool ParallelSlot::flast(
                         i += 1;
                         break;
                 }
-                i += 1;
                 delete p;
+                i += 1;
                 p = B->move(cc, i * this->DH());
         }
         delete p;
@@ -109,12 +572,12 @@ void ParallelSlot::fpose()
         BicycleCar *CC = new BicycleCar(
                 this->fposecenter()->x(),
                 this->fposecenter()->y() - 0.01,
-                M_PI / 2
+                this->slotHeading()
         );
         BicycleCar *B = new BicycleCar(
                 CC->x() - CC->width() / 2,
                 CC->y() - (CC->length() + CC->wheelbase()) / 2,
-                M_PI / 2
+                this->slotHeading()
         );
         if (this->slot().bnodes()[0]->x() > this->slot().bnodes()[1]->x()) {
                 left = true;
@@ -123,7 +586,7 @@ void ParallelSlot::fpose()
                 B = new BicycleCar(
                         CC->x() + CC->width() / 2,
                         CC->y() - (CC->length() + CC->wheelbase()) / 2,
-                        M_PI / 2
+                        this->slotHeading()
                 );
         }
         this->DH(di * 0.01 / CC->out_radi());
@@ -142,3 +605,256 @@ void ParallelSlot::fpose()
                 p = B->move(CC, -i * di * 0.01 / CC->diag_radi());
         }
 }
+
+BicycleCar *ParallelSlot::getEP()
+{
+        // new pose for parallel parking to right slot
+        float tnx;
+        float tny;
+        float nx;
+        float ny;
+        BicycleCar *CC = this->getEPC();
+        // move left by car width / 2
+        tnx = CC->x() + CC->width() / 2 * cos(CC->h() + M_PI / 2);
+        tny = CC->y() + CC->width() / 2 * sin(CC->h() + M_PI / 2);
+        if (this->slotSide() == LEFT) {
+                // move right by car width / 2
+                tnx = CC->x() + CC->width() / 2 * cos(CC->h() - M_PI / 2);
+                tny = CC->y() + CC->width() / 2 * sin(CC->h() - M_PI / 2);
+        }
+        if (this->slotType() == PARALLEL) {
+                // move down
+                nx = tnx - (CC->length() + CC->wheelbase()) / 2 * cos(CC->h());
+                ny = tny - (CC->length() + CC->wheelbase()) / 2 * sin(CC->h());
+        } else {
+                // move down
+                nx = tnx + (CC->length() - CC->wheelbase()) / 2 * cos(CC->h());
+                ny = tny + (CC->length() - CC->wheelbase()) / 2 * sin(CC->h());
+        }
+        return new BicycleCar(nx, ny, CC->h());
+}
+
+BicycleCar *ParallelSlot::getEPC()
+{
+        // new pose for parallel parking to right slot
+        float ta;
+        float nx;
+        float ny;
+        ta = this->slotHeading() + M_PI;
+        if (this->slotSide() == RIGHT)
+                ta -= M_PI / 4;
+        else
+                ta += M_PI / 4;
+        nx = this->fposecenter()->x() + 0.01 * cos(ta);
+        ny = this->fposecenter()->y() + 0.01 * sin(ta);
+        return new BicycleCar(nx, ny, this->slotHeading());
+}
+
+BicycleCar *ParallelSlot::getFP()
+{
+        this->setAll();
+        float x = this->slot().bnodes()[0]->x();
+        float y = this->slot().bnodes()[0]->y();
+        float h = this->slotHeading();
+        float ph = this->poseHeading();
+        float nx;
+        float ny;
+        if (this->slotType() == PARALLEL) {
+                if (this->slotSide() == LEFT) {
+                        nx = x + BCAR_WIDTH / 2 * cos(h + M_PI / 2);
+                        ny = y + BCAR_WIDTH / 2 * sin(h + M_PI / 2);
+                } else {
+                        nx = x + BCAR_WIDTH / 2 * cos(h - M_PI / 2);
+                        ny = y + BCAR_WIDTH / 2 * sin(h - M_PI / 2);
+                }
+                x = nx + ((BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 + 0.01) * cos(h);
+                y = ny + ((BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 + 0.01) * sin(h);
+        } else {
+                if (this->slotSide() == LEFT) {
+                        nx = x + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
+                                * cos(ph + M_PI);
+                        ny = y + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
+                                * sin(ph + M_PI);
+                        x = nx + (BCAR_DIAG_RRADI) * cos(h);
+                        y = ny + (BCAR_DIAG_RRADI) * sin(h);
+                } else {
+                        nx = x + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
+                                * cos(ph + M_PI);
+                        ny = y + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
+                                * sin(ph + M_PI);
+                        x = nx + (BCAR_DIAG_RRADI) * cos(h);
+                        y = ny + (BCAR_DIAG_RRADI) * sin(h);
+                }
+        }
+        return new BicycleCar(x, y, ph);
+}
+
+BicycleCar *ParallelSlot::getISPP(BicycleCar *B)
+{
+        // rigt side (for right parking slot)
+        float x = this->slot().bnodes().back()->x();
+        float y = this->slot().bnodes().back()->y();
+        float x1;
+        float y1;
+        if (this->slotSide() == LEFT) {
+                x1 = B->ccl()->x();
+                y1 = B->ccl()->y();
+        } else {
+                x1 = B->ccr()->x();
+                y1 = B->ccr()->y();
+        }
+        float IR = BCAR_IN_RADI;
+        float a = 1;
+        float b = (x1 - x) * 2 * cos(B->h()) + (y1 - y) * 2 * sin(B->h());
+        float c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
+        float D = pow(b, 2) - 4 * a * c;
+        float delta;
+        delta = -b - sqrt(D);
+        delta /= 2 * a;
+        float delta_1 = delta;
+        // left front (for right parking slot)
+        x = this->slot().bnodes().front()->x();
+        y = this->slot().bnodes().front()->y();
+        IR = BCAR_OUT_RADI;
+        a = 1;
+        b = (x1 - x) * 2 * cos(B->h()) + (y1 - y) * 2 * sin(B->h());
+        c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
+        D = pow(b, 2) - 4 * a * c;
+        //delta = -b + sqrt(D);
+        //delta /= 2 * a;
+        float delta_2 = delta;
+        delta = -b - sqrt(D);
+        delta /= 2 * a;
+        float delta_3 = delta;
+        delta = std::max(delta_1, std::max(delta_2, delta_3));
+        return new BicycleCar(
+                B->x() + delta * cos(B->h()),
+                B->y() + delta * sin(B->h()),
+                B->h()
+        );
+}
+
+BicycleCar *ParallelSlot::getFPf()
+{
+        this->setAll();
+        float x = this->slot().bnodes().front()->x();
+        float y = this->slot().bnodes().front()->y();
+        float h = this->slotHeading();
+        float ph = this->poseHeading();
+        ph += M_PI;
+        while (ph > M_PI)
+                ph -= 2 * M_PI;
+        while (ph <= -M_PI)
+                ph += 2 * M_PI;
+        float nx;
+        float ny;
+        nx = x + (BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 * cos(ph);
+        ny = y + (BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 * sin(ph);
+        x = nx + (BCAR_DIAG_RRADI) * cos(h);
+        y = ny + (BCAR_DIAG_RRADI) * sin(h);
+        return new BicycleCar(x, y, ph);
+}
+
+BicycleCar *ParallelSlot::getISPPf(BicycleCar *B)
+{
+        // right rear (for right parking slot)
+        float x = this->slot().bnodes().front()->x();
+        float y = this->slot().bnodes().front()->y();
+        float x1;
+        float y1;
+        if (this->slotSide() == LEFT) {
+                x1 = B->ccl()->x();
+                y1 = B->ccl()->y();
+        } else {
+                x1 = B->ccr()->x();
+                y1 = B->ccr()->y();
+        }
+        float IR = BCAR_IN_RADI;
+        float a = 1;
+        float b = (x - x1) * 2 * cos(B->h()) + (y - y1) * 2 * sin(B->h());
+        float c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
+        float D = pow(b, 2) - 4 * a * c;
+        float delta;
+        delta = -b - sqrt(D); // TODO why this works?
+        delta /= 2 * a;
+        float delta_1 = delta;
+        // left front (for right parking slot)
+        x = this->slot().bnodes().back()->x();
+        y = this->slot().bnodes().back()->y();
+        IR = BCAR_OUT_RADI;
+        a = 1;
+        b = (x - x1) * 2 * cos(B->h()) + (y - y1) * 2 * sin(B->h());
+        c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
+        D = pow(b, 2) - 4 * a * c;
+        delta = -b + sqrt(D);
+        delta /= 2 * a;
+        float delta_2 = delta;
+        delta = -b - sqrt(D);
+        delta /= 2 * a;
+        float delta_3 = delta;
+        delta = std::max(delta_1, std::max(delta_2, delta_3));
+        return new BicycleCar(
+                B->x() - delta * cos(B->h()),
+                B->y() - delta * sin(B->h()),
+                B->h()
+        );
+}
+
+bool ParallelSlot::isInside(BicycleCar *c)
+{
+        bool inside = true;
+        RRTNode *tmpn;
+        tmpn = new RRTNode(c->lfx(), c->lfy(), 0);
+        if (!this->slot().collide(tmpn))
+                inside = false;
+        delete tmpn;
+        tmpn = new RRTNode(c->lrx(), c->lry(), 0);
+        if (!this->slot().collide(tmpn))
+                inside = false;
+        delete tmpn;
+        tmpn = new RRTNode(c->rrx(), c->rry(), 0);
+        if (!this->slot().collide(tmpn))
+                inside = false;
+        delete tmpn;
+        tmpn = new RRTNode(c->rfx(), c->rfy(), 0);
+        if (!this->slot().collide(tmpn))
+                inside = false;
+        delete tmpn;
+        return inside;
+}
+
+struct SamplingInfo ParallelSlot::getSamplingInfo()
+{
+        struct SamplingInfo si;
+        RRTNode *n = this->getMidd();
+        if (n == nullptr)
+                return si;
+        BicycleCar *bc = new BicycleCar(n->x(), n->y(), n->h());
+        RRTNode *cc;
+        if (this->slotSide() == LEFT)
+                cc = bc->ccl();
+        else
+                cc = bc->ccr();
+        if (this->slotType() == PARALLEL) {
+                BicycleCar *nbc = bc->move(cc, this->slotHeading() - n->h());
+                si.x0 = nbc->x();
+                si.y0 = nbc->y();
+                si.h0 = nbc->h();
+                si.x = BCAR_WIDTH;
+                si.y = BCAR_WIDTH;
+                si.h = M_PI / 8;
+        } else {
+                BicycleCar *nbc;
+                if (this->slotSide() == LEFT)
+                        nbc = bc->move(cc, M_PI/4);
+                else
+                        nbc = bc->move(cc, -M_PI/4);
+                si.x0 = nbc->x();
+                si.y0 = nbc->y();
+                si.h0 = nbc->h();
+                si.x = BCAR_WIDTH;
+                si.y = BCAR_WIDTH;
+                si.h = M_PI / 8;
+        }
+        return si;
+}