]> rtime.felk.cvut.cz Git - hubacji1/bcar.git/blob - src/bcar.cc
720057929894e40ababb4897f8142ab2987ac2a5
[hubacji1/bcar.git] / src / bcar.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 <cmath>
8 #include "bcar.hh"
9
10 namespace bcar {
11
12 Point::Point()
13 {
14 }
15
16 Point::Point(double x, double y) : _x(x), _y(y)
17 {
18 }
19
20 double
21 Point::x() const
22 {
23         return this->_x;
24 }
25
26 void
27 Point::x(double x)
28 {
29         this->_x = x;
30 }
31
32 double
33 Point::y() const
34 {
35         return this->_y;
36 }
37
38 void
39 Point::y(double y)
40 {
41         this->_y = y;
42 }
43
44 double
45 Point::min_angle_between(Point const& p1, Point const& p2) const
46 {
47         double d1x = p1.x() - this->x();
48         double d1y = p1.y() - this->y();
49         double d2x = p2.x() - p1.x();
50         double d2y = p2.y() - p1.y();
51
52         double dot = d1x*d2x + d1y*d2y;
53         double d1 = sqrt(d1x*d1x + d1y*d1y);
54         double d2 = sqrt(d2x*d2x + d2y*d2y);
55
56         double delta = acos(dot / (d1 * d2));
57         return std::min(delta, M_PI - delta);
58 }
59
60 bool
61 Point::inside_of(std::vector<Point> const& poly) const
62 {
63         unsigned int num = poly.size();
64         unsigned int j = num - 1;
65         bool c = false;
66         for (unsigned int i = 0; i < num; i++) {
67                 if (this->x() == poly[i].x() && this->y() == poly[i].y()) {
68                         return true;
69                 }
70                 if ((poly[i].y() > this->y()) != (poly[j].y() > this->y())) {
71                         auto slope1 = this->x() - poly[i].x();
72                         slope1 *= poly[j].y() - poly[i].y();
73                         auto slope2 = poly[j].x() - poly[i].x();
74                         slope2 *= this->y() - poly[i].y();
75                         auto slope = slope1 - slope2;
76                         if (slope == 0.0) {
77                                 return true;
78                         }
79                         if ((slope < 0.0) != (poly[j].y() < poly[i].y())) {
80                                 c = !c;
81                         }
82                 }
83                 j = i;
84         }
85         return c;
86 }
87
88 bool
89 Point::on_right_side_of(Line const& li) const
90 {
91         auto x1 = li.b().x();
92         auto y1 = li.b().y();
93         auto x2 = li.e().x();
94         auto y2 = li.e().y();
95         auto x3 = this->_x;
96         auto y3 = this->_y;
97         if (sgn((x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1)) < 0.0) {
98                 return false;
99         } else {
100                 return true;
101         }
102 }
103
104 void
105 Point::translate(Point const& p)
106 {
107         this->_x += p.x();
108         this->_y += p.y();
109 }
110
111 void
112 Point::rotate(Point const& c, double const angl)
113 {
114         double px = this->x();
115         double py = this->y();
116         px -= c.x();
117         py -= c.y();
118         double nx = px * cos(angl) - py * sin(angl);
119         double ny = px * sin(angl) + py * cos(angl);
120         this->x(nx + c.x());
121         this->y(ny + c.y());
122 }
123
124 void
125 Point::reflect(Line const& li)
126 {
127         this->rotate(li.b(), -li.h());
128         this->_y -= li.b().y();
129         this->_y *= -1.0;
130         this->_y += li.b().y();
131         this->rotate(li.b(), li.h());
132 }
133
134 double
135 Point::edist(Point const& p) const
136 {
137         return sqrt(pow(p.x() - this->_x, 2.0) + pow(p.y() - this->_y, 2.0));
138 }
139
140 void
141 Point::gen_gnuplot_to(std::ostream& out)
142 {
143         out << this->_x << " " << this->_y << std::endl;
144 }
145
146 bool
147 Point::operator==(Point const& p)
148 {
149         return this->x() == p.x() && this->y() == p.y();
150 }
151
152 std::ostream&
153 operator<<(std::ostream& out, Point const& p)
154 {
155         out << "[" << p.x() << "," << p.y() << "]";
156         return out;
157 }
158
159 Line::Line(Point const& b, Point const& e): _b(b), _e(e)
160 {
161 }
162
163 Point
164 Line::b() const&
165 {
166         return this->_b;
167 }
168
169 Point
170 Line::e() const&
171 {
172         return this->_e;
173 }
174
175 Point
176 Line::m() const
177 {
178         return Point((this->_b.x() + this->_e.x()) / 2.0,
179                 (this->_b.y() + this->_e.y()) / 2.0);
180 }
181
182 Point
183 Line::i1() const&
184 {
185         return this->_i1;
186 }
187
188 Point
189 Line::i2() const&
190 {
191         return this->_i2;
192 }
193
194 bool
195 Line::intersects_with(Line const& li)
196 {
197         auto x1 = this->_b.x();
198         auto y1 = this->_b.y();
199         auto x2 = this->_e.x();
200         auto y2 = this->_e.y();
201         auto x3 = li.b().x();
202         auto y3 = li.b().y();
203         auto x4 = li.e().x();
204         auto y4 = li.e().y();
205         double deno = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
206         if (deno == 0.0) {
207                 return false;
208         }
209         double t = (x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4);
210         t /= deno;
211         double u = (x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3);
212         u *= -1.0;
213         u /= deno;
214         if (t < 0.0 || t > 1.0 || u < 0.0 || u > 1.0) {
215                 return false;
216         }
217         this->_i1.x(x1 + t * (x2 - x1));
218         this->_i1.y(y1 + t * (y2 - y1));
219         return true;
220 }
221
222 bool
223 Line::intersects_with(Point const& c, double const r)
224 {
225         auto x1 = this->_b.x();
226         auto y1 = this->_b.y();
227         auto x2 = this->_e.x();
228         auto y2 = this->_e.y();
229         auto cx = c.x();
230         auto cy = c.y();
231         x2 -= cx;
232         x1 -= cx;
233         y2 -= cy;
234         y1 -= cy;
235         if (y1 == y2) {
236                 y1 += 0.00001;
237         }
238         double dx = x2 - x1;
239         double dy = y2 - y1;
240         double dr = sqrt(dx*dx + dy*dy);
241         double D = x1*y2 - x2*y1;
242         if (r*r * dr*dr - D*D < 0.0) {
243                 return false;
244         }
245         // intersection coordinates
246         double ix1 = (D*dy + sgn(dy)*dx*sqrt(r*r * dr*dr - D*D)) / (dr*dr);
247         ix1 += cx;
248         double ix2 = (D*dy - sgn(dy)*dx*sqrt(r*r * dr*dr - D*D)) / (dr*dr);
249         ix2 += cx;
250         double iy1 = (-D*dx + std::abs(dy)*sqrt(r*r * dr*dr - D*D)) / (dr*dr);
251         iy1 += cy;
252         double iy2 = (-D*dx - std::abs(dy)*sqrt(r*r * dr*dr - D*D)) / (dr*dr);
253         iy2 += cy;
254         this->_i1.x(ix1);
255         this->_i1.y(iy1);
256         this->_i2.x(ix2);
257         this->_i2.y(iy2);
258         return true;
259 }
260
261 double
262 Line::len() const
263 {
264         return this->_b.edist(this->_e);
265 }
266
267 double
268 Line::h() const
269 {
270         return atan2(this->_e.y() - this->_b.y(), this->_e.x() - this->_b.x());
271 }
272
273 std::ostream&
274 operator<<(std::ostream& out, Line const& li)
275 {
276         out << "[" << li._b << "," << li._e << "]";
277         return out;
278 }
279
280 Pose::Pose(double x, double y, double h) : Point(x, y), _h(h)
281 {
282 }
283
284 double
285 Pose::h() const
286 {
287         return this->_h;
288 }
289
290 void
291 Pose::h(double h)
292 {
293         while (h < -M_PI) {
294                 h += 2 * M_PI;
295         }
296         while (h > +M_PI) {
297                 h -= 2 * M_PI;
298         }
299         this->_h = h;
300 }
301
302 void
303 Pose::set_pose(Pose const& p)
304 {
305         this->x(p.x());
306         this->y(p.y());
307         this->h(p.h());
308 }
309
310 void
311 Pose::rotate(Point const& c, double const angl)
312 {
313         Point::rotate(c, angl);
314         this->h(this->h() + angl);
315 }
316
317 void
318 Pose::reflect(Line const& li)
319 {
320         Point::reflect(li);
321         double dh = li.h() - this->h();
322         this->h(this->h() + 2.0 * dh);
323 }
324
325 bool
326 Pose::operator==(Pose const& p)
327 {
328         return this->x() == p.x() && this->y() == p.y() && this->h() == p.h();
329 }
330
331 std::ostream&
332 operator<<(std::ostream& out, Pose const& p)
333 {
334         out << "[" << p.x() << "," << p.y() << "," << p.h() << "]";
335         return out;
336 }
337
338 void
339 PoseRange::set_xyh()
340 {
341         double clen = 10.0;
342         double bpbx = this->_bp.x() - clen * cos(this->_bp.h());
343         double bpby = this->_bp.y() - clen * sin(this->_bp.h());
344         double bpfx = this->_bp.x() + clen * cos(this->_bp.h());
345         double bpfy = this->_bp.y() + clen * sin(this->_bp.h());
346         Line li1(Point(bpbx, bpby), Point(bpfx, bpfy));
347         double epbx = this->_ep.x() - clen * cos(this->_ep.h());
348         double epby = this->_ep.y() - clen * sin(this->_ep.h());
349         double epfx = this->_ep.x() + clen * cos(this->_ep.h());
350         double epfy = this->_ep.y() + clen * sin(this->_ep.h());
351         Line li2(Point(epbx, epby), Point(epfx, epfy));
352         li1.intersects_with(li2);
353         this->x(li1.i1().x());
354         this->y(li1.i1().y());
355         double bh = this->b();
356         while (bh < 0.0) {
357                 bh += 2.0 * M_PI;
358         }
359         this->_bp.h(bh);
360         double eh = this->e();
361         while (eh < 0.0) {
362                 eh += 2.0 * M_PI;
363         }
364         this->_ep.h(eh);
365         this->h((this->b() + this->e()) / 2.0);
366 }
367
368 PoseRange::PoseRange(Pose bp, Pose ep) : _bp(bp), _ep(ep)
369 {
370         if (this->_bp == this->_ep) {
371                 this->set_pose(this->_ep);
372         } else {
373                 this->set_xyh();
374         }
375 }
376
377 PoseRange::PoseRange(double x, double y, double b, double e)
378                 : PoseRange(Pose(x, y, b), Pose(x, y, e))
379 {
380 }
381
382 Pose
383 PoseRange::bp() const
384 {
385         return this->_bp;
386 }
387
388 Pose
389 PoseRange::ep() const
390 {
391         return this->_ep;
392 }
393
394 double
395 PoseRange::b() const
396 {
397         return std::min(this->_bp.h(), this->_ep.h());
398 }
399
400 double
401 PoseRange::e() const
402 {
403         return std::max(this->_bp.h(), this->_ep.h());
404 }
405
406 void
407 PoseRange::translate(Point const& p)
408 {
409         this->_bp.translate(p);
410         this->_ep.translate(p);
411         this->set_xyh();
412 }
413
414 void
415 PoseRange::rotate(Point const& c, double const angl)
416 {
417         this->_bp.rotate(c, angl);
418         this->_ep.rotate(c, angl);
419         this->set_xyh();
420 }
421
422 void
423 PoseRange::reflect(Line const& li)
424 {
425         this->_bp.reflect(li);
426         this->_ep.reflect(li);
427         this->set_xyh();
428 }
429
430 std::ostream&
431 operator<<(std::ostream& out, PoseRange const& p)
432 {
433         out << "[" << p.x() << "," << p.y() << "," << p.b() << "," << p.e();
434         out << "]";
435         return out;
436 }
437
438 double
439 CarSize::ctc() const
440 {
441         return this->_curb_to_curb;
442 }
443
444 void
445 CarSize::ctc(double ctc)
446 {
447         this->_curb_to_curb = ctc;
448 }
449
450 double
451 CarSize::wb() const
452 {
453         return this->_wheelbase;
454 }
455
456 void
457 CarSize::wb(double wb)
458 {
459         this->_wheelbase = wb;
460 }
461
462 double
463 CarSize::w() const
464 {
465         return this->_width;
466 }
467
468 void
469 CarSize::w(double w)
470 {
471         this->_width = w;
472 }
473
474 double
475 CarSize::wwm() const
476 {
477         return this->_width_with_mirrors;
478 }
479
480 void
481 CarSize::wwm(double w)
482 {
483         this->_width_with_mirrors = w;
484 }
485
486 double
487 CarSize::len() const
488 {
489         return this->_length;
490 }
491
492 void
493 CarSize::len(double len)
494 {
495         this->_length = len;
496 }
497
498 double
499 CarSize::df() const
500 {
501         return this->_distance_to_front;
502 }
503
504 void
505 CarSize::df(double df)
506 {
507         this->_distance_to_front = df;
508 }
509
510 double
511 CarSize::dr() const
512 {
513         return this->len() - this->df();
514 }
515
516 void
517 CarSize::ft(double ft)
518 {
519         this->_front_track = ft;
520 }
521
522 double
523 CarSize::ft() const
524 {
525         return this->_front_track;
526 }
527
528 double
529 CarSize::mtr() const
530 {
531         auto ctc2 = pow(this->ctc() / 2.0, 2.0);
532         auto wb2 = pow(this->wb(), 2.0);
533         return sqrt(ctc2 - wb2) - this->ft() / 2.0;
534 }
535
536 double
537 CarSize::iradi() const
538 {
539         return this->mtr() - this->w() / 2;
540 }
541
542 double
543 CarSize::ofradi() const
544 {
545         auto mtrw2 = pow(this->mtr() + this->w() / 2.0, 2.0);
546         auto df2 = pow(this->df(), 2.0);
547         return sqrt(mtrw2 + df2);
548 }
549
550 double
551 CarSize::orradi() const
552 {
553         auto mtrw2 = pow(this->mtr() + this->w() / 2.0, 2.0);
554         auto dr2 = pow(this->dr(), 2.0);
555         return sqrt(mtrw2 + dr2);
556 }
557
558 double
559 CarSize::imradi() const
560 {
561         auto mtrw2 = pow(this->mtr() - this->wwm() / 2.0, 2.0);
562         auto df2 = pow(this->wb(), 2.0);
563         return sqrt(mtrw2 + df2);
564 }
565
566 double
567 CarSize::omradi() const
568 {
569         auto mtrw2 = pow(this->mtr() + this->wwm() / 2.0, 2.0);
570         auto df2 = pow(this->wb(), 2.0);
571         return sqrt(mtrw2 + df2);
572 }
573
574 double
575 CarSize::perfect_parking_slot_len() const
576 {
577         auto r = this->ctc() / 2.0;
578         auto l = this->wb();
579         auto k = this->df() - this->wb();
580         auto w = this->w(); // FIXME use wwm()?
581         auto r2l2 = r * r - l * l;
582         auto s = r2l2 + pow(l + k, 2.0) - pow(sqrt(r2l2) - w, 2.0);
583         return this->len() + sqrt(s) - l - k;
584 }
585
586 double
587 CarMove::sp() const
588 {
589         return this->_speed;
590 }
591
592 void
593 CarMove::sp(double sp)
594 {
595         this->_speed = sp;
596 }
597
598 double
599 CarMove::st() const
600 {
601         return this->_steer;
602 }
603
604 void
605 CarMove::st(double st)
606 {
607         this->_steer = st;
608 }
609
610 bool
611 BicycleCar::drivable(Pose const& p) const
612 {
613         return this->drivable(PoseRange(p, p));
614 }
615
616 bool
617 BicycleCar::drivable(PoseRange const& p) const
618 {
619         double a_1 = atan2(p.y() - this->y(), p.x() - this->x()) - this->h();
620         while (a_1 < -M_PI)
621                 a_1 += 2 * M_PI;
622         while (a_1 > +M_PI)
623                 a_1 -= 2 * M_PI;
624         double h_d = p.h() - this->h();
625         while (h_d < -M_PI)
626                 h_d += 2 * M_PI;
627         while (h_d > +M_PI)
628                 h_d -= 2 * M_PI;
629         double a_2 = 0;
630         if (h_d == 0 && (a_1 == 0 || a_2 == M_PI || a_2 == -M_PI)) {
631                 return true;
632         } else if (0 < a_1 && a_1 <= M_PI/2) { // left front
633                 BicycleCar z(*this); // zone border
634                 z.h(p.e());
635                 h_d = p.h() - this->h();
636                 z.rotate(this->ccl(), h_d);
637                 // assert z.h() == p.h()
638                 if (p.y() == z.y() && p.x() == z.x()) // p on zone border
639                         return true;
640                 a_2 = atan2(p.y() - z.y(), p.x() - z.x());
641                 while (a_2 < -M_PI)
642                         a_2 += 2 * M_PI;
643                 while (a_2 > +M_PI)
644                         a_2 -= 2 * M_PI;
645                 if (z.h() >= a_2 && a_2 >= this->h())
646                         return true;
647         } else if (M_PI/2 < a_1 && a_1 <= M_PI) { // left rear
648                 BicycleCar z(*this); // zone border
649                 z.h(p.e());
650                 h_d = p.h() - this->h();
651                 z.rotate(this->ccl(), h_d);
652                 // assert z.h() == p.h()
653                 if (p.y() == z.y() && p.x() == z.x()) // p on zone border
654                         return true;
655                 a_2 = atan2(p.y() - z.y(), p.x() - z.x());
656                 a_2 -= M_PI;
657                 while (a_2 < -M_PI)
658                         a_2 += 2 * M_PI;
659                 while (a_2 > +M_PI)
660                         a_2 -= 2 * M_PI;
661                 if (this->h() >= a_2 && a_2 >= z.h())
662                         return true;
663         } else if (0 > a_1 && a_1 >= -M_PI/2) { // right front
664                 BicycleCar z(*this); // zone border
665                 z.h(p.b());
666                 h_d = p.h() - this->h();
667                 z.rotate(this->ccr(), h_d);
668                 // assert z.h() == p.h()
669                 if (p.y() == z.y() && p.x() == z.x()) // p on zone border
670                         return true;
671                 a_2 = atan2(p.y() - z.y(), p.x() - z.x());
672                 while (a_2 < -M_PI)
673                         a_2 += 2 * M_PI;
674                 while (a_2 > +M_PI)
675                         a_2 -= 2 * M_PI;
676                 if (this->h() >= a_2 && a_2 >= z.h())
677                         return true;
678         } else if (-M_PI/2 > a_1 && a_1 >= -M_PI) { // right rear
679                 BicycleCar z(*this); // zone border
680                 z.h(p.b());
681                 h_d = p.h() - this->h();
682                 z.rotate(this->ccr(), h_d);
683                 // assert z.h() == p.h()
684                 if (p.y() == z.y() && p.x() == z.x()) // p on zone border
685                         return true;
686                 a_2 = atan2(p.y() - z.y(), p.x() - z.x());
687                 a_2 -= M_PI;
688                 while (a_2 < -M_PI)
689                         a_2 += 2 * M_PI;
690                 while (a_2 > +M_PI)
691                         a_2 -= 2 * M_PI;
692                 if (z.h() >= a_2 && a_2 >= this->h())
693                         return true;
694         } else {
695                 // Not happenning, as ``-pi <= a <= pi``.
696         }
697         return false;
698 }
699
700 void
701 BicycleCar::set_max_steer()
702 {
703         this->st(atan(this->wb() / this->mtr()));
704 }
705
706 double
707 BicycleCar::lfx() const
708 {
709         double lfx = this->x();
710         lfx += (this->w() / 2.0) * cos(this->h() + M_PI / 2.0);
711         lfx += this->df() * cos(this->h());
712         return lfx;
713 }
714
715 double
716 BicycleCar::lfy() const
717 {
718         double lfy = this->y();
719         lfy += (this->w() / 2.0) * sin(this->h() + M_PI / 2.0);
720         lfy += this->df() * sin(this->h());
721         return lfy;
722 }
723
724 double
725 BicycleCar::lrx() const
726 {
727         double lrx = this->x();
728         lrx += (this->w() / 2.0) * cos(this->h() + M_PI / 2.0);
729         lrx += -this->dr() * cos(this->h());
730         return lrx;
731 }
732
733 double
734 BicycleCar::lry() const
735 {
736         double lry = this->y();
737         lry += (this->w() / 2.0) * sin(this->h() + M_PI / 2.0);
738         lry += -this->dr() * sin(this->h());
739         return lry;
740 }
741
742 double
743 BicycleCar::rrx() const
744 {
745         double rrx = this->x();
746         rrx += (this->w() / 2.0) * cos(this->h() - M_PI / 2.0);
747         rrx += -this->dr() * cos(this->h());
748         return rrx;
749 }
750
751 double
752 BicycleCar::rry() const
753 {
754         double rry = this->y();
755         rry += (this->w() / 2.0) * sin(this->h() - M_PI / 2.0);
756         rry += -this->dr() * sin(this->h());
757         return rry;
758 }
759
760 double
761 BicycleCar::rfx() const
762 {
763         double rfx = this->x();
764         rfx += (this->w() / 2.0) * cos(this->h() - M_PI / 2.0);
765         rfx += this->df() * cos(this->h());
766         return rfx;
767 }
768
769 double
770 BicycleCar::rfy() const
771 {
772         double rfy = this->y();
773         rfy += (this->w() / 2.0) * sin(this->h() - M_PI / 2.0);
774         rfy += this->df() * sin(this->h());
775         return rfy;
776 }
777
778 Point
779 BicycleCar::lf() const
780 {
781         return Point(this->lfx(), this->lfy());
782 }
783
784 Point
785 BicycleCar::lr() const
786 {
787         return Point(this->lrx(), this->lry());
788 }
789
790 Point
791 BicycleCar::rr() const
792 {
793         return Point(this->rrx(), this->rry());
794 }
795
796 Point
797 BicycleCar::rf() const
798 {
799         return Point(this->rfx(), this->rfy());
800 }
801
802 Line
803 BicycleCar::left() const
804 {
805         return Line(this->lr(), this->lf());
806 }
807
808 Line
809 BicycleCar::rear() const
810 {
811         return Line(this->lr(), this->rr());
812 }
813
814 Line
815 BicycleCar::right() const
816 {
817         return Line(this->rr(), this->rf());
818 }
819
820 Line
821 BicycleCar::front() const
822 {
823         return Line(this->rf(), this->lf());
824 }
825
826 double
827 BicycleCar::lrax() const
828 {
829         double lrx = this->x();
830         lrx += (this->w() / 2.0) * cos(this->h() + M_PI / 2.0);
831         return lrx;
832 }
833 double
834 BicycleCar::lray() const
835 {
836         double lry = this->y();
837         lry += (this->w() / 2.0) * sin(this->h() + M_PI / 2.0);
838         return lry;
839 }
840
841 double
842 BicycleCar::rrax() const
843 {
844         double rrx = this->x();
845         rrx += (this->w() / 2.0) * cos(this->h() - M_PI / 2.0);
846         return rrx;
847 }
848
849 double
850 BicycleCar::rray() const
851 {
852         double rry = this->y();
853         rry += (this->w() / 2.0) * sin(this->h() - M_PI / 2.0);
854         return rry;
855 }
856
857 Point
858 BicycleCar::lra() const
859 {
860         return Point(this->lrax(), this->lray());
861 }
862
863 Point
864 BicycleCar::rra() const
865 {
866         return Point(this->rrax(), this->rray());
867 }
868
869 double
870 BicycleCar::lfax() const
871 {
872         return this->lrax() + this->wb() * cos(this->h());
873 }
874
875 double
876 BicycleCar::lfay() const
877 {
878         return this->lray() + this->wb() * sin(this->h());
879 }
880
881 double
882 BicycleCar::rfax() const
883 {
884         return this->rrax() + this->wb() * cos(this->h());
885 }
886
887 double
888 BicycleCar::rfay() const
889 {
890         return this->rray() + this->wb() * sin(this->h());
891 }
892
893 Point
894 BicycleCar::lfa() const
895 {
896         return Point(this->lfax(), this->lfay());
897 }
898
899 Point
900 BicycleCar::rfa() const
901 {
902         return Point(this->rfax(), this->rfay());
903 }
904
905 double
906 BicycleCar::lfmx() const
907 {
908         double x = this->x();
909         x += (this->wwm() / 2.0) * cos(this->h() + M_PI / 2.0);
910         x += this->wb() * cos(this->h());
911         return x;
912 }
913
914 double
915 BicycleCar::lfmy() const
916 {
917         double y = this->y();
918         y += (this->wwm() / 2.0) * sin(this->h() + M_PI / 2.0);
919         y += this->wb() * sin(this->h());
920         return y;
921 }
922
923 double
924 BicycleCar::rfmx() const
925 {
926         double x = this->x();
927         x += (this->wwm() / 2.0) * cos(this->h() - M_PI / 2.0);
928         x += this->wb() * cos(this->h());
929         return x;
930 }
931
932 double
933 BicycleCar::rfmy() const
934 {
935         double y = this->y();
936         y += (this->wwm() / 2.0) * sin(this->h() - M_PI / 2.0);
937         y += this->wb() * sin(this->h());
938         return y;
939 }
940
941 Point
942 BicycleCar::lfm() const
943 {
944         return Point(this->lfmx(), this->lfmy());
945 }
946
947 Point
948 BicycleCar::rfm() const
949 {
950         return Point(this->rfmx(), this->rfmy());
951 }
952
953 double
954 BicycleCar::cfx() const
955 {
956         return this->x() + this->df() * cos(this->h());
957 }
958
959 double
960 BicycleCar::cfy() const
961 {
962         return this->y() + this->df() * sin(this->h());
963 }
964
965 Point
966 BicycleCar::cf() const
967 {
968         return Point(this->cfx(), this->cfy());
969 }
970
971 Point
972 BicycleCar::ccl() const
973 {
974         return Point(
975                 this->x() + this->mtr() * cos(this->h() + M_PI / 2.0),
976                 this->y() + this->mtr() * sin(this->h() + M_PI / 2.0)
977         );
978 }
979
980 Point
981 BicycleCar::ccr() const
982 {
983         return Point(
984                 this->x() + this->mtr() * cos(this->h() - M_PI / 2.0),
985                 this->y() + this->mtr() * sin(this->h() - M_PI / 2.0)
986         );
987 }
988
989 void
990 BicycleCar::next()
991 {
992         this->x(this->x() + this->sp() * cos(this->h()));
993         this->y(this->y() + this->sp() * sin(this->h()));
994         this->h(this->h() + this->sp() / this->wb() * tan(this->st()));
995 }
996
997 void
998 BicycleCar::gen_gnuplot_to(std::ostream& out, GenPlotOpts opts)
999 {
1000         if (opts.ALL) {
1001                 opts.CAR = true;
1002                 opts.MIRRORS = true;
1003         }
1004         if (opts.MIRRORS) {
1005                 opts.LEFT_MIRROR = true;
1006                 opts.RIGHT_MIRROR = true;
1007         }
1008         if (opts.CAR) {
1009                 opts.FRAME = true;
1010                 opts.CROSS = true;
1011                 opts.ARROW = true;
1012         }
1013         if (opts.FRAME) {
1014                 opts.LEFT = true;
1015                 opts.RIGHT = true;
1016                 opts.REAR = true;
1017                 opts.FRONT = true;
1018         }
1019         if (opts.LF_POINT) {
1020                 this->lf().gen_gnuplot_to(out);
1021         }
1022         if (opts.LR_POINT) {
1023                 this->lr().gen_gnuplot_to(out);
1024         }
1025         if (opts.RR_POINT) {
1026                 this->rr().gen_gnuplot_to(out);
1027         }
1028         if (opts.RF_POINT) {
1029                 this->rf().gen_gnuplot_to(out);
1030         }
1031         if (opts.LFM_POINT) {
1032                 this->lfm().gen_gnuplot_to(out);
1033         }
1034         if (opts.RFM_POINT) {
1035                 this->rfm().gen_gnuplot_to(out);
1036         }
1037         if (opts.LEFT) {
1038                 this->lf().gen_gnuplot_to(out);
1039                 this->lr().gen_gnuplot_to(out);
1040                 out << std::endl;
1041         }
1042         if (opts.RIGHT) {
1043                 this->rf().gen_gnuplot_to(out);
1044                 this->rr().gen_gnuplot_to(out);
1045                 out << std::endl;
1046         }
1047         if (opts.REAR) {
1048                 this->lr().gen_gnuplot_to(out);
1049                 this->rr().gen_gnuplot_to(out);
1050                 out << std::endl;
1051         }
1052         if (opts.FRONT) {
1053                 this->lf().gen_gnuplot_to(out);
1054                 this->rf().gen_gnuplot_to(out);
1055                 out << std::endl;
1056         }
1057         if (opts.ARROW) {
1058                 this->cf().gen_gnuplot_to(out);
1059                 this->lfa().gen_gnuplot_to(out);
1060                 this->rfa().gen_gnuplot_to(out);
1061                 this->cf().gen_gnuplot_to(out);
1062                 out << std::endl;
1063         }
1064         if (opts.CROSS) {
1065                 double lx = this->x() + 0.2 * cos(this->h() + M_PI/2);
1066                 double rx = this->x() - 0.2 * cos(this->h() + M_PI/2);
1067                 double fx = this->x() + 0.2 * cos(this->h());
1068                 double bx = this->x() - 0.2 * cos(this->h()); // rear is back
1069                 double ly = this->y() + 0.2 * sin(this->h() + M_PI/2);
1070                 double ry = this->y() - 0.2 * sin(this->h() + M_PI/2);
1071                 double fy = this->y() + 0.2 * sin(this->h());
1072                 double by = this->y() - 0.2 * sin(this->h()); // rear is back
1073                 out << lx << " " << ly << std::endl;
1074                 out << rx << " " << ry << std::endl;
1075                 out << std::endl;
1076                 out << fx << " " << fy << std::endl;
1077                 out << bx << " " << by << std::endl;
1078                 out << std::endl;
1079         }
1080         if (opts.LEFT_MIRROR) {
1081                 this->lf().gen_gnuplot_to(out);
1082                 this->lfm().gen_gnuplot_to(out);
1083                 this->lr().gen_gnuplot_to(out);
1084                 out << std::endl;
1085
1086         }
1087         if (opts.RIGHT_MIRROR) {
1088                 this->rf().gen_gnuplot_to(out);
1089                 this->rfm().gen_gnuplot_to(out);
1090                 this->rr().gen_gnuplot_to(out);
1091                 out << std::endl;
1092         }
1093 }
1094
1095 } // namespace bcar