Cloned the main project into two submodules, mock and visualiser

#story[778]
main
Erika Savell 9 years ago
parent d12f70c8f8
commit 669718d406

@ -1,2 +0,0 @@
# Design Decisions

@ -1,7 +0,0 @@
# Examples
You should also include example data files for your application that demonstrate the
features of your application. These should contain adequate amounts of data that
would be expected from actual use of your application.
This file should provide a basic overview of the example files available.

@ -1 +0,0 @@
# User Manual

@ -3,151 +3,15 @@
<modelVersion>4.0.0</modelVersion>
<groupId>seng302</groupId>
<artifactId>team-7</artifactId>
<packaging>jar</packaging>
<version>0.0</version>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>team-7</name>
<url>https://eng-git.canterbury.ac.nz/SENG302-2016/team-7</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-referencing</artifactId>
<version>9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>com.github.bfsmith</groupId>
<artifactId>geotimezone</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.11</version>
<scope>test</scope>
</dependency>
<modules>
<module>mock</module>
<module>visualiser</module>
</modules>
</dependencies>
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net repository</name>
<url>http://download.java.net/maven/2</url>
</repository>
<repository>
<id>osgeo</id>
<name>Open Source Geospatial Foundation Repository</name>
<url>http://download.osgeo.org/webdav/geotools/</url>
</repository>
<repository>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>opengeo</id>
<name>OpenGeo Maven Repository</name>
<url>http://repo.opengeo.org</url>
</repository>
</repositories>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<url>https://eng-git.canterbury.ac.nz/SENG302-2016/team-7</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>seng302.App</Main-Class>
<X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
<X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
</manifestEntries>
</transformer>
</transformers>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.6</version>
<configuration>
<linkXRef>true</linkXRef>
<targetJdk>${maven.compiler.target}</targetJdk>
<rulesets>
<ruleset>/rulesets/java/basic.xml</ruleset>
<ruleset>/rulesets/java/imports.xml</ruleset>
<ruleset>/rulesets/java/codesize.xml</ruleset>
<ruleset>/rulesets/java/design.xml</ruleset>
<ruleset>/rulesets/java/empty.xml</ruleset>
<ruleset>/rulesets/java/junit.xml</ruleset>
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
</rulesets>
<includeXmlInSite>true</includeXmlInSite>
<sourceEncoding>utf-8</sourceEncoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<configuration>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.19.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.8.1</version>
</plugin>
</plugins>
</reporting>
</project>

@ -1,82 +0,0 @@
package seng302;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class App extends Application {
Stage primaryStage;
BorderPane mainContainer;
Scene mainScene;
/**
* Entry point for running the programme
*
* @param args for starting the programme
*/
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/scenes/main.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root, 1200, 800);
stage.setScene(scene);
stage.show();
}
// /**
// * Loads and sets up the GUI elements
// *
// * @param primaryStage Base for all scenes
// * @throws Exception Error in initialising programme
// */
// @Override
// public void start(Stage primaryStage) throws Exception {
// this.primaryStage = primaryStage;
// primaryStage.minHeightProperty().setValue(600);
// primaryStage.minWidthProperty().setValue(780);
// //load the first container
// try {
// FXMLLoader loader = new FXMLLoader();
// InputStream in = getClass().getClassLoader().getResourceAsStream("scenes/main.fxml");
// mainContainer = (BorderPane) loader.load(in);
// mainScene = new Scene(mainContainer, 1200, 800);
// primaryStage.setScene(mainScene);
// primaryStage.sizeToScene();
// MainController mainController = (MainController) loader.getController();
// mainController.setParent(this);
// in.close();
// //add the center
// loadPane("race.fxml");
// } catch (Exception e) {
// e.printStackTrace();
// }
// primaryStage.show();
// }
//
// /**
// * Loads panes for use in the GUI
// *
// * @param fxmlName name of resource fxml file
// * @throws Exception critical error in loading file
// */
// public void loadPane(String fxmlName) throws Exception {
// FXMLLoader loader = new FXMLLoader();
// InputStream in = getClass().getClassLoader().getResourceAsStream("scenes/" + fxmlName);
// Parent page;
// try {
// page = (Parent) loader.load(in);
// } finally {
// in.close();
// }
// mainContainer.getChildren().remove(mainContainer.getCenter());
// mainContainer.setCenter(page);
// Controller controller = (Controller) loader.getController();
// controller.setParent(this);
// }
}

@ -1,33 +0,0 @@
package seng302;
import javafx.scene.paint.Color;
import seng302.Model.BoatInRace;
/**
* Constants that are used throughout the program
* Created by Erika on 19-Mar-17.
*/
public class Constants {
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);
public static final GPSCoordinate leewardGate2 = new GPSCoordinate(32.308046, -64.831785);
public static final GPSCoordinate finishLineMarker1 = new GPSCoordinate(32.317379, -64.839291);
public static final GPSCoordinate finishLineMarker2 = new GPSCoordinate(32.317257, -64.836260);
public static final double wakeScale = 10;
public static final BoatInRace[] OFFICIAL_AC35_COMPETITORS = new BoatInRace[]
{new BoatInRace("Oracle Team USA", 30.0, Color.BLUEVIOLET, "Oracle"),
new BoatInRace("Land Rover BAR", 23.0, Color.BLACK, "BGR"),
new BoatInRace("SoftBank Team Japan", 27.0, Color.RED, "JPN"),
new BoatInRace("Groupama Team France", 25.0, Color.ORANGE, "FRA"),
new BoatInRace("Artemis Racing", 22.5, Color.DARKOLIVEGREEN, "SWE"),
new BoatInRace("Emirates Team New Zealand", 62, Color.LIMEGREEN, "ETNZ")};
}

@ -1,33 +0,0 @@
package seng302.Controllers;
import javafx.fxml.Initializable;
import seng302.App;
import java.net.URL;
import java.util.ResourceBundle;
/**
* Controller parent for app controllers.
* Created by fwy13 on 15/03/2017.
*/
public abstract class Controller implements Initializable {
protected MainController parent;
/**
* Sets the parent of the application
*
* @param parent controller
*/
public void setParent(MainController parent) {
this.parent = parent;
}
/**
* Initialisation class that is run on start up.
*
* @param location resources location
* @param resources resources bundle
*/
@Override
public abstract void initialize(URL location, ResourceBundle resources);
}

@ -1,42 +0,0 @@
package seng302.Controllers;
import javafx.fxml.FXML;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import seng302.RaceDataSource;
import seng302.RaceXMLReader;
import java.net.URL;
import java.util.ResourceBundle;
/**
* Created by fwy13 on 15/03/2017.
*/
public class MainController extends Controller {
@FXML StartController startController;
@FXML RaceController raceController;
public void beginRace(int scaleFactor, RaceDataSource raceData) {
raceController.startRace(scaleFactor, raceData);
}
/**
* Main Controller for the applications will house the menu and the displayed pane.
*
* @param location of resources
* @param resources bundle
*/
@Override
public void initialize(URL location, ResourceBundle resources) {
startController.setParent(this);
raceController.setParent(this);
AnchorPane.setTopAnchor(startController.startWrapper(), 0.0);
AnchorPane.setBottomAnchor(startController.startWrapper(), 0.0);
AnchorPane.setLeftAnchor(startController.startWrapper(), 0.0);
AnchorPane.setRightAnchor(startController.startWrapper(), 0.0);
}
}

@ -1,227 +0,0 @@
package seng302.Controllers;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import org.xml.sax.SAXException;
import seng302.Model.*;
import seng302.RaceDataSource;
import seng302.RaceXMLReader;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;
/**
* Created by fwy13 on 15/03/2017.
*/
public class RaceController extends Controller {
@FXML
GridPane canvasBase;
//user saved data for annotation display
private ArrayList<Boolean> presetAnno;
ResizableRaceCanvas raceMap;
@FXML
SplitPane race;
@FXML
CheckBox showFPS;
@FXML
CheckBox showBoatPath;
@FXML
CheckBox showAnnotations;
@FXML
Label timer;
@FXML
Label FPS;
@FXML
Label timeZone;
@FXML
CheckBox showName;
@FXML
CheckBox showAbbrev;
@FXML
CheckBox showSpeed;
@FXML
Button saveAnno;
@FXML
Button showSetAnno;
@FXML
TableView<BoatInRace> boatInfoTable;
@FXML
TableColumn<BoatInRace, String> boatPlacingColumn;
@FXML
TableColumn<BoatInRace, String> boatTeamColumn;
@FXML
TableColumn<BoatInRace, String> boatMarkColumn;
@FXML
TableColumn<BoatInRace, String> boatSpeedColumn;
/**
* Updates the ResizableRaceCanvas (raceMap) with most recent data
*
* @param boats boats that are to be displayed in the race
* @see ResizableRaceCanvas
*/
public void updateMap(ObservableList<BoatInRace> boats) {
raceMap.setBoats(boats);
raceMap.update();
}
/**
* Updates the array listened by the TableView (boatInfoTable) that displays the boat information.
*
* @param race Race to listen to.
*/
public void setInfoTable(Race race) {
//boatInfoTable.getItems().clear();
boatInfoTable.setItems(race.getStartingBoats());
boatTeamColumn.setCellValueFactory(cellData -> cellData.getValue().getName());
boatSpeedColumn.setCellValueFactory(cellData -> cellData.getValue().getVelocityProp());
boatMarkColumn.setCellValueFactory(cellData -> cellData.getValue().getCurrentLegName());
boatPlacingColumn.setCellValueFactory(cellData -> cellData.getValue().positionProperty());
}
@Override
public void initialize(URL location, ResourceBundle resources) {
//listener for fps
showFPS.selectedProperty().addListener((ov, old_val, new_val) -> {
if (showFPS.isSelected()) {
FPS.setVisible(true);
} else {
FPS.setVisible(false);
}
});
}
/**
* Initializes and runs the race, based on the user's chosen scale factor
* Currently uses an example racecourse
*
* @param scaleFactor scale value of race
*/
public void startRace(int scaleFactor, RaceDataSource raceData) {
ConstantVelocityRace newRace = new ConstantVelocityRace(raceData, this, scaleFactor);
newRace.initialiseBoats();
raceMap = new ResizableRaceCanvas(raceData);
raceMap.setMouseTransparent(true);
raceMap.widthProperty().bind(canvasBase.widthProperty());
raceMap.heightProperty().bind(canvasBase.heightProperty());
raceMap.setBoats(newRace.getStartingBoats());
raceMap.setRaceBoundaries(raceData.getBoundary());
raceMap.drawRaceMap();
raceMap.setVisible(true);
canvasBase.getChildren().add(raceMap);
race.setVisible(true);
//Initialize save annotation array, fps listener, and annotation listeners
//timezone
RaceClock raceClock = new RaceClock(raceData.getMark());
timeZone.setText(raceClock.getTimeZone());
initializeFPS();
initializeAnnotations();
new Thread((newRace)).start();
}
/**
* Set the value for the race clock label
*
* @param time time that the label will be updated to
*/
public void setTimer(String time) {
timer.setText(time);
}
/**
* Set the value for the fps label
*
* @param fps fps that the label will be updated to
*/
public void setFrames(String fps) {
FPS.setText((fps));
}
/**
* Set up FPS display at bottom of screen
*/
private void initializeFPS() {
showFPS.setVisible(true);
showFPS.selectedProperty().addListener((ov, old_val, new_val) -> {
if (showFPS.isSelected()) {
FPS.setVisible(true);
} else {
FPS.setVisible(false);
}
});
}
/**
* Set up boat annotations
*/
private void initializeAnnotations() {
presetAnno = new ArrayList<>();
//listener for annotation
showAnnotations.selectedProperty().addListener((ov, old_val, new_val) -> {
raceMap.toggleAnnotations();
raceMap.update();
});
//listener for show name in annotation
showName.selectedProperty().addListener((ov, old_val, new_val) -> {
raceMap.toggleAnnoName();
raceMap.update();
});
//listener for show abbreviation for annotation
showAbbrev.selectedProperty().addListener((ov, old_val, new_val) -> {
raceMap.toggleAnnoAbbrev();
raceMap.update();
});
//listener for show boat path for annotation
showBoatPath.selectedProperty().addListener((ov, old_val, new_val) -> {
raceMap.toggleBoatPath();
raceMap.update();
});
//listener to show speed for annotation
showSpeed.selectedProperty().addListener((ov, old_val, new_val) -> {
raceMap.toggleAnnoSpeed();
raceMap.update();
});
//listener to save currently selected annotation
saveAnno.setOnAction(event -> {
presetAnno.clear();
presetAnno.add(showName.isSelected());
presetAnno.add(showAbbrev.isSelected());
presetAnno.add(showSpeed.isSelected());
presetAnno.add(showBoatPath.isSelected());
});
//listener to show saved annotation
showSetAnno.setOnAction(event -> {
if (presetAnno.size() > 0) {
showName.setSelected(presetAnno.get(0));
showAbbrev.setSelected(presetAnno.get(1));
showSpeed.setSelected(presetAnno.get(2));
showBoatPath.setSelected(presetAnno.get(3));
raceMap.update();
}
});
}
}

