[Geom4j-developer] SF.net SVN: geom4j:[32] trunk/src/net/sourceforge/geom4j
Status: Pre-Alpha
Brought to you by:
skhenkin
From: <skh...@us...> - 2010-01-16 23:19:57
|
Revision: 32 http://geom4j.svn.sourceforge.net/geom4j/?rev=32&view=rev Author: skhenkin Date: 2010-01-16 23:19:49 +0000 (Sat, 16 Jan 2010) Log Message: ----------- Polygon class refactored to store vertices in counter-clockwise traversal order Modified Paths: -------------- trunk/src/net/sourceforge/geom4j/ConvexHullAlgorithm.java trunk/src/net/sourceforge/geom4j/Polygon.java trunk/src/net/sourceforge/geom4j/PolygonTest.java Added Paths: ----------- trunk/src/net/sourceforge/geom4j/util/Utils.java trunk/src/net/sourceforge/geom4j/util/UtilsTest.java Modified: trunk/src/net/sourceforge/geom4j/ConvexHullAlgorithm.java =================================================================== --- trunk/src/net/sourceforge/geom4j/ConvexHullAlgorithm.java 2010-01-16 11:32:17 UTC (rev 31) +++ trunk/src/net/sourceforge/geom4j/ConvexHullAlgorithm.java 2010-01-16 23:19:49 UTC (rev 32) @@ -21,6 +21,8 @@ import java.util.LinkedList; import java.util.List; +import net.sourceforge.geom4j.util.Utils; + /** * An algorithm to construct convex hull (convex envelope) for a point set. * The convex hull is represented as a polygon. @@ -138,7 +140,7 @@ int m = 2; // a pointer to the top stack element for (int i = 2; i < points.size(); i++) { // test each point of the set - while (nonLeftTurn(stack[m-1], stack[m], points.get(i))) { + while (Utils.isNonLeftTurn(stack[m-1], stack[m], points.get(i))) { /* rollback if the turn is non-left, i.e. it breaks the rule for a convex polygon */ m--; @@ -151,14 +153,6 @@ hull.add(stack[i]); } return new Polygon(hull); - } - - /** Test if p1-p2-p3 form a non-left turn, i.e. straight line or right turn */ - private boolean nonLeftTurn(Point p1, Point p2, Point p3) { - Vector v1 = new Vector(p1, p2); - Vector v2 = new Vector(p2, p3); - return v1.crossProduct(v2) <= 0; - } - + } }; } Modified: trunk/src/net/sourceforge/geom4j/Polygon.java =================================================================== --- trunk/src/net/sourceforge/geom4j/Polygon.java 2010-01-16 11:32:17 UTC (rev 31) +++ trunk/src/net/sourceforge/geom4j/Polygon.java 2010-01-16 23:19:49 UTC (rev 32) @@ -17,9 +17,12 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; +import net.sourceforge.geom4j.util.Utils; + /** * A polygon is a closed shape in a plane. * This is immutable class. @@ -40,6 +43,7 @@ for (Point vertex: vertices) { this.vertices.add(vertex); } + orderCounterClockwise(); } public Polygon(Collection<Point> vertices) { @@ -196,21 +200,13 @@ /** Check if the polygon is convex or not */ public boolean isConvex() { - if (vertices.size() < 3) return true; // it's not really a polygon - // convex polygon <=> all cross products of its sides are of the same sign - Iterator<Point> i = vertices.iterator(); - Point p1 = vertices.get(getVertexCount()-1); - Point p2 = i.next(); - Vector v1 = new Vector(vertices.get(getVertexCount()-2), p1); - Vector v2 = new Vector(p1, p2); - double sign0 = Math.signum(v1.crossProduct(v2)); - while (i.hasNext()) { - p1 = p2; - p2 = i.next(); - v1 = v2; - v2 = new Vector(p1, p2); - double sign = Math.signum(v1.crossProduct(v2)); - if (sign0*sign < 0) { + /* check if there's no right turns in counter-clockwise traversal + * of the polygon vertices + */ + int n = vertices.size(); + for (int i = 0; i < n; i++) { + if (!Utils.isNonRightTurn(getPreviousVertex(i), + getVertex(i), getNextVertex(i))) { return false; } } @@ -233,6 +229,14 @@ return vertices.get(i); } + public Point getNextVertex(int i) { + return getVertex(i == vertices.size()-1 ? 0 : i+1); + } + + public Point getPreviousVertex(int i) { + return getVertex(i == 0 ? vertices.size()-1 : i-1); + } + public Point getFirstVertex() { return getVertex(0); } @@ -267,18 +271,39 @@ public Triangulation triangulate(PolygonTriangulationAlgorithm alg) { return alg.run(this); } - + + /** Order vertices so that the traversal order is counter clockwise */ + private void orderCounterClockwise() { + if (isClockwise()) { + Collections.reverse(vertices); + } + } + /** * Check if the traversal order of the vertices in the polygon is clockwise. * @return true for clockwise order and false for counter-clockwise */ - public boolean isClockwise() { - return true; // TODO: implement + boolean isClockwise() { + int n = vertices.size(); + // find rightmost vertex + int maxIdx = 0; + double maxX = Double.MIN_VALUE; + for (int i = 0; i < n; i++) { + if (vertices.get(i).getX() > maxX) { + maxIdx = i; + maxX = vertices.get(i).getX(); + } + } + // check if the the turn at this point is wrong + return isConcaveVertex(maxIdx) + || getPreviousVertex(maxIdx).getX() == getVertex(maxIdx).getX() + && getVertex(maxIdx).getX() == getNextVertex(maxIdx).getX() + && getPreviousVertex(maxIdx).getY() < getNextVertex(maxIdx).getY(); } /** Check if the vertex number i is convex */ public boolean isConvexVertex(int i) { - return true; // TODO: implement + return Utils.isNonRightTurn(getPreviousVertex(i), getVertex(i), getNextVertex(i)); } /** Check if the vertex number i is concave */ Modified: trunk/src/net/sourceforge/geom4j/PolygonTest.java =================================================================== --- trunk/src/net/sourceforge/geom4j/PolygonTest.java 2010-01-16 11:32:17 UTC (rev 31) +++ trunk/src/net/sourceforge/geom4j/PolygonTest.java 2010-01-16 23:19:49 UTC (rev 32) @@ -33,13 +33,13 @@ public void setUp() throws Exception { p = new Polygon( new Point(1, 4), - new Point(4, 8), + new Point(3, 4), + new Point(3, 6), + new Point(7, 3), + new Point(11, 6), + new Point(8, 10), new Point(8, 8), - new Point(8, 10), - new Point(11, 6), - new Point(7, 3), - new Point(3, 6), - new Point(3, 4)); + new Point(4, 8)); } @Test @@ -158,4 +158,72 @@ new Point(20, 20)) .isSimple()); } + + @Test + public void testIsClockwise() { + assertFalse(new Polygon( + new Point(4, 4), + new Point(5, 3), + new Point(6, 4), + new Point(5, 5)).isClockwise()); + assertFalse(new Polygon( + new Point(4, 4), + new Point(5, 5), + new Point(6, 4), + new Point(5, 3)).isClockwise()); + assertFalse(new Polygon( + new Point(4, 4), + new Point(5, 3), + new Point(6, 3), + new Point(6, 4), + new Point(6, 5), + new Point(5, 5)).isClockwise()); + } + + @Test + public void testConvexAndConcaveVertex1() { + Polygon p = new Polygon( + new Point(4, 4), //0 + new Point(5, 3), //1 + new Point(6, 3), //2 + new Point(6, 4), //3 + new Point(6, 5), //4 + new Point(5, 6), //5 + new Point(6, 7), //6 + new Point(5, 7), //7 + new Point(4, 6)); //8 + assertTrue(p.isConvexVertex(0)); + assertTrue(p.isConvexVertex(1)); + assertTrue(p.isConvexVertex(2)); + assertTrue(p.isConvexVertex(3)); + assertTrue(p.isConvexVertex(4)); + assertTrue(p.isConcaveVertex(5)); + assertTrue(p.isConvexVertex(6)); + assertTrue(p.isConvexVertex(7)); + assertTrue(p.isConvexVertex(8)); + + } + + @Test + public void testConvexAndConcaveVertex2() { + assertTrue(p.isConvexVertex(0)); + assertTrue(p.isConvexVertex(1)); + assertTrue(p.isConcaveVertex(2)); + assertTrue(p.isConvexVertex(3)); + assertTrue(p.isConvexVertex(4)); + assertTrue(p.isConvexVertex(5)); + assertTrue(p.isConcaveVertex(6)); + assertTrue(p.isConvexVertex(7)); + } + + @Test + public void testPreviousAndNextVertex() { + assertEquals(new Point(4, 8), p.getPreviousVertex(0)); + assertEquals(new Point(3, 4), p.getNextVertex(0)); + assertEquals(new Point(7, 3), p.getPreviousVertex(4)); + assertEquals(new Point(8, 10), p.getNextVertex(4)); + assertEquals(new Point(8, 8), p.getPreviousVertex(7)); + assertEquals(new Point(1, 4), p.getNextVertex(7)); + } } + Added: trunk/src/net/sourceforge/geom4j/util/Utils.java =================================================================== --- trunk/src/net/sourceforge/geom4j/util/Utils.java (rev 0) +++ trunk/src/net/sourceforge/geom4j/util/Utils.java 2010-01-16 23:19:49 UTC (rev 32) @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Sergey Khenkin. All rights reserved. + * Licensed 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 net.sourceforge.geom4j.util; + +import net.sourceforge.geom4j.Point; +import net.sourceforge.geom4j.Vector; + +/** + * Miscellaneous utility functions. + * + * @author Sergey Khenkin + * @since 1.0.0 + */ +public class Utils { + /** + * Test if p1-p2-p3 form a non-left turn, i.e. straight line or right turn + */ + public static boolean isNonLeftTurn(Point p1, Point p2, Point p3) { + return pointProduct(p1, p2, p3) <= 0; + } + + /** + * Test if p1-p2-p3 form a non-right turn, i.e. straight line or left turn + */ + public static boolean isNonRightTurn(Point p1, Point p2, Point p3) { + return pointProduct(p1, p2, p3) >= 0; + } + + private static double pointProduct(Point p1, Point p2, Point p3) { + Vector v1 = new Vector(p1, p2); + Vector v2 = new Vector(p2, p3); + return v1.crossProduct(v2); + } +} Added: trunk/src/net/sourceforge/geom4j/util/UtilsTest.java =================================================================== --- trunk/src/net/sourceforge/geom4j/util/UtilsTest.java (rev 0) +++ trunk/src/net/sourceforge/geom4j/util/UtilsTest.java 2010-01-16 23:19:49 UTC (rev 32) @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009 Sergey Khenkin. All rights reserved. + * Licensed 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 net.sourceforge.geom4j.util; + +import net.sourceforge.geom4j.Point; + +import org.junit.Test; +import static net.sourceforge.geom4j.util.Utils.*; +import static org.junit.Assert.*; + +/** + * Tests for miscellaneous utility functions + * + * @author Sergey Khenkin + * @since 1.0.0 + */ +public class UtilsTest { + @Test + public void testNonLeftTurn() { + assertTrue(isNonLeftTurn(new Point(5, 5), new Point(9, 8), new Point(11, 3))); + assertTrue(isNonLeftTurn(new Point(5, 5), new Point(9, 9), new Point(11, 11))); + assertFalse(isNonLeftTurn(new Point(5, 5), new Point(9, 9), new Point(8, 11))); + } + + @Test + public void testNonRightTurn() { + assertFalse(isNonRightTurn(new Point(5, 5), new Point(9, 8), new Point(11, 3))); + assertTrue(isNonRightTurn(new Point(5, 5), new Point(9, 9), new Point(11, 11))); + assertTrue(isNonRightTurn(new Point(5, 5), new Point(9, 9), new Point(8, 11))); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |