I had accidentally broken the raceXML construction - fixed it.

Fixed a few issues where boat didn't have nextMark/previousMark times under certain circumstances.
LatestMessages wasn't actually notifying properly - fixed.
The various XML readers now treat a string constructor as containing file contents, not file name - this was how it was mostly already used.
Fixed some issues in RaceXMLReader, including where element.getChildNodes() was used instead of element.getElementsByName(...).
Boat: changes speed to a doubleProperty. Changed leg to a Property<Leg>.
Race.lastFps is now an IntegerProperty.
Added breaks to the case statements in VisualiserInput. Whoops.
ResizableRaceCanvas now handles drawing the race boundary. Tidied up code a bit.
Removed ResizableRaceMap.

Started refactoring Sparkline. Currently doesn't work.
This commit is contained in:
fjc40
2017-07-10 08:35:43 +12:00
parent abbbf70146
commit 7d3cf6ee80
38 changed files with 1414 additions and 775 deletions
@@ -1,17 +1,16 @@
package visualiser.model;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.paint.Color;
import network.Messages.Enums.BoatStatusEnum;
import org.geotools.referencing.GeodeticCalculator;
import shared.model.Azimuth;
import shared.model.Boat;
import shared.model.Constants;
import shared.model.GPSCoordinate;
import java.awt.geom.Point2D;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a Boat on the visualiser side of a race.
@@ -27,33 +26,40 @@ public class VisualiserBoat extends Boat {
/**
* The collection of trackpoints generated for the boat.
*/
private final Queue<TrackPoint> track = new ConcurrentLinkedQueue<>();
private final List<TrackPoint> track = new ArrayList<>();
/**
* The next time, in milliseconds since unix epoch, at which we may create a new track point.
*/
private long nextValidTime = 0;
private ZonedDateTime timeSinceLastMark;
/**
* The minimum period of time, in milliseconds, between the creation of each track point.
*/
private static final long trackPointTimeInterval = 5000;
/**
* The number of track points that should be created before fully diminishing the alpha of a given track point.
*/
private static final int trackPointLimit = 10;
/**
* The boat's color.
*/
private Color color;
/**
* Boat initializer which keeps all of the information of the boat.
*
* @param sourceID The source ID of the boat.
* @param name Name of the Boat.
* @param abbrev The team/country abbreviation of the boat.
* @param color The color of the boat.
* Scalar used to scale the boat's wake.
*/
public VisualiserBoat(int sourceID, String name, String abbrev, Color color) {
super(sourceID, name, abbrev);
private static final double wakeScale = 5;
this.color = color;
}
/**
* Constructs a mock boat object from a given boat and polars table.
* Constructs a boat object from a given boat and color.
*
* @param boat The boat to convert into a MockBoat.
* @param color The color of the boat.
@@ -73,41 +79,62 @@ public class VisualiserBoat extends Boat {
* @return GPSCoordinate of wake endpoint.
*/
public GPSCoordinate getWake() {
double reverseHeading = getBearing().degrees() - 180;
double wakeScale = 5;
double distance = wakeScale * getCurrentSpeed();
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(
new Point2D.Double(getCurrentPosition().getLongitude(), getCurrentPosition().getLatitude())
);
calc.setDirection(reverseHeading, distance);
Point2D endpoint = calc.getDestinationGeographicPoint();
return new GPSCoordinate(endpoint.getY(), endpoint.getX());
//Calculate the reverse bearing of the boat, and convert it to an azimuth.
Azimuth reverseAzimuth = Azimuth.fromDegrees(getBearing().degrees() - 180d);
//Calculate the distance, in meters, of the wake.
//We currently use boat's speed, in meters per second, to calculate the wake length. Could maybe move the knot -> m/s calculation somewhere else.
double speedKnots = getCurrentSpeed();
double speedMetersPerHour = speedKnots * Constants.NMToMetersConversion;
double speedMetersPerSecond = speedMetersPerHour / Constants.OneHourSeconds;
double wakeDistanceMeters = speedMetersPerSecond * this.wakeScale;
//Calculate the new coordinate.
GPSCoordinate wakeCoordinate = GPSCoordinate.calculateNewPosition(getCurrentPosition(), wakeDistanceMeters, reverseAzimuth);
return wakeCoordinate;
}
/**
* Adds a new point to boat's track.
* @param coordinate of point on track
* Attempts to add a new point to boat's track.
* It only adds a new point if the boat is still racing (see {@link #getStatus()} and {@link BoatStatusEnum#RACING}), and if at least {@link #trackPointTimeInterval} milliseconds have occurred.
* @param coordinate The {@link GPSCoordinate} of the trackpoint.
* @see TrackPoint
*/
public void addTrackPoint(GPSCoordinate coordinate) {
Boolean added = System.currentTimeMillis() >= nextValidTime;
//Get current time.
long currentTime = System.currentTimeMillis();
if (added && (this.getStatus() == BoatStatusEnum.RACING)) {
float trackPointTimeInterval = 5000;
nextValidTime = currentTime + (long) trackPointTimeInterval;
int TRACK_POINT_LIMIT = 10;
track.add(new TrackPoint(coordinate, currentTime, TRACK_POINT_LIMIT * (long) trackPointTimeInterval));
//Check if enough time has passed to create a new track point.
Boolean canBeAdded = currentTime >= nextValidTime;
//If it has, and if we are still racing, create the point.
if (canBeAdded && (getStatus() == BoatStatusEnum.RACING)) {
//Calculate the period of time that it should take the track point to diminish over. We essentially allow for trackPointLimit number of track points to be created before it should fade out.
long expiryPeriod = trackPointTimeInterval * trackPointLimit;
//Create and add point.
TrackPoint trackPoint = new TrackPoint(coordinate, currentTime, expiryPeriod);
track.add(trackPoint);
//Update the nextValidTime for the next track point.
nextValidTime = currentTime + trackPointTimeInterval;
}
}
/**
* Returns the boat's sampled track between start of race and current time.
* @return queue of track points
* @return The list of track points.
* @see TrackPoint
*/
public Queue<TrackPoint> getTrack() {
public List<TrackPoint> getTrack() {
return track;
}
@@ -128,27 +155,59 @@ public class VisualiserBoat extends Boat {
return getName();
}
public ZonedDateTime getTimeSinceLastMark() {
return timeSinceLastMark;
}
public void setTimeSinceLastMark(ZonedDateTime timeSinceLastMark) {
this.timeSinceLastMark = timeSinceLastMark;
}
public String getFormattedEstTime() {
if (getEstimatedTime() < 0) {
/**
* Returns the time until the boat will reach the next mark, as a string.
* @param currentTime The current race time.
* @return The time delta until the boat reaches the next mark.
*/
public String getTimeToNextMarkFormatted(ZonedDateTime currentTime) {
//Calculate time delta.
Duration timeUntil = Duration.between(currentTime, getEstimatedTimeAtNextMark());
//Convert to seconds.
long secondsUntil = timeUntil.getSeconds();
//This means the estimated time is in the past, or not racing.
if ((secondsUntil < 0) || (getStatus() != BoatStatusEnum.RACING)) {
return " -";
}
if (getEstimatedTime() <= 60) {
return " " + getEstimatedTime() + "s";
if (secondsUntil <= 60) {
//If less than 1 minute, display seconds only.
return " " + secondsUntil + "s";
} else {
long seconds = getEstimatedTime() % 60;
long minutes = (getEstimatedTime() - seconds) / 60;
//Otherwise display minutes and seconds.
long seconds = secondsUntil % 60;
long minutes = (secondsUntil - seconds) / 60;
return String.format(" %dm %ds", minutes, seconds);
}
}
/**
* Returns the time since the boat passed the previous mark, as a string.
* @param currentTime The current race time.
* @return The time delta since the boat passed the previous mark.
*/
public String getTimeSinceLastMarkFormatted(ZonedDateTime currentTime) {
if (getTimeAtLastMark() != null) {
//Calculate time delta.
Duration timeSince = Duration.between(getTimeAtLastMark(), currentTime);
//Format it.
return String.format(" %ds ", timeSince.getSeconds());
} else {
return " -";
}
}
}