Click here to Skip to main content
Click here to Skip to main content
Go to top

A C# Implementation of Douglas-Peucker Line Approximation Algorithm

, 6 Jun 2007
Rate this:
Please Sign up or sign in to vote.
DP Line approximation algorithm is a well-known method to approximate 2D lines. It is quite fast, O(nlog_2(n)) for a n-points line and can drastically compress a data curve. Here, a fully OOP implementation is given.

Introduction

I have found multiple implementations of the Douglas-Peucker algorithm but not in any .NET language, so I decided to port it over. Jonathan de Halleux has a wonderful explanation here.

Background

I needed to reduce polygons size to display on a map based on zoom levels.

Using the Code

The code included is complete and should run out of the box in Visual Studio 2005.
If it does not, please let me know.

/// <span class="code-SummaryComment"><summary></span>
/// Uses the Douglas Peucker algorithm to reduce the number of points.
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="Points">The points.</param></span>
/// <span class="code-SummaryComment"><param name="Tolerance">The tolerance.</param></span>
/// <span class="code-SummaryComment"><returns></returns></span>
public static List<Point> DouglasPeuckerReduction
    (List<Point> Points, Double Tolerance)
{
    if (Points == null || Points.Count < 3)
    return Points;

    Int32 firstPoint = 0;
    Int32 lastPoint = Points.Count - 1;
    List<Int32> pointIndexsToKeep = new List<Int32>();

    //Add the first and last index to the keepers
    pointIndexsToKeep.Add(firstPoint);
    pointIndexsToKeep.Add(lastPoint);

    //The first and the last point cannot be the same
    while (Points[firstPoint].Equals(Points[lastPoint]))
    {
        lastPoint--;
    }

    DouglasPeuckerReduction(Points, firstPoint, lastPoint, 
    Tolerance, ref pointIndexsToKeep);

    List<Point> returnPoints = new List<Point>();
    pointIndexsToKeep.Sort();
    foreach (Int32 index in pointIndexsToKeep)
    {
        returnPoints.Add(Points[index]);
    }

    return returnPoints;
}
    
/// <span class="code-SummaryComment"><summary></span>
/// Douglases the peucker reduction.
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="points">The points.</param></span>
/// <span class="code-SummaryComment"><param name="firstPoint">The first point.</param></span>
/// <span class="code-SummaryComment"><param name="lastPoint">The last point.</param></span>
/// <span class="code-SummaryComment"><param name="tolerance">The tolerance.</param></span>
/// <span class="code-SummaryComment"><param name="pointIndexsToKeep">The point index to keep.</param></span>
private static void DouglasPeuckerReduction(List<Point> 
    points, Int32 firstPoint, Int32 lastPoint, Double tolerance, 
    ref List<Int32> pointIndexsToKeep)
{
    Double maxDistance = 0;
    Int32 indexFarthest = 0;
    
    for (Int32 index = firstPoint; index < lastPoint; index++)
    {
        Double distance = PerpendicularDistance
            (points[firstPoint], points[lastPoint], points[index]);
        if (distance > maxDistance)
        {
            maxDistance = distance;
            indexFarthest = index;
        }
    }

    if (maxDistance > tolerance && indexFarthest != 0)
    {
        //Add the largest point that exceeds the tolerance
        pointIndexsToKeep.Add(indexFarthest);
    
        DouglasPeuckerReduction(points, firstPoint, 
        indexFarthest, tolerance, ref pointIndexsToKeep);
        DouglasPeuckerReduction(points, indexFarthest, 
        lastPoint, tolerance, ref pointIndexsToKeep);
    }
}

