diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index b86b465d..df036566 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -61,7 +61,7 @@ public class App extends Application { } } //Change the StreamReceiver in this else block to change the default data source. - else { + else{ sr = new StreamReceiver("localhost", 4949, "RaceStream"); } @@ -71,7 +71,6 @@ public class App extends Application { launch(args); - } } diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 24ff0163..aa09d9d1 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -1,6 +1,5 @@ package seng302.controllers; -import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.beans.value.ChangeListener; @@ -34,7 +33,8 @@ import java.util.*; /** * Created by ptg19 on 29/03/17. */ -public class RaceViewController extends Thread implements ImportantAnnotationDelegate{ +public class RaceViewController extends Thread implements ImportantAnnotationDelegate { + @FXML private VBox positionVbox; @FXML @@ -55,8 +55,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel private ArrayList startingBoats = new ArrayList<>(); private boolean displayFps; private Timeline timerTimeline; - private Map timelineInfos = new HashMap<>(); - private ArrayList boatOrder = new ArrayList<>(); private Race race; private Stage stage; private ImportantAnnotationsState importantAnnotations; @@ -79,10 +77,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel initializeSettings(); initialiseWindDirection(); 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(); selectAnnotationBtn.setOnAction(event -> { @@ -92,11 +86,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel /** * The important annotations have been changed, update this view + * * @param importantAnnotationsState The current state of the selected annotations */ - public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState){ + public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) { this.importantAnnotations = importantAnnotationsState; - setAnnotations((int)annotationSlider.getValue()); // Refresh the displayed annotations + setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations } /** @@ -108,12 +103,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Stage stage = new Stage(); // Set controller - ImportantAnnotationController controller = new ImportantAnnotationController(this, stage); + ImportantAnnotationController controller = new ImportantAnnotationController(this, + stage); fxmlLoader.setController(controller); // Load FXML and set CSS - fxmlLoader.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml")); - Scene scene = new Scene(fxmlLoader.load(), 469, 248); + fxmlLoader + .setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml")); + Scene scene = new Scene(fxmlLoader.load(), 469, 270); scene.getStylesheets().add(getClass().getResource("/css/master.css").toString()); stage.initStyle(StageStyle.UNDECORATED); @@ -132,7 +129,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel toggleFps.selectedProperty().addListener(new ChangeListener() { @Override - public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { + public void changed(ObservableValue observable, Boolean oldValue, + Boolean newValue) { displayFps = !displayFps; } }); @@ -141,10 +139,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel annotationSlider.setLabelFormatter(new StringConverter() { @Override public String toString(Double n) { - if (n == 0) return "None"; - if (n == 1) return "Low"; - if (n == 2) return "Important"; - if (n == 3) return "All"; + if (n == 0) { + return "None"; + } + if (n == 1) { + return "Low"; + } + if (n == 2) { + return "Important"; + } + if (n == 3) { + return "All"; + } return "All"; } @@ -168,25 +174,25 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel }); annotationSlider.valueProperty().addListener((obs, oldval, newVal) -> - setAnnotations((int)annotationSlider.getValue())); + setAnnotations((int) annotationSlider.getValue())); annotationSlider.setValue(3); } - private void initializeTimer(){ + private void initializeTimer() { timerTimeline = new Timeline(); timerTimeline.setCycleCount(Timeline.INDEFINITE); // Run timer update every second timerTimeline.getKeyFrames().add( - new KeyFrame(Duration.seconds(1), - event -> { - if (StreamParser.isRaceFinished()) { - timerLabel.setFill(Color.RED); - timerLabel.setText("Race Finished!"); - } else { - timerLabel.setText(currentTimer()); - } - }) + new KeyFrame(Duration.seconds(1), + event -> { + if (StreamParser.isRaceFinished()) { + timerLabel.setFill(Color.RED); + timerLabel.setText("Race Finished!"); + } else { + timerLabel.setText(currentTimer()); + } + }) ); // Start the timer @@ -197,11 +203,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel 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()); - }) + new KeyFrame(Duration.seconds(1), + event -> { + windDirectionText + .setText(String.format("%.1f°", StreamParser.getWindDirection())); + windArrowText.setRotate(StreamParser.getWindDirection()); + }) ); windDirTimeline.playFromStart(); } @@ -211,106 +218,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Timeline posVBoxTimeline = new Timeline(); posVBoxTimeline.setCycleCount(Timeline.INDEFINITE); posVBoxTimeline.getKeyFrames().add( - new KeyFrame(Duration.seconds(1), - event -> { - showOrder(); - }) + new KeyFrame(Duration.seconds(1), + event -> { + showOrder(); + }) ); posVBoxTimeline.playFromStart(); } - /** - * Generates time line for each boat, and stores time time into timelineInfos hash map - */ - private void initializeTimelines() { - HashMap 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 keyFrames = new ArrayList<>(); -// List 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 */ @@ -330,39 +246,21 @@ 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() { - @Override - public int compare(Yacht b1, Yacht b2) { - return b2.getMarkLastPast() - b1.getMarkLastPast(); - } - }); - showOrder(); - } - private void showOrder() { positionVbox.getChildren().clear(); positionVbox.getChildren().removeAll(); 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()) { if (boat.getBoatStatus() == 3) { // 3 is finish status Text textToAdd = new Text(boat.getPosition() + ". " + - boat.getShortName() + " (Finished)"); + boat.getShortName() + " (Finished)"); textToAdd.setFill(Paint.valueOf("#d3d3d3")); positionVbox.getChildren().add(textToAdd); } else { Text textToAdd = new Text(boat.getPosition() + ". " + - boat.getShortName() + " "); + boat.getShortName() + " "); textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setStyle(""); positionVbox.getChildren().add(textToAdd); @@ -407,6 +305,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel public void stopTimer() { timerTimeline.stop(); } + public void startTimer() { timerTimeline.play(); } @@ -419,46 +318,51 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel return race; } - public Map getTimelineInfos() { - return timelineInfos; - } - - public ArrayList getStartingBoats(){ + public ArrayList getStartingBoats() { return startingBoats; } /** * Display the important annotations for a specific BoatGroup + * * @param bg The boat group to set the annotations for */ - private void setBoatGroupImportantAnnotations(BoatGroup bg){ - if (importantAnnotations.getAnnotationState(Annotation.NAME)){ + private void setBoatGroupImportantAnnotations(BoatGroup bg) { + if (importantAnnotations.getAnnotationState(Annotation.NAME)) { bg.setTeamNameObjectVisible(true); - } - else{ + } else { bg.setTeamNameObjectVisible(false); } - if (importantAnnotations.getAnnotationState(Annotation.SPEED)){ + if (importantAnnotations.getAnnotationState(Annotation.SPEED)) { bg.setVelocityObjectVisible(true); - } - else{ + } else { bg.setVelocityObjectVisible(false); } - if (importantAnnotations.getAnnotationState(Annotation.TRACK)){ + if (importantAnnotations.getAnnotationState(Annotation.TRACK)) { bg.setLineGroupVisible(true); - } - else{ + } else { bg.setLineGroupVisible(false); } - if (importantAnnotations.getAnnotationState(Annotation.WAKE)){ + if (importantAnnotations.getAnnotationState(Annotation.WAKE)) { bg.setWakeVisible(true); - } - else{ + } else { 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) { @@ -466,10 +370,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // No Annotations case 0: for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { + if (ro instanceof BoatGroup) { BoatGroup bg = (BoatGroup) ro; bg.setTeamNameObjectVisible(false); bg.setVelocityObjectVisible(false); + bg.setEstTimeToNextMarkObjectVisible(false); + bg.setLegTimeObjectVisible(false); bg.setLineGroupVisible(false); bg.setWakeVisible(false); } @@ -478,10 +384,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // Low Annotations case 1: for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { + 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); } @@ -490,7 +398,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // Important Annotations case 2: for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { + if (ro instanceof BoatGroup) { BoatGroup bg = (BoatGroup) ro; setBoatGroupImportantAnnotations(bg); } @@ -499,10 +407,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // All Annotations case 3: for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { + if (ro instanceof BoatGroup) { BoatGroup bg = (BoatGroup) ro; bg.setTeamNameObjectVisible(true); bg.setVelocityObjectVisible(true); + bg.setEstTimeToNextMarkObjectVisible(true); + bg.setLegTimeObjectVisible(true); bg.setLineGroupVisible(true); bg.setWakeVisible(true); } @@ -511,11 +421,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel } } - void setStage (Stage stage) { + void setStage(Stage stage) { this.stage = stage; } - Stage getStage () { + Stage getStage() { return stage; } } \ No newline at end of file diff --git a/src/main/java/seng302/controllers/annotations/Annotation.java b/src/main/java/seng302/controllers/annotations/Annotation.java index eed70162..20a2c265 100644 --- a/src/main/java/seng302/controllers/annotations/Annotation.java +++ b/src/main/java/seng302/controllers/annotations/Annotation.java @@ -7,5 +7,7 @@ public enum Annotation { SPEED, WAKE, TRACK, - NAME + NAME, + ESTTIMETONEXTMARK, + LEGTIME } diff --git a/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java b/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java index 0d1585af..8dfa8df7 100644 --- a/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java +++ b/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.ResourceBundle; public class ImportantAnnotationController implements Initializable { + /* * JavaFX Outlets */ @@ -30,6 +31,12 @@ public class ImportantAnnotationController implements Initializable { @FXML private CheckBox boatNameSelect; + @FXML + private CheckBox boatEstTimeToNextMarkSelect; + + @FXML + private CheckBox boatElapsedTimeSelect; + @FXML private AnchorPane annotationSelectWindow; @@ -40,7 +47,7 @@ public class ImportantAnnotationController implements Initializable { private ImportantAnnotationsState importantAnnotationsState; private Stage stage; - public ImportantAnnotationController(ImportantAnnotationDelegate delegate, Stage stage){ + public ImportantAnnotationController(ImportantAnnotationDelegate delegate, Stage stage) { this.delegate = delegate; importantAnnotationsState = new ImportantAnnotationsState(); this.stage = stage; @@ -49,10 +56,11 @@ public class ImportantAnnotationController implements Initializable { /** * Sets whether or not an annotation is considered important, then * sends an update to the delegate + * * @param annotation The annotation * @param isSet True if annotation is important */ - private void setAnnotation(Annotation annotation, Boolean isSet){ + private void setAnnotation(Annotation annotation, Boolean isSet) { importantAnnotationsState.setAnnotationState(annotation, isSet); sendUpdate(); } @@ -61,36 +69,50 @@ public class ImportantAnnotationController implements Initializable { * Sends an update to the delegate when the important * annotations have changed */ - private void sendUpdate(){ + private void sendUpdate() { this.delegate.importantAnnotationsChanged(importantAnnotationsState); } /** * Load the current state of the 'important annotations' + * * @param currentState hashmap containing the states of each annotation */ - public void loadState(ImportantAnnotationsState currentState){ + public void loadState(ImportantAnnotationsState currentState) { this.importantAnnotationsState = currentState; // Initialise checkboxes - for (Annotation annotation : importantAnnotationsState.getAnnotations()){ - switch (annotation){ + for (Annotation annotation : importantAnnotationsState.getAnnotations()) { + switch (annotation) { case WAKE: - boatWakeSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + boatWakeSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; case SPEED: - boatSpeedSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + boatSpeedSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; case TRACK: - boatTrackSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + boatTrackSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; case NAME: - boatNameSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + boatNameSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; + case ESTTIMETONEXTMARK: + boatEstTimeToNextMarkSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); + break; + + case LEGTIME: + boatElapsedTimeSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); + default: break; } @@ -99,15 +121,24 @@ public class ImportantAnnotationController implements Initializable { /** * View did load + * * @param location . * @param resources . */ @Override public void initialize(URL location, ResourceBundle resources) { - boatWakeSelect.setOnAction(event -> setAnnotation(Annotation.WAKE, boatWakeSelect.isSelected())); - boatSpeedSelect.setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected())); - boatTrackSelect.setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected())); - boatNameSelect.setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected())); + boatWakeSelect + .setOnAction(event -> setAnnotation(Annotation.WAKE, boatWakeSelect.isSelected())); + boatSpeedSelect + .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()); } diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 57dd48db..e07c57ee 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -8,24 +8,32 @@ import javafx.scene.shape.Polygon; import javafx.scene.text.Text; import javafx.scene.transform.Rotate; import javafx.stage.Stage; +import seng302.models.parsers.StreamParser; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; /** - * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 dimensional boat. - * 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 - * annotate the boat teams name and the boats velocity. The boat will update it's position onscreen everytime - * UpdatePosition is called unless the window is minimized in which case it attempts to store animations and apply them - * when the window is maximised. + * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 + * dimensional boat. 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 annotate the boat teams name and the boats velocity. The + * boat will update it's position onscreen everytime UpdatePosition is called unless the window is + * 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 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_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_WIDTH = 10d; //Variables for boat logic. @@ -38,51 +46,69 @@ public class BoatGroup extends RaceObject{ private Polygon boatPoly; private Text teamNameObject; private Text velocityObject; + private Text estTimeToNextMarkObject; + private Text legTimeObject; private Wake wake; //Handles boat moving when connecting to a stream private boolean setToInitialLocation = false; private boolean destinationSet; //Variables for handling minimization private Stage stage; - private boolean isMaximized= true; + private boolean isMaximized = true; private List lineStorage = new ArrayList<>(); private int setCallCount = 5; /** * 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. */ - public BoatGroup (Yacht boat, Color color){ + public BoatGroup(Yacht boat, Color color) { this.boat = boat; initChildren(color); } /** - * Creates a BoatGroup with the boat being the default polygon. The head of the boat should be at point (0,0). - * @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which - * BoatGroup to update. + * Creates a BoatGroup with the boat being the default polygon. The head of the boat should be + * at point (0,0). + * + * @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 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; initChildren(color, points); } /** * 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 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.setFill(color); teamNameObject = new Text(boat.getShortName()); 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.setY(TEAMNAME_Y_OFFSET); @@ -93,23 +119,37 @@ public class BoatGroup extends RaceObject{ velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); 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); - 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. + * * @param color The colour of the boat polygon and the trailing line. */ - private void initChildren (Color color) { + private void initChildren(Color color) { initChildren(color, - -BOAT_WIDTH / 2, BOAT_HEIGHT / 2, - 0.0, -BOAT_HEIGHT / 2, - BOAT_WIDTH / 2, BOAT_HEIGHT / 2); + -BOAT_WIDTH / 2, BOAT_HEIGHT / 2, + 0.0, -BOAT_HEIGHT / 2, + BOAT_WIDTH / 2, BOAT_HEIGHT / 2); } /** - * 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 dy The amount to move the Y coordinate by */ @@ -120,6 +160,10 @@ public class BoatGroup extends RaceObject{ teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy); velocityObject.setLayoutX(velocityObject.getLayoutX() + dx); 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.setLayoutY(wake.getLayoutY() + dy); rotateTo(rotation + currentRotation); @@ -127,27 +171,33 @@ public class BoatGroup extends RaceObject{ /** * Moves the boat and its children annotations to coordinates specified + * * @param x The X 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. */ - public void moveTo (double x, double y, double rotation) { + public void moveTo(double x, double y, double rotation) { rotateTo(rotation); moveTo(x, y); } /** * Moves the boat and its children annotations to coordinates specified + * * @param x The X coordinate to move the boat to * @param y The Y coordinate to move the boat to */ - public void moveTo (double x, double y) { + public void moveTo(double x, double y) { boatPoly.setLayoutX(x); boatPoly.setLayoutY(y); teamNameObject.setLayoutX(x); teamNameObject.setLayoutY(y); velocityObject.setLayoutX(x); velocityObject.setLayoutY(y); + estTimeToNextMarkObject.setLayoutX(x); + estTimeToNextMarkObject.setLayoutY(y); + legTimeObject.setLayoutX(x); + legTimeObject.setLayoutY(y); wake.setLayoutX(x); wake.setLayoutY(y); wake.rotate(currentRotation); @@ -155,9 +205,11 @@ public class BoatGroup extends RaceObject{ /** * 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. if (isMaximized) { double dx = pixelVelocityX * timeInterval; @@ -170,10 +222,10 @@ public class BoatGroup extends RaceObject{ distanceTravelled = 0; if (lastPoint != null) { Line l = new Line( - lastPoint.getX(), - lastPoint.getY(), - boatPoly.getLayoutX(), - boatPoly.getLayoutY() + lastPoint.getX(), + lastPoint.getY(), + boatPoly.getLayoutX(), + boatPoly.getLayoutY() ); l.getStrokeDashArray().setAll(3d, 7d); l.setStroke(boatPoly.getFill()); @@ -189,18 +241,21 @@ public class BoatGroup extends RaceObject{ /** * 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 newYValue The Y co-ordinate the boat needs to move to. * @param rotation Rotation to move graphics to. * @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 (setToInitialLocation) { destinationSet = true; boat.setVelocity(groundSpeed); - if (currentRotation < 0) + if (currentRotation < 0) { currentRotation = 360 - currentRotation; + } double dx = newXValue - boatPoly.getLayoutX(); double dy = newYValue - boatPoly.getLayoutY(); //Check movement is reasonable. Assumes a 1000 * 1000 canvas @@ -221,9 +276,23 @@ public class BoatGroup extends RaceObject{ rotationalVelocity = 0; wakeGenerationDelay--; } else { - wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, boat.getVelocity()); + wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, + 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 { setToInitialLocation = true; rotationalGoal = rotation; @@ -234,14 +303,14 @@ public class BoatGroup extends RaceObject{ if (!isMaximized) { setToInitialLocation = false; wakeGenerationDelay = 2; - if(setCallCount-- == 0) { + if (setCallCount-- == 0) { setCallCount = 5; if (lastPoint != null) { Line l = new Line( - lastPoint.getX(), - lastPoint.getY(), - newXValue, - newYValue + lastPoint.getX(), + lastPoint.getY(), + newXValue, + newYValue ); l.getStrokeDashArray().setAll(3d, 7d); l.setStroke(boatPoly.getFill()); @@ -254,28 +323,29 @@ 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; if (hasRaceId(raceIDs)) { double rotation = Math.abs( - Math.toDegrees( - Math.atan( - (newYValue - boatPoly.getLayoutY()) / (newXValue - boatPoly.getLayoutX()) - ) + Math.toDegrees( + Math.atan( + (newYValue - boatPoly.getLayoutY()) / (newXValue - boatPoly.getLayoutX()) ) + ) ); setDestination(newXValue, newYValue, rotation, groundSpeed, raceIDs); } } - public void rotateTo (double rotation) { + public void rotateTo(double rotation) { currentRotation = rotation; boatPoly.getTransforms().setAll(new Rotate(rotation)); } - public void forceRotation () { - rotateTo (rotationalGoal); + public void forceRotation() { + rotateTo(rotationalGoal); wake.rotate(rotationalGoal); } @@ -287,6 +357,14 @@ public class BoatGroup extends RaceObject{ velocityObject.setVisible(visible); } + public void setEstTimeToNextMarkObjectVisible(Boolean visible) { + estTimeToNextMarkObject.setVisible(visible); + } + + public void setLegTimeObjectVisible(Boolean visible) { + legTimeObject.setVisible(visible); + } + public void setLineGroupVisible(Boolean visible) { lineGroup.setVisible(visible); } @@ -305,10 +383,11 @@ public class BoatGroup extends RaceObject{ * @param raceIds The ID's to check the BoatGroup for. * @return True if the BoatGroup contains at east one of the given IDs, false otherwise. */ - public boolean hasRaceId (int... raceIds) { + public boolean hasRaceId(int... raceIds) { for (int id : raceIds) { - if (id == boat.getSourceID()) + if (id == boat.getSourceID()) { return true; + } } return false; } @@ -318,31 +397,32 @@ public class BoatGroup extends RaceObject{ * * @return An array containing all ID's associated with this RaceObject. */ - public int[] getRaceIds () { - return new int[] {boat.getSourceID()}; + public int[] getRaceIds() { + return new int[]{boat.getSourceID()}; } /** - * Due to javaFX limitations annotations associated with a boat that you want to appear below all boats in the - * Z-axis need to be pulled out of the BoatGroup and added to the parent group of the BoatGroups. This function - * returns these annotations as a group. + * Due to javaFX limitations annotations associated with a boat that you want to appear below + * all boats in the Z-axis need to be pulled out of the BoatGroup and added to the parent group + * of the BoatGroups. This function returns these annotations as a group. * * @return A group containing low priority annotations. */ - public Group getLowPriorityAnnotations () { + public Group getLowPriorityAnnotations() { Group group = new Group(); group.getChildren().addAll(wake, lineGroup); return group; } /** - * Use this function to let the BoatGroup know about the stage it is in. If it knows about it's stage then it will - * listen to the iconified property of that stage and change it's behaviour upon minimization. Without setting the - * Stage there is guarantee that the BoatGroup will draw properly when the stage is minimized. + * Use this function to let the BoatGroup know about the stage it is in. If it knows about it's + * stage then it will listen to the iconified property of that stage and change it's behaviour + * 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. */ - public void setStage (Stage stage) { + public void setStage(Stage stage) { /* TODO: 4/05/17 cir27 - Find a way to get the stage to this point. Need to pass it through multiple controllers. App.start() -> Controller.setContentPane -> RaceViewController -> CanvasController */ diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 68970268..e21384f9 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -12,9 +12,9 @@ import java.text.SimpleDateFormat; * also done outside Boat class because some old variables are not used anymore. */ public class Yacht { + // Used in boat group private Color colour; private double velocity; - private Integer markLastPast; private String boatType; private Integer sourceID; @@ -30,6 +30,8 @@ public class Yacht { private Long estimateTimeAtNextMark; private Long estimateTimeAtFinish; private String position; + // Mark rounding + private Long markRoundingTime; /** * Used in EventTest and RaceTest. @@ -157,11 +159,11 @@ public class Yacht { this.velocity = velocity; } - public Integer getMarkLastPast() { - return markLastPast; + public Long getMarkRoundingTime() { + return markRoundingTime; } - public void setMarkLastPast(Integer markLastPast) { - this.markLastPast = markLastPast; + public void setMarkRoundingTime(Long markRoundingTime) { + this.markRoundingTime = markRoundingTime; } } diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index e13883ee..73994d87 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -40,6 +40,7 @@ public class StreamParser extends Thread{ private static Map boats = new HashMap<>(); private static Map boatsPos = new TreeMap<>(); private static double windDirection = 0; + private static Long currentTimeLong; private static String currentTimeString; private static boolean appRunning; @@ -199,9 +200,11 @@ public class StreamParser extends Thread{ long currentTime = bytesToLong(Arrays.copyOfRange(payload,1,7)); long raceId = bytesToLong(Arrays.copyOfRange(payload,7,11)); int raceStatus = payload[11]; -// System.out.println("raceStatus = " + raceStatus); 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"); if (xmlObject.getRegattaXML() != null) { 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; - if (timeTillStart > 0) { timeSinceStart = timeTillStart; //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"); timeSinceStart = timeTillStart; } - long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); + double windDirFactor = 0x4000 / 90; //0x4000 is 90 degrees, 0x8000 is 180 degrees, etc... windDirection = windDir / windDirFactor; - long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22)); + int noBoats = payload[22]; int raceType = payload[23]; // ArrayList boatStatuses = new ArrayList<>(); @@ -239,11 +241,11 @@ public class StreamParser extends Thread{ Yacht boat = boats.get((int)(long) boatStatusSourceID); boat.setBoatStatus((int)payload[28 + (i * 20)]); boat.setLegNumber((int)payload[29 + (i * 20)]); - boat.setPenaltiesAwarded((int)payload[29 + (i * 20)]); - boat.setPenaltiesServed((int)payload[30 + (i * 20)]); - Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,31 + (i * 20),37+ (i * 20))); + boat.setPenaltiesAwarded((int)payload[30 + (i * 20)]); + boat.setPenaltiesServed((int)payload[31 + (i * 20)]); + Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,32 + (i * 20),38+ (i * 20))); 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); boatsPos.put(estTimeAtFinish, boat); // String boatStatus = "SourceID: " + boatStatusSourceID; @@ -434,6 +436,9 @@ public class StreamParser extends Thread{ int roundingSide = payload[18]; int markType = payload[19]; 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; } + /** + * returns current time in stream in long + * + * @return a long value of current time + */ + public static Long getCurrentTimeLong() { + return currentTimeLong; + } + public static void appClose(){ appRunning = false; System.out.println("[CLIENT] Shutting down stream parser"); diff --git a/src/main/resources/views/importantAnnotationSelectView.fxml b/src/main/resources/views/importantAnnotationSelectView.fxml index fb88442d..8b21c2d9 100644 --- a/src/main/resources/views/importantAnnotationSelectView.fxml +++ b/src/main/resources/views/importantAnnotationSelectView.fxml @@ -5,7 +5,7 @@ - + @@ -15,7 +15,8 @@ - + + +