本方法采用描点法进行双曲线绘制:
焦点坐标信息类:
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();
}
欢迎拍砖,有更好的解决方案,可以提出来共享,互相学习,互相进步!