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]
main
fjc40 9 years ago
parent 7f37dbbcb5
commit f4d5df9df2

@ -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);
}
}

@ -251,7 +251,7 @@ public class BoatLocation extends AC35Data {
* @param angle Angle to convert. double.
* @return short representation of heading.
*/
public static short convertTrueWindAngleShortToDouble(double angle) {
public static short convertTrueWindAngleDoubleToShort(double angle) {
short angleShort = (short) ((angle / 180.0) * 32768.0);

Loading…
Cancel
Save