GIS 点、线缓冲区生成算法的C#实现(V0.95)

来源:互联网 发布:流星网络电视apk下载 编辑:程序博客网 时间:2024/06/08 16:27

声明:

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

    }

}

原创粉丝点击