Merge branch 'develop' into Story47CourseLimits

Conflicts:
	src/main/java/seng302/App.java
This commit is contained in:
Michael Rausch
2017-05-15 18:37:31 +12:00
8 changed files with 307 additions and 267 deletions
-1
View File
@@ -71,7 +71,6 @@ public class App extends Application {
launch(args); launch(args);
} }
} }
@@ -1,6 +1,5 @@
package seng302.controllers; package seng302.controllers;
import javafx.animation.Animation;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
@@ -35,6 +34,7 @@ import java.util.*;
* Created by ptg19 on 29/03/17. * Created by ptg19 on 29/03/17.
*/ */
public class RaceViewController extends Thread implements ImportantAnnotationDelegate { public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
@FXML @FXML
private VBox positionVbox; private VBox positionVbox;
@FXML @FXML
@@ -55,8 +55,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private ArrayList<Yacht> startingBoats = new ArrayList<>(); private ArrayList<Yacht> startingBoats = new ArrayList<>();
private boolean displayFps; private boolean displayFps;
private Timeline timerTimeline; private Timeline timerTimeline;
private Map<Yacht, TimelineInfo> timelineInfos = new HashMap<>();
private ArrayList<Yacht> boatOrder = new ArrayList<>();
private Race race; private Race race;
private Stage stage; private Stage stage;
private ImportantAnnotationsState importantAnnotations; private ImportantAnnotationsState importantAnnotations;
@@ -79,10 +77,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
initializeSettings(); initializeSettings();
initialiseWindDirection(); initialiseWindDirection();
initialisePositionVBox(); initialisePositionVBox();
//set wind direction!!!!!!! can't find another place to put my code --haoming
// double windDirection = new ConfigParser("/config/config.xml").getWindDirection();
// windDirectionText.setText(String.format("%.1f°", windDirection));
// windArrowText.setRotate(windDirection);
includedCanvasController.timer.start(); includedCanvasController.timer.start();
selectAnnotationBtn.setOnAction(event -> { selectAnnotationBtn.setOnAction(event -> {
@@ -92,6 +86,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* The important annotations have been changed, update this view * The important annotations have been changed, update this view
*
* @param importantAnnotationsState The current state of the selected annotations * @param importantAnnotationsState The current state of the selected annotations
*/ */
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) { public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
@@ -108,12 +103,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
Stage stage = new Stage(); Stage stage = new Stage();
// Set controller // Set controller
ImportantAnnotationController controller = new ImportantAnnotationController(this, stage); ImportantAnnotationController controller = new ImportantAnnotationController(this,
stage);
fxmlLoader.setController(controller); fxmlLoader.setController(controller);
// Load FXML and set CSS // Load FXML and set CSS
fxmlLoader.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml")); fxmlLoader
Scene scene = new Scene(fxmlLoader.load(), 469, 248); .setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 469, 270);
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString()); scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
stage.initStyle(StageStyle.UNDECORATED); stage.initStyle(StageStyle.UNDECORATED);
@@ -132,7 +129,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
toggleFps.selectedProperty().addListener(new ChangeListener<Boolean>() { toggleFps.selectedProperty().addListener(new ChangeListener<Boolean>() {
@Override @Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
Boolean newValue) {
displayFps = !displayFps; displayFps = !displayFps;
} }
}); });
@@ -141,10 +139,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
annotationSlider.setLabelFormatter(new StringConverter<Double>() { annotationSlider.setLabelFormatter(new StringConverter<Double>() {
@Override @Override
public String toString(Double n) { public String toString(Double n) {
if (n == 0) return "None"; if (n == 0) {
if (n == 1) return "Low"; return "None";
if (n == 2) return "Important"; }
if (n == 3) return "All"; if (n == 1) {
return "Low";
}
if (n == 2) {
return "Important";
}
if (n == 3) {
return "All";
}
return "All"; return "All";
} }
@@ -199,7 +205,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
windDirTimeline.getKeyFrames().add( windDirTimeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1), new KeyFrame(Duration.seconds(1),
event -> { event -> {
windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection())); windDirectionText
.setText(String.format("%.1f°", StreamParser.getWindDirection()));
windArrowText.setRotate(StreamParser.getWindDirection()); windArrowText.setRotate(StreamParser.getWindDirection());
}) })
); );
@@ -220,97 +227,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
/**
* Generates time line for each boat, and stores time time into timelineInfos hash map
*/
private void initializeTimelines() {
HashMap<Yacht, List> boat_events = race.getEvents();
for (Yacht boat : boat_events.keySet()) {
startingBoats.add(boat);
// // x, y are the real time coordinates
// DoubleProperty x = new SimpleDoubleProperty();
// DoubleProperty y = new SimpleDoubleProperty();
//
// List<KeyFrame> keyFrames = new ArrayList<>();
// List<Event> events = boat_events.get(boat);
//
// // iterates all events and convert each event to keyFrame, then add them into a list
// for (Event event : events) {
// if (event.getIsFinishingEvent()) {
// keyFrames.add(
// new KeyFrame(Duration.seconds(event.getTime()),
// onFinished -> {race.setBoatFinished(boat); handleEvent(event);},
// new KeyValue(x, event.getThisMark().getLatitude()),
// new KeyValue(y, event.getThisMark().getLongitude())
// )
// );
// } else {
// keyFrames.add(
// new KeyFrame(Duration.seconds(event.getTime()),
// onFinished ->{
// handleEvent(event);
// boat.setHeading(event.getBoatHeading());
// },
// new KeyValue(x, event.getThisMark().getLatitude()),
// new KeyValue(y, event.getThisMark().getLongitude())
// )
// );
// }
// }
// timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y));
}
setRaceDuration();
}
private void setRaceDuration(){
Double maxDuration = 0.0;
Timeline maxTimeline = null;
for (TimelineInfo timelineInfo : timelineInfos.values()) {
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getTotalDuration().toMillis() >= maxDuration) {
maxDuration = timeline.getTotalDuration().toMillis();
maxTimeline = timeline;
}
// Timelines are paused by default
timeline.play();
timeline.pause();
}
maxTimeline.setOnFinished(event -> {
race.setRaceFinished();
loadRaceResultView();
});
}
/**
* Play each boats timerTimeline
*/
public void playTimelines(){
for (TimelineInfo timelineInfo : timelineInfos.values()){
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getStatus() == Animation.Status.PAUSED){
timeline.play();
}
}
}
/**
* Pause each boats timerTimeline
*/
public void pauseTimelines(){
for (TimelineInfo timelineInfo : timelineInfos.values()){
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getStatus() == Animation.Status.RUNNING){
timeline.pause();
}
}
}
/** /**
* Display the list of boats in the order they finished the race * Display the list of boats in the order they finished the race
*/ */
@@ -330,29 +246,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
} }
public void handleEvent(Event event) {
Yacht boat = event.getBoat();
boatOrder.remove(boat);
boat.setMarkLastPast(event.getMarkPosInRace());
boatOrder.add(boat);
boatOrder.sort(new Comparator<Yacht>() {
@Override
public int compare(Yacht b1, Yacht b2) {
return b2.getMarkLastPast() - b1.getMarkLastPast();
}
});
showOrder();
}
private void showOrder() { private void showOrder() {
positionVbox.getChildren().clear(); positionVbox.getChildren().clear();
positionVbox.getChildren().removeAll(); positionVbox.getChildren().removeAll();
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// for (Boat boat : boatOrder) {
// positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots"));
// }
for (Yacht boat : StreamParser.getBoatsPos().values()) { for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (boat.getBoatStatus() == 3) { // 3 is finish status if (boat.getBoatStatus() == 3) { // 3 is finish status
Text textToAdd = new Text(boat.getPosition() + ". " + Text textToAdd = new Text(boat.getPosition() + ". " +
@@ -407,6 +305,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
public void stopTimer() { public void stopTimer() {
timerTimeline.stop(); timerTimeline.stop();
} }
public void startTimer() { public void startTimer() {
timerTimeline.play(); timerTimeline.play();
} }
@@ -419,46 +318,51 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
return race; return race;
} }
public Map<Yacht, TimelineInfo> getTimelineInfos() {
return timelineInfos;
}
public ArrayList<Yacht> getStartingBoats() { public ArrayList<Yacht> getStartingBoats() {
return startingBoats; return startingBoats;
} }
/** /**
* Display the important annotations for a specific BoatGroup * Display the important annotations for a specific BoatGroup
*
* @param bg The boat group to set the annotations for * @param bg The boat group to set the annotations for
*/ */
private void setBoatGroupImportantAnnotations(BoatGroup bg) { private void setBoatGroupImportantAnnotations(BoatGroup bg) {
if (importantAnnotations.getAnnotationState(Annotation.NAME)) { if (importantAnnotations.getAnnotationState(Annotation.NAME)) {
bg.setTeamNameObjectVisible(true); bg.setTeamNameObjectVisible(true);
} } else {
else{
bg.setTeamNameObjectVisible(false); bg.setTeamNameObjectVisible(false);
} }
if (importantAnnotations.getAnnotationState(Annotation.SPEED)) { if (importantAnnotations.getAnnotationState(Annotation.SPEED)) {
bg.setVelocityObjectVisible(true); bg.setVelocityObjectVisible(true);
} } else {
else{
bg.setVelocityObjectVisible(false); bg.setVelocityObjectVisible(false);
} }
if (importantAnnotations.getAnnotationState(Annotation.TRACK)) { if (importantAnnotations.getAnnotationState(Annotation.TRACK)) {
bg.setLineGroupVisible(true); bg.setLineGroupVisible(true);
} } else {
else{
bg.setLineGroupVisible(false); bg.setLineGroupVisible(false);
} }
if (importantAnnotations.getAnnotationState(Annotation.WAKE)) { if (importantAnnotations.getAnnotationState(Annotation.WAKE)) {
bg.setWakeVisible(true); bg.setWakeVisible(true);
} } else {
else{
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) {
bg.setEstTimeToNextMarkObjectVisible(true);
} else {
bg.setEstTimeToNextMarkObjectVisible(false);
}
if (importantAnnotations.getAnnotationState(Annotation.LEGTIME)) {
bg.setLegTimeObjectVisible(true);
} else {
bg.setLegTimeObjectVisible(false);
}
} }
private void setAnnotations(Integer annotationLevel) { private void setAnnotations(Integer annotationLevel) {
@@ -470,6 +374,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
BoatGroup bg = (BoatGroup) ro; BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(false); bg.setTeamNameObjectVisible(false);
bg.setVelocityObjectVisible(false); bg.setVelocityObjectVisible(false);
bg.setEstTimeToNextMarkObjectVisible(false);
bg.setLegTimeObjectVisible(false);
bg.setLineGroupVisible(false); bg.setLineGroupVisible(false);
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
@@ -482,6 +388,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
BoatGroup bg = (BoatGroup) ro; BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(true); bg.setTeamNameObjectVisible(true);
bg.setVelocityObjectVisible(false); bg.setVelocityObjectVisible(false);
bg.setEstTimeToNextMarkObjectVisible(false);
bg.setLegTimeObjectVisible(false);
bg.setLineGroupVisible(false); bg.setLineGroupVisible(false);
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
@@ -503,6 +411,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
BoatGroup bg = (BoatGroup) ro; BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(true); bg.setTeamNameObjectVisible(true);
bg.setVelocityObjectVisible(true); bg.setVelocityObjectVisible(true);
bg.setEstTimeToNextMarkObjectVisible(true);
bg.setLegTimeObjectVisible(true);
bg.setLineGroupVisible(true); bg.setLineGroupVisible(true);
bg.setWakeVisible(true); bg.setWakeVisible(true);
} }
@@ -7,5 +7,7 @@ public enum Annotation {
SPEED, SPEED,
WAKE, WAKE,
TRACK, TRACK,
NAME NAME,
ESTTIMETONEXTMARK,
LEGTIME
} }
@@ -15,6 +15,7 @@ import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class ImportantAnnotationController implements Initializable { public class ImportantAnnotationController implements Initializable {
/* /*
* JavaFX Outlets * JavaFX Outlets
*/ */
@@ -30,6 +31,12 @@ public class ImportantAnnotationController implements Initializable {
@FXML @FXML
private CheckBox boatNameSelect; private CheckBox boatNameSelect;
@FXML
private CheckBox boatEstTimeToNextMarkSelect;
@FXML
private CheckBox boatElapsedTimeSelect;
@FXML @FXML
private AnchorPane annotationSelectWindow; private AnchorPane annotationSelectWindow;
@@ -49,6 +56,7 @@ public class ImportantAnnotationController implements Initializable {
/** /**
* Sets whether or not an annotation is considered important, then * Sets whether or not an annotation is considered important, then
* sends an update to the delegate * sends an update to the delegate
*
* @param annotation The annotation * @param annotation The annotation
* @param isSet True if annotation is important * @param isSet True if annotation is important
*/ */
@@ -67,6 +75,7 @@ public class ImportantAnnotationController implements Initializable {
/** /**
* Load the current state of the 'important annotations' * Load the current state of the 'important annotations'
*
* @param currentState hashmap containing the states of each annotation * @param currentState hashmap containing the states of each annotation
*/ */
public void loadState(ImportantAnnotationsState currentState) { public void loadState(ImportantAnnotationsState currentState) {
@@ -76,21 +85,34 @@ public class ImportantAnnotationController implements Initializable {
for (Annotation annotation : importantAnnotationsState.getAnnotations()) { for (Annotation annotation : importantAnnotationsState.getAnnotations()) {
switch (annotation) { switch (annotation) {
case WAKE: case WAKE:
boatWakeSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); boatWakeSelect
.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break; break;
case SPEED: case SPEED:
boatSpeedSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); boatSpeedSelect
.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break; break;
case TRACK: case TRACK:
boatTrackSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); boatTrackSelect
.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break; break;
case NAME: case NAME:
boatNameSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); boatNameSelect
.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break; break;
case ESTTIMETONEXTMARK:
boatEstTimeToNextMarkSelect
.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
case LEGTIME:
boatElapsedTimeSelect
.setSelected(importantAnnotationsState.getAnnotationState(annotation));
default: default:
break; break;
} }
@@ -99,15 +121,24 @@ public class ImportantAnnotationController implements Initializable {
/** /**
* View did load * View did load
*
* @param location . * @param location .
* @param resources . * @param resources .
*/ */
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
boatWakeSelect.setOnAction(event -> setAnnotation(Annotation.WAKE, boatWakeSelect.isSelected())); boatWakeSelect
boatSpeedSelect.setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected())); .setOnAction(event -> setAnnotation(Annotation.WAKE, boatWakeSelect.isSelected()));
boatTrackSelect.setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected())); boatSpeedSelect
boatNameSelect.setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected())); .setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected()));
boatTrackSelect
.setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected()));
boatNameSelect
.setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected()));
boatEstTimeToNextMarkSelect.setOnAction(event -> setAnnotation(Annotation.ESTTIMETONEXTMARK,
boatEstTimeToNextMarkSelect.isSelected()));
boatElapsedTimeSelect.setOnAction(
event -> setAnnotation(Annotation.LEGTIME, boatElapsedTimeSelect.isSelected()));
closeButton.setOnAction(event -> stage.close()); closeButton.setOnAction(event -> stage.close());
} }
+110 -30
View File
@@ -8,24 +8,32 @@ import javafx.scene.shape.Polygon;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
import javafx.stage.Stage; import javafx.stage.Stage;
import seng302.models.parsers.StreamParser;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 dimensional boat. * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2
* It contains a single polygon for the boat, a group of lines to show it's path, a wake object and two text labels to * dimensional boat. It contains a single polygon for the boat, a group of lines to show it's path,
* annotate the boat teams name and the boats velocity. The boat will update it's position onscreen everytime * a wake object and two text labels to annotate the boat teams name and the boats velocity. The
* UpdatePosition is called unless the window is minimized in which case it attempts to store animations and apply them * boat will update it's position onscreen everytime UpdatePosition is called unless the window is
* when the window is maximised. * minimized in which case it attempts to store animations and apply them when the window is
* maximised.
*/ */
public class BoatGroup extends RaceObject { public class BoatGroup extends RaceObject {
//Constants for drawing //Constants for drawing
private static final double TEAMNAME_X_OFFSET = 10d; private static final double TEAMNAME_X_OFFSET = 10d;
private static final double TEAMNAME_Y_OFFSET = -15d; private static final double TEAMNAME_Y_OFFSET = -29d;
private static final double VELOCITY_X_OFFSET = 10d; private static final double VELOCITY_X_OFFSET = 10d;
private static final double VELOCITY_Y_OFFSET = -5d; private static final double VELOCITY_Y_OFFSET = -17d;
private static final double ESTTIMETONEXTMARK_X_OFFSET = 10d;
private static final double ESTTIMETONEXTMARK_Y_OFFSET = -5d;
private static final double LEGTIME_X_OFFSET = 10d;
private static final double LEGTIME_Y_OFFSET = 7d;
private static final double BOAT_HEIGHT = 15d; private static final double BOAT_HEIGHT = 15d;
private static final double BOAT_WIDTH = 10d; private static final double BOAT_WIDTH = 10d;
//Variables for boat logic. //Variables for boat logic.
@@ -38,6 +46,8 @@ public class BoatGroup extends RaceObject{
private Polygon boatPoly; private Polygon boatPoly;
private Text teamNameObject; private Text teamNameObject;
private Text velocityObject; private Text velocityObject;
private Text estTimeToNextMarkObject;
private Text legTimeObject;
private Wake wake; private Wake wake;
//Handles boat moving when connecting to a stream //Handles boat moving when connecting to a stream
private boolean setToInitialLocation = false; private boolean setToInitialLocation = false;
@@ -50,8 +60,9 @@ public class BoatGroup extends RaceObject{
/** /**
* Creates a BoatGroup with the default triangular boat polygon. * Creates a BoatGroup with the default triangular boat polygon.
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which *
* BoatGroup to update. * @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
* to tell which BoatGroup to update.
* @param color The colour of the boat polygon and the trailing line. * @param color The colour of the boat polygon and the trailing line.
*/ */
public BoatGroup(Yacht boat, Color color) { public BoatGroup(Yacht boat, Color color) {
@@ -60,22 +71,26 @@ public class BoatGroup extends RaceObject{
} }
/** /**
* Creates a BoatGroup with the boat being the default polygon. The head of the boat should be at point (0,0). * Creates a BoatGroup with the boat being the default polygon. The head of the boat should be
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which * at point (0,0).
* BoatGroup to update. *
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
* to tell which BoatGroup to update.
* @param color The colour of the boat polygon and the trailing line. * @param color The colour of the boat polygon and the trailing line.
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon. * @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
* polygon.
*/ */
public BoatGroup (Yacht boat, Color color, double... points) public BoatGroup(Yacht boat, Color color, double... points) {
{
this.boat = boat; this.boat = boat;
initChildren(color, points); initChildren(color, points);
} }
/** /**
* Creates the javafx objects that will be the in the group by default. * Creates the javafx objects that will be the in the group by default.
*
* @param color The colour of the boat polygon and the trailing line. * @param color The colour of the boat polygon and the trailing line.
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon. * @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
* polygon.
*/ */
private void initChildren(Color color, double... points) { private void initChildren(Color color, double... points) {
boatPoly = new Polygon(points); boatPoly = new Polygon(points);
@@ -83,6 +98,17 @@ public class BoatGroup extends RaceObject{
teamNameObject = new Text(boat.getShortName()); teamNameObject = new Text(boat.getShortName());
velocityObject = new Text(String.valueOf(boat.getVelocity())); velocityObject = new Text(String.valueOf(boat.getVelocity()));
DateFormat format = new SimpleDateFormat("mm:ss");
String timeToNextMark = format
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark);
if (boat.getMarkRoundingTime() != null) {
String elapsedTime = format
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
legTimeObject = new Text("Last mark: " + elapsedTime);
} else {
legTimeObject = new Text("Last mark: -");
}
teamNameObject.setX(TEAMNAME_X_OFFSET); teamNameObject.setX(TEAMNAME_X_OFFSET);
teamNameObject.setY(TEAMNAME_Y_OFFSET); teamNameObject.setY(TEAMNAME_Y_OFFSET);
@@ -93,12 +119,24 @@ public class BoatGroup extends RaceObject{
velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
destinationSet = false; destinationSet = false;
estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET);
estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET);
estTimeToNextMarkObject
.relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY());
legTimeObject.setX(LEGTIME_X_OFFSET);
legTimeObject.setY(LEGTIME_Y_OFFSET);
legTimeObject.relocate(legTimeObject.getX(), legTimeObject.getY());
wake = new Wake(0, -BOAT_HEIGHT); wake = new Wake(0, -BOAT_HEIGHT);
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly); super.getChildren()
.addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject,
legTimeObject);
} }
/** /**
* Creates the javafx objects that will be the in the group by default. * Creates the javafx objects that will be the in the group by default.
*
* @param color The colour of the boat polygon and the trailing line. * @param color The colour of the boat polygon and the trailing line.
*/ */
private void initChildren(Color color) { private void initChildren(Color color) {
@@ -109,7 +147,9 @@ public class BoatGroup extends RaceObject{
} }
/** /**
* Moves the boat and its children annotations from its current coordinates by specified amounts. * Moves the boat and its children annotations from its current coordinates by specified
* amounts.
*
* @param dx The amount to move the X coordinate by * @param dx The amount to move the X coordinate by
* @param dy The amount to move the Y coordinate by * @param dy The amount to move the Y coordinate by
*/ */
@@ -120,6 +160,10 @@ public class BoatGroup extends RaceObject{
teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy); teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy);
velocityObject.setLayoutX(velocityObject.getLayoutX() + dx); velocityObject.setLayoutX(velocityObject.getLayoutX() + dx);
velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); velocityObject.setLayoutY(velocityObject.getLayoutY() + dy);
estTimeToNextMarkObject.setLayoutX(estTimeToNextMarkObject.getLayoutX() + dx);
estTimeToNextMarkObject.setLayoutY(estTimeToNextMarkObject.getLayoutY() + dy);
legTimeObject.setLayoutX(legTimeObject.getLayoutX() + dx);
legTimeObject.setLayoutY(legTimeObject.getLayoutY() + dy);
wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutX(wake.getLayoutX() + dx);
wake.setLayoutY(wake.getLayoutY() + dy); wake.setLayoutY(wake.getLayoutY() + dy);
rotateTo(rotation + currentRotation); rotateTo(rotation + currentRotation);
@@ -127,6 +171,7 @@ public class BoatGroup extends RaceObject{
/** /**
* Moves the boat and its children annotations to coordinates specified * Moves the boat and its children annotations to coordinates specified
*
* @param x The X coordinate to move the boat to * @param x The X coordinate to move the boat to
* @param y The Y coordinate to move the boat to * @param y The Y coordinate to move the boat to
* @param rotation The heading in degrees from north the boat should rotate to. * @param rotation The heading in degrees from north the boat should rotate to.
@@ -138,6 +183,7 @@ public class BoatGroup extends RaceObject{
/** /**
* Moves the boat and its children annotations to coordinates specified * Moves the boat and its children annotations to coordinates specified
*
* @param x The X coordinate to move the boat to * @param x The X coordinate to move the boat to
* @param y The Y coordinate to move the boat to * @param y The Y coordinate to move the boat to
*/ */
@@ -148,6 +194,10 @@ public class BoatGroup extends RaceObject{
teamNameObject.setLayoutY(y); teamNameObject.setLayoutY(y);
velocityObject.setLayoutX(x); velocityObject.setLayoutX(x);
velocityObject.setLayoutY(y); velocityObject.setLayoutY(y);
estTimeToNextMarkObject.setLayoutX(x);
estTimeToNextMarkObject.setLayoutY(y);
legTimeObject.setLayoutX(x);
legTimeObject.setLayoutY(y);
wake.setLayoutX(x); wake.setLayoutX(x);
wake.setLayoutY(y); wake.setLayoutY(y);
wake.rotate(currentRotation); wake.rotate(currentRotation);
@@ -155,7 +205,9 @@ public class BoatGroup extends RaceObject{
/** /**
* Updates the position of all graphics in the BoatGroup based off of the given time interval. * Updates the position of all graphics in the BoatGroup based off of the given time interval.
* @param timeInterval The interval, in milliseconds, the boat should update it's position based on. *
* @param timeInterval The interval, in milliseconds, the boat should update it's position based
* on.
*/ */
public void updatePosition(long timeInterval) { public void updatePosition(long timeInterval) {
//Calculate the movement of the boat. //Calculate the movement of the boat.
@@ -189,18 +241,21 @@ public class BoatGroup extends RaceObject{
/** /**
* Sets the destination of the boat and the headng it should have once it reaches * Sets the destination of the boat and the headng it should have once it reaches
*
* @param newXValue The X co-ordinate the boat needs to move to. * @param newXValue The X co-ordinate the boat needs to move to.
* @param newYValue The Y co-ordinate the boat needs to move to. * @param newYValue The Y co-ordinate the boat needs to move to.
* @param rotation Rotation to move graphics to. * @param rotation Rotation to move graphics to.
* @param raceIds RaceID of the object to move. * @param raceIds RaceID of the object to move.
*/ */
public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, int... raceIds) { public void setDestination(double newXValue, double newYValue, double rotation,
double groundSpeed, int... raceIds) {
if (hasRaceId(raceIds)) { if (hasRaceId(raceIds)) {
if (setToInitialLocation) { if (setToInitialLocation) {
destinationSet = true; destinationSet = true;
boat.setVelocity(groundSpeed); boat.setVelocity(groundSpeed);
if (currentRotation < 0) if (currentRotation < 0) {
currentRotation = 360 - currentRotation; currentRotation = 360 - currentRotation;
}
double dx = newXValue - boatPoly.getLayoutX(); double dx = newXValue - boatPoly.getLayoutX();
double dy = newYValue - boatPoly.getLayoutY(); double dy = newYValue - boatPoly.getLayoutY();
//Check movement is reasonable. Assumes a 1000 * 1000 canvas //Check movement is reasonable. Assumes a 1000 * 1000 canvas
@@ -221,9 +276,23 @@ public class BoatGroup extends RaceObject{
rotationalVelocity = 0; rotationalVelocity = 0;
wakeGenerationDelay--; wakeGenerationDelay--;
} else { } else {
wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, boat.getVelocity()); wake.setRotationalVelocity(rotationalVelocity, rotationalGoal,
boat.getVelocity());
} }
velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); velocityObject.setText(String.format("%.2f m/s", boat.getVelocity()));
DateFormat format = new SimpleDateFormat("mm:ss");
// estimate time to next mark
String timeToNextMark = format
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark);
// elapsed time
if (boat.getMarkRoundingTime() != null) {
String elapsedTime = format
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
legTimeObject.setText("Last mark: " + elapsedTime);
} else {
legTimeObject.setText("Last mark: -");
}
} else { } else {
setToInitialLocation = true; setToInitialLocation = true;
rotationalGoal = rotation; rotationalGoal = rotation;
@@ -254,7 +323,8 @@ public class BoatGroup extends RaceObject{
} }
} }
public void setDestination (double newXValue, double newYValue, double groundSpeed, int... raceIDs) { public void setDestination(double newXValue, double newYValue, double groundSpeed,
int... raceIDs) {
destinationSet = true; destinationSet = true;
if (hasRaceId(raceIDs)) { if (hasRaceId(raceIDs)) {
@@ -287,6 +357,14 @@ public class BoatGroup extends RaceObject{
velocityObject.setVisible(visible); velocityObject.setVisible(visible);
} }
public void setEstTimeToNextMarkObjectVisible(Boolean visible) {
estTimeToNextMarkObject.setVisible(visible);
}
public void setLegTimeObjectVisible(Boolean visible) {
legTimeObject.setVisible(visible);
}
public void setLineGroupVisible(Boolean visible) { public void setLineGroupVisible(Boolean visible) {
lineGroup.setVisible(visible); lineGroup.setVisible(visible);
} }
@@ -307,9 +385,10 @@ public class BoatGroup extends RaceObject{
*/ */
public boolean hasRaceId(int... raceIds) { public boolean hasRaceId(int... raceIds) {
for (int id : raceIds) { for (int id : raceIds) {
if (id == boat.getSourceID()) if (id == boat.getSourceID()) {
return true; return true;
} }
}
return false; return false;
} }
@@ -323,9 +402,9 @@ public class BoatGroup extends RaceObject{
} }
/** /**
* Due to javaFX limitations annotations associated with a boat that you want to appear below all boats in the * Due to javaFX limitations annotations associated with a boat that you want to appear below
* Z-axis need to be pulled out of the BoatGroup and added to the parent group of the BoatGroups. This function * all boats in the Z-axis need to be pulled out of the BoatGroup and added to the parent group
* returns these annotations as a group. * of the BoatGroups. This function returns these annotations as a group.
* *
* @return A group containing low priority annotations. * @return A group containing low priority annotations.
*/ */
@@ -336,9 +415,10 @@ public class BoatGroup extends RaceObject{
} }
/** /**
* Use this function to let the BoatGroup know about the stage it is in. If it knows about it's stage then it will * Use this function to let the BoatGroup know about the stage it is in. If it knows about it's
* listen to the iconified property of that stage and change it's behaviour upon minimization. Without setting the * stage then it will listen to the iconified property of that stage and change it's behaviour
* Stage there is guarantee that the BoatGroup will draw properly when the stage is minimized. * upon minimization. Without setting the Stage there is guarantee that the BoatGroup will draw
* properly when the stage is minimized.
* *
* @param stage The stage that the BoatGroup is added to. * @param stage The stage that the BoatGroup is added to.
*/ */
+7 -5
View File
@@ -12,9 +12,9 @@ import java.text.SimpleDateFormat;
* also done outside Boat class because some old variables are not used anymore. * also done outside Boat class because some old variables are not used anymore.
*/ */
public class Yacht { public class Yacht {
// Used in boat group
private Color colour; private Color colour;
private double velocity; private double velocity;
private Integer markLastPast;
private String boatType; private String boatType;
private Integer sourceID; private Integer sourceID;
@@ -30,6 +30,8 @@ public class Yacht {
private Long estimateTimeAtNextMark; private Long estimateTimeAtNextMark;
private Long estimateTimeAtFinish; private Long estimateTimeAtFinish;
private String position; private String position;
// Mark rounding
private Long markRoundingTime;
/** /**
* Used in EventTest and RaceTest. * Used in EventTest and RaceTest.
@@ -157,11 +159,11 @@ public class Yacht {
this.velocity = velocity; this.velocity = velocity;
} }
public Integer getMarkLastPast() { public Long getMarkRoundingTime() {
return markLastPast; return markRoundingTime;
} }
public void setMarkLastPast(Integer markLastPast) { public void setMarkRoundingTime(Long markRoundingTime) {
this.markLastPast = markLastPast; this.markRoundingTime = markRoundingTime;
} }
} }
@@ -40,6 +40,7 @@ public class StreamParser extends Thread{
private static Map<Integer, Yacht> boats = new HashMap<>(); private static Map<Integer, Yacht> boats = new HashMap<>();
private static Map<Long, Yacht> boatsPos = new TreeMap<>(); private static Map<Long, Yacht> boatsPos = new TreeMap<>();
private static double windDirection = 0; private static double windDirection = 0;
private static Long currentTimeLong;
private static String currentTimeString; private static String currentTimeString;
private static boolean appRunning; private static boolean appRunning;
@@ -199,9 +200,11 @@ public class StreamParser extends Thread{
long currentTime = bytesToLong(Arrays.copyOfRange(payload,1,7)); long currentTime = bytesToLong(Arrays.copyOfRange(payload,1,7));
long raceId = bytesToLong(Arrays.copyOfRange(payload,7,11)); long raceId = bytesToLong(Arrays.copyOfRange(payload,7,11));
int raceStatus = payload[11]; int raceStatus = payload[11];
// System.out.println("raceStatus = " + raceStatus);
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18)); long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18));
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22));
currentTimeLong = currentTime;
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
if (xmlObject.getRegattaXML() != null) { if (xmlObject.getRegattaXML() != null) {
format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString())); format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString()));
@@ -209,7 +212,6 @@ public class StreamParser extends Thread{
} }
long timeTillStart = ((new Date (expectedStartTime)).getTime() - (new Date (currentTime)).getTime())/1000; long timeTillStart = ((new Date (expectedStartTime)).getTime() - (new Date (currentTime)).getTime())/1000;
if (timeTillStart > 0) { if (timeTillStart > 0) {
timeSinceStart = timeTillStart; timeSinceStart = timeTillStart;
//System.out.println("Time till start: " + timeTillStart + " Seconds"); //System.out.println("Time till start: " + timeTillStart + " Seconds");
@@ -226,10 +228,10 @@ public class StreamParser extends Thread{
//System.out.println("Time since start: " + -1 * timeTillStart + " Seconds"); //System.out.println("Time since start: " + -1 * timeTillStart + " Seconds");
timeSinceStart = timeTillStart; timeSinceStart = timeTillStart;
} }
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
double windDirFactor = 0x4000 / 90; //0x4000 is 90 degrees, 0x8000 is 180 degrees, etc... double windDirFactor = 0x4000 / 90; //0x4000 is 90 degrees, 0x8000 is 180 degrees, etc...
windDirection = windDir / windDirFactor; windDirection = windDir / windDirFactor;
long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22));
int noBoats = payload[22]; int noBoats = payload[22];
int raceType = payload[23]; int raceType = payload[23];
// ArrayList<String> boatStatuses = new ArrayList<>(); // ArrayList<String> boatStatuses = new ArrayList<>();
@@ -239,11 +241,11 @@ public class StreamParser extends Thread{
Yacht boat = boats.get((int)(long) boatStatusSourceID); Yacht boat = boats.get((int)(long) boatStatusSourceID);
boat.setBoatStatus((int)payload[28 + (i * 20)]); boat.setBoatStatus((int)payload[28 + (i * 20)]);
boat.setLegNumber((int)payload[29 + (i * 20)]); boat.setLegNumber((int)payload[29 + (i * 20)]);
boat.setPenaltiesAwarded((int)payload[29 + (i * 20)]); boat.setPenaltiesAwarded((int)payload[30 + (i * 20)]);
boat.setPenaltiesServed((int)payload[30 + (i * 20)]); boat.setPenaltiesServed((int)payload[31 + (i * 20)]);
Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,31 + (i * 20),37+ (i * 20))); Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,32 + (i * 20),38+ (i * 20)));
boat.setEstimateTimeAtNextMark(estTimeAtNextMark); boat.setEstimateTimeAtNextMark(estTimeAtNextMark);
Long estTimeAtFinish = bytesToLong(Arrays.copyOfRange(payload,37 + (i * 20),43+ (i * 20))); Long estTimeAtFinish = bytesToLong(Arrays.copyOfRange(payload,38 + (i * 20),44+ (i * 20)));
boat.setEstimateTimeAtFinish(estTimeAtFinish); boat.setEstimateTimeAtFinish(estTimeAtFinish);
boatsPos.put(estTimeAtFinish, boat); boatsPos.put(estTimeAtFinish, boat);
// String boatStatus = "SourceID: " + boatStatusSourceID; // String boatStatus = "SourceID: " + boatStatusSourceID;
@@ -434,6 +436,9 @@ public class StreamParser extends Thread{
int roundingSide = payload[18]; int roundingSide = payload[18];
int markType = payload[19]; int markType = payload[19];
int markId = payload[20]; int markId = payload[20];
// assign mark rounding time to boat
boats.get((int)subjectId).setMarkRoundingTime(timeStamp);
} }
/** /**
@@ -580,6 +585,15 @@ public class StreamParser extends Thread{
return boatsPos; return boatsPos;
} }
/**
* returns current time in stream in long
*
* @return a long value of current time
*/
public static Long getCurrentTimeLong() {
return currentTimeLong;
}
public static void appClose(){ public static void appClose(){
appRunning = false; appRunning = false;
System.out.println("[CLIENT] Shutting down stream parser"); System.out.println("[CLIENT] Shutting down stream parser");
@@ -5,7 +5,7 @@
<?import java.lang.*?> <?import java.lang.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<AnchorPane fx:id="annotationSelectWindow" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="248.0" prefWidth="469.0" styleClass="background-blue" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <AnchorPane fx:id="annotationSelectWindow" maxHeight="270.0" maxWidth="469.0" minHeight="270.0" minWidth="469.0" prefHeight="270.0" prefWidth="469.0" styleClass="background-blue" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children> <children>
<Text fill="WHITE" layoutX="26.0" layoutY="52.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Select important annotations"> <Text fill="WHITE" layoutX="26.0" layoutY="52.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Select important annotations">
<font> <font>
@@ -15,7 +15,8 @@
<CheckBox fx:id="boatWakeSelect" layoutX="26.0" layoutY="80.0" mnemonicParsing="false" style="-fx-border-width: 0; -fx-background-insets: 0;" text="Boat Wakes" textFill="#e7e7e7" /> <CheckBox fx:id="boatWakeSelect" layoutX="26.0" layoutY="80.0" mnemonicParsing="false" style="-fx-border-width: 0; -fx-background-insets: 0;" text="Boat Wakes" textFill="#e7e7e7" />
<CheckBox fx:id="boatSpeedSelect" layoutX="26.0" layoutY="111.0" mnemonicParsing="false" text="Boat Speed" textFill="#e7e7e7" /> <CheckBox fx:id="boatSpeedSelect" layoutX="26.0" layoutY="111.0" mnemonicParsing="false" text="Boat Speed" textFill="#e7e7e7" />
<CheckBox fx:id="boatTrackSelect" layoutX="26.0" layoutY="142.0" mnemonicParsing="false" text="Boat Tracks" textFill="#e7e7e7" /> <CheckBox fx:id="boatTrackSelect" layoutX="26.0" layoutY="142.0" mnemonicParsing="false" text="Boat Tracks" textFill="#e7e7e7" />
<CheckBox fx:id="boatNameSelect" layoutX="26.0" layoutY="175.0" mnemonicParsing="false" text="Boat Name" textFill="#e7e7e7" /> <CheckBox fx:id="boatNameSelect" layoutX="26.0" layoutY="173.0" mnemonicParsing="false" text="Boat Name" textFill="#e7e7e7" />
<CheckBox fx:id="boatEstTimeToNextMarkSelect" layoutX="26.0" layoutY="204.0" mnemonicParsing="false" text="Boat Estimated Time To Next Mark" textFill="#e7e7e7" />
<Button fx:id="closeButton" layoutX="424.0" layoutY="-1.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="49.0" style=": 0;" text="X" textFill="#ffffff4e"> <Button fx:id="closeButton" layoutX="424.0" layoutY="-1.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="49.0" style=": 0;" text="X" textFill="#ffffff4e">
<font> <font>
<Font size="24.0" /> <Font size="24.0" />
@@ -25,5 +26,6 @@
<String fx:value="clearExitButton" /> <String fx:value="clearExitButton" />
</styleClass> </styleClass>
</Button> </Button>
<CheckBox fx:id="boatElapsedTimeSelect" layoutX="26.0" layoutY="235.0" mnemonicParsing="false" text="Boat Elapsed Time Since Last Mark" textFill="#e7e7e7" />
</children> </children>
</AnchorPane> </AnchorPane>