]> rtime.felk.cvut.cz Git - hubacji1/psp.git/blob - src/psp.cc
Make backward default, add goal to last maneuver
[hubacji1/psp.git] / src / psp.cc
1 #include <cmath>
2 #include <list>
3 #include <queue>
4 #include "psp.h"
5
6 bool PSPlanner::collide()
7 {
8         std::vector<std::tuple<double, double>> bc;
9         bc.push_back(std::make_tuple(this->cc().lfx(), this->cc().lfy()));
10         bc.push_back(std::make_tuple(this->cc().lrx(), this->cc().lry()));
11         bc.push_back(std::make_tuple(this->cc().rrx(), this->cc().rry()));
12         bc.push_back(std::make_tuple(this->cc().rfx(), this->cc().rfy()));
13         bc.push_back(std::make_tuple(this->cc().lfx(), this->cc().lfy()));
14         std::vector<std::tuple<double, double>> ps;
15         ps.push_back(std::make_tuple(this->ps().x1(), this->ps().y1()));
16         ps.push_back(std::make_tuple(this->ps().x2(), this->ps().y2()));
17         ps.push_back(std::make_tuple(this->ps().x3(), this->ps().y3()));
18         ps.push_back(std::make_tuple(this->ps().x4(), this->ps().y4()));
19         return std::get<0>(::collide(bc, ps));
20 }
21
22 bool PSPlanner::forward()
23 {
24 #if FORWARD_PARKING > 0
25         return true;
26 #else
27         return false;
28 #endif
29 }
30
31 void PSPlanner::gc_to_4()
32 {
33         double angl_slot = atan2(
34                 this->ps().y3() - this->ps().y4(),
35                 this->ps().x3() - this->ps().x4()
36         );
37         double angl_delta = M_PI / 2;
38         if (this->ps().right())
39                 angl_delta = -M_PI / 2;
40         double x = this->ps().x4();
41         double y = this->ps().y4();
42         x += (this->gc().dr() + 0.01) * cos(angl_slot);
43         y += (this->gc().dr() + 0.01) * sin(angl_slot);
44         x += (this->gc().w() / 2 + 0.01) * cos(angl_slot + angl_delta);
45         y += (this->gc().w() / 2 + 0.01) * sin(angl_slot + angl_delta);
46         this->gc().x(x);
47         this->gc().y(y);
48         this->gc().h(angl_slot);
49 }
50
51 std::tuple<double, double, double, double> circle_line_intersection(
52         double cx, double cy, double r,
53         double x1, double y1,
54         double x2, double y2
55 )
56 {
57         double t = (y2 - y1) / (x2 - x1);
58         //double a = 1 + pow(t, 2);
59         //double b = - 2 * cx - 2 * pow(t, 2) * x1 + 2 * t * y1 - 2 * t * cy;
60         //double c = pow(cx, 2) + pow(t, 2) * pow(x1, 2) - 2 * t * y1 * x1
61         //        + pow(y1, 2) + 2 * t * cy * x1 - 2 * y1 * cy + pow(cy, 2)
62         //        - pow(r, 2);
63         double a = 1 + pow(t, 2);
64         double b = - 2 * cx + 2 * t * (-t * x1 + y1) - 2 * cy * t;
65         double c = pow(cx, 2) + pow(cy, 2) - pow(r, 2);
66         c += pow(-t * x1 + y1, 2);
67         c += 2 * cy * t * x1 - 2 * cy * y1;
68         double D = pow(b, 2) - 4 * a * c;
69         if (D < 0)
70                 return std::make_tuple(cx, cy, cx, cy);
71         double res_x1 = (-b + sqrt(D)) / (2 * a);
72         double res_y1 = t * (res_x1 - x1) + y1;
73         double res_x2 = (-b - sqrt(D)) / (2 * a);
74         double res_y2 = t * (res_x2 - x1) + y1;
75         return std::make_tuple(res_x1, res_y1, res_x2, res_y2);
76 }
77
78 double edist(double x1, double y1, double x2, double y2)
79 {
80         return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
81 }
82
83 void PSPlanner::guess_gc()
84 {
85         double x = this->ps().x1();
86         double y = this->ps().y1();
87         double h = this->ps().heading();
88         double dts = + M_PI / 2; // direction to slot
89         if (this->ps().right())
90                 dts = - M_PI / 2;
91         if (this->ps().parallel()) {
92                 x += (this->gc().w() / 2 + 0.01) * cos(h + dts);
93                 x += (this->gc().dr() + 0.01) * cos(h);
94                 y += (this->gc().w() / 2 + 0.01) * sin(h + dts);
95                 y += (this->gc().dr() + 0.01) * sin(h);
96         } else {
97 #if FORWARD_PARKING > 0
98                 // Forward parking
99                 double entry_width = edist(
100                         this->ps().x1(), this->ps().y1(),
101                         this->ps().x4(), this->ps().y4()
102                 );
103                 x += entry_width / 2 * cos(h);
104                 y += entry_width / 2 * sin(h);
105                 h = atan2(
106                         this->ps().y2() - this->ps().y1(),
107                         this->ps().x2() - this->ps().x1()
108                 );
109                 while (h < 0) h += 2 * M_PI;
110                 x += 2 * this->gc().dr() * cos(h);
111                 y += 2 * this->gc().dr() * sin(h);
112 #else
113                 // Backward parking
114                 double entry_width = edist(
115                         this->ps().x1(), this->ps().y1(),
116                         this->ps().x4(), this->ps().y4()
117                 );
118                 x += entry_width / 2 * cos(h);
119                 y += entry_width / 2 * sin(h);
120                 h = atan2(
121                         this->ps().y1() - this->ps().y2(),
122                         this->ps().x1() - this->ps().x2()
123                 );
124                 while (h < 0) h += 2 * M_PI;
125                 x += this->gc().df() * cos(h + M_PI);
126                 y += this->gc().df() * sin(h + M_PI);
127 #endif
128         }
129         while (h > M_PI)
130                 h -= 2 * M_PI;
131         while (h <= -M_PI)
132                 h += 2 * M_PI;
133         this->gc().x(x);
134         this->gc().y(y);
135         this->gc().h(h);
136 }
137
138 std::vector<BicycleCar> PSPlanner::last_maneuver()
139 {
140         std::vector<BicycleCar> lm;
141         if (this->ps().parallel()) {
142                 // zig-zag out from the slot
143                 this->cc() = BicycleCar(this->gc());
144                 this->cc().sp(0.1);
145                 lm.push_back(BicycleCar(this->cc()));
146                 while (!this->left()) {
147                         while (!this->collide() && !this->left()) {
148                                 this->cc().next();
149                                 lm.push_back(BicycleCar(this->cc()));
150                         }
151                         if (this->left() && !this->collide()) {
152                                 break;
153                         } else {
154                                 lm.pop_back();
155                                 this->cc().sp(this->cc().sp() * -1);
156                                 this->cc().next();
157                                 this->cc().st(this->cc().st() * -1);
158                                 this->c_++;
159                                 lm.push_back(BicycleCar(this->cc()));
160                         }
161                 }
162                 if (this->cc().st() < 0) {
163                         this->c_++;
164                         lm.push_back(BicycleCar(this->cc()));
165                 }
166         } else {
167                 // go 1 m forward
168                 this->cc().sp(0.1);
169                 BicycleCar orig_cc(this->cc());
170                 for (unsigned int i = 0; i < 10; i++) {
171                         this->cc().next();
172                         lm.push_back(BicycleCar(this->cc()));
173                 }
174                 this->cc() = BicycleCar(orig_cc);
175         }
176         return lm;
177 }
178
179 bool PSPlanner::left()
180 {
181         double lfx = this->cc().lfx();
182         double lfy = this->cc().lfy();
183         double lrx = this->cc().lrx();
184         double lry = this->cc().lry();
185         double rrx = this->cc().rrx();
186         double rry = this->cc().rry();
187         double rfx = this->cc().rfx();
188         double rfy = this->cc().rfy();
189         double lfs = sgn(
190                 (lfx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
191                 - (lfy - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
192         );
193         double lrs = sgn(
194                 (lrx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
195                 - (lry - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
196         );
197         double rrs = sgn(
198                 (rrx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
199                 - (rry - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
200         );
201         double rfs = sgn(
202                 (rfx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
203                 - (rfy - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
204         );
205         if (this->ps().parallel())
206                 return lfs == rfs && (lfs != lrs || lfs != rrs);
207         else if (!this->forward())
208                 return lfs == rfs && (lfs != lrs || lfs != rrs);
209         else
210                 return lrs == rrs && (lrs != lfs || lrs != rfs);
211 }
212
213 bool PSPlanner::parked()
214 {
215         std::vector<std::tuple<double, double>> slot;
216         slot.push_back(std::make_tuple(this->ps().x1(), this->ps().y1()));
217         slot.push_back(std::make_tuple(this->ps().x2(), this->ps().y2()));
218         slot.push_back(std::make_tuple(this->ps().x3(), this->ps().y3()));
219         slot.push_back(std::make_tuple(this->ps().x4(), this->ps().y4()));
220         return inside(this->gc().lfx(), this->gc().lfy(), slot)
221                 && inside(this->gc().lrx(), this->gc().lry(), slot)
222                 && inside(this->gc().rrx(), this->gc().rry(), slot)
223                 && inside(this->gc().rfx(), this->gc().rfy(), slot);
224 }
225
226 std::vector<BicycleCar> PSPlanner::possible_goals(
227         unsigned int cnt,
228         double dist
229 )
230 {
231         std::vector<BicycleCar> pi;
232         if (this->ps().parallel())
233                 this->cc().sp(1);
234         else
235                 this->cc().sp(-1);
236         this->cc().sp(this->cc().sp() * dist);
237         BicycleCar orig_cc(this->cc());
238         for (unsigned int i = 0; i < cnt; i++) {
239                 this->cc().next();
240                 pi.push_back(BicycleCar(this->cc()));
241         }
242         this->cc() = BicycleCar(orig_cc);
243         if (this->ps().parallel()) {
244                 this->cc().st(0);
245                 for (unsigned int i = 0; i < cnt; i++) {
246                         this->cc().next();
247                         pi.push_back(BicycleCar(this->cc()));
248                 }
249                 this->cc() = BicycleCar(orig_cc);
250         } else {
251                 if (!this->ps().right()) {
252                         this->cc().set_max_steer();
253                         for (unsigned int i = 0; i < cnt; i++) {
254                                 this->cc().next();
255                                 pi.push_back(BicycleCar(this->cc()));
256                         }
257                 } else {
258                         this->cc().set_max_steer();
259                         this->cc().st(this->cc().st() * -1);
260                         for (unsigned int i = 0; i < cnt; i++) {
261                                 this->cc().next();
262                                 pi.push_back(BicycleCar(this->cc()));
263                         }
264                 }
265                 this->cc() = BicycleCar(orig_cc);
266         }
267         return pi;
268 }
269
270 void PSPlanner::shrink_to_perfect_len()
271 {
272         if (!this->ps().parallel())
273                 return;
274         double perfect_len = this->gc().perfect_parking_slot_len();
275         if (edist(
276                 this->ps().x1(), this->ps().y1(),
277                 this->ps().x4(), this->ps().y4()
278         ) < perfect_len)
279                 return;
280         double h = this->ps().heading();
281         h -= M_PI;
282         while (h < 0) h += 2 * M_PI;
283         double ch = perfect_len * cos(h);
284         double sh = perfect_len * sin(h);
285         this->ps().border(
286                 this->ps().x4() + ch, this->ps().y4() + sh,
287                 this->ps().x3() + ch, this->ps().y3() + sh,
288                 this->ps().x3(), this->ps().y3(),
289                 this->ps().x4(), this->ps().y4()
290         );
291 }
292
293 // find entry
294 void PSPlanner::fe()
295 {
296         this->c_ = 0;
297         if (this->ps().parallel()) {
298                 return this->fe_parallel();
299         } else {
300                 this->guess_gc();
301                 this->cc() = BicycleCar(this->gc());
302                 //this->cc().set_max_steer();
303                 //if (this->ps().right())
304                 //        this->cc().st(this->cc().st() * -1);
305                 this->cc().sp(-0.2);
306         }
307 }
308
309 double angle_between_closer_point(
310         double sx, double sy, // common start point
311         double cx, double cy, // common middle point
312         double x1, double y1, // first ending point
313         double x2, double y2 // second ending point
314 ) {
315         if (edist(sx, sy, x1, y1) < edist(sx, sy, x2, y2))
316                 return ::angle_between_three_points(sx, sy, cx, cy, x1, y1);
317         else
318                 return ::angle_between_three_points(sx, sy, cx, cy, x2, y2);
319 }
320
321 void PSPlanner::fe_parallel()
322 {
323         this->shrink_to_perfect_len();
324         BicycleCar bco = BicycleCar(this->gc());
325         this->cc() = BicycleCar();
326         this->cc().sp(-0.01);
327         this->cc().set_max_steer();
328         if (!this->ps().right())
329                 this->cc().st(this->cc().st() * -1);
330         this->cc().h(this->ps().heading());
331         double angl_in_slot = this->ps().heading() - M_PI / 4;
332         if (!this->ps().right())
333                 angl_in_slot += M_PI / 2;
334         this->cc().x(
335                 this->ps().x4()
336                 + this->cc().w()/2 * cos(
337                         this->ps().heading()
338                         + (this->ps().right() ? + M_PI / 2 : - M_PI / 2)
339                 )
340                 + (this->cc().df() + 0.01) * cos(
341                         this->ps().heading() + M_PI
342                 )
343         );
344         this->cc().y(
345                 this->ps().y4()
346                 + this->cc().w()/2 * sin(
347                         this->ps().heading()
348                         + (this->ps().right() ? + M_PI / 2 : - M_PI / 2)
349                 )
350                 + (this->cc().df() + 0.01) * sin(
351                         this->ps().heading() + M_PI
352                 )
353         );
354
355         std::queue<BicycleCar, std::list<BicycleCar>> q;
356         while (!this->collide()) {
357                 q.push(this->cc());
358                 this->cc().rotate(
359                         this->ps().x4(),
360                         this->ps().y4() - 0.01,
361                         ((this->ps().right()) ? 0.001 : -0.001)
362                 );
363         }
364         // BFS - find entry current car `cc` and corresponding goal car `gc`
365         unsigned int iter_cntr = 0;
366         while (!q.empty() && iter_cntr < 30) {
367                 this->cc() = BicycleCar(q.front());
368                 q.pop();
369                 if (this->ps().right() && this->cc().sp() < 0) {
370                         double cclx = this->cc().ccl().x();
371                         double ccly = this->cc().ccl().y();
372                         double ccl_lr = edist(
373                                 cclx, ccly,
374                                 this->cc().lrx(), this->cc().lry()
375                         );
376                         double ccl_rr = edist(
377                                 cclx, ccly,
378                                 this->cc().rrx(), this->cc().rry()
379                         );
380                         double ccl_p1 = edist(
381                                 cclx, ccly,
382                                 this->ps().x1(), this->ps().y1()
383                         );
384                         if (ccl_rr < ccl_p1) {
385                                 // pass parking slot
386                                 continue;
387                         } else if (ccl_rr >= ccl_p1 && ccl_lr < ccl_p1) {
388                                 // partially out of parking slot
389                                 auto cli1 = ::intersect(
390                                         cclx, ccly, ccl_p1,
391                                         this->cc().lrx(), this->cc().lry(),
392                                         this->cc().rrx(), this->cc().rry()
393                                 );
394                                 double a1 = ::angle_between_closer_point(
395                                         this->ps().x1(), this->ps().y1(),
396                                         cclx, ccly,
397                                         std::get<1>(cli1), std::get<2>(cli1),
398                                         std::get<3>(cli1), std::get<4>(cli1)
399                                 );
400                                 auto cli2 = ::intersect(
401                                         cclx, ccly, ccl_rr,
402                                         this->ps().x2(), this->ps().y2(),
403                                         this->ps().x3(), this->ps().y3()
404                                 );
405                                 double a2 = angle_between_closer_point(
406                                         this->cc().rrx(), this->cc().rry(),
407                                         cclx, ccly,
408                                         std::get<1>(cli2), std::get<2>(cli2),
409                                         std::get<3>(cli2), std::get<4>(cli2)
410                                 );
411                                 if (std::get<0>(cli1) && (
412                                         !std::get<0>(cli2)
413                                         || a1 < a2
414                                 )) {
415                                         this->cc().rotate(cclx, ccly, -a1);
416                                         if (::right_side_of_line(
417                                                 this->cc().x(), this->cc().y(),
418
419                                                 this->cc().x()
420                                                 + cos(this->ps().heading()),
421                                                 this->cc().y()
422                                                 + sin(this->ps().heading()),
423
424                                                 this->cc().x()
425                                                 + cos(this->cc().h()),
426                                                 this->cc().y()
427                                                 + sin(this->cc().h())
428                                         )) {
429                                                 continue;
430                                         }
431                                 } else if (std::get<0>(cli2) && (
432                                         !std::get<0>(cli1)
433                                         || a2 < a1
434                                 )) {
435                                         this->cc().rotate(cclx, ccly, -a2);
436                                 } else {
437                                         continue;
438                                 }
439                         } else if (ccl_lr >= ccl_p1) {
440                                 // in parking slot
441                                 auto cli1 = ::intersect(
442                                         cclx, ccly, ccl_lr,
443                                         this->ps().x1(), this->ps().y1(),
444                                         this->ps().x2(), this->ps().y2()
445                                 );
446                                 double a1 = angle_between_closer_point(
447                                         this->cc().lrx(), this->cc().lry(),
448                                         cclx, ccly,
449                                         std::get<1>(cli1), std::get<2>(cli1),
450                                         std::get<3>(cli1), std::get<4>(cli1)
451                                 );
452                                 auto cli2 = ::intersect(
453                                         cclx, ccly, ccl_rr,
454                                         this->ps().x2(), this->ps().y2(),
455                                         this->ps().x3(), this->ps().y3()
456                                 );
457                                 double a2 = angle_between_closer_point(
458                                         this->cc().rrx(), this->cc().rry(),
459                                         cclx, ccly,
460                                         std::get<1>(cli2), std::get<2>(cli2),
461                                         std::get<3>(cli2), std::get<4>(cli2)
462                                 );
463                                 if (std::get<0>(cli1) && (
464                                         !std::get<0>(cli2)
465                                         || a1 < a2
466                                 )) {
467                                         this->cc().rotate(cclx, ccly, -a1);
468                                         if (::right_side_of_line(
469                                                 this->cc().x(), this->cc().y(),
470
471                                                 this->cc().x()
472                                                 + cos(this->ps().heading()),
473                                                 this->cc().y()
474                                                 + sin(this->ps().heading()),
475
476                                                 this->cc().x()
477                                                 + cos(this->cc().h()),
478                                                 this->cc().y()
479                                                 + sin(this->cc().h())
480                                         )) {
481                                                 continue;
482                                         }
483                                 } else if (std::get<0>(cli2) && (
484                                         !std::get<0>(cli1)
485                                         || a2 < a1
486                                 )) {
487                                         this->cc().rotate(cclx, ccly, -a2);
488                                 } else {
489                                         continue;
490                                 }
491                         }
492                 } else if (this->ps().right() && this->cc().sp() > 0) {
493                         double ccrx = this->cc().ccr().x();
494                         double ccry = this->cc().ccr().y();
495                         double ccr_lf = edist(
496                                 ccrx, ccry,
497                                 this->cc().lfx(), this->cc().lfy()
498                         );
499                         double ccr_rf = edist(
500                                 ccrx, ccry,
501                                 this->cc().rfx(), this->cc().rfy()
502                         );
503                         {
504                                 double af = std::abs(
505                                         this->ps().heading()
506                                         - this->cc().h()
507                                 );
508                                 auto tmp_cc = BicycleCar(this->cc());
509                                 this->cc().rotate(ccrx, ccry, -af);
510                                 this->gc() = BicycleCar(this->cc());
511                                 if (
512                                         !this->collide()
513                                         && this->parked()
514                                 ) {
515                                         this->cc().sp(this->cc().sp() * -1);
516                                         this->gc() = BicycleCar(this->cc());
517                                         goto successfinish;
518                                 } else {
519                                         this->cc() = BicycleCar(tmp_cc);
520                                 }
521                         }
522                         auto cli1 = ::intersect(
523                                 ccrx, ccry, ccr_rf,
524                                 this->ps().x3(), this->ps().y3(),
525                                 this->ps().x4(), this->ps().y4()
526                         );
527                         double a1 = angle_between_closer_point(
528                                 this->cc().rfx(), this->cc().rfy(),
529                                 ccrx, ccry,
530                                 std::get<1>(cli1), std::get<2>(cli1),
531                                 std::get<3>(cli1), std::get<4>(cli1)
532                         );
533                         auto cli2 = ::intersect(
534                                 ccrx, ccry, ccr_rf,
535                                 this->ps().x2(), this->ps().y2(),
536                                 this->ps().x3(), this->ps().y3()
537                         );
538                         double a2 = angle_between_closer_point(
539                                 this->cc().rfx(), this->cc().rfy(),
540                                 ccrx, ccry,
541                                 std::get<1>(cli2), std::get<2>(cli2),
542                                 std::get<3>(cli2), std::get<4>(cli2)
543                         );
544                         auto cli3 = ::intersect(
545                                 ccrx, ccry, ccr_lf,
546                                 this->ps().x3(), this->ps().y3(),
547                                 this->ps().x4(), this->ps().y4()
548                         );
549                         double a3 = angle_between_closer_point(
550                                 this->cc().lfx(), this->cc().lfy(),
551                                 ccrx, ccry,
552                                 std::get<1>(cli3), std::get<2>(cli3),
553                                 std::get<3>(cli3), std::get<4>(cli3)
554                         );
555                         if (std::get<0>(cli1) && (
556                             (!std::get<0>(cli2) && !std::get<0>(cli3))
557                             || (a1 < a2 && !std::get<0>(cli3))
558                             || (a1 < a3 && !std::get<0>(cli2))
559                             || (a1 < a2 && a1 < a3)
560                         )) {
561                             this->cc().rotate(ccrx, ccry, -a1);
562                         } else if (std::get<0>(cli2) && (
563                             (!std::get<0>(cli1) && !std::get<0>(cli3))
564                             || (a2 < a1 && !std::get<0>(cli3))
565                             || (a2 < a3 && !std::get<0>(cli1))
566                             || (a2 < a1 && a2 < a3)
567                         )) {
568                             this->cc().rotate(ccrx, ccry, -a2);
569                         } else if (std::get<0>(cli3) && (
570                             (!std::get<0>(cli1) && !std::get<0>(cli2))
571                             || (a3 < a1 && !std::get<0>(cli2))
572                             || (a3 < a2 && !std::get<0>(cli1))
573                             || (a3 < a1 && a3 < a2)
574                         )) {
575                             this->cc().rotate(ccrx, ccry, -a3);
576                         } else {
577                             continue;
578                         }
579                 } else if (!this->ps().right() && this->cc().sp() < 0) {
580                         double ccrx = this->cc().ccr().x();
581                         double ccry = this->cc().ccr().y();
582                         double ccr_rr = edist(
583                                 ccrx, ccry,
584                                 this->cc().rrx(), this->cc().rry()
585                         );
586                         double ccr_lr = edist(
587                                 ccrx, ccry,
588                                 this->cc().lrx(), this->cc().lry()
589                         );
590                         double ccr_p1 = edist(
591                                 ccrx, ccry,
592                                 this->ps().x1(), this->ps().y1()
593                         );
594                         if (ccr_lr < ccr_p1) {
595                                 // pass parking slot
596                                 continue;
597                         } else if (ccr_lr >= ccr_p1 && ccr_rr < ccr_p1) {
598                                 // partially out of parking slot
599                                 auto cli1 = ::intersect(
600                                         ccrx, ccry, ccr_p1,
601                                         this->cc().lrx(), this->cc().lry(),
602                                         this->cc().rrx(), this->cc().rry()
603                                 );
604                                 double a1 = ::angle_between_closer_point(
605                                         this->ps().x1(), this->ps().y1(),
606                                         ccrx, ccry,
607                                         std::get<1>(cli1), std::get<2>(cli1),
608                                         std::get<3>(cli1), std::get<4>(cli1)
609                                 );
610                                 auto cli2 = ::intersect(
611                                         ccrx, ccry, ccr_lr,
612                                         this->ps().x2(), this->ps().y2(),
613                                         this->ps().x3(), this->ps().y3()
614                                 );
615                                 double a2 = angle_between_closer_point(
616                                         this->cc().lrx(), this->cc().lry(),
617                                         ccrx, ccry,
618                                         std::get<1>(cli2), std::get<2>(cli2),
619                                         std::get<3>(cli2), std::get<4>(cli2)
620                                 );
621                                 if (std::get<0>(cli1) && (
622                                         !std::get<0>(cli2)
623                                         || a1 < a2
624                                 )) {
625                                         this->cc().rotate(ccrx, ccry, a1);
626                                         if (!::right_side_of_line(
627                                                 this->cc().x(), this->cc().y(),
628
629                                                 this->cc().x()
630                                                 + cos(this->ps().heading()),
631                                                 this->cc().y()
632                                                 + sin(this->ps().heading()),
633
634                                                 this->cc().x()
635                                                 + cos(this->cc().h()),
636                                                 this->cc().y()
637                                                 + sin(this->cc().h())
638                                         )) {
639                                                 continue;
640                                         }
641                                 } else if (std::get<0>(cli2) && (
642                                         !std::get<0>(cli1)
643                                         || a2 < a1
644                                 )) {
645                                         this->cc().rotate(ccrx, ccry, a2);
646                                 } else {
647                                         continue;
648                                 }
649                         } else if (ccr_rr >= ccr_p1) {
650                                 // in parking slot
651                                 auto cli1 = ::intersect(
652                                         ccrx, ccry, ccr_rr,
653                                         this->ps().x1(), this->ps().y1(),
654                                         this->ps().x2(), this->ps().y2()
655                                 );
656                                 double a1 = angle_between_closer_point(
657                                         this->cc().rrx(), this->cc().rry(),
658                                         ccrx, ccry,
659                                         std::get<1>(cli1), std::get<2>(cli1),
660                                         std::get<3>(cli1), std::get<4>(cli1)
661                                 );
662                                 auto cli2 = ::intersect(
663                                         ccrx, ccry, ccr_lr,
664                                         this->ps().x2(), this->ps().y2(),
665                                         this->ps().x3(), this->ps().y3()
666                                 );
667                                 double a2 = angle_between_closer_point(
668                                         this->cc().lrx(), this->cc().lry(),
669                                         ccrx, ccry,
670                                         std::get<1>(cli2), std::get<2>(cli2),
671                                         std::get<3>(cli2), std::get<4>(cli2)
672                                 );
673                                 if (std::get<0>(cli1) && (
674                                         !std::get<0>(cli2)
675                                         || a1 < a2
676                                 )) {
677                                         this->cc().rotate(ccrx, ccry, a1);
678                                         if (!::right_side_of_line(
679                                                 this->cc().x(), this->cc().y(),
680
681                                                 this->cc().x()
682                                                 + cos(this->ps().heading()),
683                                                 this->cc().y()
684                                                 + sin(this->ps().heading()),
685
686                                                 this->cc().x()
687                                                 + cos(this->cc().h()),
688                                                 this->cc().y()
689                                                 + sin(this->cc().h())
690                                         )) {
691                                                 continue;
692                                         }
693                                 } else if (std::get<0>(cli2) && (
694                                         !std::get<0>(cli1)
695                                         || a2 < a1
696                                 )) {
697                                         this->cc().rotate(ccrx, ccry, a2);
698                                 } else {
699                                         continue;
700                                 }
701                         }
702                 } else if (!this->ps().right() && this->cc().sp() > 0) {
703                         double cclx = this->cc().ccl().x();
704                         double ccly = this->cc().ccl().y();
705                         double ccl_rf = edist(
706                                 cclx, ccly,
707                                 this->cc().rfx(), this->cc().rfy()
708                         );
709                         double ccl_lf = edist(
710                                 cclx, ccly,
711                                 this->cc().lfx(), this->cc().lfy()
712                         );
713                         {
714                                 double af = std::abs(
715                                         this->ps().heading()
716                                         - this->cc().h()
717                                 );
718                                 auto tmp_cc = BicycleCar(this->cc());
719                                 this->cc().rotate(cclx, ccly, af);
720                                 this->gc() = BicycleCar(this->cc());
721                                 if (
722                                         !this->collide()
723                                         && this->parked()
724                                 ) {
725                                         this->cc().sp(this->cc().sp() * -1);
726                                         this->gc() = BicycleCar(this->cc());
727                                         goto successfinish;
728                                 } else {
729                                         this->cc() = BicycleCar(tmp_cc);
730                                 }
731                         }
732                         auto cli1 = ::intersect(
733                                 cclx, ccly, ccl_lf,
734                                 this->ps().x3(), this->ps().y3(),
735                                 this->ps().x4(), this->ps().y4()
736                         );
737                         double a1 = angle_between_closer_point(
738                                 this->cc().lfx(), this->cc().lfy(),
739                                 cclx, ccly,
740                                 std::get<1>(cli1), std::get<2>(cli1),
741                                 std::get<3>(cli1), std::get<4>(cli1)
742                         );
743                         auto cli2 = ::intersect(
744                                 cclx, ccly, ccl_lf,
745                                 this->ps().x2(), this->ps().y2(),
746                                 this->ps().x3(), this->ps().y3()
747                         );
748                         double a2 = angle_between_closer_point(
749                                 this->cc().lfx(), this->cc().lfy(),
750                                 cclx, ccly,
751                                 std::get<1>(cli2), std::get<2>(cli2),
752                                 std::get<3>(cli2), std::get<4>(cli2)
753                         );
754                         auto cli3 = ::intersect(
755                                 cclx, ccly, ccl_rf,
756                                 this->ps().x3(), this->ps().y3(),
757                                 this->ps().x4(), this->ps().y4()
758                         );
759                         double a3 = angle_between_closer_point(
760                                 this->cc().rfx(), this->cc().rfy(),
761                                 cclx, ccly,
762                                 std::get<1>(cli3), std::get<2>(cli3),
763                                 std::get<3>(cli3), std::get<4>(cli3)
764                         );
765                         if (std::get<0>(cli1) && (
766                             (!std::get<0>(cli2) && !std::get<0>(cli3))
767                             || (a1 < a2 && !std::get<0>(cli3))
768                             || (a1 < a3 && !std::get<0>(cli2))
769                             || (a1 < a2 && a1 < a3)
770                         )) {
771                             this->cc().rotate(cclx, ccly, a1);
772                         } else if (std::get<0>(cli2) && (
773                             (!std::get<0>(cli1) && !std::get<0>(cli3))
774                             || (a2 < a1 && !std::get<0>(cli3))
775                             || (a2 < a3 && !std::get<0>(cli1))
776                             || (a2 < a1 && a2 < a3)
777                         )) {
778                             this->cc().rotate(cclx, ccly, a2);
779                         } else if (std::get<0>(cli3) && (
780                             (!std::get<0>(cli1) && !std::get<0>(cli2))
781                             || (a3 < a1 && !std::get<0>(cli2))
782                             || (a3 < a2 && !std::get<0>(cli1))
783                             || (a3 < a1 && a3 < a2)
784                         )) {
785                             this->cc().rotate(cclx, ccly, a3);
786                         } else {
787                             continue;
788                         }
789                 } else {
790                         // TODO left parking slot (both forward, backward)
791                 }
792                 this->cc().sp(this->cc().sp() * -1);
793                 this->cc().next();
794                 this->gc() = BicycleCar(this->cc());
795                 if (this->parked())
796                         goto successfinish;
797                 this->cc().st(this->cc().st() * -1);
798                 q.push(BicycleCar(this->cc()));
799                 if (sgn(this->cc().st()) == sgn(q.front().st()))
800                         iter_cntr++;
801         }
802         // fallback to fer
803         this->gc() = BicycleCar(bco);
804 successfinish:
805         return this->fer_parallel();
806 }
807
808 void PSPlanner::fe_perpendicular()
809 {
810         // TODO Try multiple angles when going from parking slot.
811         //
812         //      Do not use just the maximum steer angle. Test angles
813         //      until the whole current car `cc` is out of the parking
814         //      slot `ps`.
815         //
816         //      Another approach could be testing angles from the
817         //      beginning of the escape parkig slot maneuver.
818         if (this->forward())
819                 this->cc().sp(-0.01);
820         else
821                 this->cc().sp(0.01);
822         while (!this->left())
823                 this->cc().next();
824         return;
825 }
826
827 void PSPlanner::fer()
828 {
829         this->c_ = 0;
830         if (this->ps().parallel()) {
831                 this->guess_gc();
832                 this->cc() = BicycleCar(this->gc());
833                 this->cc().set_max_steer();
834                 if (!this->ps().right())
835                         this->cc().st(this->cc().st() * -1);
836                 this->cc().sp(0.01);
837                 return this->fer_parallel();
838         } else {
839                 return this->fer_perpendicular();
840         }
841 }
842
843 void PSPlanner::fer_parallel()
844 {
845         this->cusps_.clear();
846         while (!this->left()) {
847                 while (!this->collide() && !this->left())
848                         this->cc().next();
849                 if (this->left() && !this->collide()) {
850                         break;
851                 } else {
852                         this->cc().sp(this->cc().sp() * -1);
853                         this->cc().next();
854                         this->cc().st(this->cc().st() * -1);
855                         this->c_++;
856                         this->cusps_.push_back(this->cc());
857                 }
858         }
859         if (this->cc().st() < 0) {
860                 this->c_++;
861                 this->cusps_.push_back(this->cc());
862         }
863 }
864
865 void PSPlanner::fer_perpendicular()
866 {
867         bool delta_use[] = {true, true, true};
868         double cc_h = this->cc().h();
869         double x;
870         double y;
871         // check inner radius
872         if (this->forward()) {
873                 x = this->ps().x1();
874                 y = this->ps().y1();
875         } else {
876                 x = this->ps().x4();
877                 y = this->ps().y4();
878         }
879         double x1;
880         double y1;
881         if (this->ps().right()) {
882                 x1 = this->cc().ccr().x();
883                 y1 = this->cc().ccr().y();
884         } else {
885                 x1 = this->cc().ccl().x();
886                 y1 = this->cc().ccl().y();
887         }
888         double IR = this->cc().iradi();
889         double a = 1;
890         double b;
891         if (this->forward())
892                 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
893         else
894                 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
895         double c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
896         double D = pow(b, 2) - 4 * a * c;
897         double delta;
898         delta = -b - sqrt(D);
899         delta /= 2 * a;
900         double delta_1 = delta;
901         if (D < 0)
902                 delta_use[0] = false;
903         // check outer radius
904         if (this->forward()) {
905                 x = this->ps().x4();
906                 y = this->ps().y4();
907         } else {
908                 x = this->ps().x1();
909                 y = this->ps().y1();
910         }
911         IR = this->cc().ofradi();
912         a = 1;
913         if (this->forward())
914                 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
915         else
916                 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
917         c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
918         D = pow(b, 2) - 4 * a * c;
919         if (this->forward()) {
920                 delta = -b + sqrt(D);
921                 delta /= 2 * a;
922         }
923         double delta_2 = delta;
924         if (D < 0)
925                 delta_use[1] = false;
926         delta = -b - sqrt(D);
927         delta /= 2 * a;
928         double delta_3 = delta;
929         if (D < 0)
930                 delta_use[2] = false;
931         if (delta_use[0] && delta_use[1] && delta_use[2])
932                 delta = std::max(delta_1, std::max(delta_2, delta_3));
933         else if (delta_use[0] && delta_use[1])
934                 delta = std::max(delta_1, delta_2);
935         else if (delta_use[0] && delta_use[2])
936                 delta = std::max(delta_1, delta_3);
937         else if (delta_use[1] && delta_use[2])
938                 delta = std::max(delta_2, delta_3);
939         else if (delta_use[0])
940                 delta = delta_1;
941         else if (delta_use[1])
942                 delta = delta_2;
943         else if (delta_use[2])
944                 delta = delta_3;
945         else
946                 return;
947         // current car `cc` can get out of slot with max steer
948         this->cc().x(this->cc().x() + delta * cos(cc_h));
949         this->cc().y(this->cc().y() + delta * sin(cc_h));
950         this->cc().h(cc_h);
951         // get current car `cc` out of slot
952         if (this->forward())
953                 this->cc().sp(-0.01);
954         else
955                 this->cc().sp(0.01);
956         this->cc().set_max_steer();
957         if (this->ps().right())
958                 this->cc().st(this->cc().st() * -1);
959         while (!this->left()) {
960                 while (!this->collide() && !this->left())
961                         this->cc().next();
962                 if (this->left() && !this->collide()) {
963                         break;
964                 } else {
965                         this->cc().sp(this->cc().sp() * -1);
966                         this->cc().next();
967                         this->cc().st(this->cc().st() * -1);
968                 }
969         }
970 }
971
972 PSPlanner::PSPlanner()
973 {
974 }