diff --git a/doc/examples/config.json b/doc/examples/config.json
index 8a3f3ac2..80c3b3e4 100644
--- a/doc/examples/config.json
+++ b/doc/examples/config.json
@@ -9,7 +9,7 @@
},
{
"team-name": "Artemis Racing",
- "velocity": 10.3
+ "velocity": 59.3
},
{
"team-name": "Emirates Team New Zealand",
@@ -17,7 +17,7 @@
},
{
"team-name": "Groupama Team France",
- "velocity": 9.9
+ "velocity": 29.9
},
{
"team-name": "Land Rover BAR",
diff --git a/doc/examples/config.xml b/doc/examples/config.xml
index 05c20921..4a1b0770 100644
--- a/doc/examples/config.xml
+++ b/doc/examples/config.xml
@@ -3,6 +3,7 @@
AC35
6
- 2.0
+ 1.0
+ 135
diff --git a/doc/examples/course.xml b/doc/examples/course.xml
index 49e17923..f8bfa00e 100644
--- a/doc/examples/course.xml
+++ b/doc/examples/course.xml
@@ -6,57 +6,57 @@
Start
Start1
- 32.296038
- -64.854401
+ 32.296577
+ -64.854304
Start2
- 32.293834
- -64.855195
+ 32.293771
+ -64.855242
Mid Mark
- 32.292881
- -64.843231
+ 32.293039
+ -64.843983
Leeward Gate
Leeward Gate1
- 32.283808
- -64.850012
+ 32.284680
+ -64.850045
Leeward Gate2
- 32.283216
- -64.847686
+ 32.280164
+ -64.847591
Windward Gate
Windward Gate1
- 32.309908
- -64.833665
+ 32.309693
+ -64.835249
Windward Gate2
- 32.309158
- -64.830834
+ 32.308046
+ -64.831785
Finish
Finish1
- 32.318439
- -64.837367
+ 32.317379
+ -64.839291
Finish2
- 32.318303
- -64.834974
+ 32.317257
+ -64.836260
diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java
index db1e823e..b2dd4250 100644
--- a/src/main/java/seng302/App.java
+++ b/src/main/java/seng302/App.java
@@ -10,7 +10,7 @@ public class App extends Application
{
@Override
public void start(Stage primaryStage) throws Exception {
- Parent root = FXMLLoader.load(getClass().getResource("/RaceView.fxml"));
+ Parent root = FXMLLoader.load(getClass().getResource("/MainView.fxml"));
primaryStage.setTitle("RaceVision");
primaryStage.setScene(new Scene(root));
diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java
index e3663035..96476e41 100644
--- a/src/main/java/seng302/controllers/CanvasController.java
+++ b/src/main/java/seng302/controllers/CanvasController.java
@@ -1,18 +1,18 @@
package seng302.controllers;
-import javafx.animation.AnimationTimer;
-import javafx.animation.KeyFrame;
-import javafx.animation.KeyValue;
-import javafx.animation.Timeline;
+import javafx.animation.*;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
-import javafx.scene.control.TextArea;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
+import javafx.scene.text.Text;
import javafx.util.Duration;
import seng302.models.Boat;
import seng302.models.Event;
@@ -22,13 +22,13 @@ import seng302.models.mark.GateMark;
import seng302.models.mark.Mark;
import seng302.models.mark.MarkType;
import seng302.models.mark.SingleMark;
+import seng302.models.parsers.ConfigParser;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import static java.lang.Math.abs;
-
/**
* Created by ptg19 on 15/03/17.
* Modified by Haoming Yin (hyi25) on 20/3/2017.
@@ -42,13 +42,94 @@ public class CanvasController {
private Race race;
private GraphicsContext gc;
private HashMap timelineInfos;
- private final double VIEW_CORNER_LAT = 32.280808;
- private final double VIEW_CORNER_LON = -64.858401;
+ private AnchorPane raceResults;
+ private final double ORIGIN_LAT = 32.320504;
+ private final double ORIGIN_LON = -64.857063;
+
+ @FXML
+ private AnchorPane contentAnchorPane;
+ @FXML
+ private Text windArrowText, windDirectionText;
+
+ @FXML Pane raceTimer;
+
+ private Animation.Status raceStatus = Animation.Status.PAUSED;
+
+ /**
+ * Display the list of boats in the order they finished the race
+ */
+ private void loadRaceResultView() {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/FinishView.fxml"));
+ loader.setController(new RaceResultController(race));
+
+ try {
+ contentAnchorPane.getChildren().removeAll();
+ contentAnchorPane.getChildren().clear();
+ contentAnchorPane.getChildren().addAll((Pane) loader.load());
+
+ } catch (javafx.fxml.LoadException e) {
+ System.err.println(e.getCause());
+ } catch (IOException e) {
+ System.err.println(e);
+ }
+ }
+
+ /**
+ * Load the race timer
+ */
+ private void loadTimerView(){
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/raceTimer.fxml"));
+ loader.setController(new RaceTimerController(race));
+
+ try{
+ raceTimer.getChildren().clear();
+ raceTimer.getChildren().removeAll();
+ raceTimer.getChildren().addAll((Pane) loader.load());
+ }
+ catch(javafx.fxml.LoadException e){
+ System.out.println(e);
+ }
+ catch(IOException e){
+ System.out.println(e);
+ }
+ }
+
+ /**
+ * Play each boats timeline
+ */
+ private void playTimelines(){
+ for (TimelineInfo timelineInfo : timelineInfos.values()){
+ Timeline timeline = timelineInfo.getTimeline();
+
+ if (timeline.getStatus() == Animation.Status.PAUSED){
+ timeline.play();
+ }
+ }
+ raceStatus = Animation.Status.RUNNING;
+ }
+
+ /**
+ * Pause each boats timeline
+ */
+ private void pauseTimelines(){
+ for (TimelineInfo timelineInfo : timelineInfos.values()){
+ Timeline timeline = timelineInfo.getTimeline();
+
+ if (timeline.getStatus() == Animation.Status.RUNNING){
+ timeline.pause();
+ }
+ }
+ raceStatus = Animation.Status.PAUSED;
+ }
+
+ /**
+ * Initialize the controller
+ */
public void initialize() {
gc = canvas.getGraphicsContext2D();
- gc.scale(22, 22);
+ gc.scale(15, 15);
RaceController raceController = new RaceController();
raceController.initializeRace();
race = raceController.getRace();
@@ -62,17 +143,53 @@ public class CanvasController {
drawCourse();
drawBoats();
+ // If race has started, draw the boats and play the timeline
+ if (race.getRaceTime() > 1){
+ playTimelines();
+
+ }
+ // Race has not started, pause the timelines
+ else if (race.getRaceTime() < 1 || raceStatus == Animation.Status.RUNNING){
+ pauseTimelines();
+ }
+
}
};
generateTimeline();
- // starts the timer and reads events from each boat's time line
timer.start();
+
+ loadTimerView();
+
+ Double maxDuration = 0.0;
+ Timeline maxTimeline = null;
+
for (TimelineInfo timelineInfo : timelineInfos.values()) {
+
Timeline timeline = timelineInfo.getTimeline();
+ System.out.println();
+
+ if (timeline.getTotalDuration().toMillis() >= maxDuration) {
+ maxDuration = timeline.getTotalDuration().toMillis();
+ maxTimeline = timeline;
+ }
+
+ // Timelines are paused by default
timeline.play();
+ timeline.pause();
+ raceStatus = Animation.Status.RUNNING;
}
+
+ maxTimeline.setOnFinished(event -> {
+ race.setRaceFinished();
+ loadRaceResultView();
+ });
+
+ //set wind direction!!!!!!! can't find another place to put my code --haoming
+ double windDirection = new ConfigParser("doc/examples/config.xml").getWindDirection();
+ windDirectionText.setText(String.format("%.1f°", windDirection));
+ windArrowText.setRotate(windDirection);
}
/**
@@ -97,13 +214,22 @@ public class CanvasController {
// iterates all events and convert each event to keyFrame, then add them into a list
for (Event event : events) {
- keyFrames.add(
- new KeyFrame(Duration.seconds(event.getTime() / 60 / 60 / 5),
- onFinished,
- new KeyValue(x, event.getThisMark().getLatitude()),
- new KeyValue(y, event.getThisMark().getLongitude())
- )
- );
+ if (event.getIsFinishingEvent()) {
+ keyFrames.add(
+ new KeyFrame(Duration.seconds(event.getTime() / 60 / 60 / 5),
+ event1 -> race.setBoatFinished(boat),
+ new KeyValue(x, event.getThisMark().getLatitude()),
+ new KeyValue(y, event.getThisMark().getLongitude())
+ )
+ );
+ } else {
+ keyFrames.add(
+ new KeyFrame(Duration.seconds(event.getTime() / 60 / 60 / 5),
+ new KeyValue(x, event.getThisMark().getLatitude()),
+ new KeyValue(y, event.getThisMark().getLongitude())
+ )
+ );
+ }
}
// uses the lists generated above to create a Timeline for the boat.
@@ -121,22 +247,6 @@ public class CanvasController {
}
}
- /**
- * @return the distance between the two marks
- */
- public double getDistanceBetweenMarks(Mark mark1, Mark mark2) {
- double earth_radius = 6378.137;
- double dLat = mark2.getLatitude() * Math.PI / 180 - mark1.getLatitude() * Math.PI / 180;
- double dLon = mark2.getLongitude() * Math.PI / 180 - mark1.getLongitude() * Math.PI / 180;
-
- double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(mark1.getLatitude() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
-
- double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- double d = earth_radius * c;
-
- return d * 1000;
- }
-
/**
* Draws a boat with given (x, y) position in the given color
*
@@ -146,13 +256,11 @@ public class CanvasController {
*/
private void drawBoat(double lat, double lon, Color color) {
// Latitude
- //Double x = (MAP_WIDTH / 360.0) * (180 + lon);
- //Double y = (MAP_HEIGHT / 180.0) * (80 - lat);
-
- double x = (lat - VIEW_CORNER_LAT) * 1000; // to prevent negative longitude
- double y = (lon - VIEW_CORNER_LON) * 1000; // to prevent negative latitude
+ double x = (lon - ORIGIN_LON) * 1000;
+ double y = (ORIGIN_LAT - lat) * 1000;
double diameter = 0.5;
+
gc.setFill(color);
gc.fillOval(x, y, diameter, diameter);
}
@@ -163,7 +271,7 @@ public class CanvasController {
private void drawCourse() {
for (Mark mark : race.getCourse()) {
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
- drawSingleMark((SingleMark) mark);
+ drawSingleMark((SingleMark) mark, Color.BLACK);
} else if (mark.getMarkType() == MarkType.GATE_MARK) {
drawGateMark((GateMark) mark);
}
@@ -175,12 +283,12 @@ public class CanvasController {
*
* @param singleMark
*/
- private void drawSingleMark(SingleMark singleMark) {
- double x = (singleMark.getLatitude() - VIEW_CORNER_LAT) * 1000; // to prevent negative longitude
- double y = (singleMark.getLongitude() - VIEW_CORNER_LON) * 1000; // to prevent negative latitude
+ private void drawSingleMark(SingleMark singleMark, Color color) {
+ double x = (singleMark.getLongitude() - ORIGIN_LON) * 1000;
+ double y = (ORIGIN_LAT - singleMark.getLatitude()) * 1000;
- gc.setFill(Color.BLACK);
- gc.fillOval(x, y, 0.5, 0.5);
+ gc.setFill(color);
+ gc.fillRect(x,y,0.5,0.5);
}
/**
@@ -189,7 +297,35 @@ public class CanvasController {
* @param gateMark
*/
private void drawGateMark(GateMark gateMark) {
- drawSingleMark(gateMark.getSingleMark1());
- drawSingleMark(gateMark.getSingleMark2());
+ Color color = Color.BLUE;
+
+ if (gateMark.getName().equals("Start")){
+ color = Color.RED;
+ }
+
+ if (gateMark.getName().equals("Finish")){
+ color = Color.GREEN;
+ }
+
+ drawSingleMark(gateMark.getSingleMark1(), color);
+ drawSingleMark(gateMark.getSingleMark2(), color);
+
+ GraphicsContext gc = canvas.getGraphicsContext2D();
+
+ gc.setStroke(color);
+
+ // Convert lat/lon to x,y
+ double x1 = (gateMark.getSingleMark1().getLongitude()- ORIGIN_LON) * 1000;
+ double y1 = (ORIGIN_LAT - gateMark.getSingleMark1().getLatitude()) * 1000;
+
+ double x2 = (gateMark.getSingleMark2().getLongitude() - ORIGIN_LON) * 1000;
+ double y2 = (ORIGIN_LAT - gateMark.getSingleMark2().getLatitude()) * 1000;
+
+ gc.setLineWidth(0.07);
+ gc.strokeLine(x1, y1, x2, y2);
}
-}
+
+ public Race getRace(){
+ return this.race;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java
deleted file mode 100644
index 41fb6dc2..00000000
--- a/src/main/java/seng302/controllers/Controller.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package seng302.controllers;
-
-import javafx.fxml.FXML;
-import javafx.scene.Parent;
-import javafx.scene.layout.AnchorPane;
-
-/**
- * Created by ptg19 on 20/03/17.
- */
-public class Controller {
- @FXML private AnchorPane window;
- @FXML private Parent raceView;
- @FXML private RaceController raceViewController;
-
- //^ this is automatic fxml linking based off http://blog.buildpath.de/fxml-composition-how-to-get-the-controller-of-an-included-fxml-view-nested-controllers/
- // From googling it's probably better to just add a child however you did that in your 301 michael, it kinda depends on how we are going to
- // make an event for changing the screen.
-}
diff --git a/src/main/java/seng302/controllers/MasterViewController.java b/src/main/java/seng302/controllers/MasterViewController.java
new file mode 100644
index 00000000..72de0419
--- /dev/null
+++ b/src/main/java/seng302/controllers/MasterViewController.java
@@ -0,0 +1,38 @@
+package seng302.controllers;
+
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.Pane;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ResourceBundle;
+
+/**
+ * Created by michaelrausch on 21/03/17.
+ */
+public class MasterViewController implements Initializable {
+ @FXML
+ private AnchorPane contentPane;
+
+ private void setContentPane(String jfxUrl){
+ try{
+ contentPane.getChildren().removeAll();
+ contentPane.getChildren().clear();
+ contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
+ }
+ catch(javafx.fxml.LoadException e){
+ System.err.println(e.getCause());
+ }
+ catch(IOException e){
+ System.err.println(e);
+ }
+ }
+
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+ setContentPane("/RaceView.fxml");
+ }
+}
diff --git a/src/main/java/seng302/controllers/RaceController.java b/src/main/java/seng302/controllers/RaceController.java
index 11f3a318..e8471426 100644
--- a/src/main/java/seng302/controllers/RaceController.java
+++ b/src/main/java/seng302/controllers/RaceController.java
@@ -2,9 +2,8 @@ package seng302.controllers;
import seng302.models.Boat;
import seng302.models.OldFileParser;
-import seng302.models.parsers.*;
-import seng302.models.mark.*;
import seng302.models.Race;
+import seng302.models.parsers.CourseParser;
import java.io.FileNotFoundException;
import java.lang.reflect.Array;
@@ -20,6 +19,7 @@ import java.util.Random;
*/
public class RaceController {
Race race = null;
+
public void initializeRace() {
String raceConfigFile;
raceConfigFile = "doc/examples/config.json";
@@ -55,13 +55,18 @@ public class RaceController {
//get race size
int numberOfBoats = (int) fp.getRaceSize();
+ int boatsAdded = 0;
//get time scale
double timeScale = fp.getTimeScale();
race.setTimeScale(timeScale);
for (Map team : teams) {
- boatNames.add((String) team.get("team-name"));
+ if (boatsAdded < numberOfBoats){
+ boatNames.add((String) team.get("team-name"));
+ race.addBoat(new Boat(team.get("team-name").toString(), (Double) (team.get("velocity"))));
+ }
+ boatsAdded++;
}
// Shuffle team names
@@ -72,11 +77,6 @@ public class RaceController {
return null;
}
- // Add boats to the race
- for (int i = 0; i < numberOfBoats; i++) {
- race.addBoat(new Boat(boatNames.get(i), (Double) (teams.get(i).get("velocity"))));
- }
-
CourseParser cp = new CourseParser("doc/examples/course.xml");
race.addCourse(cp.getCourse());
diff --git a/src/main/java/seng302/controllers/RaceResultController.java b/src/main/java/seng302/controllers/RaceResultController.java
new file mode 100644
index 00000000..7378fa68
--- /dev/null
+++ b/src/main/java/seng302/controllers/RaceResultController.java
@@ -0,0 +1,37 @@
+package seng302.controllers;
+
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import seng302.models.Race;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+/**
+ * Created by ptg19 on 20/03/17.
+ */
+public class RaceResultController implements Initializable{
+ @FXML private AnchorPane window;
+ @FXML private VBox resultsVBox;
+ private Race race;
+
+ RaceResultController(Race race){
+ this.race = race;
+ }
+
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+ int boatPosition = this.race.getFinishedBoats().length;
+
+ for (int i = this.race.getFinishedBoats().length - 1; i >= 0; i--){
+ resultsVBox.getChildren().add(0, new Text(boatPosition + ": " + this.race.getFinishedBoats()[i].getTeamName()));
+ boatPosition--;
+ }
+
+
+
+ }
+}
diff --git a/src/main/java/seng302/controllers/RaceTimerController.java b/src/main/java/seng302/controllers/RaceTimerController.java
new file mode 100644
index 00000000..9c1d1130
--- /dev/null
+++ b/src/main/java/seng302/controllers/RaceTimerController.java
@@ -0,0 +1,78 @@
+package seng302.controllers;
+
+import javafx.animation.KeyFrame;
+import javafx.animation.Timeline;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.text.Text;
+import javafx.util.Duration;
+import seng302.models.Race;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class RaceTimerController implements Initializable{
+ private Timeline timeline;
+ private Race race;
+
+ @FXML
+ private Text timerLabel;
+
+ /**
+ * Convert seconds to a string of the format mm:ss
+ * @param time the time in seconds
+ * @return a formatted string
+ */
+ public String convertTimeToMinutesSeconds(int time){
+ if (time < 0){
+ return String.format("-%02d:%02d", (time * -1) / 60, (time * -1)% 60);
+ }
+ return String.format("%02d:%02d", time / 60, time % 60);
+ }
+
+ /**
+ * Controller to control the race timer
+ * @param race the race the timer is timing
+ */
+ public RaceTimerController(Race race){
+ this.race = race;
+ }
+
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+ timeline = new Timeline();
+ timeline.setCycleCount(Timeline.INDEFINITE);
+
+ // Run timer update every second
+ timeline.getKeyFrames().add(
+ new KeyFrame(Duration.seconds(1),
+ event -> {
+ // Stop timer if race is finished
+ if (this.race.isRaceFinished()){
+ this.timeline.stop();
+ }
+ else{
+ timerLabel.setText(convertTimeToMinutesSeconds(race.getRaceTime()));
+ this.race.incrementRaceTime();
+ }
+ })
+ );
+
+ // Start the timer
+ timeline.playFromStart();
+ }
+
+ /**
+ * Stop the race timer
+ */
+ public void stop(){
+ timeline.stop();
+ }
+
+ /**
+ * Start the race timer
+ */
+ public void start(){
+ timeline.play();
+ }
+}
diff --git a/src/main/java/seng302/models/Event.java b/src/main/java/seng302/models/Event.java
index 51eb814c..00a2b8bd 100644
--- a/src/main/java/seng302/models/Event.java
+++ b/src/main/java/seng302/models/Event.java
@@ -1,7 +1,6 @@
package seng302.models;
import seng302.models.mark.Mark;
-import seng302.models.mark.SingleMark;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -40,7 +39,7 @@ public class Event {
* @param eventTime, what time the event happens
* @param eventBoat, the boat that the event belongs to
*/
- public Event(Double eventTime, Boat eventBoat, SingleMark mark1) {
+ public Event(Double eventTime, Boat eventBoat, Mark mark1) {
this.time = eventTime;
this.boat = eventBoat;
this.mark1 = mark1;
diff --git a/src/main/java/seng302/models/Race.java b/src/main/java/seng302/models/Race.java
index ab036664..2ad111e8 100644
--- a/src/main/java/seng302/models/Race.java
+++ b/src/main/java/seng302/models/Race.java
@@ -15,6 +15,8 @@ public class Race {
private List course; // Marks in the race
private long startTime = 0;
private double timeScale = 1;
+ private boolean raceFinished = false; // Race is finished
+ private int raceTime = -10; // Current time in the race
/**
* Race class containing the boats and legs in the race
@@ -104,7 +106,7 @@ public class Race {
// There are no more marks after this event
else{
- Event event = new Event(time, boat, course.get(i), course.get(i));
+ Event event = new Event(time, boat, course.get(i));
events.get(boat).add(event);
}
}
@@ -121,15 +123,74 @@ public class Race {
generateEvents();
}
+ /**
+ * Set the race course
+ * @param course a list of marks in the course
+ */
public void addCourse(List course) {
this.course = course;
}
+ /**
+ * Get a list of marks in the course
+ * @return
+ */
public List getCourse() {
return course;
}
+ /**
+ * Get a map of the events in the race
+ * @return
+ */
public HashMap getEvents() {
return events;
}
+
+ /**
+ * Set a boat as finished
+ * @param boat The boat that has finished the race
+ */
+ public void setBoatFinished(Boat boat){
+ System.out.println(boat.getTeamName() + " finished");
+ this.finishingOrder.add(boat);
+ }
+
+ /**
+ * Set the race as finished
+ */
+ public void setRaceFinished(){
+ this.raceFinished = true;
+ }
+
+ /**
+ * Return whether or not the race is finished
+ * @return true if the race is finished
+ */
+ public boolean isRaceFinished(){
+ return this.raceFinished;
+ }
+
+ /**
+ * Set the race time
+ * @param raceTime the race time in seconds
+ */
+ public void setRaceTime(int raceTime){
+ this.raceTime = raceTime;
+ }
+
+ /**
+ * Return the race time
+ * @return the race time in seconds
+ */
+ public int getRaceTime(){
+ return this.raceTime;
+ }
+
+ /**
+ * Increment the race time by one second
+ */
+ public void incrementRaceTime(){
+ this.raceTime ++;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/seng302/models/mark/GateMark.java b/src/main/java/seng302/models/mark/GateMark.java
index 208d2416..edf4f4ec 100644
--- a/src/main/java/seng302/models/mark/GateMark.java
+++ b/src/main/java/seng302/models/mark/GateMark.java
@@ -37,4 +37,12 @@ public class GateMark extends Mark {
public void setSingleMark2(SingleMark singleMark2) {
this.singleMark2 = singleMark2;
}
+
+ public double getLatitude(){
+ return (this.getSingleMark1().getLatitude() + this.getSingleMark2().getLatitude()) / 2;
+ }
+
+ public double getLongitude(){
+ return (this.getSingleMark1().getLongitude() + this.getSingleMark2().getLongitude()) / 2;
+ }
}
diff --git a/src/main/java/seng302/models/parsers/ConfigParser.java b/src/main/java/seng302/models/parsers/ConfigParser.java
new file mode 100644
index 00000000..74d0986a
--- /dev/null
+++ b/src/main/java/seng302/models/parsers/ConfigParser.java
@@ -0,0 +1,80 @@
+package seng302.models.parsers;
+
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import java.util.DoubleSummaryStatistics;
+
+public class ConfigParser extends FileParser {
+
+ private Document doc;
+
+ public ConfigParser(String path) {
+ super(path);
+ this.doc = this.parseFile();
+ }
+
+ /**
+ * Gets wind direction from config file.
+ *
+ * @return a double type degree, or 0 if no value or invalid value is found
+ */
+ public double getWindDirection() {
+ return getDoubleByTagName("wind-direction", 0.0);
+ }
+
+ /**
+ * Gets a non negative time scale for the race
+ *
+ * @return a double type scale, or 0 if no scale or invalid scale is found
+ */
+ public double getTimeScale() {
+ return getDoubleByTagName("time-scale", 1.0);
+ }
+
+ /**
+ * Gets a double type number by given tag name found in xml file
+ *
+ * @param tagName a string of tag name
+ * @param defaultVal value returned if no value or invalid value is found
+ * @return value found
+ */
+ public double getDoubleByTagName(String tagName, double defaultVal) {
+ double val = defaultVal;
+ try {
+ Node node = this.doc.getElementsByTagName(tagName).item(0);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element element = (Element) node;
+ val = Double.valueOf(element.getTextContent());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ return val;
+ }
+ }
+
+ /**
+ * Gets a string by given tag name found in xml file
+ *
+ * @param tagName a string of tag name
+ * @param defaultVal a string returned if no value or invalid value is found
+ * @return string found
+ */
+ public String getStringByTagName(String tagName, String defaultVal) {
+ String string = defaultVal;
+ try {
+ Node node = this.doc.getElementsByTagName(tagName).item(0);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element element = (Element) node;
+ string = element.getTextContent();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ return string;
+ }
+ }
+}
diff --git a/src/main/resources/FinishView.fxml b/src/main/resources/FinishView.fxml
index 3e743bab..debdea26 100644
--- a/src/main/resources/FinishView.fxml
+++ b/src/main/resources/FinishView.fxml
@@ -1,37 +1,53 @@
+
-
-
+
-
-
+
+
-
-
-
+
+
+
+
-
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/MainView.fxml b/src/main/resources/MainView.fxml
index e69d850e..9c1ea80f 100644
--- a/src/main/resources/MainView.fxml
+++ b/src/main/resources/MainView.fxml
@@ -4,9 +4,8 @@
-
-
+
-
+
diff --git a/src/main/resources/RaceView.fxml b/src/main/resources/RaceView.fxml
index 1ac0d054..c56e4edb 100644
--- a/src/main/resources/RaceView.fxml
+++ b/src/main/resources/RaceView.fxml
@@ -1,5 +1,7 @@
+
+
@@ -9,26 +11,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/raceTimer.fxml b/src/main/resources/raceTimer.fxml
new file mode 100644
index 00000000..afa99263
--- /dev/null
+++ b/src/main/resources/raceTimer.fxml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/seng302/TestRaceTimer.java b/src/test/java/seng302/TestRaceTimer.java
new file mode 100644
index 00000000..cd51db3b
--- /dev/null
+++ b/src/test/java/seng302/TestRaceTimer.java
@@ -0,0 +1,26 @@
+package seng302;
+
+import org.junit.Test;
+import seng302.controllers.RaceTimerController;
+import seng302.models.Race;
+
+import static org.junit.Assert.assertTrue;
+
+
+public class TestRaceTimer {
+ @Test
+ public void testPositiveTimeString(){
+ RaceTimerController controller = new RaceTimerController(new Race());
+ String result = controller.convertTimeToMinutesSeconds(61);
+
+ assertTrue(result.equals("01:01"));
+ }
+
+ @Test
+ public void testNegativeTimeString(){
+ RaceTimerController controller = new RaceTimerController(new Race());
+ String result = controller.convertTimeToMinutesSeconds(-61);
+
+ assertTrue(result.equals("-01:01"));
+ }
+}
diff --git a/src/test/java/seng302/models/parsers/ConfigParserTest.java b/src/test/java/seng302/models/parsers/ConfigParserTest.java
new file mode 100644
index 00000000..26387220
--- /dev/null
+++ b/src/test/java/seng302/models/parsers/ConfigParserTest.java
@@ -0,0 +1,42 @@
+package seng302.models.parsers;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by Haoming on 23/03/17.
+ */
+public class ConfigParserTest {
+
+ private ConfigParser cp;
+
+ @Before
+ public void initializeParser() throws Exception {
+ cp = new ConfigParser("doc/examples/config.xml");
+ }
+
+ @Test
+ public void getWindDirection() throws Exception {
+ assertEquals(135, cp.getWindDirection(), 1e-10);
+ }
+
+ @Test
+ public void getTimeScale() throws Exception {
+ assertEquals(1.0, cp.getTimeScale(), 1e-10);
+ }
+
+ @Test
+ public void getDoubleByTagName() throws Exception {
+ assertEquals(6, cp.getDoubleByTagName("race-size", 0), 1e-10);
+ assertEquals(100, cp.getDoubleByTagName("noTag", 100), 1e-10);
+ }
+
+ @Test
+ public void getStringByTagName() throws Exception {
+ assertEquals("AC35", cp.getStringByTagName("race-name", "11"));
+ assertEquals("oops", cp.getStringByTagName("noTag", "oops"));
+ }
+
+}
\ No newline at end of file