commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t.@apache.org
Subject svn commit: r1562999 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/ test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/
Date Thu, 30 Jan 2014 22:16:59 GMT
Author: tn
Date: Thu Jan 30 22:16:59 2014
New Revision: 1562999

URL: http://svn.apache.org/r1562999
Log:
[MATH-749] Add AklToussaintHeuristic as pre-processing step for convex hull generation.

Added:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
  (with props)
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
  (with props)
Modified:
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristic.java?rev=1562999&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
(added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
Thu Jan 30 22:16:59 2014
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math3.geometry.euclidean.twod.hull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
+
+/**
+ * A simple heuristic to improve the performance of convex hull algorithms.
+ * <p>
+ * The heuristic is based on the idea of a convex quadrilateral, which is formed by
+ * four points with the lowest and highest x / y coordinates. Any point that lies inside
+ * this quadrilateral can not be part of the convex hull and can thus be safely discarded
+ * before generating the convex hull itself.
+ * <p>
+ * The complexity of the operation is O(n), and may greatly improve the time it takes to
+ * construct the convex hull afterwards, depending on the point distribution.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Convex_hull_algorithms#Akl-Toussaint_heuristic">
+ * Akl-Toussaint heuristic (Wikipedia)</a>
+ * @since 3.3
+ * @version $Id$
+ */
+public final class AklToussaintHeuristic {
+
+    /** Hide utility constructor. */
+    private AklToussaintHeuristic() {
+    }
+
+    /**
+     * Returns a point set that is reduced by all points for which it is safe to assume
+     * that they are not part of the convex hull.
+     *
+     * @param points the original point set
+     * @return a reduced point set, useful as input for convex hull algorithms
+     */
+    public static Collection<Vector2D> reducePoints(final Collection<Vector2D>
points) {
+
+        // find the leftmost point
+        int size = 0;
+        Vector2D minX = null;
+        Vector2D maxX = null;
+        Vector2D minY = null;
+        Vector2D maxY = null;
+        for (Vector2D p : points) {
+            if (minX == null || p.getX() < minX.getX()) {
+                minX = p;
+            }
+            if (maxX == null || p.getX() > maxX.getX()) {
+                maxX = p;
+            }
+            if (minY == null || p.getY() < minY.getY()) {
+                minY = p;
+            }
+            if (maxY == null || p.getY() > maxY.getY()) {
+                maxY = p;
+            }
+            size++;
+        }
+
+        if (size < 4) {
+            return points;
+        }
+
+        final List<Vector2D> quadrilateral = buildQuadrilateral(minY, maxX, maxY, minX);
+        // if the quadrilateral is not well formed, e.g. only 2 points, do not attempt to
reduce
+        if (quadrilateral.size() < 3) {
+            return points;
+        }
+
+        final List<Vector2D> reducedPoints = new ArrayList<Vector2D>(quadrilateral);
+        for (final Vector2D p : points) {
+            // check all points if they are within the quadrilateral
+            // in which case they can not be part of the convex hull
+            if (!insideQuadrilateral(p, quadrilateral)) {
+                reducedPoints.add(p);
+            }
+        }
+
+        return reducedPoints;
+    }
+
+    /**
+     * Build the convex quadrilateral with the found corner points (with min/max x/y coordinates).
+     *
+     * @param points the respective points with min/max x/y coordinate
+     * @return the quadrilateral
+     */
+    private static List<Vector2D> buildQuadrilateral(final Vector2D... points) {
+        List<Vector2D> quadrilateral = new ArrayList<Vector2D>();
+        for (Vector2D p : points) {
+            if (!quadrilateral.contains(p)) {
+                quadrilateral.add(p);
+            }
+        }
+        return quadrilateral;
+    }
+
+    /**
+     * Checks if the given point is located within the convex quadrilateral.
+     * @param point the point to check
+     * @param quadrilateralPoints the convex quadrilateral, represented by 4 points
+     * @return {@code true} if the point is inside the quadrilateral, {@code false} otherwise
+     */
+    private static boolean insideQuadrilateral(final Vector2D point,
+                                               final List<Vector2D> quadrilateralPoints)
{
+
+        Vector2D p1 = quadrilateralPoints.get(0);
+        Vector2D p2 = quadrilateralPoints.get(1);
+
+        if (point.equals(p1) || point.equals(p2)) {
+            return true;
+        }
+
+        // get the location of the point relative to the first two vertices
+        final double last = getLocation(point, p1, p2);
+        final int size = quadrilateralPoints.size();
+        // loop through the rest of the vertices
+        for (int i = 1; i < size; i++) {
+            p1 = p2;
+            p2 = quadrilateralPoints.get((i + 1) == size ? 0 : i + 1);
+
+            if (point.equals(p1) || point.equals(p2)) {
+                return true;
+            }
+
+            // do side of line test
+            // multiply the last location with this location
+            // if they are the same sign then the operation will yield a positive result
+            // -x * -y = +xy, x * y = +xy, -x * y = -xy, x * -y = -xy
+            if (last * getLocation(point, p1, p2) < 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Get the location of a point with regard to the given line.
+     * <p>
+     * Note: this method does the same as {@link Line#getOffset(Vector)} but is
+     * faster, thus preferred for this heuristic.
+     *
+     * @param point the point to check
+     * @param linePoint1 the first point of the line
+     * @param linePoint2 the second point of the line
+     * @return the location of the point with regard to the line
+     */
+    private static double getLocation(final Vector2D point,
+                                      final Vector2D linePoint1,
+                                      final Vector2D linePoint2) {
+        return (linePoint2.getX() - linePoint1.getX()) * (point.getY() - linePoint1.getY())
-
+               (point.getX() - linePoint1.getX()) * (linePoint2.getY() - linePoint1.getY());
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision HeadURL

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristic.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java?rev=1562999&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
(added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
Thu Jan 30 22:16:59 2014
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math3.geometry.euclidean.twod.hull;
+
+import java.util.Collection;
+
+import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
+
+/**
+ * Test class for AklToussaintHeuristic.
+ * @version $Id$
+ */
+public class AklToussaintHeuristicTest extends ConvexHullGenerator2DAbstractTest {
+
+    protected ConvexHullGenerator2D createConvexHullGenerator() {
+        return new GrahamScan2D();
+    }
+
+    @Override
+    protected Collection<Vector2D> reducePoints(Collection<Vector2D> points)
{
+        return AklToussaintHeuristic.reducePoints(points);
+    }
+
+}

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision HeadURL

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/AklToussaintHeuristicTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java?rev=1562999&r1=1562998&r2=1562999&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java
(original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/euclidean/twod/hull/ConvexHullGenerator2DAbstractTest.java
Thu Jan 30 22:16:59 2014
@@ -45,6 +45,11 @@ public abstract class ConvexHullGenerato
 
     protected abstract ConvexHullGenerator2D createConvexHullGenerator();
 
+    protected Collection<Vector2D> reducePoints(Collection<Vector2D> points)
{
+        // do nothing by default, may be overridden by other tests
+        return points;
+    }
+
     @Before
     public void setUp() {
         generator = createConvexHullGenerator();
@@ -89,7 +94,7 @@ public abstract class ConvexHullGenerato
             int size = (int) FastMath.floor(random.nextDouble() * 96.0 + 4.0);
 
             List<Vector2D> points = createRandomPoints(size);
-            ConvexHull2D hull = generator.generate(points);
+            ConvexHull2D hull = generator.generate(reducePoints(points));
             checkConvexHull(points, hull);
         }
     }



Mime
View raw message