Fixed gate passing algorithm

boats now must pass through the correct way. This works for start in-race and finish gates
Refactored yacht algorithm code for better readability
Logging function added or seeing mark roundings occur

tags: #story[1124] #pair[hyi25, wmu16]
This commit is contained in:
William Muir
2017-08-08 15:58:13 +12:00
parent ed0a783374
commit b0e7dddaf3
2 changed files with 131 additions and 48 deletions
+130 -47
View File
@@ -58,10 +58,12 @@ public class Yacht {
private GeoPoint location; private GeoPoint location;
private Integer boatStatus; private Integer boatStatus;
private Double velocity; private Double velocity;
//MARK ROUNDING INFO //MARK ROUNDING INFO
private GeoPoint lastLocation; //For purposes of mark rounding calculations private GeoPoint lastLocation; //For purposes of mark rounding calculations
private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round
private Boolean hasPassedFirstLine; //The line extrapolated from the next mark to the current mark private Boolean hasPassedFirstLine; //The line extrapolated from the next mark to the current mark
private Boolean hasPassedThroughGate;
//CLIENT SIDE //CLIENT SIDE
private List<YachtLocationListener> locationListeners = new ArrayList<>(); private List<YachtLocationListener> locationListeners = new ArrayList<>();
@@ -88,6 +90,7 @@ public class Yacht {
this.hasEnteredRoundingZone = false; this.hasEnteredRoundingZone = false;
this.hasPassedFirstLine = false; this.hasPassedFirstLine = false;
this.hasPassedThroughGate = false;
} }
/** /**
@@ -129,7 +132,7 @@ public class Yacht {
//CHECK FOR MARK ROUNDING //CHECK FOR MARK ROUNDING
//Algorithm wont currently work on last gate and start gate //Algorithm wont currently work on last gate and start gate
checkForMarkRounding(); checkForLegProgression();
// TODO: 3/08/17 wmu16 - Implement line cross check here // TODO: 3/08/17 wmu16 - Implement line cross check here
} }
@@ -157,70 +160,139 @@ public class Yacht {
} }
/**
* 4 Different cases of progression in the race
* 1 - Passing the start line
* 2 - Passing any in-race Gate
* 3 - Passing any in-race Mark
* 4 - Passing the finish line
*/
private void checkForLegProgression() {
CompoundMark currentMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID);
if (currentMarkSeqID == 0) {
checkStartLineCrossing(currentMark);
} else if (GameState.getMarkOrder().isLastMark(currentMarkSeqID)) {
checkFinishLineCrossing(currentMark);
} else if (currentMark.isGate()) {
checkGateRounding(currentMark);
} else {
checkMarkRounding(currentMark);
}
}
/**
* If we pass the start line gate in the correct direction, progress
*
* @param currentMark The current gate
*/
private void checkStartLineCrossing(CompoundMark currentMark) {
Integer crossedLine = GeoUtility.checkCrossedLine(currentMark.getSubMark(1),
currentMark.getSubMark(2), lastLocation, location);
if (crossedLine > 0) {
CompoundMark nextMark = GameState.getMarkOrder().getNextMark(currentMarkSeqID);
Boolean isClockwiseCross = GeoUtility.isClockwise(currentMark.getSubMark(1),
currentMark.getSubMark(2),
nextMark.getSubMark(1));
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
logMarkRounding(currentMark);
currentMarkSeqID++;
}
}
}
/** /**
* This algorithm checks for mark rounding. And increments the currentMarSeqID number attribute * This algorithm checks for mark rounding. And increments the currentMarSeqID number attribute
* of the yacht if so. * of the yacht if so.
* The algorithm works by using the last mark, the current mark, the next mark and the change in * The algorithm works by using the last mark, the current mark, the next mark and the change in
* boats location, like so: * boats location, like so:
* -Condition 1: * -Condition 1:
* The boat has entered the mark rounding distance * The boat has entered the mark rounding distance
* -Condition 2: * -Condition 2:
* The boat has passed the line extending from the last mark to the current mark * The boat has passed the line extending from the last mark to the current mark
* -Condition 3: * -Condition 3:
* The boat has passed the line extending from the next mark to the current mark * The boat has passed the line extending from the next mark to the current mark
* *
* A more visual representation of this algorithm can be seen on the Wiki under * A more visual representation of this algorithm can be seen on the Wiki under
* 'mark passing algorithm' * 'mark passing algorithm'
*/ */
private void checkForMarkRounding() { private void checkMarkRounding(CompoundMark currentMark) {
CompoundMark currentMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID); distanceToNextMark = calcDistanceToNextMark();
CompoundMark nextMark = GameState.getMarkOrder().getNextMark(currentMarkSeqID);
CompoundMark prevMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID);
if (GameState.getMarkOrder().isLastMark(currentMarkSeqID) || currentMarkSeqID == 0) { //1 TEST FOR ENTERING THE ROUNDING DISTANCE
if (GeoUtility.checkCrossedLine(currentMark.getSubMark(1), if (distanceToNextMark < ROUNDING_DISTANCE) {
currentMark.getSubMark(2), lastLocation, location) > 0) { hasEnteredRoundingZone = true;
System.out.println( }
"(" + currentMarkSeqID + ") Passed gate: " + currentMark.getMarks().get(0)
.getName() //If the current mark is a gate mark we need to check both its marks for rounding, thus
+ " ID(" + currentMark.getId() + ")"); //we loop
currentMarkSeqID++; for (Mark thisCurrentMark : currentMark.getMarks()) {
//2 TEST FOR CROSSING NEXT - CURRENT LINE FIRST
if (GeoUtility
.isPointInTriangle(lastLocation, location, nextMark.getMarks().get(0),
thisCurrentMark)) {
hasPassedFirstLine = true;
} }
} else { //3 TEST FOR CROSSING PREV - CURRENT LINE SECOND
//ALL OTHER MARKS if (GeoUtility
distanceToNextMark = calcDistanceToNextMark(); .isPointInTriangle(lastLocation, location, prevMark.getMarks().get(0),
// System.out.println("distanceToNextMark = " + distanceToNextMark); thisCurrentMark)) {
CompoundMark nextMark = GameState.getMarkOrder().getNextMark(currentMarkSeqID); if (hasPassedFirstLine && hasEnteredRoundingZone) {
currentMarkSeqID++;
hasPassedFirstLine = false;
hasEnteredRoundingZone = false;
hasPassedThroughGate = false;
logMarkRounding(currentMark);
break;
}
}
}
}
/**
* Checks if a gate line has been crossed and in the correct direction
*
* @param currentMark The current gate
*/
private void checkGateRounding(CompoundMark currentMark) {
Integer crossedLine = GeoUtility.checkCrossedLine(currentMark.getSubMark(1),
currentMark.getSubMark(2), lastLocation, location);
//We have crossed the line
if (crossedLine > 0) {
CompoundMark prevMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID); CompoundMark prevMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID);
Boolean isClockwiseCross = GeoUtility.isClockwise(currentMark.getSubMark(1),
//1 TEST FOR ENTERING THE ROUDNING DISTANCE currentMark.getSubMark(2),
if (distanceToNextMark < ROUNDING_DISTANCE) { prevMark.getSubMark(1));
hasEnteredRoundingZone = true; if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
// System.out.println("Entered rounding zone!"); hasPassedThroughGate = true;
} }
}
//If the current mark is a gate mark we need to check both its marks for rounding, thus if (hasPassedThroughGate) {
//we loop checkMarkRounding(currentMark);
for (Mark thisCurrentMark : currentMark.getMarks()) { }
}
//2 TEST FOR CROSSING NEXT - CURRENT LINE FIRST /**
if (GeoUtility.isPointInTriangle(lastLocation, location, nextMark.getMarks().get(0), * If we pass the finish gate in the correct direction // TODO: 8/08/17 wmu16 - do something
thisCurrentMark)) { *
hasPassedFirstLine = true; * @param currentMark The current gate
} */
private void checkFinishLineCrossing(CompoundMark currentMark) {
//3 TEST FOR CROSSING PREV - CURRENT LINE SECOND Integer crossedLine = GeoUtility.checkCrossedLine(currentMark.getSubMark(1),
if (GeoUtility.isPointInTriangle(lastLocation, location, prevMark.getMarks().get(0), currentMark.getSubMark(2), lastLocation, location);
thisCurrentMark)) { if (crossedLine > 0) {
if (hasPassedFirstLine && hasEnteredRoundingZone) { CompoundMark previousMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID);
currentMarkSeqID++; Boolean isClockwiseCross = GeoUtility.isClockwise(currentMark.getSubMark(1),
hasPassedFirstLine = false; currentMark.getSubMark(2),
hasEnteredRoundingZone = false; previousMark.getSubMark(1));
System.out.println( if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
"(" + currentMarkSeqID + ") Passed mark: " + currentMark.getMarks() logMarkRounding(currentMark);
.get(0).getName() // TODO: 8/08/17 wmu16 - Do something!
+ " ID(" + currentMark.getId() + ")");
break;
}
}
} }
} }
} }
@@ -508,6 +580,17 @@ public class Yacht {
} }
} }
private void logMarkRounding(CompoundMark currentMark) {
String typeString = "mark";
if (currentMark.isGate()) {
typeString = "gate";
}
System.out.println(
"(" + currentMarkSeqID + ") Passed " + typeString + ": " + currentMark.getMarks().get(0)
.getName()
+ " ID(" + currentMark.getId() + ")");
}
public void addLocationListener (YachtLocationListener listener) { public void addLocationListener (YachtLocationListener listener) {
locationListeners.add(listener); locationListeners.add(listener);
} }
@@ -193,7 +193,7 @@ public class GeoUtility {
* @param point the point to be tested * @param point the point to be tested
* @return true if the point is on the RHS of the line * @return true if the point is on the RHS of the line
*/ */
private static Boolean isClockwise(GeoPoint v1, GeoPoint v2, GeoPoint point) { public static Boolean isClockwise(GeoPoint v1, GeoPoint v2, GeoPoint point) {
return getBearingDiff(getBearing(v1, v2), getBearing(v1, point)) < 180; return getBearingDiff(getBearing(v1, v2), getBearing(v1, point)) < 180;
} }