Mock.Polars:
Fixed a bug where calculateVMG was placing velocity into the VMG object, instead of speed. Maybe fixed a bug when a bearingLowerBound which is greater than bearingUpperBound is provided. Added another test case. Mock.Constants: Added knots to millimeters per second conversion factor. Mock.Boat: Added calculateDIstanceToNextMarker function, which returns the distance, in nautical miles, to the next mark. Mock.Race: Added wind direction as a race property. Added wind speed as a race property. The race status messages sent by Race now use Race's wind speed and direction. #story[873]
This commit is contained in:
@@ -8,5 +8,8 @@ public class Constants {
|
||||
|
||||
public static final int NMToMetersConversion = 1852; // 1 nautical mile = 1852 meters
|
||||
|
||||
///1 knot = 514.444 millimeters per second.
|
||||
public static final double KnotsToMMPerSecond = 514.444;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package seng302.Model;
|
||||
|
||||
import org.geotools.referencing.GeodeticCalculator;
|
||||
import seng302.Constants;
|
||||
|
||||
|
||||
/**
|
||||
@@ -85,6 +86,31 @@ public class Boat {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the distance between the boat and its target marker in nautical miles (1.852 km).
|
||||
* @return The distance (in nautical miles) between the boat and its target marker.
|
||||
*/
|
||||
public double calculateDistanceToNextMarker() {
|
||||
|
||||
GeodeticCalculator calc = new GeodeticCalculator();
|
||||
|
||||
GPSCoordinate startMarker = this.getCurrentPosition();
|
||||
|
||||
//When boats finish, their "current leg" doesn't have an end marker.
|
||||
if (this.getCurrentLeg().getEndMarker() == null) {
|
||||
return 0d;
|
||||
}
|
||||
|
||||
GPSCoordinate endMarker = this.getCurrentLeg().getEndMarker().getAverageGPSCoordinate();
|
||||
|
||||
//Add points to calculator.
|
||||
calc.setStartingGeographicPoint(startMarker.getLongitude(), startMarker.getLatitude());
|
||||
calc.setDestinationGeographicPoint(endMarker.getLongitude(), endMarker.getLatitude());
|
||||
|
||||
//Convert meters to nautical miles.
|
||||
return calc.getOrthodromicDistance() / Constants.NMToMetersConversion;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -85,10 +85,16 @@ public class Polars {
|
||||
* @param destinationAngle The angle between the boat and the destination point.
|
||||
* @param bearingLowerBound The lowest bearing (angle) that the boat may travel on.
|
||||
* @param bearingUpperBound The highest bearing (angle) that the boat may travel on.
|
||||
* @return
|
||||
* @return The VMG.
|
||||
*/
|
||||
public VMG calculateVMG(double trueWindAngle, double trueWindSpeed, double destinationAngle, double bearingLowerBound, double bearingUpperBound) {
|
||||
|
||||
//TODO BUG there may be a bug when you provide a bearingUpperBound < bearingLowerBound (e.g., lower = 340, upper = 15).
|
||||
bearingLowerBound = ((bearingLowerBound % 360d) + 360d) % 360d;
|
||||
bearingUpperBound = ((bearingUpperBound % 360d) + 360d) % 360d;
|
||||
if (bearingLowerBound > bearingUpperBound) {
|
||||
bearingLowerBound -= 360d;
|
||||
}
|
||||
|
||||
//Sorts polar angles.
|
||||
for (ArrayList<Double> angles : this.polarAngles.values()) {
|
||||
@@ -119,7 +125,6 @@ public class Polars {
|
||||
}
|
||||
|
||||
}
|
||||
//TODO for wind speeds larger than any in the Polars table, we will simply not find an upper bound, and therefore never calculate an upper VMG, or interpolate between them.
|
||||
|
||||
|
||||
|
||||
@@ -218,7 +223,7 @@ public class Polars {
|
||||
|
||||
//Check that the velocity is better.
|
||||
if (vmgTemp > bestVMGVelocity) {
|
||||
bestVMGVelocity = vmgTemp;
|
||||
bestVMGVelocity = interpolatedSpeed;
|
||||
bestVMGAngle = trueBoatBearing;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.geotools.referencing.GeodeticCalculator;
|
||||
import seng302.Constants;
|
||||
import seng302.DataInput.RaceDataSource;
|
||||
import seng302.MockOutput;
|
||||
import seng302.Networking.Messages.BoatLocation;
|
||||
import seng302.Networking.Messages.BoatStatus;
|
||||
import seng302.Networking.Messages.Enums.BoatStatusEnum;
|
||||
import seng302.Networking.Messages.RaceStatus;
|
||||
@@ -47,6 +48,11 @@ public class Race implements Runnable {
|
||||
private int finished = 0;
|
||||
private List<GPSCoordinate> boundary;
|
||||
|
||||
///Wind direction bearing.
|
||||
private double windDirection = 0;
|
||||
///Wind speed (knots). Convert this to millimeters per second before passing to RaceStatus.
|
||||
private double windSpeed = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Initailiser for Race
|
||||
@@ -65,6 +71,9 @@ public class Race implements Runnable {
|
||||
this.mockOutput = mockOutput;
|
||||
this.boundary = boundary;
|
||||
|
||||
this.windSpeed = 12;//TODO could use input parameters for these. And should fluctuate during race.
|
||||
this.windDirection = 0;
|
||||
|
||||
//TODO refactor
|
||||
this.startTime = System.currentTimeMillis() + (this.PRERACE_TIME / this.scaleFactor);
|
||||
|
||||
@@ -140,7 +149,7 @@ public class Race implements Runnable {
|
||||
boatOffset = (boatOffset + 1) % (startingBoats.size());
|
||||
|
||||
if (timeLeft <= 60000/scaleFactor && timeLeft > 0) {
|
||||
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 2, startTime, 0, 2300, 1, boatStatuses);
|
||||
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 2, startTime, BoatLocation.convertHeadingDoubleToInt(windDirection), (int) (windSpeed * Constants.KnotsToMMPerSecond), 1, boatStatuses);
|
||||
mockOutput.parseRaceStatus(raceStatus);
|
||||
}
|
||||
else if (timeLeft <= 0) {
|
||||
@@ -151,7 +160,7 @@ public class Race implements Runnable {
|
||||
stop();
|
||||
}
|
||||
else {
|
||||
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 1, startTime, 0, 2300,1, boatStatuses);
|
||||
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 1, startTime, BoatLocation.convertHeadingDoubleToInt(windDirection), (int) (windSpeed * Constants.KnotsToMMPerSecond),1, boatStatuses);
|
||||
mockOutput.parseRaceStatus(raceStatus);
|
||||
}
|
||||
currentTime = System.currentTimeMillis();
|
||||
@@ -182,6 +191,7 @@ public class Race implements Runnable {
|
||||
if (boatsFinished < startingBoats.size()) {
|
||||
//Get the current time.
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
//Update the total elapsed time.
|
||||
totalTimeElapsed = currentTime - timeRaceStarted;
|
||||
ArrayList<BoatStatus> boatStatuses = new ArrayList<BoatStatus>();
|
||||
@@ -205,7 +215,7 @@ public class Race implements Runnable {
|
||||
boat.getCurrentLeg().getLegNumber() >= 0 ? BoatStatusEnum.RACING : BoatStatusEnum.DNF, boat.getCurrentLeg().getLegNumber()));
|
||||
}
|
||||
if (startingBoats.size()==finished){
|
||||
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 4, startTime, 0, 2300, 2, boatStatuses);//TODO FIX the second currentTime is a placeholder! Also, replace magic values.
|
||||
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 4, startTime, BoatLocation.convertHeadingDoubleToInt(windDirection), (int) (windSpeed * Constants.KnotsToMMPerSecond), 2, boatStatuses);//TODO FIX replace magic values.
|
||||
mockOutput.parseRaceStatus(raceStatus);
|
||||
}
|
||||
} else {
|
||||
@@ -213,7 +223,7 @@ public class Race implements Runnable {
|
||||
}
|
||||
}
|
||||
boatOffset = (boatOffset + 1) % (startingBoats.size());
|
||||
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 3, startTime, 0, 2300, 2, boatStatuses);//TODO FIX the second currentTime is a placeholder! Also, replace magic values.
|
||||
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 3, startTime, BoatLocation.convertHeadingDoubleToInt(windDirection), (int) (windSpeed * Constants.KnotsToMMPerSecond), 2, boatStatuses);//TODO FIX replace magic values.
|
||||
mockOutput.parseRaceStatus(raceStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,25 @@ public class PolarsTest {
|
||||
//assertEquals(calcVMGAngle3, vmgAngle3, angleEpsilon);
|
||||
//assertEquals(calcVMGSpeed3, vmgSpeed3, speedEpsilon);
|
||||
|
||||
|
||||
//Test 4.
|
||||
//This test has a wind speed of 0.
|
||||
double windAngle4 = 5;
|
||||
double destAngle4 = 100;
|
||||
double windSpeed4 = 0;//knots
|
||||
double vmgAngle4 = 88;
|
||||
double vmgSpeed4 = 12;
|
||||
|
||||
VMG calcVMG4 = polars.calculateVMG(windAngle4, windSpeed4, destAngle4, 0, 360);
|
||||
double calcVMGAngle4 = calcVMG4.getBearing();
|
||||
double calcVMGSpeed4 = calcVMG4.getSpeed();
|
||||
|
||||
System.out.println("VMG speed = " + calcVMGSpeed4 + " , VMG angle = " + calcVMGAngle4);//TEMP DEBUG REMOVE
|
||||
|
||||
|
||||
//assertEquals(calcVMGAngle4, vmgAngle4, angleEpsilon);
|
||||
//assertEquals(calcVMGSpeed4, vmgSpeed4, speedEpsilon);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user