@ -1,159 +0,0 @@
package seng302.Controllers;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import org.xml.sax.SAXException;
import seng302.Model.BoatInRace;
import seng302.Model.RaceClock;
import seng302.RaceDataSource;
import seng302.RaceXMLReader;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
/**
* Created by esa46 on 6/04/17.
*/
public class StartController extends Controller {
@FXML private GridPane start;
@FXML private AnchorPane startWrapper;
@FXML private TableView<BoatInRace> boatNameTable;
@FXML private TableColumn<BoatInRace, String> boatNameColumn;
@FXML private TableColumn<BoatInRace, String> boatCodeColumn;
@FXML private Label timeZoneTime;
@FXML private Label timer;
@FXML private int PRERACE_TIME = 15000;
@FXML Button oneMinButton;
@FXML Button fiveMinButton;
@FXML Button fifteenMinButton;
private RaceClock raceClock;
private RaceDataSource raceData;
/**
* 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);
}
private void startRace(int raceScale){
oneMinButton.setDisable(true);
fiveMinButton.setDisable(true);
fifteenMinButton.setDisable(true);
countdownTimer(raceScale);
}
@Override
public void initialize(URL location, ResourceBundle resources){
raceData = null;
try {
raceData = new RaceXMLReader("raceXML/bermuda_AC35.xml");
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
initialiseTables();
}
public AnchorPane startWrapper(){
return startWrapper;
}
private void initialiseTables() {
List<BoatInRace> boats = raceData.getBoats();
ObservableList<BoatInRace> observableBoats = FXCollections.observableArrayList(boats);
boatNameTable.setItems(observableBoats);
boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().getName());
boatCodeColumn.setCellValueFactory(new PropertyValueFactory<>("abbrev"));
//timezone
raceClock = new RaceClock(raceData.getMark());
timeZoneTime.textProperty().bind(raceClock.timeProperty());
}
/**
* Updates the calculated time to the timer label
*
* @param time The calculated time from calcTimer() method
*/
protected void updateTime(String time) {
Platform.runLater(() -> {
timer.setText(time);
});
}
/**
* Countdown timer until race starts. Use PRERACE_TIME to set countdown duration.
*/
protected void countdownTimer(int scaleFactor) {
new AnimationTimer() {
long currentTime = System.currentTimeMillis();
long startTime = currentTime + (PRERACE_TIME/scaleFactor);
long minutes;
long currentTimeInSeconds;
long remainingSeconds;
long hours;
long timeLeft;
@Override
public void handle(long arg0) {
timeLeft = startTime - currentTime;
if (timeLeft <= 0) {
updateTime("Race is starting...");
stop();
parent.beginRace(scaleFactor, raceData);
startWrapper.setVisible(false);
} else {
currentTimeInSeconds = (timeLeft*scaleFactor) / 1000;
minutes = currentTimeInSeconds / 60;
remainingSeconds = currentTimeInSeconds % 60;
hours = minutes / 60;
minutes = minutes % 60;
updateTime(String.format("Race Clock: -%02d:%02d:%02d", hours, minutes, remainingSeconds));
raceClock.updateTime();
}
currentTime = System.currentTimeMillis();
}
}.start();
}
}

