diff --git a/mock/src/main/java/seng302/App.java b/mock/src/main/java/seng302/App.java index 3863bea6..ec55b651 100644 --- a/mock/src/main/java/seng302/App.java +++ b/mock/src/main/java/seng302/App.java @@ -25,7 +25,7 @@ public class App extends Application { public void start(Stage primaryStage) { try { RaceDataSource raceData = new RaceXMLReader("raceXML/bermuda_AC35.xml"); - ConstantVelocityRace newRace = new ConstantVelocityRace(raceData, 15); + Race newRace = new Race(raceData, 15); System.out.println(newRace.getStartingBoats()); new Thread((newRace)).start(); } catch (IOException e) { @@ -36,5 +36,4 @@ public class App extends Application { e.printStackTrace(); } } - } diff --git a/mock/src/main/java/seng302/Model/ConstantVelocityRace.java b/mock/src/main/java/seng302/Model/ConstantVelocityRace.java index b9ed2ba6..d30d9a54 100644 --- a/mock/src/main/java/seng302/Model/ConstantVelocityRace.java +++ b/mock/src/main/java/seng302/Model/ConstantVelocityRace.java @@ -15,188 +15,9 @@ import java.util.Random; * Created by cbt24 on 6/03/17. * */ -public class ConstantVelocityRace extends Race { +public class ConstantVelocityRace{ - private int dnfChance = 0; //%percentage chance a boat fails at each checkpoint - /** - * Initialiser for a constant velocity race without standard data source - * - * @param startingBoats in race - * @param legs in race - * @param scaleFactor of timer - */ - public ConstantVelocityRace(List startingBoats, List legs, int scaleFactor) { - super(startingBoats, legs, scaleFactor); - } - /** - * Initialiser for legacy tests - * - * @param startingBoats in race - * @param legs in race - * @param scaleFactor of timer - * - */ - public ConstantVelocityRace(BoatInRace[] startingBoats, List legs, int scaleFactor) { - super(Arrays.asList(startingBoats), legs, scaleFactor); - } - - /** - * Initialiser for constant velocity race with standard data source - * @param raceData for race - * @param scaleFactor of timer - */ - public ConstantVelocityRace(RaceDataSource raceData, int scaleFactor) { - super(raceData, scaleFactor); - } - - public void initialiseBoats() { - Leg officialStart = legs.get(0); - String name = officialStart.getName(); - Marker endMarker = officialStart.getEndMarker(); - - BoatInRace.setTrackPointTimeInterval(BoatInRace.getBaseTrackPointTimeInterval() / scaleFactor); - - ArrayList startMarkers = getSpreadStartingPositions(); - for (int i = 0; i < startingBoats.size(); i++) { - BoatInRace boat = startingBoats.get(i); - if (boat != null) { - boat.setScaledVelocity(boat.getVelocity() * scaleFactor); - Leg startLeg = new Leg(name, 0); - boat.setCurrentPosition(startMarkers.get(i).getAverageGPSCoordinate()); - startLeg.setStartMarker(startMarkers.get(i)); - startLeg.setEndMarker(endMarker); - startLeg.calculateDistance(); - boat.setCurrentLeg(startLeg); - boat.setHeading(boat.calculateHeading()); - } - } - } - - /** - * Creates a list of starting positions for the different boats, so they do not appear cramped at the start line - * - * @return list of starting positions - */ - public ArrayList getSpreadStartingPositions() { - - int nBoats = startingBoats.size(); - Marker marker = legs.get(0).getStartMarker(); - - GeodeticCalculator initialCalc = new GeodeticCalculator(); - initialCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); - initialCalc.setDestinationGeographicPoint(marker.getMark2().getLongitude(), marker.getMark2().getLatitude()); - - double azimuth = initialCalc.getAzimuth(); - double distanceBetweenMarkers = initialCalc.getOrthodromicDistance(); - double distanceBetweenBoats = distanceBetweenMarkers / (nBoats + 1); - - GeodeticCalculator positionCalc = new GeodeticCalculator(); - positionCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); - ArrayList positions = new ArrayList<>(); - - for (int i = 0; i < nBoats; i++) { - positionCalc.setDirection(azimuth, distanceBetweenBoats); - Point2D position = positionCalc.getDestinationGeographicPoint(); - positions.add(new Marker(new GPSCoordinate(position.getY(), position.getX()))); - - positionCalc = new GeodeticCalculator(); - positionCalc.setStartingGeographicPoint(position); - } - return positions; - } - - /** - * Sets the chance each boat has of failing at a gate or marker - * @param chance percentage chance a boat has of failing per checkpoint. - */ - protected void setDnfChance(int chance) { - if (chance >= 0 && chance <= 100) { - dnfChance = chance; - } - } - - protected boolean doNotFinish() { - Random rand = new Random(); - return rand.nextInt(100) < dnfChance; - } - - /** - * Calculates the distance a boat has travelled and updates its current position according to this value. - * - * @param boat to be updated - * @param millisecondsElapsed since last update - */ - protected void updatePosition(BoatInRace boat, int millisecondsElapsed) { - - //distanceTravelled = velocity (nm p hr) * time taken to update loop - double distanceTravelled = (boat.getScaledVelocity() * millisecondsElapsed) / 3600000; - - double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg(); - - boolean finish = boat.getCurrentLeg().getName().equals("Finish"); - if (!finish) { - boat.setHeading(boat.calculateHeading()); - //update boat's distance travelled - boat.setDistanceTravelledInLeg(totalDistanceTravelled); - //Calculate boat's new position by adding the distance travelled onto the start point of the leg - boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartMarker().getAverageGPSCoordinate(), - totalDistanceTravelled, boat.calculateAzimuth())); - } - } - - protected void checkPosition(BoatInRace boat, long timeElapsed) { - if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) { - //boat has passed onto new leg - if (boat.getCurrentLeg().getName().equals("Finish")) { - //boat has finished - boatsFinished++; - boat.setFinished(true); - boat.setTimeFinished(timeElapsed); - } else if (doNotFinish()) { - boatsFinished++; - boat.setFinished(true); - boat.setCurrentLeg(new Leg("DNF", -1)); - boat.setVelocity(0); - boat.setScaledVelocity(0); - } else { - //Calculate how much the boat overshot the marker by - boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance()); - //Move boat on to next leg - Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1); - - boat.setCurrentLeg(nextLeg); - //Add overshoot distance into the distance travelled for the next leg - boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg()); - } - //Update the boat display table in the GUI to reflect the leg change - updatePositions(); - } - } - - /** - * Calculates the boats next GPS position based on its distance travelled and heading - * - * @param oldCoordinates GPS coordinates of the boat's starting position - * @param distanceTravelled distance in nautical miles - * @param azimuth boat's current direction. Value between -180 and 180 - * @return The boat's new coordinate - */ - public static GPSCoordinate calculatePosition(GPSCoordinate oldCoordinates, double distanceTravelled, double azimuth) { - - //Find new coordinate using current heading and distance - - GeodeticCalculator geodeticCalculator = new GeodeticCalculator(); - //Load start point into calculator - Point2D startPoint = new Point2D.Double(oldCoordinates.getLongitude(), oldCoordinates.getLatitude()); - geodeticCalculator.setStartingGeographicPoint(startPoint); - //load direction and distance tranvelled into calculator - geodeticCalculator.setDirection(azimuth, distanceTravelled * Constants.NMToMetersConversion); - //get new point - Point2D endPoint = geodeticCalculator.getDestinationGeographicPoint(); - - return new GPSCoordinate(endPoint.getY(), endPoint.getX()); - } } \ No newline at end of file diff --git a/mock/src/main/java/seng302/Model/Race.java b/mock/src/main/java/seng302/Model/Race.java index 22a7d152..582d1c0c 100644 --- a/mock/src/main/java/seng302/Model/Race.java +++ b/mock/src/main/java/seng302/Model/Race.java @@ -7,18 +7,24 @@ import javafx.animation.AnimationTimer; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import org.geotools.referencing.GeodeticCalculator; +import seng302.Constants; +import seng302.GPSCoordinate; import seng302.RaceDataSource; +import java.awt.geom.Point2D; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Random; /** * Parent class for races * Created by fwy13 on 3/03/17. */ -public abstract class Race implements Runnable { +public class Race implements Runnable { //protected BoatInRace[] startingBoats; protected ObservableList startingBoats; protected List legs; @@ -57,31 +63,6 @@ public abstract class Race implements Runnable { this(raceData.getBoats(), raceData.getLegs(), scaleFactor); } - public abstract void initialiseBoats(); - - /** - * Randomly generate number to see if boat fails - * @return True if number lower than dnfChance else false - */ - protected abstract boolean doNotFinish(); - - /** - * Checks the position of the boat, this updates the boats current position. - * - * @param boat Boat that the position is to be updated for. - * @param timeElapsed Time that has elapse since the start of the the race. - * @see BoatInRace - */ - protected abstract void checkPosition(BoatInRace boat, long timeElapsed); - - /** - * Updates the boat's gps coordinates depending on time elapsed - * - * @param boat to be updated - * @param millisecondsElapsed time since last update - */ - protected abstract void updatePosition(BoatInRace boat, int millisecondsElapsed); - /** * Runnable for the thread. */ @@ -190,6 +171,157 @@ public abstract class Race implements Runnable { } } + + + public void initialiseBoats() { + Leg officialStart = legs.get(0); + String name = officialStart.getName(); + Marker endMarker = officialStart.getEndMarker(); + + BoatInRace.setTrackPointTimeInterval(BoatInRace.getBaseTrackPointTimeInterval() / scaleFactor); + + ArrayList startMarkers = getSpreadStartingPositions(); + for (int i = 0; i < startingBoats.size(); i++) { + BoatInRace boat = startingBoats.get(i); + if (boat != null) { + boat.setScaledVelocity(boat.getVelocity() * scaleFactor); + Leg startLeg = new Leg(name, 0); + boat.setCurrentPosition(startMarkers.get(i).getAverageGPSCoordinate()); + startLeg.setStartMarker(startMarkers.get(i)); + startLeg.setEndMarker(endMarker); + startLeg.calculateDistance(); + boat.setCurrentLeg(startLeg); + boat.setHeading(boat.calculateHeading()); + } + } + } + + /** + * Creates a list of starting positions for the different boats, so they do not appear cramped at the start line + * + * @return list of starting positions + */ + public ArrayList getSpreadStartingPositions() { + + int nBoats = startingBoats.size(); + Marker marker = legs.get(0).getStartMarker(); + + GeodeticCalculator initialCalc = new GeodeticCalculator(); + initialCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); + initialCalc.setDestinationGeographicPoint(marker.getMark2().getLongitude(), marker.getMark2().getLatitude()); + + double azimuth = initialCalc.getAzimuth(); + double distanceBetweenMarkers = initialCalc.getOrthodromicDistance(); + double distanceBetweenBoats = distanceBetweenMarkers / (nBoats + 1); + + GeodeticCalculator positionCalc = new GeodeticCalculator(); + positionCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); + ArrayList positions = new ArrayList<>(); + + for (int i = 0; i < nBoats; i++) { + positionCalc.setDirection(azimuth, distanceBetweenBoats); + Point2D position = positionCalc.getDestinationGeographicPoint(); + positions.add(new Marker(new GPSCoordinate(position.getY(), position.getX()))); + + positionCalc = new GeodeticCalculator(); + positionCalc.setStartingGeographicPoint(position); + } + return positions; + } + + /** + * Sets the chance each boat has of failing at a gate or marker + * @param chance percentage chance a boat has of failing per checkpoint. + */ + protected void setDnfChance(int chance) { + if (chance >= 0 && chance <= 100) { + dnfChance = chance; + } + } + + protected boolean doNotFinish() { + Random rand = new Random(); + return rand.nextInt(100) < dnfChance; + } + + /** + * Calculates the distance a boat has travelled and updates its current position according to this value. + * + * @param boat to be updated + * @param millisecondsElapsed since last update + */ + protected void updatePosition(BoatInRace boat, int millisecondsElapsed) { + + //distanceTravelled = velocity (nm p hr) * time taken to update loop + double distanceTravelled = (boat.getScaledVelocity() * millisecondsElapsed) / 3600000; + + double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg(); + + boolean finish = boat.getCurrentLeg().getName().equals("Finish"); + if (!finish) { + boat.setHeading(boat.calculateHeading()); + //update boat's distance travelled + boat.setDistanceTravelledInLeg(totalDistanceTravelled); + //Calculate boat's new position by adding the distance travelled onto the start point of the leg + boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartMarker().getAverageGPSCoordinate(), + totalDistanceTravelled, boat.calculateAzimuth())); + } + } + + protected void checkPosition(BoatInRace boat, long timeElapsed) { + if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) { + //boat has passed onto new leg + if (boat.getCurrentLeg().getName().equals("Finish")) { + //boat has finished + boatsFinished++; + boat.setFinished(true); + boat.setTimeFinished(timeElapsed); + } else if (doNotFinish()) { + boatsFinished++; + boat.setFinished(true); + boat.setCurrentLeg(new Leg("DNF", -1)); + boat.setVelocity(0); + boat.setScaledVelocity(0); + } else { + //Calculate how much the boat overshot the marker by + boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance()); + //Move boat on to next leg + Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1); + + boat.setCurrentLeg(nextLeg); + //Add overshoot distance into the distance travelled for the next leg + boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg()); + } + //Update the boat display table in the GUI to reflect the leg change + updatePositions(); + } + } + + /** + * Calculates the boats next GPS position based on its distance travelled and heading + * + * @param oldCoordinates GPS coordinates of the boat's starting position + * @param distanceTravelled distance in nautical miles + * @param azimuth boat's current direction. Value between -180 and 180 + * @return The boat's new coordinate + */ + public static GPSCoordinate calculatePosition(GPSCoordinate oldCoordinates, double distanceTravelled, double azimuth) { + + //Find new coordinate using current heading and distance + + GeodeticCalculator geodeticCalculator = new GeodeticCalculator(); + //Load start point into calculator + Point2D startPoint = new Point2D.Double(oldCoordinates.getLongitude(), oldCoordinates.getLatitude()); + geodeticCalculator.setStartingGeographicPoint(startPoint); + //load direction and distance tranvelled into calculator + geodeticCalculator.setDirection(azimuth, distanceTravelled * Constants.NMToMetersConversion); + //get new point + Point2D endPoint = geodeticCalculator.getDestinationGeographicPoint(); + + return new GPSCoordinate(endPoint.getY(), endPoint.getX()); + } + + /** * Returns the boats that have started the race. *