Mock.Race:
An alternate tacking implementation during race simulate. Doesn't handle keeping the boats in-bounds, and sometimes has issues with landing directly on a mark. Also seems to use wrong starting velocities (from the XML file). #story[873]
This commit is contained in:
@@ -23,6 +23,9 @@ public class Boat {
|
|||||||
private double heading;
|
private double heading;
|
||||||
private Polars polars;
|
private Polars polars;
|
||||||
|
|
||||||
|
///This stores the milliseconds since the boat has changed its tack, to allow for only updating the tack every X milliseconds.
|
||||||
|
private long timeSinceTackChange = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boat initialiser which keeps all of the information of the boat.
|
* Boat initialiser which keeps all of the information of the boat.
|
||||||
*
|
*
|
||||||
@@ -223,4 +226,21 @@ public class Boat {
|
|||||||
public void setPolars(Polars polars) {
|
public void setPolars(Polars polars) {
|
||||||
this.polars = polars;
|
this.polars = polars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time since the boat changed its tack, in milliseconds.
|
||||||
|
* @return Time since the boat changed its tack, in milliseconds.
|
||||||
|
*/
|
||||||
|
public long getTimeSinceTackChange() {
|
||||||
|
return timeSinceTackChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the time since the boat changed it's tack, in milliseconds.
|
||||||
|
* @param timeSinceTackChange Time since the boat changed its tack, in milliseconds.
|
||||||
|
*/
|
||||||
|
public void setTimeSinceTackChange(long timeSinceTackChange) {
|
||||||
|
this.timeSinceTackChange = timeSinceTackChange;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class Event {
|
|||||||
System.out.println("Sending Boat");
|
System.out.println("Sending Boat");
|
||||||
sendBoatData();
|
sendBoatData();
|
||||||
|
|
||||||
int scaleFactor = 5;//TEMP - was 15.
|
int scaleFactor = 25;//TEMP - was 15.
|
||||||
Race newRace = new Race(raceDataSource, scaleFactor, mockOutput);
|
Race newRace = new Race(raceDataSource, scaleFactor, mockOutput);
|
||||||
new Thread((newRace)).start();
|
new Thread((newRace)).start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class Race implements Runnable {
|
|||||||
this.boundary = boundary;
|
this.boundary = boundary;
|
||||||
|
|
||||||
this.windSpeed = 12;//TODO could use input parameters for these. And should fluctuate during race.
|
this.windSpeed = 12;//TODO could use input parameters for these. And should fluctuate during race.
|
||||||
this.windDirection = 0;
|
this.windDirection = 180;
|
||||||
|
|
||||||
//TODO refactor
|
//TODO refactor
|
||||||
this.startTime = System.currentTimeMillis() + (this.PRERACE_TIME / this.scaleFactor);
|
this.startTime = System.currentTimeMillis() + (this.PRERACE_TIME / this.scaleFactor);
|
||||||
@@ -246,6 +246,7 @@ public class Race implements Runnable {
|
|||||||
startLeg.calculateDistance();
|
startLeg.calculateDistance();
|
||||||
boat.setCurrentLeg(startLeg);
|
boat.setCurrentLeg(startLeg);
|
||||||
boat.setHeading(boat.calculateHeading());
|
boat.setHeading(boat.calculateHeading());
|
||||||
|
boat.setTimeSinceTackChange(999999);//We set a large time since tack change so that it calculates a new VMG when the simulation starts.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,27 +309,40 @@ public class Race implements Runnable {
|
|||||||
protected void updatePosition(Boat boat, int millisecondsElapsed) {
|
protected void updatePosition(Boat boat, int millisecondsElapsed) {
|
||||||
|
|
||||||
//distanceTravelled = velocity (nm p hr) * time taken to update loop
|
//distanceTravelled = velocity (nm p hr) * time taken to update loop
|
||||||
double distanceTravelled = (boat.getScaledVelocity() * millisecondsElapsed) / 3600000;
|
double distanceTravelled = (boat.getVelocity() * this.scaleFactor * millisecondsElapsed) / 3600000;
|
||||||
|
|
||||||
double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg();
|
double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg();
|
||||||
|
|
||||||
boolean finish = boat.getCurrentLeg().getName().equals("Finish");
|
boolean finish = boat.getCurrentLeg().getName().equals("Finish");
|
||||||
if (!finish) {
|
if (!finish) {
|
||||||
int windAngle = 360;//todo - get the wind speed from somewhere, using 360 for now
|
|
||||||
if(boat.getCurrentLeg().getName().endsWith("to Windward Gate")){//todo something is broken in this if statement, not sure what
|
|
||||||
double totalDistanceTravelledInTack = distanceTravelled + boat.getDistanceTravelledInTack();
|
double totalDistanceTravelledInTack = distanceTravelled + boat.getDistanceTravelledInTack();
|
||||||
|
|
||||||
double bound1 = (boat.calculateBearingToDestination() - 90) % 360;
|
double bound1 = (boat.calculateBearingToDestination() - 90) % 360;
|
||||||
double bound2 = (boat.calculateBearingToDestination() + 90) % 360;
|
double bound2 = (boat.calculateBearingToDestination() + 90) % 360;
|
||||||
|
//TODO the actual bearing bounds need to be the interval in which the boat won't go out of bounds.
|
||||||
|
bound1 = 0;
|
||||||
|
bound2 = 360;
|
||||||
|
|
||||||
VMG newHeading = boat.getPolars().calculateVMG(windAngle, 30,
|
boat.setTimeSinceTackChange(boat.getTimeSinceTackChange() + this.scaleFactor * millisecondsElapsed);
|
||||||
boat.calculateBearingToDestination(), min(bound1, bound2), max(bound1,bound2));
|
|
||||||
|
|
||||||
|
|
||||||
double azimuth = newHeading.getBearing();
|
//How fast a boat can turn, in degrees per millisecond.
|
||||||
if (newHeading.getBearing() > 180){
|
double turnRate = 0.03; //Roughly 30 per second, or 12 seconds per revolution.
|
||||||
azimuth = newHeading.getBearing() -360;
|
|
||||||
}
|
//How much the boat is allowed to turn, considering how long since it last turned.
|
||||||
|
double turnAngle = turnRate * boat.getTimeSinceTackChange();
|
||||||
|
|
||||||
|
|
||||||
|
//System.out.println("boat " + boat.getAbbrev() + " turn angle is " + turnAngle + ".");//TEMP DEBUG REMOVE
|
||||||
|
|
||||||
|
//Find the bounds on what angle the boat is allowed to travel at.
|
||||||
|
bound1 = boat.getHeading() - turnAngle;
|
||||||
|
bound2 = boat.getHeading() + turnAngle;
|
||||||
|
|
||||||
|
|
||||||
|
VMG newHeading = boat.getPolars().calculateVMG(this.windDirection, this.windSpeed,
|
||||||
|
boat.calculateBearingToDestination(), bound1, bound2);
|
||||||
|
|
||||||
|
|
||||||
// if (!GPSCoordinate.isInsideBoundary(calculatePosition(boat.getCurrentPosition(),
|
// if (!GPSCoordinate.isInsideBoundary(calculatePosition(boat.getCurrentPosition(),
|
||||||
// 1, azimuth), boundary)){
|
// 1, azimuth), boundary)){
|
||||||
@@ -337,35 +351,55 @@ public class Race implements Runnable {
|
|||||||
// newHeading.bearing = tempHeading;
|
// newHeading.bearing = tempHeading;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
//Is this new VMG better than the current VMG?
|
||||||
|
|
||||||
|
double angleBetweenDestAndHeading = boat.getHeading() - boat.calculateBearingToDestination();
|
||||||
|
double angleBetweenDestAndNewVMG = newHeading.getBearing() - boat.calculateBearingToDestination();
|
||||||
|
double currentVelocity = cos(Math.toRadians(angleBetweenDestAndHeading)) * boat.getVelocity();
|
||||||
|
double vmgVelocity = cos(Math.toRadians(angleBetweenDestAndNewVMG)) * newHeading.getSpeed();
|
||||||
|
//System.out.println("boat " + boat.getAbbrev() + " current velocity is " + currentVelocity + " knots, possible VMG is " + vmgVelocity + " knots.");//TEMP DEBUG REMOVE
|
||||||
|
if (vmgVelocity > currentVelocity) {
|
||||||
boat.setHeading(newHeading.getBearing());
|
boat.setHeading(newHeading.getBearing());
|
||||||
boat.setVelocity(newHeading.getSpeed());
|
boat.setVelocity(newHeading.getSpeed());
|
||||||
|
boat.setTimeSinceTackChange(0);
|
||||||
|
|
||||||
|
//System.out.println("boat " + boat.getAbbrev() + " has a new bearing " + boat.getHeading() + " degrees, and is " + boat.calculateDistanceToNextMarker() + " nautical miles to the next marker. Velocity to next marker is " + boat.getVelocity() + " knots.");//TEMP DEBUG REMOVE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//TODO one way to fix the boat's rapid turning it to only update the velocity/heading every X seconds (e.g., every 5 seconds).
|
||||||
|
//TODO may need a lower tack period
|
||||||
|
//TODO another way would be to allow boats use a better VMG if it is within turnRate * timeSinceTackChange. E.g., after 100ms a boat can select a more optimal VMG within 5deg of their current bearing. After 500ms VMG can be within 25deg of current bearing. After 2sec it can be 100deg of bearing, etc...
|
||||||
|
|
||||||
//calc the distance travelled in a straight line to windward
|
//calc the distance travelled in a straight line to windward
|
||||||
double angleBetweenDestAndHeading = newHeading.getBearing() - boat.calculateBearingToDestination();
|
//double angleBetweenDestAndHeading = boat.getHeading() - boat.calculateBearingToDestination();
|
||||||
totalDistanceTravelled = cos(angleBetweenDestAndHeading)*totalDistanceTravelledInTack;
|
totalDistanceTravelled = cos(Math.toRadians(angleBetweenDestAndHeading))*totalDistanceTravelledInTack;
|
||||||
boat.setDistanceTravelledInLeg(totalDistanceTravelled);
|
boat.setDistanceTravelledInLeg(totalDistanceTravelled);
|
||||||
|
|
||||||
|
|
||||||
//Calculate boat's new position by adding the distance travelled onto the start point of the leg
|
//Calculate boat's new position by adding the distance travelled onto the start point of the leg
|
||||||
|
double azimuth = boat.getHeading();
|
||||||
|
if (azimuth > 180) {
|
||||||
|
azimuth = azimuth - 360;
|
||||||
|
}
|
||||||
boat.setCurrentPosition(calculatePosition(boat.getCurrentPosition(),
|
boat.setCurrentPosition(calculatePosition(boat.getCurrentPosition(),
|
||||||
totalDistanceTravelledInTack, azimuth));
|
totalDistanceTravelledInTack, azimuth));
|
||||||
|
|
||||||
}else{
|
|
||||||
boat.setHeading(boat.calculateHeading());
|
|
||||||
//update boat's distance travelled
|
|
||||||
boat.setDistanceTravelledInLeg(totalDistanceTravelled);
|
|
||||||
//Calculate boat's new position by adding the distance travelled onto the start point of the leg
|
|
||||||
boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartMarker().getAverageGPSCoordinate(),
|
|
||||||
totalDistanceTravelled, boat.calculateAzimuth(boat.getCurrentLeg().getStartMarker().getAverageGPSCoordinate(),
|
|
||||||
boat.getCurrentLeg().getEndMarker().getAverageGPSCoordinate())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkPosition(Boat boat, long timeElapsed) {
|
protected void checkPosition(Boat boat, long timeElapsed) {
|
||||||
System.out.println(boat.getDistanceTravelledInLeg());
|
//System.out.println(boat.getDistanceTravelledInLeg());
|
||||||
System.out.println(boat.getCurrentLeg().getDistance());
|
//System.out.println(boat.getCurrentLeg().getDistance());
|
||||||
System.out.println(" ");
|
//System.out.println(" ");
|
||||||
if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) {
|
//if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) {
|
||||||
|
//The distance (in nautical miles) within which the boat needs to get in order to consider that it has reached the marker.
|
||||||
|
double epsilon = 100.0 / Constants.NMToMetersConversion; //100 meters. TODO should be more like 5-10.
|
||||||
|
if (boat.calculateDistanceToNextMarker() < epsilon) {
|
||||||
//boat has passed onto new leg
|
//boat has passed onto new leg
|
||||||
if (boat.getCurrentLeg().getName().equals("Finish")) {
|
if (boat.getCurrentLeg().getName().equals("Finish")) {
|
||||||
//boat has finished
|
//boat has finished
|
||||||
@@ -387,6 +421,9 @@ public class Race implements Runnable {
|
|||||||
boat.setCurrentLeg(nextLeg);
|
boat.setCurrentLeg(nextLeg);
|
||||||
//Add overshoot distance into the distance travelled for the next leg
|
//Add overshoot distance into the distance travelled for the next leg
|
||||||
boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg());
|
boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg());
|
||||||
|
|
||||||
|
//Setting a high value for this allows the boat to immediately do a large turn, as it has needs to in order to get to the next mark.
|
||||||
|
boat.setTimeSinceTackChange(999999);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user