diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index c598eb05..9560b665 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -1,19 +1,13 @@ package mock.model; import mock.model.wind.WindGenerator; -import javafx.animation.AnimationTimer; import mock.model.collider.ColliderRegistry; -import mock.xml.*; -import network.Messages.BoatLocation; -import network.Messages.BoatStatus; import network.Messages.Enums.BoatStatusEnum; import network.Messages.Enums.RaceStatusEnum; -import network.Utils.AC35UnitConverter; import shared.dataInput.BoatDataSource; import shared.dataInput.RaceDataSource; import shared.dataInput.RegattaDataSource; import shared.exceptions.BoatNotFoundException; -import shared.enums.RoundingType; import shared.model.*; import shared.model.Bearing; @@ -358,8 +352,6 @@ public class MockRace extends RaceState { if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds && boat.isSailsOut()) { - checkPosition(boat, totalElapsedMilliseconds); - if (boat.getCurrentSpeed() == 0) { newOptimalVMG(boat); boat.setBearing(boat.calculateBearingToNextMarker()); @@ -373,6 +365,7 @@ public class MockRace extends RaceState { //Scale it. distanceTravelledMeters = distanceTravelledMeters * this.scaleFactor; + checkPosition(boat, totalElapsedMilliseconds); //Move the boat forwards that many meters, and advances its time counters by enough milliseconds. boat.moveForwards(distanceTravelledMeters); @@ -515,32 +508,28 @@ public class MockRace extends RaceState { /** * Checks to be run on boats rounding marks on the port side * @param boat the boat that is rounding a mark - * @param roundingChecks the checks to run - * @param legBearing the direction of the leg + * @param roundingData The data for the current leg's rounding. */ - private void boatRoundingCheckPort(MockBoat boat, List roundingChecks, Bearing legBearing) { + private void boatRoundingCheckPort(MockBoat boat, MarkRoundingData roundingData) { //boats must pass all checks in order to round a mark //boolean for if boat has to/needs to pass through a gate boolean gateCheck = boat.getCurrentLeg().getEndCompoundMark().getMark2() == null || boat.isBetweenGate(boat.getCurrentLeg().getEndCompoundMark()); - Mark roundingMark = boat.getCurrentLeg().getEndCompoundMark().getMarkForRounding(legBearing); - System.out.println("boat rounding state: " + boat.getRoundingStatus());//TEMP REMOVE + switch (boat.getRoundingStatus()) { case 0://hasn't started rounding - System.out.println("portside? " + boat.isPortSide(roundingMark));//TEMP REMOVE - System.out.println("passes line? " + GPSCoordinate.passesLine(roundingMark.getPosition(), roundingChecks.get(0), boat.getPosition(), legBearing));//TEMP REMOVE - System.out.println("gatecheck? " + gateCheck);//TEMP REMOVE - System.out.println("between gates? " + boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0))));//TEMP REMOVE - if (boat.isPortSide(roundingMark) && + if (boat.isPortSide(roundingData.getMarkToRound()) && GPSCoordinate.passesLine( - roundingMark.getPosition(), - roundingChecks.get(0), + roundingData.getMarkToRound().getPosition(), + roundingData.getRoundCheck1(), boat.getPosition(), - legBearing) && + roundingData.getLegBearing()) && gateCheck && - boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) { + boat.isBetweenGate( + roundingData.getMarkToRound(), + Mark.tempMark(roundingData.getRoundCheck1())) ) { boat.increaseRoundingStatus(); if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){ //boat has finished race @@ -549,13 +538,18 @@ public class MockRace extends RaceState { } break; case 1://has been parallel to the mark; - if (boat.isPortSide(roundingMark) && + if (boat.isPortSide(roundingData.getMarkToRound()) && GPSCoordinate.passesLine( - roundingMark.getPosition(), - roundingChecks.get(1), + roundingData.getMarkToRound().getPosition(), + roundingData.getRoundCheck2(), boat.getPosition(), - Bearing.fromDegrees(legBearing.degrees() - 90)) &&//negative 90 from bearing because of port rounding - boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) { + Bearing.fromDegrees( + GPSCoordinate.calculateBearing( + roundingData.getMarkToRound().getPosition(), + roundingData.getRoundCheck2()).degrees() - 90)) &&//negative 90 from bearing because of port rounding + boat.isBetweenGate( + roundingData.getMarkToRound(), + Mark.tempMark(roundingData.getRoundCheck2()))) { boat.increaseRoundingStatus(); } break; @@ -571,25 +565,27 @@ public class MockRace extends RaceState { /** * Checks to be run on boats rounding marks on the starboard side * @param boat the boat that is rounding a mark - * @param roundingChecks the checks to run - * @param legBearing the direction of the leg + * @param roundingData The data for the current leg's rounding. */ - private void boatRoundingCheckStarboard(MockBoat boat, List roundingChecks, Bearing legBearing){ + private void boatRoundingCheckStarboard(MockBoat boat, MarkRoundingData roundingData){ //boats must pass all checks in order to round a mark //boolean for if boat has to/needs to pass through a gate boolean gateCheck = boat.getCurrentLeg().getEndCompoundMark().getMark2() == null || boat.isBetweenGate(boat.getCurrentLeg().getEndCompoundMark()); - Mark roundingMark = boat.getCurrentLeg().getEndCompoundMark().getMarkForRounding(legBearing); - System.out.println("boat rounding state: " + boat.getRoundingStatus());//TEMP REMOVE switch (boat.getRoundingStatus()) { case 0://hasn't started rounding - if (boat.isStarboardSide(roundingMark) && - GPSCoordinate.passesLine(roundingMark.getPosition(), - roundingChecks.get(0), boat.getPosition(), legBearing) && + if (boat.isStarboardSide(roundingData.getMarkToRound()) && + GPSCoordinate.passesLine( + roundingData.getMarkToRound().getPosition(), + roundingData.getRoundCheck1(), + boat.getPosition(), + roundingData.getLegBearing()) && gateCheck && - boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) { + boat.isBetweenGate( + roundingData.getMarkToRound(), + Mark.tempMark(roundingData.getRoundCheck1()))) { boat.increaseRoundingStatus(); if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){ //boat has finished race @@ -598,10 +594,18 @@ public class MockRace extends RaceState { } break; case 1://has been parallel to the mark - if (boat.isStarboardSide(roundingMark) && - GPSCoordinate.passesLine(roundingMark.getPosition(), - roundingChecks.get(1), boat.getPosition(), Bearing.fromDegrees(legBearing.degrees() + 90)) && //positive 90 from bearing because of starboard rounding - boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) { + if (boat.isStarboardSide(roundingData.getMarkToRound()) && + GPSCoordinate.passesLine( + roundingData.getMarkToRound().getPosition(), + roundingData.getRoundCheck2(), + boat.getPosition(), + Bearing.fromDegrees( + GPSCoordinate.calculateBearing( + roundingData.getMarkToRound().getPosition(), + roundingData.getRoundCheck2() ).degrees() + 90)) && //positive 90 from bearing because of starboard rounding + boat.isBetweenGate( + roundingData.getMarkToRound(), + Mark.tempMark(roundingData.getRoundCheck2())) ) { boat.increaseRoundingStatus(); } break; @@ -620,84 +624,29 @@ public class MockRace extends RaceState { * @param timeElapsed The total time, in milliseconds, that has elapsed since the race started. */ protected void checkPosition(MockBoat boat, long timeElapsed) { - //The distance, in nautical miles, within which the boat needs to get in order to consider that it has reached the marker. - double epsilonMeters = boat.getCurrentLeg().getEndCompoundMark().getRoundingDistance(); //250 meters. - //System.out.println("epsilon dist meters: " + epsilonMeters);//TEMP REMOVE - - //System.out.println("boat dist to next point NM: " + boat.calculateDistanceToNextMarker());//TEMP REMOVE - - double epsilonNM = epsilonMeters / Constants.NMToMetersConversion; - - //System.out.println("epsilon NM: " + epsilonNM);//TEMP REMOVE - - if (boat.calculateDistanceToNextMarker() < epsilonNM) { - //Boat is within an acceptable distance from the mark. - - GPSCoordinate startDirectionLinePoint = boat.getCurrentLeg().getStartCompoundMark().getAverageGPSCoordinate(); - GPSCoordinate endDirectionLinePoint = boat.getCurrentLeg().getEndCompoundMark().getAverageGPSCoordinate(); - Bearing bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint); - - //use the direction line to create three invisible points that act as crossover lines a boat must cross - //to round a mark - - double bearingToAdd; - //System.out.println("leg: " + boat.getCurrentLeg().getName() + " has bearing DL of: " + bearingOfDirectionLine.degrees());//TEMP REMOVE - if (boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.Port || - boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.SP){ - bearingToAdd = 90; - }else{ - bearingToAdd = -90; - } - - //System.out.println("so new bearing is " + (bearingToAdd + bearingOfDirectionLine.degrees()));//TEMP REMOVE - - GPSCoordinate roundCheck1 = GPSCoordinate.calculateNewPosition( - endDirectionLinePoint, - epsilonMeters, - Azimuth.fromDegrees(bearingOfDirectionLine.degrees() + bearingToAdd) ); - //System.out.println("this has a rounding coordinate of (" + roundCheck1.getLongitude() + ", " + roundCheck1.getLatitude() + ")");//TEMP REMOVE - - GPSCoordinate roundCheck2; - try{ - Leg nextLeg = getLegs().get(getLegs().indexOf(boat.getCurrentLeg()) + 1); - - GPSCoordinate startNextDirectionLinePoint = nextLeg.getStartCompoundMark().getAverageGPSCoordinate(); - GPSCoordinate endNextDirectionLinePoint = nextLeg.getEndCompoundMark().getAverageGPSCoordinate(); - Bearing bearingOfNextDirectionLine = GPSCoordinate.calculateBearing(startNextDirectionLinePoint, endNextDirectionLinePoint); - - roundCheck2 = GPSCoordinate.calculateNewPosition( - endDirectionLinePoint, - epsilonMeters, - Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees() + bearingToAdd) ); - }catch(NullPointerException e){ - //this is caused by the last leg not being having a leg after it - roundCheck2 = roundCheck1; - } - - List roundingChecks = new ArrayList<>(Arrays.asList(roundCheck1, roundCheck2)); - - switch (boat.getCurrentLeg().getEndCompoundMark().getRoundingType()) { - case SP://Not yet implemented so these gates will be rounded port side - case Port: - boatRoundingCheckPort(boat, roundingChecks, bearingOfDirectionLine); - break; - case PS://not yet implemented so these gates will be rounded starboard side - case Starboard: - boatRoundingCheckStarboard(boat, roundingChecks, bearingOfDirectionLine); - break; - } - - System.out.println("resultant boat rounding state: " + boat.getRoundingStatus());//TEMP REMOVE + switch (boat.getCurrentLeg().getEndCompoundMark().getRoundingType()) { + case SP://Not yet implemented so these gates will be rounded port side + case Port: + boatRoundingCheckPort( + boat, + getMarkRoundingSequence().getRoundingData(boat.getCurrentLeg()) ); + break; + case PS://not yet implemented so these gates will be rounded starboard side + case Starboard: + boatRoundingCheckStarboard( + boat, + getMarkRoundingSequence().getRoundingData(boat.getCurrentLeg()) ); + break; + } - //Check if the boat has finished or stopped racing. - if (this.isLastLeg(boat.getCurrentLeg())) { - //Boat has finished. - boat.setTimeFinished(timeElapsed); - boat.setCurrentSpeed(0); - boat.setStatus(BoatStatusEnum.FINISHED); - } + //Check if the boat has finished or stopped racing. + if (this.isLastLeg(boat.getCurrentLeg())) { + //Boat has finished. + boat.setTimeFinished(timeElapsed); + boat.setCurrentSpeed(0); + boat.setStatus(BoatStatusEnum.FINISHED); } diff --git a/racevisionGame/src/main/java/shared/model/MarkRoundingData.java b/racevisionGame/src/main/java/shared/model/MarkRoundingData.java new file mode 100644 index 00000000..c9fb36a2 --- /dev/null +++ b/racevisionGame/src/main/java/shared/model/MarkRoundingData.java @@ -0,0 +1,118 @@ +package shared.model; + + + +/** + * Contains data related to mark rounding for a specific leg. + */ +public class MarkRoundingData { + + /** + * The leg this relates to. + */ + private Leg leg; + + /** + * The mark that should be rounded. + */ + private Mark markToRound; + + /** + * The bearing of the leg. + */ + private Bearing legBearing; + + /** + * The bearing of the next leg. + */ + private Bearing nextLegBearing; + + /** + * The location of the first rounding check point. + */ + private GPSCoordinate roundCheck1; + + /** + * The location of the second rounding check point. + */ + private GPSCoordinate roundCheck2; + + /** + * A halfway point between mark to round and roundCheck1. + */ + private GPSCoordinate roundCheck1Halfway; + + /** + * A halfway point between mark to round and roundCheck2. + */ + private GPSCoordinate roundCheck2Halfway; + + + public MarkRoundingData() { + } + + + public Leg getLeg() { + return leg; + } + + public void setLeg(Leg leg) { + this.leg = leg; + } + + public Mark getMarkToRound() { + return markToRound; + } + + public void setMarkToRound(Mark markToRound) { + this.markToRound = markToRound; + } + + public Bearing getLegBearing() { + return legBearing; + } + + public void setLegBearing(Bearing legBearing) { + this.legBearing = legBearing; + } + + public Bearing getNextLegBearing() { + return nextLegBearing; + } + + public void setNextLegBearing(Bearing nextLegBearing) { + this.nextLegBearing = nextLegBearing; + } + + public GPSCoordinate getRoundCheck1() { + return roundCheck1; + } + + public void setRoundCheck1(GPSCoordinate roundCheck1) { + this.roundCheck1 = roundCheck1; + } + + public GPSCoordinate getRoundCheck2() { + return roundCheck2; + } + + public void setRoundCheck2(GPSCoordinate roundCheck2) { + this.roundCheck2 = roundCheck2; + } + + public GPSCoordinate getRoundCheck1Halfway() { + return roundCheck1Halfway; + } + + public void setRoundCheck1Halfway(GPSCoordinate roundCheck1Halfway) { + this.roundCheck1Halfway = roundCheck1Halfway; + } + + public GPSCoordinate getRoundCheck2Halfway() { + return roundCheck2Halfway; + } + + public void setRoundCheck2Halfway(GPSCoordinate roundCheck2Halfway) { + this.roundCheck2Halfway = roundCheck2Halfway; + } +} diff --git a/racevisionGame/src/main/java/shared/model/MarkRoundingSequence.java b/racevisionGame/src/main/java/shared/model/MarkRoundingSequence.java index 48fc3999..de11c170 100644 --- a/racevisionGame/src/main/java/shared/model/MarkRoundingSequence.java +++ b/racevisionGame/src/main/java/shared/model/MarkRoundingSequence.java @@ -1,11 +1,8 @@ package shared.model; -import org.jetbrains.annotations.Nullable; +import java.util.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import static shared.enums.RoundingType.*; /** * This class contains a sequence of points that describe the mark rounding order for a course. @@ -19,9 +16,9 @@ public class MarkRoundingSequence { private List legs; /** - * For each leg, a sequence of rounding points. + * For each leg, mark rounding information. */ - private Map> roundingPoints; + private Map roundingPoints; @@ -31,6 +28,16 @@ public class MarkRoundingSequence { } + /** + * Returns the rounding points for a given leg. + * @param leg Leg to check. + * @return Rounding points for leg. + */ + public MarkRoundingData getRoundingData(Leg leg) { + return roundingPoints.get(leg); + } + + /** * Generates the rounding points for all legs in the race. */ @@ -39,7 +46,11 @@ public class MarkRoundingSequence { for (int i = 0; i < this.legs.size(); i++) { Leg currentLeg = this.legs.get(i); - Optional nextLeg = Optional.ofNullable(this.legs.get(i + 1)); + + Optional nextLeg = Optional.empty(); + if (i < legs.size() - 1) { + nextLeg = Optional.of(this.legs.get(i + 1)); + } generateRoundingPoint(currentLeg, nextLeg); } @@ -50,14 +61,85 @@ public class MarkRoundingSequence { /** * Generates the rounding points for a specific leg. * @param currentLeg The leg to generate rounding points for. - * @param nextLeg The following leg, used to help generate rounding points. + * @param nextLeg The following leg, used to help generate rounding points. Final leg of race doesn't have a following leg. */ private void generateRoundingPoint(Leg currentLeg, Optional nextLeg) { + Bearing bearingToAddFirstPoint = calculateBearingToAdd(currentLeg); + + GPSCoordinate startCoord = currentLeg.getStartCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate endCoord = currentLeg.getEndCompoundMark().getAverageGPSCoordinate(); + Bearing legBearing = GPSCoordinate.calculateBearing(startCoord, endCoord); + Bearing nextBearing = legBearing; + + Mark markToRound = currentLeg.getEndCompoundMark().getMarkForRounding(legBearing); + + GPSCoordinate roundCheck1; + if (currentLeg.getEndCompoundMark().getMark2() == null) { + //End is a single mark. + roundCheck1 = calculateRoundingCheckPoint( + currentLeg, + markToRound, + legBearing, + bearingToAddFirstPoint); + } else { + //End is a gate. + if (markToRound == currentLeg.getEndCompoundMark().getMark1()) { + roundCheck1 = currentLeg.getEndCompoundMark().getMark2().getPosition(); + } else { + roundCheck1 = currentLeg.getEndCompoundMark().getMark1().getPosition(); + } + } + + //TODO the halfway points currently haven't been done properly. + + GPSCoordinate roundCheck1Halfway = calculateRoundingCheckPoint( + currentLeg, + markToRound, + legBearing, + bearingToAddFirstPoint); + + + GPSCoordinate roundCheck2 = roundCheck1; + GPSCoordinate roundCheck2Halfway = roundCheck1Halfway; + if (nextLeg.isPresent()) { + + Bearing bearingToAddSecondPoint = bearingToAddFirstPoint;//calculateBearingToAdd(nextLeg.get()); + + GPSCoordinate startCoord2 = nextLeg.get().getStartCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate endCoord2 = nextLeg.get().getEndCompoundMark().getAverageGPSCoordinate(); + nextBearing = GPSCoordinate.calculateBearing(startCoord2, endCoord2); + + roundCheck2 = calculateRoundingCheckPoint( + currentLeg, + markToRound, + nextBearing, + bearingToAddSecondPoint); + + roundCheck2Halfway = calculateRoundingCheckPoint( + currentLeg, + markToRound, + nextBearing, + bearingToAddSecondPoint); + } + + + MarkRoundingData roundingData = new MarkRoundingData(); + roundingData.setLeg(currentLeg); + + roundingData.setLegBearing(legBearing); + roundingData.setNextLegBearing(nextBearing); + + roundingData.setMarkToRound(markToRound); + roundingData.setRoundCheck1(roundCheck1); + roundingData.setRoundCheck1Halfway(roundCheck1Halfway); + roundingData.setRoundCheck2(roundCheck2); + roundingData.setRoundCheck2Halfway(roundCheck2Halfway); + this.roundingPoints.put(currentLeg, roundingData); //Rounding points: @@ -75,4 +157,54 @@ public class MarkRoundingSequence { //the second rounding point is the same as the first, except LEGBEARING is the bearing between end of current leg, and start of next leg. } + + + /** + * Calculates the location of the rounding check point, which together with the mark to round, forms a line that the boat must cross to round the mark. + * @param leg Leg of race to check. + * @param markToRound Mark at end of leg to round. + * @param legBearing The bearing of the nearest leg. For the first rounding point this is the leg's bearing, for the second rounding point it is the next leg's bearing. + * @param bearingToAdd The bearing to add to the leg bearing to get a perpendicular bearing. + * @return The location of the rounding point, which together with the mark to round forms a line the boat must cross. + */ + private GPSCoordinate calculateRoundingCheckPoint(Leg leg, Mark markToRound, Bearing legBearing, Bearing bearingToAdd) { + + + double roundingDistanceMeters = leg.getEndCompoundMark().getRoundingDistance(); + + + //We project from rounding mark to get the second point which forms the line the boat must cross. + /* + c2 + | + | + r------c1 + b + */ + GPSCoordinate roundCheck = GPSCoordinate.calculateNewPosition( + markToRound.getPosition(), + roundingDistanceMeters, + Azimuth.fromDegrees(legBearing.degrees() + bearingToAdd.degrees()) ); + + return roundCheck; + } + + + /** + * Calculates the bearing that must be added to a leg's bearing to calculate a perpendicular bearing, used for finding rounding points. + * @param leg Leg to check. + * @return Bearing to add. Will be either +90 or -90. + */ + private Bearing calculateBearingToAdd(Leg leg) { + + if (leg.getEndCompoundMark().getRoundingType() == Port || + leg.getEndCompoundMark().getRoundingType() == SP) { + return Bearing.fromDegrees(90); + } else { + return Bearing.fromDegrees(-90); + } + + } + + } diff --git a/racevisionGame/src/main/java/shared/model/RaceState.java b/racevisionGame/src/main/java/shared/model/RaceState.java index 48361da2..36448981 100644 --- a/racevisionGame/src/main/java/shared/model/RaceState.java +++ b/racevisionGame/src/main/java/shared/model/RaceState.java @@ -46,6 +46,12 @@ public abstract class RaceState { private ObservableList legs; + /** + * The sequence of rounding points for each leg/mark. + */ + private MarkRoundingSequence markRoundingSequence; + + /** * The clock which tracks the race's start time, current time, and elapsed duration. @@ -102,10 +108,15 @@ public abstract class RaceState { */ protected void useLegsList(List legs) { this.legs.setAll(legs); + + //We create this before adding the extra finish leg, as it doesn't contain compound marks. + this.markRoundingSequence = new MarkRoundingSequence(getLegs()); + //We add a "dummy" leg at the end of the race. if (getLegs().size() > 0) { getLegs().add(new Leg("Finish", getLegs().size())); } + } @@ -367,6 +378,11 @@ public abstract class RaceState { } - - + /** + * Returns the rounding sequences for each leg. + * @return Rounding sequence for each leg. + */ + public MarkRoundingSequence getMarkRoundingSequence() { + return markRoundingSequence; + } } diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index 3f475e63..6c0dee48 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -495,8 +495,6 @@ public class ResizableRaceCanvas extends ResizableCanvas { private void drawRoundingLines() { - - //ugly hack //rounding lines @@ -511,52 +509,16 @@ public class ResizableRaceCanvas extends ResizableCanvas { return; } - GPSCoordinate startDirectionLinePoint = boat.getCurrentLeg().getStartCompoundMark().getAverageGPSCoordinate(); - GPSCoordinate endDirectionLinePoint = boat.getCurrentLeg().getEndCompoundMark().getAverageGPSCoordinate(); - Bearing bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint); - - //use the direction line to create three invisible points that act as crossover lines a boat must cross - //to round a mark - - double bearingToAdd; - if (boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.Port || - boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.SP) { - bearingToAdd = 90; - }else{ - bearingToAdd = -90; - } - - double epsilonMeters = boat.getCurrentLeg().getEndCompoundMark().getRoundingDistance(); + Leg currentLeg = boat.getCurrentLeg(); - GPSCoordinate endMarkPos = boat.getCurrentLeg().getEndCompoundMark().getMarkForRounding(bearingOfDirectionLine).getPosition(); + MarkRoundingData roundingData = raceState.getMarkRoundingSequence().getRoundingData(currentLeg); - GPSCoordinate roundCheck1 = GPSCoordinate.calculateNewPosition( - endMarkPos, - epsilonMeters, - Azimuth.fromDegrees(bearingOfDirectionLine.degrees() + bearingToAdd) ); - GPSCoordinate roundCheck2; - try{ - Leg nextLeg = raceState.getLegs().get(raceState.getLegs().indexOf(boat.getCurrentLeg()) + 1); - - GPSCoordinate startNextDirectionLinePoint = nextLeg.getStartCompoundMark().getAverageGPSCoordinate(); - GPSCoordinate endNextDirectionLinePoint = nextLeg.getEndCompoundMark().getAverageGPSCoordinate(); - Bearing bearingOfNextDirectionLine = GPSCoordinate.calculateBearing(startNextDirectionLinePoint, endNextDirectionLinePoint); - - roundCheck2 = GPSCoordinate.calculateNewPosition( - endDirectionLinePoint, - epsilonMeters, - Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees() + bearingToAdd) ); - } catch(NullPointerException e) { - //this is caused by the last leg not being having a leg after it - roundCheck2 = roundCheck1; - } //To screen coords. - GraphCoordinate legEnd = map.convertGPS(endDirectionLinePoint); - GraphCoordinate round1 = map.convertGPS(roundCheck1); - GraphCoordinate round2 = map.convertGPS(roundCheck2); - + GraphCoordinate legEnd = map.convertGPS(roundingData.getMarkToRound().getPosition()); + GraphCoordinate round1 = map.convertGPS(roundingData.getRoundCheck1()); + GraphCoordinate round2 = map.convertGPS(roundingData.getRoundCheck2()); gc.strokeLine( @@ -571,6 +533,9 @@ public class ResizableRaceCanvas extends ResizableCanvas { round2.getX(), round2.getY() ); + drawCircle(round1, 12, Color.ORANGE); + drawCircle(round2, 12, Color.GREEN); + }