The Douglas-Peucker algorithm is an algorithm for reducing the number of points in a curve that is approximated by a series of points. - Java 2D Graphics

Java examples for 2D Graphics:Curve

Description

The Douglas-Peucker algorithm is an algorithm for reducing the number of points in a curve that is approximated by a series of points.

Demo Code

/*/*ww  w .j  a v  a 2s .  com*/
 *  Flingbox - An OpenSource physics sandbox for Google's Android
 *  Copyright (C) 2009  Jon Ander Pe?alba & Endika Guti?rrez
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
import java.util.ArrayList;

public class Main{
    /**
     * The Douglas-Peucker algorithm is an algorithm for reducing the number 
     * of points in a curve that is approximated by a series of points.
     * The end of this function is a good moment to call the GarbageCollector
     * 
     * @param points   Array of the polygon's points 
     * @param epsilon   Max distance to ignore a point
     * @return         New array with optimized points
     */
    public static Vector2D[] douglasPeuckerReducer(final Vector2D[] points,
            final float epsilon) {
        final int lastPoint = points.length - 1;
        if (lastPoint < 3 || epsilon <= 0.0f)
            return points; // No reduction possible

        final ArrayList<Vector2D> reducedPolygon = new ArrayList<Vector2D>();

        reducedPolygon.add(points[0]); // First point will not be include

        /* Call recursively to algorithm */
        douglasPeucker(points, epsilon, 0, lastPoint, reducedPolygon);

        if (points[0].distanceToPoint(points[lastPoint]) > epsilon)
            reducedPolygon.add(points[lastPoint]); // Last point neither

        reducedPolygon.trimToSize();

        return (Vector2D[]) reducedPolygon.toArray(new Vector2D[0]);
    }
    /**
     * Recursively Calculation of DouglasPeucker Algorithm
     */
    private static void douglasPeucker(final Vector2D[] points,
            final float epsilon, final int first, final int last,
            final ArrayList<Vector2D> resultPoints) {

        float maxDistance = 0.0f;
        int maxDistanceIndex = 0;

        /* Find maximum distance point.  */
        for (int i = first + 1; i < last; i++) {
            float distance = distanceFromLineToPoint(points[first],
                    points[last], points[i]);
            if (distance > maxDistance) { // Store point
                maxDistance = distance;
                maxDistanceIndex = i;
            }
        }

        /* If point distance is more than epsilon then split points array in 
         * two parts and iterate for each. 
         */
        if (maxDistance > epsilon) {
            /* Find in previous segment */
            if ((maxDistanceIndex - first) > 1)
                douglasPeucker(points, epsilon, first, maxDistanceIndex,
                        resultPoints);
            /* Put point in buffer(2 coords) */
            resultPoints.add(points[maxDistanceIndex]);
            /* Continue searching important points */
            if ((last - maxDistanceIndex) > 1)
                douglasPeucker(points, epsilon, maxDistanceIndex, last,
                        resultPoints);
        }
    }
    /**
     * Computes minimum distance from line to point
     */
    public static float distanceFromLineToPoint(final Vector2D p0,
            final Vector2D p1, final Vector2D p) {
        final float area = (p0.i * p1.j + p1.i * p.j + p.i * p0.j - p1.i
                * p0.j - p.i * p1.j - p0.i * p.j) / 2f;
        final float base = (float) Math.sqrt((p1.i - p0.i) * (p1.i - p0.i)
                + (p1.j - p0.j) * (p1.j - p0.j));
        return (float) Math.abs(2f * area / base);
    }
}

Related Tutorials