@ -8,7 +8,8 @@ import java.util.Set;
import java.util.TreeMap ;
import java.util.TreeMap ;
/ * *
/ * *
* Created by fwy13 on 4 / 0 9 / 17.
* New Polars are the revampe of the old Polars class which interpolates the data after being parsed from the Polar Parser
* There can only be one NewPolars instance stored statically however if a boat does happen to have a special case it can be assigned .
* /
* /
public class NewPolars {
public class NewPolars {
@ -22,6 +23,12 @@ public class NewPolars {
newPolars = this ;
newPolars = this ;
}
}
/ * *
* Add polars from the polar table
* @param trueWindSpeed True Wind Speed that the true wind angle and speed corresponds to
* @param trueWindAngle True Wind Angle of the race
* @param boatSpeed The speed the boat should be going at given the true wind angle
* /
public static void addPolars ( double trueWindSpeed , Bearing trueWindAngle , double boatSpeed ) {
public static void addPolars ( double trueWindSpeed , Bearing trueWindAngle , double boatSpeed ) {
double tws = trueWindSpeed ;
double tws = trueWindSpeed ;
double bs = boatSpeed ;
double bs = boatSpeed ;
@ -31,31 +38,33 @@ public class NewPolars {
}
}
polars . get ( tws ) . putIfAbsent ( twa , bs ) ;
polars . get ( tws ) . putIfAbsent ( twa , bs ) ;
polars . get ( tws ) . putIfAbsent ( 360 d - twa , bs ) ;
polars . get ( tws ) . putIfAbsent ( 360 d - twa , bs ) ;
//System.out.println(String.format("tws %f, twa %f, bs %f", tws, twa, bs));
}
}
/ * *
* Linearly Interpolates this should only be called once per parsing of a polar table
* /
public static void linearInterpolatePolars ( ) {
public static void linearInterpolatePolars ( ) {
// double maxTWS = 0;
// for (double key: polars.keySet()){
// if (maxTWS < key){
// maxTWS = key;
// }
// }
/ * for ( double windSpeed : polars . keySet ( ) ) {
if ( ! polars . get ( windSpeed ) . containsKey ( 180 d ) ) {
polars . get ( windSpeed ) . put ( 180 d , windSpeed ) ;
}
} * /
TreeMap < Double , Double > prevTWS = null ;
TreeMap < Double , Double > prevTWS = null ;
TreeMap < Double , TreeMap < Double , Double > > iterablePolars = new TreeMap < > ( polars ) ;
TreeMap < Double , TreeMap < Double , Double > > iterablePolars = new TreeMap < > ( polars ) ;
//this loop averages out the speed between tow angles
//Example: Pair one: 0 degrees, 0 knots
// Pair two: 3 degrees, 6 knots
//This loop will add
//Pair one: 0 degrees, 0 knots
//Pair two: 1 degrees, 2 knots
//Pair three: 2 degrees, 4 knots
//Pair four: 3 degrees, 6 knots
for ( double windSpeed : iterablePolars . keySet ( ) ) {
for ( double windSpeed : iterablePolars . keySet ( ) ) {
TreeMap < Double , Double > tws = iterablePolars . get ( windSpeed ) ;
TreeMap < Double , Double > tws = iterablePolars . get ( windSpeed ) ;
if ( prevTWS = = null ) {
if ( prevTWS = = null ) {
prevTWS = tws ;
prevTWS = tws ;
continue ;
continue ;
}
}
double previousTWA = - 1 ;
double previousTWA = - 1 ;
TreeMap < Double , Double > iterableTWS = new TreeMap < > ( tws ) ;
TreeMap < Double , Double > iterableTWS = new TreeMap < > ( tws ) ;
for ( double twa : iterableTWS . keySet ( ) ) {
for ( double twa : iterableTWS . keySet ( ) ) {
if ( previousTWA = = - 1 ) {
if ( previousTWA = = - 1 ) {
previousTWA = twa ;
previousTWA = twa ;
@ -65,11 +74,10 @@ public class NewPolars {
double speedDiff = iterableTWS . get ( twa ) - iterableTWS . get ( previousTWA ) ;
double speedDiff = iterableTWS . get ( twa ) - iterableTWS . get ( previousTWA ) ;
double prevSpeed = iterableTWS . get ( previousTWA ) ;
double prevSpeed = iterableTWS . get ( previousTWA ) ;
double diff = speedDiff / twaDiff ;
double diff = speedDiff / twaDiff ;
for ( double i = previousTWA ; i < twa ; i + + ) {
for ( double i = previousTWA ; i < twa ; i + + ) {
double mult = i - previousTWA ;
double mult = i - previousTWA ;
double newSpeed = diff * mult + prevSpeed ;
double newSpeed = diff * mult + prevSpeed ;
//System.out.println(newSpeed);
//System.out.println(String.format("tws %f, twa %f, bs %f", windSpeed, i, newSpeed));
tws . put ( i , newSpeed ) ;
tws . put ( i , newSpeed ) ;
}
}
previousTWA = twa ;
previousTWA = twa ;
@ -100,17 +108,18 @@ public class NewPolars {
* @return
* @return
* /
* /
private static int getQuadrant ( double degrees ) {
private static int getQuadrant ( double degrees ) {
return ( ( ( ( int ) degrees % 360 ) + 360 ) % 360 ) / 90 + 1 ;
return ( int ) modulateAngle ( degrees ) / 90 + 1 ;
}
}
private static double getBestSpeedInQuadrant ( int quad , Map < Double , Double > set ) {
private static double getBestSpeedInQuadrant ( int quad , Map < Double , Double > set ) {
double min = ( quad - 1 ) * 90 ;
double min = ( quad - 1 ) * 90 ;
double max = quad * 90 ;
double max = quad * 90 ;
//System.out.println(quad);
//System.out.println(min + " " + max);
double maxAngle = 0 ;
double maxAngle = 0 ;
double maxSpeed = 0 ;
double maxSpeed = 0 ;
double dupAngle = 0 ; //index where speed is duplicated
double dupAngle = 0 ;
//DupAngle will average the angle between maxAngles that have the same speed
//Example: if 150 degrees, 180 degrees, and 210 degrees all go at 10 knots
//then the average will be taken as (150 + 210) / 2 and the angle will be returned on that.
for ( Double s : set . keySet ( ) ) {
for ( Double s : set . keySet ( ) ) {
if ( s > = min & & s < max ) {
if ( s > = min & & s < max ) {
if ( set . get ( s ) > maxSpeed ) {
if ( set . get ( s ) > maxSpeed ) {
@ -121,42 +130,48 @@ public class NewPolars {
dupAngle = s ;
dupAngle = s ;
}
}
}
}
} / *
}
if ( dupAngle ! = 0 ) {
if ( dupAngle ! = 0 ) {
return getClosest ( ( dupAngle + maxAngle ) / 2 , set . keySet ( ) ) ;
return getClosest ( ( dupAngle + maxAngle ) / 2 , set . keySet ( ) ) ;
} * /
}
return maxAngle ;
return maxAngle ;
}
}
/ * *
/ * *
*
* Returns the best VMG that the boat can change to given it ' s current diagonal heading direction .
* @param trueWindAngle
* @param trueWindAngle True wind angle of the race
* @param trueWindSpeed
* @param trueWindSpeed True wind speed of the race
* @param boatAngle
* @param boatAngle Angle that the boat is currently at
* @return
* @return the best vmg that the boat can change to
* /
* /
public static VMG setBestVMG ( Bearing trueWindAngle , double trueWindSpeed , Bearing boatAngle ) {
public static VMG setBestVMG ( Bearing trueWindAngle , double trueWindSpeed , Bearing boatAngle ) {
//System.out.println("VMG AUTO CALLED");
//System.out.println("VMG AUTO CALLED");
//speed
//speed
double closestSpeed = getClosest ( trueWindSpeed , polars . keySet ( ) ) ;
double closestSpeed = getClosest ( trueWindSpeed , polars . keySet ( ) ) ;
double angle = ( ( boatAngle . degrees ( ) - trueWindAngle . degrees ( ) ) % 360 + 360 ) % 360 ;
double angle = modulateAngle ( boatAngle . degrees ( ) - trueWindAngle . degrees ( ) ) ;
int quad = getQuadrant ( angle ) ;
int quad = getQuadrant ( angle ) ;
double bestAngle = getBestSpeedInQuadrant ( quad , polars . get ( closestSpeed ) ) ;
double bestAngle = getBestSpeedInQuadrant ( quad , polars . get ( closestSpeed ) ) ;
Bearing vmgAngle = Bearing . fromDegrees ( ( bestAngle ) % 360 ) ;
double boatSpeed = polars . get ( closestSpeed ) . get ( bestAngle ) ;
double boatSpeed = polars . get ( closestSpeed ) . get ( bestAngle ) ;
double newAngle = ( bestAngle + trueWindAngle . degrees ( ) % 360 + 360 ) % 360 ;
double newAngle = modulateAngle ( bestAngle + trueWindAngle . degrees ( ) ) ;
return new VMG ( boatSpeed , Bearing . fromDegrees ( newAngle ) ) ;
return new VMG ( boatSpeed , Bearing . fromDegrees ( newAngle ) ) ;
}
}
/ * *
* Calculates the speed that a certain angle should be doing
* @param trueWindAngle TrueWind Angle of the race
* @param trueWindSpeed True Wind Speed of the race
* @param boatAngle Angle that the boat is current at
* @return the speed that the boat should be traveling at .
* /
public static double calculateSpeed ( Bearing trueWindAngle , double trueWindSpeed , Bearing boatAngle ) {
public static double calculateSpeed ( Bearing trueWindAngle , double trueWindSpeed , Bearing boatAngle ) {
//speed
//speed
double closestSpeed = getClosest ( trueWindSpeed , polars . keySet ( ) ) ;
double closestSpeed = getClosest ( trueWindSpeed , polars . keySet ( ) ) ;
double angleDiff = ( ( boatAngle . degrees ( ) - trueWindAngle . degrees ( ) ) % 360 + 360 ) % 360 ;
double angleDiff = modulateAngle ( boatAngle . degrees ( ) - trueWindAngle . degrees ( ) ) ;
double closestAngle = getClosest ( angleDiff , polars . get ( closestSpeed ) . keySet ( ) ) ;
double closestAngle = getClosest ( angleDiff , polars . get ( closestSpeed ) . keySet ( ) ) ;
double boatSpeed = polars . get ( closestSpeed ) . get ( closestAngle ) ;
double boatSpeed = polars . get ( closestSpeed ) . get ( closestAngle ) ;
@ -166,6 +181,10 @@ public class NewPolars {
}
}
public static double modulateAngle ( double angle ) {
return ( angle % 360 + 360 ) % 360 ;
}
private Map < Double , TreeMap < Double , Double > > getPolars ( ) {
private Map < Double , TreeMap < Double , Double > > getPolars ( ) {
//this function is just for testing so therefore it is private
//this function is just for testing so therefore it is private
return polars ;
return polars ;
@ -178,7 +197,6 @@ public class NewPolars {
System . out . println ( "==================================================" ) ;
System . out . println ( "==================================================" ) ;
for ( double twa : polars . get ( tws ) . keySet ( ) ) {
for ( double twa : polars . get ( tws ) . keySet ( ) ) {
System . out . println ( "TWA: " + twa + ", Boat Speed: " + polars . get ( tws ) . get ( twa ) ) ;
System . out . println ( "TWA: " + twa + ", Boat Speed: " + polars . get ( tws ) . get ( twa ) ) ;
//System.out.println("--------------------------------------------------");
}
}
}
}
}
}