【基础函数-圆相关】

在apollo的common中没有圆相关的计算,而在路径规划领域圆相关的计算也有一些应用,尤其是泊车规划,目前整理了一些基本的公式使用。

基本定义

定一个圆为圆心坐标和半径r

class Circle
{
  private:
  double x_;
  double y_;
  double r_;
  Circle() : x_(0), y_(0), r_(0) {}
  Circle(double a, double b, double c) : x_(a), y_(b), r_(c) {}
}

圆的方程有一般式和标准式:
x2+y2+Dx+Ey+F=0, (D2+E2-4F>0),或可以表示为
( x + D / 2 ) 2 + ( x + E / 2 ) 2 = ( D 2 + E 2 − 4 F ) / 4 (x+D/2)^2+(x+E/2)^2=(D^2+E^2-4F)/4 (x+D/2)2+(x+E/2)2=(D2+E24F)/4
如果(1)圆半径长r;(2)中心A的坐标(a,b),标准方程就是:
( x − a ) 2 + ( y − b ) 2 = r 2 (x-a)^2+(y-b)^2=r^2 (xa)2+(yb)2=r2

三点确定一个圆心

设圆心坐标O为 ( x 0 , y 0 ) (x_0,y_0) (x0,y0),半径为r,三个点的坐标分别是,A ( x 1 , y 1 ) (x_1,y_1) (x1,y1),B ( x 2 , y 2 ) (x_2,y_2) (x2,y2)),C ( x 3 , y 3 ) (x_3,y_3) (x3,y3)
根据三个点到圆心的距离相等:
在这里插入图片描述
化简可以得到:
在这里插入图片描述
其中:
在这里插入图片描述
此处参考:三点定圆推导公式
首先判断三点是否共线,如果共线则不存在圆

 bool Circle::CalCircle(const Vec2d &pt1, const Vec2d &pt2, const Vec2d &pt3, Vec2d &center)
            {
                if (Line::ThreePointsIsCollinear(pt1, pt2, pt3))
                {
                    return false;
                }
                double a = pt1.x() - pt2.x();
                double b = pt1.y() - pt2.y();
                double c = pt1.x() - pt3.x();
                double d = pt1.y() - pt3.y();
                double e = ((pt1.x() * pt1.x() - pt2.x() * pt2.x()) - (pt2.y() * pt2.y() - pt1.y() * pt1.y())) / 2;
                double f = ((pt1.x() * pt1.x() - pt3.x() * pt3.x()) - (pt3.y() * pt3.y() - pt1.y() * pt1.y())) / 2;

                // 圆心位置
                double x = (e * d - b * f) / (a * d - b * c);
                double y = (a * f - e * c) / (a * d - b * c);
                center.set_x(x);
                center.set_y(y);
                r_ = center.DistanceTo(pt1);
                center_ = center;
                return true;
            }

计算两个圆的位置关系并且求出交点

利用圆心距与两圆半径之间的关系来判断两圆的位置关系。假设 d c dc dc为圆心距, R R R与 r r r分别是两圆的半径,则:
(1) dc>R+r,两圆外离;
(2) dc=R+r,两圆外切;
(3) |R – r|< d c < |R + r| ,两圆相交;
(4) dc = |R – r| ,两圆内切;
(5) 0 < = d c < |R – r| ,两圆内含。

 // 两个圆的位置关系存在五种,分别是外离,外切,相交,内切,内含分别对应12345;
            int Circle::PosRelationToOtherCircle(const Circle &other_circle, Vec2d &p1, Vec2d &p2)
            {
                double dis = center_.DistanceTo(other_circle.center_);
                double r1 = r_;
                double r2 = other_circle.r();
                if (dis - (r1 + r2) > 0)
                {
                    // std::cout << "两圆外离" << endl;
                    return 1;
                }
                else if (dis == (r1 + r2))
                {
                    IntersectionToCircle(other_circle, p1, p2);
                    //  cout << "两圆外切" << endl;
                    return 2;
                }
                else if ((fabs(r1 - r2) - dis < 0) && (dis - (r1 + r2) < 0))
                {
                    IntersectionToCircle(other_circle, p1, p2);
                    // cout << "两圆相交" << endl;
                    return 3;
                }
                else if (dis == abs(r1 - r2))
                {
                    IntersectionToCircle(other_circle, p1, p2);
                    //  cout << "两圆内切" << endl;
                    return 4;
                }
                else
                {
                    // cout << "两圆内含" << endl;
                    return 4;
                }
            }

