C# GDI+绘制双曲线

来源:互联网 发布:淘宝客服总结报告 编辑:程序博客网 时间:2024/05/01 02:13

本方法采用描点法进行双曲线绘制:

焦点坐标信息类:
    public class CirclePoint
    {
        public CirclePoint() { }
        public CirclePoint(double lng, double lat, double zoom, double radius)
        {
            this.Lng = lng;
            this.Lat = lat;
            this.Radius = radius;
        }
        public CirclePoint(double lng, double lat)
        {
            this.Lng = lng;
            this.Lat = lat;
        }

        //经度
        private double _lng;
        //纬度
        private double _lat;
        //半径
        private double _radius;
        //重复出现的次数
        private int _count;

        private double _zoom;

        public double Lng
        {
            get
            {
                return this._lng;
            }
            set
            {
                this._lng = value;
            }
        }
        public double Lat
        {
            get
            {
                return this._lat;
            }
            set
            {
                this._lat = value;
            }
        }
        public double Radius
        {
            get
            {
                return this._radius;
            }
            set
            {
                this._radius = value;
            }
        }

        public double Zoom
        {
            get;
            set;
        }

        /// <summary>
        /// 统计与当前圆相交或者重叠的圆的个数,有必要的时候应该定义为long
        /// </summary>
        public int Count
        {
            get
            {
                return _count;
            }
            set
            {
                this._count = value;
            }
        }

        /// <summary>
        /// 计算两个点之间的距离
        /// </summary>
        /// <param name="cp1">点1</param>
        /// <param name="cp2">点2</param>
        /// <returns>两点之间的距离</returns>
        public static double ComputDist(CirclePoint cp1, CirclePoint cp2)
        {
            return cp1.Equals(cp2) ? 0 : Math.Sqrt(Squre(cp1.Lng - cp2.Lng) + Squre(cp1.Lat - cp2.Lat));
        }

}

获取双曲线点集方法,分为四段,添加到集合points,返回bool值确定是否运算成功:

distDiff为双曲线上一点到两焦点的距离差,crossPoint为双曲线上一点,判断返回那一侧的点集,可以为空

        public static bool ProduceHyberPoints(CirclePoint cp1, CirclePoint cp2, double distDiff, CirclePoint crossPoint, out List<double[]> points,out float rotateAngle)
        {
            //station =[20, 30; 80,30];% (20,30),(80,30),测试数据
            const int N = 4096;
            bool flag = false;
            if(cp1.Lng>cp2.Lng)
            {
                CirclePoint temp = cp1;
                cp1 = cp2;
                cp2 = temp;
            }
            CirclePoint middle = new CirclePoint((cp1.Lng + cp2.Lng) / 2.0, (cp1.Lat + cp2.Lat) / 2.0);
            double distStation = Math.Sqrt(Squre(cp1.Lng - cp2.Lng) + Squre(cp1.Lat - cp2.Lat));
            double c = distStation / 2.0;
            double a = distDiff / 2.0;
            double a_2 = Squre(a);
            double b_2 = -1;
            double interval = (cp2.Lng - cp1.Lng) / N;
            points = new List<double[]>();

            if ((c - a) <= 0)
            {
                rotateAngle = 0.0f;
                Debug.WriteLine("无法构成双曲线");
                flag = false;            
            }
            else
            {
                 b_2 = Squre(c) - Squre(a);//b_2-c^2-a^2                
            }

            //存储双曲线,的四部分
            double[] XRight = new double[N];
            double[] XLeft = new double[N];
            double[] YUp = new double[N];
            double[] YDown = new double[N];    

            #region 计算要旋转的角度

            CirclePoint vector = new CirclePoint(cp2.Lng - cp1.Lng, cp2.Lat - cp1.Lat);//监测站构成的向量        
            //旋转角度
            float.TryParse((180 / Math.PI * Math.Atan(Math.Abs(vector.Lat) / Math.Abs(vector.Lng))).ToString(), out rotateAngle);

            #endregion
            
            #region 生成双曲线点集
          
            XRight[0] = a + middle.Lng;           
            //生成双曲线坐标点集数据

            for (int i = 1; i < XRight.Length; i++)
            {
                XRight[i] = XRight[i - 1] + interval;
            }
            try
            {
                for (int j = 0; j < YUp.Length; j++)
                {     
                    YUp[j] = Math.Sqrt(b_2 * (Squre(XRight[j] - middle.Lng) / a_2 - 1)) + middle.Lat;//sqrt((a^2/x^2-1)*b^2)                               
                }
            }
            catch
            {
                Debug.WriteLine("算术运算错误,可能是对复数开方所导致!");
                flag = false;
            }
            //从标准直角坐标系向middle平移
            for (int i = 0; i < XRight.Length; i++)
            {             
                XLeft[i] = 2 * middle.Lng - XRight[i];
              
                YDown[i] = -1 * YUp[i];
                YDown[i] += 2 * middle.Lat;
            }

            #endregion

            #region 判断交点位置,返回交点所在那一侧的一条
            if (crossPoint == null)
            {
                points.Add(XRight);
                points.Add(XLeft);
            }
            else if (crossPoint.Lng >  middle.Lng)
            {
                points.Add(XRight);
            }
            else
            {
                points.Add(XLeft);
            }
           

            #endregion          
          
            points.Add(YUp);
            points.Add(YDown);          
            flag = true;
            return flag;
        }

