Merge branch 'story33_add_estimated_time_annotation' into 'develop'

Story33 add estimated time annotation

Added estimated time to next mark to annotation

See merge request !28
This commit is contained in:
Michael Rausch
2017-05-15 15:50:46 +12:00
7 changed files with 66 additions and 128 deletions
+2
View File
@@ -62,6 +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("livedata.americascup.com", 4941, "RaceStream");
sr = new StreamReceiver("localhost", 4949, "RaceStream"); sr = new StreamReceiver("localhost", 4949, "RaceStream");
} }
@@ -55,8 +55,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private ArrayList<Yacht> startingBoats = new ArrayList<>(); private ArrayList<Yacht> startingBoats = new ArrayList<>();
private boolean displayFps; private boolean displayFps;
private Timeline timerTimeline; private Timeline timerTimeline;
private Map<Yacht, TimelineInfo> timelineInfos = new HashMap<>();
private ArrayList<Yacht> boatOrder = new ArrayList<>();
private Race race; private Race race;
private Stage stage; private Stage stage;
private ImportantAnnotationsState importantAnnotations; private ImportantAnnotationsState importantAnnotations;
@@ -79,10 +77,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
initializeSettings(); initializeSettings();
initialiseWindDirection(); initialiseWindDirection();
initialisePositionVBox(); initialisePositionVBox();
//set wind direction!!!!!!! can't find another place to put my code --haoming
// double windDirection = new ConfigParser("/config/config.xml").getWindDirection();
// windDirectionText.setText(String.format("%.1f°", windDirection));
// windArrowText.setRotate(windDirection);
includedCanvasController.timer.start(); includedCanvasController.timer.start();
selectAnnotationBtn.setOnAction(event -> { selectAnnotationBtn.setOnAction(event -> {
@@ -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<Yacht, List> boat_events = race.getEvents();
for (Yacht boat : boat_events.keySet()) {
startingBoats.add(boat);
// // x, y are the real time coordinates
// DoubleProperty x = new SimpleDoubleProperty();
// DoubleProperty y = new SimpleDoubleProperty();
//
// List<KeyFrame> keyFrames = new ArrayList<>();
// List<Event> events = boat_events.get(boat);
//
// // iterates all events and convert each event to keyFrame, then add them into a list
// for (Event event : events) {
// if (event.getIsFinishingEvent()) {
// keyFrames.add(
// new KeyFrame(Duration.seconds(event.getTime()),
// onFinished -> {race.setBoatFinished(boat); handleEvent(event);},
// new KeyValue(x, event.getThisMark().getLatitude()),
// new KeyValue(y, event.getThisMark().getLongitude())
// )
// );
// } else {
// keyFrames.add(
// new KeyFrame(Duration.seconds(event.getTime()),
// onFinished ->{
// handleEvent(event);
// boat.setHeading(event.getBoatHeading());
// },
// new KeyValue(x, event.getThisMark().getLatitude()),
// new KeyValue(y, event.getThisMark().getLongitude())
// )
// );
// }
// }
// timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y));
}
setRaceDuration();
}
private void setRaceDuration(){
Double maxDuration = 0.0;
Timeline maxTimeline = null;
for (TimelineInfo timelineInfo : timelineInfos.values()) {
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getTotalDuration().toMillis() >= maxDuration) {
maxDuration = timeline.getTotalDuration().toMillis();
maxTimeline = timeline;
}
// Timelines are paused by default
timeline.play();
timeline.pause();
}
maxTimeline.setOnFinished(event -> {
race.setRaceFinished();
loadRaceResultView();
});
}
/**
* Play each boats timerTimeline
*/
public void playTimelines(){
for (TimelineInfo timelineInfo : timelineInfos.values()){
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getStatus() == Animation.Status.PAUSED){
timeline.play();
}
}
}
/**
* Pause each boats timerTimeline
*/
public void pauseTimelines(){
for (TimelineInfo timelineInfo : timelineInfos.values()){
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getStatus() == Animation.Status.RUNNING){
timeline.pause();
}
}
}
/** /**
* Display the list of boats in the order they finished the race * Display the list of boats in the order they finished the race
*/ */
@@ -330,29 +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<Yacht>() {
@Override
public int compare(Yacht b1, Yacht b2) {
return b2.getMarkLastPast() - b1.getMarkLastPast();
}
});
showOrder();
}
private void showOrder() { private void showOrder() {
positionVbox.getChildren().clear(); positionVbox.getChildren().clear();
positionVbox.getChildren().removeAll(); positionVbox.getChildren().removeAll();
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// for (Boat boat : boatOrder) {
// positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots"));
// }
for (Yacht boat : StreamParser.getBoatsPos().values()) { for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (boat.getBoatStatus() == 3) { // 3 is finish status if (boat.getBoatStatus() == 3) { // 3 is finish status
Text textToAdd = new Text(boat.getPosition() + ". " + Text textToAdd = new Text(boat.getPosition() + ". " +
@@ -419,10 +304,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
return race; return race;
} }
public Map<Yacht, TimelineInfo> getTimelineInfos() {
return timelineInfos;
}
public ArrayList<Yacht> getStartingBoats(){ public ArrayList<Yacht> getStartingBoats(){
return startingBoats; return startingBoats;
} }
@@ -459,6 +340,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
else{ else{
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) {
bg.setEstTimeToNextMarkVisible(true);
}
else {
bg.setEstTimeToNextMarkVisible(false);
}
} }
private void setAnnotations(Integer annotationLevel) { private void setAnnotations(Integer annotationLevel) {
@@ -470,6 +358,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
BoatGroup bg = (BoatGroup) ro; BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(false); bg.setTeamNameObjectVisible(false);
bg.setVelocityObjectVisible(false); bg.setVelocityObjectVisible(false);
bg.setEstTimeToNextMarkVisible(false);
bg.setLineGroupVisible(false); bg.setLineGroupVisible(false);
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
@@ -482,6 +371,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
BoatGroup bg = (BoatGroup) ro; BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(true); bg.setTeamNameObjectVisible(true);
bg.setVelocityObjectVisible(false); bg.setVelocityObjectVisible(false);
bg.setEstTimeToNextMarkVisible(false);
bg.setLineGroupVisible(false); bg.setLineGroupVisible(false);
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
@@ -503,6 +393,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
BoatGroup bg = (BoatGroup) ro; BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(true); bg.setTeamNameObjectVisible(true);
bg.setVelocityObjectVisible(true); bg.setVelocityObjectVisible(true);
bg.setEstTimeToNextMarkVisible(true);
bg.setLineGroupVisible(true); bg.setLineGroupVisible(true);
bg.setWakeVisible(true); bg.setWakeVisible(true);
} }
@@ -7,5 +7,6 @@ public enum Annotation {
SPEED, SPEED,
WAKE, WAKE,
TRACK, TRACK,
NAME NAME,
ESTTIMETONEXTMARK
} }
@@ -30,6 +30,9 @@ public class ImportantAnnotationController implements Initializable {
@FXML @FXML
private CheckBox boatNameSelect; private CheckBox boatNameSelect;
@FXML
private CheckBox boatEstTimeToNextMarkSelect;
@FXML @FXML
private AnchorPane annotationSelectWindow; private AnchorPane annotationSelectWindow;
@@ -91,6 +94,10 @@ public class ImportantAnnotationController implements Initializable {
boatNameSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); boatNameSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break; break;
case ESTTIMETONEXTMARK:
boatEstTimeToNextMarkSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation));
break;
default: default:
break; break;
} }
@@ -108,6 +115,7 @@ public class ImportantAnnotationController implements Initializable {
boatSpeedSelect.setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected())); boatSpeedSelect.setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected()));
boatTrackSelect.setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected())); boatTrackSelect.setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected()));
boatNameSelect.setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected())); boatNameSelect.setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected()));
boatEstTimeToNextMarkSelect.setOnAction(event -> setAnnotation(Annotation.ESTTIMETONEXTMARK, boatEstTimeToNextMarkSelect.isSelected()));
closeButton.setOnAction(event -> stage.close()); closeButton.setOnAction(event -> stage.close());
} }
+27 -3
View File
@@ -8,7 +8,10 @@ import javafx.scene.shape.Polygon;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
import javafx.stage.Stage; import javafx.stage.Stage;
import seng302.models.parsers.StreamParser;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -23,9 +26,11 @@ public class BoatGroup extends RaceObject{
//Constants for drawing //Constants for drawing
private static final double TEAMNAME_X_OFFSET = 10d; private static final double TEAMNAME_X_OFFSET = 10d;
private static final double TEAMNAME_Y_OFFSET = -15d; private static final double TEAMNAME_Y_OFFSET = -29d;
private static final double VELOCITY_X_OFFSET = 10d; private static final double VELOCITY_X_OFFSET = 10d;
private static final double VELOCITY_Y_OFFSET = -5d; private static final double VELOCITY_Y_OFFSET = -17d;
private static final double ESTTIMETONEXTMARK_X_OFFSET = 10d;
private static final double ESTTIMETONEXTMARK_Y_OFFSET = -5d;
private static final double BOAT_HEIGHT = 15d; private static final double BOAT_HEIGHT = 15d;
private static final double BOAT_WIDTH = 10d; private static final double BOAT_WIDTH = 10d;
//Variables for boat logic. //Variables for boat logic.
@@ -38,6 +43,7 @@ public class BoatGroup extends RaceObject{
private Polygon boatPoly; private Polygon boatPoly;
private Text teamNameObject; private Text teamNameObject;
private Text velocityObject; private Text velocityObject;
private Text estTimeToNextMarkObject;
private Wake wake; private Wake wake;
//Handles boat moving when connecting to a stream //Handles boat moving when connecting to a stream
private boolean setToInitialLocation = false; private boolean setToInitialLocation = false;
@@ -83,6 +89,9 @@ public class BoatGroup extends RaceObject{
teamNameObject = new Text(boat.getShortName()); teamNameObject = new Text(boat.getShortName());
velocityObject = new Text(String.valueOf(boat.getVelocity())); velocityObject = new Text(String.valueOf(boat.getVelocity()));
DateFormat format = new SimpleDateFormat("mm:ss");
String timeToNextMark = format.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark);
teamNameObject.setX(TEAMNAME_X_OFFSET); teamNameObject.setX(TEAMNAME_X_OFFSET);
teamNameObject.setY(TEAMNAME_Y_OFFSET); teamNameObject.setY(TEAMNAME_Y_OFFSET);
@@ -93,8 +102,12 @@ public class BoatGroup extends RaceObject{
velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
destinationSet = false; destinationSet = false;
estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET);
estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET);
estTimeToNextMarkObject.relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY());
wake = new Wake(0, -BOAT_HEIGHT); wake = new Wake(0, -BOAT_HEIGHT);
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly); super.getChildren().addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject);
} }
/** /**
@@ -120,6 +133,8 @@ public class BoatGroup extends RaceObject{
teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy); teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy);
velocityObject.setLayoutX(velocityObject.getLayoutX() + dx); velocityObject.setLayoutX(velocityObject.getLayoutX() + dx);
velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); velocityObject.setLayoutY(velocityObject.getLayoutY() + dy);
estTimeToNextMarkObject.setLayoutX(estTimeToNextMarkObject.getLayoutX() + dx);
estTimeToNextMarkObject.setLayoutY(estTimeToNextMarkObject.getLayoutY() + dy);
wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutX(wake.getLayoutX() + dx);
wake.setLayoutY(wake.getLayoutY() + dy); wake.setLayoutY(wake.getLayoutY() + dy);
rotateTo(rotation + currentRotation); rotateTo(rotation + currentRotation);
@@ -148,6 +163,8 @@ public class BoatGroup extends RaceObject{
teamNameObject.setLayoutY(y); teamNameObject.setLayoutY(y);
velocityObject.setLayoutX(x); velocityObject.setLayoutX(x);
velocityObject.setLayoutY(y); velocityObject.setLayoutY(y);
estTimeToNextMarkObject.setLayoutX(x);
estTimeToNextMarkObject.setLayoutY(y);
wake.setLayoutX(x); wake.setLayoutX(x);
wake.setLayoutY(y); wake.setLayoutY(y);
wake.rotate(currentRotation); wake.rotate(currentRotation);
@@ -224,6 +241,9 @@ public class BoatGroup extends RaceObject{
wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, boat.getVelocity()); wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, boat.getVelocity());
} }
velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); velocityObject.setText(String.format("%.2f m/s", boat.getVelocity()));
DateFormat format = new SimpleDateFormat("mm:ss");
String timeToNextMark = format.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark);
} else { } else {
setToInitialLocation = true; setToInitialLocation = true;
rotationalGoal = rotation; rotationalGoal = rotation;
@@ -287,6 +307,10 @@ public class BoatGroup extends RaceObject{
velocityObject.setVisible(visible); velocityObject.setVisible(visible);
} }
public void setEstTimeToNextMarkVisible(Boolean visible) {
estTimeToNextMarkObject.setVisible(visible);
}
public void setLineGroupVisible(Boolean visible) { public void setLineGroupVisible(Boolean visible) {
lineGroup.setVisible(visible); lineGroup.setVisible(visible);
} }
@@ -39,6 +39,7 @@ public class StreamParser extends Thread{
private static Map<Integer, Yacht> boats = new HashMap<>(); private static Map<Integer, Yacht> boats = new HashMap<>();
private static Map<Long, Yacht> boatsPos = new TreeMap<>(); private static Map<Long, Yacht> boatsPos = new TreeMap<>();
private static double windDirection = 0; private static double windDirection = 0;
private static Long currentTimeLong;
private static String currentTimeString; private static String currentTimeString;
private static boolean appRunning; private static boolean appRunning;
@@ -199,6 +200,7 @@ public class StreamParser extends Thread{
// System.out.println("raceStatus = " + raceStatus); // System.out.println("raceStatus = " + raceStatus);
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18)); long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18));
currentTimeLong = currentTime;
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
if (xmlObject.getRegattaXML() != null) { if (xmlObject.getRegattaXML() != null) {
format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString())); format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString()));
@@ -236,11 +238,11 @@ public class StreamParser extends Thread{
Yacht boat = boats.get((int)(long) boatStatusSourceID); Yacht boat = boats.get((int)(long) boatStatusSourceID);
boat.setBoatStatus((int)payload[28 + (i * 20)]); boat.setBoatStatus((int)payload[28 + (i * 20)]);
boat.setLegNumber((int)payload[29 + (i * 20)]); boat.setLegNumber((int)payload[29 + (i * 20)]);
boat.setPenaltiesAwarded((int)payload[29 + (i * 20)]); boat.setPenaltiesAwarded((int)payload[30 + (i * 20)]);
boat.setPenaltiesServed((int)payload[30 + (i * 20)]); boat.setPenaltiesServed((int)payload[31 + (i * 20)]);
Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,31 + (i * 20),37+ (i * 20))); Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,32 + (i * 20),38+ (i * 20)));
boat.setEstimateTimeAtNextMark(estTimeAtNextMark); boat.setEstimateTimeAtNextMark(estTimeAtNextMark);
Long estTimeAtFinish = bytesToLong(Arrays.copyOfRange(payload,37 + (i * 20),43+ (i * 20))); Long estTimeAtFinish = bytesToLong(Arrays.copyOfRange(payload,38 + (i * 20),44+ (i * 20)));
boat.setEstimateTimeAtFinish(estTimeAtFinish); boat.setEstimateTimeAtFinish(estTimeAtFinish);
boatsPos.put(estTimeAtFinish, boat); boatsPos.put(estTimeAtFinish, boat);
// String boatStatus = "SourceID: " + boatStatusSourceID; // String boatStatus = "SourceID: " + boatStatusSourceID;
@@ -575,6 +577,15 @@ public class StreamParser extends Thread{
return boatsPos; return boatsPos;
} }
/**
* returns current time in stream in long
*
* @return a long value of current time
*/
public static Long getCurrentTimeLong() {
return currentTimeLong;
}
public static void appClose(){ public static void appClose(){
appRunning = false; appRunning = false;
System.out.println("[CLIENT] Shutting down stream parser"); System.out.println("[CLIENT] Shutting down stream parser");
@@ -15,7 +15,8 @@
<CheckBox fx:id="boatWakeSelect" layoutX="26.0" layoutY="80.0" mnemonicParsing="false" style="-fx-border-width: 0; -fx-background-insets: 0;" text="Boat Wakes" textFill="#e7e7e7" /> <CheckBox fx:id="boatWakeSelect" layoutX="26.0" layoutY="80.0" mnemonicParsing="false" style="-fx-border-width: 0; -fx-background-insets: 0;" text="Boat Wakes" textFill="#e7e7e7" />
<CheckBox fx:id="boatSpeedSelect" layoutX="26.0" layoutY="111.0" mnemonicParsing="false" text="Boat Speed" textFill="#e7e7e7" /> <CheckBox fx:id="boatSpeedSelect" layoutX="26.0" layoutY="111.0" mnemonicParsing="false" text="Boat Speed" textFill="#e7e7e7" />
<CheckBox fx:id="boatTrackSelect" layoutX="26.0" layoutY="142.0" mnemonicParsing="false" text="Boat Tracks" textFill="#e7e7e7" /> <CheckBox fx:id="boatTrackSelect" layoutX="26.0" layoutY="142.0" mnemonicParsing="false" text="Boat Tracks" textFill="#e7e7e7" />
<CheckBox fx:id="boatNameSelect" layoutX="26.0" layoutY="175.0" mnemonicParsing="false" text="Boat Name" textFill="#e7e7e7" /> <CheckBox fx:id="boatNameSelect" layoutX="26.0" layoutY="173.0" mnemonicParsing="false" text="Boat Name" textFill="#e7e7e7" />
<CheckBox fx:id="boatEstTimeToNextMarkSelect" layoutX="26.0" layoutY="204.0" mnemonicParsing="false" text="Boat Estimated Time To Next Mark" textFill="#e7e7e7" />
<Button fx:id="closeButton" layoutX="424.0" layoutY="-1.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="49.0" style=": 0;" text="X" textFill="#ffffff4e"> <Button fx:id="closeButton" layoutX="424.0" layoutY="-1.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="49.0" style=": 0;" text="X" textFill="#ffffff4e">
<font> <font>
<Font size="24.0" /> <Font size="24.0" />