【源代碼】GIS 點、線緩衝區生成算法的C#實現(V0.95)
今天將源代碼都貼上,請大家多多批評賜教。
廣泛希望大家能指出一些錯誤,謝謝。
以後我會抽空學習一下特殊情況的處理,然後加上去,希望大家多多支持。
源代碼結構:
源代碼分別附上:
1.MathTool.cs
/*******************************************************
* 文檔作者:dxj
* 創建時間:2010.3.7
* 文檔說明:
* 在GIS中常用的通用數學函數。
******************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using DXJ.Teresa.GIS.GeoObject;
namespace DXJ.Teresa.GIS.Utility
{
/// <summary>
/// 常用的通用數學函數
/// </summary>
public static class MathTool
{
/// <summary>
/// 獲取由兩個點所形成的向量的象限角度
/// </summary>
/// <param name="preCoord">第一個點的座標</param>
/// <param name="nextCoord">第二個點的座標</param>
/// <returns></returns>
public static double GetQuadrantAngle(Coordinate preCoord, Coordinate nextCoord)
{
return GetQuadrantAngle(nextCoord.X - preCoord.X, nextCoord.Y - preCoord.Y);
}
/// <summary>
/// 由增量X和增量Y所形成的向量的象限角度
/// </summary>
/// <param name="x">增量X</param>
/// <param name="y">增量Y</param>
/// <returns>象限角</returns>
public static double GetQuadrantAngle(double x, double y)
{
double theta = Math.Atan(y / x);
if (x > 0 && y > 0) return theta;
if (x > 0 && y < 0) return Math.PI * 2 + theta;
if (x < 0 && y > 0) return theta + Math.PI;
if (x < 0 && y < 0) return theta + Math.PI;
return theta;
}
/// <summary>
/// 獲取由相鄰的三個點所形成的兩個向量之間的夾角
/// </summary>
/// <param name="preCoord"></param>
/// <param name="midCoord"></param>
/// <param name="nextCoord"></param>
/// <returns></returns>
public static double GetIncludedAngel(Coordinate preCoord, Coordinate midCoord, Coordinate nextCoord)
{
double innerProduct = (midCoord.X - preCoord.X) * (nextCoord.X - midCoord.X) + (midCoord.Y - preCoord.Y) * (nextCoord.Y - midCoord.Y);
double mode1 = Math.Sqrt(Math.Pow((midCoord.X - preCoord.X), 2.0) + Math.Pow((midCoord.Y - preCoord.Y), 2.0));
double mode2 = Math.Sqrt(Math.Pow((nextCoord.X - midCoord.X), 2.0) + Math.Pow((nextCoord.Y - midCoord.Y), 2.0));
return Math.Acos(innerProduct / (mode1 * mode2));
}
/// <summary>
/// 獲取由兩個點所形成的向量的模(長度)
/// </summary>
/// <param name="preCoord">第一個點</param>
/// <param name="nextCoord">第二個點</param>
/// <returns>由兩個點所形成的向量的模(長度)</returns>
public static double GetDistance(Coordinate preCoord, Coordinate nextCoord)
{
return Math.Sqrt(Math.Pow((nextCoord.X - preCoord.X), 2) + Math.Pow((nextCoord.Y - preCoord.Y), 2));
}
}
}
2.Coordinate.cs
/*******************************************************
* 文檔作者:dxj
* 創建時間:2010.3.7
* 文檔說明:
* 本文件是座標類。
******************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace DXJ.Teresa.GIS.GeoObject
{
/// <summary>
/// GEOObject座標類
/// </summary>
public class Coordinate
{
#region Private Members
private double _x = 0.0;
private double _y = 0.0;
#endregion
#region Public Construtors
public Coordinate()
{
//
}
public Coordinate(double x, double y)
{
this._x = x;
this._y = y;
}
public Coordinate(string x, string y)
{
try
{
this._x = x.Trim() == "" ? 0.0 : Convert.ToDouble(x.Trim());
this._y = y.Trim() == "" ? 0.0 : Convert.ToDouble(y.Trim());
}
catch (Exception)
{
}
}
public Coordinate(string coord)
{
if (coord.Trim().Length > 0)
{
string[] coords = coord.Split(new char[] { ',' });
if (coords.Length == 2)
{
this._x = coords[0].Trim().Length > 0 ? Convert.ToDouble(coords[0].Trim()) : 0.0;
this._y = coords[1].Trim().Length > 0 ? Convert.ToDouble(coords[1].Trim()) : 0.0;
}
}
}
#endregion
#region Public Properities
public double X
{
get
{
return this._x;
}
set
{
this._x = value;
}
}
public double Y
{
get
{
return this._y;
}
set
{
this._y = value;
}
}
#endregion
#region Public Override Methods
public override string ToString()
{
return "(" + this._x.ToString() + "," + this._y.ToString() + ")";
}
#endregion
}
}
3.PointBuffer.cs
/************************************************************
* 文檔作者:dxj
* 創建時間:2010.3.7
* 文檔說明:
* 本文件是點緩衝區邊界生成算法的C#實現。
*
************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using DXJ.Teresa.GIS.GeoObject;
namespace DXJ.Teresa.GIS.Buffer
{
/// <summary>
/// 點緩衝區邊界生成算法
/// </summary>
public class PointBuffer
{
#region Public Members
/// <summary>
/// 用於近似表示點緩衝區邊界的內接正多邊形的邊數N
/// </summary>
public static int N = 12;
#endregion
#region Public Static Methods
/// <summary>
/// 根據一個給定點的座標,生成基於這個點的點緩衝區邊界點座標串(逆時針)
/// </summary>
/// <param name="center">一個給定點的座標</param>
/// <param name="radius">緩衝區的半徑</param>
/// <returns>點緩衝區邊界點座標串(逆時針)</returns>
public static string GetBufferEdgeCoords(Coordinate center, double radius)
{
double alpha = 0.0;//Math.PI / 6;
double gamma = (2 * Math.PI) / N;
StringBuilder strCoords = new StringBuilder();
double x = 0.0, y = 0.0;
for (double phi = 0; phi < (N - 1) * gamma; phi += gamma)
{
x = center.X + radius * Math.Cos(alpha + phi);
y = center.Y + radius * Math.Sin(alpha + phi);
if (strCoords.Length > 0) strCoords.Append(";");
strCoords.Append(x.ToString()+","+y.ToString());
}
return strCoords.ToString();
}
#endregion
}
}
4.PolylineBuffer.cs
/***********************************************************************
* 文檔作者:dxj
* 創建時間:2010.3.7 20:17
* 文檔說明:
* 本文件是線緩衝區邊界生成算法的C#實現。
**********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using DXJ.Teresa.GIS.GeoObject;
using DXJ.Teresa.GIS.Utility;
namespace DXJ.Teresa.GIS.Buffer
{
/// <summary>
/// 線緩衝區邊界生成算法
/// </summary>
public class PolylineBuffer
{
/// <summary>
/// 根據給定的一系列有順序的座標,逆時針生成緩衝區的邊界座標。
/// </summary>
/// <param name="strPolyLineCoords">一系列有順序的座標</param>
/// <param name="radius">緩衝區半徑</param>
/// <returns>緩衝區的邊界座標</returns>
public static string GetBufferEdgeCoords(string strPolyLineCoords, double radius)
{
//參數處理
if (strPolyLineCoords.Trim().Length < 1) return "";
string[] strCoords = strPolyLineCoords.Split(new char[] { ';' });
List<Coordinate> coords = new List<Coordinate>();
foreach (string coord in strCoords)
{
coords.Add(new Coordinate(coord));
}
//分別生成左側和右側的緩衝區邊界點座標串
string leftBufferCoords = GetLeftBufferEdgeCoords(coords, radius);
coords.Reverse();
string rightBufferCoords = GetLeftBufferEdgeCoords(coords, radius);
return leftBufferCoords + ";" + rightBufferCoords;
}
#region Private Methods
/// <summary>
/// 根據給定的一系列有順序的座標,逆時針生成軸線左側的緩衝區邊界點
/// </summary>
/// <param name="coords">一系列有順序的座標</param>
/// <param name="radius">緩衝區半徑</param>
/// <returns>緩衝區的邊界座標</returns>
private static string GetLeftBufferEdgeCoords(IList<Coordinate> coords, double radius)
{
//參數處理
if (coords.Count < 1) return "";
else if (coords.Count < 2) return PointBuffer.GetBufferEdgeCoords(coords[0], radius);
//計算時所需變量
double alpha = 0.0;//向量繞起始點沿順時針方向旋轉到X軸正半軸所掃過的角度
double delta = 0.0;//前後線段所形成的向量之間的夾角
double l = 0.0;//前後線段所形成的向量的叉積
//輔助變量
StringBuilder strCoords = new StringBuilder();
double startRadian = 0.0;
double endRadian = 0.0;
double beta = 0.0;
double x = 0.0, y = 0.0;
//第一節點的緩衝區
{
alpha = MathTool.GetQuadrantAngle(coords[0], coords[1]);
startRadian = alpha + Math.PI;
endRadian = alpha + (3 * Math.PI) / 2;
strCoords.Append(GetBufferCoordsByRadian(coords[0], startRadian, endRadian, radius));
}
//中間節點
for (int i = 1; i < coords.Count - 1; i++)
{
alpha = MathTool.GetQuadrantAngle(coords[i], coords[i + 1]);
delta = MathTool.GetIncludedAngel(coords[i - 1], coords[i], coords[i + 1]);
l = GetVectorProduct(coords[i - 1], coords[i], coords[i + 1]);
if (l > 0)
{
startRadian = alpha + (3 * Math.PI) / 2 - delta;
endRadian = alpha + (3 * Math.PI) / 2;
if (strCoords.Length > 0) strCoords.Append(";");
strCoords.Append(GetBufferCoordsByRadian(coords[i], startRadian, endRadian, radius));
}
else if (l < 0)
{
beta = alpha - (Math.PI - delta) / 2;
x = coords[i].X + radius * Math.Cos(beta);
y = coords[i].Y + radius * Math.Sin(beta);
if (strCoords.Length > 0) strCoords.Append(";");
strCoords.Append(x.ToString() + "," + y.ToString());
}
}
//最後一個點
{
alpha = MathTool.GetQuadrantAngle(coords[coords.Count - 2], coords[coords.Count - 1]);
startRadian = alpha + (3 * Math.PI) / 2;
endRadian = alpha + 2 * Math.PI;
if (strCoords.Length > 0) strCoords.Append(";");
strCoords.Append(GetBufferCoordsByRadian(coords[coords.Count - 1], startRadian, endRadian, radius));
}
return strCoords.ToString();
}
/// <summary>
/// 獲取指定弧度範圍之間的緩衝區圓弧擬合邊界點
/// </summary>
/// <param name="center">指定擬合圓弧的原點</param>
/// <param name="startRadian">開始弧度</param>
/// <param name="endRadian">結束弧度</param>
/// <param name="radius">緩衝區半徑</param>
/// <returns>緩衝區的邊界座標</returns>
private static string GetBufferCoordsByRadian(Coordinate center, double startRadian, double endRadian, double radius)
{
double gamma = Math.PI / 6;
StringBuilder strCoords = new StringBuilder();
double x = 0.0, y = 0.0;
for (double phi = startRadian; phi <= endRadian + 0.000000000000001; phi += gamma)
{
x = center.X + radius * Math.Cos(phi);
y = center.Y + radius * Math.Sin(phi);
if (strCoords.Length > 0) strCoords.Append(";");
strCoords.Append(x.ToString() + "," + y.ToString());
}
return strCoords.ToString();
}
/// <summary>
/// 獲取相鄰三個點所形成的兩個向量的交叉乘積
/// </summary>
/// <param name="preCoord">第一個節點座標</param>
/// <param name="midCoord">第二個節點座標</param>
/// <param name="nextCoord">第三個節點座標</param>
/// <returns>相鄰三個點所形成的兩個向量的交叉乘積</returns>
private static double GetVectorProduct(Coordinate preCoord, Coordinate midCoord, Coordinate nextCoord)
{
return (midCoord.X - preCoord.X) * (nextCoord.Y - midCoord.Y) - (nextCoord.X - midCoord.X) * (midCoord.Y - preCoord.Y);
}
#endregion
}
}
4.測試代碼
/************************************************************
* 文檔作者:dxj
* 創建時間:2010.3.7
* 文檔說明:
* 本文件是測試程序,根據一系列點生成邊界值。
*
************************************************************/
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DXJ.Teresa.GIS.Buffer;
using DXJ.Teresa.GIS.GeoObject;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Coordinate coord = new Coordinate(117.9761419921875,36.7177825);
double radius = 0.0058633144143721562925090295041981;
//string strCoords = PointBuffer.GetBufferEdgeCoords(coord, radius);
//Response.Write(strCoords);
string coords = "117.3469162109375,36.552475;118.77600527343749,36.56047375;118.49871933593751,37.11772;117.5442158203125,37.000405;117.680192578125,37.405675;119.1386099609375,37.15238125;119.162605859375,36.45649;118.89865097656251,36.28851625;118.63736230468748,36.19253125;118.5093841796875,36.189865";
string strCoords = PolylineBuffer.GetBufferEdgeCoords(coords, radius);
Response.Write(strCoords);
}
}
【注:】本算法是我根據網上的一篇論文提供的一種思路,自己編寫代碼實現的緩衝區算法,編寫本算法的初衷只是爲了服務自己的項目,現在發佈出來也是爲了方便大家,以使大家免得再周折一番,但請務必不要作爲學術論文發表。
下載:http://files.cnblogs.com/longshaoye/BufferV1.0.0.7z