@ -1,72 +0,0 @@
package seng302;
/**
* GPS Coordinate for the world map.
* Created by esa46 on 15/03/17.
*/
public class GPSCoordinate {
private double latitude;
private double longitude;
/**
* Constructor Method
*
* @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;
}
/**
* Gets the Latitude that the Coordinate is at.
*
* @return Returns the latitude of the Coordinate.
*/
public double getLatitude() {
return latitude;
}
/**
* Gets the Longitude that the Coordinate is at.
*
* @return Returns the longitude of the Coordinate.
*/
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() {
return String.format("Latitude: %f, Longitude: %f", latitude, longitude);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GPSCoordinate that = (GPSCoordinate) o;
if (Math.abs(this.latitude - latitude) > 1e-6) return false;
return (Math.abs(this.longitude - longitude) < 1e-6);
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(latitude);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(longitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}

@ -1,40 +0,0 @@
package seng302;
/**
* Graph Coordinate that is to be displayed on the Canvas
* Created by cbt24 on 15/03/17.
*/
public class GraphCoordinate {
private int x;
private int y;
/**
* Constructor method.
*
* @param x X coordinate.
* @param y Y coordinate.
*/
public GraphCoordinate(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Returns the X coordinate.
*
* @return x axis Coordinate.
*/
public int getX() {
return x;
}
/**
* Returns the Y coordinate.
*
* @return y axis Coordinate.
*/
public int getY() {
return y;
}
}

@ -1,99 +0,0 @@
package seng302.Mock;
/**
* Created by jjg64 on 19/04/17.
*/
public class Regatta {
int regattaID;
String RegattaName;
int raceID = 0;
String courseName;
double centralLatitude;
double centralLongitude;
double centralAltitude;
float utcOffset;
float magneticVariation;
public Regatta(int regattaID, String regattaName, String courseName, double centralLatitude, double centralLongitude, double centralAltitude, float utcOffset, float magneticVariation) {
this.regattaID = regattaID;
this.RegattaName = regattaName;
this.courseName = courseName;
this.centralLatitude = centralLatitude;
this.centralLongitude = centralLongitude;
this.centralAltitude = centralAltitude;
this.utcOffset = utcOffset;
this.magneticVariation = magneticVariation;
}
public int getRegattaID() {
return regattaID;
}
public void setRegattaID(int ID) {
this.regattaID = ID;
}
public String getRegattaName() {
return RegattaName;
}
public void setRegattaName(String regattaName) {
RegattaName = regattaName;
}
public int getRaceID() {
return raceID;
}
public void setRaceID(int raceID) {
this.raceID = raceID;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public double getCentralLatitude() {
return centralLatitude;
}
public void setCentralLatitude(double centralLatitude) {
this.centralLatitude = centralLatitude;
}
public double getCentralLongitude() {
return centralLongitude;
}
public void setCentralLongitude(double centralLongitude) {
this.centralLongitude = centralLongitude;
}
public double getCentralAltitude() {
return centralAltitude;
}
public void setCentralAltitude(double centralAltitude) {
this.centralAltitude = centralAltitude;
}
public float getUtcOffset() {
return utcOffset;
}
public void setUtcOffset(float utcOffset) {
this.utcOffset = utcOffset;
}
public float getMagneticVariation() {
return magneticVariation;
}
public void setMagneticVariation(float magneticVariation) {
this.magneticVariation = magneticVariation;
}
}

@ -1,68 +0,0 @@
package seng302.Mock;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import seng302.XMLReader;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
/**
* Created by jjg64 on 19/04/17.
*/
public class RegattaXMLReader extends XMLReader {
private Regatta regatta;
/**
* Constructor for Regatta XML
* @param filePath path of the file
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public RegattaXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException {
this(filePath, true);
}
/**
* Constructor for Regatta XML
* @param filePath file path to read
* @param read whether or not to read and store the files straight away.
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public RegattaXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException {
super(filePath);
if (read) {
read();
}
}
/**
* Read the XML
*/
private void read() {
NodeList attributeConfig = doc.getElementsByTagName("RegattaConfig");
Element attributes = (Element) attributeConfig.item(0);
makeRegatta(attributes);
}
private void makeRegatta(Element attributes) {
int regattaID = Integer.parseInt(getTextValueOfNode(attributes, "RegattaID"));
String regattaName = getTextValueOfNode(attributes, "RegattaName");
String courseName = getTextValueOfNode(attributes, "CourseName");
double centralLatitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralLatitude"));
double centralLongitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralLongitude"));
double centralAltitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralAltitude"));
float utcOffset = Float.parseFloat(getTextValueOfNode(attributes, "UtcOffset"));
float magneticVariation = Float.parseFloat(getTextValueOfNode(attributes, "MagneticVariation"));
regatta = new Regatta(regattaID, regattaName, courseName, centralLatitude, centralLongitude, centralAltitude, utcOffset, magneticVariation);
}
public Regatta getRegatta() {
return regatta;
}
}

@ -1,86 +0,0 @@
package seng302.Model;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
* Created by fwy13 on 3/03/17.
*/
public class Boat {
private StringProperty name;
private double velocity;
private StringProperty velocityProp;
private String abbrev;
/**
* Boat initialiser which keeps all of the information of the boat.
*
* @param name Name of the Boat.
* @param velocity Speed in m/s that the boat travels at.
* @param abbrev nam abbreviation
*/
public Boat(String name, double velocity, String abbrev) {
this.velocity = velocity;
this.velocityProp = new SimpleStringProperty(String.valueOf(Math.round(velocity)));
this.abbrev = abbrev;
this.name = new SimpleStringProperty(name);
}
/**
* @return Name of the boat
*/
public StringProperty getName() {
return name;
}
/**
* Sets the boat name
*
* @param name of boat
*/
public void setName(String name) {
this.name.setValue(name);
}
/**
* @return Speed of the boat.
*/
public double getVelocity() {
return velocity;
}
/**
* Sets the speed of the boat in knots.
*
* @param velocity speed in knots
*/
public void setVelocity(double velocity) {
this.velocity = velocity;
this.velocityProp.setValue(String.valueOf(Math.round(velocity)));
}
/**
* Print method prints the name of the boat
*
* @return Name of the boat.
*/
public String toString() {
return getName().getValue();
}
/**
* @return Velocity String Property of the boat
*/
public StringProperty getVelocityProp() {
return velocityProp;
}
/**
* @return Abbreviation of the boat
*/
public String getAbbrev() {
return abbrev;
}
}

@ -1,329 +0,0 @@
package seng302.Model;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.paint.Color;
import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants;
import seng302.GPSCoordinate;
import java.awt.geom.Point2D;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Boat in the Race extends Boat.
* Created by esa46 on 15/03/17.
*/
public class BoatInRace extends Boat {
private Leg currentLeg;
private double scaledVelocity;
private double distanceTravelledInLeg;
private GPSCoordinate currentPosition;
private long timeFinished;
private Color colour;
private boolean finished = false;
private StringProperty currentLegName;
private boolean started = false;
private StringProperty position;
private double heading;
private Queue<TrackPoint> track = new ConcurrentLinkedQueue<>();
private long nextValidTime = 0;
private static final float BASE_TRACK_POINT_TIME_INTERVAL = 5000;
private static float trackPointTimeInterval = 5000; // every 1 seconds
private final int TRACK_POINT_LIMIT = 10;
private boolean trackVisible = true;
/**
* Constructor method.
*
* @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 abbrev of boat
*/
public BoatInRace(String name, double velocity, Color colour, String abbrev) {
super(name, velocity, abbrev);
setColour(colour);
currentLegName = new SimpleStringProperty("");
position = new SimpleStringProperty("-");
}
/**
* 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();
GPSCoordinate start = currentLeg.getStartMarker().getAverageGPSCoordinate();
GPSCoordinate end = currentLeg.getEndMarker().getAverageGPSCoordinate();
calc.setStartingGeographicPoint(start.getLongitude(), start.getLatitude());
calc.setDestinationGeographicPoint(end.getLongitude(), end.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 double getHeading() {
return heading;
}
public void setHeading(double heading) {
this.heading = heading;
}
/**
* 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);
}
/**
* Returns the position of the end of the boat's wake, which is 180 degrees
* from the boat's heading, and whose length is proportional to the boat's
* speed.
*
* @return GPSCoordinate of wake endpoint.
*/
public GPSCoordinate getWake() {
double reverseHeading = getHeading() - 180;
double distance = Constants.wakeScale * 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 of boat
*/
public void setScaledVelocity(double velocity) {
this.scaledVelocity = velocity;
}
/**
* @return Returns the current position of the boat in a GPSCoordinate Class.
* @see GPSCoordinate
*/
public GPSCoordinate getCurrentPosition() {
return currentPosition;
}
/**
* 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() {
return timeFinished;
}
/**
* 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() {
return colour;
}
/**
* 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
*/
public void setColour(Color colour) {
this.colour = colour;
}
/**
* Gets the current leg that the boat is on.
*
* @return returns the leg the boat is on in a Leg class
* @see Leg
*/
public Leg getCurrentLeg() {
return currentLeg;
}
/**
* Sets the boat's current leg.
*
* @param currentLeg Leg class that the boat is currently on.
* @see Leg
*/
public void setCurrentLeg(Leg currentLeg) {
this.currentLeg = currentLeg;
this.currentLegName.setValue(currentLeg.getName());
}
/**
* @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 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;
}
/**
* @return true if boat has finished, false if not
*/
public boolean isFinished() {
return this.finished;
}
/**
* Sets whether boat is finished or not
*
* @param bool is finished value
*/
public void setFinished(boolean bool) {
this.finished = bool;
}
public boolean isStarted() {
return started;
}
public void setStarted(boolean started) {
this.started = started;
}
public String getPosition() {
return position.get();
}
public StringProperty positionProperty() {
return position;
}
public void setPosition(String position) {
this.position.set(position);
}
/**
* Adds a new point to boat's track.
* @param coordinate of point on track
* @return whether add is successful
* @see seng302.Model.TrackPoint
*/
public boolean addTrackPoint(GPSCoordinate coordinate) {
Boolean added = System.currentTimeMillis() >= nextValidTime;
long currentTime = System.currentTimeMillis();
if (added && this.started) {
nextValidTime = currentTime + (long) trackPointTimeInterval;
track.add(new TrackPoint(coordinate, currentTime, TRACK_POINT_LIMIT * (long) trackPointTimeInterval));
}
return added;
}
/**
* Returns the boat's sampled track between start of race and current time.
* @return queue of track points
* @see seng302.Model.TrackPoint
*/
public Queue<TrackPoint> getTrack() {
return track;
}
/**
* Returns whether track is visible
* @return true if visible
*/
public boolean isTrackVisible() {
return trackVisible;
}
/**
* Sets track visibility.
* @param trackVisible visible if true.
*/
public void setTrackVisible(boolean trackVisible) {
this.trackVisible = trackVisible;
}
/**
* Get base track point time interval
* @return base track point time interval
*/
public static float getBaseTrackPointTimeInterval() {
return BASE_TRACK_POINT_TIME_INTERVAL;
}
/**
* Set track point time interval
* @param value track point time interval value
*/
public static void setTrackPointTimeInterval(float value) {
trackPointTimeInterval = value;
}
}

@ -1,208 +0,0 @@
package seng302.Model;
import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants;
import seng302.Controllers.RaceController;
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;
/**
* Created by cbt24 on 6/03/17.
*
* @deprecated
*/
public class ConstantVelocityRace extends Race {
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 controller for graphics
* @param scaleFactor of timer
*/
public ConstantVelocityRace(List<BoatInRace> startingBoats, List<Leg> legs, RaceController controller, int scaleFactor) {
super(startingBoats, legs, controller, scaleFactor);
}
/**
* Initialiser for legacy tests
*
* @param startingBoats in race
* @param legs in race
* @param controller for graphics
* @param scaleFactor of timer
*
* @deprecated Please use {@link #ConstantVelocityRace(List, List, RaceController, int) } for future tests.
*/
public ConstantVelocityRace(BoatInRace[] startingBoats, List<Leg> legs, RaceController controller, int scaleFactor) {
super(Arrays.asList(startingBoats), legs, controller, scaleFactor);
}
/**
* Initialiser for constant velocity race with standard data source
* @param raceData for race
* @param controller for graphics
* @param scaleFactor of timer
*/
public ConstantVelocityRace(RaceDataSource raceData, RaceController controller, int scaleFactor) {
super(raceData, controller, scaleFactor);
}
public void initialiseBoats() {
Leg officialStart = legs.get(0);
String name = officialStart.getName();
Marker endMarker = officialStart.getEndMarker();
BoatInRace.setTrackPointTimeInterval(BoatInRace.getBaseTrackPointTimeInterval() / scaleFactor);
ArrayList<Marker> 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<Marker> 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<Marker> 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());
}
}

@ -1,106 +0,0 @@
package seng302.Model;
import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants;
import seng302.GPSCoordinate;
/**
* Created by cbt24 on 6/03/17.
*/
public class Leg {
private String name; //nautical miles
private double distance;
private Marker startMarker;
private Marker endMarker;
private int legNumber;
/**
* Leg Initialiser
*
* @param name Name of the Leg
* @param start marker
* @param end marker
* @param number Leg's position in race
*/
public Leg(String name, Marker start, Marker end, int number) {
this.name = name;
this.startMarker = start;
this.endMarker = end;
this.legNumber = number;
calculateDistance();
}
/**
* Construction Method
*
* @param name Name of the Leg
* @param number leg number
*/
public Leg(String name, int number) {
this.name = name;
this.legNumber = number;
}
/**
* Returns the name of the Leg
*
* @return Returns the name of the Leg
*/
public String getName() {
return name;
}
/**
* Get the distance in nautical miles
*
* @return Returns the total distance of the leg.
*/
public double getDistance() {
return distance;
}
/**
* Returns the leg number that the leg exists in the Race
*
* @return Returns the Leg
* @see Race
*/
public int getLegNumber() {
return legNumber;
}
public Marker getStartMarker() {
return startMarker;
}
public Marker getEndMarker() {
return endMarker;
}
public void setStartMarker(Marker startMarker) {
this.startMarker = startMarker;
}
public void setEndMarker(Marker endMarker) {
this.endMarker = endMarker;
}
/**
* Calculates the distance that the legs are in nautical miles (1.852 km).
*/
public void calculateDistance() {
GeodeticCalculator calc = new GeodeticCalculator();
//Load start and end of leg
GPSCoordinate startMarker = this.startMarker.getAverageGPSCoordinate();
GPSCoordinate endMarker = this.endMarker.getAverageGPSCoordinate();
calc.setStartingGeographicPoint(startMarker.getLongitude(), startMarker.getLatitude());
calc.setDestinationGeographicPoint(endMarker.getLongitude(), endMarker.getLatitude());
this.distance = calc.getOrthodromicDistance() / Constants.NMToMetersConversion;
}
}

@ -1,62 +0,0 @@
package seng302.Model;
import org.geotools.referencing.GeodeticCalculator;
import seng302.GPSCoordinate;
import java.awt.geom.Point2D;
/**
* Created by esa46 on 29/03/17.
*/
public class Marker {
private GPSCoordinate averageGPSCoordinate;
private GPSCoordinate mark1;
private GPSCoordinate mark2;
public Marker(GPSCoordinate mark1) {
this.mark1 = mark1;
this.mark2 = mark1;
this.averageGPSCoordinate = calculateAverage();
}
public Marker(GPSCoordinate mark1, GPSCoordinate mark2) {
this.mark1 = mark1;
this.mark2 = mark2;
this.averageGPSCoordinate = calculateAverage();
}
public GPSCoordinate getMark1() {
return mark1;
}
public GPSCoordinate getMark2() {
return mark2;
}
public GPSCoordinate getAverageGPSCoordinate() {
return averageGPSCoordinate;
}
private GPSCoordinate calculateAverage() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(mark1.getLongitude(), mark1.getLatitude());
calc.setDestinationGeographicPoint(mark2.getLongitude(), mark2.getLatitude());
double azimuth = calc.getAzimuth();
double distance = calc.getOrthodromicDistance();
GeodeticCalculator middleCalc = new GeodeticCalculator();
middleCalc.setStartingGeographicPoint(mark1.getLongitude(), mark1.getLatitude());
middleCalc.setDirection(azimuth, distance / 2);
Point2D middlePoint = middleCalc.getDestinationGeographicPoint();
return new GPSCoordinate(middlePoint.getY(), middlePoint.getX());
}
}

@ -1,263 +0,0 @@
package seng302.Model;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.geotools.referencing.GeodeticCalculator;
import seng302.Controllers.RaceController;
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 {
//protected BoatInRace[] startingBoats;
protected ObservableList<BoatInRace> startingBoats;
protected List<Leg> legs;
protected RaceController controller;
protected int boatsFinished = 0;
protected long totalTimeElapsed;
private int lastFPS = 20;
protected int scaleFactor;
protected int PRERACE_TIME = 120000; //time in milliseconds to pause during pre-race
private boolean timerEnabled = true; //boolean to determine if timer is ran
/**
* 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 controller race controller
* @param scaleFactor for race
*/
public Race(List<BoatInRace> boats, List<Leg> legs, RaceController controller, int scaleFactor) {
this.startingBoats = FXCollections.observableArrayList(boats);
this.legs = legs;
this.legs.add(new Leg("Finish", this.legs.size()));
this.controller = controller;
this.scaleFactor = scaleFactor;
if (startingBoats != null && startingBoats.size() > 0) {
initialiseBoats();
}
}
public Race(BoatInRace[] startingBoats, List<Leg> legs, RaceController controller, int scaleFactor) {
this(Arrays.asList(startingBoats), legs, controller, scaleFactor);
}
public Race(RaceDataSource raceData, RaceController controller, int scaleFactor) {
this(raceData.getBoats(), raceData.getLegs(), controller, 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 postion 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.
*/
public void run() {
setControllerListeners();
initialiseBoats();
if (timerEnabled) countdownTimer();
//simulateRace();
}
/**
* Disable the timer
*/
public void disableTimer() {
timerEnabled = false;
}
/**
* Countdown timer until race starts. Use PRERACE_TIME to set countdown duration.
*/
protected void countdownTimer() {
new AnimationTimer() {
long currentTime = System.currentTimeMillis();
long startTime = currentTime + (PRERACE_TIME/scaleFactor);
long minutes;
long currentTimeInSeconds;
long remainingSeconds;
long hours;
long timeLeft;
@Override
public void handle(long arg0) {
timeLeft = startTime - currentTime;
if (timeLeft <= 0 && controller != null) {
updateTime("Race is starting...");
stop();
simulateRace();
} else {
currentTimeInSeconds = (timeLeft*scaleFactor) / 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));
}
}
currentTime = System.currentTimeMillis();
}
}.start();
}
/**
* Takes total time elapsed and format to hour:minute:second
*
* @return Formatted time as string
*/
protected String calcTimer() {
long minutes;
long currentTimeInSeconds;
long remainingSeconds;
long hours;
currentTimeInSeconds = (totalTimeElapsed * scaleFactor) / 1000;
minutes = currentTimeInSeconds / 60;
remainingSeconds = currentTimeInSeconds % 60;
hours = minutes / 60;
minutes = minutes % 60;
return String.format("Race clock: %02d:%02d:%02d", hours, minutes, remainingSeconds);
}
/**
* Updates the calculated time to the timer label
*
* @param time The calculated time from calcTimer() method
*/
protected void updateTime(String time) {
Platform.runLater(() -> {
controller.setTimer(time);
});
}
/**
* Update the calculated fps to the fps label
*
* @param fps The new calculated fps value
*/
private void updateFPS(int fps) {
Platform.runLater(() -> {
controller.setFrames("FPS: " + fps);
});
}
/**
* Starts the Race Simulation, playing the race start to finish with the timescale.
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events.
*/
private void simulateRace() {
System.setProperty("javafx.animation.fullspeed", "true");
for (BoatInRace boat : startingBoats) {
boat.setStarted(true);
}
new AnimationTimer() {
long timeRaceStarted = System.currentTimeMillis(); //start time of loop
int fps = 0; //init fps value
long timeCurrent = System.currentTimeMillis(); //current time
@Override
public void handle(long arg0) {
if (boatsFinished < startingBoats.size()) {
totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted;
for (BoatInRace boat : startingBoats) {
if (boat != null && !boat.isFinished()) {
boat.addTrackPoint(boat.getCurrentPosition());
updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS));
checkPosition(boat, totalTimeElapsed);
}
}
if (timerEnabled)
updateTime(calcTimer());
}
controller.updateMap(startingBoats);
fps++;
if ((System.currentTimeMillis() - timeCurrent) > 1000) {
updateFPS(fps);
lastFPS = fps;
fps = 0;
timeCurrent = System.currentTimeMillis();
}
}
}.start();
}
/**
* Update position of boats in race, no position if on starting leg or DNF.
*/
protected void updatePositions() {
FXCollections.sort(startingBoats, (a, b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber());
for(BoatInRace boat: startingBoats) {
if(boat != null) {
boat.setPosition(Integer.toString(startingBoats.indexOf(boat) + 1));
if (boat.getCurrentLeg().getName().equals("DNF") || boat.getCurrentLeg().getLegNumber() == 0)
boat.setPosition("-");
}
}
}
/**
* Update call for the controller.
*/
protected void setControllerListeners() {
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
*/
public ObservableList<BoatInRace> getStartingBoats() {
return startingBoats;
}
}

@ -1,53 +0,0 @@
package seng302.Model;
import com.github.bfsmith.geotimezone.TimeZoneLookup;
import com.github.bfsmith.geotimezone.TimeZoneResult;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import seng302.GPSCoordinate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* Created by Gondr on 19/04/2017.
*/
public class RaceClock {
private StringProperty time;
private DateTimeFormatter dateTimeFormatter;
private String timeZone;
private ZoneId zoneId;
public RaceClock(GPSCoordinate gpsCoordinate){
TimeZoneLookup timeZoneLookup = new TimeZoneLookup();
TimeZoneResult timeZoneResult = timeZoneLookup.getTimeZone(gpsCoordinate.getLatitude(), gpsCoordinate.getLongitude());
zoneId = ZoneId.of(timeZoneResult.getResult());
LocalDateTime localDateTime = LocalDateTime.now(zoneId);
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM HH:mm:ss z");
// System.out.println(dateTimeFormatter.format(zonedDateTime));
time = new SimpleStringProperty(dateTimeFormatter.format(zonedDateTime));
DateTimeFormatter timeZoneFormatter = DateTimeFormatter.ofPattern("z");
timeZone = timeZoneFormatter.format(zonedDateTime);
}
public void updateTime(){
LocalDateTime localDateTime = LocalDateTime.now(zoneId);
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
time.setValue(dateTimeFormatter.format(zonedDateTime));
}
public String getTime() {
return time.get();
}
public StringProperty timeProperty() {
return time;
}
public String getTimeZone() {
return timeZone;
}
}

@ -1,410 +0,0 @@
package seng302.Model;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.transform.Rotate;
import seng302.*;
import seng302.Controllers.RaceController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* This creates a JavaFX Canvas that is fills it's parent.
* Cannot be downsized.
* Created by fwy13 on 17/03/17.
*/
public class ResizableRaceCanvas extends Canvas {
private GraphicsContext gc;
private RaceMap map;
private List<BoatInRace> boats;
private boolean raceAnno = true;
private boolean annoName = true;
private boolean annoAbbrev = true;
private boolean annoSpeed = true;
private boolean annoPath = true;
private ArrayList<GPSCoordinate> raceBoundaries;
double[] xpoints = {}, ypoints = {};
public ResizableRaceCanvas(RaceDataSource raceData) {
gc = this.getGraphicsContext2D();
// Redraw canvas when size changes.
widthProperty().addListener(evt -> drawRaceMap());
heightProperty().addListener(evt -> drawRaceMap());
double lat1 = raceData.getMapTopLeft().getLatitude();
double long1 = raceData.getMapTopLeft().getLongitude();
double lat2 = raceData.getMapBottomRight().getLatitude();
double long2 = raceData.getMapBottomRight().getLongitude();
setMap(new RaceMap(lat1, long1, lat2, long2, (int) getWidth(), (int) getHeight()));
}
/**
* Sets the boats that are to be displayed in this race.
*
* @param boats in race
*/
public void setBoats(List<BoatInRace> boats) {
this.boats = boats;
}
/**
* Sets the RaceMap that the RaceCanvas is to be displaying for.
*
* @param map race 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.
* @see GraphCoordinate
* @see Color
* @see Paint
*/
public void displayMark(GraphCoordinate graphCoordinate, Paint paint) {
double d = 25;
gc.setFill(paint);
gc.fillOval(graphCoordinate.getX() - (d / 2), graphCoordinate.getY() - (d / 2), d, d);
}
public void displayBoat(BoatInRace boat, double angle) {
GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition());
Paint paint = boat.getColour();
double[] x = {pos.getX() - 6, pos.getX(), pos.getX() + 6};
double[] y = {pos.getY() + 12, pos.getY() - 12, pos.getY() + 12};
gc.setFill(paint);
gc.save();
rotate(angle, pos.getX(), pos.getY());
gc.fillPolygon(x, y, 3);
gc.restore();
}
/**
* 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.
* @see GraphCoordinate
* @see Color
* @see Paint
*/
private void displayLine(GraphCoordinate graphCoordinateA, GraphCoordinate graphCoordinateB, Paint paint) {
gc.setStroke(paint);
gc.setFill(paint);
gc.fillOval(graphCoordinateA.getX() - 3, graphCoordinateA.getY() - 3, 6, 6);
gc.fillOval(graphCoordinateB.getX() - 3, graphCoordinateB.getY() - 3, 6, 6);
gc.strokeLine(graphCoordinateA.getX(), graphCoordinateA.getY(), graphCoordinateB.getX(), graphCoordinateB.getY());
}
/**
* 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.
* @see GraphCoordinate
* @see Paint
* @see Color
*/
private 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).
* @see GraphCoordinate
*/
private void displayArrow(GraphCoordinate coordinate, int angle) {
gc.save();
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},
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.
*/
private void rotate(double angle, double px, double py) {
Rotate r = new Rotate(angle, px, py);
gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy());
}
/**
* Display given name and speed of boat at a graph coordinate
*
* @param name name of the boat
* @param abbrev abbreviation of the boat name
* @param speed speed of the boat
* @param coordinate coordinate the text appears
*/
private void displayText(String name, String abbrev, double speed, GraphCoordinate coordinate) {
String text = "";
//Check name toggle value
if (annoName){
text += String.format("%s ", name);
}
//Check abbreviation toggle value
if (annoAbbrev){
text += String.format("%s ", abbrev);
}
//Check speed toggle value
if (annoSpeed){
text += String.format("%.2fkn", speed);
}
//String text = String.format("%s, %2$.2fkn", name, speed);
long xCoord = coordinate.getX() + 20;
long yCoord = coordinate.getY();
if (xCoord + (text.length() * 7) >= getWidth()) {
xCoord -= text.length() * 7;
}
if (yCoord - (text.length() * 2) <= 0) {
yCoord += 30;
}
gc.fillText(text, xCoord, yCoord);
}
/**
* Draws race map with up to date data.
*/
public void update() {
this.drawRaceMap();
this.updateBoats();
}
/**
* Draw boundary of the race.
*/
public void drawBoundaries() {
if (this.raceBoundaries == null) {
return;
}
gc.setFill(Color.AQUA);
setRaceBoundCoordinates();
gc.fillPolygon(xpoints, ypoints, xpoints.length);
}
/**
* Draws the Race Map
*/
public void drawRaceMap() {
double width = getWidth();
double height = getHeight();
gc.clearRect(0, 0, width, height);
if (map == null) {
return;//TODO this should return a exception in the future
}
this.map.setHeight((int) height);
this.map.setWidth((int) width);
//finish line
gc.setLineWidth(2);
drawBoundaries();
GraphCoordinate finishLineCoord1 = this.map.convertGPS(Constants.finishLineMarker1);
GraphCoordinate finishLineCoord2 = this.map.convertGPS(Constants.finishLineMarker2);
displayLine(finishLineCoord1, finishLineCoord2, Color.DARKRED);
//marks
GraphCoordinate markCoord = this.map.convertGPS(Constants.mark1);
GraphCoordinate windwardGate1 = this.map.convertGPS(Constants.windwardGate1);
GraphCoordinate windwardGate2 = this.map.convertGPS(Constants.windwardGate2);
GraphCoordinate leewardGate1 = this.map.convertGPS(Constants.leewardGate1);
GraphCoordinate leewardGate2 = this.map.convertGPS(Constants.leewardGate2);
displayMark(markCoord, Color.GOLD);
displayLine(windwardGate1, windwardGate2, Color.DARKCYAN);
displayLine(leewardGate1, leewardGate2, Color.DARKVIOLET);
//start line
GraphCoordinate startline1 = this.map.convertGPS(Constants.startLineMarker1);
GraphCoordinate startline2 = this.map.convertGPS(Constants.startLineMarker2);
displayLine(startline1, startline2, Color.GREEN);
updateBoats();
//display wind direction arrow - specify origin point and angle - angle now set to random angle
displayArrow(new GraphCoordinate((int) getWidth() - 40, 40), 150);
}
/**
* 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);
displayPoint(graphCoordinate, colour);
}
/**
* Toggle the raceAnno value
*/
public void toggleAnnotations() {
if (raceAnno) {
raceAnno = false;
} else {
raceAnno = true;
}
}
/**
* Toggle name display in annotation
*/
public void toggleAnnoName() {
if (annoName) {
annoName = false;
} else {
annoName = true;
}
}
public void toggleBoatPath() {
if (annoPath) {
annoPath = false;
} else {
annoPath = true;
}
}
/**
* Toggle abbreviation display in annotation
*/
public void toggleAnnoAbbrev() {
if (annoAbbrev) {
annoAbbrev = false;
} else {
annoAbbrev = true;
}
}
/**
* Toggle speed display in annotation
*/
public void toggleAnnoSpeed() {
if (annoSpeed) {
annoSpeed = false;
} else {
annoSpeed = true;
}
}
/**
* Draws boats while race in progress, when leg heading is set.
*/
public void updateBoats() {
if (boats != null) {
for (BoatInRace boat : boats) {
boolean finished = boat.getCurrentLeg().getName().equals("Finish") || boat.getCurrentLeg().getName().equals("DNF");
boolean isStart = boat.isStarted();
if (!finished && isStart) {
displayBoat(boat, boat.getHeading());
GraphCoordinate wakeFrom = this.map.convertGPS(boat.getCurrentPosition());
GraphCoordinate wakeTo = this.map.convertGPS(boat.getWake());
displayLine(wakeFrom, wakeTo, boat.getColour());
} else if (!isStart) {
displayBoat(boat, boat.getHeading());
} else {
displayBoat(boat, 0);
}
if (raceAnno)
displayText(boat.toString(), boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition()));
if(boat.isTrackVisible()) drawTrack(boat);
}
}
}
/**
* Draws all track points for a given boat. Colour is set by boat, opacity by track point.
* @param boat whose track is displayed
* @see seng302.Model.TrackPoint
*/
private void drawTrack(BoatInRace boat) {
if (annoPath && raceAnno) {
for (TrackPoint point : boat.getTrack()) {
GraphCoordinate scaledCoordinate = this.map.convertGPS(point.getCoordinate());
Color boatColour = boat.getColour();
gc.setFill(new Color(boatColour.getRed(), boatColour.getGreen(), boatColour.getBlue(), point.getAlpha()));
gc.fillOval(scaledCoordinate.getX(), scaledCoordinate.getY(), 5, 5);
}
}
}
public void setRaceBoundaries(List<GPSCoordinate> boundaries) {
this.raceBoundaries = new ArrayList<>();
for (GPSCoordinate bound : boundaries) {
raceBoundaries.add(bound);
}
setRaceBoundCoordinates();
}
public void setRaceBoundCoordinates() {
xpoints = new double[this.raceBoundaries.size()];
ypoints = new double[this.raceBoundaries.size()];
for (int i = 0; i < raceBoundaries.size(); i++) {
GraphCoordinate coord = map.convertGPS(raceBoundaries.get(i));
xpoints[i] = coord.getX();
ypoints[i] = coord.getY();
}
}
/**
* Set the Canvas to resizable.
*
* @return That the Canvas is resizable.
*/
@Override
public boolean isResizable() {
return true;
}
/**
* Returns the preferred width of the Canvas
*
* @param width of canvas
* @return Returns the width of the Canvas
*/
@Override
public double prefWidth(double width) {
return getWidth();
}
/**
* Returns the preferred height of the Canvas
*
* @param height of canvas
* @return Returns the height of the Canvas
*/
@Override
public double prefHeight(double height) {
return getHeight();
}
}

