diff --git a/src/main/java/seng302/model/Yacht.java b/src/main/java/seng302/model/Yacht.java index 34bbb4f0..f0adde0a 100644 --- a/src/main/java/seng302/model/Yacht.java +++ b/src/main/java/seng302/model/Yacht.java @@ -177,7 +177,7 @@ public class Yacht { if (GameState.getMarkOrder().isLastMark(currentMarkSeqID) || currentMarkSeqID == 0) { if (GeoUtility.checkCrossedLine(currentMark.getSubMark(1), - currentMark.getSubMark(2), lastLocation, location)) { + currentMark.getSubMark(2), lastLocation, location) > 0) { System.out.println( "(" + currentMarkSeqID + ") Passed gate: " + currentMark.getMarks().get(0) .getName() diff --git a/src/main/java/seng302/utilities/GeoUtility.java b/src/main/java/seng302/utilities/GeoUtility.java index 81acebe6..ab87c3be 100644 --- a/src/main/java/seng302/utilities/GeoUtility.java +++ b/src/main/java/seng302/utilities/GeoUtility.java @@ -1,10 +1,7 @@ package seng302.utilities; import javafx.geometry.Point2D; -import seng302.gameServer.GameState; import seng302.model.GeoPoint; -import seng302.model.mark.CompoundMark; -import seng302.model.mark.Mark; public class GeoUtility { @@ -96,7 +93,6 @@ public class GeoUtility { return new GeoPoint(Math.toDegrees(endLat), Math.toDegrees(endLng)); } - /** * Performs the line function on two points of a line and a test point to test which side of the * line that point is on. If the return value is return 1, then the point is on one side of the @@ -128,36 +124,32 @@ public class GeoUtility { } } - /** - * Checks if a point passes across a line, either direction - * See the wiki Mark Rounding algorithm for more info + * Checks if the line formed by lastLocation and location doesn't intersect the line segment + * formed by mark1 and mark2 See the wiki Mark Rounding algorithm for more info * * @param mark1 One mark of the line * @param mark2 The second mark of the line * @param lastLocation The last location of the point crossing this line * @param location The current location of the point crossing this line - * @return True if crossed since last location --> current location, false otherwise + * @return 0 if two line segment doesn't intersect, otherwise 1 if they intersect and + * lastLocation is on RHS of the line segment (mark1 -> mark2) or 2 if lastLocation on LHS of + * the line segment (mark1 -> mark2) */ - public static Boolean checkCrossedLine(GeoPoint mark1, GeoPoint mark2, GeoPoint lastLocation, + public static Integer checkCrossedLine(GeoPoint mark1, GeoPoint mark2, GeoPoint lastLocation, GeoPoint location) { - //START GATE OR FINISH GATE - Double alpha = GeoUtility.getBearing(mark1, lastLocation); - Double beta = GeoUtility.getBearing(mark1, mark2); - Double theta = GeoUtility.getBearing(mark1, location); - alpha = (alpha > 180) ? 360 - alpha : alpha; - beta = (beta > 180) ? 360 - beta : beta; - theta = (theta > 180) ? 360 - theta : theta; + boolean enteredDirection = isClockwise(mark1, mark2, lastLocation); + boolean exitedDirection = isClockwise(mark1, mark2, location); + if (enteredDirection != exitedDirection) { + if (!isPointInTriangle(mark1, lastLocation, location, mark2) + && !isPointInTriangle(mark2, lastLocation, location, mark1)) { - if (alpha < beta && theta > beta) { - if (!GeoUtility.isPointInTriangle(mark1, lastLocation, location, mark2)) { - return true; + return enteredDirection ? 1 : 2; } } - return false; + return 0; } - /** * Given a point and a vector (angle and vector length) Will create a new point, that vector * away from the origin point @@ -187,10 +179,24 @@ public class GeoUtility { * @param bearing2 the bearing of v2 * @return the difference of bearing from v1 to v2 */ - private static double getBearingDiff(double bearing1, double bearing2) { + private static Double getBearingDiff(double bearing1, double bearing2) { return ((360 - bearing1) + bearing2) % 360; } + /** + * Check if a geo point ins on the right hand side of the line segment, which + * formed by two geo points v1 -> v2. (Algorithm: point is clockwise to the + * line if the bearing difference is less than 180 deg.) + * + * @param v1 one end of the line segment + * @param v2 another end of the line segment + * @param point the point to be tested + * @return true if the point is on the RHS of the line + */ + private static Boolean isClockwise(GeoPoint v1, GeoPoint v2, GeoPoint point) { + return getBearingDiff(getBearing(v1, v2), getBearing(v1, point)) < 180; + } + /** * Given three geo points to form a triangle, the method returns true if the fourth point is * inside the triangle @@ -201,15 +207,15 @@ public class GeoUtility { * @param point the point to be tested * @return true if the fourth point is inside the triangle */ - public static boolean isPointInTriangle(GeoPoint v1, GeoPoint v2, GeoPoint v3, GeoPoint point) { + public static Boolean isPointInTriangle(GeoPoint v1, GeoPoint v2, GeoPoint v3, GeoPoint point) { // true, if diff of bearing from (v1->v2) to (v1->p) is less than 180 deg - boolean sideFlag = getBearingDiff(getBearing(v1, v2), getBearing(v1, point)) < 180; + boolean isCW = isClockwise(v1, v2, point); - if ((getBearingDiff(getBearing(v2, v3), getBearing(v2, point)) < 180) != sideFlag) { + if (isClockwise(v2, v3, point) != isCW) { return false; } - if ((getBearingDiff(getBearing(v3, v1), getBearing(v3, point)) < 180) != sideFlag) { + if (isClockwise(v3, v1, point) != isCW) { return false; } diff --git a/src/test/java/seng302/utilities/GeoUtilityTest.java b/src/test/java/seng302/utilities/GeoUtilityTest.java index 4bd1e128..109b1723 100644 --- a/src/test/java/seng302/utilities/GeoUtilityTest.java +++ b/src/test/java/seng302/utilities/GeoUtilityTest.java @@ -6,11 +6,8 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import javafx.geometry.Point2D; -import org.junit.Before; import org.junit.Test; import seng302.model.GeoPoint; -import seng302.model.mark.CompoundMark; -import seng302.utilities.GeoUtility; /** * http://www.geoplaner.com/ For plotting geo points for visualisation @@ -161,13 +158,16 @@ public class GeoUtilityTest { GeoPoint location1 = new GeoPoint(37.40964, -122.62196); GeoPoint location2 = new GeoPoint(37.40910, -122.62189); GeoPoint location3 = new GeoPoint(37.40949, -122.62202); - GeoPoint location4 = new GeoPoint(34.40955, -122.62176); - GeoPoint location5 = new GeoPoint(37.40927, -122.62152); - GeoPoint location6 = new GeoPoint(34.40933, -122.62163); + GeoPoint location4 = new GeoPoint(37.40927, -122.62152); - assertTrue(GeoUtility.checkCrossedLine(mark1, mark2, location1, location2)); - assertFalse(GeoUtility.checkCrossedLine(mark1, mark2, location4, location3)); - assertFalse(GeoUtility.checkCrossedLine(mark1, mark2, location1, location3)); - assertFalse(GeoUtility.checkCrossedLine(mark1, mark2, location5, location6)); + // M1 -> M3 enters from CCW side + assertTrue(GeoUtility.checkCrossedLine(mark1, mark2, location1, location2) == 2); + // M1 -> M3 doesn't across + assertFalse(GeoUtility.checkCrossedLine(mark1, mark2, location1, location3) > 0); + // M2 -> M3 enters from CW side + assertTrue(GeoUtility.checkCrossedLine(mark1, mark2, location2, location3) == 1); + // order changes intersect direction + assertTrue(GeoUtility.checkCrossedLine(mark2, mark1, location2, location3) == 2); + assertTrue(GeoUtility.checkCrossedLine(mark1, mark2, location3, location2) == 2); } } \ No newline at end of file