mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge branch '38a_Select_Boats' into 'develop'
38a select boats Selection of boats now possible by selecting a boat from a drop down menu to focus that boat singularly or clicking a boat on the canvas to toggle that boats annotations. Changed the annotations slider to remove the low annotation option. Only now includes None, Important and All. I think this makes much more sense. Refactor of the race view controller class to combine all timelines for polling the Stream Parser to update race view data such as tables into one timeline for polling. In the future this should be improved further from polling to an observer model. See merge request !31
This commit is contained in:
@@ -62,7 +62,8 @@ public class App extends Application {
|
|||||||
}
|
}
|
||||||
//Change the StreamReceiver in this else block to change the default data source.
|
//Change the StreamReceiver in this else block to change the default data source.
|
||||||
else{
|
else{
|
||||||
sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
// sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
||||||
|
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
||||||
}
|
}
|
||||||
|
|
||||||
sr.start();
|
sr.start();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class RaceController {
|
|||||||
String teamsConfigFile = "/config/teams.xml";
|
String teamsConfigFile = "/config/teams.xml";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
race = createRace(raceConfigFile, teamsConfigFile);
|
race = createRace(raceConfigFile, teamsConfigFile); //These config files arent actually used
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("There was an error creating the race.");
|
System.out.println("There was an error creating the race.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package seng302.controllers;
|
|||||||
|
|
||||||
import javafx.animation.KeyFrame;
|
import javafx.animation.KeyFrame;
|
||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Slider;
|
import javafx.scene.control.Slider;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
@@ -50,6 +51,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
@FXML
|
@FXML
|
||||||
private Button selectAnnotationBtn;
|
private Button selectAnnotationBtn;
|
||||||
@FXML
|
@FXML
|
||||||
|
private ComboBox boatSelectionComboBox;
|
||||||
|
@FXML
|
||||||
private CanvasController includedCanvasController;
|
private CanvasController includedCanvasController;
|
||||||
|
|
||||||
private ArrayList<Yacht> startingBoats = new ArrayList<>();
|
private ArrayList<Yacht> startingBoats = new ArrayList<>();
|
||||||
@@ -57,26 +60,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private Timeline timerTimeline;
|
private Timeline timerTimeline;
|
||||||
private Race race;
|
private Race race;
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
|
|
||||||
private ImportantAnnotationsState importantAnnotations;
|
private ImportantAnnotationsState importantAnnotations;
|
||||||
|
private Yacht selectedBoat;
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
// Load a default important annotation state
|
// Load a default important annotation state
|
||||||
importantAnnotations = new ImportantAnnotationsState();
|
importantAnnotations = new ImportantAnnotationsState();
|
||||||
|
|
||||||
|
//Initialise race controller
|
||||||
RaceController raceController = new RaceController();
|
RaceController raceController = new RaceController();
|
||||||
raceController.initializeRace();
|
raceController.initializeRace();
|
||||||
race = raceController.getRace();
|
race = raceController.getRace();
|
||||||
|
|
||||||
for (Yacht boat : race.getBoats()) {
|
startingBoats = new ArrayList<>(Arrays.asList(race.getBoats()));
|
||||||
startingBoats.add(boat);
|
|
||||||
}
|
|
||||||
|
|
||||||
includedCanvasController.setup(this);
|
includedCanvasController.setup(this);
|
||||||
includedCanvasController.initializeCanvas();
|
includedCanvasController.initializeCanvas();
|
||||||
initializeTimer();
|
initializeUpdateTimer();
|
||||||
initializeSettings();
|
initialiseFPSCheckBox();
|
||||||
initialiseWindDirection();
|
initialiseAnnotationSlider();
|
||||||
initialisePositionVBox();
|
initialiseBoatSelectionComboBox();
|
||||||
includedCanvasController.timer.start();
|
includedCanvasController.timer.start();
|
||||||
|
|
||||||
selectAnnotationBtn.setOnAction(event -> {
|
selectAnnotationBtn.setOnAction(event -> {
|
||||||
@@ -86,7 +90,6 @@ 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) {
|
||||||
@@ -110,7 +113,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
// Load FXML and set CSS
|
// Load FXML and set CSS
|
||||||
fxmlLoader
|
fxmlLoader
|
||||||
.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
|
.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
|
||||||
Scene scene = new Scene(fxmlLoader.load(), 469, 270);
|
Scene scene = new Scene(fxmlLoader.load(), 469, 248);
|
||||||
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);
|
||||||
|
|
||||||
@@ -124,18 +127,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSettings() {
|
|
||||||
|
private void initialiseFPSCheckBox() {
|
||||||
displayFps = true;
|
displayFps = true;
|
||||||
|
toggleFps.selectedProperty().addListener(
|
||||||
|
(observable, oldValue, newValue) -> displayFps = !displayFps);
|
||||||
|
}
|
||||||
|
|
||||||
toggleFps.selectedProperty().addListener(new ChangeListener<Boolean>() {
|
private void initialiseAnnotationSlider() {
|
||||||
@Override
|
|
||||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
|
|
||||||
Boolean newValue) {
|
|
||||||
displayFps = !displayFps;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//SLIDER STUFF BELOW
|
|
||||||
annotationSlider.setLabelFormatter(new StringConverter<Double>() {
|
annotationSlider.setLabelFormatter(new StringConverter<Double>() {
|
||||||
@Override
|
@Override
|
||||||
public String toString(Double n) {
|
public String toString(Double n) {
|
||||||
@@ -143,12 +142,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
return "None";
|
return "None";
|
||||||
}
|
}
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
return "Low";
|
|
||||||
}
|
|
||||||
if (n == 2) {
|
|
||||||
return "Important";
|
return "Important";
|
||||||
}
|
}
|
||||||
if (n == 3) {
|
if (n == 2) {
|
||||||
return "All";
|
return "All";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,15 +156,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
switch (s) {
|
switch (s) {
|
||||||
case "None":
|
case "None":
|
||||||
return 0d;
|
return 0d;
|
||||||
case "Low":
|
|
||||||
return 1d;
|
|
||||||
case "Important":
|
case "Important":
|
||||||
return 2d;
|
return 1d;
|
||||||
case "All":
|
case "All":
|
||||||
return 3d;
|
return 2d;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 3d;
|
return 2d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -176,22 +170,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
annotationSlider.valueProperty().addListener((obs, oldval, newVal) ->
|
annotationSlider.valueProperty().addListener((obs, oldval, newVal) ->
|
||||||
setAnnotations((int) annotationSlider.getValue()));
|
setAnnotations((int) annotationSlider.getValue()));
|
||||||
|
|
||||||
annotationSlider.setValue(3);
|
annotationSlider.setValue(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTimer() {
|
|
||||||
|
/**
|
||||||
|
* Initalises a timer which updates elements of the RaceView such as wind direction, boat
|
||||||
|
* orderings etc.. which are dependent on the info from the stream parser constantly.
|
||||||
|
* Updates of each of these attributes are called ONCE EACH SECOND
|
||||||
|
*/
|
||||||
|
private void initializeUpdateTimer() {
|
||||||
timerTimeline = new Timeline();
|
timerTimeline = new Timeline();
|
||||||
timerTimeline.setCycleCount(Timeline.INDEFINITE);
|
timerTimeline.setCycleCount(Timeline.INDEFINITE);
|
||||||
// Run timer update every second
|
// Run timer update every second
|
||||||
timerTimeline.getKeyFrames().add(
|
timerTimeline.getKeyFrames().add(
|
||||||
new KeyFrame(Duration.seconds(1),
|
new KeyFrame(Duration.seconds(1),
|
||||||
event -> {
|
event -> {
|
||||||
if (StreamParser.isRaceFinished()) {
|
updateRaceTime();
|
||||||
timerLabel.setFill(Color.RED);
|
updateWindDirection();
|
||||||
timerLabel.setText("Race Finished!");
|
updateOrder();
|
||||||
} else {
|
updateBoatSelectionComboBox();
|
||||||
timerLabel.setText(currentTimer());
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -199,54 +198,45 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
timerTimeline.playFromStart();
|
timerTimeline.playFromStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialiseWindDirection() {
|
|
||||||
Timeline windDirTimeline = new Timeline();
|
|
||||||
windDirTimeline.setCycleCount(Timeline.INDEFINITE);
|
|
||||||
windDirTimeline.getKeyFrames().add(
|
|
||||||
new KeyFrame(Duration.seconds(1),
|
|
||||||
event -> {
|
|
||||||
windDirectionText
|
|
||||||
.setText(String.format("%.1f°", StreamParser.getWindDirection()));
|
|
||||||
windArrowText.setRotate(StreamParser.getWindDirection());
|
|
||||||
})
|
|
||||||
);
|
|
||||||
windDirTimeline.playFromStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialisePositionVBox() {
|
|
||||||
|
|
||||||
Timeline posVBoxTimeline = new Timeline();
|
|
||||||
posVBoxTimeline.setCycleCount(Timeline.INDEFINITE);
|
|
||||||
posVBoxTimeline.getKeyFrames().add(
|
|
||||||
new KeyFrame(Duration.seconds(1),
|
|
||||||
event -> {
|
|
||||||
showOrder();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
posVBoxTimeline.playFromStart();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the list of boats in the order they finished the race
|
* Updates the wind direction arrow and text as from info from the StreamParser
|
||||||
*/
|
*/
|
||||||
private void loadRaceResultView() {
|
private void updateWindDirection() {
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
|
windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection()));
|
||||||
loader.setController(new RaceResultController(race));
|
windArrowText.setRotate(StreamParser.getWindDirection());
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
contentAnchorPane.getChildren().removeAll();
|
|
||||||
contentAnchorPane.getChildren().clear();
|
|
||||||
contentAnchorPane.getChildren().addAll((Pane) loader.load());
|
|
||||||
|
|
||||||
} catch (javafx.fxml.LoadException e) {
|
/**
|
||||||
System.err.println(e.getCause());
|
* Updates the clock for the race
|
||||||
} catch (IOException e) {
|
*/
|
||||||
System.err.println(e);
|
private void updateRaceTime() {
|
||||||
|
if (StreamParser.isRaceFinished()) {
|
||||||
|
timerLabel.setFill(Color.RED);
|
||||||
|
timerLabel.setText("Race Finished!");
|
||||||
|
} else {
|
||||||
|
timerLabel.setText(getTimeSinceStartOfRace());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showOrder() {
|
|
||||||
|
/**
|
||||||
|
* Grabs the boats currently in the race as from the StreamParser and sets them to be selectable
|
||||||
|
* in the boat selection combo box
|
||||||
|
*/
|
||||||
|
private void updateBoatSelectionComboBox() {
|
||||||
|
ObservableList<Yacht> observableBoats = FXCollections
|
||||||
|
.observableArrayList(StreamParser.getBoatsPos().values());
|
||||||
|
boatSelectionComboBox.setItems(observableBoats);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the order of the boats as from the StreamParser and sets them in the boat order
|
||||||
|
* section
|
||||||
|
*/
|
||||||
|
private void updateOrder() {
|
||||||
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());
|
||||||
@@ -269,6 +259,44 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialised the combo box with any boats currently in the race and adds the required listener
|
||||||
|
* for the combobox to take action upon selection
|
||||||
|
*/
|
||||||
|
private void initialiseBoatSelectionComboBox() {
|
||||||
|
updateBoatSelectionComboBox();
|
||||||
|
boatSelectionComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
//This listener is fired whenever the combo box changes. This means when the values are updated
|
||||||
|
//We dont want to set the selected value if the values are updated but nothing clicked (null)
|
||||||
|
if (newValue != null && newValue != selectedBoat) {
|
||||||
|
Yacht thisYacht = (Yacht) newValue;
|
||||||
|
setSelectedBoat(thisYacht);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the list of boats in the order they finished the race
|
||||||
|
*/
|
||||||
|
private void loadRaceResultView() {
|
||||||
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert seconds to a string of the format mm:ss
|
* Convert seconds to a string of the format mm:ss
|
||||||
*
|
*
|
||||||
@@ -282,7 +310,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
return String.format("%02d:%02d", time / 60, time % 60);
|
return String.format("%02d:%02d", time / 60, time % 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String currentTimer() {
|
private String getTimeSinceStartOfRace() {
|
||||||
String timerString = "0:00";
|
String timerString = "0:00";
|
||||||
if (StreamParser.getTimeSinceStart() > 0) {
|
if (StreamParser.getTimeSinceStart() > 0) {
|
||||||
String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60);
|
String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60);
|
||||||
@@ -302,13 +330,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
return timerString;
|
return timerString;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopTimer() {
|
|
||||||
timerTimeline.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startTimer() {
|
|
||||||
timerTimeline.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisplayFps() {
|
public boolean isDisplayFps() {
|
||||||
return displayFps;
|
return displayFps;
|
||||||
@@ -318,13 +339,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
return race;
|
return race;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Yacht> getStartingBoats() {
|
|
||||||
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) {
|
||||||
@@ -381,22 +398,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Low Annotations
|
|
||||||
case 1:
|
|
||||||
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
|
||||||
if (ro instanceof BoatGroup) {
|
|
||||||
BoatGroup bg = (BoatGroup) ro;
|
|
||||||
bg.setTeamNameObjectVisible(true);
|
|
||||||
bg.setVelocityObjectVisible(false);
|
|
||||||
bg.setEstTimeToNextMarkObjectVisible(false);
|
|
||||||
bg.setLegTimeObjectVisible(false);
|
|
||||||
bg.setLineGroupVisible(false);
|
|
||||||
bg.setWakeVisible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Important Annotations
|
// Important Annotations
|
||||||
case 2:
|
case 1:
|
||||||
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
||||||
if (ro instanceof BoatGroup) {
|
if (ro instanceof BoatGroup) {
|
||||||
BoatGroup bg = (BoatGroup) ro;
|
BoatGroup bg = (BoatGroup) ro;
|
||||||
@@ -405,7 +408,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// All Annotations
|
// All Annotations
|
||||||
case 3:
|
case 2:
|
||||||
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
||||||
if (ro instanceof BoatGroup) {
|
if (ro instanceof BoatGroup) {
|
||||||
BoatGroup bg = (BoatGroup) ro;
|
BoatGroup bg = (BoatGroup) ro;
|
||||||
@@ -421,6 +424,28 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets all the annotations of the selected boat to be visible and all others to be hidden
|
||||||
|
*
|
||||||
|
* @param yacht The yacht for which we want to view all annotations
|
||||||
|
*/
|
||||||
|
private void setSelectedBoat(Yacht yacht) {
|
||||||
|
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
||||||
|
if (ro instanceof BoatGroup) {
|
||||||
|
BoatGroup bg = (BoatGroup) ro;
|
||||||
|
//We need to iterate over all race groups to get the matching boat group belonging to this boat if we
|
||||||
|
//are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup.
|
||||||
|
if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
|
||||||
|
bg.setIsSelected(true);
|
||||||
|
selectedBoat = yacht;
|
||||||
|
} else {
|
||||||
|
bg.setIsSelected(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setStage(Stage stage) {
|
void setStage(Stage stage) {
|
||||||
this.stage = stage;
|
this.stage = stage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ public class BoatGroup extends RaceObject {
|
|||||||
private Text estTimeToNextMarkObject;
|
private Text estTimeToNextMarkObject;
|
||||||
private Text legTimeObject;
|
private Text legTimeObject;
|
||||||
private Wake wake;
|
private Wake wake;
|
||||||
|
private boolean isSelected = true; //Boats annotations are visible by default at the start
|
||||||
//Handles boat moving when connecting to a stream
|
//Handles boat moving when connecting to a stream
|
||||||
private boolean setToInitialLocation = false;
|
private boolean setToInitialLocation = false;
|
||||||
private boolean destinationSet;
|
private boolean destinationSet;
|
||||||
@@ -61,8 +62,8 @@ 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
|
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
|
||||||
* to tell which BoatGroup to update.
|
* 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) {
|
||||||
@@ -74,11 +75,11 @@ public class BoatGroup extends RaceObject {
|
|||||||
* Creates a BoatGroup with the boat being the default polygon. The head of the boat should be
|
* Creates a BoatGroup with the boat being the default polygon. The head of the boat should be
|
||||||
* at point (0,0).
|
* at point (0,0).
|
||||||
*
|
*
|
||||||
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
|
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
|
||||||
* to tell which BoatGroup to update.
|
* 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
|
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
|
||||||
* polygon.
|
* polygon.
|
||||||
*/
|
*/
|
||||||
public BoatGroup(Yacht boat, Color color, double... points) {
|
public BoatGroup(Yacht boat, Color color, double... points) {
|
||||||
this.boat = boat;
|
this.boat = boat;
|
||||||
@@ -88,23 +89,26 @@ public class BoatGroup extends RaceObject {
|
|||||||
/**
|
/**
|
||||||
* 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
|
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
|
||||||
* polygon.
|
* polygon.
|
||||||
*/
|
*/
|
||||||
private void initChildren(Color color, double... points) {
|
private void initChildren(Color color, double... points) {
|
||||||
boatPoly = new Polygon(points);
|
boatPoly = new Polygon(points);
|
||||||
boatPoly.setFill(color);
|
boatPoly.setFill(color);
|
||||||
|
boatPoly.setOnMouseEntered(event -> boatPoly.setFill(Color.FLORALWHITE));
|
||||||
|
boatPoly.setOnMouseExited(event -> boatPoly.setFill(color));
|
||||||
|
boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected));
|
||||||
|
|
||||||
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");
|
DateFormat format = new SimpleDateFormat("mm:ss");
|
||||||
String timeToNextMark = format
|
String timeToNextMark = format
|
||||||
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
|
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
|
||||||
estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark);
|
estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark);
|
||||||
if (boat.getMarkRoundingTime() != null) {
|
if (boat.getMarkRoundingTime() != null) {
|
||||||
String elapsedTime = format
|
String elapsedTime = format
|
||||||
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
|
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
|
||||||
legTimeObject = new Text("Last mark: " + elapsedTime);
|
legTimeObject = new Text("Last mark: " + elapsedTime);
|
||||||
} else {
|
} else {
|
||||||
legTimeObject = new Text("Last mark: -");
|
legTimeObject = new Text("Last mark: -");
|
||||||
@@ -122,7 +126,7 @@ public class BoatGroup extends RaceObject {
|
|||||||
estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET);
|
estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET);
|
||||||
estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET);
|
estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET);
|
||||||
estTimeToNextMarkObject
|
estTimeToNextMarkObject
|
||||||
.relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY());
|
.relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY());
|
||||||
|
|
||||||
legTimeObject.setX(LEGTIME_X_OFFSET);
|
legTimeObject.setX(LEGTIME_X_OFFSET);
|
||||||
legTimeObject.setY(LEGTIME_Y_OFFSET);
|
legTimeObject.setY(LEGTIME_Y_OFFSET);
|
||||||
@@ -130,8 +134,8 @@ public class BoatGroup extends RaceObject {
|
|||||||
|
|
||||||
wake = new Wake(0, -BOAT_HEIGHT);
|
wake = new Wake(0, -BOAT_HEIGHT);
|
||||||
super.getChildren()
|
super.getChildren()
|
||||||
.addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject,
|
.addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject,
|
||||||
legTimeObject);
|
legTimeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,9 +145,9 @@ public class BoatGroup extends RaceObject {
|
|||||||
*/
|
*/
|
||||||
private void initChildren(Color color) {
|
private void initChildren(Color color) {
|
||||||
initChildren(color,
|
initChildren(color,
|
||||||
-BOAT_WIDTH / 2, BOAT_HEIGHT / 2,
|
-BOAT_WIDTH / 2, BOAT_HEIGHT / 2,
|
||||||
0.0, -BOAT_HEIGHT / 2,
|
0.0, -BOAT_HEIGHT / 2,
|
||||||
BOAT_WIDTH / 2, BOAT_HEIGHT / 2);
|
BOAT_WIDTH / 2, BOAT_HEIGHT / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -172,8 +176,8 @@ 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.
|
||||||
*/
|
*/
|
||||||
public void moveTo(double x, double y, double rotation) {
|
public void moveTo(double x, double y, double rotation) {
|
||||||
@@ -207,7 +211,7 @@ 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
|
* @param timeInterval The interval, in milliseconds, the boat should update it's position based
|
||||||
* on.
|
* on.
|
||||||
*/
|
*/
|
||||||
public void updatePosition(long timeInterval) {
|
public void updatePosition(long timeInterval) {
|
||||||
//Calculate the movement of the boat.
|
//Calculate the movement of the boat.
|
||||||
@@ -222,13 +226,13 @@ public class BoatGroup extends RaceObject {
|
|||||||
distanceTravelled = 0;
|
distanceTravelled = 0;
|
||||||
if (lastPoint != null) {
|
if (lastPoint != null) {
|
||||||
Line l = new Line(
|
Line l = new Line(
|
||||||
lastPoint.getX(),
|
lastPoint.getX(),
|
||||||
lastPoint.getY(),
|
lastPoint.getY(),
|
||||||
boatPoly.getLayoutX(),
|
boatPoly.getLayoutX(),
|
||||||
boatPoly.getLayoutY()
|
boatPoly.getLayoutY()
|
||||||
);
|
);
|
||||||
l.getStrokeDashArray().setAll(3d, 7d);
|
l.getStrokeDashArray().setAll(3d, 7d);
|
||||||
l.setStroke(boatPoly.getFill());
|
l.setStroke(boat.getColour());
|
||||||
lineGroup.getChildren().add(l);
|
lineGroup.getChildren().add(l);
|
||||||
}
|
}
|
||||||
if (destinationSet) { //Only begin drawing after the first destination is set
|
if (destinationSet) { //Only begin drawing after the first destination is set
|
||||||
@@ -244,11 +248,11 @@ public class BoatGroup extends RaceObject {
|
|||||||
*
|
*
|
||||||
* @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,
|
public void setDestination(double newXValue, double newYValue, double rotation,
|
||||||
double groundSpeed, int... raceIds) {
|
double groundSpeed, int... raceIds) {
|
||||||
if (hasRaceId(raceIds)) {
|
if (hasRaceId(raceIds)) {
|
||||||
if (setToInitialLocation) {
|
if (setToInitialLocation) {
|
||||||
destinationSet = true;
|
destinationSet = true;
|
||||||
@@ -277,18 +281,18 @@ public class BoatGroup extends RaceObject {
|
|||||||
wakeGenerationDelay--;
|
wakeGenerationDelay--;
|
||||||
} else {
|
} else {
|
||||||
wake.setRotationalVelocity(rotationalVelocity, rotationalGoal,
|
wake.setRotationalVelocity(rotationalVelocity, rotationalGoal,
|
||||||
boat.getVelocity());
|
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");
|
DateFormat format = new SimpleDateFormat("mm:ss");
|
||||||
// estimate time to next mark
|
// estimate time to next mark
|
||||||
String timeToNextMark = format
|
String timeToNextMark = format
|
||||||
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
|
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
|
||||||
estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark);
|
estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark);
|
||||||
// elapsed time
|
// elapsed time
|
||||||
if (boat.getMarkRoundingTime() != null) {
|
if (boat.getMarkRoundingTime() != null) {
|
||||||
String elapsedTime = format
|
String elapsedTime = format
|
||||||
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
|
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
|
||||||
legTimeObject.setText("Last mark: " + elapsedTime);
|
legTimeObject.setText("Last mark: " + elapsedTime);
|
||||||
} else {
|
} else {
|
||||||
legTimeObject.setText("Last mark: -");
|
legTimeObject.setText("Last mark: -");
|
||||||
@@ -307,10 +311,10 @@ public class BoatGroup extends RaceObject {
|
|||||||
setCallCount = 5;
|
setCallCount = 5;
|
||||||
if (lastPoint != null) {
|
if (lastPoint != null) {
|
||||||
Line l = new Line(
|
Line l = new Line(
|
||||||
lastPoint.getX(),
|
lastPoint.getX(),
|
||||||
lastPoint.getY(),
|
lastPoint.getY(),
|
||||||
newXValue,
|
newXValue,
|
||||||
newYValue
|
newYValue
|
||||||
);
|
);
|
||||||
l.getStrokeDashArray().setAll(3d, 7d);
|
l.getStrokeDashArray().setAll(3d, 7d);
|
||||||
l.setStroke(boatPoly.getFill());
|
l.setStroke(boatPoly.getFill());
|
||||||
@@ -324,16 +328,16 @@ public class BoatGroup extends RaceObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setDestination(double newXValue, double newYValue, double groundSpeed,
|
public void setDestination(double newXValue, double newYValue, double groundSpeed,
|
||||||
int... raceIDs) {
|
int... raceIDs) {
|
||||||
destinationSet = true;
|
destinationSet = true;
|
||||||
|
|
||||||
if (hasRaceId(raceIDs)) {
|
if (hasRaceId(raceIDs)) {
|
||||||
double rotation = Math.abs(
|
double rotation = Math.abs(
|
||||||
Math.toDegrees(
|
Math.toDegrees(
|
||||||
Math.atan(
|
Math.atan(
|
||||||
(newYValue - boatPoly.getLayoutY()) / (newXValue - boatPoly.getLayoutX())
|
(newYValue - boatPoly.getLayoutY()) / (newXValue - boatPoly.getLayoutX())
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
);
|
);
|
||||||
setDestination(newXValue, newYValue, rotation, groundSpeed, raceIDs);
|
setDestination(newXValue, newYValue, rotation, groundSpeed, raceIDs);
|
||||||
}
|
}
|
||||||
@@ -349,6 +353,10 @@ public class BoatGroup extends RaceObject {
|
|||||||
wake.rotate(rotationalGoal);
|
wake.rotate(rotationalGoal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void paintBoat(Color color) {
|
||||||
|
boatPoly.setFill(color);
|
||||||
|
}
|
||||||
|
|
||||||
public void setTeamNameObjectVisible(Boolean visible) {
|
public void setTeamNameObjectVisible(Boolean visible) {
|
||||||
teamNameObject.setVisible(visible);
|
teamNameObject.setVisible(visible);
|
||||||
}
|
}
|
||||||
@@ -377,6 +385,24 @@ public class BoatGroup extends RaceObject {
|
|||||||
return boat;
|
return boat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function sets the boats isSelected property AS WELL as actually acting upon the value of
|
||||||
|
* that selection. (Painting or not painting annotations)
|
||||||
|
*
|
||||||
|
* @param isSelected A Boolean indicating whether or not the boat is selected
|
||||||
|
*/
|
||||||
|
public void setIsSelected(Boolean isSelected) {
|
||||||
|
this.isSelected = isSelected;
|
||||||
|
setTeamNameObjectVisible(isSelected);
|
||||||
|
setVelocityObjectVisible(isSelected);
|
||||||
|
setLineGroupVisible(isSelected);
|
||||||
|
setWakeVisible(isSelected);
|
||||||
|
setEstTimeToNextMarkObjectVisible(isSelected);
|
||||||
|
setLegTimeObjectVisible(isSelected);
|
||||||
|
// TODO: 17/05/17 wmu16 - this should iterate over some list of annotations which we should make to easily make extensible
|
||||||
|
// paintBoat((isSelected) ? Color.WHITE : boat.getColour());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this BoatGroup contains at least one of the given IDs.
|
* Returns true if this BoatGroup contains at least one of the given IDs.
|
||||||
*
|
*
|
||||||
@@ -435,4 +461,9 @@ public class BoatGroup extends RaceObject {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return boat.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,4 +166,9 @@ public class Yacht {
|
|||||||
public void setMarkRoundingTime(Long markRoundingTime) {
|
public void setMarkRoundingTime(Long markRoundingTime) {
|
||||||
this.markRoundingTime = markRoundingTime;
|
this.markRoundingTime = markRoundingTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return boatName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package seng302.models.mark;
|
package seng302.models.mark;
|
||||||
|
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
|
import javafx.scene.CacheHint;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import java.util.concurrent.PriorityBlockingQueue;
|
|||||||
* and parsed in by turning the byte arrays into useful data. There are two public static hashmaps
|
* and parsed in by turning the byte arrays into useful data. There are two public static hashmaps
|
||||||
* that are threadsafe so the visualiser can always access the latest speed and position available
|
* that are threadsafe so the visualiser can always access the latest speed and position available
|
||||||
* Created by kre39 on 23/04/17.
|
* Created by kre39 on 23/04/17.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class StreamParser extends Thread{
|
public class StreamParser extends Thread{
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,24 @@ Table
|
|||||||
-fx-border-style: none;
|
-fx-border-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Combo Box
|
||||||
|
*/
|
||||||
|
|
||||||
|
.combo-box-base {
|
||||||
|
-fx-background-color: #119796;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-box-popup .list-view .list-cell:hover {
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-box .cell:selected {
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Remove scroll bars
|
Remove scroll bars
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -56,9 +56,11 @@
|
|||||||
</Text>
|
</Text>
|
||||||
</children>
|
</children>
|
||||||
</Pane>
|
</Pane>
|
||||||
<Slider fx:id="annotationSlider" blockIncrement="1.0" layoutX="38.0" layoutY="527.0" majorTickUnit="1.0" max="3.0" minorTickCount="0" prefHeight="51.0" prefWidth="170.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" styleClass="ui-slider" />
|
<Slider fx:id="annotationSlider" blockIncrement="1.0" layoutX="38.0" layoutY="527.0" majorTickUnit="1.0" max="2.0" minorTickCount="0" prefHeight="51.0" prefWidth="170.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" styleClass="ui-slider" />
|
||||||
<Label layoutX="10.0" layoutY="499.0" text="Annotations" textFill="WHITE" />
|
<Label layoutX="10.0" layoutY="499.0" text="Annotations" textFill="WHITE" />
|
||||||
<Button fx:id="selectAnnotationBtn" layoutX="35.0" layoutY="578.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="170.0" styleClass="blue-ui-btn" text="Select Annotations" textFill="WHITE" />
|
<Button fx:id="selectAnnotationBtn" layoutX="35.0" layoutY="578.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="170.0" styleClass="blue-ui-btn" text="Select Annotations" textFill="WHITE" />
|
||||||
|
<Text fill="WHITE" layoutX="11.0" layoutY="649.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Boat Selection" />
|
||||||
|
<ComboBox fx:id="boatSelectionComboBox" layoutX="37.0" layoutY="664.0" prefHeight="25.0" prefWidth="170.0" promptText="Select Boat" styleClass="combo-box-base" />
|
||||||
</children>
|
</children>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
<AnchorPane fx:id="contentAnchorPane" prefHeight="960.0" prefWidth="1280.0" style="-fx-background-color: skyblue;" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2147483647" GridPane.valignment="TOP">
|
<AnchorPane fx:id="contentAnchorPane" prefHeight="960.0" prefWidth="1280.0" style="-fx-background-color: skyblue;" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2147483647" GridPane.valignment="TOP">
|
||||||
|
|||||||
Reference in New Issue
Block a user