@ -1,50 +0,0 @@
package seng302.Model;
import seng302.GPSCoordinate;
/**
* Created by cbt24 on 7/04/17.
*/
public class TrackPoint {
private GPSCoordinate coordinate;
private long timeAdded;
private long expiry;
private double minAlpha;
/**
* Creates a new track point with fixed GPS coordinates and time, to reach minimum opacity on expiry.
* @param coordinate position of point on physical race map
* @param timeAdded system clock at time of addition
* @param expiry time to minimum opacity after added
*/
public TrackPoint(GPSCoordinate coordinate, long timeAdded, long expiry) {
this.coordinate = coordinate;
this.timeAdded = timeAdded;
this.expiry = expiry;
this.minAlpha = 0.1;
}
/**
* Gets the position of the point on physical race map.
* @return GPS coordinate of point
*/
public GPSCoordinate getCoordinate() {
return coordinate;
}
/**
* Gets opacity of point scaled by age in proportion to expiry, between 1 and minimum opacity inclusive.
* @return greater of minimum opacity and scaled opacity
*/
public double getAlpha() {
return Double.max(minAlpha,1.0 - (double)(System.currentTimeMillis() - timeAdded) / expiry);
}
/**
* Gets time point was added to track.
* @return system clock at time of addition
*/
public long getTimeAdded() {
return timeAdded;
}
}

