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