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;
    }

  • 相关阅读:
    左孩子右兄弟的字典树
    UVA 1401 Remember the Word
    HDOJ 4770 Lights Against Dudely
    UvaLA 3938 "Ray, Pass me the dishes!"
    UVA
    Codeforces 215A A.Sereja and Coat Rack
    Codeforces 215B B.Sereja and Suffixes
    HDU 4788 Hard Disk Drive
    HDU 2095 find your present (2)
    图的连通性问题—学习笔记
  • 原文地址:https://www.cnblogs.com/william7neral/p/4182398.html
Copyright © 2011-2022 走看看