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