diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 90f61908..d840f6fb 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -11,18 +11,24 @@ import seng302.Controllers.MainController; import java.io.InputStream; - -public class App extends Application -{ +public class App extends Application { Stage primaryStage; BorderPane mainContainer; Scene mainScene; - public static void main( String[] args ) - { + /** + * Entry point for running the programme + * @param args + */ + public static void main(String[] args) { launch(args); } + /** + * Loads and sets up the GUI elements + * @param primaryStage + * @throws Exception + */ @Override public void start(Stage primaryStage) throws Exception { this.primaryStage = primaryStage; @@ -32,7 +38,7 @@ public class App extends Application FXMLLoader loader = new FXMLLoader(); InputStream in = getClass().getClassLoader().getResourceAsStream("scenes//mainpane.fxml"); mainContainer = (BorderPane) loader.load(in); - mainScene = new Scene(mainContainer, 800, 600); + mainScene = new Scene(mainContainer, 1200, 800); primaryStage.setScene(mainScene); primaryStage.sizeToScene(); MainController mainController = (MainController) loader.getController(); @@ -46,9 +52,14 @@ public class App extends Application primaryStage.show(); } - public void loadPane(String fxmlName) throws Exception{ + /** + * Loads panes for use in the GUI + * @param fxmlName + * @throws Exception + */ + public void loadPane(String fxmlName) throws Exception { FXMLLoader loader = new FXMLLoader(); - InputStream in = getClass().getClassLoader().getResourceAsStream("scenes//"+fxmlName); + InputStream in = getClass().getClassLoader().getResourceAsStream("scenes//" + fxmlName); Parent page; try { page = (Parent) loader.load(in); diff --git a/src/main/java/seng302/Constants.java b/src/main/java/seng302/Constants.java index afec2bcf..fc198910 100644 --- a/src/main/java/seng302/Constants.java +++ b/src/main/java/seng302/Constants.java @@ -2,7 +2,6 @@ package seng302; import javafx.scene.paint.Color; import seng302.Model.BoatInRace; -import seng302.Model.Leg; /** * Constants that are used throughout the program @@ -10,13 +9,11 @@ import seng302.Model.Leg; */ public class Constants { - public static final int NMToMetersConversion = 1852; //nautical miles + public static final int NMToMetersConversion = 1852; // 1 nautical mile = 1852 meters public static final GPSCoordinate startLineMarker1 = new GPSCoordinate(32.296577, -64.854304); public static final GPSCoordinate startLineMarker2 = new GPSCoordinate(32.293771, -64.855242); - public static final GPSCoordinate mark1 = new GPSCoordinate(32.293039, -64.843983); - public static final GPSCoordinate windwardGate1 = new GPSCoordinate(32.284680, -64.850045); public static final GPSCoordinate windwardGate2 = new GPSCoordinate(32.280164, -64.847591); public static final GPSCoordinate leewardGate1 = new GPSCoordinate(32.309693, -64.835249); @@ -25,12 +22,11 @@ public class Constants { public static final GPSCoordinate finishLineMarker2 = new GPSCoordinate(32.317257, -64.836260); public static final BoatInRace[] OFFICIAL_AC35_COMPETITORS = new BoatInRace[] - {new BoatInRace("Oracle Team USA", 300.0, Color.BLUEVIOLET, "USA"), - new BoatInRace("Land Rover BAR", 500.0, Color.BLACK, "BAR"), - new BoatInRace("SoftBank Team Japan", 400.0, Color.RED, "JAP"), - new BoatInRace("Groupama Team France", 350.0, Color.ORANGE, "FRN"), - new BoatInRace("Artemis Racing", 440.0, Color.DARKOLIVEGREEN, "ART"), - new BoatInRace("Emirates Team New Zealand", 620, Color.LIMEGREEN, "ENZ")}; + {new BoatInRace("Oracle Team USA", 30.0, Color.BLUEVIOLET, "USA"), + new BoatInRace("Land Rover BAR", 23.0, Color.BLACK, "BAR"), + new BoatInRace("SoftBank Team Japan", 27.0, Color.RED, "JAP"), + new BoatInRace("Groupama Team France", 25.0, Color.ORANGE, "FRN"), + new BoatInRace("Artemis Racing", 22.5, Color.DARKOLIVEGREEN, "ART"), + new BoatInRace("Emirates Team New Zealand", 62, Color.LIMEGREEN, "ENZ")}; - //public static final Leg bermudaCourseStartToMark1 = new Leg(0, , new ) } diff --git a/src/main/java/seng302/Controllers/Controller.java b/src/main/java/seng302/Controllers/Controller.java index e771e8d0..b4feabbb 100644 --- a/src/main/java/seng302/Controllers/Controller.java +++ b/src/main/java/seng302/Controllers/Controller.java @@ -10,19 +10,21 @@ import java.util.ResourceBundle; * Controller parent for app controllers. * Created by fwy13 on 15/03/2017. */ -public abstract class Controller implements Initializable{ +public abstract class Controller implements Initializable { protected App parent; /** * Sets the parent of the application + * * @param parent */ - public void setParent(App parent){ + public void setParent(App parent) { this.parent = parent; } /** * Sets the loads a pane into the parent. + * * @param fxmlName * @throws Exception */ @@ -32,6 +34,7 @@ public abstract class Controller implements Initializable{ /** * Initialisation class that is run on start up. + * * @param location * @param resources */ diff --git a/src/main/java/seng302/Controllers/MainController.java b/src/main/java/seng302/Controllers/MainController.java index 5ebb99cc..5948d827 100644 --- a/src/main/java/seng302/Controllers/MainController.java +++ b/src/main/java/seng302/Controllers/MainController.java @@ -1,7 +1,5 @@ package seng302.Controllers; -import javafx.fxml.Initializable; - import java.net.URL; import java.util.ResourceBundle; @@ -12,6 +10,7 @@ public class MainController extends Controller { /** * Main Controller for the applications will house the menu and the displayed pane. + * * @param location * @param resources */ diff --git a/src/main/java/seng302/Controllers/RaceController.java b/src/main/java/seng302/Controllers/RaceController.java index da82c3dc..6cb86211 100644 --- a/src/main/java/seng302/Controllers/RaceController.java +++ b/src/main/java/seng302/Controllers/RaceController.java @@ -3,12 +3,11 @@ package seng302.Controllers; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.fxml.FXML; -import javafx.scene.canvas.GraphicsContext; import javafx.scene.control.Label; +import javafx.scene.control.SplitPane; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TitledPane; @@ -17,15 +16,11 @@ import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.HBox; import javafx.scene.paint.Color; +import javafx.scene.layout.GridPane; import javafx.util.Callback; -import org.geotools.referencing.GeodeticCalculator; import seng302.Constants; -import seng302.GPSCoordinate; -import seng302.Model.ResizableRaceCanvas; import seng302.Model.*; -import seng302.RaceMap; -import java.awt.geom.Point2D; import java.net.URL; import java.util.ArrayList; import java.util.ResourceBundle; @@ -33,11 +28,17 @@ import java.util.ResourceBundle; /** * Created by fwy13 on 15/03/2017. */ -public class RaceController extends Controller{ +public class RaceController extends Controller { + + ResizableRaceCanvas raceMap; @FXML AnchorPane canvasBase; - ResizableRaceCanvas raceMap; + @FXML + GridPane startScreen; + @FXML + SplitPane ongoingRacePane; + @FXML Label timer; @@ -58,7 +59,8 @@ public class RaceController extends Controller{ TableColumn boatSpeedColumn; /** - * updates the ResizableRaceCanvas (raceMap) with most recent data + * Updates the ResizableRaceCanvas (raceMap) with most recent data + * * @param boats boats that are to be displayed in the race * @see ResizableRaceCanvas */ @@ -71,6 +73,7 @@ public class RaceController extends Controller{ /** * Updates the array listened by the TableView (boatInfoTable) that displays the boat information. + * * @param race Race to listen to. */ public void setInfoTable(Race race) { @@ -88,28 +91,62 @@ public class RaceController extends Controller{ }); } + /** + * Begins the race with a scale factor of 15 + */ + public void startRace1Min() { + startRace(15); + } + + /** + * Begins the race with a scale factor of 3 + */ + public void startRace5Min() { + startRace(3); + } + + /** + * Begins the race with a scale factor of 1 + */ + public void startRaceNoScaling() { + startRace(1); + } + @Override public void initialize(URL location, ResourceBundle resources) { - BoatInRace[] boats = generateAC35Competitors(); + } + /** + * Initializes and runs the race, based on the user's chosen scale factor + * Currently uses an example racecourse + * + * @param scaleFactor + */ + private void startRace(int scaleFactor) { + BoatInRace[] boats = generateAC35Competitors(); raceMap = new ResizableRaceCanvas(); raceMap.widthProperty().bind(canvasBase.widthProperty()); raceMap.heightProperty().bind(canvasBase.heightProperty()); raceMap.setBoats(boats); raceMap.drawRaceMap(); + raceMap.setVisible(true); canvasBase.getChildren().add(raceMap); + startScreen.setVisible(false); + ongoingRacePane.setVisible(true); ArrayList legs = generateBermudaCourseLegs(); - ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, this); + ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, this, scaleFactor); + new Thread((race)).start(); } /** - * Function for the Bermuda Race. + * Generates an example race course (Bermuda 2017) + * * @return legs in the Bermuda Race. */ private ArrayList generateBermudaCourseLegs() { @@ -119,27 +156,32 @@ public class RaceController extends Controller{ Leg leg3 = new Leg("Leeward Gate to Windward Gate", Constants.leewardGate1, Constants.windwardGate1, 2); Leg leg4 = new Leg("Windward Gate to Leeward Gate", Constants.windwardGate1, Constants.leewardGate1, 3); Leg leg5 = new Leg("Leeward Gate to Finish", Constants.leewardGate1, Constants.finishLineMarker1, 4); - legs.add(leg1); legs.add(leg2); legs.add(leg3); legs.add(leg4); legs.add(leg5); + legs.add(leg1); + legs.add(leg2); + legs.add(leg3); + legs.add(leg4); + legs.add(leg5); return legs; } + /** + * Generates an example list of competitors (Official AC35 competitors) + * @return List of official AC35 competing boats + */ private BoatInRace[] generateAC35Competitors() { BoatInRace[] boats = new BoatInRace[6]; - int i = 0; for (BoatInRace boat : Constants.OFFICIAL_AC35_COMPETITORS) { boat.setCurrentPosition(Constants.startLineMarker1); boats[i] = boat; i++; } - return boats; - } - public void setTimer(String time){ + public void setTimer(String time) { timer.setText(time); } diff --git a/src/main/java/seng302/GPSCoordinate.java b/src/main/java/seng302/GPSCoordinate.java index 13fa0231..cc7e3df5 100644 --- a/src/main/java/seng302/GPSCoordinate.java +++ b/src/main/java/seng302/GPSCoordinate.java @@ -11,13 +11,18 @@ public class GPSCoordinate { /** * Constructor Method - * @param latitude latitude the coordinate is located at. + * + * @param latitude latitude the coordinate is located at. * @param longitude Longitude that the coordinate is located at. */ - public GPSCoordinate(double latitude, double longitude) { this.latitude = latitude; this.longitude = longitude; } + public GPSCoordinate(double latitude, double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } /** * Gets the Latitude that the Coordinate is at. + * * @return Returns the latitude of the Coordinate. */ public double getLatitude() { @@ -26,12 +31,16 @@ public class GPSCoordinate { /** * Gets the Longitude that the Coordinate is at. + * * @return Returns the longitude of the Coordinate. */ - public double getLongitude() { return longitude; } + public double getLongitude() { + return longitude; + } /** * To String method of the Coordinate in the form Latitude: $f, Longitude: $f. + * * @return A String representation of the GPSCoordinate Class. */ public String toString() { diff --git a/src/main/java/seng302/GraphCoordinate.java b/src/main/java/seng302/GraphCoordinate.java index 0ac557ab..050931c2 100644 --- a/src/main/java/seng302/GraphCoordinate.java +++ b/src/main/java/seng302/GraphCoordinate.java @@ -10,13 +10,18 @@ public class GraphCoordinate { /** * Constructor method. + * * @param x X coordinate. * @param y Y coordinate. */ - public GraphCoordinate(int x, int y) { this.x = x; this.y = y; } + public GraphCoordinate(int x, int y) { + this.x = x; + this.y = y; + } /** * Returns the X coordinate. + * * @return x axis Coordinate. */ public int getX() { @@ -25,6 +30,7 @@ public class GraphCoordinate { /** * Returns the Y coordinate. + * * @return y axis Coordinate. */ public int getY() { diff --git a/src/main/java/seng302/Model/Boat.java b/src/main/java/seng302/Model/Boat.java index a0625638..1b1801fc 100644 --- a/src/main/java/seng302/Model/Boat.java +++ b/src/main/java/seng302/Model/Boat.java @@ -1,16 +1,13 @@ package seng302.Model; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -import java.util.ArrayList; - /** * Created by fwy13 on 3/03/17. */ public class Boat { + private StringProperty name; private double velocity; private StringProperty velocityProp; @@ -18,10 +15,11 @@ public class Boat { /** * Boat initialiser which keeps all of the information of the boat. - * @param name Name of the Boat. + * + * @param name Name of the Boat. * @param velocity Speed in m/s that the boat travels at. */ - public Boat(String name, double velocity, String abbrev){ + public Boat(String name, double velocity, String abbrev) { this.velocity = velocity; this.velocityProp = new SimpleStringProperty(String.valueOf(velocity* 1.94384)); this.abbrev = abbrev; @@ -29,20 +27,22 @@ public class Boat { } /** - * - * @return The name of the boat + * @return Name of the boat */ public StringProperty getName() { return name; } + /** + * Sets the boat name + * @param name + */ public void setName(String name) { this.name.setValue(name); } /** - * - * @return returns the speed of the boat. + * @return Speed of the boat. */ public double getVelocity() { return velocity; @@ -53,17 +53,25 @@ public class Boat { } /** - * - * @return The Name of the boat. + * Print method prints the name of the boat + * @return Name of the boat. */ - public String toString(){ + public String toString() { return getName().toString(); } + /** + * @return Velocity String Property of the boat + */ public StringProperty getVelocityProp() { return velocityProp; } - public String getAbbrev() { return abbrev; } + /** + * @return Abbreviation of the boat + */ + public String getAbbrev() { + return abbrev; + } } diff --git a/src/main/java/seng302/Model/BoatInRace.java b/src/main/java/seng302/Model/BoatInRace.java index 5291244f..d2776845 100644 --- a/src/main/java/seng302/Model/BoatInRace.java +++ b/src/main/java/seng302/Model/BoatInRace.java @@ -8,7 +8,6 @@ import seng302.GPSCoordinate; import java.awt.geom.Point2D; - /** * Boat in the Race extends Boat. * Created by esa46 on 15/03/17. @@ -16,6 +15,7 @@ import java.awt.geom.Point2D; public class BoatInRace extends Boat { private Leg currentLeg; + private double scaledVelocity; private double distanceTravelledInLeg; private GPSCoordinate currentPosition; private long timeFinished; @@ -25,9 +25,10 @@ public class BoatInRace extends Boat { /** * Constructor method. - * @param name Name of the boat. + * + * @param name Name of the boat. * @param velocity Speed that the boat travels. - * @param colour Colour the boat will be displayed as on the map + * @param colour Colour the boat will be displayed as on the map */ public BoatInRace(String name, double velocity, Color colour, String abbrev) { super(name, velocity, abbrev); @@ -36,7 +37,72 @@ public class BoatInRace extends Boat { } /** + * Calculates the azimuth of the travel via map coordinates of the raceMarkers * + * @return the direction that the boat is heading towards in degrees (-180 to 180). + */ + public double calculateAzimuth() { + + GeodeticCalculator calc = new GeodeticCalculator(); + calc.setStartingGeographicPoint(currentLeg.getStartGraphCoordinate().getLongitude(), currentLeg.getStartGraphCoordinate().getLatitude()); + calc.setDestinationGeographicPoint(currentLeg.getEndGraphCoordinate().getLongitude(), currentLeg.getEndGraphCoordinate().getLatitude()); + + return calc.getAzimuth(); + } + + /** + * Converts an azimuth to a bearing + * + * @param azimuth azimuth value to be converted + * @return the bearings in degrees (0 to 360). + */ + public static double calculateHeading(double azimuth) { + if (azimuth >= 0) { + return azimuth; + } else { + return azimuth + 360; + } + } + + /** + * Calculates the bearing of the travel via map coordinates of the raceMarkers + * + * @return the direction that the boat is heading towards in degrees (0 to 360). + */ + public double calculateHeading() { + double azimuth = this.calculateAzimuth(); + return calculateHeading(azimuth); + } + + public GPSCoordinate getWake() { + double reverseHeading = calculateHeading() - 180; + double distance = getVelocity(); + + GeodeticCalculator calc = new GeodeticCalculator(); + calc.setStartingGeographicPoint( + new Point2D.Double(getCurrentPosition().getLongitude(), getCurrentPosition().getLatitude()) + ); + calc.setDirection(reverseHeading, distance); + Point2D endpoint = calc.getDestinationGeographicPoint(); + return new GPSCoordinate(endpoint.getY(), endpoint.getX()); + } + + /** + * @return Scaled velocity of the boat + */ + public double getScaledVelocity() { + return scaledVelocity; + } + + /** + * Sets the boat's scaled velocity + * @param velocity + */ + public void setScaledVelocity(double velocity) { + this.scaledVelocity = velocity; + } + + /** * @return Returns the current position of the boat in a GPSCoordinate Class. * @see GPSCoordinate */ @@ -45,7 +111,16 @@ public class BoatInRace extends Boat { } /** + * Sets the current position on the GPS that the boat. * + * @param position GPSCoordinate of the position that the boat is currently on. + * @see GPSCoordinate + */ + public void setCurrentPosition(GPSCoordinate position) { + this.currentPosition = position; + } + + /** * @return Returns the time that the boat finished the race. */ public long getTimeFinished() { @@ -53,7 +128,15 @@ public class BoatInRace extends Boat { } /** + * Sets the time that the boat finished the race. * + * @param timeFinished Time the boat finished the race. + */ + public void setTimeFinished(long timeFinished) { + this.timeFinished = timeFinished; + } + + /** * @return Returns the colour of the boat. */ public Color getColour() { @@ -62,6 +145,7 @@ public class BoatInRace extends Boat { /** * Sets the colour that boat will be shown as when drawn on the ResizableRaceCanvas. + * * @param colour Colour that the boat is to be set to. * @see ResizableRaceCanvas */ @@ -69,16 +153,9 @@ public class BoatInRace extends Boat { this.colour = colour; } - /** - * Sets the time that the boat finished the race. - * @param timeFinished Time the boat finished the race. - */ - public void setTimeFinished(long timeFinished) { - this.timeFinished = timeFinished; - } - /** * Gets the current leg that the boat is on. + * * @return returns the leg the boat is on in a Leg class * @see Leg */ @@ -87,7 +164,8 @@ public class BoatInRace extends Boat { } /** - * Sets the current Leg of that the boat is on. + * Sets the boat's current leg. + * * @param currentLeg Leg class that the boat is currently on. * @see Leg */ @@ -96,89 +174,44 @@ public class BoatInRace extends Boat { this.currentLegName.setValue(currentLeg.getName()); } - public StringProperty getCurrentLegName(){ + /** + * @return Name of boat's current leg + */ + public StringProperty getCurrentLegName() { return currentLegName; } /** * Gets the distance travelled by the boat in the leg. + * * @return Returns the value in nautical miles (1.852km) that the boat has traversed. */ public double getDistanceTravelledInLeg() { return distanceTravelledInLeg; } - /** - * Sets the current position on the GPS that the boat. - * @param position GPSCoordinate of the position that the boat is currently on. - * @see GPSCoordinate - */ - public void setCurrentPosition(GPSCoordinate position) { - this.currentPosition = position; - } - /** * Sets the distance travelled by the boat in the leg in nautical miles (1.852km) + * * @param distanceTravelledInLeg Distance travelled by the boat in nautical miles. */ public void setDistanceTravelledInLeg(double distanceTravelledInLeg) { this.distanceTravelledInLeg = distanceTravelledInLeg; } - public boolean isFinished() { - return this.finished; - } - - public void setFinished(boolean bool) { - this.finished = bool; - } - /** - * Calculates the azimuth of the travel via map coordinates of the raceMarkers - * @return the direction that the boat is heading towards in degrees (-180 to 180). + * @return true if boat has finished, fals eif not */ - public double calculateAzimuth(){ - - GeodeticCalculator calc = new GeodeticCalculator(); - calc.setStartingGeographicPoint(currentLeg.getStartGraphCoordinate().getLongitude(), currentLeg.getStartGraphCoordinate().getLatitude()); - calc.setDestinationGeographicPoint(currentLeg.getEndGraphCoordinate().getLongitude(), currentLeg.getEndGraphCoordinate().getLatitude()); - - return calc.getAzimuth(); - } - - /** - * Converts an azimuth to a bearing - * @param azimuth azimuth value to be converted - * @return the bearings in degrees (0 to 360). - */ - public static double calculateHeading(double azimuth) { - if (azimuth >= 0) { - return azimuth; - } - else { - return azimuth + 360; - } + public boolean isFinished() { + return this.finished; } /** - * Calculates the bearing of the travel via map coordinates of the raceMarkers - * @return the direction that the boat is heading towards in degrees (0 to 360). + * Sets whether boat is finished or not + * @param bool */ - public double calculateHeading(){ - double azimuth = this.calculateAzimuth(); - return calculateHeading(azimuth); + public void setFinished(boolean bool) { + this.finished = bool; } - public GPSCoordinate getWake() { - double reverseHeading = calculateHeading() - 180; - double distance = getVelocity(); - - GeodeticCalculator calc = new GeodeticCalculator(); - calc.setStartingGeographicPoint( - new Point2D.Double(getCurrentPosition().getLongitude(), getCurrentPosition().getLatitude()) - ); - calc.setDirection(reverseHeading, distance); - Point2D endpoint = calc.getDestinationGeographicPoint(); - return new GPSCoordinate(endpoint.getY(), endpoint.getX()); - } } diff --git a/src/main/java/seng302/Model/ConstantVelocityRace.java b/src/main/java/seng302/Model/ConstantVelocityRace.java index 1b83c92d..da340ae0 100644 --- a/src/main/java/seng302/Model/ConstantVelocityRace.java +++ b/src/main/java/seng302/Model/ConstantVelocityRace.java @@ -1,12 +1,11 @@ package seng302.Model; +import org.geotools.referencing.GeodeticCalculator; import seng302.Constants; import seng302.Controllers.RaceController; -import java.awt.geom.Point2D; - -import org.geotools.referencing.GeodeticCalculator; import seng302.GPSCoordinate; +import java.awt.geom.Point2D; import java.util.ArrayList; /** @@ -15,54 +14,57 @@ import java.util.ArrayList; public class ConstantVelocityRace extends Race { /** - * Initialiser for a Race with constant velocity. - * @param startingBoats array of boats - * @param marks array of RaceMarkers that the boats need to pass in order to finish the course. - * @see Boat - * @see Leg + * Initialiser for a constant velocity race + * + * @param startingBoats + * @param legs + * @param controller + * @param scaleFactor */ - - public ConstantVelocityRace(BoatInRace[] startingBoats, ArrayList marks, RaceController controller) { - super(startingBoats, marks, controller); + public ConstantVelocityRace(BoatInRace[] startingBoats, ArrayList legs, RaceController controller, int scaleFactor) { + super(startingBoats, legs, controller, scaleFactor); } - public ConstantVelocityRace(BoatInRace[] startingBoats, ArrayList marks) { - super(startingBoats, marks); - } + /** + * Calculates the distance a boat has travelled and updates its current position according to this value. + * @param boat + * @param millisecondsElapsed + */ protected void updatePosition(BoatInRace boat, int millisecondsElapsed) { //distanceTravelled = velocity (nm p hr) * time taken to update loop - double distanceTravelled = boat.getVelocity() * millisecondsElapsed/3600000; + double distanceTravelled = boat.getScaledVelocity() * millisecondsElapsed / 3600000; double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg(); boolean finish = boat.getCurrentLeg().getName().equals("Finish"); if (!finish) { - + //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().getStartGraphCoordinate(), - totalDistanceTravelled, boat.calculateAzimuth())); + totalDistanceTravelled, boat.calculateAzimuth())); } } /** - * - * @param oldCoordinates GPS coordinates of the boat's starting position + * 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 + * @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); - - geodeticCalculator.setDirection(azimuth,distanceTravelled * Constants.NMToMetersConversion); - + //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()); diff --git a/src/main/java/seng302/Model/Leg.java b/src/main/java/seng302/Model/Leg.java index 3cc41743..c3466f8b 100644 --- a/src/main/java/seng302/Model/Leg.java +++ b/src/main/java/seng302/Model/Leg.java @@ -1,10 +1,8 @@ package seng302.Model; -import org.geotools.referencing.Console; import org.geotools.referencing.GeodeticCalculator; import seng302.Constants; import seng302.GPSCoordinate; -import seng302.GraphCoordinate; /** * Created by cbt24 on 6/03/17. @@ -20,9 +18,10 @@ public class Leg { /** * Leg Initialiser + * * @param name Name of the Leg */ - public Leg(String name, GPSCoordinate start, GPSCoordinate end, int number) { + public Leg(String name, GPSCoordinate start, GPSCoordinate end, int number) { this.name = name; this.startGPSCoordinate = start; this.endGPSCoordinate = end; @@ -32,6 +31,7 @@ public class Leg { /** * Construction Method + * * @param name Name of the Leg */ public Leg(String name, int number) { @@ -41,6 +41,7 @@ public class Leg { /** * Returns the name of the Leg + * * @return Returns the name of the Leg */ public String getName() { @@ -49,6 +50,7 @@ public class Leg { /** * Get the distance in nautical miles + * * @return Returns the total distance of the leg. */ public double getDistance() { @@ -57,6 +59,7 @@ public class Leg { /** * Returns the coordinates in GPSCoordinate class of the boats starting coordinate. + * * @return Returns the coordinate of the start of the leg. * @see GPSCoordinate */ @@ -66,6 +69,7 @@ public class Leg { /** * Returns the coordinates in a GPSCoordinate class that the boat ends on. + * * @return Returns the coordinate of the end of the leg. * @see GPSCoordinate */ @@ -75,6 +79,7 @@ public class Leg { /** * Returns the leg number that the leg exists in the Race + * * @return Returns the Leg * @see Race */ @@ -84,11 +89,13 @@ public class Leg { /** * Calculates the distance that the legs are in nautical miles (1.852 km). + * * @return Returns the leg distance. */ private double calculateDistance() { GeodeticCalculator calc = new GeodeticCalculator(); + //Load start and end of leg calc.setStartingGeographicPoint(startGPSCoordinate.getLongitude(), startGPSCoordinate.getLatitude()); calc.setDestinationGeographicPoint(endGPSCoordinate.getLongitude(), endGPSCoordinate.getLatitude()); return calc.getOrthodromicDistance() / Constants.NMToMetersConversion; diff --git a/src/main/java/seng302/Model/Race.java b/src/main/java/seng302/Model/Race.java index 6b5f0867..340b7e35 100644 --- a/src/main/java/seng302/Model/Race.java +++ b/src/main/java/seng302/Model/Race.java @@ -3,14 +3,11 @@ package seng302.Model; import javafx.animation.AnimationTimer; import javafx.application.Platform; -import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; -import javafx.collections.ObservableArray; import javafx.collections.ObservableList; import seng302.Controllers.RaceController; -import seng302.GPSCoordinate; -import java.util.*; +import java.util.ArrayList; /** * Parent class for races @@ -24,39 +21,62 @@ public abstract class Race implements Runnable { protected int boatsFinished = 0; protected long totalTimeElapsed; + protected int scaleFactor; private int SLEEP_TIME = 100; //time in milliseconds to pause in a paced loop - protected int PRERACE_TIME = 10000;//Integer.MAX_VALUE; //time in milliseconds to pause during pre-race + protected int PRERACE_TIME = 100;//Integer.MAX_VALUE; //time in milliseconds to pause during pre-race private boolean timerEnabled = true; /** * Initailiser for Race + * * @param boats Takes in an array of boats that are participating in the race. - * @param legs Number of marks in order that the boats pass in order to complete the race. + * @param legs Number of marks in order that the boats pass in order to complete the race. */ - public Race(BoatInRace[] boats, ArrayList legs, RaceController controller) { + public Race(BoatInRace[] boats, ArrayList legs, RaceController controller, int scaleFactor) { + if (boats.length > 0) { + for (BoatInRace boat : boats) { + if (boat != null) { + boat.setScaledVelocity(boat.getVelocity() * scaleFactor); + } + } + } + this.startingBoats = FXCollections.observableArrayList(boats); this.legs = legs; this.legs.add(new Leg("Finish", this.legs.size())); this.controller = controller; + this.scaleFactor = scaleFactor; } /** * Constructor for Race class + * * @param boats boats participating in the race. - * @param marks legs that there are in the race. + * @param legs legs that there are in the race. */ - public Race(BoatInRace[] boats, ArrayList marks) { - this(boats, marks, null); + public Race(BoatInRace[] boats, ArrayList legs, int scaleFactor) { + if (boats.length > 0) { + for (BoatInRace boat : boats) { + if (boat != null) { + boat.setScaledVelocity(boat.getVelocity() * scaleFactor); + } + } + } + this.startingBoats = FXCollections.observableArrayList(boats); + this.legs = legs; + this.legs.add(new Leg("Finish", this.legs.size())); + this.scaleFactor = scaleFactor; } + /** * Runnable for the thread. */ public void run() { setControllerListeners(); preRace(); - if(timerEnabled) countdownTimer(); + if (timerEnabled) countdownTimer(); simulateRace(); } @@ -68,16 +88,13 @@ public abstract class Race implements Runnable { } /** - * Set up the state in waiting for the race starts. + * Initialises the boats, + * Sets the boats' current to the first leg in the race */ private void preRace() { //show the boats participating. - System.out.println("Boats Participating:"); - System.out.println("===================="); for (int i = 0; i < startingBoats.size(); i++) { if (startingBoats.get(i) != null) { - System.out.println(i + 1 + ". " + startingBoats.get(i).toString() + ", Speed: " - + Math.round(startingBoats.get(i).getVelocity() * 1.94384) + "kn"); startingBoats.get(i).setCurrentLeg(legs.get(0)); } } @@ -98,13 +115,17 @@ public abstract class Race implements Runnable { while (currentTime <= startTime) { timeLeft = startTime - currentTime; - currentTimeInSeconds = timeLeft / 1000; - minutes = currentTimeInSeconds / 60; - remainingSeconds = currentTimeInSeconds % 60; - hours = minutes / 60; - minutes = minutes % 60; - if (controller != null) { - updateTime(String.format("Time until race starts: %02d:%02d:%02d", hours, minutes, remainingSeconds)); + if (timeLeft == 0 && controller != null) { + updateTime("Race is starting..."); + } else { + currentTimeInSeconds = timeLeft / 1000; + minutes = currentTimeInSeconds / 60; + remainingSeconds = currentTimeInSeconds % 60; + hours = minutes / 60; + minutes = minutes % 60; + if (controller != null) { + updateTime(String.format("Race clock: -%02d:%02d:%02d", hours, minutes, remainingSeconds)); + } } try { timeLoopEnded = System.currentTimeMillis(); @@ -127,8 +148,9 @@ public abstract class Race implements Runnable { long hours; currentTimeInSeconds = totalTimeElapsed / 1000; - minutes = currentTimeInSeconds / 60; - remainingSeconds = currentTimeInSeconds % 60; + long scaledTimeInSeconds = currentTimeInSeconds * scaleFactor; + minutes = scaledTimeInSeconds / 60; + remainingSeconds = scaledTimeInSeconds % 60; hours = minutes / 60; minutes = minutes % 60; return String.format("Race clock: %02d:%02d:%02d", hours, minutes, remainingSeconds); @@ -205,13 +227,13 @@ public abstract class Race implements Runnable { /** * Checks the position of the boat, this updates the boats current position. - * @param boat Boat that the postion is to be updated for. + * + * @param boat Boat that the postion is to be updated for. * @param timeElapsed Time that has elapse since the start of the the race. * @see BoatInRace */ protected void checkPosition(BoatInRace boat, long timeElapsed) { - if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()){ -// updateController(); + if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) { //boat has passed onto new leg if (boat.getCurrentLeg().getName().equals("Finish")) { //boat has finished @@ -219,13 +241,16 @@ public abstract class Race implements Runnable { boat.setFinished(true); boat.setTimeFinished(timeElapsed); } 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()); } - FXCollections.sort(startingBoats, (a,b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber()); + //Update the boat display table in the GUI to reflect the leg change + FXCollections.sort(startingBoats, (a, b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber()); } } @@ -233,11 +258,12 @@ public abstract class Race implements Runnable { * Update call for the controller. */ protected void setControllerListeners() { - if(controller != null) controller.setInfoTable(this); + if (controller != null) controller.setInfoTable(this); } /** * Returns the boats that have started the race. + * * @return ObservableList of BoatInRace class that participated in the race. * @see ObservableList * @see BoatInRace @@ -246,12 +272,12 @@ public abstract class Race implements Runnable { return startingBoats; } + /** - * This function is a function that generates the Race and populates the events list. - * Is automatically called by the initialiser function, so that simulateRace() does not return an empty race. - * @see Race#simulateRace() + * Updates the boat's gps coordinates depending on time elapsed + * @param boat + * @param millisecondsElapsed */ - protected abstract void updatePosition(BoatInRace boat, int millisecondsElapsed); } diff --git a/src/main/java/seng302/Model/ResizableRaceCanvas.java b/src/main/java/seng302/Model/ResizableRaceCanvas.java index 36d16531..c6891e72 100644 --- a/src/main/java/seng302/Model/ResizableRaceCanvas.java +++ b/src/main/java/seng302/Model/ResizableRaceCanvas.java @@ -28,6 +28,7 @@ public class ResizableRaceCanvas extends Canvas { /** * Sets the boats that are to be displayed in this race. + * * @param boats */ public void setBoats(BoatInRace[] boats) { @@ -45,22 +46,24 @@ public class ResizableRaceCanvas extends Canvas { /** * Constructor */ - public ResizableRaceCanvas(){ + public ResizableRaceCanvas() { this(null); } /** * Sets the RaceMap that the RaceCanvas is to be displaying for. + * * @param map */ - public void setMap (RaceMap map) { + public void setMap(RaceMap map) { this.map = map; } /** * Displays the mark of a race as a circle. + * * @param graphCoordinate Latitude and Logintude in GraphCoordinate that it is to be displayed as. - * @param paint Colour the mark is to be coloured. + * @param paint Colour the mark is to be coloured. * @see GraphCoordinate * @see Color * @see Paint @@ -73,14 +76,15 @@ public class ResizableRaceCanvas extends Canvas { /** * Displays a line on the map with rectangles on the starting and ending point of the line. + * * @param graphCoordinateA Starting Point of the line in GraphCoordinate. * @param graphCoordinateB End Point of the line in GraphCoordinate. - * @param paint Colour the line is to coloured. + * @param paint Colour the line is to coloured. * @see GraphCoordinate * @see Color * @see Paint */ - public void displayLine(GraphCoordinate graphCoordinateA, GraphCoordinate graphCoordinateB, Paint paint){ + public void displayLine(GraphCoordinate graphCoordinateA, GraphCoordinate graphCoordinateB, Paint paint) { gc.setStroke(paint); gc.setFill(paint); gc.fillOval(graphCoordinateA.getX() - 3, graphCoordinateA.getY() - 3, 6, 6); @@ -90,38 +94,41 @@ public class ResizableRaceCanvas extends Canvas { /** * Display a point on the Canvas + * * @param graphCoordinate Coordinate that the point is to be displayed at. - * @param paint Colour that the boat is to be coloured. + * @param paint Colour that the boat is to be coloured. * @see GraphCoordinate * @see Paint * @see Color */ - public void displayPoint(GraphCoordinate graphCoordinate, Paint paint){ + public void displayPoint(GraphCoordinate graphCoordinate, Paint paint) { gc.setFill(paint); gc.fillOval(graphCoordinate.getX(), graphCoordinate.getY(), 10, 10); } /** * Displays an arrow on the Canvas + * * @param coordinate Coordinate that the arrow is to be displayed at. - * @param angle Angle that the arrow is to be facing in degrees 0 degrees = North (Up). + * @param angle Angle that the arrow is to be facing in degrees 0 degrees = North (Up). * @see GraphCoordinate */ - public void displayArrow(GraphCoordinate coordinate, int angle){ + public void displayArrow(GraphCoordinate coordinate, int angle) { gc.save(); - rotate(angle, coordinate.getX(),coordinate.getY()); + rotate(angle, coordinate.getX(), coordinate.getY()); gc.setFill(Color.BLACK); - gc.fillPolygon(new double[]{coordinate.getX()-12, coordinate.getX()-6, coordinate.getX(), coordinate.getX()-4, coordinate.getX()-4, coordinate.getX()-8, coordinate.getX()-8}, - new double[]{coordinate.getY()-5, coordinate.getY()-20, coordinate.getY()-5, coordinate.getY()-5, coordinate.getY()+20, coordinate.getY()+20, coordinate.getY()-5}, + gc.fillPolygon(new double[]{coordinate.getX() - 12, coordinate.getX() - 6, coordinate.getX(), coordinate.getX() - 4, coordinate.getX() - 4, coordinate.getX() - 8, coordinate.getX() - 8}, + new double[]{coordinate.getY() - 5, coordinate.getY() - 20, coordinate.getY() - 5, coordinate.getY() - 5, coordinate.getY() + 20, coordinate.getY() + 20, coordinate.getY() - 5}, 7); gc.restore(); } /** * Rotates things on the canvas Note: this must be called in between gc.save() and gc.restore() else they will rotate everything + * * @param angle Bearing angle to rotate at in degrees - * @param px Pivot point x of rotation. - * @param py Pivot point y of rotation. + * @param px Pivot point x of rotation. + * @param py Pivot point y of rotation. */ private void rotate(double angle, double px, double py) { Rotate r = new Rotate(angle, px, py); @@ -130,8 +137,9 @@ public class ResizableRaceCanvas extends Canvas { /** * Display given name and speed of boat at a graph coordinate - * @param name name of the boat - * @param speed speed of the boat + * + * @param name name of the boat + * @param speed speed of the boat * @param coordinate coordinate the text appears */ public void displayText(String name, double speed, GraphCoordinate coordinate){ @@ -158,9 +166,9 @@ public class ResizableRaceCanvas extends Canvas { gc.clearRect(0, 0, width, height); //System.out.println("Race Map Canvas Width: "+ width + ", Height:" + height); - this.map = new RaceMap(32.278, -64.863, 32.320989, -64.821, (int)width, (int)height); + this.map = new RaceMap(32.278, -64.863, 32.320989, -64.821, (int) width, (int) height); - if (map == null){ + if (map == null) { return; } @@ -209,9 +217,23 @@ public class ResizableRaceCanvas extends Canvas { } } } + /** + * Draws a boat at a certain GPSCoordinate + * + * @param colour Colour to colour boat. + * @param gpsCoordinates GPScoordinate that the boat is to be drawn at. + * @see GPSCoordinate + * @see Color + */ + public void drawBoat(Color colour, GPSCoordinate gpsCoordinates) { + GraphCoordinate graphCoordinate = this.map.convertGPS(gpsCoordinates); + //System.out.println("DrawingBoat" + gpsCoordinates.getLongitude()); + displayPoint(graphCoordinate, colour); + } /** * Set the Canvas to resizable. + * * @return That the Canvas is resizable. */ @Override @@ -221,6 +243,7 @@ public class ResizableRaceCanvas extends Canvas { /** * Returns the preferred width of the Canvas + * * @param width * @return Returns the width of the Canvas */ @@ -231,6 +254,7 @@ public class ResizableRaceCanvas extends Canvas { /** * Returns the preferred height of the Canvas + * * @param height * @return Returns the height of the Canvas */ diff --git a/src/main/java/seng302/RaceMap.java b/src/main/java/seng302/RaceMap.java index cf924202..420214f3 100644 --- a/src/main/java/seng302/RaceMap.java +++ b/src/main/java/seng302/RaceMap.java @@ -8,20 +8,27 @@ public class RaceMap { private int width, height; /** - * Contructor Method. - * @param x1 Longitude of the top left point. - * @param y1 Latitude of the top left point. - * @param x2 Longitude of the top right point. - * @param y2 Latitude of the top right point. - * @param width width that the Canvas the race is to be drawn on is. + * Constructor Method. + * + * @param x1 Longitude of the top left point. + * @param y1 Latitude of the top left point. + * @param x2 Longitude of the top right point. + * @param y2 Latitude of the top right point. + * @param width width that the Canvas the race is to be drawn on is. * @param height height that the Canvas the race is to be drawn on is. */ public RaceMap(double y1, double x1, double y2, double x2, int height, int width) { - this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; this.width = width; this.height = height; + this.x1 = x1; + this.x2 = x2; + this.y1 = y1; + this.y2 = y2; + this.width = width; + this.height = height; } /** * Converts GPS coordinates to coordinates for container + * * @param lat GPS latitude * @param lon GPS longitude * @return GraphCoordinate (pair of doubles) @@ -29,11 +36,12 @@ public class RaceMap { */ public GraphCoordinate convertGPS(double lat, double lon) { - return new GraphCoordinate((int) (width * (lon - x1) / (x2 - x1)), (int) (height - (height * (lat - y1) / (y2 - y1)))); + return new GraphCoordinate((int) (width * (lon - x1) / (x2 - x1)), (int) (height - (height * (lat - y1) / (y2 - y1)))); } /** * Converts the GPS Coordinate to GraphCoordinates + * * @param coordinate GPSCoordinate representation of Latitude and Longitude. * @return GraphCoordinate that the GPS is coordinates are to be displayed on the map. * @see GraphCoordinate diff --git a/src/main/resources/raceXML/bermuda_AC35.xml b/src/main/resources/raceXML/bermuda_AC35.xml index 57dcc08e..97867f69 100644 --- a/src/main/resources/raceXML/bermuda_AC35.xml +++ b/src/main/resources/raceXML/bermuda_AC35.xml @@ -59,7 +59,7 @@ 32.293039 -64.843983 - + @@ -87,11 +87,11 @@ Windward Gate to Leeward Gate - - 32.284680 - -64.850045 + + 32.284680 + -64.850045 + - @@ -106,7 +106,7 @@ 32.309693 -64.835249 - + diff --git a/src/main/resources/scenes/mainpane.fxml b/src/main/resources/scenes/mainpane.fxml index c230b883..ca502553 100644 --- a/src/main/resources/scenes/mainpane.fxml +++ b/src/main/resources/scenes/mainpane.fxml @@ -1,7 +1,7 @@ - - - - + + diff --git a/src/main/resources/scenes/racepane.fxml b/src/main/resources/scenes/racepane.fxml index 61e3c713..2840e5a1 100644 --- a/src/main/resources/scenes/racepane.fxml +++ b/src/main/resources/scenes/racepane.fxml @@ -1,33 +1,95 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + +