【源代碼】GIS 點、線緩衝區生成算法的C#實現(V0.95)

原創 【源代碼】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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章