/// <span class="code-SummaryComment"><summary></span>
/// The distance of a point from a line made from point1 and point2.
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="pt1">The PT1.</param></span>
/// <span class="code-SummaryComment"><param name="pt2">The PT2.</param></span>
/// <span class="code-SummaryComment"><param name="p">The p.</param></span>
/// <span class="code-SummaryComment"><returns></returns></span>
public static Double PerpendicularDistance
    (Point Point1, Point Point2, Point Point)
{
    //Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)|   *Area of triangle
    //Base = v((x1-x2)²+(x1-x2)²)                               *Base of Triangle*
    //Area = .5*Base*H                                          *Solve for height
    //Height = Area/.5/Base

    Double area = Math.Abs(.5 * (Point1.X * Point2.Y + Point2.X * 
    Point.Y + Point.X * Point1.Y - Point2.X * Point1.Y - Point.X * 
    Point2.Y - Point1.X * Point.Y));
    Double bottom = Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) + 
    Math.Pow(Point1.Y - Point2.Y, 2));
    Double height = area / bottom * 2;

    return height;
    
    //Another option
    //Double A = Point.X - Point1.X;
    //Double B = Point.Y - Point1.Y;
    //Double C = Point2.X - Point1.X;
    //Double D = Point2.Y - Point1.Y;
    
    //Double dot = A * C + B * D;
    //Double len_sq = C * C + D * D;
    //Double param = dot / len_sq;
    
    //Double xx, yy;
    
    //if (param < 0)
    //{
    //    xx = Point1.X;
    //    yy = Point1.Y;
    //}
    //else if (param > 1)
    //{
    //    xx = Point2.X;
    //    yy = Point2.Y;
    //}
    //else
    //{
    //    xx = Point1.X + param * C;
    //    yy = Point1.Y + param * D;
    //}
    
    //Double d = DistanceBetweenOn2DPlane(Point, new Point(xx, yy));
}

Points of Interest

The code is not overly complicated. It was fun to port this algorithm, since all I feel I do now a days is hold business' hands to help them try and solve business problems that there is no consensus on.

History

  • Beta 1

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

CraigSelbert
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
QuestionUsing this algorithm on data from database PinmemberSaket Surya2-Jun-14 2:38 
QuestionPoint projected on the line but behind the segment? Bug? PinmemberSergiy Tkachuk25-Mar-14 13:31 
QuestionAbout Tolerance Pingroupkamlesh Prajapati8-Jan-14 22:55 
QuestionWhy do you create your own Point? Pinmemberleiyangge3-Jan-14 21:37 
QuestionLicense PinmemberDiego Catalano14-Dec-13 1:42 
Question1 bug, + 1 potential bug [modified] Pinmembergyuri1023-Apr-12 22:45 
AnswerRe: 1 bug, + 1 potential bug Pinmembertplokas26-Mar-13 13:46 
QuestionUseful,Thanks! Pinmembermasy19112-Mar-12 22:43 
I really need it,thank you very much!
QuestionGreat Job! Pinmembercdrake19-Dec-11 7:32 
Generalhow calculate an epsilon value Pinmemberunravel-the-sky23-May-11 5:52 
GeneralSome Issues with your implementation Pinmembermatthew minke15-Jul-10 10:57 
GeneralVery useful thanks - Point number reduction (Max Distance relevant tolerance) [modified] Pinmemberkamyk3-Mar-10 22:05 
GeneralVery useful thanks Pinmemberdylanhayes17-Nov-09 1:35 
GeneralThanks! PinmemberMember 337866727-Mar-09 9:28 
QuestionAnd other functions from Plot Graphic Library? Pinmemberagorby28-Apr-08 2:28 
Generalperpendicular PinmemberAlex Bespalov22-Dec-07 20:23 
Generalperpendicular PinmemberAlex Bespalov22-Dec-07 20:21 
GeneralDo you know offhand if the result of this algorithm is the same/different.... Pinmembersherifffruitfly6-Jun-07 11:28 
GeneralRe: Do you know offhand if the result of this algorithm is the same/different.... PinmemberCraigSelbert6-Jun-07 15:27 
GeneralCode question PinmemberDocJim4-Jun-07 8:46 
GeneralRe: Code question PinmemberCraigSelbert6-Jun-07 8:30 
GeneralNeat...Yeah...New algorithm Pinmemberjconwell25-May-07 4:50 
GeneralRe: Neat...Yeah...New algorithm PinmemberCraigSelbert25-May-07 15:40 
GeneralTake a look here PinmemberD_Guidi25-May-07 3:32 
GeneralRe: Take a look here PinmemberCraigSelbert25-May-07 15:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140905.1 | Last Updated 6 Jun 2007
Article Copyright 2007 by CraigSelbert
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid