Skip to content

Commit

Permalink
Fix for issue #151
Browse files Browse the repository at this point in the history
If an arc segment is colinear, then the positions are already linear. No need to throw an exception during linearization.
  • Loading branch information
maesenka committed Sep 17, 2022
1 parent 5f766ca commit 62c6ba0
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 23 deletions.
41 changes: 23 additions & 18 deletions geom/src/main/java/org/geolatte/geom/cga/CircularArcLinearizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class CircularArcLinearizer<P extends Position> {
final private P p1;
final private P p2;
final private Circle c;
final private boolean isCounterClockwise;
final private NumericalMethods.Orientation orientation;
final private PositionSequenceBuilder<P> builder;

//TODO threshold must become parameter of linearize/linearizeCircle!!
Expand All @@ -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<P>) p0.getClass());
}

Expand Down Expand Up @@ -89,23 +89,28 @@ public PositionSequence<P> linearize() {

//now we "walk" from theta, over theta1 to theta2 (or inversely)
PositionSequenceBuilder<P> builder = variableSized((Class<P>) 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
Expand Down
14 changes: 11 additions & 3 deletions geom/src/main/java/org/geolatte/geom/cga/NumericalMethods.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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
}

}

0 comments on commit 62c6ba0

Please sign in to comment.