]> rtime.felk.cvut.cz Git - hubacji1/iamcar.git/blob - decision_control/slotplanner.cc
d37a8913fe682d0c2fe38726de96a9b369e806db
[hubacji1/iamcar.git] / decision_control / slotplanner.cc
1 /*
2 This file is part of I am car.
3
4 I am car is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 I am car is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with I am car. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <algorithm>
19 #include <cmath>
20 #include <list>
21 #include <queue>
22 #include "slotplanner.h"
23
24 ParallelSlot::ParallelSlot()
25 {}
26
27 // getter
28 std::vector<RRTNode *> &ParallelSlot::goals()
29 {
30         return this->goals_;
31 }
32
33 RRTNode *ParallelSlot::getMidd()
34 {
35         if (this->cusp().size() > 0)
36                 return this->cusp().front().front();
37         else
38                 return nullptr;
39 }
40
41 std::vector<std::vector<RRTNode *>> &ParallelSlot::cusp()
42 {
43         return this->cusp_;
44 }
45
46 float ParallelSlot::DH() const
47 {
48         return this->DH_;
49 }
50
51 PolygonObstacle &ParallelSlot::slot()
52 {
53         return this->slot_;
54 }
55
56 float ParallelSlot::slotHeading()
57 {
58         return this->slotHeading_;
59 }
60
61 SlotSide ParallelSlot::slotSide()
62 {
63         return this->slotSide_;
64 }
65
66 SlotType ParallelSlot::slotType()
67 {
68         return this->slotType_;
69 }
70
71 float ParallelSlot::poseHeading()
72 {
73         return this->poseHeading_;
74 }
75
76 // setter
77 void ParallelSlot::DH(float dh)
78 {
79         this->DH_ = dh;
80 }
81
82 void ParallelSlot::setAll()
83 {
84         // slot heading
85         float y0 = this->slot().bnodes()[0]->y();
86         float x0 = this->slot().bnodes()[0]->x();
87         float y3 = this->slot().bnodes()[3]->y();
88         float x3 = this->slot().bnodes()[3]->x();
89         float dy = y3 - y0;
90         float dx = x3 - x0;
91         this->slotHeading_ = atan2(dy, dx);
92         // pose heading
93         float y1 = this->slot().bnodes()[1]->y();
94         float x1 = this->slot().bnodes()[1]->x();
95         dy = y0 - y1;
96         dx = x0 - x1;
97         this->poseHeading_ = atan2(dy, dx);
98         // slot side
99         if (sgn((x1 - x0) * (y3 - y0) - (y1 - y0) * (x3 - x0)) < 0)
100                 this->slotSide_ = LEFT;
101         else
102                 this->slotSide_ = RIGHT;
103         // slot type
104         float d1 = EDIST(
105                 this->slot().bnodes()[0],
106                 this->slot().bnodes()[1]
107         );
108         float d2 = EDIST(
109                 this->slot().bnodes()[1],
110                 this->slot().bnodes()[2]
111         );
112         if (d1 > d2)
113                 this->slotType_ = PERPENDICULAR;
114         else
115                 this->slotType_ = PARALLEL;
116 }
117
118 // other
119 void ParallelSlot::fip(
120         std::vector<CircleObstacle>& co,
121         std::vector<SegmentObstacle>& so
122 )
123 {
124         this->setAll();
125         if (this->slotType() == PERPENDICULAR) {
126                 std::vector<RRTNode *> tmpc;
127                 BicycleCar *tmpf = this->getFP();
128                 BicycleCar *tmpb = this->getISPP(tmpf);
129                 RRTNode *cc;
130                 if (this->slotSide() == LEFT)
131                         cc = tmpb->ccl();
132                 else
133                         cc = tmpb->ccr();
134                 if (this->slotSide() == LEFT)
135                         this->DH(1 * 0.5 / tmpb->out_radi());
136                 else
137                         this->DH(-1 * 0.5 / tmpb->out_radi());
138                 BicycleCar *p;
139                 int i = 1;
140                 p = tmpb->move(cc, i * this->DH());
141                 while (
142                         !this->slot().collide(p->frame())
143                         && ((
144                                 this->slotSide() == LEFT
145                                 && p->h() < this->slotHeading()
146                         ) || (
147                                 this->slotSide() == RIGHT
148                                 && (
149                                         p->h() > this->slotHeading()
150                                         || p->h() < 0
151                                 )
152                         ))
153                 ) {
154                         if (tmpc.size() == 0) {
155                                 i = 0;
156                                 p = this->getFP();
157                         }
158                         bool end = false;
159                         std::vector<RRTEdge *> eds = p->frame();
160                         for (auto o: co)
161                                 if (o.collide(eds))
162                                         end = true;
163                         for (auto o: so)
164                                 if (o.collide(eds))
165                                         end = true;
166                         for (auto e: eds)
167                                 delete e;
168                         if (end)
169                                 break;
170                         this->goals_.push_back(p);
171                         tmpc.push_back(p);
172                         i += 1;
173                         p = tmpb->move(cc, i * this->DH());
174                 }
175                 if (tmpc.size() > 0)
176                         this->cusp().push_back(tmpc);
177                 return;
178         }
179         // see https://courses.cs.washington.edu/courses/cse326/03su/homework/hw3/bfs.html
180         // RRTNode.s() works as iteration level
181         std::queue<BicycleCar *, std::list<BicycleCar *>> q;
182         std::queue<BicycleCar *, std::list<BicycleCar *>> empty;
183         int di = -1;
184         if (this->slotSide() == LEFT)
185                 di = 1;
186         BicycleCar *CC = this->getEPC();
187         BicycleCar *B = this->getEP();
188         this->DH(di * 0.01 / CC->out_radi());
189         BicycleCar *c;
190         int i = 0;
191         c = B->move(CC, -i * di * 0.01 / CC->diag_radi());
192         while (!this->slot().collide(c->frame())) {
193                 bool end = false;
194                 std::vector<RRTEdge *> eds = c->frame();
195                 for (auto o: co)
196                         if (o.collide(eds))
197                                 end = true;
198                 for (auto o: so)
199                         if (o.collide(eds))
200                                 end = true;
201                 for (auto e: eds)
202                         delete e;
203                 if (!end)
204                         q.push(c);
205                 c = B->move(CC, -i * di * 0.01 / CC->diag_radi());
206                 i += 1;
207         }
208         delete c; // not in q and collide
209         while (!q.empty()) {
210                 c = q.front();
211                 q.pop();
212                 if (this->isInside(c)) {
213                         goto createcuspandfinish;
214                 } else if (c->s() < 9) {
215                         BicycleCar *cc = this->flnc(c, co, so);
216                         cc->s(c->s() + 1);
217                         cc->bcparent(c);
218                         q.push(cc);
219                 } else {
220                         delete c; // not in q and collide
221                 }
222         }
223         std::swap(q, empty);
224         return;
225 createcuspandfinish:
226         std::vector<RRTNode *> cusp;
227         while (c) {
228                 cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
229                 c = c->bcparent();
230         }
231         std::reverse(cusp.begin(), cusp.end());
232         this->cusp().push_back(cusp);
233         std::swap(q, empty);
234 }
235
236 void ParallelSlot::fipf(
237         std::vector<CircleObstacle>& co,
238         std::vector<SegmentObstacle>& so
239 )
240 {
241         this->setAll();
242         std::vector<RRTNode *> tmpc;
243         BicycleCar *tmpf = this->getFPf();
244         BicycleCar *tmpb = this->getISPPf(tmpf);
245         RRTNode *cc;
246         if (this->slotSide() == LEFT)
247                 cc = tmpb->ccl();
248         else
249                 cc = tmpb->ccr();
250         if (this->slotSide() == LEFT)
251                 this->DH(-1 * 0.5 / tmpb->out_radi());
252         else
253                 this->DH(1 * 0.5 / tmpb->out_radi());
254         BicycleCar *p;
255         int i = 1;
256         p = tmpb->move(cc, i * this->DH());
257         while (
258                 !this->slot().collide(p->frame())
259                 && ((
260                         this->slotSide() == LEFT
261                         && p->h() > this->slotHeading()
262                 ) || (
263                         this->slotSide() == RIGHT
264                         && p->h() < this->slotHeading()
265                 ))
266         ) {
267                 if (tmpc.size() == 0) {
268                         i = 0;
269                         p = this->getFPf();
270                 }
271                 bool end = false;
272                 std::vector<RRTEdge *> eds = p->frame();
273                 for (auto o: co)
274                         if (o.collide(eds))
275                                 end = true;
276                 for (auto o: so)
277                         if (o.collide(eds))
278                                 end = true;
279                 for (auto e: eds)
280                         delete e;
281                 if (end)
282                         break;
283                 this->goals_.push_back(p);
284                 tmpc.push_back(p);
285                 i += 1;
286                 p = tmpb->move(cc, i * this->DH());
287         }
288         if (tmpc.size() > 0)
289                 this->cusp().push_back(tmpc);
290         return;
291 }
292
293 BicycleCar *ParallelSlot::flnc(
294         BicycleCar *B,
295         std::vector<CircleObstacle>& co,
296         std::vector<SegmentObstacle>& so
297 )
298 {
299         RRTNode *cc;
300         if (this->slotSide() == LEFT) {
301                 if (int(B->s()) % 2 == 0)
302                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
303                 else
304                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
305         } else {
306                 if (int(B->s()) % 2 == 0)
307                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
308                 else
309                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
310         }
311         BicycleCar *p;
312         int i = 1;
313         p = B->move(cc, i * this->DH());
314         while (
315                 !this->slot().collide(p->frame())
316                 && std::abs(this->slotHeading() - p->h()) < M_PI / 2
317         ) {
318                 delete p;
319                 i += 10;
320                 p = B->move(cc, i * this->DH());
321                 bool end = false;
322                 std::vector<RRTEdge *> eds = p->frame();
323                 for (auto o: co)
324                         if (o.collide(eds))
325                                 end = true;
326                 for (auto o: so)
327                         if (o.collide(eds))
328                                 end = true;
329                 for (auto e: eds)
330                         delete e;
331                 if (end)
332                         break;
333         }
334         i -= 10;
335         p = B->move(cc, i * this->DH());
336         while (
337                 !this->slot().collide(p->frame())
338                 && std::abs(this->slotHeading() - p->h()) < M_PI / 2
339         ) {
340                 if (this->isInside(p)) {
341                         i += 1;
342                         break;
343                 }
344                 delete p;
345                 i += 1;
346                 p = B->move(cc, i * this->DH());
347                 bool end = false;
348                 std::vector<RRTEdge *> eds = p->frame();
349                 for (auto o: co)
350                         if (o.collide(eds))
351                                 end = true;
352                 for (auto o: so)
353                         if (o.collide(eds))
354                                 end = true;
355                 for (auto e: eds)
356                         delete e;
357                 if (end)
358                         break;
359         }
360         delete p;
361         return B->move(cc, (i - 1) * this->DH());
362 }
363
364 void ParallelSlot::fipr(RRTNode *n)
365 {
366         return this->fipr(new BicycleCar(n->x(), n->y(), n->h()));
367 }
368
369 void ParallelSlot::fipr(BicycleCar *B)
370 {
371         std::vector<RRTNode *> cusp;
372         cusp.push_back(new RRTNode(B->x(), B->y(), B->h()));
373         int di = 1;
374         if (this->slotSide() == LEFT)
375                 di = -1;
376         if (this->slotType() == PERPENDICULAR) {
377                 this->DH(di * 0.01 / B->out_radi()); // TODO car in slot h()
378                 RRTNode *cc;
379                 if (this->slotSide() == LEFT)
380                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
381                 else
382                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
383                 BicycleCar *p;
384                 int i = 1;
385                 p = B->move(cc, i * this->DH());
386                 while (
387                         !this->slot().collide(p->frame())
388                         && this->slot().collide(p)
389                 ) {
390                         delete p;
391                         i += 10;
392                         p = B->move(cc, i * this->DH());
393                 }
394                 i -= 10;
395                 p = B->move(cc, i * this->DH());
396                 while (
397                         !this->slot().collide(p->frame())
398                         && this->slot().collide(p)
399                 ) {
400                         delete p;
401                         i += 1;
402                         p = B->move(cc, i * this->DH());
403                 }
404                 i -= 1;
405                 p = B->move(cc, i * this->DH());
406                 cusp.push_back(new RRTNode(p->x(), p->y(), p->h()));
407                 std::reverse(cusp.begin(), cusp.end());
408                 this->cusp().push_back(cusp);
409                 return;
410         }
411         this->DH(di * 0.01 / B->out_radi());
412         BicycleCar *c;
413         c = this->flncr(B);
414         c->s(B->s() + 1);
415         while ((
416                 this->slotSide() == LEFT
417                 && this->slot().collide(new RRTNode(c->lfx(), c->lfy(), 0))
418         ) || (
419                 this->slotSide() == RIGHT
420                 && this->slot().collide(new RRTNode(c->rfx(), c->rfy(), 0))
421         )) {
422                 cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
423                 BicycleCar *cc = this->flncr(c);
424                 cc->s(c->s() + 1);
425                 delete c;
426                 c = cc;
427         }
428         cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
429         std::reverse(cusp.begin(), cusp.end());
430         this->cusp().push_back(cusp);
431 }
432
433 BicycleCar *ParallelSlot::flncr(BicycleCar *B)
434 {
435         RRTNode *cc;
436         if (this->slotSide() == LEFT) {
437                 if (int(B->s()) % 2 == 0)
438                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
439                 else
440                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
441         } else {
442                 if (int(B->s()) % 2 == 0)
443                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
444                 else
445                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
446         }
447         BicycleCar *p;
448         int i = 1;
449         p = B->move(cc, i * this->DH());
450         while (
451                 !this->slot().collide(p->frame())
452                 && ((
453                         this->slotSide() == LEFT
454                         && this->slot().collide(new RRTNode(
455                                 p->lfx(),
456                                 p->lfy(),
457                                 0
458                         ))
459                 ) || (
460                         this->slotSide() == RIGHT
461                         && this->slot().collide(new RRTNode(
462                                 p->rfx(),
463                                 p->rfy(),
464                                 0
465                         ))
466                 ))
467         ) {
468                 delete p;
469                 i += 10;
470                 p = B->move(cc, i * this->DH());
471         }
472         i -= 10;
473         p = B->move(cc, i * this->DH());
474         while (!this->slot().collide(p->frame())) {
475                 if(
476                         this->slotSide() == LEFT
477                         && !this->slot().collide(new RRTNode(
478                                 p->lfx(),
479                                 p->lfy(),
480                                 0
481                         ))
482                 ) {
483                         i += 1;
484                         break;
485                 }
486                 if(
487                         this->slotSide() == RIGHT
488                         && !this->slot().collide(new RRTNode(
489                                 p->rfx(),
490                                 p->rfy(),
491                                 0
492                         ))
493                 ) {
494                         i += 1;
495                         break;
496                 }
497                 i += 1;
498                 p = B->move(cc, i * this->DH());
499         }
500         delete p;
501         return B->move(cc, (i - 1) * this->DH());
502 }
503
504 RRTNode *ParallelSlot::fposecenter()
505 {
506         return this->slot().bnodes().back();
507 }
508
509 bool ParallelSlot::flast(
510         RRTNode *P,
511         bool right,
512         int il,
513         std::vector<RRTNode *> &cusp
514 )
515 {
516         BicycleCar *B = new BicycleCar(P->x(), P->y(), P->h());
517         RRTNode *cc;
518         if (right)
519                 cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
520         else
521                 cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
522         BicycleCar *p;
523         int i = 1;
524         p = B->move(cc, i * this->DH());
525         while (!this->slot().collide(p->frame())
526                         && (
527                                 (this->DH() > 0 && p->x() <= 0)
528                                 || (this->DH() < 0 && p->x() >= 0)
529                         )) {
530                 delete p;
531                 i += 10;
532                 p = B->move(cc, i * this->DH());
533         }
534         i -= 10;
535         p = B->move(cc, i * this->DH());
536         while (!this->slot().collide(p->frame())
537                         && (
538                                 (this->DH() > 0 && p->x() <= 0)
539                                 || (this->DH() < 0 && p->x() >= 0)
540                         )) {
541                 if (this->DH() > 0 && p->rfx() <= 0 && p->rrx() <= 0) {
542                         i += 1;
543                         break;
544                 }
545                 if (this->DH() < 0 && p->lfx() >= 0 && p->lrx() >= 0) {
546                         i += 1;
547                         break;
548                 }
549                 delete p;
550                 i += 1;
551                 p = B->move(cc, i * this->DH());
552         }
553         delete p;
554         p = B->move(cc, (i - 1) * this->DH());
555         if (this->DH() > 0 && p->rfx() <= 0 && p->rrx() <= 0) {
556                 cusp.push_back(p);
557                 return true;
558         } else if (this->DH() < 0 && p->lfx() >= 0 && p->lrx() >= 0) {
559                 cusp.push_back(p);
560                 return true;
561         } else if (il < 8) {
562                 cusp.push_back(p);
563                 return this->flast(p, !right, il + 1, cusp);
564         }
565         return false;
566 }
567
568 void ParallelSlot::fpose()
569 {
570         bool left = false; // right parking slot
571         float di = -1;
572         BicycleCar *CC = new BicycleCar(
573                 this->fposecenter()->x(),
574                 this->fposecenter()->y() - 0.01,
575                 this->slotHeading()
576         );
577         BicycleCar *B = new BicycleCar(
578                 CC->x() - CC->width() / 2,
579                 CC->y() - (CC->length() + CC->wheelbase()) / 2,
580                 this->slotHeading()
581         );
582         if (this->slot().bnodes()[0]->x() > this->slot().bnodes()[1]->x()) {
583                 left = true;
584                 di = 1;
585                 delete B;
586                 B = new BicycleCar(
587                         CC->x() + CC->width() / 2,
588                         CC->y() - (CC->length() + CC->wheelbase()) / 2,
589                         this->slotHeading()
590                 );
591         }
592         this->DH(di * 0.01 / CC->out_radi());
593         BicycleCar *p;
594         int i = 0;
595         p = B->move(CC, -i * di * 0.01 / CC->diag_radi());
596         while (!this->slot().collide(p->frame())) {
597                 std::vector<RRTNode *> tmpcusp;
598                 tmpcusp.push_back(new BicycleCar(p->x(), p->y(), p->h()));
599                 if (this->flast(p, left, 0, tmpcusp)) {
600                         this->cusp().push_back(tmpcusp);
601                         return;
602                 }
603                 i += 1;
604                 delete p;
605                 p = B->move(CC, -i * di * 0.01 / CC->diag_radi());
606         }
607 }
608
609 BicycleCar *ParallelSlot::getEP()
610 {
611         // new pose for parallel parking to right slot
612         float tnx;
613         float tny;
614         float nx;
615         float ny;
616         BicycleCar *CC = this->getEPC();
617         // move left by car width / 2
618         tnx = CC->x() + CC->width() / 2 * cos(CC->h() + M_PI / 2);
619         tny = CC->y() + CC->width() / 2 * sin(CC->h() + M_PI / 2);
620         if (this->slotSide() == LEFT) {
621                 // move right by car width / 2
622                 tnx = CC->x() + CC->width() / 2 * cos(CC->h() - M_PI / 2);
623                 tny = CC->y() + CC->width() / 2 * sin(CC->h() - M_PI / 2);
624         }
625         if (this->slotType() == PARALLEL) {
626                 // move down
627                 nx = tnx - (CC->length() + CC->wheelbase()) / 2 * cos(CC->h());
628                 ny = tny - (CC->length() + CC->wheelbase()) / 2 * sin(CC->h());
629         } else {
630                 // move down
631                 nx = tnx + (CC->length() - CC->wheelbase()) / 2 * cos(CC->h());
632                 ny = tny + (CC->length() - CC->wheelbase()) / 2 * sin(CC->h());
633         }
634         return new BicycleCar(nx, ny, CC->h());
635 }
636
637 BicycleCar *ParallelSlot::getEPC()
638 {
639         // new pose for parallel parking to right slot
640         float ta;
641         float nx;
642         float ny;
643         ta = this->slotHeading() + M_PI;
644         if (this->slotSide() == RIGHT)
645                 ta -= M_PI / 4;
646         else
647                 ta += M_PI / 4;
648         nx = this->fposecenter()->x() + 0.01 * cos(ta);
649         ny = this->fposecenter()->y() + 0.01 * sin(ta);
650         return new BicycleCar(nx, ny, this->slotHeading());
651 }
652
653 BicycleCar *ParallelSlot::getFP()
654 {
655         this->setAll();
656         float x = this->slot().bnodes()[0]->x();
657         float y = this->slot().bnodes()[0]->y();
658         float h = this->slotHeading();
659         float ph = this->poseHeading();
660         float nx;
661         float ny;
662         if (this->slotType() == PARALLEL) {
663                 if (this->slotSide() == LEFT) {
664                         nx = x + BCAR_WIDTH / 2 * cos(h + M_PI / 2);
665                         ny = y + BCAR_WIDTH / 2 * sin(h + M_PI / 2);
666                 } else {
667                         nx = x + BCAR_WIDTH / 2 * cos(h - M_PI / 2);
668                         ny = y + BCAR_WIDTH / 2 * sin(h - M_PI / 2);
669                 }
670                 x = nx + ((BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 + 0.01) * cos(h);
671                 y = ny + ((BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 + 0.01) * sin(h);
672         } else {
673                 if (this->slotSide() == LEFT) {
674                         nx = x + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
675                                 * cos(ph + M_PI);
676                         ny = y + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
677                                 * sin(ph + M_PI);
678                         x = nx + (BCAR_DIAG_RRADI) * cos(h);
679                         y = ny + (BCAR_DIAG_RRADI) * sin(h);
680                 } else {
681                         nx = x + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
682                                 * cos(ph + M_PI);
683                         ny = y + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
684                                 * sin(ph + M_PI);
685                         x = nx + (BCAR_DIAG_RRADI) * cos(h);
686                         y = ny + (BCAR_DIAG_RRADI) * sin(h);
687                 }
688         }
689         return new BicycleCar(x, y, ph);
690 }
691
692 BicycleCar *ParallelSlot::getISPP(BicycleCar *B)
693 {
694         // rigt side (for right parking slot)
695         float x = this->slot().bnodes().back()->x();
696         float y = this->slot().bnodes().back()->y();
697         float x1;
698         float y1;
699         if (this->slotSide() == LEFT) {
700                 x1 = B->ccl()->x();
701                 y1 = B->ccl()->y();
702         } else {
703                 x1 = B->ccr()->x();
704                 y1 = B->ccr()->y();
705         }
706         float IR = BCAR_IN_RADI;
707         float a = 1;
708         float b = (x1 - x) * 2 * cos(B->h()) + (y1 - y) * 2 * sin(B->h());
709         float c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
710         float D = pow(b, 2) - 4 * a * c;
711         float delta;
712         delta = -b - sqrt(D);
713         delta /= 2 * a;
714         float delta_1 = delta;
715         // left front (for right parking slot)
716         x = this->slot().bnodes().front()->x();
717         y = this->slot().bnodes().front()->y();
718         IR = BCAR_OUT_RADI;
719         a = 1;
720         b = (x1 - x) * 2 * cos(B->h()) + (y1 - y) * 2 * sin(B->h());
721         c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
722         D = pow(b, 2) - 4 * a * c;
723         //delta = -b + sqrt(D);
724         //delta /= 2 * a;
725         float delta_2 = delta;
726         delta = -b - sqrt(D);
727         delta /= 2 * a;
728         float delta_3 = delta;
729         delta = std::max(delta_1, std::max(delta_2, delta_3));
730         return new BicycleCar(
731                 B->x() + delta * cos(B->h()),
732                 B->y() + delta * sin(B->h()),
733                 B->h()
734         );
735 }
736
737 BicycleCar *ParallelSlot::getFPf()
738 {
739         this->setAll();
740         float x = this->slot().bnodes().front()->x();
741         float y = this->slot().bnodes().front()->y();
742         float h = this->slotHeading();
743         float ph = this->poseHeading();
744         ph += M_PI;
745         while (ph > M_PI)
746                 ph -= 2 * M_PI;
747         while (ph <= -M_PI)
748                 ph += 2 * M_PI;
749         float nx;
750         float ny;
751         nx = x + (BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 * cos(ph);
752         ny = y + (BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 * sin(ph);
753         x = nx + (BCAR_DIAG_RRADI) * cos(h);
754         y = ny + (BCAR_DIAG_RRADI) * sin(h);
755         return new BicycleCar(x, y, ph);
756 }
757
758 BicycleCar *ParallelSlot::getISPPf(BicycleCar *B)
759 {
760         // right rear (for right parking slot)
761         float x = this->slot().bnodes().front()->x();
762         float y = this->slot().bnodes().front()->y();
763         float x1;
764         float y1;
765         if (this->slotSide() == LEFT) {
766                 x1 = B->ccl()->x();
767                 y1 = B->ccl()->y();
768         } else {
769                 x1 = B->ccr()->x();
770                 y1 = B->ccr()->y();
771         }
772         float IR = BCAR_IN_RADI;
773         float a = 1;
774         float b = (x - x1) * 2 * cos(B->h()) + (y - y1) * 2 * sin(B->h());
775         float c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
776         float D = pow(b, 2) - 4 * a * c;
777         float delta;
778         delta = -b - sqrt(D); // TODO why this works?
779         delta /= 2 * a;
780         float delta_1 = delta;
781         // left front (for right parking slot)
782         x = this->slot().bnodes().back()->x();
783         y = this->slot().bnodes().back()->y();
784         IR = BCAR_OUT_RADI;
785         a = 1;
786         b = (x - x1) * 2 * cos(B->h()) + (y - y1) * 2 * sin(B->h());
787         c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
788         D = pow(b, 2) - 4 * a * c;
789         delta = -b + sqrt(D);
790         delta /= 2 * a;
791         float delta_2 = delta;
792         delta = -b - sqrt(D);
793         delta /= 2 * a;
794         float delta_3 = delta;
795         delta = std::max(delta_1, std::max(delta_2, delta_3));
796         return new BicycleCar(
797                 B->x() - delta * cos(B->h()),
798                 B->y() - delta * sin(B->h()),
799                 B->h()
800         );
801 }
802
803 bool ParallelSlot::isInside(BicycleCar *c)
804 {
805         bool inside = true;
806         RRTNode *tmpn;
807         tmpn = new RRTNode(c->lfx(), c->lfy(), 0);
808         if (!this->slot().collide(tmpn))
809                 inside = false;
810         delete tmpn;
811         tmpn = new RRTNode(c->lrx(), c->lry(), 0);
812         if (!this->slot().collide(tmpn))
813                 inside = false;
814         delete tmpn;
815         tmpn = new RRTNode(c->rrx(), c->rry(), 0);
816         if (!this->slot().collide(tmpn))
817                 inside = false;
818         delete tmpn;
819         tmpn = new RRTNode(c->rfx(), c->rfy(), 0);
820         if (!this->slot().collide(tmpn))
821                 inside = false;
822         delete tmpn;
823         return inside;
824 }
825
826 struct SamplingInfo ParallelSlot::getSamplingInfo()
827 {
828         struct SamplingInfo si;
829         RRTNode *n = this->getMidd();
830         if (this->slotType() == PARALLEL) {
831                 if (n != nullptr) {
832                         si.x0 = n->x() + 1.5 * BCAR_LENGTH * cos(n->h());
833                         si.y0 = n->y() + 1.5 * BCAR_LENGTH * sin(n->h());
834                         si.h0 = n->h();
835                 } else {
836                         si.x0 = this->slot().bnodes().front()->x();
837                         si.y0 = this->slot().bnodes().front()->y();
838                         si.h0 = this->slotHeading();
839                 }
840                 si.x = BCAR_WIDTH;
841                 si.y = BCAR_WIDTH;
842                 si.h = M_PI / 8;
843         } else {
844                 // TODO
845         }
846         return si;
847 }