]> rtime.felk.cvut.cz Git - hubacji1/psp.git/blob - src/psp.cc
Add more possible goals for perpendicular slot
[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 (this->ps().parallel())
25                 return false;
26         else
27                 return true;
28         double heading = atan2(
29                 this->ps().y2() - this->ps().y1(),
30                 this->ps().x2() - this->ps().x1()
31         );
32         while (heading < 0) heading += 2 * M_PI;
33         double h = this->gc().h();
34         while (h < 0) h += 2 * M_PI;
35         if (std::abs(heading - h) < M_PI / 4)
36                 return true;
37         return false;
38 }
39
40 void PSPlanner::gc_to_4()
41 {
42         double angl_slot = atan2(
43                 this->ps().y3() - this->ps().y4(),
44                 this->ps().x3() - this->ps().x4()
45         );
46         double angl_delta = M_PI / 2;
47         if (this->ps().right())
48                 angl_delta = -M_PI / 2;
49         double x = this->ps().x4();
50         double y = this->ps().y4();
51         x += (this->gc().dr() + 0.01) * cos(angl_slot);
52         y += (this->gc().dr() + 0.01) * sin(angl_slot);
53         x += (this->gc().w() / 2 + 0.01) * cos(angl_slot + angl_delta);
54         y += (this->gc().w() / 2 + 0.01) * sin(angl_slot + angl_delta);
55         this->gc().x(x);
56         this->gc().y(y);
57         this->gc().h(angl_slot);
58 }
59
60 std::tuple<double, double, double, double> circle_line_intersection(
61         double cx, double cy, double r,
62         double x1, double y1,
63         double x2, double y2
64 )
65 {
66         double t = (y2 - y1) / (x2 - x1);
67         //double a = 1 + pow(t, 2);
68         //double b = - 2 * cx - 2 * pow(t, 2) * x1 + 2 * t * y1 - 2 * t * cy;
69         //double c = pow(cx, 2) + pow(t, 2) * pow(x1, 2) - 2 * t * y1 * x1
70         //        + pow(y1, 2) + 2 * t * cy * x1 - 2 * y1 * cy + pow(cy, 2)
71         //        - pow(r, 2);
72         double a = 1 + pow(t, 2);
73         double b = - 2 * cx + 2 * t * (-t * x1 + y1) - 2 * cy * t;
74         double c = pow(cx, 2) + pow(cy, 2) - pow(r, 2);
75         c += pow(-t * x1 + y1, 2);
76         c += 2 * cy * t * x1 - 2 * cy * y1;
77         double D = pow(b, 2) - 4 * a * c;
78         if (D < 0)
79                 return std::make_tuple(cx, cy, cx, cy);
80         double res_x1 = (-b + sqrt(D)) / (2 * a);
81         double res_y1 = t * (res_x1 - x1) + y1;
82         double res_x2 = (-b - sqrt(D)) / (2 * a);
83         double res_y2 = t * (res_x2 - x1) + y1;
84         return std::make_tuple(res_x1, res_y1, res_x2, res_y2);
85 }
86
87 double edist(double x1, double y1, double x2, double y2)
88 {
89         return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
90 }
91
92 void PSPlanner::guess_gc()
93 {
94         double x = this->ps().x1();
95         double y = this->ps().y1();
96         double h = this->ps().heading();
97         double dts = + M_PI / 2; // direction to slot
98         if (this->ps().right())
99                 dts = - M_PI / 2;
100         if (this->ps().parallel()) {
101                 x += (this->gc().w() / 2 + 0.01) * cos(h + dts);
102                 x += (this->gc().dr() + 0.01) * cos(h);
103                 y += (this->gc().w() / 2 + 0.01) * sin(h + dts);
104                 y += (this->gc().dr() + 0.01) * sin(h);
105         } else {
106                 // Forward parking
107                 double entry_width = edist(
108                         this->ps().x1(), this->ps().y1(),
109                         this->ps().x4(), this->ps().y4()
110                 );
111                 x += entry_width / 2 * cos(h);
112                 y += entry_width / 2 * sin(h);
113                 h = atan2(
114                         this->ps().y2() - this->ps().y1(),
115                         this->ps().x2() - this->ps().x1()
116                 );
117                 while (h < 0) h += 2 * M_PI;
118
119                 //// This is for backward parking only.
120                 //double entry_width = edist(
121                 //        this->ps().x1(), this->ps().y1(),
122                 //        this->ps().x4(), this->ps().y4()
123                 //);
124                 //double dist_l =
125                 //        this->gc().orradi()
126                 //        - (this->gc().mtr() + this->gc().w() / 2)
127                 //;
128                 //double move1 = dist_l + this->gc().w() / 2;
129                 //double dist_r = entry_width - this->gc().w() - dist_l;
130                 //double move2 = sqrt(
131                 //        pow(this->gc().iradi(), 2)
132                 //        - pow(this->gc().iradi() - dist_r, 2)
133                 //);
134                 //move2 -= this->gc().dr() / 2; // workaround
135                 //x += move1 * cos(h);
136                 //y += move1 * sin(h);
137                 //dts = atan2(
138                 //        this->ps().y2() - this->ps().y1(),
139                 //        this->ps().x2() - this->ps().x1()
140                 //);
141                 //while (dts < 0) dts += 2 * M_PI;
142                 //x += move2 * cos(h + dts);
143                 //y += move2 * sin(h + dts);
144                 //h += dts - M_PI / 2;
145         }
146         while (h > M_PI)
147                 h -= 2 * M_PI;
148         while (h <= -M_PI)
149                 h += 2 * M_PI;
150         this->gc().x(x);
151         this->gc().y(y);
152         this->gc().h(h);
153 }
154
155 bool PSPlanner::left()
156 {
157         double lfx = this->cc().lfx();
158         double lfy = this->cc().lfy();
159         double lrx = this->cc().lrx();
160         double lry = this->cc().lry();
161         double rrx = this->cc().rrx();
162         double rry = this->cc().rry();
163         double rfx = this->cc().rfx();
164         double rfy = this->cc().rfy();
165         double lfs = sgn(
166                 (lfx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
167                 - (lfy - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
168         );
169         double lrs = sgn(
170                 (lrx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
171                 - (lry - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
172         );
173         double rrs = sgn(
174                 (rrx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
175                 - (rry - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
176         );
177         double rfs = sgn(
178                 (rfx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
179                 - (rfy - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
180         );
181         if (this->ps().parallel())
182                 return lfs == rfs && (lfs != lrs || lfs != rrs);
183         else if (!this->forward())
184                 return lfs == rfs && (lfs != lrs || lfs != rrs);
185         else
186                 return lrs == rrs && (lrs != lfs || lrs != rfs);
187 }
188
189 bool PSPlanner::parked()
190 {
191         std::vector<std::tuple<double, double>> slot;
192         slot.push_back(std::make_tuple(this->ps().x1(), this->ps().y1()));
193         slot.push_back(std::make_tuple(this->ps().x2(), this->ps().y2()));
194         slot.push_back(std::make_tuple(this->ps().x3(), this->ps().y3()));
195         slot.push_back(std::make_tuple(this->ps().x4(), this->ps().y4()));
196         return inside(this->gc().lfx(), this->gc().lfy(), slot)
197                 && inside(this->gc().lrx(), this->gc().lry(), slot)
198                 && inside(this->gc().rrx(), this->gc().rry(), slot)
199                 && inside(this->gc().rfx(), this->gc().rfy(), slot);
200 }
201
202 std::vector<BicycleCar> PSPlanner::possible_goals(
203         unsigned int cnt,
204         double dist
205 )
206 {
207         std::vector<BicycleCar> pi;
208         if (this->ps().parallel())
209                 this->cc().sp(1);
210         else
211                 this->cc().sp(-1);
212         this->cc().sp(this->cc().sp() * dist);
213         BicycleCar orig_cc(this->cc());
214         for (unsigned int i = 0; i < cnt; i++) {
215                 this->cc().next();
216                 pi.push_back(BicycleCar(this->cc()));
217         }
218         this->cc() = BicycleCar(orig_cc);
219         if (this->ps().parallel()) {
220                 this->cc().st(0);
221                 for (unsigned int i = 0; i < cnt; i++) {
222                         this->cc().next();
223                         pi.push_back(BicycleCar(this->cc()));
224                 }
225                 this->cc() = BicycleCar(orig_cc);
226         } else {
227                 if (!this->ps().right()) {
228                         this->cc().set_max_steer();
229                         for (unsigned int i = 0; i < cnt; i++) {
230                                 this->cc().next();
231                                 pi.push_back(BicycleCar(this->cc()));
232                         }
233                 } else {
234                         this->cc().set_max_steer();
235                         this->cc().st(this->cc().st() * -1);
236                         for (unsigned int i = 0; i < cnt; i++) {
237                                 this->cc().next();
238                                 pi.push_back(BicycleCar(this->cc()));
239                         }
240                 }
241                 this->cc() = BicycleCar(orig_cc);
242         }
243         return pi;
244 }
245
246 // find entry
247 void PSPlanner::fe()
248 {
249         this->c_ = 0;
250         if (this->ps().parallel()) {
251                 return this->fe_parallel();
252         } else {
253                 this->guess_gc();
254                 this->cc() = BicycleCar(this->gc());
255                 //this->cc().set_max_steer();
256                 //if (this->ps().right())
257                 //        this->cc().st(this->cc().st() * -1);
258                 this->cc().sp(-0.2);
259         }
260 }
261
262 void PSPlanner::fe_parallel()
263 {
264         BicycleCar bco = BicycleCar(this->gc());
265         this->cc() = BicycleCar();
266         this->cc().sp(-0.01);
267         this->cc().set_max_steer();
268         if (!this->ps().right())
269                 this->cc().st(this->cc().st() * -1);
270         this->cc().h(this->ps().heading());
271         double angl_in_slot = this->ps().heading() - M_PI / 4;
272         if (!this->ps().right())
273                 angl_in_slot += M_PI / 2;
274         this->cc().x(
275                 this->ps().x4()
276                 + this->cc().w()/2 * cos(
277                         this->ps().heading()
278                         + (this->ps().right() ? + M_PI / 2 : - M_PI / 2)
279                 )
280                 + (this->cc().df() + 0.01) * cos(
281                         this->ps().heading() + M_PI
282                 )
283         );
284         this->cc().y(
285                 this->ps().y4()
286                 + this->cc().w()/2 * sin(
287                         this->ps().heading()
288                         + (this->ps().right() ? + M_PI / 2 : - M_PI / 2)
289                 )
290                 + (this->cc().df() + 0.01) * sin(
291                         this->ps().heading() + M_PI
292                 )
293         );
294
295         std::queue<BicycleCar, std::list<BicycleCar>> q;
296         while (!this->collide()) {
297                 q.push(this->cc());
298                 this->cc().rotate(
299                         this->ps().x4(),
300                         this->ps().y4() - 0.01,
301                         ((this->ps().right()) ? 0.001 : -0.001)
302                 );
303         }
304         // BFS - find entry current car `cc` and corresponding goal car `gc`
305         unsigned int iter_cntr = 0;
306         while (!q.empty() && iter_cntr < 30) {
307                 this->cc() = BicycleCar(q.front());
308                 q.pop();
309                 while (
310                         !this->collide()
311                         && (std::abs(
312                                 this->cc().h() - this->ps().heading()
313                         ) > M_PI / 32)
314                         && (std::abs(
315                                 this->cc().h() - this->ps().heading()
316                         ) < M_PI / 2)
317                 )
318                         this->cc().next();
319                 this->cc().sp(this->cc().sp() * -1);
320                 this->cc().next();
321                 this->gc() = BicycleCar(this->cc());
322                 if (this->parked())
323                         goto successfinish;
324                 this->cc().st(this->cc().st() * -1);
325                 q.push(BicycleCar(this->cc()));
326                 if (sgn(this->cc().st()) == sgn(q.front().st()))
327                         iter_cntr++;
328         }
329         // fallback to fer
330         this->gc() = BicycleCar(bco);
331 successfinish:
332         return this->fer_parallel();
333 }
334
335 void PSPlanner::fe_perpendicular()
336 {
337         // TODO Try multiple angles when going from parking slot.
338         //
339         //      Do not use just the maximum steer angle. Test angles
340         //      until the whole current car `cc` is out of the parking
341         //      slot `ps`.
342         //
343         //      Another approach could be testing angles from the
344         //      beginning of the escape parkig slot maneuver.
345         if (this->forward())
346                 this->cc().sp(-0.01);
347         else
348                 this->cc().sp(0.01);
349         while (!this->left())
350                 this->cc().next();
351         return;
352 }
353
354 void PSPlanner::fer()
355 {
356         this->c_ = 0;
357         if (this->ps().parallel()) {
358                 this->guess_gc();
359                 this->cc() = BicycleCar(this->gc());
360                 this->cc().set_max_steer();
361                 if (!this->ps().right())
362                         this->cc().st(this->cc().st() * -1);
363                 this->cc().sp(0.01);
364                 return this->fer_parallel();
365         } else {
366                 return this->fer_perpendicular();
367         }
368 }
369
370 void PSPlanner::fer_parallel()
371 {
372         this->cusps_.clear();
373         while (!this->left()) {
374                 while (!this->collide() && !this->left())
375                         this->cc().next();
376                 if (this->left() && !this->collide()) {
377                         break;
378                 } else {
379                         this->cc().sp(this->cc().sp() * -1);
380                         this->cc().next();
381                         this->cc().st(this->cc().st() * -1);
382                         this->c_++;
383                         this->cusps_.push_back(this->cc());
384                 }
385         }
386         if (this->cc().st() < 0) {
387                 this->c_++;
388                 this->cusps_.push_back(this->cc());
389         }
390 }
391
392 void PSPlanner::fer_perpendicular()
393 {
394         bool delta_use[] = {true, true, true};
395         double cc_h = this->cc().h();
396         double x;
397         double y;
398         // check inner radius
399         if (this->forward()) {
400                 x = this->ps().x1();
401                 y = this->ps().y1();
402         } else {
403                 x = this->ps().x4();
404                 y = this->ps().y4();
405         }
406         double x1;
407         double y1;
408         if (this->ps().right()) {
409                 x1 = this->cc().ccr().x();
410                 y1 = this->cc().ccr().y();
411         } else {
412                 x1 = this->cc().ccl().x();
413                 y1 = this->cc().ccl().y();
414         }
415         double IR = this->cc().iradi();
416         double a = 1;
417         double b;
418         if (this->forward())
419                 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
420         else
421                 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
422         double c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
423         double D = pow(b, 2) - 4 * a * c;
424         double delta;
425         delta = -b - sqrt(D);
426         delta /= 2 * a;
427         double delta_1 = delta;
428         if (D < 0)
429                 delta_use[0] = false;
430         // check outer radius
431         if (this->forward()) {
432                 x = this->ps().x4();
433                 y = this->ps().y4();
434         } else {
435                 x = this->ps().x1();
436                 y = this->ps().y1();
437         }
438         IR = this->cc().ofradi();
439         a = 1;
440         if (this->forward())
441                 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
442         else
443                 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
444         c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
445         D = pow(b, 2) - 4 * a * c;
446         if (this->forward()) {
447                 delta = -b + sqrt(D);
448                 delta /= 2 * a;
449         }
450         double delta_2 = delta;
451         if (D < 0)
452                 delta_use[1] = false;
453         delta = -b - sqrt(D);
454         delta /= 2 * a;
455         double delta_3 = delta;
456         if (D < 0)
457                 delta_use[2] = false;
458         if (delta_use[0] && delta_use[1] && delta_use[2])
459                 delta = std::max(delta_1, std::max(delta_2, delta_3));
460         else if (delta_use[0] && delta_use[1])
461                 delta = std::max(delta_1, delta_2);
462         else if (delta_use[0] && delta_use[2])
463                 delta = std::max(delta_1, delta_3);
464         else if (delta_use[1] && delta_use[2])
465                 delta = std::max(delta_2, delta_3);
466         else if (delta_use[0])
467                 delta = delta_1;
468         else if (delta_use[1])
469                 delta = delta_2;
470         else if (delta_use[2])
471                 delta = delta_3;
472         else
473                 return;
474         // current car `cc` can get out of slot with max steer
475         this->cc().x(this->cc().x() + delta * cos(cc_h));
476         this->cc().y(this->cc().y() + delta * sin(cc_h));
477         this->cc().h(cc_h);
478         // get current car `cc` out of slot
479         if (this->forward())
480                 this->cc().sp(-0.01);
481         else
482                 this->cc().sp(0.01);
483         this->cc().set_max_steer();
484         if (this->ps().right())
485                 this->cc().st(this->cc().st() * -1);
486         while (!this->left()) {
487                 while (!this->collide() && !this->left())
488                         this->cc().next();
489                 if (this->left() && !this->collide()) {
490                         break;
491                 } else {
492                         this->cc().sp(this->cc().sp() * -1);
493                         this->cc().next();
494                         this->cc().st(this->cc().st() * -1);
495                 }
496         }
497 }
498
499 PSPlanner::PSPlanner()
500 {
501 }