C#道格拉斯线压缩算法(经纬度坐标抽稀)

Douglas—Peucker算法
是将曲线近似表示为一系列点,并减少点的数量的一种算法。它的优点是具有平移和旋转不变性,给定曲线与阈值后,抽样结果一定。

算法思路:
对每一条曲线的首末点虚连一条直线,求所有点与直线的距离,并找出最大距离值dmax,用dmax与限差D相比:
若dmax<D,这条曲线上的中间点全部舍去;
若dmax≥D,保留dmax对应的坐标点,并以该点为界,把曲线分为两部分,对这两部分重复使用该方法。
传统的道格拉斯算法是采用递归的方法,算法的核心是求点到直线的距离。设置一个距离阈值,当点到线的距离小于该阈值,那么点视为可以删除的点。最后剩下的点即为最终结果

在这里插入图片描述
程序下载:地图投影与抽稀

1、算法输入:inPoint为待处理的点列数据, D为阈值

public class MyPoint
    {
        public double x;
        public double y;
    }

public void Do(List<MyPoint> inPoint, double D )
        {
       	    int n1 = 0;
            int n2 = inPoint.Count;
            Douglas(inPoint, n1, n2, D);
         }

2、调用Douglas算法,n1, n2分别为首尾点的位置标记

public struct line//记录直线参数的结构
    {
        public double k;
        public double b;
    }

	/// <summary>
        /// 求直线斜率与截距
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns></returns>
        private line parameter(MyPoint p1, MyPoint p2)
        {
            double k, b;
            line newcs = new line();
            k = (p2.y - p1.y) / (p2.x - p1.x);
            b = p1.y - k * p1.x;
            newcs.k = k;
            newcs.b = b;
            return newcs;
        }

 	/// <summary>
        /// 求点到直线的距离
        /// </summary>
        /// <param name="dot"></param>
        /// <param name="cs"></param>
        /// <returns></returns>
        private double distance(MyPoint dot, line cs)
        {
            double dis = (Math.Abs(cs.k * dot.x - dot.y + cs.b)) / Math.Sqrt(cs.k * cs.k + 1);
            return dis;
        }
List<MyPoint> outPoint = new List<MyPoint>();//保存结果
private void Douglas(List<MyPoint> InPoints, int n1, int n2, double d)
        {
            int num = InPoints.Count;
            //List<MyPoint> OutPoint = new List<MyPoint>();
            int Max = 0;//定义拥有最大距离值的点的编号
            line MyLine = new line();
            MyLine = parameter(InPoints[n1], InPoints[n2 - 1]);  //得到收尾点连线组成的虚线
            double MaxDistance = 0;
            if (d == 0)
            {
                outPoint = InPoints;
            }
            else
            {
                for (int i = n1 + 1; i < n2 - 1; i++)
                {
                    double pDistance = distance(InPoints[i], MyLine);
                    if (pDistance > d && pDistance >= MaxDistance)
                    {
                        Max = i;
                        MaxDistance = pDistance;
                    }
                }
                if (Max == 0) //如果最大值距离小于阈值直接返回首位
                {
                    outPoint.Add(InPoints[n1]);
                    outPoint.Add(InPoints[n2 - 1]);
                    return;
                }
                else if (n1 + 1 == Max && n2 - 2 != Max)   //第二个点为最大距离
                {
                    Douglas(InPoints, Max + 1, n2, d);
                    outPoint.Add(InPoints[n1]);
                }
                else if (n2 - 2 == Max && n1 + 1 != Max)  //倒数第二个点为最大距离
                {
                    Douglas(InPoints, 0, Max + 1, d);
                    outPoint.Add(InPoints[n2 - 1]);
                }
                else if (n1 + 1 == Max && n2 - 2 == Max)  //夹中间
                {
                    outPoint.Add(InPoints[Max - 1]);
                    outPoint.Add(InPoints[Max]);
                    outPoint.Add(InPoints[Max + 1]);
                    return;
                }
                else
                {
                    Douglas(InPoints, n1, Max + 1, d);
                    Douglas(InPoints, Max, n2, d);
                }
            }
        }

调用算法对点坐标压缩
在这里插入图片描述

在这里插入图片描述

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值