Merge branch 'master' into issue_18_trackpoint
This commit is contained in:
@@ -40,6 +40,7 @@ public class Annotations {
|
||||
private static String pathCheckAnno = "showBoatPath";
|
||||
private static String timeCheckAnno = "showTime";
|
||||
private static String estTimeCheckAnno = "showEstTime";
|
||||
private static String guideLineAnno = "showGuideline";
|
||||
|
||||
// string values match the fx:id value of radio buttons
|
||||
private static String noBtn = "noBtn";
|
||||
@@ -160,6 +161,16 @@ public class Annotations {
|
||||
raceMap.draw();
|
||||
}
|
||||
});
|
||||
|
||||
//listener to show estimated time for annotation
|
||||
checkBoxes.get(guideLineAnno).selectedProperty()
|
||||
.addListener((ov, old_val, new_val) -> {
|
||||
if (old_val != new_val) {
|
||||
raceMap.toggleGuideLine();
|
||||
storeCurrentAnnotationState(guideLineAnno, new_val);
|
||||
raceMap.draw();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,9 +7,8 @@ import javafx.scene.paint.Paint;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import network.Messages.Enums.BoatStatusEnum;
|
||||
import shared.dataInput.RaceDataSource;
|
||||
import shared.model.GPSCoordinate;
|
||||
import shared.model.Mark;
|
||||
import shared.model.RaceClock;
|
||||
import shared.enums.RoundingType;
|
||||
import shared.model.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -46,6 +45,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
private boolean annoPath = true;
|
||||
private boolean annoEstTime = true;
|
||||
private boolean annoTimeSinceLastMark = true;
|
||||
private boolean annoGuideLine = false;
|
||||
|
||||
|
||||
|
||||
@@ -113,6 +113,13 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
annoSpeed = !annoSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the guideline annotation
|
||||
*/
|
||||
public void toggleGuideLine() {
|
||||
annoGuideLine = !annoGuideLine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -313,40 +320,36 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
*/
|
||||
private void drawBoat(VisualiserBoat boat) {
|
||||
|
||||
//The position may be null if we haven't received any BoatLocation messages yet.
|
||||
if (boat.getCurrentPosition() != null) {
|
||||
|
||||
if (boat.isClientBoat()) {
|
||||
drawClientBoat(boat);
|
||||
}
|
||||
|
||||
//Convert position to graph coordinate.
|
||||
GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition());
|
||||
|
||||
//The x coordinates of each vertex of the boat.
|
||||
double[] x = {
|
||||
pos.getX() - 6,
|
||||
pos.getX(),
|
||||
pos.getX() + 6 };
|
||||
|
||||
//The y coordinates of each vertex of the boat.
|
||||
double[] y = {
|
||||
pos.getY() + 12,
|
||||
pos.getY() - 12,
|
||||
pos.getY() + 12 };
|
||||
|
||||
//The above shape is essentially a triangle 12px wide, and 24px long.
|
||||
|
||||
//Draw the boat.
|
||||
gc.setFill(boat.getColor());
|
||||
|
||||
gc.save();
|
||||
rotate(boat.getBearing().degrees(), pos.getX(), pos.getY());
|
||||
gc.fillPolygon(x, y, 3);
|
||||
gc.restore();
|
||||
|
||||
if (boat.isClientBoat()) {
|
||||
drawClientBoat(boat);
|
||||
}
|
||||
|
||||
//Convert position to graph coordinate.
|
||||
GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition());
|
||||
|
||||
//The x coordinates of each vertex of the boat.
|
||||
double[] x = {
|
||||
pos.getX() - 6,
|
||||
pos.getX(),
|
||||
pos.getX() + 6 };
|
||||
|
||||
//The y coordinates of each vertex of the boat.
|
||||
double[] y = {
|
||||
pos.getY() + 12,
|
||||
pos.getY() - 12,
|
||||
pos.getY() + 12 };
|
||||
|
||||
//The above shape is essentially a triangle 12px wide, and 24px long.
|
||||
|
||||
//Draw the boat.
|
||||
gc.setFill(boat.getColor());
|
||||
|
||||
gc.save();
|
||||
rotate(boat.getBearing().degrees(), pos.getX(), pos.getY());
|
||||
gc.fillPolygon(x, y, 3);
|
||||
gc.restore();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,6 +503,11 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
//Race boundary.
|
||||
drawBoundary();
|
||||
|
||||
//Guiding Line
|
||||
if (annoGuideLine){
|
||||
drawRaceLine();
|
||||
}
|
||||
|
||||
//Boats.
|
||||
drawBoats();
|
||||
|
||||
@@ -508,6 +516,140 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* draws a transparent line around the course that shows the paths boats must travel
|
||||
*/
|
||||
public void drawRaceLine(){
|
||||
List<Leg> legs = this.visualiserRace.getVisualiserRaceState().getLegs();
|
||||
GPSCoordinate legStartPoint = legs.get(0).getStartCompoundMark().getAverageGPSCoordinate();
|
||||
GPSCoordinate nextStartPoint;
|
||||
for (int i = 0; i < legs.size() -1; i++) {
|
||||
nextStartPoint = drawLineRounding(legs, i, legStartPoint);
|
||||
legStartPoint = nextStartPoint;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a line around a course that shows where boats need to go. This method
|
||||
* draws the line leg by leg
|
||||
* @param legs the legs of a race
|
||||
* @param index the index of the current leg to use
|
||||
* @param legStartPoint The position the current leg.
|
||||
* @return the end point of the current leg that has been drawn
|
||||
*/
|
||||
private GPSCoordinate drawLineRounding(List<Leg> legs, int index, GPSCoordinate legStartPoint){
|
||||
GPSCoordinate startDirectionLinePoint;
|
||||
GPSCoordinate endDirectionLinePoint;
|
||||
Bearing bearingOfDirectionLine;
|
||||
|
||||
GPSCoordinate startNextDirectionLinePoint;
|
||||
GPSCoordinate endNextDirectionLinePoint;
|
||||
Bearing bearingOfNextDirectionLine;
|
||||
|
||||
//finds the direction of the current leg as a bearing
|
||||
startDirectionLinePoint = legStartPoint;
|
||||
GPSCoordinate tempEndDirectionLinePoint = legs.get(index).getEndCompoundMark().getAverageGPSCoordinate();
|
||||
|
||||
bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, tempEndDirectionLinePoint);
|
||||
|
||||
//after finding the initial bearing pick the mark used for rounding
|
||||
endDirectionLinePoint = legs.get(index).getEndCompoundMark().getMarkForRounding(bearingOfDirectionLine).getPosition();
|
||||
bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint);
|
||||
|
||||
//finds the direction of the next leg as a bearing
|
||||
if (index < legs.size() -2){ // not last leg
|
||||
startNextDirectionLinePoint = legs.get(index + 1).getStartCompoundMark().getMark1Position();
|
||||
endNextDirectionLinePoint = legs.get(index + 1).getEndCompoundMark().getMark1Position();
|
||||
bearingOfNextDirectionLine = GPSCoordinate.calculateBearing(startNextDirectionLinePoint, endNextDirectionLinePoint);
|
||||
|
||||
double degreesToAdd;
|
||||
//find which side is need to be used
|
||||
if (legs.get(index).getEndCompoundMark().getRoundingType() == RoundingType.Port ||
|
||||
legs.get(index).getEndCompoundMark().getRoundingType() == RoundingType.SP){
|
||||
degreesToAdd = 90;
|
||||
}else{
|
||||
degreesToAdd = -90;
|
||||
}
|
||||
|
||||
//use the direction line to find a point parallel to it by the mark
|
||||
GPSCoordinate pointToStartCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint,
|
||||
100, Azimuth.fromDegrees(bearingOfDirectionLine.degrees()+degreesToAdd));
|
||||
|
||||
//use the direction line to find a point to curve too
|
||||
GPSCoordinate pointToEndCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint,
|
||||
100, Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees()+degreesToAdd));
|
||||
|
||||
//use the curve points to find the two control points for the bezier curve
|
||||
GPSCoordinate controlPoint;
|
||||
GPSCoordinate controlPoint2;
|
||||
Bearing bearingOfCurveLine = GPSCoordinate.calculateBearing(pointToStartCurve, pointToEndCurve);
|
||||
if ((bearingOfDirectionLine.degrees() - bearingOfNextDirectionLine.degrees() +360)%360< 145){
|
||||
//small turn
|
||||
controlPoint = GPSCoordinate.calculateNewPosition(pointToStartCurve,
|
||||
50, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+(degreesToAdd/2)));
|
||||
controlPoint2 = controlPoint;
|
||||
}else{
|
||||
//large turn
|
||||
controlPoint = GPSCoordinate.calculateNewPosition(pointToStartCurve,
|
||||
150, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+degreesToAdd));
|
||||
controlPoint2 = GPSCoordinate.calculateNewPosition(pointToEndCurve,
|
||||
150, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+degreesToAdd));
|
||||
}
|
||||
|
||||
|
||||
//change all gps into graph coordinate
|
||||
GraphCoordinate startPath = this.map.convertGPS(startDirectionLinePoint);
|
||||
GraphCoordinate curvePoint = this.map.convertGPS(pointToStartCurve);
|
||||
GraphCoordinate curvePointEnd = this.map.convertGPS(pointToEndCurve);
|
||||
GraphCoordinate c1 = this.map.convertGPS(controlPoint);
|
||||
GraphCoordinate c2 = this.map.convertGPS(controlPoint2);
|
||||
|
||||
gc.setLineWidth(2);
|
||||
gc.setStroke(Color.MEDIUMAQUAMARINE);
|
||||
|
||||
gc.beginPath();
|
||||
gc.moveTo(startPath.getX(), startPath.getY());
|
||||
gc.lineTo(curvePoint.getX(), curvePoint.getY());
|
||||
drawArrowHead(startDirectionLinePoint, pointToStartCurve);
|
||||
gc.bezierCurveTo(c1.getX(), c1.getY(), c2.getX(), c2.getY(), curvePointEnd.getX(), curvePointEnd.getY());
|
||||
gc.stroke();
|
||||
gc.closePath();
|
||||
gc.save();
|
||||
|
||||
return pointToEndCurve;
|
||||
}else{//last leg so no curve
|
||||
GraphCoordinate startPath = this.map.convertGPS(legStartPoint);
|
||||
GraphCoordinate endPath = this.map.convertGPS(legs.get(index).getEndCompoundMark().getAverageGPSCoordinate());
|
||||
|
||||
gc.beginPath();
|
||||
gc.moveTo(startPath.getX(), startPath.getY());
|
||||
gc.lineTo(endPath.getX(), endPath.getY());
|
||||
gc.stroke();
|
||||
gc.closePath();
|
||||
gc.save();
|
||||
drawArrowHead(legStartPoint, legs.get(index).getEndCompoundMark().getAverageGPSCoordinate());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void drawArrowHead(GPSCoordinate start, GPSCoordinate end){
|
||||
|
||||
GraphCoordinate lineStart = this.map.convertGPS(start);
|
||||
GraphCoordinate lineEnd = this.map.convertGPS(end);
|
||||
|
||||
double arrowAngle = Math.toRadians(45.0);
|
||||
double arrowLength = 10.0;
|
||||
double dx = lineStart.getX() - lineEnd.getX();
|
||||
double dy = lineStart.getY() - lineEnd.getY();
|
||||
double angle = Math.atan2(dy, dx);
|
||||
double x1 = Math.cos(angle + arrowAngle) * arrowLength + lineEnd.getX();
|
||||
double y1 = Math.sin(angle + arrowAngle) * arrowLength + lineEnd.getY();
|
||||
|
||||
double x2 = Math.cos(angle - arrowAngle) * arrowLength + lineEnd.getX();
|
||||
double y2 = Math.sin(angle - arrowAngle) * arrowLength + lineEnd.getY();
|
||||
gc.strokeLine(lineEnd.getX(), lineEnd.getY(), x1, y1);
|
||||
gc.strokeLine(lineEnd.getX(), lineEnd.getY(), x2, y2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -519,7 +661,6 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
* @see TrackPoint
|
||||
*/
|
||||
private void drawTrack(VisualiserBoat boat) {
|
||||
|
||||
//Check that track points are enabled.
|
||||
if (this.annoPath) {
|
||||
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package visualiser.model;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
import javafx.scene.chart.LineChart;
|
||||
import javafx.scene.chart.NumberAxis;
|
||||
import javafx.scene.chart.XYChart;
|
||||
import javafx.scene.paint.Color;
|
||||
import shared.model.Leg;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
@@ -32,10 +36,10 @@ public class Sparkline {
|
||||
private ObservableList<VisualiserBoat> boats;
|
||||
|
||||
/**
|
||||
* The number of legs in the race.
|
||||
* Used to correctly scale the linechart.
|
||||
* Race legs to observe.
|
||||
* We need to observe legs as they may be added after the sparkline is created if race.xml is received after this is created.
|
||||
*/
|
||||
private Integer legNum;
|
||||
private ObservableList<Leg> legs;
|
||||
|
||||
|
||||
/**
|
||||
@@ -53,21 +57,31 @@ public class Sparkline {
|
||||
*/
|
||||
private NumberAxis yAxis;
|
||||
|
||||
/**
|
||||
* A map between a boat and its data series in the sparkline.
|
||||
* This is used so that we can remove a series when (or if) a boat is removed from the race.
|
||||
*/
|
||||
private Map<VisualiserBoat, XYChart.Series<Number, Number>> boatSeriesMap;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor to set up initial sparkline (LineChart) object
|
||||
* @param race The race to listen to.
|
||||
* @param sparklineChart JavaFX LineChart for the sparkline.
|
||||
*/
|
||||
public Sparkline(VisualiserRaceState race, LineChart<Number,Number> sparklineChart) {
|
||||
public Sparkline(VisualiserRaceState race, LineChart<Number, Number> sparklineChart) {
|
||||
this.race = race;
|
||||
this.boats = new SortedList<>(race.getBoats());
|
||||
this.legNum = race.getLegCount();
|
||||
this.legs = race.getLegs();
|
||||
|
||||
this.sparklineChart = sparklineChart;
|
||||
this.yAxis = (NumberAxis) sparklineChart.getYAxis();
|
||||
this.xAxis = (NumberAxis) sparklineChart.getXAxis();
|
||||
|
||||
this.boatSeriesMap = new HashMap<>();
|
||||
|
||||
createSparkline();
|
||||
|
||||
}
|
||||
@@ -79,50 +93,45 @@ public class Sparkline {
|
||||
* Position numbers are displayed.
|
||||
*/
|
||||
private void createSparkline() {
|
||||
// NOTE: Y axis is in negatives to display correct positions
|
||||
|
||||
//For each boat...
|
||||
for (VisualiserBoat boat : this.boats) {
|
||||
//We need to dynamically update the sparkline when boats are added/removed.
|
||||
boats.addListener((ListChangeListener.Change<? extends VisualiserBoat> c) -> {
|
||||
|
||||
//Create data series for each boat.
|
||||
XYChart.Series<Number, Number> series = new XYChart.Series<>();
|
||||
Platform.runLater(() -> {
|
||||
|
||||
while (c.next()) {
|
||||
|
||||
if (c.wasAdded()) {
|
||||
for (VisualiserBoat boat : c.getAddedSubList()) {
|
||||
addBoatSeries(boat);
|
||||
}
|
||||
|
||||
} else if (c.wasRemoved()) {
|
||||
for (VisualiserBoat boat : c.getRemoved()) {
|
||||
removeBoatSeries(boat);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Update height of y axis.
|
||||
setYAxisLowerBound();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
//All boats start in "last" place.
|
||||
series.getData().add(new XYChart.Data<>(0, boats.size()));
|
||||
|
||||
//Listen for changes in the boat's leg - we only update the graph when it changes leg.
|
||||
boat.legProperty().addListener(
|
||||
(observable, oldValue, newValue) -> {
|
||||
|
||||
//Get the data to plot.
|
||||
List<VisualiserBoat> boatOrder = race.getLegCompletionOrder().get(oldValue);
|
||||
//Find boat position in list.
|
||||
int boatPosition = boatOrder.indexOf(boat) + 1;
|
||||
|
||||
//Get leg number.
|
||||
int legNumber = oldValue.getLegNumber() + 1;
|
||||
|
||||
|
||||
//Create new data point for boat's position at the new leg.
|
||||
XYChart.Data<Number, Number> dataPoint = new XYChart.Data<>(legNumber, boatPosition);
|
||||
|
||||
//Add to series.
|
||||
Platform.runLater(() -> series.getData().add(dataPoint));
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
//Add to chart.
|
||||
sparklineChart.getData().add(series);
|
||||
|
||||
//Color using boat's color. We need to do this after adding the series to a chart, otherwise we get null pointer exceptions.
|
||||
series.getNode().setStyle("-fx-stroke: " + colourToHex(boat.getColor()) + ";");
|
||||
legs.addListener((ListChangeListener.Change<? extends Leg> c) -> {
|
||||
Platform.runLater(() -> xAxis.setUpperBound(race.getLegCount()));
|
||||
});
|
||||
|
||||
|
||||
//Initialise chart for existing boats.
|
||||
for (VisualiserBoat boat : boats) {
|
||||
addBoatSeries(boat);
|
||||
}
|
||||
|
||||
|
||||
sparklineChart.setCreateSymbols(false);
|
||||
|
||||
//Set x axis details
|
||||
@@ -131,20 +140,109 @@ public class Sparkline {
|
||||
xAxis.setTickLabelsVisible(false);
|
||||
xAxis.setMinorTickVisible(false);
|
||||
xAxis.setLowerBound(0);
|
||||
xAxis.setUpperBound(legNum + 2);
|
||||
xAxis.setUpperBound(race.getLegCount());
|
||||
xAxis.setTickUnit(1);
|
||||
|
||||
|
||||
//The y-axis uses negative values, with the minus sign hidden (e.g., boat in 1st has position -1, which becomes 1, boat in 6th has position -6, which becomes 6).
|
||||
//This is necessary to actually get the y-axis labelled correctly. Negative tick count doesn't work.
|
||||
//Set y axis details
|
||||
yAxis.setLowerBound(boats.size());
|
||||
yAxis.setUpperBound(1);
|
||||
yAxis.setAutoRanging(false);
|
||||
|
||||
yAxis.setTickUnit(1);
|
||||
yAxis.setMinorTickCount(0);
|
||||
|
||||
yAxis.setUpperBound(0);
|
||||
setYAxisLowerBound();
|
||||
|
||||
yAxis.setLabel("Position in Race");
|
||||
yAxis.setTickUnit(-1);//Negative tick reverses the y axis.
|
||||
|
||||
yAxis.setTickMarkVisible(true);
|
||||
yAxis.setTickLabelsVisible(true);
|
||||
yAxis.setTickMarkVisible(true);
|
||||
yAxis.setMinorTickVisible(true);
|
||||
yAxis.setMinorTickVisible(false);
|
||||
|
||||
|
||||
|
||||
//Hide minus number from displaying on axis.
|
||||
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
|
||||
@Override
|
||||
public String toString(Number value) {
|
||||
if ((value.intValue() == 0) || (value.intValue() < -boats.size())) {
|
||||
return "";
|
||||
|
||||
} else {
|
||||
return String.format("%d", -value.intValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the lower bound of the y-axis.
|
||||
*/
|
||||
private void setYAxisLowerBound() {
|
||||
yAxis.setLowerBound( -(boats.size() + 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Removes the data series for a given boat from the sparkline.
|
||||
* @param boat Boat to remove series for.
|
||||
*/
|
||||
private void removeBoatSeries(VisualiserBoat boat) {
|
||||
sparklineChart.getData().remove(boatSeriesMap.get(boat));
|
||||
boatSeriesMap.remove(boat);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a data series for a boat, and adds it to the sparkline.
|
||||
* @param boat Boat to add series for.
|
||||
*/
|
||||
private void addBoatSeries(VisualiserBoat boat) {
|
||||
|
||||
//Create data series for boat.
|
||||
XYChart.Series<Number, Number> series = new XYChart.Series<>();
|
||||
|
||||
|
||||
//All boats start in "last" place.
|
||||
series.getData().add(new XYChart.Data<>(0, -(boats.size())));
|
||||
|
||||
//Listen for changes in the boat's leg - we only update the graph when it changes leg.
|
||||
boat.legProperty().addListener(
|
||||
(observable, oldValue, newValue) -> {
|
||||
|
||||
//Get the data to plot.
|
||||
List<VisualiserBoat> boatOrder = race.getLegCompletionOrder().get(oldValue);
|
||||
//Find boat position in list.
|
||||
int boatPosition = -(boatOrder.indexOf(boat) + 1);
|
||||
|
||||
//Get leg number.
|
||||
int legNumber = oldValue.getLegNumber() + 1;
|
||||
|
||||
|
||||
//Create new data point for boat's position at the new leg.
|
||||
XYChart.Data<Number, Number> dataPoint = new XYChart.Data<>(legNumber, boatPosition);
|
||||
|
||||
//Add to series.
|
||||
Platform.runLater(() -> series.getData().add(dataPoint));
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
//Add to chart.
|
||||
sparklineChart.getData().add(series);
|
||||
|
||||
//Color using boat's color. We need to do this after adding the series to a chart, otherwise we get null pointer exceptions.
|
||||
series.getNode().setStyle("-fx-stroke: " + colourToHex(boat.getColor()) + ";");
|
||||
|
||||
|
||||
boatSeriesMap.put(boat, series);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ public class VisualiserBoat extends Boat {
|
||||
*/
|
||||
public String getTimeToNextMarkFormatted(ZonedDateTime currentTime) {
|
||||
|
||||
if (getTimeAtLastMark() != null) {
|
||||
if ((getTimeAtLastMark() != null) && (currentTime != null)) {
|
||||
//Calculate time delta.
|
||||
Duration timeUntil = Duration.between(currentTime, getEstimatedTimeAtNextMark());
|
||||
|
||||
@@ -211,7 +211,7 @@ public class VisualiserBoat extends Boat {
|
||||
*/
|
||||
public String getTimeSinceLastMarkFormatted(ZonedDateTime currentTime) {
|
||||
|
||||
if (getTimeAtLastMark() != null) {
|
||||
if ((getTimeAtLastMark() != null) && (currentTime != null)) {
|
||||
//Calculate time delta.
|
||||
Duration timeSince = Duration.between(getTimeAtLastMark(), currentTime);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package visualiser.model;
|
||||
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.paint.Color;
|
||||
@@ -97,7 +98,7 @@ public class VisualiserRaceState extends RaceState {
|
||||
this.generateVisualiserBoats(this.boats, getBoatDataSource().getBoats(), raceDataSource.getParticipants(), unassignedColors);
|
||||
}
|
||||
|
||||
useLegsList(raceDataSource.getLegs());
|
||||
initialiseLegCompletionOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,14 +126,9 @@ public class VisualiserRaceState extends RaceState {
|
||||
|
||||
|
||||
/**
|
||||
* See {@link RaceState#useLegsList(List)}.
|
||||
* Also initialises the {@link #legCompletionOrder} map.
|
||||
* @param legs The new list of legs to use.
|
||||
* Initialises the {@link #legCompletionOrder} map.
|
||||
*/
|
||||
@Override
|
||||
public void useLegsList(List<Leg> legs) {
|
||||
super.useLegsList(legs);
|
||||
|
||||
public void initialiseLegCompletionOrder() {
|
||||
//Initialise the leg completion order map.
|
||||
for (Leg leg : getLegs()) {
|
||||
this.legCompletionOrder.put(leg, new ArrayList<>(this.boats.size()));
|
||||
@@ -206,7 +202,7 @@ public class VisualiserRaceState extends RaceState {
|
||||
|
||||
if (getPlayerBoatID() != 0) {
|
||||
|
||||
for (VisualiserBoat boat : getBoats()) {
|
||||
for (VisualiserBoat boat : new ArrayList<>(getBoats())) {
|
||||
|
||||
if (boat.getSourceID() == getPlayerBoatID()) {
|
||||
boat.setClientBoat(true);
|
||||
|
||||
Reference in New Issue
Block a user