top of page
Search
cedarcantab

Douglas Peuker Algorithm

Updated: Mar 12

## Bing

Certainly! The Ramer–Douglas–Peucker algorithm, also known as the Douglas–Peucker algorithm, is a method for simplifying a curve composed of line segments. Its primary goal is to reduce the number of points while preserving the overall shape of the curve. Let's dive into how it works:

- Input:

- The algorithm takes as input a curve represented by an ordered set of points or line segments.

- It also requires a distance threshold denoted as ε (epsilon).

- Objective:

- Given the curve, the algorithm aims to find a similar curve with fewer points.

- The definition of "dissimilarity" is based on the maximum distance between the original curve and the simplified curve (measured using the Hausdorff distance).

- Algorithm Steps:

- The algorithm starts with the entire curve (all points) between the first and last points.

- It automatically marks the first and last points to be kept.

- Next, it identifies the point that is farthest from the line segment formed by connecting the first and last points. This point represents the maximum deviation from the approximating line segment.

- If this farthest point is closer than ε to the line segment, any other points not marked to be kept can be discarded without significantly affecting the simplified curve.

- If the farthest point is greater than ε away from the approximation, it must be kept.

- The algorithm then recursively calls itself with:

- The first point and the farthest point.

- The farthest point and the last point (including marking the farthest point as kept).

- When the recursion completes, the output curve consists of only the points marked as kept.

- Non-Parametric Approach:

- While the choice of ε is usually user-defined, the algorithm can be made non-parametric by considering the error bound due to digitization and quantization as a termination condition.

- Pseudocode Example:

function DouglasPeucker(PointList[], epsilon):

# Find the point with the maximum distance

dmax = 0

index = 0

end = length(PointList)

for i = 2 to (end - 1):

d = perpendicularDistance(PointList[i], Line(PointList[1], PointList[end]))

if d > dmax:

index = i

dmax = d

ResultList[] = empty

if dmax > epsilon:

# Recursive call

recResults1[] = DouglasPeucker(PointList[1...index], epsilon)

recResults2[] = DouglasPeucker(PointList[index...end], epsilon)

# Build the result list

ResultList[] = {recResults1[1...length(recResults1) - 1], recResults2[1...length(recResults2)]}

else:

ResultList[] = {PointList[1], PointList[end]}

return ResultList[]

Remember that the choice of ε affects the level of simplification. Smaller ε values retain more points, while larger ε values lead to greater simplification. The Douglas–Peucker algorithm has applications in cartography, graphics, and shape simplification .



//////////////////////////////// source: http://mourner.github.io/simplify-js/ // square distance between 2 points function getSqDist(p1, p2) { var dx = p1[0] - p2[0], dy = p1[1] - p2[1]; return dx dx + dy dy; } // square distance from a point to a segment function getSqSegDist(p, p1, p2) { var x = p1[0], y = p1[1], dx = p2[0] - x, dy = p2[1] - y; if (dx !== 0 || dy !== 0) { var t = ((p[0] - x) dx + (p[1] - y) dy) / (dx dx + dy dy); if (t > 1) { x = p2[0]; y = p2[1]; } else if (t > 0) { x += dx t; y += dy t; } } dx = p[0] - x; dy = p[1] - y; return dx dx + dy dy; } // rest of the code doesn't care about point format // basic distance-based simplification function simplifyRadialDist(points, sqTolerance) { var prevPoint = points[0], newPoints = [prevPoint], point; for (var i = 1, len = points.length; i < len; i++) { point = points[i]; if (getSqDist(point, prevPoint) > sqTolerance) { newPoints.push(point); prevPoint = point; } } if (prevPoint !== point) newPoints.push(point); return newPoints; } function simplifyDPStep(points, first, last, sqTolerance, simplified) { var maxSqDist = sqTolerance, index; for (var i = first + 1; i < last; i++) { var sqDist = getSqSegDist(points[i], points[first], points[last]); if (sqDist > maxSqDist) { index = i; maxSqDist = sqDist; } } if (maxSqDist > sqTolerance) { if (index - first > 1) simplifyDPStep(points, first, index, sqTolerance, simplified); simplified.push(points[index]); if (last - index > 1) simplifyDPStep(points, index, last, sqTolerance, simplified); } } // simplification using Ramer-Douglas-Peucker algorithm function simplifyDouglasPeucker(points, sqTolerance) { var last = points.length - 1; var simplified = [points[0]]; simplifyDPStep(points, 0, last, sqTolerance, simplified); simplified.push(points[last]); return simplified; } function simplify(points, tolerance, highestQuality) { if (points.length <= 2) return points; var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1; points = highestQuality ? points : simplifyRadialDist(points, sqTolerance); points = simplifyDouglasPeucker(points, sqTolerance); return points; }







Useful References




3 views0 comments

Recent Posts

See All

p2 naive broadphase

var Broadphase = require('../collision/Broadphase'); module.exports = NaiveBroadphase; /** * Naive broadphase implementation. Does N^2...

sopiro motor constranit

import { Matrix2, Vector2 } from "./math.js"; import { RigidBody } from "./rigidbody.js"; import { Settings } from "./settings.js";...

Comments


記事: Blog2_Post
bottom of page