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