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:
@@ -31,12 +31,12 @@ public class BoatXMLReader extends XMLReader implements BoatDataSource {
|
||||
/**
|
||||
* Constructor for Boat XML using a file read as a resource.
|
||||
*
|
||||
* @param filePath Name/path of file to read. Read as a resource.
|
||||
* @param fileContents Contents of xml file.
|
||||
* @throws XMLReaderException Thrown if the file cannot be parsed.
|
||||
* @throws InvalidBoatDataException Thrown if the file cannot be parsed correctly.
|
||||
*/
|
||||
public BoatXMLReader(String filePath) throws XMLReaderException, InvalidBoatDataException {
|
||||
super(filePath);
|
||||
public BoatXMLReader(String fileContents) throws XMLReaderException, InvalidBoatDataException {
|
||||
super(fileContents);
|
||||
|
||||
//Attempt to read boat xml file.
|
||||
try {
|
||||
|
||||
@@ -82,13 +82,13 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
|
||||
/**
|
||||
* Constructor for Streamed Race XML
|
||||
* @param filePath file path to read
|
||||
* @param fileContents Contents of xml file.
|
||||
* @throws XMLReaderException Thrown if an XML reader cannot be constructed for the given file.
|
||||
* @throws InvalidRaceDataException Thrown if the XML file is invalid in some way.
|
||||
*/
|
||||
public RaceXMLReader(String filePath) throws XMLReaderException, InvalidRaceDataException {
|
||||
public RaceXMLReader(String fileContents) throws XMLReaderException, InvalidRaceDataException {
|
||||
|
||||
super(filePath);
|
||||
super(fileContents);
|
||||
|
||||
|
||||
//Attempt to read race xml file.
|
||||
@@ -101,8 +101,9 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
|
||||
/**
|
||||
* Reads the contents of the race xml file.
|
||||
* @throws InvalidRaceDataException Thrown if we cannot parse the document properly.
|
||||
*/
|
||||
private void read() {
|
||||
private void read() throws InvalidRaceDataException {
|
||||
readRace();
|
||||
readParticipants();
|
||||
readCourse();
|
||||
@@ -127,7 +128,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
|
||||
//Race type.
|
||||
String raceTypeString = getTextValueOfNode(settings, "RaceType");
|
||||
raceType = RaceTypeEnum.valueOf(raceTypeString);
|
||||
raceType = RaceTypeEnum.fromString(raceTypeString);
|
||||
|
||||
//XML creation time.
|
||||
creationTimeDate = ZonedDateTime.parse(getTextValueOfNode(settings, "CreationTimeDate"), dateFormat);
|
||||
@@ -178,8 +179,9 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
|
||||
/**
|
||||
* Reads course data from the xml file.
|
||||
* @throws InvalidRaceDataException Thrown if we cannot parse the document properly.
|
||||
*/
|
||||
private void readCourse() {
|
||||
private void readCourse() throws InvalidRaceDataException {
|
||||
readCompoundMarks();
|
||||
readCompoundMarkSequence();
|
||||
readCourseLimits();
|
||||
@@ -189,30 +191,31 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
|
||||
/**
|
||||
* Indexes CompoundMark elements by their ID for use in generating the course, and populates list of Markers.
|
||||
* @throws InvalidRaceDataException thrown if we cannot create a compound mark from the document.
|
||||
* @see CompoundMark
|
||||
*/
|
||||
private void readCompoundMarks() {
|
||||
private void readCompoundMarks() throws InvalidRaceDataException {
|
||||
|
||||
//Gets the "<Course>...</..>" element.
|
||||
Element course = (Element) doc.getElementsByTagName("Course").item(0);
|
||||
|
||||
//Get the list of CompoundMark elements.
|
||||
NodeList compoundMarkList = course.getElementsByTagName("CompoundMark");
|
||||
|
||||
//Number of compound marks in the course.
|
||||
int numberOfCompoundMarks = course.getChildNodes().getLength();
|
||||
int numberOfCompoundMarks = compoundMarkList.getLength();
|
||||
|
||||
//For each CompoundMark element, create a CompoundMark object.
|
||||
for(int i = 0; i < numberOfCompoundMarks; i++) {
|
||||
|
||||
//Get the CompoundMark element.
|
||||
Element compoundMarkElement = (Element) course.getChildNodes().item(i);
|
||||
Element compoundMarkElement = (Element) compoundMarkList.item(i);
|
||||
|
||||
//If it is actually a CompoundMark element, turn it into a CompoundMark object.
|
||||
if(compoundMarkElement.getNodeName().equals("CompoundMark")) {
|
||||
|
||||
CompoundMark compoundMark = createCompoundMark(compoundMarkElement);
|
||||
//Convert to CompoundMark object.
|
||||
CompoundMark compoundMark = createCompoundMark(compoundMarkElement);
|
||||
|
||||
compoundMarkMap.put(compoundMark.getId(), compoundMark);
|
||||
|
||||
}
|
||||
compoundMarkMap.put(compoundMark.getId(), compoundMark);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -321,7 +324,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
NodeList corners = compoundMarkSequence.getElementsByTagName("Corner");
|
||||
|
||||
//Gets the first corner.
|
||||
Element cornerElement = (Element)corners.item(0);
|
||||
Element cornerElement = (Element) corners.item(0);
|
||||
|
||||
//Gets the ID number of this corner element.
|
||||
int cornerID = getCompoundMarkID(cornerElement);
|
||||
@@ -365,20 +368,19 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
//The "<CourseLimit>...</...>" element. This contains a sequence of Limit elements.
|
||||
Element courseLimit = (Element) doc.getElementsByTagName("CourseLimit").item(0);
|
||||
|
||||
//Get the list of Limit elements.
|
||||
NodeList limitList = courseLimit.getElementsByTagName("Limit");
|
||||
|
||||
//For each limit element...
|
||||
for(int i = 0; i < courseLimit.getChildNodes().getLength(); i++) {
|
||||
for(int i = 0; i < limitList.getLength(); i++) {
|
||||
|
||||
//Get the Limit element.
|
||||
Element limit = (Element) courseLimit.getChildNodes().item(i);
|
||||
Element limit = (Element) limitList.item(i);
|
||||
|
||||
//If it is actually a Limit element, add the limit to boundary list.
|
||||
if (limit.getNodeName().equals("Limit")) {
|
||||
|
||||
double latitude = Double.parseDouble(limit.getAttribute("Lat"));
|
||||
double longitude = Double.parseDouble(limit.getAttribute("Lon"));
|
||||
boundary.add(new GPSCoordinate(latitude, longitude));
|
||||
|
||||
}
|
||||
//Convert to GPSCoordinate.
|
||||
double latitude = Double.parseDouble(limit.getAttribute("Lat"));
|
||||
double longitude = Double.parseDouble(limit.getAttribute("Lon"));
|
||||
boundary.add(new GPSCoordinate(latitude, longitude));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,12 +66,12 @@ public class RegattaXMLReader extends XMLReader implements RegattaDataSource {
|
||||
/**
|
||||
* Constructor for Regatta XML using a file read as a resource.
|
||||
*
|
||||
* @param filePath path of the file to read. Read as a resource.
|
||||
* @param fileContents Contents of xml file.
|
||||
* @throws XMLReaderException Thrown if the file cannot be parsed.
|
||||
* @throws InvalidRegattaDataException Thrown if the file cannot be parsed correctly.
|
||||
*/
|
||||
public RegattaXMLReader(String filePath) throws XMLReaderException, InvalidRegattaDataException {
|
||||
super(filePath);
|
||||
public RegattaXMLReader(String fileContents) throws XMLReaderException, InvalidRegattaDataException {
|
||||
super(fileContents);
|
||||
|
||||
//Attempt to read boat xml file.
|
||||
try {
|
||||
|
||||
@@ -15,9 +15,8 @@ import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Base Reader for XML Files
|
||||
@@ -27,14 +26,14 @@ public abstract class XMLReader {
|
||||
protected Document doc;
|
||||
|
||||
/**
|
||||
* Read an XML file by name as a resource.
|
||||
* @param filePath filepath for XML file. Loaded as a resource.
|
||||
* Read an XML file.
|
||||
* @param fileContents Contents of the xml file.
|
||||
* @throws XMLReaderException Thrown if the file cannot be parsed.
|
||||
*/
|
||||
public XMLReader(String filePath) throws XMLReaderException {
|
||||
public XMLReader(String fileContents) throws XMLReaderException {
|
||||
|
||||
//Read file as resource.
|
||||
InputStream xmlInputStream = getClass().getClassLoader().getResourceAsStream(filePath);
|
||||
//Wrap file contents in input stream.
|
||||
InputStream xmlInputStream = new ByteArrayInputStream(fileContents.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
this.doc = parseInputStream(xmlInputStream);
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package shared.model;
|
||||
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import com.sun.istack.internal.Nullable;
|
||||
import javafx.beans.property.*;
|
||||
import network.Messages.Enums.BoatStatusEnum;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
* Boat Model that is used to store information on the boats that are running in the race.
|
||||
*/
|
||||
@@ -18,7 +20,7 @@ public class Boat {
|
||||
* The current speed of the boat, in knots.
|
||||
* TODO knots
|
||||
*/
|
||||
private double currentSpeed;
|
||||
private DoubleProperty currentSpeed = new SimpleDoubleProperty(0);
|
||||
|
||||
/**
|
||||
* The current bearing/heading of the boat.
|
||||
@@ -44,7 +46,7 @@ public class Boat {
|
||||
/**
|
||||
* The leg of the race that the boat is currently on.
|
||||
*/
|
||||
private Leg currentLeg;
|
||||
private Property<Leg> currentLeg = new SimpleObjectProperty<>();
|
||||
|
||||
/**
|
||||
* The distance, in meters, that the boat has travelled in the current leg.
|
||||
@@ -55,7 +57,7 @@ public class Boat {
|
||||
/**
|
||||
* The boat's position within the race (e.g., 5th).
|
||||
*/
|
||||
private StringProperty positionInRace;
|
||||
private StringProperty positionInRace = new SimpleStringProperty();
|
||||
|
||||
/**
|
||||
* The time, in milliseconds, that has elapsed during the current leg.
|
||||
@@ -77,9 +79,15 @@ public class Boat {
|
||||
|
||||
|
||||
/**
|
||||
* The amount of time, in seconds, until the boat reaches the next mark.
|
||||
* The time at which the boat is estimated to reach the next mark, in milliseconds since unix epoch.
|
||||
*/
|
||||
private long estimatedTime = 0;
|
||||
private ZonedDateTime estimatedTimeAtNextMark;
|
||||
|
||||
/**
|
||||
* The time at which the boat reached the previous mark.
|
||||
*/
|
||||
@Nullable
|
||||
private ZonedDateTime timeAtLastMark;
|
||||
|
||||
|
||||
/**
|
||||
@@ -132,7 +140,7 @@ public class Boat {
|
||||
* @return The current speed of the boat, in knots.
|
||||
*/
|
||||
public double getCurrentSpeed() {
|
||||
return currentSpeed;
|
||||
return currentSpeed.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +148,15 @@ public class Boat {
|
||||
* @param currentSpeed The new speed of the boat, in knots.
|
||||
*/
|
||||
public void setCurrentSpeed(double currentSpeed) {
|
||||
this.currentSpeed = currentSpeed;
|
||||
this.currentSpeed.set(currentSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current speed property of the boat.
|
||||
* @return The current speed of the boat, in a DoubleProperty.
|
||||
*/
|
||||
public DoubleProperty currentSpeedProperty() {
|
||||
return currentSpeed;
|
||||
}
|
||||
|
||||
|
||||
@@ -189,6 +205,14 @@ public class Boat {
|
||||
* @return The current leg of the race the boat is in.
|
||||
*/
|
||||
public Leg getCurrentLeg() {
|
||||
return currentLeg.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current leg, wrapped in a property.
|
||||
* @return Current leg, wrapped in a property.
|
||||
*/
|
||||
public Property<Leg> legProperty() {
|
||||
return currentLeg;
|
||||
}
|
||||
|
||||
@@ -198,7 +222,7 @@ public class Boat {
|
||||
* @param currentLeg The new leg of the race the boat is in.
|
||||
*/
|
||||
public void setCurrentLeg(Leg currentLeg) {
|
||||
this.currentLeg = currentLeg;
|
||||
this.currentLeg.setValue(currentLeg);
|
||||
this.setTimeElapsedInCurrentLeg(0);
|
||||
this.setDistanceTravelledInLeg(0);
|
||||
}
|
||||
@@ -221,14 +245,26 @@ public class Boat {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the position within the race the boat has (e.g., 5th).
|
||||
* @return The boat's position in race.
|
||||
*/
|
||||
public StringProperty positionProperty() {
|
||||
return positionInRace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position within the race the boat has (e.g., 5th).
|
||||
* @param position The boat's position in race.
|
||||
*/
|
||||
public void setPosition(String position) {
|
||||
this.positionInRace.set(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position within the race the boat has (e.g., 5th).
|
||||
* @return The boat's position in race.
|
||||
*/
|
||||
public String getPosition() {
|
||||
return this.positionInRace.get();
|
||||
}
|
||||
@@ -321,13 +357,38 @@ public class Boat {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public long getEstimatedTime() {
|
||||
return estimatedTime;
|
||||
/**
|
||||
* Returns the time at which the boat should reach the next mark.
|
||||
* @return Time at which the boat should reach next mark.
|
||||
*/
|
||||
public ZonedDateTime getEstimatedTimeAtNextMark() {
|
||||
return estimatedTimeAtNextMark;
|
||||
}
|
||||
|
||||
public void setEstimatedTime(long estimatedTime) {
|
||||
this.estimatedTime = estimatedTime;
|
||||
/**
|
||||
* Sets the time at which the boat should reach the next mark.
|
||||
* @param estimatedTimeAtNextMark Time at which the boat should reach next mark.
|
||||
*/
|
||||
public void setEstimatedTimeAtNextMark(ZonedDateTime estimatedTimeAtNextMark) {
|
||||
this.estimatedTimeAtNextMark = estimatedTimeAtNextMark;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the time at which the boat reached the previous mark.
|
||||
* @return The time at which the boat reached the previous mark. May be null.
|
||||
*/
|
||||
@Nullable
|
||||
public ZonedDateTime getTimeAtLastMark() {
|
||||
return timeAtLastMark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time at which the boat reached the previous mark to a specified time.
|
||||
* @param timeAtLastMark Time at which boat passed previous mark.
|
||||
*/
|
||||
public void setTimeAtLastMark(ZonedDateTime timeAtLastMark) {
|
||||
this.timeAtLastMark = timeAtLastMark;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class Constants {
|
||||
* Frame periods are multiplied by this to get the amount of time a single frame represents.
|
||||
* E.g., frame period = 20ms, scale = 5, frame represents 20 * 5 = 100ms, and so boats are simulated for 100ms, even though only 20ms actually occurred.
|
||||
*/
|
||||
public static final int RaceTimeScale = 1;
|
||||
public static final int RaceTimeScale = 25;
|
||||
|
||||
/**
|
||||
* The race pre-start time, in milliseconds. 3 minutes.
|
||||
@@ -49,9 +49,22 @@ public class Constants {
|
||||
|
||||
/**
|
||||
* The number of milliseconds in one hour.
|
||||
* <br>
|
||||
* Multiply by this factor to convert milliseconds to hours.
|
||||
* <br>
|
||||
* Divide by this factor to convert hours to milliseconds.
|
||||
*/
|
||||
public static long OneHourMilliseconds = 1 * 60 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* The number of seconds in one hour.
|
||||
* <br>
|
||||
* Multiply by this factor to convert seconds to hours.
|
||||
* <br>
|
||||
* Divide by this factor to convert hours to seconds.
|
||||
*/
|
||||
public static long OneHourSeconds = 1 * 60 * 60;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -299,6 +299,7 @@ public class GPSCoordinate {
|
||||
*/
|
||||
public static List<GPSCoordinate> getShrinkBoundary(List<GPSCoordinate> boundary) {
|
||||
|
||||
//TODO shrinkDistance should be a parameter. Also the code should be refactored to be smaller/simpler.
|
||||
|
||||
double shrinkDistance = 50d;
|
||||
List<GPSCoordinate> shrunkBoundary = new ArrayList<>(boundary.size());
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package shared.model;
|
||||
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
import network.Messages.Enums.RaceTypeEnum;
|
||||
import network.Messages.LatestMessages;
|
||||
@@ -116,7 +118,7 @@ public abstract class Race implements Runnable {
|
||||
/**
|
||||
* The number of frames per second we generated over the last 1 second period.
|
||||
*/
|
||||
private int lastFps = 0;
|
||||
private IntegerProperty lastFps = new SimpleIntegerProperty(0);
|
||||
|
||||
/**
|
||||
* The time, in milliseconds, since we last reset our {@link #currentFps} counter.
|
||||
@@ -280,12 +282,46 @@ public abstract class Race implements Runnable {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the RaceDataSource used for the race.
|
||||
* @return The RaceDataSource used for the race.
|
||||
*/
|
||||
public RaceDataSource getRaceDataSource() {
|
||||
return raceDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of legs in the race.
|
||||
* @return The number of legs in the race.
|
||||
*/
|
||||
public int getLegCount() {
|
||||
//We minus one, as we have added an extra "dummy" leg.
|
||||
return legs.size() - 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the race boundary.
|
||||
* @return The race boundary.
|
||||
*/
|
||||
public List<GPSCoordinate> getBoundary() {
|
||||
return boundary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of frames generated per second.
|
||||
* @return Frames per second.
|
||||
*/
|
||||
public int getFps() {
|
||||
return lastFps;
|
||||
return lastFps.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fps property.
|
||||
* @return The fps property.
|
||||
*/
|
||||
public IntegerProperty fpsProperty() {
|
||||
return lastFps;
|
||||
}
|
||||
|
||||
|
||||
@@ -302,7 +338,7 @@ public abstract class Race implements Runnable {
|
||||
|
||||
//If we have reached 1 second period, snapshot the framerate and reset.
|
||||
if (this.lastFpsResetTime > 1000) {
|
||||
this.lastFps = this.currentFps;
|
||||
this.lastFps.set(this.currentFps);
|
||||
|
||||
this.currentFps = 0;
|
||||
this.lastFpsResetTime = 0;
|
||||
|
||||
@@ -72,8 +72,9 @@ public class RaceClock implements Runnable {
|
||||
|
||||
/**
|
||||
* Format string used for current time.
|
||||
* TODO probably need to fix this.
|
||||
*/
|
||||
private String currentTimeFormat = "'Starting time:' HH:mm dd/MM/YYYY";
|
||||
private String currentTimeFormat = "'Current time:' HH:mm dd/MM/YYYY";
|
||||
|
||||
/**
|
||||
* Format string used for duration before it has started.
|
||||
|
||||
Reference in New Issue
Block a user