圆与圆的交点计算后续补充。

圆与直线的位置关系及交点计算

假设直线方程和圆的方程为:
y = k x + c y=kx+c y=kx+c
( x − a ) 2 + ( y − b ) 2 = r 2 (x-a)^2+(y-b)^2=r^2 (xa)2+(yb)2=r2
联立两个方程可以得到:
( 1 + k 2 ) x 2 + x [ 2 k ( c − b ) − 2 a ] + a 2 + ( c − b ) 2 − r 2 = 0 (1+k^2)x^2+x[2k(c-b)-2a]+a^2+(c-b)^2-r^2=0 (1+k2)x2+x[2k(cb)2a]+a2+(cb)2r2=0
这里主要是使用圆的方程和直线方程联合求解,得到一个一元二次方程,这个二次方程的解就是交点坐标的x值。

  // calculate intersection point of a line and a circle
 // return 0 无交点,1.一个交点,2是两个交点
            int Circle::IntersecLine(const Line &line, Vec2d &p0, Vec2d &p1)
            {
                // get known line A B C
                float A, B, C;
                A = line.A_;
                B = line.B_;
                C = line.C_;
                float x0, x1, y0, y1;
                // calculate intersection
                float k, b, AA, BB, CC;
                int nRet = 0;
                if (fabs(A) < kMathEpsilon && fabs(B) < kMathEpsilon)
                {
                    return 0;
                }
                if (fabs(B) > kMathEpsilon)
                {
                    k = -A / B;
                    b = -C / B;
                    AA = 1 + k * k;
                    BB = 2 * (k * b - x_ - k * y_);
                    CC = pow(x_, 2) + pow((b - y_), 2) - r_ * r_;
                    if (SolveEquation::QuadraticEquation(AA, BB, CC, x0, x1))
                    {
                        y0 = k * x0 + b;
                        y1 = k * x1 + b;
                        nRet = 2;
                    }
                }
                else
                {
                    b = -C / A;
                    x0 = b;
                    x1 = b;
                    if (pow(r_, 2) >= pow(x_ - b, 2))
                    {
                        nRet = 2;
                        y0 = sqrt(r_ * r_ - pow((x_ - b), 2)) + y_;
                        y1 = y_ - sqrt(r_ * r_ - pow((x_ - b), 2));
                    }
                    else
                    {
                        nRet = 0;
                    }
                }
                if (nRet != 0)
                {
                    p0.set_x(x0);
                    p0.set_x(y0);
                    p1.set_x(x1);
                    p1.set_x(y1);
                }
                return nRet;
            }

已知两直线,求其相切圆

已经知道两条直线的方程L0,L1,求与其相切的圆的坐标,半径(已知)。
后续补充。

已知两个点在圆上,求两圆相切时的半径

针对平行车位(右侧车位,左侧车位转到右侧计算)来说,常见的场景如下图所示:
在这里插入图片描述

左侧的为入库点,可能存在情况基本为如图所示的三种,而这三种case计算圆心坐标的方式只有一种:
O 1 . x = 0 ; O 1 . y = − r ; O 2 . x = x 1 − r ∗ s i n ( θ ) ; O 2 . y = y 1 + r ∗ c o s ( θ ) ; O_1.x=0; O_1.y=-r; O_2.x=x_1-r*sin(\theta); O_2.y=y_1+r*cos(\theta); O1.x=0;O1.y=r;O2.x=x1rsin(θ);O2.y=y1+rcos(θ);
其中x1,y1是新坐标系下的目标点的坐标。
那么可以列方程:两圆心之间的距离=2*r;
这样可以得到一个一元二次方程。

double a = sin(t1) * sin(t1) + (1 + cos(t1)) * (1 + cos(t1)) - 4;
double b = -2 * sin(t1) * x1 + 2 * (1 + cos(t1)) * y1;
double c = x1 * x1 + y1 * y1;

求出半径即可。

以上为个人学习使用,请批评指正,如有侵权,请联系删除。

参考文献

【1】https://blog.csdn.net/qq_45874328/article/details/114934147

  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈喽汽车人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值