@ -1,19 +0,0 @@
package seng302;
import seng302.Model.BoatInRace;
import seng302.Model.Leg;
import java.util.List;
/**
* Created by connortaylorbrown on 19/04/17.
*/
public interface RaceDataSource {
List<BoatInRace> getBoats();
List<Leg> getLegs();
List<GPSCoordinate> getBoundary();
GPSCoordinate getMark();
GPSCoordinate getMapTopLeft();
GPSCoordinate getMapBottomRight();
}

@ -1,69 +0,0 @@
package seng302;
/**
* Created by cbt24 on 15/03/17.
*/
public class RaceMap {
private double x1, x2, y1, y2;
private int width, height;
/**
* 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;
}
/**
* Converts GPS coordinates to coordinates for container
*
* @param lat GPS latitude
* @param lon GPS longitude
* @return GraphCoordinate (pair of doubles)
* @see GraphCoordinate
*/
public GraphCoordinate convertGPS(double lat, double lon) {
int difference = Math.abs(width - height);
int size = width;
if (width > height) {
size = height;
return new GraphCoordinate((int) ((size * (lon - x1) / (x2 - x1)) + difference / 2), (int) (size - (size * (lat - y1) / (y2 - y1))));
} else {
return new GraphCoordinate((int) (size * (lon - x1) / (x2 - x1)), (int) ((size - (size * (lat - y1) / (y2 - y1))) + difference / 2));
}
//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
* @see GPSCoordinate
*/
public GraphCoordinate convertGPS(GPSCoordinate coordinate) {
return convertGPS(coordinate.getLatitude(), coordinate.getLongitude());
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
}

@ -1,322 +0,0 @@
package seng302;
import javafx.scene.paint.Color;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import seng302.Model.BoatInRace;
import seng302.Model.Leg;
import seng302.Model.Marker;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by fwy13 on 26/03/2017.
*/
public class RaceXMLReader extends XMLReader implements RaceDataSource {
private List<BoatInRace> boats = new ArrayList<>();
private Color[] colors = {Color.BLUEVIOLET, Color.BLACK, Color.RED, Color.ORANGE, Color.DARKOLIVEGREEN, Color.LIMEGREEN};//TODO make this established in xml or come up with a better system.
private List<Leg> legs = new ArrayList<>();
private GPSCoordinate mark, startPt1, startPt2, finishPt1, finishPt2, leewardPt1, leewardPt2, windwardPt1, windwardPt2;
private GPSCoordinate mapTopLeft, mapBottomRight;
private List<GPSCoordinate> boundary = new ArrayList<>();
private static double COORDINATEPADDING = 0.0005;
/**
* Constractor for Race XML
* @param filePath path of the file
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public RaceXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException {
this(filePath, true);
}
/**
* COnstructor for Race XML
* @param filePath file path to read
* @param read whether or not to read and store the files straight away.
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public RaceXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException {
super(filePath);
if (read) {
read();
}
}
/**
* Read the files
*/
private void read() {
readCourse();
readLegs();
readBoats();
}
/**
* Read all the boats in the XML file
*/
public void readBoats() {
//get all boats
NodeList nBoats = doc.getElementsByTagName("boat");
for (int i = 0; i < nBoats.getLength(); i++) {
String name = getTextValueOfNode((Element) nBoats.item(i), "name");
String abbrev = getTextValueOfNode((Element) nBoats.item(i), "abbr");
double velo = Double.parseDouble(getTextValueOfNode((Element) nBoats.item(i), "speed"));
BoatInRace boat = new BoatInRace(name, velo, colors[i], abbrev);
boat.setCurrentPosition(startPt1);
if (legs.size() > 0) {
boat.setCurrentLeg(legs.get(0));
}
boats.add(boat);
}
}
/**
* Read all the legs in the XML file
*/
public void readLegs() {
//get all legs
NodeList nLegs = doc.getElementsByTagName("leg");
for (int i = 0; i < nLegs.getLength(); i++) {
String label = getTextValueOfNode((Element) nLegs.item(i), "name");
NodeList start = ((Element) nLegs.item(i)).getElementsByTagName("start");
Marker startMarker = getMarker(start);
NodeList finish = ((Element) nLegs.item(i)).getElementsByTagName("finish");
Marker finishMarker = getMarker(finish);
legs.add(new Leg(label, startMarker, finishMarker, i));
}
}
/**
* Read courses in XML file
*/
public void readCourse() {
NodeList nCourse = doc.getElementsByTagName("course");
NodeList nBounds = ((Element) nCourse.item(0)).getElementsByTagName("boundaries");
nBounds = ((Element) nBounds.item(0)).getElementsByTagName("coordinate");
int maxLatitudeIndex = 0;
double maxLatitude = -Double.MIN_VALUE;
int maxLongitudeIndex = 0;
double maxLongitude = -180;
int minLatitudeIndex = 0;
double minLatitude = Double.MAX_VALUE;
int minLongitudeIndex = 0;
double minLongitude = Double.MAX_VALUE;
for (int i = 0; i < nBounds.getLength(); i++) {
boundary.add(getCoordinates((Element) nBounds.item(i)));
if (boundary.get(i).getLatitude() > maxLatitude) {
maxLatitudeIndex = i;
maxLatitude = boundary.get(i).getLatitude();
}
if (boundary.get(i).getLatitude() < minLatitude) {
minLatitudeIndex = i;
minLatitude = boundary.get(i).getLatitude();
}
if (boundary.get(i).getLongitude() > maxLongitude) {
maxLongitudeIndex = i;
maxLongitude = boundary.get(i).getLongitude();
}
if (boundary.get(i).getLongitude() < minLongitude) {
minLongitudeIndex = i;
minLongitude = boundary.get(i).getLongitude();
}
}
double difference = 0;//this will hold the largest difference so we can make the map square.
double latitudeDiff = Math.abs(Math.abs(boundary.get(maxLatitudeIndex).getLatitude()) - Math.abs(boundary.get(minLatitudeIndex).getLatitude()));
double longitudeDiff = Math.abs(Math.abs(boundary.get(maxLongitudeIndex).getLongitude()) - Math.abs(boundary.get(minLongitudeIndex).getLongitude()));
if (latitudeDiff >= longitudeDiff) {
difference = latitudeDiff - longitudeDiff;
maxLongitude += difference / 2;
minLongitude -= difference / 2;
} else {
difference = longitudeDiff - latitudeDiff;
maxLatitude += difference / 2;
minLatitude -= difference / 2;
}
maxLatitude += COORDINATEPADDING;
minLatitude -= COORDINATEPADDING;
maxLongitude += COORDINATEPADDING;
minLongitude -= COORDINATEPADDING;
//now create map boundaries
//top left canvas point is min logitude, max latitude
//bottom right of canvas point is min longitude, max latitude.
mapTopLeft = new GPSCoordinate(minLatitude, minLongitude);
mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude);
NodeList nMarks = ((Element) nCourse.item(0)).getElementsByTagName("marker");
startPt1 = getCoordinates(nMarks, 0);
startPt2 = getCoordinates(nMarks, 0, 1);
mark = getCoordinates(nMarks, 1);
windwardPt1 = getCoordinates(nMarks, 2);
windwardPt2 = getCoordinates(nMarks, 2, 1);
leewardPt1 = getCoordinates(nMarks, 3);
leewardPt2 = getCoordinates(nMarks, 3, 1);
finishPt1 = getCoordinates(nMarks, 4);
finishPt2 = getCoordinates(nMarks, 4, 1);
}
/**
* gets a marker from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @return
*/
private Marker getMarker(NodeList start) {
return getMarker(start, 0);
}
/**
* gets a marker from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex index in the node that has the coordinate tag
* @return
*/
private Marker getMarker(NodeList start, int startIndex) {
return getMarker(start, startIndex, 0);
}
/**
* gets a marker from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex index in the node that has the coordinate tag
* @param nodeIndex coordinate index
* @return
*/
private Marker getMarker(NodeList start, int startIndex, int nodeIndex) {
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("marker");
Element marker = (Element) nodeList.item(nodeIndex);
return getMarker(marker);
}
/**
* gets a changes a marker to GPS coordinates into a marker
* @param markerNode marker to turn into coordinates
* @return
*/
private Marker getMarker(Element markerNode) {
NodeList nCoordinates = markerNode.getElementsByTagName("coordinate");
GPSCoordinate side1 = getCoordinates((Element) nCoordinates.item(0));
GPSCoordinate side2;
if (nCoordinates.getLength() > 1) {
side2 = getCoordinates((Element) nCoordinates.item(1));
} else {
side2 = side1;
}
return new Marker(side1, side2);
}
/**
* gets a coordinates from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @return
*/
private GPSCoordinate getCoordinates(NodeList start) {
return getCoordinates(start, 0);
}
/**
* gets a coordinates from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex the index the tag containing the coordinate should be in
* @return
*/
private GPSCoordinate getCoordinates(NodeList start, int startIndex) {
return getCoordinates(start, startIndex, 0);
}
/**
* gets a coordinates from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex the index the tag containing the coordinate should be in
* @param nodeIndex The coordinate index
* @return
*/
private GPSCoordinate getCoordinates(NodeList start, int startIndex, int nodeIndex) {
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("coordinate");
Element coord = (Element) nodeList.item(nodeIndex);
return getCoordinates(coord);
}
/**
* Returns the coordinate TODO raise exception that runs when the XML is formatted wrongly.
*
* @param coordNode
* @return
*/
private GPSCoordinate getCoordinates(Element coordNode) {
double startLat = Double.parseDouble(getTextValueOfNode(coordNode, "latitude"));
double startLong = Double.parseDouble(getTextValueOfNode(coordNode, "longitude"));
return new GPSCoordinate(startLat, startLong);
}
public List<BoatInRace> getBoats() {
return boats;
}
public List<Leg> getLegs() {
return legs;
}
public GPSCoordinate getMark() {
return mark;
}
public GPSCoordinate getStartPt1() {
return startPt1;
}
public GPSCoordinate getStartPt2() {
return startPt2;
}
public GPSCoordinate getFinishPt1() {
return finishPt1;
}
public GPSCoordinate getFinishPt2() {
return finishPt2;
}
public GPSCoordinate getLeewardPt1() {
return leewardPt1;
}
public GPSCoordinate getLeewardPt2() {
return leewardPt2;
}
public GPSCoordinate getWindwardPt1() {
return windwardPt1;
}
public GPSCoordinate getWindwardPt2() {
return windwardPt2;
}
public List<GPSCoordinate> getBoundary() {
return boundary;
}
public GPSCoordinate getMapTopLeft() {
return mapTopLeft;
}
public GPSCoordinate getMapBottomRight() {
return mapBottomRight;
}
}

@ -1,40 +0,0 @@
package seng302;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by fwy13 on 26/03/2017.
*/
public abstract class XMLReader {
protected Document doc;
public XMLReader(String filePath) throws ParserConfigurationException, IOException, SAXException {
InputStream fXmlFile = getClass().getClassLoader().getResourceAsStream(filePath);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
}
public Document getDocument() {
return doc;
}
public String getTextValueOfNode(Element n, String tagName) {
return n.getElementsByTagName(tagName).item(0).getTextContent();
}
public String getAttribute(Element n, String attr) {
return n.getAttribute(attr);
}
}

@ -1,268 +0,0 @@
<race>
<boats>
<boat>
<name>ORACLE TEAM USA</name>
<speed>20</speed>
<abbr>USA</abbr>
<colour>BLUEVIOLET</colour>
</boat>
<boat>
<name>Land Rover BAR</name>
<speed>30</speed>
<abbr>GBR</abbr>
<colour>BLACK</colour>
</boat>
<boat>
<name>SoftBank Team Japan</name>
<speed>25</speed>
<abbr>JPN</abbr>
<colour>RED</colour>
</boat>
<boat>
<name>Groupama Team France</name>
<speed>20</speed>
<abbr>FRA</abbr>
<colour>ORANGE</colour>
</boat>
<boat>
<name>Artemis Racing</name>
<speed>29</speed>
<abbr>SWE</abbr>
<colour>DARKOLIVEGREEN</colour>
</boat>
<boat>
<name>Emirates Team New Zealand</name>
<speed>62</speed>
<abbr>NZL</abbr>
<colour>LIMEGREEN</colour>
</boat>
</boats>
<legs>
<leg>
<name>Start to Mark 1</name>
<start>
<marker>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
</coordinate>
<coordinate>
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Mark 1 to Leeward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Leeward Gate to Windward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Windward Gate to Leeward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Leeward Gate to Finish</name>
<start>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</finish>
</leg>
</legs>
<course>
<boundaries>
<coordinate>
<latitude>32.313922</latitude>
<longitude>-64.837168</longitude>
</coordinate>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317911</latitude>
<longitude>-64.836996</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
<coordinate>
<latitude>32.304273</latitude>
<longitude>-64.822834</longitude>
</coordinate>
<coordinate>
<latitude>32.279097</latitude>
<longitude>-64.841545</longitude>
</coordinate>
<coordinate>
<latitude>32.279604</latitude>
<longitude>-64.849871</longitude>
</coordinate>
<coordinate>
<latitude>32.289545</latitude>
<longitude>-64.854162</longitude>
</coordinate>
<coordinate>
<latitude>32.290198</latitude>
<longitude>-64.858711</longitude>
</coordinate>
<coordinate>
<latitude>32.297164</latitude>
<longitude>-64.856394</longitude>
</coordinate>
<coordinate>
<latitude>32.296148</latitude>
<longitude>-64.849184</longitude>
</coordinate>
</boundaries>
<marker>
<name>Start Line</name>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
</coordinate>
<coordinate>
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
<marker>
<name>Mark</name>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
<marker>
<name>Windward Gate</name>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
<marker>
<name>Leeward Gate</name>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
<marker>
<name>Finish Line</name>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</course>
</race>

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane fx:id="main" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.Controllers.MainController">
<children>
<fx:include source="race.fxml" fx:id="race"/>
<fx:include source="start.fxml" fx:id="start"/>
</children>
</AnchorPane>

@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<SplitPane fx:id="race" dividerPositions="0.7" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.Controllers.RaceController">
<items>
<GridPane fx:id="canvasBase">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Pane prefHeight="200.0" prefWidth="400.0" GridPane.halignment="LEFT" GridPane.valignment="TOP">
<children>
<Accordion>
<panes>
<TitledPane animated="false" text="Annotation Control">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="240.0" prefWidth="200.0">
<children>
<CheckBox fx:id="showBoatPath" mnemonicParsing="false" selected="true" text="Show Boat Paths" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="104.0" />
<CheckBox fx:id="showAnnotations" layoutX="-2.0" layoutY="14.0" mnemonicParsing="false" selected="true" text="Show Annotations" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
<CheckBox fx:id="showName" layoutY="39.0" mnemonicParsing="false" selected="true" text="Show Boat Name" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="26.0" />
<CheckBox fx:id="showAbbrev" layoutY="61.0" mnemonicParsing="false" selected="true" text="Show Boat Abbreviation" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="52.0" />
<CheckBox fx:id="showSpeed" layoutY="90.0" mnemonicParsing="false" selected="true" text="Show Boat Speed" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="78.0" />
<Button fx:id="saveAnno" layoutX="11.0" layoutY="106.0" maxWidth="154.0" mnemonicParsing="false" prefWidth="154.0" text="Save Annotation" AnchorPane.topAnchor="130.0" />
<Button fx:id="showSetAnno" layoutX="11.0" layoutY="139.0" mnemonicParsing="false" text="Show Set Annotation" AnchorPane.topAnchor="160.0" />
</children>
</AnchorPane>
</content>
</TitledPane>
<TitledPane animated="false" text="FPS Control">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<CheckBox fx:id="showFPS" layoutX="-14.0" layoutY="13.0" mnemonicParsing="false" selected="true" text="Show FPS" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
</TitledPane>
</panes>
</Accordion>
</children>
</Pane>
<Label fx:id="timer" layoutX="45.0" layoutY="146.0" maxHeight="20.0" text="0:0" AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0" GridPane.halignment="RIGHT" GridPane.valignment="BOTTOM">
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
<Label fx:id="FPS" text="FPS: 0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
<Label fx:id="timeZone" text="Label" GridPane.halignment="RIGHT" GridPane.valignment="BOTTOM">
<GridPane.margin>
<Insets bottom="20.0" />
</GridPane.margin>
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
</children>
</GridPane>
<AnchorPane layoutX="450.0" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="200.0" GridPane.columnIndex="1">
<children>
<TableView fx:id="boatInfoTable" layoutX="-2.0" prefHeight="600.0" prefWidth="264.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="-2.0" AnchorPane.rightAnchor="-62.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="boatPlacingColumn" prefWidth="50.0" text="Place" />
<TableColumn fx:id="boatTeamColumn" prefWidth="100.0" text="Team" />
<TableColumn fx:id="boatMarkColumn" prefWidth="130.0" text="Mark" />
<TableColumn fx:id="boatSpeedColumn" prefWidth="75.0" text="Speed" />
</columns>
</TableView>
</children>
</AnchorPane>
</items>
</SplitPane>

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<AnchorPane fx:id="startWrapper" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.Controllers.StartController">
<children>
<GridPane fx:id="start" prefHeight="600.0" prefWidth="780.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" prefWidth="200.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="372.0" minWidth="10.0" prefWidth="200.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="394.0" minWidth="10.0" prefWidth="250.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="416.0" minWidth="10.0" prefWidth="200.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" prefWidth="200.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="241.0" minHeight="10.0" prefHeight="116.5" vgrow="SOMETIMES" />
<RowConstraints maxHeight="383.0" minHeight="10.0" prefHeight="257.5" vgrow="SOMETIMES" />
<RowConstraints maxHeight="369.0" minHeight="10.0" prefHeight="50.5" vgrow="SOMETIMES" />
<RowConstraints maxHeight="369.0" minHeight="10.0" prefHeight="38.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="191.5" minHeight="10.0" prefHeight="53.5" vgrow="SOMETIMES" />
<RowConstraints maxHeight="191.5" minHeight="10.0" prefHeight="82.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Welcome to RaceVision" GridPane.columnSpan="5" GridPane.halignment="CENTER">
<font>
<Font size="36.0" />
</font>
</Text>
<Button maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRace1Min" prefWidth="100.0" fx:id="oneMinButton" text="1 Minute" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="4">
<GridPane.margin>
<Insets />
</GridPane.margin>
</Button>
<Button maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRaceNoScaling" prefWidth="100.0" fx:id="fifteenMinButton" text="15 Minutes" GridPane.columnIndex="3" GridPane.halignment="LEFT" GridPane.rowIndex="4" />
<Button maxWidth="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#startRace5Min" prefWidth="100.0" fx:id="fiveMinButton" text="5 Minutes" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="4" />
<Label text="Select Race Duration:" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="3" />
<TableView fx:id="boatNameTable" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="1">
<columns>
<TableColumn fx:id="boatNameColumn" prefWidth="360.0" style="-fx-font-size: 16;" text="Team Name" />
<TableColumn fx:id="boatCodeColumn" prefWidth="133.0" style="-fx-font-size: 16;" text="Code" />
</columns>
</TableView>
<Label fx:id="timeZoneTime" contentDisplay="CENTER" text="timeZoneTime" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER" />
<Label fx:id="timer" text=" " GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="5" />
</children>
</GridPane>
</children>
</AnchorPane>

@ -1,52 +0,0 @@
package seng302.Mock;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
/**
* Created by jjg64 on 19/04/17.
*/
public class RegattaXMLTest {
RegattaXMLReader regattaXMLReader;
@Before
public void findFile(){
try {
regattaXMLReader = new RegattaXMLReader("mockXML/regattaXML/regattaTest.xml", false);
} catch (Exception e) {
fail("Cannot find mockXML/regattaXML/regattaTest.xml in the resources folder");
}
}
@Test
public void makeRegattaTest() {
try {
regattaXMLReader = new RegattaXMLReader("mockXML/regattaXML/regattaTest.xml");
assertNotEquals(regattaXMLReader.getRegatta(), null);
} catch (Exception e) {
fail("Did not make a Regatta object");
}
}
@Test
public void correctValuesTest() {
try {
regattaXMLReader = new RegattaXMLReader("mockXML/regattaXML/regattaTest.xml");
Regatta regatta = regattaXMLReader.getRegatta();
assertEquals(regatta.getRegattaID(), 3);
assertEquals(regatta.getRegattaName(), "New Zealand Test");
assertEquals(regatta.getCourseName(), "North Head");
assertEquals(regatta.getCentralLatitude(), -36.82791529, 0.00000001);
assertEquals(regatta.getCentralLongitude(), 174.81218919, 0.00000001);
assertEquals(regatta.getCentralAltitude(), 0.00, 0.00000001);
assertEquals(regatta.getUtcOffset(), 12.0, 0.001);
assertEquals(regatta.getMagneticVariation(), 14.1, 0.001);
} catch (Exception e) {
fail("Did not have the correct values");
}
}
}

@ -1,158 +0,0 @@
package seng302.Model;
import javafx.scene.paint.Color;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import seng302.GPSCoordinate;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
/**
* Created by esa46 on 22/03/17.
*/
public class BoatInRaceTest {
private GPSCoordinate ORIGIN_COORDS = new GPSCoordinate(0, 0);
private BoatInRace TEST_BOAT = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt");
@Test
public void calculateDueNorthAzimuthReturns0() {
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(50, 0));
Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start);
assertEquals(TEST_BOAT.calculateAzimuth(), 0, 1e-8);
}
@Test
public void calculateDueSouthAzimuthReturns180() {
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(-50, 0));
Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start);
assertEquals(TEST_BOAT.calculateAzimuth(), 180, 1e-8);
}
@Test
public void calculateDueEastAzimuthReturns90() {
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(0, 50));
Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start);
assertEquals(TEST_BOAT.calculateAzimuth(), 90, 1e-8);
}
@Test
public void calculateDueWestAzimuthReturnsNegative90() {
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(0, -50));
Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start);
assertEquals(TEST_BOAT.calculateAzimuth(), -90, 1e-8);
}
@Test
public void calculateDueNorthHeadingReturns0() {
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(50, 0));
Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start);
assertEquals(TEST_BOAT.calculateHeading(), 0, 1e-8);
}
@Test
public void calculateDueEastHeadingReturns90() {
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(0, 50));
Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start);
assertEquals(TEST_BOAT.calculateHeading(), 90, 1e-8);
}
@Test
public void calculateDueSouthHeadingReturns180() {
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(-50, 0));
Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start);
assertEquals(TEST_BOAT.calculateHeading(), 180, 1e-8);
}
@Test
public void calculateDueWestHeadingReturns270() {
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(0, -50));
Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start);
assertEquals(TEST_BOAT.calculateHeading(), 270, 1e-8);
}
@Test
public void createNewBoatCratesInstanceOfSuperClass() {
BoatInRace testBoat = new BoatInRace("Boat", 20, Color.ALICEBLUE, "tt");
testBoat.setName("Name can change");
assertTrue(testBoat instanceof Boat);
assertTrue(testBoat.getCurrentLeg() == null);
assertTrue(testBoat.getCurrentPosition() == null);
assertTrue(testBoat.toString().contains("Name can change"));
assertEquals(testBoat.getVelocity(), 20.0);
assertTrue(testBoat.getVelocityProp().toString().contains("20"));
assertTrue(testBoat.getAbbrev().equals("tt"));
assertTrue(testBoat.getColour().equals(Color.ALICEBLUE));
assertFalse(testBoat.isFinished());
}
@Test
public void getWakeAtProperHeading() throws Exception {
BoatInRace boat = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt");
// Construct leg of 0 degrees
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(50, 0));
Leg leg0deg = new Leg("Start", startMarker, endMarker, 0);
boat.setCurrentLeg(leg0deg);
boat.setCurrentPosition(new GPSCoordinate(0, 0));
assertEquals(0, boat.calculateHeading(), 1e-8);
// Construct leg from wake - heading should be 180 degrees
Leg leg180deg = new Leg("Start", startMarker, new Marker(boat.getWake()), 0);
boat.setCurrentLeg(leg180deg);
assertEquals(180, boat.calculateHeading(), 1e-8);
}
@Test
public void getWakeProportionalToVelocity() throws Exception {
BoatInRace boat = new BoatInRace("Test", 10, Color.ALICEBLUE, "tt");
// Construct leg of 0 degrees at 0 N
Marker startMarker = new Marker(ORIGIN_COORDS);
Marker endMarker = new Marker(new GPSCoordinate(50, 0));
Leg leg0deg = new Leg("Start", startMarker, endMarker, 0);
boat.setCurrentLeg(leg0deg);
boat.setCurrentPosition(new GPSCoordinate(0,0));
// Get latitude of endpoint of wake at 10 kn (longitude is 0)
double endpointAt10Kn = boat.getWake().getLatitude();
// Latitude of endpoint at 20 kn should be twice endpoint at 10 kn
boat.setVelocity(20);
assertEquals(2*endpointAt10Kn, boat.getWake().getLatitude(), 1e-8);
}
}

