GIS 點、線緩衝區產生演算法的C#實現(V0.95)

來源:互聯網
上載者:User

聲明:

1.當初自己在找緩衝區產生演算法時,非常難找,網上實現的代碼更是沒有,只有寥寥的幾句理論,在N天之後在網上搜到了兩篇論文,是《一種GIS緩衝區向量產生演算法及實現》和《GIS緩衝區和疊加分析》,自己根據自己的理解,寫出了這個實現的代碼,希望能給需要的人員一點協助,當然,寫的非常簡單,沒有處理銳角情況(下一步計劃將會實現),也沒有處理自相交情況(正在解決......),大家若是有什麼好的意見,請告訴我。謝謝。

2.本代碼只實現了產生緩衝區邊界點,沒有處理銳角情況(下一步計劃將會實現),也沒有處理自相交情況(正在解決......),希望大家能給寫協助。謝謝。

3.代碼之中有很多的不足,和考慮不到的情況,希望大家能給我一些指點,謝謝。

/***********************************************************************

 *  文檔作者: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);

            leftBufferCoords = leftBufferCoords.Substring(leftBufferCoords.IndexOf(';') + 1);

            coords.Reverse();

            string rightBufferCoords = GetLeftBufferEdgeCoords(coords, radius);

            rightBufferCoords = rightBufferCoords.Substring(rightBufferCoords.IndexOf(';') + 1);

            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 (Math.Abs(l) < 1E-15)//由於C#中double的精度位元為15位,第16位是不準確的,加上此調整值,可以在一定程度上減小第16位隨機數的影響。

                {

                    coords.Remove(coords[i]);//當三點共線時刪除這個中間點

                }

                else 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)//加入了一個調整C#double類型的值

            {

                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

    }

}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.