2 * SPDX-FileCopyrightText: 2021 Jiri Vlasak <jiri.vlasak.2@cvut.cz>
4 * SPDX-License-Identifier: GPL-3.0-only
16 Point::Point(double x, double y) : _x(x), _y(y)
45 Point::min_angle_between(Point const& p1, Point const& p2) const
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();
52 double dot = d1x*d2x + d1y*d2y;
53 double d1 = sqrt(d1x*d1x + d1y*d1y);
54 double d2 = sqrt(d2x*d2x + d2y*d2y);
56 double delta = acos(dot / (d1 * d2));
57 return std::min(delta, M_PI - delta);
61 Point::inside_of(std::vector<Point> const& poly) const
63 unsigned int num = poly.size();
64 unsigned int j = num - 1;
66 for (unsigned int i = 0; i < num; i++) {
67 if (this->x() == poly[i].x() && this->y() == poly[i].y()) {
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;
79 if ((slope < 0.0) != (poly[j].y() < poly[i].y())) {
89 Point::inside_of(Point const& c, double const r) const
91 double dx = this->x() - c.x();
92 double dy = this->y() - c.y();
93 return pow(dx, 2.0) + pow(dy, 2.0) < pow(r, 2.0);
97 Point::on_right_side_of(Line const& li) const
100 auto y1 = li.b().y();
101 auto x2 = li.e().x();
102 auto y2 = li.e().y();
105 if (sgn((x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1)) < 0.0) {
113 Point::translate(Point const& p)
120 Point::rotate(Point const& c, double const angl)
122 double px = this->x();
123 double py = this->y();
126 double nx = px * cos(angl) - py * sin(angl);
127 double ny = px * sin(angl) + py * cos(angl);
133 Point::reflect(Line const& li)
135 this->rotate(li.b(), -li.h());
136 this->_y -= li.b().y();
138 this->_y += li.b().y();
139 this->rotate(li.b(), li.h());
143 Point::edist(Point const& p) const
145 return sqrt(pow(p.x() - this->_x, 2.0) + pow(p.y() - this->_y, 2.0));
149 Point::arc_len(Point const& p, double r)
151 return 2 * r * asin(this->edist(p) / 2 / r);
155 Point::gen_gnuplot_to(std::ostream& out)
157 out << this->_x << " " << this->_y << std::endl;
161 Point::operator==(Point const& p)
163 return this->x() == p.x() && this->y() == p.y();
167 operator<<(std::ostream& out, Point const& p)
169 out << "[" << p.x() << "," << p.y() << "]";
173 Line::Line(Point const& b, Point const& e): _b(b), _e(e)
192 return Point((this->_b.x() + this->_e.x()) / 2.0,
193 (this->_b.y() + this->_e.y()) / 2.0);
209 Line::intersects_with(Line const& li)
211 auto x1 = this->_b.x();
212 auto y1 = this->_b.y();
213 auto x2 = this->_e.x();
214 auto y2 = this->_e.y();
215 auto x3 = li.b().x();
216 auto y3 = li.b().y();
217 auto x4 = li.e().x();
218 auto y4 = li.e().y();
219 double deno = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
223 double t = (x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4);
225 double u = (x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3);
228 if (t < 0.0 || t > 1.0 || u < 0.0 || u > 1.0) {
231 this->_i1.x(x1 + t * (x2 - x1));
232 this->_i1.y(y1 + t * (y2 - y1));
237 Line::intersects_with(Point const& c, double const r)
239 auto x1 = this->_b.x();
240 auto y1 = this->_b.y();
241 auto x2 = this->_e.x();
242 auto y2 = this->_e.y();
254 double dr = sqrt(dx*dx + dy*dy);
255 double D = x1*y2 - x2*y1;
256 if (r*r * dr*dr - D*D < 0.0) {
259 // intersection coordinates
260 double ix1 = (D*dy + sgn(dy)*dx*sqrt(r*r * dr*dr - D*D)) / (dr*dr);
262 double ix2 = (D*dy - sgn(dy)*dx*sqrt(r*r * dr*dr - D*D)) / (dr*dr);
264 double iy1 = (-D*dx + std::abs(dy)*sqrt(r*r * dr*dr - D*D)) / (dr*dr);
266 double iy2 = (-D*dx - std::abs(dy)*sqrt(r*r * dr*dr - D*D)) / (dr*dr);
278 return this->_b.edist(this->_e);
284 return atan2(this->_e.y() - this->_b.y(), this->_e.x() - this->_b.x());
288 Line::gen_gnuplot_to(std::ostream& out)
290 this->b().gen_gnuplot_to(out);
291 this->e().gen_gnuplot_to(out);
296 operator<<(std::ostream& out, Line const& li)
298 out << "[" << li._b << "," << li._e << "]";
302 Pose::Pose(double x, double y, double h) : Point(x, y), _h(h)
325 Pose::set_pose_to(Pose const& p)
333 Pose::rotate(Point const& c, double const angl)
335 Point::rotate(c, angl);
336 this->h(this->h() + angl);
340 Pose::reflect(Line const& li)
343 double dh = li.h() - this->h();
344 this->h(this->h() + 2.0 * dh);
348 Pose::operator==(Pose const& p)
350 return this->x() == p.x() && this->y() == p.y() && this->h() == p.h();
354 operator<<(std::ostream& out, Pose const& p)
356 out << "[" << p.x() << "," << p.y() << "," << p.h() << "]";
364 double bpbx = this->_bp.x() - clen * cos(this->_bp.h());
365 double bpby = this->_bp.y() - clen * sin(this->_bp.h());
366 double bpfx = this->_bp.x() + clen * cos(this->_bp.h());
367 double bpfy = this->_bp.y() + clen * sin(this->_bp.h());
368 Line li1(Point(bpbx, bpby), Point(bpfx, bpfy));
369 double epbx = this->_ep.x() - clen * cos(this->_ep.h());
370 double epby = this->_ep.y() - clen * sin(this->_ep.h());
371 double epfx = this->_ep.x() + clen * cos(this->_ep.h());
372 double epfy = this->_ep.y() + clen * sin(this->_ep.h());
373 Line li2(Point(epbx, epby), Point(epfx, epfy));
374 li1.intersects_with(li2);
375 this->x(li1.i1().x());
376 this->y(li1.i1().y());
377 double bh = this->b();
382 double eh = this->e();
387 this->h((this->b() + this->e()) / 2.0);
390 PoseRange::PoseRange(Pose bp, Pose ep) : _bp(bp), _ep(ep)
392 if (this->_bp == this->_ep) {
393 this->set_pose_to(this->_ep);
399 PoseRange::PoseRange(double x, double y, double b, double e)
400 : PoseRange(Pose(x, y, b), Pose(x, y, e))
405 PoseRange::bp() const
411 PoseRange::ep() const
419 return std::min(this->_bp.h(), this->_ep.h());
425 return std::max(this->_bp.h(), this->_ep.h());
429 PoseRange::translate(Point const& p)
431 this->_bp.translate(p);
432 this->_ep.translate(p);
437 PoseRange::rotate(Point const& c, double const angl)
439 this->_bp.rotate(c, angl);
440 this->_ep.rotate(c, angl);
445 PoseRange::reflect(Line const& li)
447 this->_bp.reflect(li);
448 this->_ep.reflect(li);
453 operator<<(std::ostream& out, PoseRange const& p)
455 out << "[" << p.x() << "," << p.y() << "," << p.b() << "," << p.e();
463 return this->_curb_to_curb;
467 CarSize::ctc(double ctc)
469 this->_curb_to_curb = ctc;
475 return this->_wheelbase;
479 CarSize::wb(double wb)
481 this->_wheelbase = wb;
499 return this->_width_with_mirrors;
503 CarSize::wwm(double w)
505 this->_width_with_mirrors = w;
511 return this->_length;
515 CarSize::len(double len)
523 return this->_distance_to_front;
527 CarSize::df(double df)
529 this->_distance_to_front = df;
535 return this->len() - this->df();
539 CarSize::ft(double ft)
541 this->_front_track = ft;
547 return this->_front_track;
551 CarSize::edist_to_rr() const
553 return sqrt(pow(this->w() / 2.0, 2) + pow(this->len() - this->df(), 2));
557 CarSize::edist_to_lf() const
559 return sqrt(pow(this->w() / 2.0, 2) + pow(this->df(), 2));
565 auto ctc2 = pow(this->ctc() / 2.0, 2.0);
566 auto wb2 = pow(this->wb(), 2.0);
567 return sqrt(ctc2 - wb2) - this->ft() / 2.0;
571 CarSize::iradi() const
573 return this->mtr() - this->w() / 2;
577 CarSize::ofradi() const
579 auto mtrw2 = pow(this->mtr() + this->w() / 2.0, 2.0);
580 auto df2 = pow(this->df(), 2.0);
581 return sqrt(mtrw2 + df2);
585 CarSize::orradi() const
587 auto mtrw2 = pow(this->mtr() + this->w() / 2.0, 2.0);
588 auto dr2 = pow(this->dr(), 2.0);
589 return sqrt(mtrw2 + dr2);
593 CarSize::imradi() const
595 auto mtrw2 = pow(this->mtr() - this->wwm() / 2.0, 2.0);
596 auto df2 = pow(this->wb(), 2.0);
597 return sqrt(mtrw2 + df2);
601 CarSize::omradi() const
603 auto mtrw2 = pow(this->mtr() + this->wwm() / 2.0, 2.0);
604 auto df2 = pow(this->wb(), 2.0);
605 return sqrt(mtrw2 + df2);
609 CarSize::perfect_parking_slot_len() const
611 auto r = this->ctc() / 2.0;
613 auto k = this->df() - this->wb();
614 auto w = this->w(); // FIXME use wwm()?
615 auto r2l2 = r * r - l * l;
616 auto s = r2l2 + pow(l + k, 2.0) - pow(sqrt(r2l2) - w, 2.0);
617 return this->len() + sqrt(s) - l - k;
621 CarSize::become(std::string const what)
623 if (what == "porsche cayenne") {
628 this->df(this->wb() + 0.936);
631 } else if (what == "chrysler pacifica" || what == "jhang2020") {
632 this->ctc(9.557619159602458);
639 } else if (what == "wang2017") {
640 this->ctc(8.411896337925237);
643 this->wb(2.7); // this is guess
644 this->df(3.7); // this is guess
646 this->ft(1.6); // this is guess
647 } else if (what == "opel corsa") {
655 } else { // renault zoe
656 this->ctc(10.802166641822163);
673 CarMove::sp(double sp)
685 CarMove::st(double st)
691 BicycleCar::drivable(Pose const& p) const
693 return this->drivable(PoseRange(p, p));
697 BicycleCar::drivable(PoseRange const& p) const
699 double a_1 = atan2(p.y() - this->y(), p.x() - this->x()) - this->h();
704 double h_d = p.h() - this->h();
710 if (h_d == 0 && (a_1 == 0 || a_2 == M_PI || a_2 == -M_PI)) {
712 } else if (0 < a_1 && a_1 <= M_PI/2) { // left front
713 BicycleCar z(*this); // zone border
715 h_d = p.h() - this->h();
716 z.rotate(this->ccl(), h_d);
717 // assert z.h() == p.h()
718 if (p.y() == z.y() && p.x() == z.x()) // p on zone border
720 a_2 = atan2(p.y() - z.y(), p.x() - z.x());
725 if (z.h() >= a_2 && a_2 >= this->h())
727 } else if (M_PI/2 < a_1 && a_1 <= M_PI) { // left rear
728 BicycleCar z(*this); // zone border
730 h_d = p.h() - this->h();
731 z.rotate(this->ccl(), h_d);
732 // assert z.h() == p.h()
733 if (p.y() == z.y() && p.x() == z.x()) // p on zone border
735 a_2 = atan2(p.y() - z.y(), p.x() - z.x());
741 if (this->h() >= a_2 && a_2 >= z.h())
743 } else if (0 > a_1 && a_1 >= -M_PI/2) { // right front
744 BicycleCar z(*this); // zone border
746 h_d = p.h() - this->h();
747 z.rotate(this->ccr(), h_d);
748 // assert z.h() == p.h()
749 if (p.y() == z.y() && p.x() == z.x()) // p on zone border
751 a_2 = atan2(p.y() - z.y(), p.x() - z.x());
756 if (this->h() >= a_2 && a_2 >= z.h())
758 } else if (-M_PI/2 > a_1 && a_1 >= -M_PI) { // right rear
759 BicycleCar z(*this); // zone border
761 h_d = p.h() - this->h();
762 z.rotate(this->ccr(), h_d);
763 // assert z.h() == p.h()
764 if (p.y() == z.y() && p.x() == z.x()) // p on zone border
766 a_2 = atan2(p.y() - z.y(), p.x() - z.x());
772 if (z.h() >= a_2 && a_2 >= this->h())
775 // Not happenning, as ``-pi <= a <= pi``.
781 BicycleCar::set_max_steer()
783 this->st(atan(this->wb() / this->mtr()));
787 BicycleCar::lfx() const
789 double lfx = this->x();
790 lfx += (this->w() / 2.0) * cos(this->h() + M_PI / 2.0);
791 lfx += this->df() * cos(this->h());
796 BicycleCar::lfy() const
798 double lfy = this->y();
799 lfy += (this->w() / 2.0) * sin(this->h() + M_PI / 2.0);
800 lfy += this->df() * sin(this->h());
805 BicycleCar::lrx() const
807 double lrx = this->x();
808 lrx += (this->w() / 2.0) * cos(this->h() + M_PI / 2.0);
809 lrx += -this->dr() * cos(this->h());
814 BicycleCar::lry() const
816 double lry = this->y();
817 lry += (this->w() / 2.0) * sin(this->h() + M_PI / 2.0);
818 lry += -this->dr() * sin(this->h());
823 BicycleCar::rrx() const
825 double rrx = this->x();
826 rrx += (this->w() / 2.0) * cos(this->h() - M_PI / 2.0);
827 rrx += -this->dr() * cos(this->h());
832 BicycleCar::rry() const
834 double rry = this->y();
835 rry += (this->w() / 2.0) * sin(this->h() - M_PI / 2.0);
836 rry += -this->dr() * sin(this->h());
841 BicycleCar::rfx() const
843 double rfx = this->x();
844 rfx += (this->w() / 2.0) * cos(this->h() - M_PI / 2.0);
845 rfx += this->df() * cos(this->h());
850 BicycleCar::rfy() const
852 double rfy = this->y();
853 rfy += (this->w() / 2.0) * sin(this->h() - M_PI / 2.0);
854 rfy += this->df() * sin(this->h());
859 BicycleCar::lf() const
861 return Point(this->lfx(), this->lfy());
865 BicycleCar::lr() const
867 return Point(this->lrx(), this->lry());
871 BicycleCar::rr() const
873 return Point(this->rrx(), this->rry());
877 BicycleCar::rf() const
879 return Point(this->rfx(), this->rfy());
883 BicycleCar::left() const
885 return Line(this->lr(), this->lf());
889 BicycleCar::rear() const
891 return Line(this->lr(), this->rr());
895 BicycleCar::right() const
897 return Line(this->rr(), this->rf());
901 BicycleCar::front() const
903 return Line(this->rf(), this->lf());
907 BicycleCar::lrax() const
909 double lrx = this->x();
910 lrx += (this->w() / 2.0) * cos(this->h() + M_PI / 2.0);
914 BicycleCar::lray() const
916 double lry = this->y();
917 lry += (this->w() / 2.0) * sin(this->h() + M_PI / 2.0);
922 BicycleCar::rrax() const
924 double rrx = this->x();
925 rrx += (this->w() / 2.0) * cos(this->h() - M_PI / 2.0);
930 BicycleCar::rray() const
932 double rry = this->y();
933 rry += (this->w() / 2.0) * sin(this->h() - M_PI / 2.0);
938 BicycleCar::lra() const
940 return Point(this->lrax(), this->lray());
944 BicycleCar::rra() const
946 return Point(this->rrax(), this->rray());
950 BicycleCar::lfax() const
952 return this->lrax() + this->wb() * cos(this->h());
956 BicycleCar::lfay() const
958 return this->lray() + this->wb() * sin(this->h());
962 BicycleCar::rfax() const
964 return this->rrax() + this->wb() * cos(this->h());
968 BicycleCar::rfay() const
970 return this->rray() + this->wb() * sin(this->h());
974 BicycleCar::lfa() const
976 return Point(this->lfax(), this->lfay());
980 BicycleCar::rfa() const
982 return Point(this->rfax(), this->rfay());
986 BicycleCar::lfmx() const
988 double x = this->x();
989 x += (this->wwm() / 2.0) * cos(this->h() + M_PI / 2.0);
990 x += this->wb() * cos(this->h());
995 BicycleCar::lfmy() const
997 double y = this->y();
998 y += (this->wwm() / 2.0) * sin(this->h() + M_PI / 2.0);
999 y += this->wb() * sin(this->h());
1004 BicycleCar::rfmx() const
1006 double x = this->x();
1007 x += (this->wwm() / 2.0) * cos(this->h() - M_PI / 2.0);
1008 x += this->wb() * cos(this->h());
1013 BicycleCar::rfmy() const
1015 double y = this->y();
1016 y += (this->wwm() / 2.0) * sin(this->h() - M_PI / 2.0);
1017 y += this->wb() * sin(this->h());
1022 BicycleCar::lfm() const
1024 return Point(this->lfmx(), this->lfmy());
1028 BicycleCar::rfm() const
1030 return Point(this->rfmx(), this->rfmy());
1034 BicycleCar::cfx() const
1036 return this->x() + this->df() * cos(this->h());
1040 BicycleCar::cfy() const
1042 return this->y() + this->df() * sin(this->h());
1046 BicycleCar::cf() const
1048 return Point(this->cfx(), this->cfy());
1052 BicycleCar::ccl() const
1055 this->x() + this->mtr() * cos(this->h() + M_PI / 2.0),
1056 this->y() + this->mtr() * sin(this->h() + M_PI / 2.0)
1061 BicycleCar::ccr() const
1064 this->x() + this->mtr() * cos(this->h() - M_PI / 2.0),
1065 this->y() + this->mtr() * sin(this->h() - M_PI / 2.0)
1072 this->x(this->x() + this->sp() * cos(this->h()));
1073 this->y(this->y() + this->sp() * sin(this->h()));
1074 this->h(this->h() + this->sp() / this->wb() * tan(this->st()));
1078 BicycleCar::gen_gnuplot_to(std::ostream& out, GenPlotOpts opts)
1082 opts.MIRRORS = true;
1085 opts.LEFT_MIRROR = true;
1086 opts.RIGHT_MIRROR = true;
1099 if (opts.LF_POINT) {
1100 this->lf().gen_gnuplot_to(out);
1102 if (opts.LR_POINT) {
1103 this->lr().gen_gnuplot_to(out);
1105 if (opts.RR_POINT) {
1106 this->rr().gen_gnuplot_to(out);
1108 if (opts.RF_POINT) {
1109 this->rf().gen_gnuplot_to(out);
1111 if (opts.LFM_POINT) {
1112 this->lfm().gen_gnuplot_to(out);
1114 if (opts.RFM_POINT) {
1115 this->rfm().gen_gnuplot_to(out);
1117 if (opts.CRA_POINT || opts.CAR_POINT) {
1118 Point::gen_gnuplot_to(out);
1120 if (opts.LRA_POINT) {
1121 this->lra().gen_gnuplot_to(out);
1123 if (opts.RRA_POINT) {
1124 this->rra().gen_gnuplot_to(out);
1127 this->lf().gen_gnuplot_to(out);
1128 this->lr().gen_gnuplot_to(out);
1132 this->rf().gen_gnuplot_to(out);
1133 this->rr().gen_gnuplot_to(out);
1137 this->lr().gen_gnuplot_to(out);
1138 this->rr().gen_gnuplot_to(out);
1142 this->lf().gen_gnuplot_to(out);
1143 this->rf().gen_gnuplot_to(out);
1147 this->cf().gen_gnuplot_to(out);
1148 this->lfa().gen_gnuplot_to(out);
1149 this->rfa().gen_gnuplot_to(out);
1150 this->cf().gen_gnuplot_to(out);
1154 double lx = this->x() + 0.2 * cos(this->h() + M_PI/2);
1155 double rx = this->x() - 0.2 * cos(this->h() + M_PI/2);
1156 double fx = this->x() + 0.2 * cos(this->h());
1157 double bx = this->x() - 0.2 * cos(this->h()); // rear is back
1158 double ly = this->y() + 0.2 * sin(this->h() + M_PI/2);
1159 double ry = this->y() - 0.2 * sin(this->h() + M_PI/2);
1160 double fy = this->y() + 0.2 * sin(this->h());
1161 double by = this->y() - 0.2 * sin(this->h()); // rear is back
1162 out << lx << " " << ly << std::endl;
1163 out << rx << " " << ry << std::endl;
1165 out << fx << " " << fy << std::endl;
1166 out << bx << " " << by << std::endl;
1169 if (opts.LEFT_MIRROR) {
1170 this->lf().gen_gnuplot_to(out);
1171 this->lfm().gen_gnuplot_to(out);
1172 this->lr().gen_gnuplot_to(out);
1176 if (opts.RIGHT_MIRROR) {
1177 this->rf().gen_gnuplot_to(out);
1178 this->rfm().gen_gnuplot_to(out);
1179 this->rr().gen_gnuplot_to(out);