@ -1,140 +0,0 @@
package seng302.Model;
import javafx.scene.paint.Color;
import org.geotools.referencing.GeodeticCalculator;
import org.junit.Test;
import seng302.Constants;
import seng302.GPSCoordinate;
import java.lang.reflect.Array;
import java.util.ArrayList;
import static org.junit.Assert.assertEquals;
/**
* Created by esa46 on 16/03/17.
*/
public class ConstantVelocityRaceTest {
Marker START_MARKER = new Marker(new GPSCoordinate(0, 0));
Marker END_MARKER = new Marker(new GPSCoordinate(10, 10));
Leg START_LEG = new Leg("Start", START_MARKER, END_MARKER, 0);
int ONE_HOUR = 3600000; //1 hour in milliseconds
private ArrayList<Leg> generateLegsArray() {
ArrayList<Leg> legs = new ArrayList<>();
legs.add(START_LEG);
return legs;
}
@Test
public void updatePositionChangesDistanceTravelled() {
ArrayList<Leg> legs = generateLegsArray();
BoatInRace boat = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt");
boat.setCurrentLeg(legs.get(0));
boat.setDistanceTravelledInLeg(0);
BoatInRace[] boats = new BoatInRace[]{boat};
ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1);
race.updatePosition(boat, ONE_HOUR);
assertEquals(boat.getDistanceTravelledInLeg(), boat.getVelocity(), 1e-8);
}
@Test
public void updatePositionHandlesNoChangeToDistanceTravelled() {
ArrayList<Leg> legs = generateLegsArray();
BoatInRace boat = new BoatInRace("Test", 0, Color.ALICEBLUE, "tt");
boat.setCurrentLeg(legs.get(0));
boat.setDistanceTravelledInLeg(0);
BoatInRace[] boats = new BoatInRace[]{boat};
ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1);
race.updatePosition(boat, ONE_HOUR);
assertEquals(boat.getDistanceTravelledInLeg(), 0, 1e-8);
}
@Test
public void changesToDistanceTravelledAreAdditive() {
ArrayList<Leg> legs = generateLegsArray();
BoatInRace boat = new BoatInRace("Test", 5, Color.ALICEBLUE, "tt");
boat.setCurrentLeg(legs.get(0));
boat.setDistanceTravelledInLeg(50);
BoatInRace[] boats = new BoatInRace[]{boat};
ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1);
race.updatePosition(boat, ONE_HOUR);
assertEquals(boat.getDistanceTravelledInLeg(), boat.getVelocity() + 50, 1e-8);
}
@Test
public void travelling10nmNorthGivesCorrectNewCoordinates() {
GPSCoordinate oldPos = new GPSCoordinate(0, 0);
GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 0);
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(0, 10 * Constants.NMToMetersConversion);
assertEquals(newPos.getLongitude(), 0, 1e-8);
assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8);
assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8);
}
@Test
public void travelling10nmEastGivesCorrectNewCoordinates() {
GPSCoordinate oldPos = new GPSCoordinate(0, 0);
GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 90);
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(90, 10 * Constants.NMToMetersConversion);
assertEquals(newPos.getLatitude(), 0, 1e-8);
assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8);
assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8);
}
@Test
public void travelling10nmWestGivesCorrectNewCoordinates() {
GPSCoordinate oldPos = new GPSCoordinate(0, 0);
GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, -90);
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(-90, 10 * Constants.NMToMetersConversion);
assertEquals(newPos.getLatitude(), 0, 1e-8);
assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8);
assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8);
}
@Test
public void travelling10nmSouthGivesCorrectNewCoordinates() {
GPSCoordinate oldPos = new GPSCoordinate(0, 0);
GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 180);
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(180, 10 * Constants.NMToMetersConversion);
assertEquals(newPos.getLongitude(), 0, 1e-8);
assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8);
assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8);
}
}

