]> rtime.felk.cvut.cz Git - hubacji1/bcar.git/blob - src/pslot.cc
Merge branch 'change/to-reuse.software'
[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 void
159 ParkingSlot::set_max_cusp(unsigned int m)
160 {
161         this->max_cusp_ = m;
162 }
163
164 void
165 ParkingSlot::set_delta_angle_to_slot(double d)
166 {
167         this->delta_angle_to_slot_ = d;
168 }
169
170 bool
171 ParkingSlot::parallel() const
172 {
173         return this->entry_.len() > this->rear_.len();
174 }
175
176 bool
177 ParkingSlot::right() const
178 {
179         return this->border_[1].on_right_side_of(this->entry_);
180 }
181
182 void
183 ParkingSlot::swap_side()
184 {
185         this->border_[1].rotate(this->border_[0], M_PI);
186         this->border_[2].rotate(this->border_[3], M_PI);
187         this->entry_ = Line(this->border_[0], this->border_[3]);
188         this->rear_ = Line(this->border_[0], this->border_[1]);
189         this->curb_ = Line(this->border_[1], this->border_[2]);
190         this->front_ = Line(this->border_[2], this->border_[3]);
191 }
192
193 bool
194 ParkingSlot::parked(BicycleCar const& c) const
195 {
196         auto b_len = sizeof(this->border_) / sizeof(this->border_[0]);
197         std::vector<Point> b(this->border_, this->border_ + b_len);
198         return c.lf().inside_of(b) && c.lr().inside_of(b)
199                 && c.rr().inside_of(b) && c.rf().inside_of(b);
200 }
201
202 bool
203 ParkingSlot::collide(BicycleCar const& c) const
204 {
205         return c.left().intersects_with(this->rear_)
206                 || c.left().intersects_with(this->curb_)
207                 || c.left().intersects_with(this->front_)
208                 || c.rear().intersects_with(this->rear_)
209                 || c.rear().intersects_with(this->curb_)
210                 || c.rear().intersects_with(this->front_)
211                 || c.right().intersects_with(this->rear_)
212                 || c.right().intersects_with(this->curb_)
213                 || c.right().intersects_with(this->front_)
214                 || c.front().intersects_with(this->rear_)
215                 || c.front().intersects_with(this->curb_)
216                 || c.front().intersects_with(this->front_);
217 }
218
219 std::vector<BicycleCar>
220 ParkingSlot::drive_in_slot(BicycleCar c)
221 {
222         assert(this->parallel());
223         assert(this->right());
224         assert(c.len() < this->len());
225         assert(c.w() < this->w());
226         std::vector<BicycleCar> path;
227         path.reserve(this->max_cusp_ + 2);
228         path.push_back(c);
229         unsigned int cusp = 0;
230         while (cusp < this->max_cusp_ + 1) {
231                 if (this->parked(c)) {
232                         if (cusp < this->max_cusp_) {
233                                 this->max_cusp_ = cusp;
234                         }
235                         path.push_back(c);
236                         return path;
237                 }
238                 double sx = c.x() + 10.0 * cos(this->h());
239                 double sy = c.y() + 10.0 * sin(this->h());
240                 double cx = c.x() + 10.0 * cos(c.h());
241                 double cy = c.y() + 10.0 * sin(c.h());
242                 if (Point(cx, cy).on_right_side_of(
243                                 Line(Point(c.x(), c.y()), Point(sx, sy)))) {
244                         return std::vector<BicycleCar>();
245                 }
246                 c.next();
247                 if (this->collide(c)) {
248                         c.sp(c.sp() * -1.0);
249                         c.next();
250                         path.push_back(c);
251                         c.st(c.st() * -1.0);
252                         cusp += 1;
253                 }
254         }
255         return std::vector<BicycleCar>();
256 }
257
258 std::vector<Pose>
259 ParkingSlot::steer_in_slot(BicycleCar c)
260 {
261         std::vector<Pose> path;
262         while (!this->parked(c)) {
263                 path.push_back(c);
264                 c.next();
265                 if (this->collide(c)) {
266                         c.sp(c.sp() * -1.0);
267                         c.next();
268                         c.st(c.st() * -1.0);
269                 }
270         }
271         return path;
272 }
273
274 PoseRange
275 ParkingSlot::fe(BicycleCar c)
276 {
277         if (!this->parallel()) {
278                 double gd = 0.0;
279                 double dd = 0.0;
280                 double radi = 0.0;
281                 if (this->parking_speed_ < 0) {
282                         gd = c.df();
283                         c.h(this->rear_.h() + M_PI);
284                         c.sp(1.0);
285                         radi = c.iradi();
286                 } else {
287                         gd = c.dr();
288                         c.h(this->rear_.h());
289                         c.sp(-1.0);
290                         radi = c.ofradi();
291                 }
292                 c.x(this->entry_.m().x() + gd * cos(this->rear_.h()));
293                 c.y(this->entry_.m().y() + gd * sin(this->rear_.h()));
294                 Point cc(0.0, 0.0);
295                 if (this->right()) {
296                         cc = c.ccl();
297                 } else {
298                         cc = c.ccr();
299                 }
300                 this->rear_.intersects_with(cc, radi);
301                 dd = std::min(this->border_[0].edist(this->rear_.i1()),
302                         this->border_[0].edist(this->rear_.i2()));
303                 c.st(0.0);
304                 c.sp(c.sp() * dd);
305                 c.next();
306                 c.sp(this->parking_speed_);
307                 return PoseRange(c.x(), c.y(), c.h(), c.h());
308         }
309         bool swapped = false;
310         if (!this->right()) {
311                 this->swap_side();
312                 swapped = true;
313         }
314         c.h(this->h());
315         double clen = -this->offset_ + this->len() - c.df();
316         double cw = c.w() / 2.0;
317         c.x(this->lrx() + clen * cos(c.h()) + cw * cos(c.h() + M_PI / 2.0));
318         c.y(this->lry() + clen * sin(c.h()) + cw * sin(c.h() + M_PI / 2.0));
319         c.set_max_steer();
320         c.sp(this->parking_speed_);
321         auto const rc = c.rf();
322         this->curb_.intersects_with(rc, c.len());
323         double max_to_slot;
324         auto const& rr = c.rr();
325         auto const& i1 = this->curb_.i1();
326         auto const& i2 = this->curb_.i2();
327         if (rr.edist(i1) < rr.edist(i2)) {
328                 max_to_slot = rr.min_angle_between(rc, i1);
329         } else {
330                 max_to_slot = rr.min_angle_between(rc, i2);
331         }
332         std::vector<BicycleCar> starts;
333         double a_to_slot = 0.0;
334         while (a_to_slot < max_to_slot) {
335                 a_to_slot += this->delta_angle_to_slot_;
336                 c.rotate(rc, this->delta_angle_to_slot_);
337                 starts.push_back(c);
338         }
339         std::vector<std::vector<BicycleCar>> entries;
340         for (auto s: starts) {
341                 auto r = this->drive_in_slot(s);
342                 if (r.size() > 0) {
343                         entries.push_back(r);
344                 }
345         }
346         if (entries.size() == 0) {
347                 return PoseRange(Pose(0.0, 0.0, 0.0), Pose(0.0, 0.0, 0.0));
348         }
349         if (entries.size() == 1) {
350                 auto f = entries.front().front();
351                 return PoseRange(f, f);
352         }
353         auto& c1 = entries.front().front();
354         auto& c2 = entries.back().front();
355         PoseRange p(c1, c2);
356         if (swapped) {
357                 this->swap_side();
358                 p.reflect(this->entry_);
359         }
360         return p;
361 }
362
363 PoseRange
364 ParkingSlot::recompute_entry(PoseRange p)
365 {
366         p.rotate(Point(0.0, 0.0), this->h());
367         p.translate(this->border_[0]);
368         if (!this->right()) {
369                 p.reflect(this->entry_);
370         }
371         return p;
372 }
373
374 std::ostream&
375 operator<<(std::ostream& o, ParkingSlot const& s)
376 {
377         o << "[";
378         o << s.border_[0] << ",";
379         o << s.border_[1] << ",";
380         o << s.border_[2] << ",";
381         o << s.border_[3];
382         o << "]";
383         return o;
384 }
385
386 } // namespace bcar