• 【源代码】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);
        }
    }

    【注:】本算法是我根据网上的一篇论文提供的一种思路,自己编写代码实现的缓冲区算法,编写本算法的初衷只是为了服务自己的项目,现在发布出来也是为了方便大家,以使大家免得再周折一番,但请务必不要作为学术论文发表。

    下载:https://files.cnblogs.com/longshaoye/BufferV1.0.0.7z

  • 相关阅读:
    MySql数据库时区异常,java.sql.SQLException: The server time zone value '?й???׼ʱ?' is unrecognized or represents more than one time zone.
    SpringBoot中自定义properties文件配置参数并带有输入提示
    Springboot2.x 集成jsp
    Spring Boot使用AOP实现REST接口简易灵活的安全认证
    Spring Boot使用过滤器和拦截器分别实现REST接口简易安全认证
    Spring Boot使用RestTemplate消费REST服务的几个问题记录
    Spring Boot开发MongoDB应用实践
    Spring Boot定时任务应用实践
    Spring Boot缓存应用实践
    Spring Boot消息队列应用实践
  • 原文地址:https://www.cnblogs.com/longshaoye/p/1794320.html
Copyright © 2020-2023  润新知