Refactored Race, MockRace, and VisualiserRace to use RaceClock instead of keeping their own timers.
Moved FPS tracking to Race class, so both VisualiserRace and MockRace can monitor their FPS. LatestMessages is now observable. It notifies observers when an XMLMessage is received. Boat now has StringProperty for name and country/abbreviation. Moved the MockRace timescale value to Constants.RaceTimeScale. This is passed in to MockRace on construction. Tidied up StartController. Copied the visualiser's resources into the resources folder. Refactored RaceClock. Added comments. Tidied code a bit. Moved to shared.model. Started work on RaceController.
This commit is contained in:
@@ -1,133 +0,0 @@
|
||||
package visualiser.model;
|
||||
|
||||
import com.github.bfsmith.geotimezone.TimeZoneLookup;
|
||||
import com.github.bfsmith.geotimezone.TimeZoneResult;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import shared.model.GPSCoordinate;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* This class is used to implement a clock which keeps track of and
|
||||
* displays times relevant to a race. This is displayed on the
|
||||
* {@link ResizableRaceCanvas} via the
|
||||
* {@link visualiser.Controllers.RaceController} and the
|
||||
* {@link visualiser.Controllers.StartController}.
|
||||
*/
|
||||
public class RaceClock implements Runnable {
|
||||
private long lastTime;
|
||||
private final ZoneId zoneId;
|
||||
private ZonedDateTime time;
|
||||
private ZonedDateTime startingTime;
|
||||
private final StringProperty timeString;
|
||||
private StringProperty duration;
|
||||
|
||||
public RaceClock(ZonedDateTime zonedDateTime) {
|
||||
this.zoneId = zonedDateTime.getZone();
|
||||
this.timeString = new SimpleStringProperty();
|
||||
this.duration = new SimpleStringProperty();
|
||||
this.time = zonedDateTime;
|
||||
setTime(time);
|
||||
}
|
||||
|
||||
public static ZonedDateTime getCurrentZonedDateTime(GPSCoordinate gpsCoordinate) {
|
||||
TimeZoneLookup timeZoneLookup = new TimeZoneLookup();
|
||||
TimeZoneResult timeZoneResult = timeZoneLookup.getTimeZone(gpsCoordinate.getLatitude(), gpsCoordinate.getLongitude());
|
||||
ZoneId zone = ZoneId.of(timeZoneResult.getResult());
|
||||
return LocalDateTime.now(zone).atZone(zone);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
new AnimationTimer() {
|
||||
@Override
|
||||
public void handle(long now) {
|
||||
updateTime();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets time to arbitrary zoned time.
|
||||
*
|
||||
* @param time arbitrary time with timezone.
|
||||
*/
|
||||
private void setTime(ZonedDateTime time) {
|
||||
this.time = time;
|
||||
this.timeString.set(DateTimeFormatter.ofPattern("HH:mm:ss dd/MM/YYYY Z").format(time));
|
||||
this.lastTime = System.currentTimeMillis();
|
||||
|
||||
|
||||
if(startingTime != null) {
|
||||
long seconds = Duration.between(startingTime.toLocalDateTime(), time.toLocalDateTime()).getSeconds();
|
||||
if(seconds < 0)
|
||||
duration.set(String.format("Starting in: %02d:%02d:%02d", -seconds/3600, -(seconds%3600)/60, -seconds%60));
|
||||
else
|
||||
duration.set(String.format("Time: %02d:%02d:%02d", seconds/3600, (seconds%3600)/60, seconds%60));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets time to given UTC time in seconds from Unix epoch, preserving timezone.
|
||||
* @param time UTC time
|
||||
*/
|
||||
public void setUTCTime(long time) {
|
||||
Date utcTime = new Date(time);
|
||||
setTime(utcTime.toInstant().atZone(this.zoneId));
|
||||
}
|
||||
|
||||
public ZonedDateTime getStartingTime() {
|
||||
return startingTime;
|
||||
}
|
||||
|
||||
public void setStartingTime(ZonedDateTime startingTime) {
|
||||
this.startingTime = startingTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ZonedDateTime corresponding to local time zone and given UTC time.
|
||||
* @param time time in mills
|
||||
* @return local date time
|
||||
*/
|
||||
public ZonedDateTime getLocalTime(long time) {
|
||||
Date utcTime = new Date(time);
|
||||
return utcTime.toInstant().atZone(this.zoneId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates time by duration elapsed since last update.
|
||||
*/
|
||||
private void updateTime() {
|
||||
this.time = this.time.plus(Duration.of(System.currentTimeMillis() - this.lastTime, ChronoUnit.MILLIS));
|
||||
this.lastTime = System.currentTimeMillis();
|
||||
setTime(time);
|
||||
}
|
||||
|
||||
public String getDuration() {
|
||||
return duration.get();
|
||||
}
|
||||
|
||||
public StringProperty durationProperty() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public String getTimeZone() {
|
||||
return zoneId.toString();
|
||||
}
|
||||
|
||||
public ZonedDateTime getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public StringProperty timeStringProperty() {
|
||||
return timeString;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import javafx.scene.transform.Rotate;
|
||||
import seng302.Mock.StreamedCourse;
|
||||
import seng302.RaceDataSource;
|
||||
import seng302.RaceMap;
|
||||
import shared.model.RaceClock;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class Sparkline {
|
||||
private ArrayList<String> colours;
|
||||
private ArrayList<Boat> startBoats = new ArrayList<>();
|
||||
private ArrayList<VisualiserBoat> startBoats = new ArrayList<>();
|
||||
private Map<Integer, String> boatColours = new HashMap<>();
|
||||
private Integer legNum;
|
||||
private Integer sparkLineNumber = 0;
|
||||
|
||||
@@ -15,9 +15,7 @@ import shared.dataInput.BoatDataSource;
|
||||
import shared.dataInput.RaceDataSource;
|
||||
import shared.dataInput.RegattaDataSource;
|
||||
import shared.model.*;
|
||||
import visualiser.Controllers.FinishController;
|
||||
import visualiser.Controllers.RaceController;
|
||||
import visualiser.app.VisualiserInput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -41,10 +39,6 @@ public class VisualiserRace extends Race {
|
||||
*/
|
||||
private ObservableList<Mark> boatMarkers;
|
||||
|
||||
//TODO remove these controller references once refactored
|
||||
private RaceController controller;
|
||||
protected FinishController finishController;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -52,10 +46,10 @@ public class VisualiserRace extends Race {
|
||||
* @param boatDataSource Data source for boat related data (yachts and marker boats).
|
||||
* @param raceDataSource Data source for race related data (participating boats, legs, etc...).
|
||||
* @param regattaDataSource Data source for race related data (course name, location, timezone, etc...).
|
||||
* @param colors A collection of colors used to assign a color to each boat.
|
||||
* @param latestMessages The LatestMessages to send events to.
|
||||
* @param colors A collection of colors used to assign a color to each boat.
|
||||
*/
|
||||
public VisualiserRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, List<Color> colors, LatestMessages latestMessages, RaceController controller) {
|
||||
public VisualiserRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, LatestMessages latestMessages, List<Color> colors) {
|
||||
|
||||
super(boatDataSource, raceDataSource, regattaDataSource, latestMessages);
|
||||
|
||||
@@ -64,9 +58,6 @@ public class VisualiserRace extends Race {
|
||||
|
||||
this.boatMarkers = FXCollections.observableArrayList(boatDataSource.getMarkerBoats().values());
|
||||
|
||||
|
||||
this.controller = controller;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +139,7 @@ public class VisualiserRace extends Race {
|
||||
for (VisualiserBoat boat : boats) {
|
||||
|
||||
boat.setCurrentLeg(startingLeg);
|
||||
boat.setTimeSinceLastMark(controller.getRaceClock().getTime());
|
||||
boat.setTimeSinceLastMark(this.raceClock.getCurrentTime());
|
||||
|
||||
}
|
||||
|
||||
@@ -209,7 +200,7 @@ public class VisualiserRace extends Race {
|
||||
if (legNumber >= 1 && legNumber < legs.size()) {
|
||||
if (boat.getCurrentLeg() != legs.get(legNumber)) {
|
||||
boat.setCurrentLeg(legs.get(legNumber));
|
||||
boat.setTimeSinceLastMark(controller.getRaceClock().getTime());
|
||||
boat.setTimeSinceLastMark(this.raceClock.getCurrentTime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,54 +270,41 @@ public class VisualiserRace extends Race {
|
||||
//Wind speed.
|
||||
this.windSpeed = raceStatus.getWindSpeedKnots();
|
||||
|
||||
//Current race time.
|
||||
this.raceClock.setUTCTime(raceStatus.getCurrentTime());
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setController(RaceController controller) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runnable for the thread.
|
||||
*/
|
||||
public void run() {
|
||||
setControllerListeners();
|
||||
Platform.runLater(() -> controller.createSparkLine(boats));
|
||||
initialiseBoats();
|
||||
startRaceStream();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the calculated fps to the fps label
|
||||
*
|
||||
* @param fps The new calculated fps value
|
||||
*/
|
||||
private void updateFPS(int fps) {
|
||||
Platform.runLater(() -> controller.setFrames("FPS: " + fps));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts the Race Simulation, playing the race start to finish with the timescale.
|
||||
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events.
|
||||
* Starts the race.
|
||||
* This updates the race based on {@link #latestMessages}.
|
||||
*/
|
||||
private void startRaceStream() {
|
||||
|
||||
System.setProperty("javafx.animation.fullspeed", "true");
|
||||
|
||||
|
||||
|
||||
new AnimationTimer() {
|
||||
|
||||
final long timeRaceStarted = System.currentTimeMillis(); //start time of loop
|
||||
//final long timeRaceStarted = System.currentTimeMillis(); //start time of loop
|
||||
int fps = 0; //init fps value
|
||||
long timeCurrent = System.currentTimeMillis(); //current time
|
||||
//long timeCurrent = System.currentTimeMillis(); //current time
|
||||
|
||||
@Override
|
||||
public void handle(long arg0) {
|
||||
|
||||
totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted;
|
||||
//totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted;
|
||||
|
||||
|
||||
|
||||
@@ -343,22 +321,11 @@ public class VisualiserRace extends Race {
|
||||
updateRaceStatus(latestMessages.getRaceStatus());
|
||||
|
||||
|
||||
//TODO tidy this circular dependency up
|
||||
if (getRaceStatusEnum() == RaceStatusEnum.FINISHED) {
|
||||
controller.finishRace(boats);
|
||||
stop();
|
||||
}
|
||||
|
||||
controller.updateMap(boats, boatMarkers);
|
||||
|
||||
fps++;
|
||||
|
||||
if ((System.currentTimeMillis() - timeCurrent) > 1000) {
|
||||
updateFPS(fps);
|
||||
lastFPS = fps;
|
||||
fps = 0;
|
||||
timeCurrent = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
@@ -400,12 +367,7 @@ public class VisualiserRace extends Race {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update call for the controller.
|
||||
*/
|
||||
private void setControllerListeners() {
|
||||
if (controller != null) controller.setInfoTable(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the boats participating in the race.
|
||||
|
||||
Reference in New Issue
Block a user