画两圆外公切线 c#

来源:互联网 发布:网络歌手怎么注册 编辑:程序博客网 时间:2024/05/01 00:08

问题描述:有圆O1,O2,已知两圆圆心,半径,绘制两圆外公切线。 效果如下图所示:

 

问题可转换为求四个切点的坐标。B1为例,大致思路如下:

设x=x2-x1,y=y2-y1,d为O1,O2两点的距离

d方=x方+y方,能看明白吧?

设一个点P,P为O1O2与A1B1的交点。设l为PO2距离
则l=d*r/(R-r)

由于d是可表达的,自然l是可表达的

设B1P长为s

由于三角形O2B1P为直角三角形,B1为直角。

r方+S方=l方

所以这里s也是可表达的。所以B1到O1O2这个轴的距离为 s*r/l

设B1到O1O2轴的垂点为M,则O2M=r*r/l

上面两步用到了相似三角形原理。

剩下就简单了,M的坐标为 (x2+O2M*(x2-x1)/d,y2+O2M*(y2-y1)/d)
最后我们已知M点,已知过M点的一条直线O1O1,知道垂线的长度,自然就知道这个端点B1了,表达式太复杂,就不写了

这个程序主要是思路,

 
public struct TyphoonCircle
    {
        private PointF center;
        private int radius;
       
        /// <summary>
        /// 获取或设置台风中心点坐标
         /// </summary>
        public PointF Center
        {
            get
            {
                return this.center;
            }
            set
            {
                this.center = value;
            }
        }
        /// <summary>
        /// 获取或设置台风中心点坐标
         /// </summary>
        public int Radius
        {
            get
            {
                return this.radius;
            }
            set
            {
                this.radius = value;
            }
        }
        /// <summary>
        /// 根据中心点坐标和风场半径建立台风圈实体结构体
         /// </summary>
        /// <param name="center">中心点坐标</param>
        /// <param name="radius">风场半径</param>
        public TyphoonCircle(PointF center,int radius)
        {
            this.center = center;
            this.radius = radius;
        }
    }
 
 
 
 
   /// <summary>
        /// 计算 circle1 与 circle2 的外公切线与circle2的交点坐标
        /// </summary>
        /// <param name="circle1">台风风圈</param>
        /// <param name="circle2">台风风圈</param>
        /// <returns>PointF</returns>
        private PointF[] ReturnCutPoints(TyphoonCircle circle1, TyphoonCircle circle2)
        {
            //切点
            PointF[] CutPoints = new PointF[2];
            if (circle1.Radius != circle2.Radius)
                CutPoints = CalculateForDifferentRadius(circle1, circle2);
            return CutPoints;
        } //ReturnCutPoints
        /// <summary>
        /// 在半径不相等的情况下,计算 circle1 和 circle2 两圆的外公切线与 circle2 的交点坐标
        /// </summary>
        /// <param name="circle1">台风风圈</param>
        /// <param name="circle2">台风风圈</param>
        private PointF[] CalculateForDifferentRadius(TyphoonCircle circle1, TyphoonCircle circle2)
        {
            //令circle1,circle2的外公切线交与点P
            //circle1的圆心为O1,circle2的圆心为O2         
            //切线于circle1的两个焦点分别记作A1,A2
            //切线于circle2的两个焦点分别记作B1,B2
            //过点 B1 引 O1O2 的垂线,垂足为 M
            // O1O2 的斜率为k
            //切点
            PointF[] CutPoints = new PointF[2];
            float deltaX = circle2.Center.X - circle1.Center.X;
            float deltaY = circle2.Center.Y - circle1.Center.Y;
            // O1 与 O2 距离
            float distance = 0;
            // P 与 O2 距离
            float lengthA;
            // P 与 B1 或 B2点的距离
            float lengthB;
            // B1 到 O1O2的距离
            float lengthC;
            // O2 到 M 的距离
            float lengthD;
            //用于记录 M 点的坐标
            PointF M = new PointF();
            //  O1O2 直线方程的斜率k
            float k;
            //  O1O2 直线方程中的常数
            float b;
            distance = (float)(Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2)));
            lengthA = distance * circle1.Radius / (circle2.Radius - circle1.Radius);
            lengthB = (float)(Math.Sqrt(Math.Pow(lengthA, 2) - Math.Pow(circle1.Radius, 2)));
            lengthC = lengthB * circle1.Radius / lengthA;
            lengthD = circle1.Radius * circle1.Radius / lengthA;
            M.X = circle1.Center.X + lengthD * -deltaX / distance;
            M.Y = circle1.Center.Y + lengthD * -deltaY / distance;
            k = (circle1.Center.Y - circle2.Center.Y) / (circle1.Center.X - circle2.Center.X);
            b = circle1.Center.Y - k * circle1.Center.X;
            float Y = 0;
            float X = 0;
            Y = (float)((k * M.X + M.Y * k * k + b + Math.Abs(lengthC) * Math.Sqrt(k * k + 1)) / (k * k + 1));
            X = M.X - (Y - M.Y) * k;
            CutPoints[0].X = X;
            CutPoints[0].Y = Y;
            Y = (float)((k * M.X + M.Y * k * k + b - Math.Abs(lengthC) * Math.Sqrt(k * k + 1)) / (k * k + 1));
            X = M.X - (Y - M.Y) * k;
            CutPoints[1].X = X;
            CutPoints[1].Y = Y;
            return CutPoints;
        } //CalculateForDifferentRadius