]> rtime.felk.cvut.cz Git - hubacji1/bcar.git/blob - src/pslot.cc
46a12a637cf0ca70d64307b8dd66bb3a24748536
[hubacji1/bcar.git] / src / pslot.cc
1 /*
2  * SPDX-FileCopyrightText: 2021 Jiri Vlasak <jiri.vlasak.2@cvut.cz>
3  *
4  * SPDX-License-Identifier: GPL-3.0-only
5  */
6
7 #include <cassert>
8 #include <cmath>
9 #include "pslot.hh"
10
11 namespace bcar {
12
13 ParkingSlot::ParkingSlot(Point p, double h, double W, double L) :
14                 border_({p,
15                         Point(p.x() + W * cos(h - M_PI / 2.0),
16                                 p.y() + W * sin(h - M_PI / 2.0)),
17                         Point(p.x() + W * cos(h - M_PI / 2.0) + L * cos(h),
18                                 p.y() + W * sin(h - M_PI / 2.0) + L * sin(h)),
19                         Point(p.x() + L * cos(h), p.y() + L * sin(h))}),
20                 entry_(border_[0], border_[3]),
21                 rear_(border_[0], border_[1]),
22                 curb_(border_[1], border_[2]),
23                 front_(border_[2], border_[3])
24 {
25 }
26
27 ParkingSlot::ParkingSlot(double lrx, double lry, double rrx, double rry,
28                 double rfx, double rfy, double lfx, double lfy) :
29                         border_({Point(lrx, lry), Point(rrx, rry),
30                                 Point(rfx, rfy), Point(lfx, lfy)}),
31                         entry_(border_[0], border_[3]),
32                         rear_(border_[0], border_[1]),
33                         curb_(border_[1], border_[2]),
34                         front_(border_[2], border_[3])
35 {
36 }
37
38 double
39 ParkingSlot::len() const
40 {
41         return this->entry_.len();
42 }
43
44 double
45 ParkingSlot::w() const
46 {
47         return this->rear_.len();
48 }
49
50 double
51 ParkingSlot::lfx() const
52 {
53         return this->border_[3].x();
54 }
55
56 double
57 ParkingSlot::lfy() const
58 {
59         return this->border_[3].y();
60 }
61
62 double
63 ParkingSlot::lrx() const
64 {
65         return this->border_[0].x();
66 }
67
68 double
69 ParkingSlot::lry() const
70 {
71         return this->border_[0].y();
72 }
73
74 double
75 ParkingSlot::rrx() const
76 {
77         return this->border_[1].x();
78 }
79
80 double
81 ParkingSlot::rry() const
82 {
83         return this->border_[1].y();
84 }
85
86 double
87 ParkingSlot::rfx() const
88 {
89         return this->border_[2].x();
90 }
91
92 double
93 ParkingSlot::rfy() const
94 {
95         return this->border_[2].y();
96 }
97
98 double
99 ParkingSlot::h() const
100 {
101         return atan2(this->lfy() - this->lry(), this->lfx() - this->lrx());
102 }
103
104 Point
105 ParkingSlot::lf() const
106 {
107         return Point(this->lfx(), this->lfy());
108 }
109
110 Point
111 ParkingSlot::lr() const
112 {
113         return Point(this->lrx(), this->lry());
114 }
115
116 Point
117 ParkingSlot::rr() const
118 {
119         return Point(this->rrx(), this->rry());
120 }
121
122 Point
123 ParkingSlot::rf() const
124 {
125         return Point(this->rfx(), this->rfy());
126 }
127
128 Line
129 ParkingSlot::entry() const
130 {
131         return this->entry_;
132 }
133
134 Line
135 ParkingSlot::rear() const
136 {
137         return this->rear_;
138 }
139
140 Line
141 ParkingSlot::curb() const
142 {
143         return this->curb_;
144 }
145
146 Line
147 ParkingSlot::front() const
148 {
149         return this->front_;
150 }
151
152 void
153 ParkingSlot::set_parking_speed(double s)
154 {
155         this->parking_speed_ = s;
156 }
157
158 unsigned int
159 ParkingSlot::get_max_cusp() const
160 {
161         return this->max_cusp_;
162 }
163
164 void
165 ParkingSlot::set_max_cusp(unsigned int m)
166 {
167         this->max_cusp_ = m;
168 }
169
170 void
171 ParkingSlot::set_delta_angle_to_slot(double d)
172 {
173         this->delta_angle_to_slot_ = d;
174 }
175
176 bool
177 ParkingSlot::parallel() const
178 {
179         return this->entry_.len() > this->rear_.len();
180 }
181
182 bool
183 ParkingSlot::right() const
184 {
185         return this->border_[1].on_right_side_of(this->entry_);
186 }
187
188 void
189 ParkingSlot::swap_side()
190 {
191         this->border_[1].rotate(this->border_[0], M_PI);
192         this->border_[2].rotate(this->border_[3], M_PI);
193         this->entry_ = Line(this->border_[0], this->border_[3]);
194         this->rear_ = Line(this->border_[0], this->border_[1]);
195         this->curb_ = Line(this->border_[1], this->border_[2]);
196         this->front_ = Line(this->border_[2], this->border_[3]);
197 }
198
199 bool
200 ParkingSlot::parked(BicycleCar const& c) const
201 {
202         auto b_len = sizeof(this->border_) / sizeof(this->border_[0]);
203         std::vector<Point> b(this->border_, this->border_ + b_len);
204         return c.lf().inside_of(b) && c.lr().inside_of(b)
205                 && c.rr().inside_of(b) && c.rf().inside_of(b);
206 }
207
208 bool
209 ParkingSlot::collide(BicycleCar const& c) const
210 {
211         return c.left().intersects_with(this->rear_)
212                 || c.left().intersects_with(this->curb_)
213                 || c.left().intersects_with(this->front_)
214                 || c.rear().intersects_with(this->rear_)
215                 || c.rear().intersects_with(this->curb_)
216                 || c.rear().intersects_with(this->front_)
217                 || c.right().intersects_with(this->rear_)
218                 || c.right().intersects_with(this->curb_)
219                 || c.right().intersects_with(this->front_)
220                 || c.front().intersects_with(this->rear_)
221                 || c.front().intersects_with(this->curb_)
222                 || c.front().intersects_with(this->front_);
223 }
224
225 std::vector<BicycleCar>
226 ParkingSlot::drive_in_slot(BicycleCar c)
227 {
228         assert(this->parallel());
229         assert(this->right());
230         assert(c.len() < this->len());
231         assert(c.w() < this->w());
232         std::vector<BicycleCar> path;
233         path.reserve(this->max_cusp_ + 2);
234         path.push_back(c);
235         unsigned int cusp = 0;
236         while (cusp < this->max_cusp_ + 1) {
237                 if (this->parked(c)) {
238                         if (cusp < this->max_cusp_) {
239                                 this->max_cusp_ = cusp;
240                         }
241                         path.push_back(c);
242                         return path;
243                 }
244                 double sx = c.x() + 10.0 * cos(this->h());
245                 double sy = c.y() + 10.0 * sin(this->h());
246                 double cx = c.x() + 10.0 * cos(c.h());
247                 double cy = c.y() + 10.0 * sin(c.h());
248                 if (Point(cx, cy).on_right_side_of(
249                                 Line(Point(c.x(), c.y()), Point(sx, sy)))) {
250                         return std::vector<BicycleCar>();
251                 }
252                 c.next();
253                 if (this->collide(c)) {
254                         c.sp(c.sp() * -1.0);
255                         c.next();
256                         path.push_back(c);
257                         c.st(c.st() * -1.0);
258                         cusp += 1;
259                 }
260         }
261         return std::vector<BicycleCar>();
262 }
263
264 std::vector<BicycleCar>
265 ParkingSlot::drive_of_slot(BicycleCar c)
266 {
267         assert(this->parallel());
268         assert(this->right());
269         assert(c.len() < this->len());
270         assert(c.w() < this->w());
271         assert(this->parked(c));
272         std::vector<BicycleCar> path;
273         path.reserve(this->max_cusp_ + 2);
274         path.push_back(c);
275         unsigned int cusp = 0;
276         auto b_len = sizeof(this->border_) / sizeof(this->border_[0]);
277         std::vector<Point> b(this->border_, this->border_ + b_len);
278         while (cusp < this->max_cusp_ + 1) {
279                 if (!c.lf().inside_of(b) && !c.rf().inside_of(b)) {
280                         if (cusp < this->max_cusp_) {
281                                 this->max_cusp_ = cusp;
282                         }
283                         path.push_back(c);
284                         return path;
285                 }
286                 c.next();
287                 if (this->collide(c)) {
288                         c.sp(c.sp() * -1.0);
289                         c.next();
290                         path.push_back(c);
291                         c.st(c.st() * -1.0);
292                         cusp += 1;
293                 }
294         }
295         return std::vector<BicycleCar>();
296 }
297
298 std::vector<Pose>
299 ParkingSlot::steer_in_slot(BicycleCar c)
300 {
301         std::vector<Pose> path;
302         while (!this->parked(c)) {
303                 path.push_back(c);
304                 c.next();
305                 if (this->collide(c)) {
306                         c.sp(c.sp() * -1.0);
307                         c.next();
308                         c.st(c.st() * -1.0);
309                 }
310         }
311         return path;
312 }
313
314 PoseRange
315 ParkingSlot::fe(BicycleCar c)
316 {
317         if (!this->parallel()) {
318                 double gd = 0.0;
319                 double dd = 0.0;
320                 double radi = 0.0;
321                 if (this->parking_speed_ < 0) {
322                         gd = c.df();
323                         c.h(this->rear_.h() + M_PI);
324                         c.sp(1.0);
325                         radi = c.iradi();
326                 } else {
327                         gd = c.dr();
328                         c.h(this->rear_.h());
329                         c.sp(-1.0);
330                         radi = c.ofradi();
331                 }
332                 c.x(this->entry_.m().x() + gd * cos(this->rear_.h()));
333                 c.y(this->entry_.m().y() + gd * sin(this->rear_.h()));
334                 Point cc(0.0, 0.0);
335                 if (this->right()) {
336                         cc = c.ccl();
337                 } else {
338                         cc = c.ccr();
339                 }
340                 this->rear_.intersects_with(cc, radi);
341                 dd = std::min(this->border_[0].edist(this->rear_.i1()),
342                         this->border_[0].edist(this->rear_.i2()));
343                 c.st(0.0);
344                 c.sp(c.sp() * dd);
345                 c.next();
346                 c.sp(this->parking_speed_);
347                 return PoseRange(c.x(), c.y(), c.h(), c.h());
348         }
349         bool swapped = false;
350         if (!this->right()) {
351                 this->swap_side();
352                 swapped = true;
353         }
354         c.h(this->h());
355         double clen = -this->offset_ + this->len() - c.df();
356         double cw = c.w() / 2.0;
357         c.x(this->lrx() + clen * cos(c.h()) + cw * cos(c.h() + M_PI / 2.0));
358         c.y(this->lry() + clen * sin(c.h()) + cw * sin(c.h() + M_PI / 2.0));
359         c.set_max_steer();
360         assert(this->parking_speed_ < 0.0);
361         c.sp(this->parking_speed_);
362         auto const rc = c.rf();
363         this->curb_.intersects_with(rc, c.len());
364         double max_to_slot;
365         auto const& rr = c.rr();
366         auto const& i1 = this->curb_.i1();
367         auto const& i2 = this->curb_.i2();
368         if (rr.edist(i1) < rr.edist(i2)) {
369                 max_to_slot = rr.min_angle_between(rc, i1);
370         } else {
371                 max_to_slot = rr.min_angle_between(rc, i2);
372         }
373         std::vector<BicycleCar> starts;
374         double a_to_slot = 0.0;
375         while (a_to_slot < max_to_slot) {
376                 a_to_slot += this->delta_angle_to_slot_;
377                 c.rotate(rc, this->delta_angle_to_slot_);
378                 starts.push_back(c);
379         }
380         std::vector<std::vector<BicycleCar>> entries;
381         for (auto s: starts) {
382                 auto r = this->drive_in_slot(s);
383                 if (r.size() > 0) {
384                         entries.push_back(r);
385                 }
386         }
387         if (entries.size() == 0) {
388                 return PoseRange(Pose(0.0, 0.0, 0.0), Pose(0.0, 0.0, 0.0));
389         }
390         if (entries.size() == 1) {
391                 auto f = entries.front().front();
392                 return PoseRange(f, f);
393         }
394         auto& c1 = entries.front().front();
395         auto& c2 = entries.back().front();
396         PoseRange p(c1, c2);
397         if (swapped) {
398                 this->swap_side();
399                 p.reflect(this->entry_);
400         }
401         return p;
402 }
403
404 PoseRange
405 ParkingSlot::recompute_entry(PoseRange p)
406 {
407         p.rotate(Point(0.0, 0.0), this->h());
408         p.translate(this->border_[0]);
409         if (!this->right()) {
410                 p.reflect(this->entry_);
411         }
412         return p;
413 }
414
415 std::ostream&
416 operator<<(std::ostream& o, ParkingSlot const& s)
417 {
418         o << "[";
419         o << s.border_[0] << ",";
420         o << s.border_[1] << ",";
421         o << s.border_[2] << ",";
422         o << s.border_[3];
423         o << "]";
424         return o;
425 }
426
427 } // namespace bcar