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