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