14
07/2017
Douglas-Peucker Algorithm implementation in C#
Douglas-Peucker algorithm is an error bounded sequence simplication. It is used for compressing trajectory, roadnetwork, etc. It's main idea can be shown as the following picture [1].
I implement the Douglas-Peucker algorithm using C#.
Here is my code. (Github: https://github.com/IrisLoveLeo/DouglasPeucker )
using System; using System.Collections.Generic; using System.Linq; namespace Statistics { public class DouglasPeucker { private List<Point> _pointsList; private double _errorBound; // degree public DouglasPeucker(List<Point> pointsList, double errorBound) { _pointsList = new List<Point>(); if (pointsList != null) { Point last = pointsList.First(); _pointsList.Add(last); for (int i = 1; i < pointsList.Count; i++) { if (!last.Equals(pointsList[i])) { _pointsList.Add(pointsList[i]); last = pointsList[i]; } else { Console.WriteLine("丢弃相同的点:" + last); } } } _errorBound = errorBound; } public List<Point> Compress() { if (_pointsList == null || _pointsList.Count <= 2) { return _pointsList; } List<Point> result = CompressHelper(_pointsList); result.Add(_pointsList.Last()); return result; } private List<Point> CompressHelper(List<Point> pointsList) { if (pointsList.Count < 2) { return pointsList; } List<Point> result = new List<Point>(); // 有可能是polygon if (pointsList.First().Equals(pointsList.Last())) { var r1 = CompressHelper(pointsList.GetRange(0, pointsList.Count / 2)); var r2 = CompressHelper(pointsList.GetRange(pointsList.Count / 2, pointsList.Count - pointsList.Count / 2)); result.AddRange(r1); result.AddRange(r2); return result; } Line line = new Line() { p1 = pointsList.First(), p2 = pointsList.Last() }; double maxDistance = 0; int maxIndex = 0; for (int i = 1; i < pointsList.Count - 1; i++) { var distance = Distance(pointsList[i], line); if (distance > maxDistance) { maxDistance = distance; maxIndex = i; } } if (maxDistance <= _errorBound) { result.Add(pointsList.First()); } else { var r1 = CompressHelper(pointsList.GetRange(0, maxIndex)); var r2 = CompressHelper(pointsList.GetRange(maxIndex + 1, pointsList.Count - maxIndex - 1)); result.AddRange(r1); result.Add(pointsList[maxIndex]); result.AddRange(r2); } return result; } private double Distance(Point p, Line line) { var p1 = line.p1; var p2 = line.p2; return Math.Abs( ((p2.Lng - p1.Lng) * p.Lat + (p1.Lat - p2.Lat) * p.Lng + (p1.Lng - p2.Lng) * p1.Lat + (p2.Lat - p1.Lat) * p1.Lng) / Math.Sqrt((p2.Lng - p1.Lng) * (p2.Lng - p1.Lng) + (p1.Lat - p2.Lat) * (p1.Lat - p2.Lat)) ); } } public class Point { public double Lat { set; get; } public double Lng { set; get; } public bool Equals(Point p) { return Lat == p.Lat && Lng == p.Lng; } override public string ToString() { return "[" + Lat + "," + Lng + "]"; } } class Line { public Point p1 { set; get; } public Point p2 { set; get; } } }
Here is the effect of the DP on road network compress.
Before Compress:
After Compress:
The road network file size has been reduced to half.
[1] Lin X, Ma S, Zhang H, et al. One-pass error bounded trajectory simplification[J]. Proceedings of the VLDB Endowment, 2017, 10(7): 841-852.
0 条评论