]> rtime.felk.cvut.cz Git - hubacji1/psp.git/blob - src/psp.cc
Fix missing iter_cntr definition
[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         double heading = this->ps().heading();
25         while (heading < 0) heading += 2 * M_PI;
26         if (!this->ps().parallel())
27                 heading -= M_PI / 2;
28         double h = this->gc().h();
29         while (h < 0) h += 2 * M_PI;
30         if (-0.00001 < heading - h && heading - h < 0.00001)
31                 return true;
32         else
33                 return false;
34 }
35
36 void PSPlanner::guess_gc()
37 {
38         double x = this->ps().x1();
39         double y = this->ps().y1();
40         double h = this->ps().heading();
41         double dts = + M_PI / 2; // direction to slot
42         if (this->ps().right())
43                 dts = - M_PI / 2;
44         if (this->ps().parallel()) {
45                 x += (this->gc().w() / 2 + 0.01) * cos(h + dts);
46                 x += (this->gc().dr() + 0.01) * cos(h);
47                 y += (this->gc().w() / 2 + 0.01) * sin(h + dts);
48                 y += (this->gc().dr() + 0.01) * sin(h);
49         } else {
50                 x += (this->ps().x4() - this->ps().x1()) / 2;
51                 x += (this->gc().df() + 0.01) * cos(h + dts);
52                 y += (this->ps().y4() - this->ps().y1()) / 2;
53                 y += (this->gc().df() + 0.01) * sin(h + dts);
54                 if (this->ps().right())
55                         h += M_PI / 2;
56                 else
57                         h -= M_PI / 2;
58         }
59         while (h > M_PI)
60                 h -= 2 * M_PI;
61         while (h <= -M_PI)
62                 h += 2 * M_PI;
63         this->gc().x(x);
64         this->gc().y(y);
65         this->gc().h(h);
66 }
67
68 bool PSPlanner::left()
69 {
70         double lfx = this->cc().lfx();
71         double lfy = this->cc().lfy();
72         double lrx = this->cc().lrx();
73         double lry = this->cc().lry();
74         double rrx = this->cc().rrx();
75         double rry = this->cc().rry();
76         double rfx = this->cc().rfx();
77         double rfy = this->cc().rfy();
78         double lfs = sgn(
79                 (lfx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
80                 - (lfy - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
81         );
82         double lrs = sgn(
83                 (lrx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
84                 - (lry - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
85         );
86         double rrs = sgn(
87                 (rrx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
88                 - (rry - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
89         );
90         double rfs = sgn(
91                 (rfx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
92                 - (rfy - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
93         );
94         if (this->ps().parallel())
95                 return lfs == rfs && (lfs != lrs || lfs != rrs);
96         else if (!this->forward())
97                 return lfs == rfs && (lfs != lrs || lfs != rrs);
98         else
99                 return lrs == rrs && (lrs != lfs || lrs != rfs);
100 }
101
102 bool PSPlanner::parked()
103 {
104         std::vector<std::tuple<double, double>> slot;
105         slot.push_back(std::make_tuple(this->ps().x1(), this->ps().y1()));
106         slot.push_back(std::make_tuple(this->ps().x2(), this->ps().y2()));
107         slot.push_back(std::make_tuple(this->ps().x3(), this->ps().y3()));
108         slot.push_back(std::make_tuple(this->ps().x4(), this->ps().y4()));
109         return inside(this->gc().lfx(), this->gc().lfy(), slot)
110                 && inside(this->gc().lrx(), this->gc().lry(), slot)
111                 && inside(this->gc().rrx(), this->gc().rry(), slot)
112                 && inside(this->gc().rfx(), this->gc().rfy(), slot);
113 }
114
115 std::vector<BicycleCar> PSPlanner::possible_inits(
116         unsigned int cnt,
117         double dist
118 )
119 {
120         std::vector<BicycleCar> pi;
121         this->cc().sp(this->cc().sp() * -dist);
122         this->cc().st(this->cc().st() * -1);
123         BicycleCar orig_cc(this->cc());
124         for (unsigned int i = 0; i < cnt; i++) {
125                 this->cc().next();
126                 pi.push_back(BicycleCar(this->cc()));
127         }
128         this->cc() = BicycleCar(orig_cc);
129         return pi;
130 }
131
132 // find entry
133 void PSPlanner::fe()
134 {
135         if (this->ps().parallel())
136                 return this->fe_parallel();
137         else
138                 return this->fe_perpendicular();
139 }
140
141 void PSPlanner::fe_parallel()
142 {
143         // angle for distance from "entry" corner
144         double dist_angl = this->ps().heading() + M_PI;
145         dist_angl += (this->ps().right()) ? - M_PI / 4 : + M_PI / 4;
146         // set bicycle car `bci` basic dimensions and heading
147         BicycleCar bci = BicycleCar(this->gc());
148         BicycleCar bco = BicycleCar(this->gc());
149         bci.h(this->ps().heading());
150         // move 0.01 from the "entry" corner
151         bci.x(this->ps().x4() + 0.01 * cos(dist_angl));
152         bci.y(this->ps().y4() + 0.01 * sin(dist_angl));
153         // align with parking "top" of slot (move backward)
154         dist_angl = bci.h() + M_PI;
155         bci.x(bci.x() + bci.df() * cos(dist_angl));
156         bci.y(bci.y() + bci.df() * sin(dist_angl));
157         // align with "entry" to pakring slot (move outside)
158         dist_angl = this->ps().heading();
159         dist_angl += (this->ps().right()) ? + M_PI / 2 : - M_PI / 2;
160         bci.x(bci.x() + bci.w() / 2 * cos(dist_angl));
161         bci.y(bci.y() + bci.w() / 2 * sin(dist_angl));
162         // set default speed, steer
163         bci.st(bci.wb() / bci.mtr());
164         if (!this->ps().right())
165                 bci.st(bci.st() * -1);
166         bci.sp(-0.01);
167         // BFS - init all starts
168         // see https://courses.cs.washington.edu/courses/cse326/03su/homework/hw3/bfs.html
169         double dist_diag = sqrt(pow(bci.w() / 2, 2) + pow(bci.df(), 2));
170         if (this->ps().right())
171                 dist_angl = atan2(bci.y() - bci.rfy(), bci.x() - bci.rfx());
172         else
173                 dist_angl = atan2(bci.y() - bci.lfy(), bci.x() - bci.lfx());
174         double DIST_ANGL = dist_angl;
175         std::queue<BicycleCar, std::list<BicycleCar>> q;
176         while (
177                 (
178                         this->ps().right()
179                         && dist_angl < DIST_ANGL + 3 * M_PI / 4
180                 )
181                 || (
182                         !this->ps().right()
183                         && dist_angl > DIST_ANGL - 3 * M_PI / 4
184                 )
185         ) {
186                 this->cc() = BicycleCar(bci);
187                 if (this->ps().right()) {
188                         this->cc().x(bci.rfx() + dist_diag * cos(dist_angl));
189                         this->cc().y(bci.rfy() + dist_diag * sin(dist_angl));
190                 } else {
191                         this->cc().x(bci.lfx() + dist_diag * cos(dist_angl));
192                         this->cc().y(bci.lfy() + dist_diag * sin(dist_angl));
193                 }
194                 this->cc().h(this->ps().heading() + dist_angl - DIST_ANGL);
195                 if (!this->collide()) {
196                         q.push(BicycleCar(this->cc()));
197                 }
198                 dist_angl += (this->ps().right()) ? + 0.01 : - 0.01;
199         }
200         // BFS - find entry current car `cc` and corresponding goal car `gc`
201         unsigned int iter_cntr = 0;
202         while (!q.empty() && iter_cntr < 9) {
203                 this->cc() = BicycleCar(q.front());
204                 q.pop();
205                 while (
206                         !this->collide()
207                         && (std::abs(
208                                 this->cc().h() - this->ps().heading()
209                         ) < M_PI / 2)
210                 )
211                         this->cc().next();
212                 this->cc().sp(this->cc().sp() * -1);
213                 this->cc().next();
214                 this->gc() = BicycleCar(this->cc());
215                 if (this->parked())
216                         goto successfinish;
217                 this->cc().st(this->cc().st() * -1);
218                 q.push(BicycleCar(this->cc()));
219                 if (sgn(this->cc().st()) == sgn(q.front().st()))
220                         iter_cntr++;
221         }
222         // fallback to fer
223         this->gc() = BicycleCar(bco);
224 successfinish:
225         return this->fer_parallel();
226 }
227
228 void PSPlanner::fe_perpendicular()
229 {
230         // TODO Try multiple angles when going from parking slot.
231         //
232         //      Do not use just the maximum steer angle. Test angles
233         //      until the whole current car `cc` is out of the parking
234         //      slot `ps`.
235         //
236         //      Another approach could be testing angles from the
237         //      beginning of the escape parkig slot maneuver.
238         return fer_perpendicular();
239 }
240
241 void PSPlanner::fer()
242 {
243         if (this->ps().parallel())
244                 return this->fer_parallel();
245         else
246                 return this->fer_perpendicular();
247 }
248
249 void PSPlanner::fer_parallel()
250 {
251         this->cc().st(this->cc().wb() / this->cc().mtr());
252         if (!this->ps().right())
253                 this->cc().st(this->cc().st() * -1);
254         this->cc().sp(0.01);
255         while (!this->left()) {
256                 while (!this->collide() && !this->left())
257                         this->cc().next();
258                 if (this->left() && !this->collide()) {
259                         break;
260                 } else {
261                         this->cc().sp(this->cc().sp() * -1);
262                         this->cc().next();
263                         this->cc().st(this->cc().st() * -1);
264                 }
265         }
266 }
267
268 void PSPlanner::fer_perpendicular()
269 {
270         bool delta_use[] = {true, true, true};
271         double cc_h = this->cc().h();
272         double x;
273         double y;
274         // check inner radius
275         if (this->forward()) {
276                 x = this->ps().x1();
277                 y = this->ps().y1();
278         } else {
279                 x = this->ps().x4();
280                 y = this->ps().y4();
281         }
282         double x1;
283         double y1;
284         if (this->ps().right()) {
285                 x1 = this->cc().ccr().x();
286                 y1 = this->cc().ccr().y();
287         } else {
288                 x1 = this->cc().ccl().x();
289                 y1 = this->cc().ccl().y();
290         }
291         double IR = this->cc().iradi();
292         double a = 1;
293         double b;
294         if (this->forward())
295                 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
296         else
297                 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
298         double c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
299         double D = pow(b, 2) - 4 * a * c;
300         double delta;
301         delta = -b - sqrt(D);
302         delta /= 2 * a;
303         double delta_1 = delta;
304         if (D < 0)
305                 delta_use[0] = false;
306         // check outer radius
307         if (this->forward()) {
308                 x = this->ps().x4();
309                 y = this->ps().y4();
310         } else {
311                 x = this->ps().x1();
312                 y = this->ps().y1();
313         }
314         IR = this->cc().ofradi();
315         a = 1;
316         if (this->forward())
317                 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
318         else
319                 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
320         c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
321         D = pow(b, 2) - 4 * a * c;
322         if (this->forward()) {
323                 delta = -b + sqrt(D);
324                 delta /= 2 * a;
325         }
326         double delta_2 = delta;
327         if (D < 0)
328                 delta_use[1] = false;
329         delta = -b - sqrt(D);
330         delta /= 2 * a;
331         double delta_3 = delta;
332         if (D < 0)
333                 delta_use[2] = false;
334         if (delta_use[0] && delta_use[1] && delta_use[22])
335                 delta = std::max(delta_1, std::max(delta_2, delta_3));
336         else if (delta_use[0] && delta_use[1])
337                 delta = std::max(delta_1, delta_2);
338         else if (delta_use[0] && delta_use[2])
339                 delta = std::max(delta_1, delta_3);
340         else if (delta_use[1] && delta_use[2])
341                 delta = std::max(delta_2, delta_3);
342         else if (delta_use[0])
343                 delta = delta_1;
344         else if (delta_use[1])
345                 delta = delta_2;
346         else if (delta_use[2])
347                 delta = delta_3;
348         else
349                 return;
350         // current car `cc` can get out of slot with max steer
351         this->cc().x(this->cc().x() + delta * cos(cc_h));
352         this->cc().y(this->cc().y() + delta * sin(cc_h));
353         this->cc().h(cc_h);
354         // get current car `cc` out of slot
355         if (this->forward())
356                 this->cc().sp(-0.1);
357         else
358                 this->cc().sp(0.1);
359         this->cc().st(this->cc().wb() / this->cc().mtr());
360         if (this->ps().right())
361                 this->cc().st(this->cc().st() * -1);
362         while (!this->left()) {
363                 while (!this->collide() && !this->left())
364                         this->cc().next();
365                 if (this->left() && !this->collide()) {
366                         break;
367                 } else {
368                         this->cc().sp(this->cc().sp() * -1);
369                         this->cc().next();
370                         this->cc().st(this->cc().st() * -1);
371                 }
372         }
373 }
374
375 PSPlanner::PSPlanner()
376 {
377 }