Douglas-Peucker algorithm

Monkey Forums/Monkey Code/Douglas-Peucker algorithm

Raph(Posted 2014) [#1]
Used for taking an array of points, such as in a polygon, and reducing the number of points (e.g. simplifying the polygon). Could also use to simplify any sort of line made of points, say for paths or gestures or something like that.

Ported from http://karthaus.nl/rdp/ and a bit of Wikipedia. That link also has a nifty demo of the algorithm. Adjust epsilon to get different degrees of optimization.

Assumes you have a Vector or Point class with .X and .Y in it.

	Function DouglasPeucker:Vector[] (pointList:Vector[], epsilon:Float)
	' implemented as a port from here: http://karthaus.nl/rdp/
		Local dmax:Float = 0
		Local index:Int = -1
		Local endPoint:Int = pointList.Length - 1
		
		If pointList.Length < 3
			Return pointList
		EndIf
		
		For Local i = 1 Until endPoint
			Local d:Float = findPerpendicularDistance(pointList[i], pointList[0], pointList[endPoint])
			If (d > dmax)
				index = i
				dmax = d
			EndIf
		Next
		
		Local resultList:Vector[]
		If (dmax > epsilon)
			' recurse
			Local results1:Vector[] = DouglasPeucker(pointList[ .. index + 1], epsilon)
			Local results2:Vector[] = DouglasPeucker(pointList[index ..], epsilon)
			
			' build the results list
			resultList = Concat(results1, results2)
			
		Else
			resultList =[pointList[0], pointList[endPoint]]
		EndIf
		Return resultList
	End
	
	Function Concat:Vector[] (arr1:Vector[], arr2:Vector[])
		Local offset:Int = arr1.Length - 1
		arr1 = arr1.Resize(offset + arr2.Length)
		For Local i = 0 Until arr2.Length
			arr1[i + offset] = arr2[i]
		Next
		Return arr1
	End
	
	Function findPerpendicularDistance:Float(p:Vector, p1:Vector, p2:Vector)
		Local result:Float
		Local slope:Float
		Local intercept:Float
		If (p1.X = p2.X)
			result = Abs(p.X - p1.X)
		Else
			slope = (p2.Y - p1.Y) / (p2.X - p1.X)
			intercept = p1.Y - (slope * p1.X)
			result = Abs(slope * p.X - p.Y + intercept) / Sqrt(Pow(slope, 2) + 1)
		EndIf
		Return Abs(result)
	End



Raph(Posted 2014) [#2]
Bugfix, code updated in first post.


Supertino(Posted 2014) [#3]
Nice, I don't have a use for it (yet) but nice all the same.


Shinkiro1(Posted 2014) [#4]
Nice.

I have actually implemented the same algorithm some time ago for bezier line drawing.
The only difference I think is, that I used a stack instead of an array.


consty(Posted 2014) [#5]
This algorithm is very good, especially if you making stuff like level editors, thanks for posting.