diff --git a/geom/src/main/java/org/geolatte/geom/cga/CircularArcLinearizer.java b/geom/src/main/java/org/geolatte/geom/cga/CircularArcLinearizer.java index cbdbd23e..afd8c4e9 100644 --- a/geom/src/main/java/org/geolatte/geom/cga/CircularArcLinearizer.java +++ b/geom/src/main/java/org/geolatte/geom/cga/CircularArcLinearizer.java @@ -23,7 +23,7 @@ public class CircularArcLinearizer

{ final private P p1; final private P p2; final private Circle c; - final private boolean isCounterClockwise; + final private NumericalMethods.Orientation orientation; final private PositionSequenceBuilder

builder; //TODO threshold must become parameter of linearize/linearizeCircle!! @@ -37,7 +37,7 @@ public CircularArcLinearizer(P p0, P p1, P p2, double threshold) { this.p1 = p1; this.p2 = p2; this.c = new Circle(p0, p1, p2, false); - this.isCounterClockwise = NumericalMethods.isCounterClockwise(p0, p1, p2); + this.orientation = NumericalMethods.orientation(p0, p1, p2); this.builder = variableSized((Class

) p0.getClass()); } @@ -89,23 +89,28 @@ public PositionSequence

linearize() { //now we "walk" from theta, over theta1 to theta2 (or inversely) PositionSequenceBuilder

builder = variableSized((Class

) p0.getClass()); - if (isCounterClockwise) { - builder.add(p0); - AddPointsBetweenPolarCoordinates(theta0, theta1, p0, p1, angleIncr, builder); - builder.add(p1); - AddPointsBetweenPolarCoordinates(theta1, theta2, p1, p2, angleIncr, builder); - builder.add(p2); - return builder.toPositionSequence(); - } else { - // If clockwise, we have to do it reverse - builder.add(p2); - AddPointsBetweenPolarCoordinates(theta2, theta1, p2, p1, angleIncr, builder); - builder.add(p1); - AddPointsBetweenPolarCoordinates(theta1, theta0, p1, p0, angleIncr, builder); - builder.add(p0); - return builder.toPositionSequence().reverse(); + switch (orientation) { + case Counterclockwise: + builder.add(p0); + AddPointsBetweenPolarCoordinates(theta0, theta1, p0, p1, angleIncr, builder); + builder.add(p1); + AddPointsBetweenPolarCoordinates(theta1, theta2, p1, p2, angleIncr, builder); + builder.add(p2); + return builder.toPositionSequence(); + case Clockwise: + // If clockwise, we have to do it reverse + builder.add(p2); + AddPointsBetweenPolarCoordinates(theta2, theta1, p2, p1, angleIncr, builder); + builder.add(p1); + AddPointsBetweenPolarCoordinates(theta1, theta0, p1, p0, angleIncr, builder); + builder.add(p0); + return builder.toPositionSequence().reverse(); + default: + builder.add(p0); + builder.add(p1); + builder.add(p2); + return builder.toPositionSequence(); } - } // Adds points strictly between theta and theta1, using the specified angle-increment diff --git a/geom/src/main/java/org/geolatte/geom/cga/NumericalMethods.java b/geom/src/main/java/org/geolatte/geom/cga/NumericalMethods.java index 44ac9971..6f2e0ac5 100644 --- a/geom/src/main/java/org/geolatte/geom/cga/NumericalMethods.java +++ b/geom/src/main/java/org/geolatte/geom/cga/NumericalMethods.java @@ -11,6 +11,14 @@ */ public class NumericalMethods { + public static enum Orientation { + Clockwise, Counterclockwise, Colinear + } + + public final static int ClockWise = 1; + public final static int CounterClockWise = 2; + + /** * Calculates the determinant of a 2x2 matrix * @@ -69,12 +77,12 @@ public static double determinant(double a11, double a12, double a13, double a21, * @param p2 * @return true if counterclockwise */ - public static boolean isCounterClockwise(Position p0, Position p1, Position p2) { + public static Orientation orientation(Position p0, Position p1, Position p2) { double det = deltaDeterminant(p0, p1, p2); if (det == 0) { - throw new IllegalArgumentException("Positions are collinear in 2D"); + return Orientation.Colinear; } - return det > 0; + return det > 0? Orientation.Counterclockwise : Orientation.Clockwise; } /** diff --git a/geom/src/test/java/org/geolatte/geom/cga/CircularArcLinearizerTest.java b/geom/src/test/java/org/geolatte/geom/cga/CircularArcLinearizerTest.java index 1707a1ab..dcb1ba9e 100644 --- a/geom/src/test/java/org/geolatte/geom/cga/CircularArcLinearizerTest.java +++ b/geom/src/test/java/org/geolatte/geom/cga/CircularArcLinearizerTest.java @@ -4,6 +4,8 @@ import static java.lang.Math.sin; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static org.geolatte.geom.cga.NumericalMethods.Orientation.Clockwise; +import static org.geolatte.geom.cga.NumericalMethods.Orientation.Counterclockwise; import static org.junit.Assert.assertEquals; import org.geolatte.geom.C2D; @@ -281,8 +283,8 @@ public ThreePointSample sample() { } // verify that we actually do return as expected. - assert ((isCCW && NumericalMethods.isCounterClockwise(positions[0], positions[1], positions[2])) || - (!isCCW && !NumericalMethods.isCounterClockwise(positions[0], positions[1], positions[2])) ); + assert ((isCCW && Counterclockwise ==NumericalMethods.orientation(positions[0], positions[1], positions[2])) || + (!isCCW && Clockwise == NumericalMethods.orientation(positions[0], positions[1], positions[2])) ); return new ThreePointSample(isCCW, theta, positions); diff --git a/geom/src/test/java/org/geolatte/geom/codec/db/oracle/SmallArcBugTest.java b/geom/src/test/java/org/geolatte/geom/codec/db/oracle/SmallArcBugTest.java new file mode 100644 index 00000000..bfdd5929 --- /dev/null +++ b/geom/src/test/java/org/geolatte/geom/codec/db/oracle/SmallArcBugTest.java @@ -0,0 +1,22 @@ +package org.geolatte.geom.codec.db.oracle; + +import org.geolatte.geom.Geometry; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +// for testing issue #151 +public class SmallArcBugTest { + + @Test + public void testCase1(){ + int[] elems = {1,1005,3,1,2,1,15,2,2,19,2,1}; + Double[] coords = {209499.475,578259.358,209503.708,578359.503,209505.325,578409.615,209505.144,578416.324,209504.933,578419.552,209505.118,578420.213,209505.693,578421.019,209500.401,578421.362,209500.401,578421.361,209500.402,578421.361,209500.832,578421.033,209501.057,578420.591,209501.063,578420.225,209499.607,578371.806,209497.623,578305.131,209495.574,578238.184,209495.409,578222.433,209495.062,578211.578,209498.02,578211.469,209499.475,578259.358}; + SDOGeometry sdo = SDOGeometryHelper.sdoGeometry( + 2003, 28992, null, elems, coords + ); + Geometry geom = Decoders.decode(sdo); + assertNotNull(geom); //check that this doesn't throw an exception + } + +}