@ -1,78 +0,0 @@
package seng302.Model;
import org.geotools.referencing.GeodeticCalculator;
import org.junit.Test;
import seng302.Constants;
import seng302.GPSCoordinate;
import java.awt.*;
import java.awt.geom.Point2D;
import static junit.framework.TestCase.assertEquals;
/**
* Created by esa46 on 22/03/17.
*/
public class LegTest {
private Marker ORIGIN_MARKER = new Marker(new GPSCoordinate(0, 0));
@Test
public void calculateDistanceHandles5nmNorth() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(0, 5 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
assertEquals(test.getDistance(), 5, 1e-8);
}
@Test
public void calculateDistanceHandles12nmEast() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(90, 12 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
assertEquals(test.getDistance(), 12, 1e-8);
}
@Test
public void calculateDistanceHandlesHalfnmSouth() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(180, 0.5 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
assertEquals(test.getDistance(), 0.5, 1e-8);
}
@Test
public void calculateDistanceHandlesPoint1nmWest() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(-90, 0.1 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
assertEquals(test.getDistance(), 0.1, 1e-8);
}
@Test
public void calculateDistanceHandlesZeroDifference() {
Leg test = new Leg("Test", ORIGIN_MARKER, ORIGIN_MARKER, 0);
assertEquals(test.getDistance(), 0, 1e-8);
}
private Marker getEndMarker(Point2D point) {
GPSCoordinate coords = new GPSCoordinate(point.getY(), point.getX());
return new Marker(coords);
}
}

@ -1,57 +0,0 @@
package seng302.Model;
import org.junit.Test;
import seng302.GPSCoordinate;
import static org.junit.Assert.assertTrue;
/**
* Created by esa46 on 29/03/17.
*/
public class MarkerTest {
GPSCoordinate ORIGIN_COORD = new GPSCoordinate(0, 0);
@Test
public void averageOfSingleMarkAtOriginIsSingleMark() {
Marker testMark = new Marker(ORIGIN_COORD);
assertTrue(testMark.getAverageGPSCoordinate().equals(ORIGIN_COORD));
}
@Test
public void averageOfSingleMarkIsSingleMark() {
GPSCoordinate testCoord = new GPSCoordinate(20, 25);
Marker testMark = new Marker(testCoord);
assertTrue(testMark.getAverageGPSCoordinate().equals(testCoord));
}
@Test
public void averageLatOfTwoMarksIsAccurate() {
GPSCoordinate testCoord = new GPSCoordinate(10, 0);
Marker testMark = new Marker(ORIGIN_COORD, testCoord);
assertTrue(testMark.getAverageGPSCoordinate().equals(new GPSCoordinate(5, 0)));
}
@Test
public void averageLongOfTwoMarksIsAccurate() {
GPSCoordinate testCoord = new GPSCoordinate(0, 10);
Marker testMark = new Marker(ORIGIN_COORD, testCoord);
assertTrue(testMark.getAverageGPSCoordinate().equals(new GPSCoordinate(0, 5)));
}
@Test
public void averageLatAndLongOfTwoMarksIsAccurate() {
GPSCoordinate testCoord1 = new GPSCoordinate(10, 30);
GPSCoordinate testCoord2 = new GPSCoordinate(30, 60);
Marker testMark = new Marker(testCoord1, testCoord2);
assertTrue(testMark.getAverageGPSCoordinate().equals(new GPSCoordinate(020.644102, 44.014817)));
}
}

