【源代码】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);
}
}
【注:】本算法是我根据网上的一篇论文提供的一种思路,自己编写代码实现的缓冲区算法,编写本算法的初衷只是为了服务自己的项目,现在发布出来也是为了方便大家,以使大家免得再周折一番,但请务必不要作为学术论文发表。
下载:https://files.cnblogs.com/longshaoye/BufferV1.0.0.7z