You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
368 lines
9.3 KiB
368 lines
9.3 KiB
package shared.model;
|
|
|
|
import javafx.beans.property.IntegerProperty;
|
|
import javafx.beans.property.Property;
|
|
import javafx.beans.property.SimpleIntegerProperty;
|
|
import javafx.beans.property.SimpleObjectProperty;
|
|
import network.Messages.Enums.RaceStatusEnum;
|
|
import network.Messages.Enums.RaceTypeEnum;
|
|
import network.Messages.LatestMessages;
|
|
import shared.dataInput.BoatDataSource;
|
|
import shared.dataInput.RaceDataSource;
|
|
import shared.dataInput.RegattaDataSource;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
/**
|
|
* Represents a yacht race.
|
|
* This is a base class inherited by {@link mock.model.MockRace} and {@link visualiser.model.VisualiserRace}.
|
|
* Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}.
|
|
*/
|
|
public abstract class Race implements Runnable {
|
|
|
|
|
|
/**
|
|
* The source of race related data.
|
|
*/
|
|
protected RaceDataSource raceDataSource;
|
|
|
|
/**
|
|
* The source of boat related data.
|
|
*/
|
|
protected BoatDataSource boatDataSource;
|
|
|
|
/**
|
|
* The source of regatta related data.
|
|
*/
|
|
protected RegattaDataSource regattaDataSource;
|
|
|
|
/**
|
|
* The collection of latest race messages.
|
|
* Can be either read from or written to.
|
|
*/
|
|
protected LatestMessages latestMessages;
|
|
|
|
/**
|
|
* The sequence number of the latest BoatLocation message sent or received.
|
|
*/
|
|
protected int boatLocationSequenceNumber = 1;
|
|
|
|
/**
|
|
* The sequence number of the latest RaceStatus message sent or received.
|
|
*/
|
|
protected int raceStatusSequenceNumber = 1;
|
|
|
|
|
|
|
|
/**
|
|
* A list of compound marks in the race.
|
|
*/
|
|
protected List<CompoundMark> compoundMarks;
|
|
|
|
/**
|
|
* A list of legs in the race.
|
|
*/
|
|
protected List<Leg> legs;
|
|
|
|
/**
|
|
* A list of coordinates describing the boundary of the course.
|
|
*/
|
|
protected List<GPSCoordinate> boundary;
|
|
|
|
|
|
|
|
/**
|
|
* The clock which tracks the race's start time, current time, and elapsed duration.
|
|
*/
|
|
protected RaceClock raceClock;
|
|
|
|
|
|
/**
|
|
* The race ID of the course.
|
|
*/
|
|
protected int raceId;
|
|
|
|
/**
|
|
* The name of the regatta.
|
|
*/
|
|
protected String regattaName;
|
|
|
|
/**
|
|
* The current status of the race.
|
|
*/
|
|
protected RaceStatusEnum raceStatusEnum;
|
|
|
|
/**
|
|
* The type of race this is.
|
|
*/
|
|
protected RaceTypeEnum raceType;
|
|
|
|
|
|
/**
|
|
* The race's wind.
|
|
*/
|
|
protected Property<Wind> raceWind = new SimpleObjectProperty<>();
|
|
|
|
|
|
/**
|
|
* The number of frames per second.
|
|
* We essentially track the number of frames generated per second, over a one second period. When {@link #lastFpsResetTime} reaches 1 second, {@link #currentFps} is reset.
|
|
*/
|
|
private int currentFps = 0;
|
|
|
|
/**
|
|
* The number of frames per second we generated over the last 1 second period.
|
|
*/
|
|
private IntegerProperty lastFps = new SimpleIntegerProperty(0);
|
|
|
|
/**
|
|
* The time, in milliseconds, since we last reset our {@link #currentFps} counter.
|
|
*/
|
|
private long lastFpsResetTime;
|
|
|
|
|
|
|
|
/**
|
|
* Constructs a race object with a given BoatDataSource, RaceDataSource, and RegattaDataSource.
|
|
* @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 latestMessages The collection of latest messages, which can be written to, or read from.
|
|
*/
|
|
public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, LatestMessages latestMessages) {
|
|
|
|
//Keep a reference to data sources.
|
|
this.raceDataSource = raceDataSource;
|
|
this.boatDataSource = boatDataSource;
|
|
this.regattaDataSource = regattaDataSource;
|
|
|
|
this.latestMessages = latestMessages;
|
|
|
|
|
|
//Marks.
|
|
this.compoundMarks = raceDataSource.getCompoundMarks();
|
|
|
|
//Boundaries.
|
|
this.boundary = raceDataSource.getBoundary();
|
|
|
|
|
|
//Legs.
|
|
this.useLegsList(raceDataSource.getLegs());
|
|
|
|
|
|
//Race ID.
|
|
this.raceId = raceDataSource.getRaceId();
|
|
|
|
//Regatta name.
|
|
this.regattaName = regattaDataSource.getRegattaName();
|
|
|
|
//Race clock.
|
|
this.raceClock = new RaceClock(this.raceDataSource.getStartDateTime());
|
|
|
|
//Race status.
|
|
this.setRaceStatusEnum(RaceStatusEnum.NOT_ACTIVE);
|
|
//Race type.
|
|
this.raceType = raceDataSource.getRaceType();
|
|
|
|
//Wind.
|
|
this.setWind(Bearing.fromDegrees(0), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Initialise the boats in the race.
|
|
* This sets their starting positions and current legs.
|
|
*/
|
|
protected abstract void initialiseBoats();
|
|
|
|
|
|
/**
|
|
* Updates the race to use a new list of legs, and adds a dummy "Finish" leg at the end.
|
|
* @param legs The new list of legs to use.
|
|
*/
|
|
protected void useLegsList(List<Leg> legs) {
|
|
//We add a "dummy" leg at the end of the race.
|
|
this.legs = legs;
|
|
this.legs.add(new Leg("Finish", this.legs.size()));
|
|
}
|
|
|
|
/**
|
|
* Determines whether or not a specific leg is the last leg in the race.
|
|
* @param leg The leg to check.
|
|
* @return Returns true if it is the last, false otherwise.
|
|
*/
|
|
protected boolean isLastLeg(Leg leg) {
|
|
|
|
//Get the last leg.
|
|
Leg lastLeg = this.legs.get(this.legs.size() - 1);
|
|
|
|
//Check its ID.
|
|
int lastLegID = lastLeg.getLegNumber();
|
|
|
|
//Get the specified leg's ID.
|
|
int legID = leg.getLegNumber();
|
|
|
|
|
|
//Check if they are the same.
|
|
return legID == lastLegID;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Returns the current race status.
|
|
* @return The current race status.
|
|
*/
|
|
public RaceStatusEnum getRaceStatusEnum() {
|
|
return raceStatusEnum;
|
|
}
|
|
|
|
/**
|
|
* Sets the current race status.
|
|
* @param raceStatusEnum The new status of the race.
|
|
*/
|
|
protected void setRaceStatusEnum(RaceStatusEnum raceStatusEnum) {
|
|
this.raceStatusEnum = raceStatusEnum;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the type of race this is.
|
|
* @return The type of race this is.
|
|
*/
|
|
public RaceTypeEnum getRaceType() {
|
|
return raceType;
|
|
}
|
|
|
|
/**
|
|
* Returns the name of the regatta.
|
|
* @return The name of the regatta.
|
|
*/
|
|
public String getRegattaName() {
|
|
return regattaName;
|
|
}
|
|
|
|
|
|
/**
|
|
* Updates the race to have a specified wind bearing and speed.
|
|
* @param windBearing New wind bearing.
|
|
* @param windSpeedKnots New wind speed, in knots.
|
|
*/
|
|
protected void setWind(Bearing windBearing, double windSpeedKnots) {
|
|
Wind wind = new Wind(windBearing, windSpeedKnots);
|
|
setWind(wind);
|
|
}
|
|
|
|
/**
|
|
* Updates the race to have a specified wind (bearing and speed).
|
|
* @param wind New wind.
|
|
*/
|
|
protected void setWind(Wind wind) {
|
|
this.raceWind.setValue(wind);
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the wind bearing.
|
|
* @return The wind bearing.
|
|
*/
|
|
public Bearing getWindDirection() {
|
|
return raceWind.getValue().getWindDirection();
|
|
}
|
|
|
|
/**
|
|
* Returns the wind speed.
|
|
* Measured in knots.
|
|
* @return The wind speed.
|
|
*/
|
|
public double getWindSpeed() {
|
|
return raceWind.getValue().getWindSpeed();
|
|
}
|
|
|
|
/**
|
|
* Returns the race's wind.
|
|
* @return The race's wind.
|
|
*/
|
|
public Property<Wind> windProperty() {
|
|
return raceWind;
|
|
}
|
|
|
|
/**
|
|
* Returns the RaceClock for this race.
|
|
* This is used to track the start time, current time, and elapsed duration of the race.
|
|
* @return The RaceClock for the race.
|
|
*/
|
|
public RaceClock getRaceClock() {
|
|
return raceClock;
|
|
}
|
|
|
|
|
|
/**
|
|
* 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.getValue();
|
|
}
|
|
|
|
/**
|
|
* Returns the fps property.
|
|
* @return The fps property.
|
|
*/
|
|
public IntegerProperty fpsProperty() {
|
|
return lastFps;
|
|
}
|
|
|
|
|
|
/**
|
|
* Increments the FPS counter, and adds timePeriod milliseconds to our FPS reset timer.
|
|
* @param timePeriod Time, in milliseconds, to add to {@link #lastFpsResetTime}.
|
|
*/
|
|
protected void incrementFps(long timePeriod) {
|
|
//Increment.
|
|
this.currentFps++;
|
|
|
|
//Add period to timer.
|
|
this.lastFpsResetTime += timePeriod;
|
|
|
|
//If we have reached 1 second period, snapshot the framerate and reset.
|
|
if (this.lastFpsResetTime > 1000) {
|
|
this.lastFps.set(this.currentFps);
|
|
|
|
this.currentFps = 0;
|
|
this.lastFpsResetTime = 0;
|
|
}
|
|
}
|
|
}
|