zoukankan      html  css  js  c++  java
  • 计算任意两个圆的交点

    这里是算法的数学思想:

    http://mathworld.wolfram.com/Circle-CircleIntersection.html

    其实懂了之后发现也很简单,中文概况是这样:

    1 计算两个圆心之间的距离L
    2 如果 L>r1+r2 无交点
    3 如果 l = r1 + r2 则一个交点, 用圆心的坐标可以计算出具体点
    4 假定 两个交点的连线和圆心连线的交点是D,D到第一个圆心的距离是d, 则
       d*d + y*y = r1*r1
       (l-d)*(l-d) + y*y = r2 * r2
       其中y就是两交点连线距离的一半了
       合并一下可得到:
       r2*r2 - r1*r1 = l*l - 2dl
       d = (l*l - r2*r2 + r1*r1) / 2l
    5 根据前面的公式,还可以确定出来 y的数值
    6 y = sqrt(r1*r1-d*d)

     1 /// <summary>
     2 /// 判断两个平行于x轴的圆的交点
     3 /// </summary>
     4 /// <param name="centerA">第一个圆的中点</param>
     5 /// <param name="rA">半径</param>
     6 /// <param name="centerB">第二个圆的中点</param>
     7 /// <param name="rB">半径</param>
     8 /// <param name="ptInter1">交点1(若不存在返回65536)</param>
     9 /// <param name="ptInter2">交点1(若不存在返回65536)</param>
    10 public static void CircleInterCircleOnXAxis(PointF centerA, double rA, PointF centerB, double rB, ref PointF ptInter1, ref PointF ptInter2)
    11 {
    12     ptInter1.X = ptInter2.X = 65536.0f;
    13     ptInter1.Y = ptInter2.Y = 65536.0f;
    14     PointF centerLeft;
    15     double R, r, d;
    16     if (centerA.X < centerB.X)
    17     {
    18         centerLeft = centerA;
    19         R = rA;
    20         r = rB;
    21         d = centerB.X - centerA.X;
    22     }
    23     else
    24     {
    25         centerLeft = centerB;
    26         R = rB;
    27         r = rA;
    28         d = centerA.X - centerB.X;
    29     }
    30     double R2 = R * R;
    31     double x = (d*d - r*r + R2)/(2*d);
    32     double y = Math.Sqrt(R2 - x * x);
    33     ptInter1.X = centerLeft.X + (int)x;
    34     ptInter1.Y = centerLeft.Y + (int)y;
    35     ptInter2.X = centerLeft.X + (int)x;
    36     ptInter2.Y = centerLeft.Y - (int)y;
    37 }

    当然上面说的方法需要两个圆平行于x轴,否则说不通。在数学计算上其实经常有这样的现象,就是变换坐标轴位置和方向,使计算简单。所以,这里思来想去需要另外一个工具函数来帮忙。

    以某个点为中心点逆时针旋转Angle角度:(代码是网上找的)

     1 /// <summary>
     2 /// 以中心点逆时针旋转Angle角度
     3 /// </summary>
     4 /// <param name="center">中心点</param>
     5 /// <param name="p1">待旋转的点</param>
     6 /// <param name="angle">旋转角度(弧度)</param>
     7 public static PointF PointRotate(PointF center, PointF p1, double angle)
     8 {
     9     double x1 = (p1.X - center.X) * Math.Cos(angle) + (p1.Y - center.Y) * Math.Sin(angle) + center.X;
    10     double y1 = -(p1.X - center.X) * Math.Sin(angle) + (p1.Y - center.Y) * Math.Cos(angle) + center.Y;
    11     return new PointF((float)x1, (float)y1);
    12 }

    思路就是,通过将两个圆的其中一个旋转到和另一个平行,计算出交点,再把交点反向旋转回来

    所以这里就需要计算两个向量夹角的函数

     1 /// <summary>
     2 /// 计算两个向量的夹角
     3 /// </summary>
     4 /// <param name="Va"></param>
     5 /// <param name="Vb"></param>
     6 /// <returns></returns>
     7 public static double GetAngleOfVectors(PointF Va, PointF Vb)
     8 {
     9     double da = Math.Sqrt(Va.X*Va.X + Va.Y*Va.Y);
    10     double db = Math.Sqrt(Vb.X*Vb.X + Vb.Y*Vb.Y);
    11     double theta = Math.Acos((Va.X*Vb.X + Va.Y*Vb.Y)/(da*db));
    12     return theta;
    13 }

    全部的代码我就不贴了,一方面是写的搓,一方面是希望各位自己也动动脑。哈

    以上代码已经经过简单测试

     好吧,还是贴出来好了:

    /// <summary>
    ///     求任意两个圆的交点
    /// </summary>
    /// <param name="centerA">第一个圆的中点</param>
    /// <param name="rA">半径</param>
    /// <param name="centerB">第二个圆的中点</param>
    /// <param name="rB">半径</param>
    /// <param name="ptInter1">交点1(若不存在返回65536)</param>
    /// <param name="ptInter2">交点1(若不存在返回65536)</param>
    public static void CircleInterCircle(PointF centerA, double rA, PointF centerB, double rB, ref PointF ptInter1,
                                            ref PointF ptInter2)
    {
        var v = new PointF(centerB.X - centerA.X, centerB.Y - centerA.Y);
        double angle = GetAngleWithXAxis(v);
        PointF bb = PointRotate(centerA, centerB, angle);
        PointF p1 = Point.Empty, p2 = Point.Empty;
        CircleInterCircleOnXAxis(centerA, rA, bb, rB, ref p1, ref p2);
        if (!Equal(p1.X, 65536.0f))
        {
            p1 = PointRotate(centerA, p1, -angle);
        }
        if (!Equal(p2.X, 65536.0f))
        {
            p2 = PointRotate(centerA, p2, -angle);
        }
        ptInter1 = p1;
        ptInter2 = p2;
    }

  • 相关阅读:
    集群服务器登录退出出现问题
    TP框架中的Db::name 和 dB::table 以及 db('') 的区别
    TP5中orderRaw用法
    视差滚动 插件
    ThinkPad t480s 电源接口进水了
    file_put_contents failed to open stream: Permission denied in
    Mac 如何安装字体?
    ZipArchive::close(): Failure to create temporary file: Permission denied
    Wifi6 路由器推荐
    名词解释 | Enteric Nervous System | Enteric Neural Crest Cell | ENS | ENCC | 神经系统 | 神经嵴细胞
  • 原文地址:https://www.cnblogs.com/william7neral/p/4182398.html
Copyright © 2011-2022 走看看