Merge branch 'issue_26_wind' into RaceFactory
# Conflicts: # racevisionGame/src/main/java/mock/model/MockRace.java # racevisionGame/src/main/java/shared/model/Race.java # racevisionGame/src/main/java/visualiser/model/VisualiserRace.java
This commit is contained in:
@@ -69,7 +69,18 @@ public class MockRace extends Race {
|
|||||||
|
|
||||||
this.shrinkBoundary = GPSCoordinate.getShrinkBoundary(this.boundary);
|
this.shrinkBoundary = GPSCoordinate.getShrinkBoundary(this.boundary);
|
||||||
|
|
||||||
this.wind = new Wind();
|
|
||||||
|
//Set up wind generator. It may be tidier to create this outside the race (with the values sourced from a data file maybe?) and pass it in.
|
||||||
|
this.windGenerator = new WindGenerator(
|
||||||
|
Bearing.fromDegrees(225),
|
||||||
|
Bearing.fromDegrees(215),
|
||||||
|
Bearing.fromDegrees(235),
|
||||||
|
12d,
|
||||||
|
8d,
|
||||||
|
16d );
|
||||||
|
|
||||||
|
//Wind.
|
||||||
|
this.setWind(windGenerator.generateBaselineWind());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,6 +117,7 @@ public class MockRace extends Race {
|
|||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
initialiseBoats();
|
initialiseBoats();
|
||||||
|
initialiseWindDirection();
|
||||||
this.countdownTimer.start();
|
this.countdownTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,8 +265,8 @@ public class MockRace extends Race {
|
|||||||
|
|
||||||
|
|
||||||
//Convert wind direction and speed to ints. //TODO this conversion should be done inside the racestatus class.
|
//Convert wind direction and speed to ints. //TODO this conversion should be done inside the racestatus class.
|
||||||
int windDirectionInt = AC35UnitConverter.encodeHeading(wind.getWindDirection().degrees());
|
int windDirectionInt = AC35UnitConverter.encodeHeading(this.getWindDirection().degrees());
|
||||||
int windSpeedInt = (int) (wind.getWindSpeed() * Constants.KnotsToMMPerSecond);
|
int windSpeedInt = (int) (this.getWindSpeed() * Constants.KnotsToMMPerSecond);
|
||||||
|
|
||||||
//Create race status object, and send it.
|
//Create race status object, and send it.
|
||||||
RaceStatus raceStatus = new RaceStatus(
|
RaceStatus raceStatus = new RaceStatus(
|
||||||
@@ -541,7 +553,12 @@ public class MockRace extends Race {
|
|||||||
|
|
||||||
|
|
||||||
//Find the VMG inside these bounds.
|
//Find the VMG inside these bounds.
|
||||||
VMG bestVMG = boat.getPolars().calculateVMG(wind.getWindDirection(), wind.getWindSpeed(), boat.calculateBearingToNextMarker(), lowerAcceptableBound, upperAcceptableBound);
|
VMG bestVMG = boat.getPolars().calculateVMG(
|
||||||
|
this.getWindDirection(),
|
||||||
|
this.getWindSpeed(),
|
||||||
|
boat.calculateBearingToNextMarker(),
|
||||||
|
lowerAcceptableBound,
|
||||||
|
upperAcceptableBound);
|
||||||
|
|
||||||
|
|
||||||
return bestVMG;
|
return bestVMG;
|
||||||
@@ -811,11 +828,24 @@ public class MockRace extends Race {
|
|||||||
return boats;
|
return boats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the wind bearing with the value of the windBaselineBearing.
|
||||||
|
*/
|
||||||
|
protected void initialiseWindDirection() {
|
||||||
|
//Set the starting bearing.
|
||||||
|
this.setWind(windGenerator.generateBaselineWind());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the wind direction randomly, while keeping it within [windLowerBound, windUpperBound].
|
* Changes the wind direction randomly, while keeping it within [windLowerBound, windUpperBound].
|
||||||
*/
|
*/
|
||||||
protected void changeWindDirection() {
|
protected void changeWindDirection() {
|
||||||
this.wind.changeWindDirection();
|
|
||||||
|
Wind nextWind = windGenerator.generateNextWind(raceWind.getValue());
|
||||||
|
|
||||||
|
setWind(nextWind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,249 @@
|
|||||||
|
package mock.model;
|
||||||
|
|
||||||
|
|
||||||
|
import shared.model.Bearing;
|
||||||
|
import shared.model.Wind;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class generates Wind objects for use in a MockRace.
|
||||||
|
* Bounds on bearing and speed can be specified.
|
||||||
|
* Wind can be completely random, or random incremental change.
|
||||||
|
*/
|
||||||
|
public class WindGenerator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bearing the wind direction starts at.
|
||||||
|
*/
|
||||||
|
private Bearing windBaselineBearing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lower bearing angle that the wind may have.
|
||||||
|
*/
|
||||||
|
private Bearing windBearingLowerBound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The upper bearing angle that the wind may have.
|
||||||
|
*/
|
||||||
|
private Bearing windBearingUpperBound;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The speed the wind starts at, in knots.
|
||||||
|
*/
|
||||||
|
private double windBaselineSpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lower speed that the wind may have, in knots.
|
||||||
|
*/
|
||||||
|
private double windSpeedLowerBound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The upper speed that the wind may have, in knots.
|
||||||
|
*/
|
||||||
|
private double windSpeedUpperBound;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a wind generator, with a baseline, lower bound, and upper bound, for the wind speed and direction.
|
||||||
|
* @param windBaselineBearing Baseline wind direction.
|
||||||
|
* @param windBearingLowerBound Lower bound for wind direction.
|
||||||
|
* @param windBearingUpperBound Upper bound for wind direction.
|
||||||
|
* @param windBaselineSpeed Baseline wind speed, in knots.
|
||||||
|
* @param windSpeedLowerBound Lower bound for wind speed, in knots.
|
||||||
|
* @param windSpeedUpperBound Upper bound for wind speed, in knots.
|
||||||
|
*/
|
||||||
|
public WindGenerator(Bearing windBaselineBearing, Bearing windBearingLowerBound, Bearing windBearingUpperBound, double windBaselineSpeed, double windSpeedLowerBound, double windSpeedUpperBound) {
|
||||||
|
|
||||||
|
this.windBaselineBearing = windBaselineBearing;
|
||||||
|
this.windBearingLowerBound = windBearingLowerBound;
|
||||||
|
this.windBearingUpperBound = windBearingUpperBound;
|
||||||
|
this.windBaselineSpeed = windBaselineSpeed;
|
||||||
|
this.windSpeedLowerBound = windSpeedLowerBound;
|
||||||
|
this.windSpeedUpperBound = windSpeedUpperBound;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a wind object using the baseline wind speed and bearing.
|
||||||
|
* @return Baseline wind object.
|
||||||
|
*/
|
||||||
|
public Wind generateBaselineWind() {
|
||||||
|
return new Wind(windBaselineBearing, windBaselineSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random Wind object, that is within the provided bounds.
|
||||||
|
* @return Generated wind object.
|
||||||
|
*/
|
||||||
|
public Wind generateRandomWind() {
|
||||||
|
|
||||||
|
double windSpeed = generateRandomWindSpeed();
|
||||||
|
Bearing windBearing = generateRandomWindBearing();
|
||||||
|
|
||||||
|
return new Wind(windBearing, windSpeed);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random wind speed within the specified bounds. In knots.
|
||||||
|
* @return Wind speed, in knots.
|
||||||
|
*/
|
||||||
|
private double generateRandomWindSpeed() {
|
||||||
|
|
||||||
|
double randomSpeedKnots = generateRandomValueInBounds(windSpeedLowerBound, windSpeedUpperBound);
|
||||||
|
|
||||||
|
return randomSpeedKnots;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random wind bearing within the specified bounds.
|
||||||
|
* @return Wind bearing.
|
||||||
|
*/
|
||||||
|
private Bearing generateRandomWindBearing() {
|
||||||
|
|
||||||
|
double randomBearingDegrees = generateRandomValueInBounds(windBearingLowerBound.degrees(), windBearingUpperBound.degrees());
|
||||||
|
|
||||||
|
return Bearing.fromDegrees(randomBearingDegrees);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random value within a specified interval.
|
||||||
|
* @param lowerBound The lower bound of the interval.
|
||||||
|
* @param upperBound The upper bound of the interval.
|
||||||
|
* @return A random value within the interval.
|
||||||
|
*/
|
||||||
|
private static double generateRandomValueInBounds(double lowerBound, double upperBound) {
|
||||||
|
|
||||||
|
float proportion = new Random().nextFloat();
|
||||||
|
|
||||||
|
double delta = upperBound - lowerBound;
|
||||||
|
|
||||||
|
double amount = delta * proportion;
|
||||||
|
|
||||||
|
double finalAmount = amount + lowerBound;
|
||||||
|
|
||||||
|
return finalAmount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new value within an interval, given a start value, chance to change, and change amount.
|
||||||
|
* @param lowerBound Lower bound of interval.
|
||||||
|
* @param upperBound Upper bound of interval.
|
||||||
|
* @param currentValue The current value to change.
|
||||||
|
* @param changeAmount The amount to change by.
|
||||||
|
* @param chanceToChange The change to actually change the value.
|
||||||
|
* @return The new value.
|
||||||
|
*/
|
||||||
|
private static double generateNextValueInBounds(double lowerBound, double upperBound, double currentValue, double changeAmount, double chanceToChange) {
|
||||||
|
|
||||||
|
float chance = new Random().nextFloat();
|
||||||
|
|
||||||
|
|
||||||
|
if (chance <= chanceToChange) {
|
||||||
|
currentValue += changeAmount;
|
||||||
|
|
||||||
|
} else if (chance <= (2 * chanceToChange)) {
|
||||||
|
currentValue -= changeAmount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
currentValue = clamp(lowerBound, upperBound, currentValue);
|
||||||
|
|
||||||
|
return currentValue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the next Wind object, that is within the provided bounds. This randomly increases or decreases the wind's speed and bearing.
|
||||||
|
* @param currentWind The current wind to change. This is not modified.
|
||||||
|
* @return Generated wind object.
|
||||||
|
*/
|
||||||
|
public Wind generateNextWind(Wind currentWind) {
|
||||||
|
|
||||||
|
double windSpeed = generateNextWindSpeed(currentWind.getWindSpeed());
|
||||||
|
Bearing windBearing = generateNextWindBearing(currentWind.getWindDirection());
|
||||||
|
|
||||||
|
return new Wind(windBearing, windSpeed);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the next wind speed to use.
|
||||||
|
* @param windSpeed Current wind speed, in knots.
|
||||||
|
* @return Next wind speed, in knots.
|
||||||
|
*/
|
||||||
|
private double generateNextWindSpeed(double windSpeed) {
|
||||||
|
|
||||||
|
double chanceToChange = 0.2;
|
||||||
|
double changeAmount = 0.1;
|
||||||
|
|
||||||
|
double nextWindSpeed = generateNextValueInBounds(
|
||||||
|
windSpeedLowerBound,
|
||||||
|
windSpeedUpperBound,
|
||||||
|
windSpeed,
|
||||||
|
changeAmount,
|
||||||
|
chanceToChange);
|
||||||
|
|
||||||
|
return nextWindSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the next wind speed to use.
|
||||||
|
* @param windBearing Current wind bearing.
|
||||||
|
* @return Next wind speed.
|
||||||
|
*/
|
||||||
|
private Bearing generateNextWindBearing(Bearing windBearing) {
|
||||||
|
|
||||||
|
double chanceToChange = 0.2;
|
||||||
|
double changeAmount = 0.5;
|
||||||
|
|
||||||
|
double nextWindBearingDegrees = generateNextValueInBounds(
|
||||||
|
windBearingLowerBound.degrees(),
|
||||||
|
windBearingUpperBound.degrees(),
|
||||||
|
windBearing.degrees(),
|
||||||
|
changeAmount,
|
||||||
|
chanceToChange);
|
||||||
|
|
||||||
|
return Bearing.fromDegrees(nextWindBearingDegrees);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clamps a value to be within an interval.
|
||||||
|
* @param lower Lower bound of the interval.
|
||||||
|
* @param upper Upper bound of the interval.
|
||||||
|
* @param value Value to clamp.
|
||||||
|
* @return The clamped value.
|
||||||
|
*/
|
||||||
|
private static double clamp(double lower, double upper, double value) {
|
||||||
|
|
||||||
|
if (value > upper) {
|
||||||
|
value = upper;
|
||||||
|
|
||||||
|
} else if (value < lower) {
|
||||||
|
value = lower;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package shared.model;
|
package shared.model;
|
||||||
|
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
|
import javafx.beans.property.Property;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import mock.model.Wind;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import network.Messages.Enums.RaceStatusEnum;
|
import network.Messages.Enums.RaceStatusEnum;
|
||||||
import network.Messages.Enums.RaceTypeEnum;
|
import network.Messages.Enums.RaceTypeEnum;
|
||||||
import network.Messages.LatestMessages;
|
import network.Messages.LatestMessages;
|
||||||
@@ -99,9 +100,9 @@ public abstract class Race implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current wind direction bearing.
|
* The race's wind.
|
||||||
*/
|
*/
|
||||||
protected Wind wind;
|
protected Property<Wind> raceWind = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -164,7 +165,9 @@ public abstract class Race implements Runnable {
|
|||||||
//Race type.
|
//Race type.
|
||||||
this.raceType = raceDataSource.getRaceType();
|
this.raceType = raceDataSource.getRaceType();
|
||||||
|
|
||||||
this.wind = new Wind();
|
//Wind.
|
||||||
|
this.setWind(Bearing.fromDegrees(0), 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -244,12 +247,32 @@ public abstract class Race implements Runnable {
|
|||||||
return regattaName;
|
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.
|
* Returns the wind bearing.
|
||||||
* @return The wind bearing.
|
* @return The wind bearing.
|
||||||
*/
|
*/
|
||||||
public Bearing getWindDirection() {
|
public Bearing getWindDirection() {
|
||||||
return wind.getWindDirection();
|
return raceWind.getValue().getWindDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,7 +281,15 @@ public abstract class Race implements Runnable {
|
|||||||
* @return The wind speed.
|
* @return The wind speed.
|
||||||
*/
|
*/
|
||||||
public double getWindSpeed() {
|
public double getWindSpeed() {
|
||||||
return wind.getWindSpeed();
|
return raceWind.getValue().getWindSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the race's wind.
|
||||||
|
* @return The race's wind.
|
||||||
|
*/
|
||||||
|
public Property<Wind> windProperty() {
|
||||||
|
return raceWind;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package shared.model;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class encapsulates the wind during a race.
|
||||||
|
* It has speed and a bearing.
|
||||||
|
* This is intended to be immutable.
|
||||||
|
*/
|
||||||
|
public class Wind {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current wind direction bearing.
|
||||||
|
*/
|
||||||
|
private Bearing windDirection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wind speed (knots).
|
||||||
|
* Convert this to millimeters per second before passing to RaceStatus.
|
||||||
|
*/
|
||||||
|
private double windSpeed;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new wind object, with a given direction and speed, in knots.
|
||||||
|
* @param windDirection The direction of the wind.
|
||||||
|
* @param windSpeed The speed of the wind, in knots.
|
||||||
|
*/
|
||||||
|
public Wind(Bearing windDirection, double windSpeed) {
|
||||||
|
this.windDirection = windDirection;
|
||||||
|
this.windSpeed = windSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the race wind's bearing.
|
||||||
|
* @return The race wind's bearing.
|
||||||
|
*/
|
||||||
|
public Bearing getWindDirection() {
|
||||||
|
return windDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the race wind's speed, in knots.
|
||||||
|
* @return The race wind's speed, in knots.
|
||||||
|
*/
|
||||||
|
public double getWindSpeed() {
|
||||||
|
return windSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -311,11 +311,10 @@ public class VisualiserRace extends Race {
|
|||||||
//Race status enum.
|
//Race status enum.
|
||||||
this.raceStatusEnum = RaceStatusEnum.fromByte(raceStatus.getRaceStatus());
|
this.raceStatusEnum = RaceStatusEnum.fromByte(raceStatus.getRaceStatus());
|
||||||
|
|
||||||
// Wind direction
|
//Wind.
|
||||||
wind.setDegrees(raceStatus.getScaledWindDirection());
|
this.setWind(
|
||||||
|
Bearing.fromDegrees(raceStatus.getScaledWindDirection()),
|
||||||
// Wind speed
|
raceStatus.getWindSpeedKnots() );
|
||||||
wind.setWindSpeed(raceStatus.getWindSpeedKnots());
|
|
||||||
|
|
||||||
//Current race time.
|
//Current race time.
|
||||||
this.raceClock.setUTCTime(raceStatus.getCurrentTime());
|
this.raceClock.setUTCTime(raceStatus.getCurrentTime());
|
||||||
|
|||||||
Reference in New Issue
Block a user