///
/// Douglas peucker algorithm for curve simplification
///
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
namespace WPM.PolygonTools {
public class DouglasPeucker {
public static List SimplifyCurve (List pointList, double epsilon) {
// Find the point with the maximum distance
double dmax = 0;
int index = 0;
int last = pointList.Count - 1;
for (int i = 2; i < last; i++) {
double d = LineToPointDistance2D (pointList [0], pointList [last], pointList [i], true);
if (d > dmax) {
index = i;
dmax = d;
}
}
// If max distance is greater than epsilon, recursively simplify
List recResults;
if (dmax > epsilon) {
// Recursive call
recResults = SimplifyCurve (pointList.GetRange (0, index + 1), epsilon);
List recResults2 = SimplifyCurve (pointList.GetRange (index, last - index + 1), epsilon);
// Build the result list
for (int k = 1; k < recResults2.Count; k++)
recResults.Add (recResults2 [k]);
} else {
recResults = new List ();
recResults.Add (pointList [0]);
recResults.Add (pointList [last]);
}
// Return the result
return recResults;
}
//Compute the dot product AB . AC
private static float DotProduct (Vector2 pointA, Vector2 pointB, Vector2 pointC) {
float ABx = pointB.x - pointA.x;
float ABy = pointB.y - pointA.y;
float BCx = pointC.x - pointB.x;
float BCy = pointC.y - pointB.y;
float dot = ABx * BCx + ABy * BCy;
return dot;
}
//Compute the cross product AB x AC
private static float CrossProduct (Vector2 pointA, Vector2 pointB, Vector2 pointC) {
float ABx = pointB.x - pointA.x;
float ABy = pointB.y - pointA.y;
float ACx = pointC.x - pointA.x;
float ACy = pointC.y - pointA.y;
float cross = ABx * ACy - ABy * ACx;
return cross;
}
//Compute the distance from A to B
static float Distance (Vector2 pointA, Vector2 pointB) {
float d1 = pointA.x - pointB.x;
float d2 = pointA.y - pointB.y;
return Mathf.Sqrt (d1 * d1 + d2 * d2);
}
//Compute the distance from AB to C
//if isSegment is true, AB is a segment, not a line.
static float LineToPointDistance2D (Vector2 pointA, Vector2 pointB, Vector2 pointC, bool isSegment) {
float dist = CrossProduct (pointA, pointB, pointC) / Distance (pointA, pointB);
if (isSegment) {
float dot1 = DotProduct (pointA, pointB, pointC);
if (dot1 > 0)
return Distance (pointB, pointC);
float dot2 = DotProduct (pointB, pointA, pointC);
if (dot2 > 0)
return Distance (pointA, pointC);
}
return Mathf.Abs (dist);
}
}
}