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