@ -1,173 +0,0 @@
package seng302.Model;
import javafx.scene.paint.Color;
import org.junit.Ignore;
import org.junit.Test;
import seng302.GPSCoordinate;
import java.util.ArrayList;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Created by esa46 on 15/03/17.
*/
public class RaceTest {
Leg START_LEG = new Leg("Start", new Marker(new GPSCoordinate(0, 0)), new Marker(new GPSCoordinate(1, 1)), 0);
Leg FINISH_LEG = new Leg("Finish", new Marker(new GPSCoordinate(1, 1)), new Marker(new GPSCoordinate(2, 2)), 0);
@Ignore
@Test
public void timerCanBeDisabled() {
BoatInRace boat1 = new BoatInRace("Test 1", 10000, Color.ALICEBLUE, "t1");
BoatInRace boat2 = new BoatInRace("Test 2", 10000, Color.BURLYWOOD, "t2");
BoatInRace[] boats = new BoatInRace[]{boat1, boat2};
ArrayList<Leg> legs = new ArrayList<>();
legs.add(START_LEG); legs.add(FINISH_LEG);
ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 5);
race.disableTimer();
race.setDnfChance(0);
long timeStarted = System.currentTimeMillis();
race.run();
assertTrue(System.currentTimeMillis() - timeStarted < 4000);
}
@Test
public void checkPositionUpdatesNumberFinishedBoats() {
BoatInRace finishedBoat = new BoatInRace("Test", 1000, Color.ALICEBLUE, "tt");
finishedBoat.setDistanceTravelledInLeg(500);
finishedBoat.setCurrentLeg(FINISH_LEG);
ArrayList<Leg> legs = new ArrayList<>();
legs.add(FINISH_LEG);
ConstantVelocityRace race = new ConstantVelocityRace(new BoatInRace[1], legs, null, 1);
race.setDnfChance(0);
assertEquals(race.boatsFinished, 0);
race.checkPosition(finishedBoat, 100000);
assertEquals(race.boatsFinished, 1);
assertEquals(finishedBoat.getTimeFinished(), 100000);
}
@Test
public void checkPositionDoesntUpdateNumberFinishedBoats() {
BoatInRace unFinishedBoat = new BoatInRace("Test", 10, Color.ALICEBLUE, "tt");
unFinishedBoat.setDistanceTravelledInLeg(0);
unFinishedBoat.setCurrentLeg(FINISH_LEG);
ArrayList<Leg> legs = new ArrayList<>();
legs.add(FINISH_LEG);
ConstantVelocityRace race = new ConstantVelocityRace(new BoatInRace[1], legs, null, 1);
race.setDnfChance(0);
assertEquals(race.boatsFinished, 0);
race.checkPosition(unFinishedBoat, 100);
assertEquals(race.boatsFinished, 0);
}
@Test
public void distanceTravelledBeforeUpdatingLegIsRetained() {
ArrayList<Leg> legs = new ArrayList<>();
legs.add(START_LEG);
legs.add(FINISH_LEG);
ConstantVelocityRace race = new ConstantVelocityRace(new BoatInRace[1], legs, null, 1);
race.setDnfChance(0);
BoatInRace unFinishedBoat = new BoatInRace("Test", 10, Color.ALICEBLUE, "tt");
unFinishedBoat.setDistanceTravelledInLeg(100);
unFinishedBoat.setCurrentLeg(START_LEG);
race.checkPosition(unFinishedBoat, 100);
assertEquals(unFinishedBoat.getCurrentLeg().getName(), "Finish");
assertTrue(unFinishedBoat.getDistanceTravelledInLeg() > 0);
assertTrue(unFinishedBoat.getDistanceTravelledInLeg() < 100);
}
/*@Test
//Test temporarily removed as countdown timer now uses animation timer
public void timerDelaysByHalfSecond() {
ArrayList<Leg> legs = new ArrayList<>();
legs.add(START_LEG);
ConstantVelocityRace race = new ConstantVelocityRace(new BoatInRace[1], legs, null, 1);
race.PRERACE_TIME = 500;
long timeStarted = System.currentTimeMillis();
race.countdownTimer();
//assertTrue(System.currentTimeMillis() - timeStarted > 500);
System.out.println(System.currentTimeMillis() - timeStarted);
}*/
@Test
public void scalerScalesVelocityCorrectly() {
int scaleFactor = 3;
float vel1 = 0;
float vel2 = (float) 1.999;
float vel3 = (float) 32.5;
float vel4 = 500;
BoatInRace boat1 = new BoatInRace("test", vel1, Color.ALICEBLUE, "tt");
BoatInRace boat2 = new BoatInRace("test", vel2, Color.ALICEBLUE, "tt");
BoatInRace boat3 = new BoatInRace("test", vel3, Color.ALICEBLUE, "tt");
BoatInRace boat4 = new BoatInRace("test", vel4, Color.ALICEBLUE, "tt");
BoatInRace[] boats = new BoatInRace[]{boat1, boat2, boat3, boat4};
ArrayList<Leg> legs = new ArrayList<>();
legs.add(START_LEG);
ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, scaleFactor);
race.setDnfChance(0);
assertEquals(race.getStartingBoats().get(0).getScaledVelocity(), vel1 * scaleFactor, 1e-6);
assertEquals(race.getStartingBoats().get(1).getScaledVelocity(), vel2 * scaleFactor, 1e-6);
assertEquals(race.getStartingBoats().get(2).getScaledVelocity(), vel3 * scaleFactor, 1e-6);
assertEquals(race.getStartingBoats().get(3).getScaledVelocity(), vel4 * scaleFactor, 1e-6);
}
@Test
public void scalerScalesRaceClockTo1MinCorrectly() {
int scaleFactor = 10;
ArrayList<Leg> legs = new ArrayList<>();
legs.add(START_LEG);
ConstantVelocityRace race = new ConstantVelocityRace(new BoatInRace[5], legs, null, scaleFactor);
race.totalTimeElapsed = 6000; //6 seconds
assertTrue(race.calcTimer().equals("Race clock: 00:01:00"));
}
@Test
public void scalerScalesRaceClockHoursMinutesAndSecondsCorrectly() {
int scaleFactor = 3;
ArrayList<Leg> legs = new ArrayList<>();
legs.add(START_LEG);
ConstantVelocityRace race = new ConstantVelocityRace(new BoatInRace[5], legs, null, scaleFactor);
race.totalTimeElapsed = 3213000;
assertTrue(race.calcTimer().equals("Race clock: 02:40:39"));
}
}

@ -1,97 +0,0 @@
package seng302.Model;/**
* Created by Gondr on 26/03/2017.
*/
import static org.junit.Assert.*;
import org.junit.Test;
import org.xml.sax.SAXException;
import seng302.RaceXMLReader;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class RaceXMLTest {
RaceXMLReader raceXMLReader;
@Test
public void canFindFile(){
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
} catch (Exception e) {
fail("Cannot find raceXML/bermuda_AC35.xml in the resources folder");
}
}
@Test
public void canReadBoats(){
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readBoats();
List<BoatInRace> boats = raceXMLReader.getBoats();
assertTrue(boats.size() == 6);
//test boat 1
assertEquals(boats.get(0).getName().getValue(), "ORACLE TEAM USA");
assertTrue(boats.get(0).getVelocity() == 20);
//test boat 2
assertEquals(boats.get(1).getName().getValue(), "Land Rover BAR");
assertTrue(boats.get(1).getVelocity() == 30);
assertEquals(boats.get(1).getAbbrev(), "GBR");
//test boat 3
assertEquals(boats.get(2).getName().getValue(), "SoftBank Team Japan");
assertTrue(boats.get(2).getVelocity() == 25);
assertEquals(boats.get(2).getAbbrev(), "JPN");
//test boat 4
assertEquals(boats.get(3).getName().getValue(), "Groupama Team France");
assertTrue(boats.get(3).getVelocity() == 20);
assertEquals(boats.get(3).getAbbrev(), "FRA");
//test boat 5
assertEquals(boats.get(4).getName().getValue(), "Artemis Racing");
assertTrue(boats.get(4).getVelocity() == 29);
assertEquals(boats.get(4).getAbbrev(), "SWE");
//test boat 6
assertEquals(boats.get(5).getName().getValue(), "Emirates Team New Zealand");
assertTrue(boats.get(5).getVelocity() == 62);
assertEquals(boats.get(5).getAbbrev(), "NZL");
} catch (Exception e) {
fail("Boat Unreadable");
}
}
@Test
public void canReadLegs(){
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readLegs();
assertTrue(raceXMLReader.getLegs().size() == 5);
} catch (Exception e) {
fail("Legs Unreadable");
}
}
@Test
public void canReadCourse(){
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readCourse();
assertTrue(raceXMLReader.getMapTopLeft() != null);
assertTrue(raceXMLReader.getMapBottomRight() != null);
assertTrue(raceXMLReader.getFinishPt1() != null);
assertTrue(raceXMLReader.getFinishPt2() != null);
assertTrue(raceXMLReader.getStartPt1() != null);
assertTrue(raceXMLReader.getStartPt2() != null);
assertTrue(raceXMLReader.getLeewardPt1() != null);
assertTrue(raceXMLReader.getLeewardPt2() != null);
assertTrue(raceXMLReader.getWindwardPt1() != null);
assertTrue(raceXMLReader.getWindwardPt2() != null);
assertTrue(raceXMLReader.getMark() != null);
assertTrue(raceXMLReader.getBoundary().size() == 11);
} catch (Exception e) {
e.printStackTrace();
fail("Course Unreadable");
}
}
}

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RegattaConfig>
<RegattaID>3</RegattaID>
<RegattaName>New Zealand Test</RegattaName>
<CourseName>North Head</CourseName>
<CentralLatitude>-36.82791529</CentralLatitude>
<CentralLongitude>174.81218919</CentralLongitude>
<CentralAltitude>0.00</CentralAltitude>
<UtcOffset>12</UtcOffset>
<MagneticVariation>14.1</MagneticVariation>
</RegattaConfig>

@ -1,268 +0,0 @@
<race>
<boats>
<boat>
<name>ORACLE TEAM USA</name>
<speed>20</speed>
<abbr>USA</abbr>
<colour>BLUEVIOLET</colour>
</boat>
<boat>
<name>Land Rover BAR</name>
<speed>30</speed>
<abbr>GBR</abbr>
<colour>BLACK</colour>
</boat>
<boat>
<name>SoftBank Team Japan</name>
<speed>25</speed>
<abbr>JPN</abbr>
<colour>RED</colour>
</boat>
<boat>
<name>Groupama Team France</name>
<speed>20</speed>
<abbr>FRA</abbr>
<colour>ORANGE</colour>
</boat>
<boat>
<name>Artemis Racing</name>
<speed>29</speed>
<abbr>SWE</abbr>
<colour>DARKOLIVEGREEN</colour>
</boat>
<boat>
<name>Emirates Team New Zealand</name>
<speed>62</speed>
<abbr>NZL</abbr>
<colour>LIMEGREEN</colour>
</boat>
</boats>
<legs>
<leg>
<name>Start to Mark 1</name>
<start>
<marker>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
</coordinate>
<coordinate>
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Mark 1 to Leeward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Leeward Gate to Windward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Windward Gate to Leeward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Leeward Gate to Finish</name>
<start>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</finish>
</leg>
</legs>
<course>
<boundaries>
<coordinate>
<latitude>32.313922</latitude>
<longitude>-64.837168</longitude>
</coordinate>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317911</latitude>
<longitude>-64.836996</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
<coordinate>
<latitude>32.304273</latitude>
<longitude>-64.822834</longitude>
</coordinate>
<coordinate>
<latitude>32.279097</latitude>
<longitude>-64.841545</longitude>
</coordinate>
<coordinate>
<latitude>32.279604</latitude>
<longitude>-64.849871</longitude>
</coordinate>
<coordinate>
<latitude>32.289545</latitude>
<longitude>-64.854162</longitude>
</coordinate>
<coordinate>
<latitude>32.290198</latitude>
<longitude>-64.858711</longitude>
</coordinate>
<coordinate>
<latitude>32.297164</latitude>
<longitude>-64.856394</longitude>
</coordinate>
<coordinate>
<latitude>32.296148</latitude>
<longitude>-64.849184</longitude>
</coordinate>
</boundaries>
<marker>
<name>Start Line</name>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
</coordinate>
<coordinate>
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
<marker>
<name>Mark</name>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
<marker>
<name>Windward Gate</name>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
<marker>
<name>Leeward Gate</name>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
<marker>
<name>Finish Line</name>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</course>
</race>
Loading…
Cancel
Save