本方法採用描點法進行雙曲線繪製:
焦點座標信息類:
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();
}
歡迎拍磚,有更好的解決方案,可以提出來共享,互相學習,互相進步!