6 bool PSPlanner::collide()
8 if(std::get<0>(intersect(
9 this->cc().lfx(), this->cc().lfy(),
10 this->cc().lrx(), this->cc().lry(),
11 this->ps().x1(), this->ps().y1(),
12 this->ps().x2(), this->ps().y2()
15 if(std::get<0>(intersect(
16 this->cc().rfx(), this->cc().rfy(),
17 this->cc().rrx(), this->cc().rry(),
18 this->ps().x1(), this->ps().y1(),
19 this->ps().x2(), this->ps().y2()
22 if(std::get<0>(intersect(
23 this->cc().lfx(), this->cc().lfy(),
24 this->cc().rfx(), this->cc().rfy(),
25 this->ps().x1(), this->ps().y1(),
26 this->ps().x2(), this->ps().y2()
29 if(std::get<0>(intersect(
30 this->cc().lrx(), this->cc().lry(),
31 this->cc().rrx(), this->cc().rry(),
32 this->ps().x1(), this->ps().y1(),
33 this->ps().x2(), this->ps().y2()
36 if(std::get<0>(intersect(
37 this->cc().lfx(), this->cc().lfy(),
38 this->cc().lrx(), this->cc().lry(),
39 this->ps().x2(), this->ps().y2(),
40 this->ps().x3(), this->ps().y3()
43 if(std::get<0>(intersect(
44 this->cc().rfx(), this->cc().rfy(),
45 this->cc().rrx(), this->cc().rry(),
46 this->ps().x2(), this->ps().y2(),
47 this->ps().x3(), this->ps().y3()
50 if(std::get<0>(intersect(
51 this->cc().lfx(), this->cc().lfy(),
52 this->cc().rfx(), this->cc().rfy(),
53 this->ps().x2(), this->ps().y2(),
54 this->ps().x3(), this->ps().y3()
57 if(std::get<0>(intersect(
58 this->cc().lrx(), this->cc().lry(),
59 this->cc().rrx(), this->cc().rry(),
60 this->ps().x2(), this->ps().y2(),
61 this->ps().x3(), this->ps().y3()
64 if(std::get<0>(intersect(
65 this->cc().lfx(), this->cc().lfy(),
66 this->cc().lrx(), this->cc().lry(),
67 this->ps().x3(), this->ps().y3(),
68 this->ps().x4(), this->ps().y4()
71 if(std::get<0>(intersect(
72 this->cc().rfx(), this->cc().rfy(),
73 this->cc().rrx(), this->cc().rry(),
74 this->ps().x3(), this->ps().y3(),
75 this->ps().x4(), this->ps().y4()
78 if(std::get<0>(intersect(
79 this->cc().lfx(), this->cc().lfy(),
80 this->cc().rfx(), this->cc().rfy(),
81 this->ps().x3(), this->ps().y3(),
82 this->ps().x4(), this->ps().y4()
85 if(std::get<0>(intersect(
86 this->cc().lrx(), this->cc().lry(),
87 this->cc().rrx(), this->cc().rry(),
88 this->ps().x3(), this->ps().y3(),
89 this->ps().x4(), this->ps().y4()
95 bool PSPlanner::left()
97 double lfx = this->cc().lfx();
98 double lfy = this->cc().lfy();
99 double lrx = this->cc().lrx();
100 double lry = this->cc().lry();
101 double rrx = this->cc().rrx();
102 double rry = this->cc().rry();
103 double rfx = this->cc().rfx();
104 double rfy = this->cc().rfy();
106 (lfx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
107 - (lfy - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
110 (lrx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
111 - (lry - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
114 (rrx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
115 - (rry - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
118 (rfx - this->ps().x1()) * (this->ps().y4() - this->ps().y1())
119 - (rfy - this->ps().y1()) * (this->ps().x4() - this->ps().x1())
121 if (this->ps().parallel())
122 return lfs == rfs && (lfs != lrs || lfs != rrs);
123 else if (!this->forward())
124 return lfs == rfs && (lfs != lrs || lfs != rrs);
126 return lrs == rrs && (lrs != lfs || lrs != rfs);
129 bool PSPlanner::parked()
131 std::vector<std::tuple<double, double>> slot;
132 slot.push_back(std::make_tuple(this->ps().x1(), this->ps().y1()));
133 slot.push_back(std::make_tuple(this->ps().x2(), this->ps().y2()));
134 slot.push_back(std::make_tuple(this->ps().x3(), this->ps().y3()));
135 slot.push_back(std::make_tuple(this->ps().x4(), this->ps().y4()));
136 return inside(this->gc().lfx(), this->gc().lfy(), slot)
137 && inside(this->gc().lrx(), this->gc().lry(), slot)
138 && inside(this->gc().rrx(), this->gc().rry(), slot)
139 && inside(this->gc().rfx(), this->gc().rfy(), slot);
145 if (this->ps().parallel())
146 return this->fe_parallel();
148 return this->fe_perpendicular();
151 void PSPlanner::fe_parallel()
153 // angle for distance from "entry" corner
154 double dist_angl = this->ps().heading() + M_PI;
155 dist_angl += (this->ps().right()) ? - M_PI / 4 : + M_PI / 4;
156 // set bicycle car `bci` basic dimensions and heading
157 BicycleCar bci = BicycleCar(this->gc());
158 BicycleCar bco = BicycleCar(this->gc());
159 bci.h(this->ps().heading());
160 // move 0.01 from the "entry" corner
161 bci.x(this->ps().x4() + 0.01 * cos(dist_angl));
162 bci.y(this->ps().y4() + 0.01 * sin(dist_angl));
163 // align with parking "top" of slot (move backward)
164 dist_angl = bci.h() + M_PI;
165 bci.x(bci.x() + bci.df() * cos(dist_angl));
166 bci.y(bci.y() + bci.df() * sin(dist_angl));
167 // align with "entry" to pakring slot (move outside)
168 dist_angl = this->ps().heading();
169 dist_angl += (this->ps().right()) ? + M_PI / 2 : - M_PI / 2;
170 bci.x(bci.x() + bci.w() / 2 * cos(dist_angl));
171 bci.y(bci.y() + bci.w() / 2 * sin(dist_angl));
172 // BFS - init all starts
173 // see https://courses.cs.washington.edu/courses/cse326/03su/homework/hw3/bfs.html
174 double dist_diag = sqrt(pow(bci.w() / 2, 2) + pow(bci.df(), 2));
175 if (this->ps().right())
176 dist_angl = atan2(bci.y() - bci.rfy(), bci.x() - bci.rfx());
178 dist_angl = atan2(bci.y() - bci.lfy(), bci.x() - bci.lfx());
179 double DIST_ANGL = dist_angl;
180 std::queue<BicycleCar, std::list<BicycleCar>> q;
184 && dist_angl < DIST_ANGL + 3 * M_PI / 4
188 && dist_angl > DIST_ANGL - 3 * M_PI / 4
191 this->cc() = BicycleCar(bci);
192 if (this->ps().right()) {
193 this->cc().x(bci.rfx() + dist_diag * cos(dist_angl));
194 this->cc().y(bci.rfy() + dist_diag * sin(dist_angl));
196 this->cc().x(bci.lfx() + dist_diag * cos(dist_angl));
197 this->cc().y(bci.lfy() + dist_diag * sin(dist_angl));
199 this->cc().h(this->ps().heading() + dist_angl - DIST_ANGL);
200 if (!this->collide()) {
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 q.push(BicycleCar(this->cc()));
207 dist_angl += (this->ps().right()) ? + 0.01 : - 0.01;
209 // BFS - find entry current car `cc` and corresponding goal car `gc`
210 unsigned int iter_cntr;
211 while (!q.empty() && iter_cntr < 9) {
212 this->cc() = BicycleCar(q.front());
217 this->cc().h() - this->ps().heading()
221 this->cc().sp(this->cc().sp() * -1);
223 this->gc() = BicycleCar(this->cc());
226 this->cc().st(this->cc().st() * -1);
227 q.push(BicycleCar(this->cc()));
228 if (sgn(this->cc().st()) == sgn(q.front().st()))
232 this->gc() = BicycleCar(bco);
234 return this->fer_parallel();
237 void PSPlanner::fe_perpendicular()
239 // TODO Try multiple angles when going from parking slot.
241 // Do not use just the maximum steer angle. Test angles
242 // until the whole current car `cc` is out of the parking
245 // Another approach could be testing angles from the
246 // beginning of the escape parkig slot maneuver.
247 return fer_perpendicular();
250 void PSPlanner::fer()
252 if (this->ps().parallel())
253 return this->fer_parallel();
255 return this->fer_perpendicular();
258 void PSPlanner::fer_parallel()
260 this->cc().st(this->cc().wb() / this->cc().mtr());
261 if (!this->ps().right())
262 this->cc().st(this->cc().st() * -1);
264 while (!this->left()) {
265 while (!this->collide() && !this->left())
267 if (this->left() && !this->collide()) {
270 this->cc().sp(this->cc().sp() * -1);
272 this->cc().st(this->cc().st() * -1);
277 void PSPlanner::fer_perpendicular()
279 double cc_h = this->cc().h();
282 // check inner radius
283 if (this->forward()) {
292 if (this->ps().right()) {
293 x1 = this->cc().ccr().x();
294 y1 = this->cc().ccr().y();
296 x1 = this->cc().ccl().x();
297 y1 = this->cc().ccl().y();
299 double IR = this->cc().iradi();
303 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
305 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
306 double c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
307 double D = D = pow(b, 2) - 4 * a * c;
309 delta = -b - sqrt(D);
311 double delta_1 = delta;
312 // check outer radius
313 if (this->forward()) {
320 IR = this->cc().ofradi();
323 b = (x - x1) * 2 * cos(cc_h) + (y - y1) * 2 * sin(cc_h);
325 b = (x1 - x) * 2 * cos(cc_h) + (y1 - y) * 2 * sin(cc_h);
326 c = pow(x - x1, 2) + pow(y - y1, 2) - pow(IR, 2);
327 D = pow(b, 2) - 4 * a * c;
328 if (this->forward()) {
329 delta = -b + sqrt(D);
332 double delta_2 = delta;
333 delta = -b - sqrt(D);
335 double delta_3 = delta;
336 delta = std::max(delta_1, std::max(delta_2, delta_3));
337 // current car `cc` can get out of slot with max steer
338 this->cc().x(this->cc().x() + delta * cos(cc_h));
339 this->cc().y(this->cc().y() + delta * sin(cc_h));
341 // get current car `cc` out of slot
346 this->cc().st(this->cc().wb() / this->cc().mtr());
347 if (this->ps().right())
348 this->cc().st(this->cc().st() * -1);
349 while (!this->left()) {
350 while (!this->collide() && !this->left())
352 if (this->left() && !this->collide()) {
355 this->cc().sp(this->cc().sp() * -1);
357 this->cc().st(this->cc().st() * -1);
362 bool PSPlanner::forward()
364 double heading = this->ps().heading();
365 while (heading < 0) heading += 2 * M_PI;
366 if (!this->ps().parallel())
368 double h = this->gc().h();
369 while (h < 0) h += 2 * M_PI;
370 if (-0.00001 < heading - h && heading - h < 0.00001)
376 PSPlanner::PSPlanner()
380 std::tuple<bool, double, double> intersect(
381 double x1, double y1,
382 double x2, double y2,
383 double x3, double y3,
387 double deno = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
389 return std::make_tuple(false, 0, 0);
390 double t = (x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4);
392 double u = (x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3);
395 if (t < 0 || t > 1 || u < 0 || u > 1)
396 return std::make_tuple(false, 0, 0);
397 return std::make_tuple(true, x1 + t * (x2 - x1), y1 + t * (y2 - y1));
400 bool inside(double x, double y, std::vector<std::tuple<double, double>> poly)
405 for (i = 0; i < 4; i++) {
407 (std::get<1>(poly[i]) > y) != (std::get<1>(poly[j]) > y)
409 x < std::get<0>(poly[i])
410 + (std::get<0>(poly[j]) - std::get<0>(poly[i]))
411 * (y - std::get<1>(poly[i]))
412 / (std::get<1>(poly[j]) - std::get<1>(poly[i]))