diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 1a400afd..80163138 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -62,6 +62,8 @@ public class App extends Application } //Change the StreamReceiver in this else block to change the default data source. else{ +// sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); + sr = new StreamReceiver("localhost", 4949, "RaceStream"); } diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 24ff0163..cce59db3 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -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 -> { @@ -220,97 +214,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 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,29 +233,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() { - @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() + ". " + @@ -419,10 +304,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel return race; } - public Map getTimelineInfos() { - return timelineInfos; - } - public ArrayList getStartingBoats(){ return startingBoats; } @@ -459,6 +340,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel else{ bg.setWakeVisible(false); } + + if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) { + bg.setEstTimeToNextMarkVisible(true); + } + else { + bg.setEstTimeToNextMarkVisible(false); + } } private void setAnnotations(Integer annotationLevel) { @@ -470,6 +358,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel BoatGroup bg = (BoatGroup) ro; bg.setTeamNameObjectVisible(false); bg.setVelocityObjectVisible(false); + bg.setEstTimeToNextMarkVisible(false); bg.setLineGroupVisible(false); bg.setWakeVisible(false); } @@ -482,6 +371,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel BoatGroup bg = (BoatGroup) ro; bg.setTeamNameObjectVisible(true); bg.setVelocityObjectVisible(false); + bg.setEstTimeToNextMarkVisible(false); bg.setLineGroupVisible(false); bg.setWakeVisible(false); } @@ -503,6 +393,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel BoatGroup bg = (BoatGroup) ro; bg.setTeamNameObjectVisible(true); bg.setVelocityObjectVisible(true); + bg.setEstTimeToNextMarkVisible(true); bg.setLineGroupVisible(true); bg.setWakeVisible(true); } diff --git a/src/main/java/seng302/controllers/annotations/Annotation.java b/src/main/java/seng302/controllers/annotations/Annotation.java index eed70162..0eea5ee2 100644 --- a/src/main/java/seng302/controllers/annotations/Annotation.java +++ b/src/main/java/seng302/controllers/annotations/Annotation.java @@ -7,5 +7,6 @@ public enum Annotation { SPEED, WAKE, TRACK, - NAME + NAME, + ESTTIMETONEXTMARK } diff --git a/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java b/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java index 0d1585af..95fe84d3 100644 --- a/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java +++ b/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java @@ -30,6 +30,9 @@ public class ImportantAnnotationController implements Initializable { @FXML private CheckBox boatNameSelect; + @FXML + private CheckBox boatEstTimeToNextMarkSelect; + @FXML private AnchorPane annotationSelectWindow; @@ -91,6 +94,10 @@ public class ImportantAnnotationController implements Initializable { boatNameSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; + case ESTTIMETONEXTMARK: + boatEstTimeToNextMarkSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + break; + default: break; } @@ -108,6 +115,7 @@ public class ImportantAnnotationController implements Initializable { 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())); 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..8204a41c 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -8,7 +8,10 @@ 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; @@ -23,9 +26,11 @@ 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 BOAT_HEIGHT = 15d; private static final double BOAT_WIDTH = 10d; //Variables for boat logic. @@ -38,6 +43,7 @@ public class BoatGroup extends RaceObject{ private Polygon boatPoly; private Text teamNameObject; private Text velocityObject; + private Text estTimeToNextMarkObject; private Wake wake; //Handles boat moving when connecting to a stream private boolean setToInitialLocation = false; @@ -83,6 +89,9 @@ public class BoatGroup extends RaceObject{ 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); teamNameObject.setX(TEAMNAME_X_OFFSET); teamNameObject.setY(TEAMNAME_Y_OFFSET); @@ -93,8 +102,12 @@ 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()); + wake = new Wake(0, -BOAT_HEIGHT); - super.getChildren().addAll(teamNameObject, velocityObject, boatPoly); + super.getChildren().addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject); } /** @@ -120,6 +133,8 @@ 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); wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutY(wake.getLayoutY() + dy); rotateTo(rotation + currentRotation); @@ -148,6 +163,8 @@ public class BoatGroup extends RaceObject{ teamNameObject.setLayoutY(y); velocityObject.setLayoutX(x); velocityObject.setLayoutY(y); + estTimeToNextMarkObject.setLayoutX(x); + estTimeToNextMarkObject.setLayoutY(y); wake.setLayoutX(x); wake.setLayoutY(y); wake.rotate(currentRotation); @@ -224,6 +241,9 @@ public class BoatGroup extends RaceObject{ wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, boat.getVelocity()); } velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); + DateFormat format = new SimpleDateFormat("mm:ss"); + String timeToNextMark = format.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); + estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); } else { setToInitialLocation = true; rotationalGoal = rotation; @@ -287,6 +307,10 @@ public class BoatGroup extends RaceObject{ velocityObject.setVisible(visible); } + public void setEstTimeToNextMarkVisible(Boolean visible) { + estTimeToNextMarkObject.setVisible(visible); + } + public void setLineGroupVisible(Boolean visible) { lineGroup.setVisible(visible); } diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index deea3184..1aca5826 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -39,6 +39,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,6 +200,7 @@ public class StreamParser extends Thread{ // System.out.println("raceStatus = " + raceStatus); long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18)); + currentTimeLong = currentTime; DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); if (xmlObject.getRegattaXML() != null) { format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString())); @@ -236,11 +238,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; @@ -575,6 +577,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..da89b52a 100644 --- a/src/main/resources/views/importantAnnotationSelectView.fxml +++ b/src/main/resources/views/importantAnnotationSelectView.fxml @@ -15,7 +15,8 @@ - + +