//窗体的Paint事件

 private void Hyberbola_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            List<CirclePoint> stations = new List<CirclePoint>()
            {
                new CirclePoint (300,200),
                new CirclePoint (360,200),
                new CirclePoint (400,250),
                new CirclePoint (370,250),
            };
            List<double[]> tempPoints = new List<double[]>();
            CirclePoint middle;
            float rotate;
            CirclePoint cross = new CirclePoint(380, 200);
            CirclePoint cross1 = new CirclePoint(200, 200);
            if (ProduceHyberPoints(stations[0], stations[3], 60, cross1, out tempPoints, out rotate))
            {
                middle = new CirclePoint((stations[0].Lng + stations[3].Lng) / 2.0, (stations[0].Lat + stations[3].Lat) / 2.0);
            }
            else
            {
                return;
            }
            Draw(g, tempPoints, middle, rotate);

            if (ProduceHyberPoints(stations[0], stations[1], 40, cross, out tempPoints, out rotate))
            {
                middle = new CirclePoint((stations[0].Lng + stations[1].Lng) / 2.0, (stations[0].Lat + stations[1].Lat) / 2.0);
            }
            else
            {
                return;
            }
            Draw(g, tempPoints, middle, rotate);

            if (ProduceHyberPoints(stations[0], stations[2], 100, null, out tempPoints, out rotate))
            {
                middle = new CirclePoint((stations[0].Lng + stations[2].Lng) / 2.0, (stations[0].Lat + stations[2].Lat) / 2.0);
            }
            else
            {
                return;
            }
            Draw(g, tempPoints, middle, rotate);
            g.Dispose();
        }
        //双曲线绘制方法
        public static void Draw(Graphics g, List<double[]> points, CirclePoint middle, float rotate)
        {
            Pen pen = new Pen(Color.Blue, 1);
            int N = points[0].Length;
            Point[] Xr = new Point[N];
            Point[] Xl = new Point[N];
            Point[] Yu = new Point[N];
            Point[] Yd = new Point[N];
            int i = 0;
            float centerX, centerY;
            float.TryParse(middle.Lng.ToString(), out centerX);
            float.TryParse(middle.Lat.ToString(), out centerY);

            if (points.Count == 3)
            {
                for (int j = 0; j < points[i].Length; j++)
                {
                    Xr[j] = new Point((int)points[i][j], (int)points[i + 1][j]);
                    Yu[j] = new Point((int)points[i][j], (int)points[i + 2][j]);
                }               
                g.TranslateTransform(centerX, centerY);//移动到中心店
                g.RotateTransform(rotate);//旋转rotate角度

                g.DrawLines(pen, Xr);
                g.DrawLines(pen, Yu);               
            }
            else
            {
                for (int j = 0; j < points[i].Length; j++)
                {
                    Xr[j] = new Point((int)points[i][j], (int)points[i + 2][j]);
                    Xl[j] = new Point((int)points[i][j], (int)points[i + 3][j]);
                    Yu[j] = new Point((int)points[i + 1][j], (int)points[i + 3][j]);
                    Yd[j] = new Point((int)points[i + 1][j], (int)points[i + 2][j]);
                }       

                //双曲线旋转       
                g.TranslateTransform(centerX, centerY);
                g.RotateTransform(rotate);

                g.DrawLines(pen, Xr);
                g.DrawLines(pen, Xl);
                g.DrawLines(pen, Yu);
                g.DrawLines(pen, Yd);
            }

            //恢复图像在水平和垂直方向的平移
            g.TranslateTransform(-centerX, -centerY);

            //重置绘图的所有变换
            g.ResetTransform();         
        }


欢迎拍砖,有更好的解决方案,可以提出来共享,互相学习,互相进步!

1 0
原创粉丝点击