Added POlar Linear Interpolation #story[1186]

This commit is contained in:
Fan-Wu Yang
2017-09-04 14:17:13 +12:00
parent 34cfe48df0
commit 71dcc8ee6c
5 changed files with 246 additions and 84 deletions
@@ -363,7 +363,7 @@ public class MockRace extends Race {
// Bearing.fromDegrees(0d),
// Bearing.fromDegrees(359.99999d));
VMG newVMG = boat.getPolars().setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
VMG newVMG = NewPolars.setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
System.out.println(newVMG);
//If the new vmg improves velocity, use it.
if (improvesVelocity(boat, newVMG)) {
@@ -380,7 +380,11 @@ public class MockRace extends Race {
// Bearing.fromDegrees(boat.getBearing().degrees() - 1),
// Bearing.fromDegrees(boat.getBearing().degrees() + 1));
//VMG vmg = boat.getPolars().setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
VMG vmg = new VMG(Math.cos (boat.getBearing().radians() - this.getWindDirection().radians()) * this.getWindSpeed() * 4, boat.getBearing()) ;
VMG vmg = new VMG(NewPolars.calculateSpeed(
this.getWindDirection(),
this.getWindSpeed(),
boat.getBearing()
), boat.getBearing()) ;
if (vmg.getSpeed() > 0) {
boat.setCurrentSpeed(vmg.getSpeed());
}
@@ -0,0 +1,151 @@
package mock.model;
import shared.model.Bearing;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Created by fwy13 on 4/09/17.
*/
public class NewPolars {
//true wind speed, <true wind angle, best boat angle>
private static Map<Double, TreeMap<Double, Double>> polars = new TreeMap<>();
public static NewPolars newPolars = null;
public NewPolars(){
newPolars = this;
}
public static void addPolars(double trueWindSpeed, Bearing trueWindAngle, double boatSpeed){
double tws = trueWindSpeed;
double bs = boatSpeed;
double twa = trueWindAngle.degrees();
if (!polars.containsKey(tws)){
polars.put(tws, new TreeMap<>());
}
polars.get(tws).put(twa, bs);
}
public static void linearInterpolatePolars(){
// double maxTWS = 0;
// for (double key: polars.keySet()){
// if (maxTWS < key){
// maxTWS = key;
// }
// }
TreeMap<Double, Double> prevTWS = null;
for (TreeMap<Double, Double> tws: polars.values()){
if (prevTWS == null){
prevTWS = tws;
continue;
}
double previousTWA = -1;
TreeMap<Double, Double> iterableTWS = new TreeMap<>(tws);
for (double twa: iterableTWS.keySet()){
if (previousTWA == -1){
previousTWA = twa;
continue;
}
double twaDiff = twa - previousTWA;
double speedDiff = iterableTWS.get(twa) - iterableTWS.get(previousTWA);
double prevSpeed = iterableTWS.get(previousTWA);
double diff = speedDiff/twaDiff;
for (double i = previousTWA; i < twa; i ++){
double mult = i - previousTWA;
double newSpeed = diff * mult + prevSpeed;
System.out.println(newS);
tws.put(i, newSpeed);
}
}
}
}
private static double getClosest(double value, Set<Double> set){
double closestVal = 0;
double smallestDiff = Double.MAX_VALUE;
for (double d: set){
double diff = Math.abs(value - d);
if (diff < smallestDiff){
closestVal = d;
smallestDiff = diff;
}
}
return closestVal;
}
/**
* Determines which quadrant degrees are in
* 0/360 Degrees
* Quadrant 4 | Quadrant 1
* -----------------------
* Quadrant 3 | Quadrant 2
* @param degrees
* @return
*/
private static int getQuadrant(double degrees){
return ((int) degrees % 360) / 90 + 1;
}
private static double getBestSpeedInQuadrant(int quad, Map<Double, Double> set){
double quadVal = (double)((quad - 1) % 2);// this is as the hash map only has values 0 - 180
double min = quadVal* 90;
double max = (quadVal + 1) * 90;
double maxAngle = 0;
double maxSpeed = 0;
for (Double s: set.keySet()){
if (s >= min && s < max){
if (set.get(s) > maxSpeed){
maxAngle = s;
maxSpeed = set.get(s);
}
}
}
if (quad > 2){
maxAngle += 180;
}
return maxAngle;
}
/**
*
* @param trueWindAngle
* @param trueWindSpeed
* @param boatAngle
* @return
*/
public static VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
//speed
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
//not using true vmg, using general concept
double angle = Math.abs(trueWindAngle.degrees() - boatAngle.degrees());
int quad = getQuadrant(boatAngle.degrees());
double bestAngle = getBestSpeedInQuadrant(quad, polars.get(closestSpeed));
Bearing vmgAngle = Bearing.fromDegrees((bestAngle) % 360);
double boatSpeed = polars.get(closestSpeed).get(bestAngle);
return new VMG(boatSpeed, Bearing.fromDegrees(vmgAngle.degrees() + trueWindAngle.degrees()));
}
public static double calculateSpeed(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
//speed
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
double angleDiff = Math.abs(trueWindAngle.degrees() - boatAngle.degrees()) % 180;
double closestAngle = getClosest(angleDiff, polars.get(closestSpeed).keySet());
double boatSpeed = polars.get(closestSpeed).get(closestAngle);
return boatSpeed;
}
}
@@ -22,8 +22,6 @@ public class Polars {
*/
private HashMap<Double, List<Bearing>> polarAngles = new HashMap<>();
//true wind speed, <true wind angle, best boat angle>
private Map<Double, HashMap<Double, Double>> polars = new TreeMap<>();
@@ -77,85 +75,6 @@ public class Polars {
}
public void addPolars(double trueWindSpeed, Bearing trueWindAngle, double boatSpeed){
double tws = trueWindSpeed;
double bs = boatSpeed;
double twa = trueWindAngle.degrees();
if (!polars.containsKey(tws)){
polars.put(tws, new HashMap<>());
}
polars.get(tws).put(twa, bs);
}
private static double getClosest(double value, Set<Double> set){
double closestVal = 0;
double smallestDiff = Double.MAX_VALUE;
for (double d: set){
double diff = Math.abs(value - d);
if (diff < smallestDiff){
closestVal = d;
smallestDiff = diff;
}
}
return closestVal;
}
/**
* Determines which quadrant degrees are in
* 0/360 Degrees
* Quadrant 4 | Quadrant 1
* -----------------------
* Quadrant 3 | Quadrant 2
* @param degrees
* @return
*/
private static int getQuadrant(double degrees){
return ((int) degrees % 360) / 90 + 1;
}
private static double getBestSpeedInQuadrant(int quad, HashMap<Double, Double> set){
double quadVal = (double)((quad - 1) % 2);// this is as the hash map only has values 0 - 180
double min = quadVal* 90;
double max = (quadVal + 1) * 90;
double maxAngle = 0;
double maxSpeed = 0;
for (Double s: set.keySet()){
if (s >= min && s < max){
if (set.get(s) > maxSpeed){
maxAngle = s;
maxSpeed = set.get(s);
}
}
}
if (quad > 2){
maxAngle += 180;
}
return maxAngle;
}
/**
*
* @param trueWindAngle
* @param trueWindSpeed
* @param boatAngle
* @return
*/
public VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
//speed
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
//not using true vmg, using general concept
double angle = Math.abs(trueWindAngle.degrees() - boatAngle.degrees());
int quad = getQuadrant(boatAngle.degrees());
double bestAngle = getBestSpeedInQuadrant(quad, polars.get(closestSpeed));
Bearing vmgAngle = Bearing.fromDegrees((bestAngle + trueWindSpeed) % 360);
double boatSpeed = Math.abs(trueWindSpeed * Math.cos(vmgAngle.radians())) * 4;
return new VMG(boatSpeed, vmgAngle);
}
/**
* Calculates the VMG for a given wind angle, wind speed, and angle to destination. Will only return VMGs that have a true bearing (angle) within a given bound - this is to ensure that you can calculate VMGs without going out of bounds.
* <br>