]> rtime.felk.cvut.cz Git - hubacji1/psp.git/blob - src/psp.cc
Merge branch 'backward-perpendicular-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 {
555                         // TODO left parking slot (both forward, backward)
556                 }
557                 this->cc().sp(this->cc().sp() * -1);
558                 this->cc().next();
559                 this->gc() = BicycleCar(this->cc());
560                 if (this->parked())
561                         goto successfinish;
562                 this->cc().st(this->cc().st() * -1);
563                 q.push(BicycleCar(this->cc()));
564                 if (sgn(this->cc().st()) == sgn(q.front().st()))
565                         iter_cntr++;
566         }
567         // fallback to fer
568         this->gc() = BicycleCar(bco);
569 successfinish:
570         return this->fer_parallel();
571 }
572
573 void PSPlanner::fe_perpendicular()
574 {
575         // TODO Try multiple angles when going from parking slot.
576         //
577         //      Do not use just the maximum steer angle. Test angles
578         //      until the whole current car `cc` is out of the parking
579         //      slot `ps`.
580         //
581         //      Another approach could be testing angles from the
582         //      beginning of the escape parkig slot maneuver.
583         if (this->forward())
584                 this->cc().sp(-0.01);
585         else
586                 this->cc().sp(0.01);
587         while (!this->left())
588                 this->cc().next();
589         return;
590 }
591
592 void PSPlanner::fer()
593 {
594         this->c_ = 0;
595         if (this->ps().parallel()) {
596                 this->guess_gc();
597                 this->cc() = BicycleCar(this->gc());
598                 this->cc().set_max_steer();
599                 if (!this->ps().right())
600                         this->cc().st(this->cc().st() * -1);
601                 this->cc().sp(0.01);
602                 return this->fer_parallel();
603         } else {
604                 return this->fer_perpendicular();
605         }
606 }
607
608 void PSPlanner::fer_parallel()
609 {
610         this->cusps_.clear();
611         while (!this->left()) {
612                 while (!this->collide() && !this->left())
613                         this->cc().next();
614                 if (this->left() && !this->collide()) {
615                         break;
616                 } else {
617                         this->cc().sp(this->cc().sp() * -1);
618                         this->cc().next();
619                         this->cc().st(this->cc().st() * -1);
620                         this->c_++;
621                         this->cusps_.push_back(this->cc());
622                 }
623         }
624         if (this->cc().st() < 0) {
625                 this->c_++;
626                 this->cusps_.push_back(this->cc());
627         }
628 }
629
630 void PSPlanner::fer_perpendicular()
631 {
632         bool delta_use[] = {true, true, true};
633         double cc_h = this->cc().h();
634         double x;
635         double y;
636         // check inner radius
637         if (this->forward()) {
638                 x = this->ps().x1();
639                 y = this->ps().y1();
640         } else {
641                 x = this->ps().x4();
642                 y = this->ps().y4();
643         }
644         double x1;
645         double y1;
646         if (this->ps().right()) {
647                 x1 = this->cc().ccr().x();
648                 y1 = this->cc().ccr().y();
649         } else {
650                 x1 = this->cc().ccl().x();
651                 y1 = this->cc().ccl().y();
652         }
653         double IR = this->cc().iradi();
654         double a = 1;
655         double b;
656         if (this->forward())
657                 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
658         else
659                 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
660         double c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
661         double D = pow(b, 2) - 4 * a * c;
662         double delta;
663         delta = -b - sqrt(D);
664         delta /= 2 * a;
665         double delta_1 = delta;
666         if (D < 0)
667                 delta_use[0] = false;
668         // check outer radius
669         if (this->forward()) {
670                 x = this->ps().x4();
671                 y = this->ps().y4();
672         } else {
673                 x = this->ps().x1();
674                 y = this->ps().y1();
675         }
676         IR = this->cc().ofradi();
677         a = 1;
678         if (this->forward())
679                 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
680         else
681                 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
682         c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
683         D = pow(b, 2) - 4 * a * c;
684         if (this->forward()) {
685                 delta = -b + sqrt(D);
686                 delta /= 2 * a;
687         }
688         double delta_2 = delta;
689         if (D < 0)
690                 delta_use[1] = false;
691         delta = -b - sqrt(D);
692         delta /= 2 * a;
693         double delta_3 = delta;
694         if (D < 0)
695                 delta_use[2] = false;
696         if (delta_use[0] && delta_use[1] && delta_use[2])
697                 delta = std::max(delta_1, std::max(delta_2, delta_3));
698         else if (delta_use[0] && delta_use[1])
699                 delta = std::max(delta_1, delta_2);
700         else if (delta_use[0] && delta_use[2])
701                 delta = std::max(delta_1, delta_3);
702         else if (delta_use[1] && delta_use[2])
703                 delta = std::max(delta_2, delta_3);
704         else if (delta_use[0])
705                 delta = delta_1;
706         else if (delta_use[1])
707                 delta = delta_2;
708         else if (delta_use[2])
709                 delta = delta_3;
710         else
711                 return;
712         // current car `cc` can get out of slot with max steer
713         this->cc().x(this->cc().x() + delta * cos(cc_h));
714         this->cc().y(this->cc().y() + delta * sin(cc_h));
715         this->cc().h(cc_h);
716         // get current car `cc` out of slot
717         if (this->forward())
718                 this->cc().sp(-0.01);
719         else
720                 this->cc().sp(0.01);
721         this->cc().set_max_steer();
722         if (this->ps().right())
723                 this->cc().st(this->cc().st() * -1);
724         while (!this->left()) {
725                 while (!this->collide() && !this->left())
726                         this->cc().next();
727                 if (this->left() && !this->collide()) {
728                         break;
729                 } else {
730                         this->cc().sp(this->cc().sp() * -1);
731                         this->cc().next();
732                         this->cc().st(this->cc().st() * -1);
733                 }
734         }
735 }
736
737 PSPlanner::PSPlanner()
738 {
739 }