道格拉斯数据压缩算法

	/// <summary>
    /// 道格拉斯数据压缩算法
    /// 2021.10.12 
    /// </summary>
    public class Douglaser
    {
        /// <summary>
        /// 数组长度
        /// </summary>
        private int sourceLenght = 0;
        /// <summary>
        /// 阈值
        /// </summary>
        private double threshold = 0;
        /// <summary>
        /// 原始数据的坐标
        /// </summary>
        private ArrayList sourceArray = new ArrayList();
        /// <summary>
        /// 存入抽稀后的数据的坐标 
        /// </summary>
        private ArrayList newArray = new ArrayList();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="_sourceArray">原始数据</param>
        /// <param name="threshold">阈值</param>
        public Douglaser(ArrayList _sourceArray,double _threshold)
        {
            sourceArray = _sourceArray;
            threshold = _threshold;
        }
        /// <summary>
        /// 运行结果
        /// </summary>
        public string Message { get; private set; }

        /// <summary>
        /// 开始计算,返回压缩后的数据字典
        /// </summary>
        /// <returns></returns>
        public Dictionary<long, double> DoWork()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Dictionary<long, double> result = new Dictionary<long, double>();
            //用自己的结构取出来数制成曲线图
            newArray.Clear();
            sourceLenght = sourceArray.Count;
            newArray.Add((DouglasPoint)sourceArray[0]);
            Douglas(0, sourceLenght);
            if (newArray.Contains((DouglasPoint)sourceArray[sourceLenght - 1]))
            { }
            else
            {
                newArray.Add((DouglasPoint)sourceArray[sourceLenght - 1]);
            }
            newArray.Sort(new SourceArrayCompare());
            result.Clear();
            for (int i = 0; i < newArray.Count; i++)
            {
                result.Add(((DouglasPoint)newArray[i]).x, ((DouglasPoint)newArray[i]).y);
            }
            sw.Stop();
            this.Message = "计算耗时:" + Math.Round(sw.ElapsedTicks / (decimal)Stopwatch.Frequency * 1000, 3).ToString() + "毫秒";
            return result;
        }

       

        public class Line//记录直线参数的类  
        {
            public double k;
            public double b;
        }

        /// <summary>
        /// 坐标数据类
        /// </summary>
        public class DouglasPoint
        {
            public long x;
            public double y;

        }

        /// <summary>
        /// 求斜率  
        /// </summary>
        /// <param name="p1">第一个点</param>
        /// <param name="p2">第二个点</param>
        /// <returns></returns>
        public Line Parameter(DouglasPoint p1, DouglasPoint p2)
        {
            double k, b;
            Line line = new Line();
            k = (p2.y - p1.y) / (p2.x - p1.x);
            b = p1.y - k * p1.x;
            line.k = k;
            line.b = b;
            return line;
        }

        /// <summary>
        /// 求点到直线距离
        /// </summary>
        /// <param name="dot"></param>
        /// <param name="line"></param>
        /// <returns></returns>
        public float Distance(DouglasPoint dot, Line line)
        {
            float dis = (float)(Math.Abs(line.k * dot.x - dot.y + line.b)) / (float)Math.Sqrt(line.k * line.k + 1);//点(x0,y0)到直线Ax+By+c=0的距离d=|Ax0+By0+c|/(A2+B2)1/2
            return dis;
        }
        public void Douglas(int number1, int number2)
        {
            int max = 0;//定义拥有最大距离值的点的编号  
            var line = Parameter((DouglasPoint)sourceArray[number1], (DouglasPoint)sourceArray[number2 - 1]);
            max = 0;
            float maxx = Distance((DouglasPoint)sourceArray[number1 + 1], line);//假设第二个点为最大距离点  

            for (int i = number1 + 1; i < number2 - 1; i++)//从第二个点遍历到最后一个点前方的点  
            {
                var distance = Distance((DouglasPoint)sourceArray[i], line);
                if (distance > threshold && distance >= maxx)//找出拥有最大距离的点  
                {
                    max = i;
                    maxx = distance;
                }
            }

            if (max == 0)//若不存在最大距离点,则只将首尾点存入arraylist,结束这一次的道格拉斯抽稀  
            {
                if (newArray.Contains((DouglasPoint)sourceArray[number2 - 1]))
                {
                    return;
                }
                else
                {
                    newArray.Add((DouglasPoint)sourceArray[number2 - 1]);
                    return;
                }
            }
            else if (number1 + 1 == max && number2 - 2 != max)//如果第二个点是最大距离点,则以下一个点和尾点作为参数进行道格拉斯抽稀释  
            {
                newArray.Add((DouglasPoint)sourceArray[max]);
                Douglas(max, number2);
            }
            else if (number2 - 2 == max && number1 + 1 != max)//<span style="font-family: Arial;">如果倒数第二个点是最大距离点,则以首点和倒数第三点作为参数进行道格拉斯抽稀  
            {
                newArray.Add((DouglasPoint)sourceArray[max]);
                Douglas(number1, max + 1);
            }
            else if (number1 + 1 == max && number2 - 2 == max)//如果首点尾点夹住最大距离点,则将最大距离点和尾点存入arraylist  
            {
                newArray.Add((DouglasPoint)sourceArray[max]);
                return;
            }
            else
            {
                newArray.Add((DouglasPoint)sourceArray[max]);
                Douglas(number1, max + 1);
                Douglas(max, number2);
            }
        }

        //newar里边的坐标按横坐标进行排序
        public class SourceArrayCompare : IComparer
        {
            public int Compare(object pA, object pB)
            {
                DouglasPoint p1 = (DouglasPoint)pA;
                DouglasPoint p2 = (DouglasPoint)pB;
                return p1.x.CompareTo(p2.x);
            }
        }

    }

使用方法

  
  				ArrayList temperatureArray = new ArrayList();
                ArrayList pressureArray = new ArrayList();               
                if (list == null) return;    
                
                //生成原始数据
                list.ForEach(t =>
                {                   
                    temperatureArray.Add(new DouglasPoint { x = t.InsertDate.Ticks, y = t.Temperature });
                    pressureArray.Add(new DouglasPoint { x = t.InsertDate.Ticks, y = t.Pressure });
                });                

                var temperatureList = new Douglaser(temperatureArray, AppData.Instance.Setting.ChartThreshold.Value).DoWork();
                var pressureList = new Douglaser(pressureArray, AppData.Instance.Setting.ChartThreshold.Value).DoWork();


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值