// ref: https://doi.org/10.3138/FM57-6770-U75U-7727 public static List <T> SimplifyByDouglasPeucker <T>(List <T> pointList, SimplificationParamters parameters /*, double threshold, bool retain3Points = false*/) where T : IPoint { var result = new List <T>(); if (pointList == null || pointList.Count < 2) { return(result); } if (pointList.Count == 2) { return(pointList); } //to handle lines with the same start and end if (pointList.First().Equals(pointList.Last())) { //return DivideForDouglasPeucker(pointList, threshold, pointList.Count / 2); return(DivideForDouglasPeucker(pointList, parameters, pointList.Count / 2)); } var numberOfPoints = pointList.Count; // double maxSemiPerpendicularDistance = 0; int maxIndex = 0; //1399.06.23 //در این جا برای سرعت بیشتر مقدار فاصله استفاه //نمیشود بلکه توان دوم آن استفاده میشود. این //روش باعث میشود در محاسبات از تابع جزر استفاده //نشود //double effectiveThreshold = threshold * threshold; double effectiveThreshold = parameters.DistanceThreshold.Value /** parameters.DistanceThreshold.Value*/; for (int i = 1; i < numberOfPoints - 1; i++) { var semiPerpendicularDistance = SpatialUtility.GetPointToLineSegmentDistance(pointList[0], pointList[numberOfPoints - 1], pointList[i]); if (semiPerpendicularDistance > maxSemiPerpendicularDistance) { maxIndex = i; maxSemiPerpendicularDistance = semiPerpendicularDistance; } } if (maxSemiPerpendicularDistance > effectiveThreshold) { return(DivideForDouglasPeucker(pointList, parameters, maxIndex)); } else { return(new List <T> { pointList[0], pointList[numberOfPoints - 1] }); } }
// http://psimpl.sourceforge.net/reumann-witkam.html public static List <T> SimplifyByReumannWitkam <T>(List <T> pointList, SimplificationParamters parameters) where T : IPoint { var result = new List <T>(); if (pointList == null || pointList.Count < 2) { return(result); } if (pointList.Count == 2) { return(pointList); } var numberOfPoints = pointList.Count; //1399.06.23 //در این جا برای سرعت بیشتر مقدار فاصله استفاه //نمیشود بلکه توان دوم آن استفاده میشود. این //روش باعث میشود در محاسبات از تابع جزر استفاده //نشود //double effectiveThreshold = threshold * threshold; double effectiveThreshold = parameters.DistanceThreshold.Value /** parameters.DistanceThreshold.Value*/; result.Add(pointList[0]); int startIndex = 0; int middleIndex = 1; for (int i = 2; i < numberOfPoints; i++) { var semiPerpendicularDistance = SpatialUtility.GetPointToLineSegmentDistance(pointList[startIndex], pointList[middleIndex], pointList[i]); if (semiPerpendicularDistance > effectiveThreshold) { result.Add(pointList[i - 1]); startIndex = i - 1; middleIndex = i; } } if (parameters.Retain3Points && result.Count == 1) { result.Add(pointList[pointList.Count() / 2]); } result.Add(pointList.Last()); return(result); }
//private static List<T> DivideForDouglasPeucker<T>(List<T> pointList, double threshold, int divideIndex) where T : IPoint //{ // var result = new List<T>(); // var leftList = pointList.Take(divideIndex + 1).ToList(); // result = SimplifyByDouglasPeucker(leftList, threshold); // var rightList = pointList.Skip(divideIndex).ToList(); // var rightResult = SimplifyByDouglasPeucker(rightList, threshold); // result.AddRange(rightResult.Skip(1)); // return result; //} private static bool AnyPerpendicularDistanceExceedTolerance <T>(List <T> pointList, double threshold) where T : IPoint { for (int i = 1; i < pointList.Count - 1; i++) { var semiPerpendicularDistance = SpatialUtility.GetPointToLineSegmentDistance(pointList[0], pointList[pointList.Count - 1], pointList[i]); if (semiPerpendicularDistance >= threshold) { return(true); } } return(false); }
// 1400.05.20 public static List <T> SimplifyByBeforeOpeningWindow <T>(List <T> points, SimplificationParamters parameters /*, double threshold, bool retain3Points = false*/) where T : IPoint { if (points == null || points.Count == 0) { return(null); } else if (points.Count == 2) { return(points); } List <T> result = new List <T>(); result.Add(points.First()); // 1400.05.20 //در این جا برای سرعت بیشتر مقدار فاصله استفاه //نمیشود بلکه توان دوم آن استفاده میشود. این //روش باعث میشود در محاسبات از تابع جزر استفاده //نشود double effectiveThreshold = parameters.DistanceThreshold.Value /* * parameters.DistanceThreshold.Value*/; int startIndex = 0, middleIndex = 1, endIndex = 2; while (endIndex < points.Count) { while (middleIndex < endIndex) { var semiDistance = SpatialUtility.GetPointToLineSegmentDistance(points[startIndex], points[endIndex], points[middleIndex]); if (semiDistance > effectiveThreshold) { result.Add(points[endIndex - 1]); startIndex = endIndex - 1; middleIndex = startIndex + 1; // after breaking it will increment by 1 6 lines below endIndex = middleIndex; break; } middleIndex++; } endIndex++; middleIndex = startIndex + 1; } if (parameters.Retain3Points && result.Count == 1) { result.Add(points[points.Count() / 2]); } if (result.Last().DistanceTo(points.Last()) != 0) { result.Add(points.Last()); } return(result); }
// 1400.05.11 // http://psimpl.sourceforge.net/perpendicular-distance.html // Ekdemir, S., Efficient Implementation of Polyline Simplification for Large Datasets and Usability Evaluation. // Master’s thesis, Uppsala University, Department of Information Technology, 2011 public static List <T> SimplifyByPerpendicularDistance <T>(List <T> points, SimplificationParamters parameters /*, double threshold, bool retain3Points = false*/) where T : IPoint { if (points == null || points.Count == 0) { return(null); } else if (points.Count == 2) { return(points); } List <T> result = new List <T>(); result.Add(points.First()); // 1400.06.05 // استفاده از مقدار توان دوم در مقایسه مشکلساز // نخواهد بود چون در هر حال تابع توان دوم هم // اکیدا صعودی است و توان دوم هیچ مقداری از توان // دوم مقدار کمتر از خودش، بیشتر نخواهد شد. اما // برای اینکه مقایسه سرعت درست انجام شود // استفاده از توان دوم متوقف شد. // 1400.05.11 //در این جا برای سرعت بیشتر مقدار فاصله استفاه //نمیشود بلکه توان دوم آن استفاده میشود. این //روش باعث میشود در محاسبات از تابع جزر استفاده //نشود //double effectiveThreshold = threshold * threshold; double effectiveThreshold = parameters.DistanceThreshold.Value /** parameters.DistanceThreshold.Value*/; for (int i = 0; i < points.Count - 2; i++) { var perpendicularDistance = SpatialUtility.GetPointToLineSegmentDistance(points[i], points[i + 2], points[i + 1]); if (perpendicularDistance > effectiveThreshold) { result.Add(points[i + 1]); } // 1400.06.05 // نقطه حذف شده به عنوان نقطه شروع استفاده نمیشود // این روش در بهترین حالت ۵۰ درصد فشرده سازی ایجاد // می کند else { result.Add(points[i + 2]); i++; } } if (parameters.Retain3Points && result.Count == 1) { result.Add(points[points.Count() / 2]); } if (result.Last().DistanceTo(points.Last()) != 0) { result.Add(points.Last()); } return(result); }