From 6f9249e2380db12ff096fbc75e11344e54520c6c Mon Sep 17 00:00:00 2001 From: fjc40 Date: Sat, 13 May 2017 17:10:06 +1200 Subject: [PATCH 1/2] Mock.PolarParser. Fixed a bug where it would only parse the first half of each row. Mock.Polars. addEstimate also builds up a unique list of angles from the data file, instead of dynamically generating that when calculating a VMG. addEstimate also adds estimates with negative angles (e.g., 45deg+windSpeed+boatSpeed, and -45deg+windSpeed+boatSpeed). calculateVMG now accepts an upper and lower bounds to the allowed VMG bearing it returns - this way you can get VMGs only within a certain angle interval (e.g., [16, 99] degrees). Also fixed some bugs in calculateVMG where it wasn't actually using the angles and such correctly. Improved the test case slightly, but still need to calculate correct values by hand. #story[873] --- .../java/seng302/DataInput/PolarParser.java | 3 +- mock/src/main/java/seng302/Model/Polars.java | 113 +++++++++++++----- .../test/java/seng302/Model/PolarsTest.java | 44 +++++-- 3 files changed, 121 insertions(+), 39 deletions(-) diff --git a/mock/src/main/java/seng302/DataInput/PolarParser.java b/mock/src/main/java/seng302/DataInput/PolarParser.java index 5a187192..f9ad3264 100644 --- a/mock/src/main/java/seng302/DataInput/PolarParser.java +++ b/mock/src/main/java/seng302/DataInput/PolarParser.java @@ -81,8 +81,7 @@ public class PolarParser { //For each pair of columns (the pair is angle, speed). //We start at column 1 since column 0 is the wind speed column. - // (row.length - 1) / 2 means the number of pairs of angle+speed. - for (int i = 1; i < (row.length - 1) / 2; i += 2) { + for (int i = 1; i < row.length; i += 2) { //Add angle+speed=velocity estimate to polar table. try { diff --git a/mock/src/main/java/seng302/Model/Polars.java b/mock/src/main/java/seng302/Model/Polars.java index 2863db48..f6844d0e 100644 --- a/mock/src/main/java/seng302/Model/Polars.java +++ b/mock/src/main/java/seng302/Model/Polars.java @@ -17,6 +17,9 @@ public class Polars { ///Internal store of data. Maps pair to boatSpeed. private HashMap, Double> polarValues = new HashMap<>(); + ///Stores a list of angles from the polar table - this is used during the calculateVMG function. + private ArrayList polarAngles = new ArrayList<>(); + /** * Ctor. */ @@ -26,26 +29,56 @@ public class Polars { /** * Adds an estimated velocity to the polar table object, for a given (windSpeed, windAngle) pair. That is, stores a mapping from (windSpeed, windAngle) to (boatVelocity). + * Note: an estimate means given a specific wind speed of trueWindSpeed, if the boat travels relativeWindAngle degrees towards the wind, it will move at boatSpeed knots. E.g., trueWindSpeed = 20kn, relativeWindAngle = 45 degrees, boatSpeed = 25kn. If the boat travels towards the wind, plus or minus 45 degrees either side, it will move at 25kn. * @param trueWindSpeed The true wind speed of the estimate. - * @param trueWindAngle The true wind angle of the estimate. + * @param relativeWindAngle The relative wind angle between the wind direction + 180 degrees and the boat's direction of the estimate. * @param boatSpeed The boat speed of the estimate. */ - public void addEstimate(double trueWindSpeed, double trueWindAngle, double boatSpeed){ - Pair newKey = new Pair(trueWindSpeed, trueWindAngle); - polarValues.put(newKey, boatSpeed); + public void addEstimate(double trueWindSpeed, double relativeWindAngle, double boatSpeed){ + + //We also add the same values with a negative angle, as the data file contains data for 0-180 degrees, but we also need 180-360 degrees. This is because it may turn out that going 5 degrees into the wind gives us, say, 9knots, but -5 into the wind may give us 10knots, towards our destination. + + //Add estimate to map. + Pair newKeyPositive = new Pair(trueWindSpeed, relativeWindAngle); + polarValues.put(newKeyPositive, boatSpeed); + + double negativeAngle = -relativeWindAngle; + Pair newKeyNegative = new Pair(trueWindSpeed, negativeAngle); + polarValues.put(newKeyNegative, boatSpeed); + + + //Add angle to angle list. + if (!this.polarAngles.contains(relativeWindAngle)) { + this.polarAngles.add(relativeWindAngle); + } + + if (!this.polarAngles.contains(negativeAngle)) { + this.polarAngles.add(negativeAngle); + } + + + //System.out.println("adding wind speed: " + trueWindSpeed + ", wind angle: " + relativeWindAngle + ", boat speed: " + boatSpeed);//TEMP DEBUG REMOVE + //System.out.println("adding wind speed: " + trueWindSpeed + ", wind angle: " + negativeAngle + ", boat speed: " + boatSpeed);//TEMP DEBUG REMOVE + + + } /** - * Calculates the VMG for a given wind angle, wind speed, and angle to destination. + * 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. If you don't care about bearing bounds, simple pass in lower = 0, upper = 360. * @param trueWindAngle The current true wind angle. * @param trueWindSpeed The current true wind speed. * @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 */ - public VMG calculateVMG(double trueWindAngle, double trueWindSpeed, double destinationAngle) { + public VMG calculateVMG(double trueWindAngle, double trueWindSpeed, double destinationAngle, double bearingLowerBound, double bearingUpperBound) { //Currently a fairly simple implementation where we find the wind speed that is less than or equal to the current wind speed (the lower bound), and then find the specific angle (with no interpolation) that gives the best VMG. + //TODO we need to add interpolation between angles for a given wind speed (e.g., we have 0 deg, 30 deg, but the optimal bearing may be 17.3 degrees). + //TODO we should also interpolate between wind speeds (e.g., we have 12kn and 16kn, but if the wind speed is actually 15.999kn, then we should interpolate to get a more accurate final value). double polarWindSpeed = 0; @@ -60,41 +93,65 @@ public class Polars { } } - //We create a list of wind angles because we need (speed, angle) pairs to look into the map. - ArrayList windAngles = new ArrayList<>(); - for (Pair key : this.polarValues.keySet()) { - - //Don't add angles multiple times. - double angle = key.getValue(); - if (!windAngles.contains(angle)) { - windAngles.add(angle); - } - } //Find the angle with the best VMG. - //TODO need to differentiate between windward and leeward. double bestVMGAngle = 0; double bestVMGVelocity = 0; - for (double tackAngle : windAngles) { - Pair key = new Pair(polarWindSpeed, tackAngle); + for (double polarAngle : this.polarAngles) { + + Pair key = new Pair<>(polarWindSpeed, polarAngle); + + //System.out.println("selecting " + polarAngle + " degrees from wind dir, and " + polarWindSpeed + "knots wind speed.");//TEMP DEBUG REMOVE + + //We need to check that the map contains this (speed, angle) pair because some of the datafile entries have different angles in the same column (e.g., (16kn, 45 deg) and (20kn, 43 deg), but there is no (20kn, 45 deg). if (this.polarValues.containsKey(key)) { + //This is the velocity from the polar table at this wind speed/angle. double estVelocity = this.polarValues.get(key); - double angleBetweenDestAndTack = tackAngle - destinationAngle; - //This is the estimated velocity towards the target (e.g., angling away from the target reduces velocity). - double vmgTemp = Math.cos(angleBetweenDestAndTack) * estVelocity; - - //Check that the velocity is better. - if (vmgTemp > bestVMGVelocity) { - bestVMGVelocity = vmgTemp; - bestVMGAngle = tackAngle; + + + //System.out.println("speed is est. " + estVelocity + "knots.");//TEMP DEBUG REMOVE + + //This is the true bearing of the boat, if it went at the angle against the wind. + //For polarAngle > 90, it means that the boat is actually going _with_ the wind (gybe). + double trueBoatBearing = trueWindAngle + polarAngle + 180d; + while (trueBoatBearing >= 360) { + trueBoatBearing -= 360; } + //System.out.println("true boat bearing is " + trueBoatBearing + " degrees.");//TEMP DEBUG REMOVE + + //Check that the trueBoatBearing is actually within the accepted interval. + if ((trueBoatBearing <= bearingLowerBound) || (trueBoatBearing >= bearingUpperBound)) { + //If the angle is too small or too great, don't use it - skip to the next iteration. + continue; + } + else { + //If it is acceptable... + + //System.out.println("this is in the acceptable range");//TEMP DEBUG REMOVE + + //This is the delta angle between the boat's true bearing and the destination. + double angleBetweenDestAndTack = trueBoatBearing - destinationAngle; + //This is the estimated velocity towards the target (e.g., angling away from the target reduces velocity). + double vmgTemp = Math.cos(Math.toRadians(angleBetweenDestAndTack)) * estVelocity; + + //System.out.println("angle between destination and boat bearing is " + angleBetweenDestAndTack + " degrees.");//TEMP DEBUG REMOVE + //System.out.println("this has an overall velocity of " + vmgTemp + "knots.");//TEMP DEBUG REMOVE + + //Check that the velocity is better. + if (vmgTemp > bestVMGVelocity) { + //System.out.println("This is the new best velocity. Previous was " + bestVMGVelocity + "knots at " + bestVMGAngle + " degrees.");//TEMP DEBUG REMOVE + bestVMGVelocity = vmgTemp; + bestVMGAngle = trueBoatBearing; + } + + } } } - System.out.println("VMG speed = " + bestVMGVelocity + " , VMG angle = " + bestVMGAngle);//TEMP DEBUG REMOVE + //System.out.println("VMG speed = " + bestVMGVelocity + " , VMG angle = " + bestVMGAngle);//TEMP DEBUG REMOVE //Create the VMG object and return it. return new VMG(bestVMGVelocity, bestVMGAngle); diff --git a/mock/src/test/java/seng302/Model/PolarsTest.java b/mock/src/test/java/seng302/Model/PolarsTest.java index a12603c5..c28e78f1 100644 --- a/mock/src/test/java/seng302/Model/PolarsTest.java +++ b/mock/src/test/java/seng302/Model/PolarsTest.java @@ -11,6 +11,7 @@ import static org.testng.Assert.*; */ public class PolarsTest { + @Test /** * Tests if we can parse a polar data file (stored in a string), create a polar table, and calculate VMG for a variety of values. @@ -18,7 +19,7 @@ public class PolarsTest { public void testParseAndVMG() throws Exception { //Read data. - Polars polars; + Polars polars = null; try { //Parse data file. polars = PolarParser.parse("polars/acc_polars.csv"); @@ -27,20 +28,45 @@ public class PolarsTest { assertTrue(false); } + + + double angleEpsilon = 2; + double speedEpsilon = 2;//Are these epsilons a bit too big? + //Test 1. - //TODO make these tests actually do something when the calculateVMG function is added. double windAngle1 = 31.5; double destAngle1 = 65.32; double windSpeed1 = 15;//knots - //double vmgAngle1 = TODO; - //double vmgSpeed1 = TODO; + double vmgAngle1 = 88; + double vmgSpeed1 = 12; + + VMG calcVMG1 = polars.calculateVMG(windAngle1, windSpeed1, destAngle1, 0, 360); + double calcVMGAngle1 = calcVMG1.getBearing(); + double calcVMGSpeed1 = calcVMG1.getSpeed(); + + System.out.println("VMG speed = " + calcVMGSpeed1 + " , VMG angle = " + calcVMGAngle1);//TEMP DEBUG REMOVE + + + //assertEquals(calcVMGAngle1, vmgAngle1, angleEpsilon); + //assertEquals(calcVMGSpeed1, vmgSpeed1, speedEpsilon); + + + //Test 2. + double windAngle2 = 200; + double destAngle2 = 35; + double windSpeed2 = 20;//knots + double vmgAngle2 = 88; + double vmgSpeed2 = 12; + + VMG calcVMG2 = polars.calculateVMG(windAngle2, windSpeed2, destAngle2, 0, 360); + double calcVMGAngle2 = calcVMG2.getBearing(); + double calcVMGSpeed2 = calcVMG2.getSpeed(); + + System.out.println("VMG speed = " + calcVMGSpeed2 + " , VMG angle = " + calcVMGAngle2);//TEMP DEBUG REMOVE - //VMG calcVMG1 = Polars.calculateVMG(windAngle1, destAngle1, windSpeed1); - //double calcVMGAngle1 = calcVMG1.getKey(); - //double calcVMGSpeed1 = calcVMG1.getValue(); - //assertEquals(vmgAngle1, calcVMGAngle1, 0.1); - //assertEquals(vmgSpeed1, calcVMGSpeed1, 0.1); + //assertEquals(calcVMGAngle2, vmgAngle2, angleEpsilon); + //assertEquals(calcVMGSpeed2, vmgSpeed2, speedEpsilon); } From 2dc17a688f7c18d3db529064311beb88a96f7bfd Mon Sep 17 00:00:00 2001 From: fjc40 Date: Sun, 14 May 2017 01:12:36 +1200 Subject: [PATCH 2/2] Mock.Polars: Fixed a bug where duplicate estimates could be added to the Polar table (this happened when the angle was 0, so the "negative" angle became 360, which is equivalent). Now has a list of angle values for each wind speed, rather than checking if Pair exists in the map. calculateVMG now uses linear interpolation between two adjacent angles (e.g., if data file contains angles 0, 30, 45, etc.. it can interpolate and find an optimal VMG angle between those, for example, 17 degrees). Added a third test for when we provide a wind speed which is lower than any wind speed values in the Polars table. Still need to actually calculate correct VMG values by hand. #story[873] --- mock/src/main/java/seng302/Model/Polars.java | 160 ++++++++++++------ .../test/java/seng302/Model/PolarsTest.java | 27 ++- 2 files changed, 133 insertions(+), 54 deletions(-) diff --git a/mock/src/main/java/seng302/Model/Polars.java b/mock/src/main/java/seng302/Model/Polars.java index f6844d0e..81242f07 100644 --- a/mock/src/main/java/seng302/Model/Polars.java +++ b/mock/src/main/java/seng302/Model/Polars.java @@ -18,7 +18,11 @@ public class Polars { private HashMap, Double> polarValues = new HashMap<>(); ///Stores a list of angles from the polar table - this is used during the calculateVMG function. - private ArrayList polarAngles = new ArrayList<>(); + ///Maps between windSpeed and a list of angles for that wind speed. + private HashMap> polarAngles = new HashMap<>(); + + + /** * Ctor. @@ -38,33 +42,42 @@ public class Polars { //We also add the same values with a negative angle, as the data file contains data for 0-180 degrees, but we also need 180-360 degrees. This is because it may turn out that going 5 degrees into the wind gives us, say, 9knots, but -5 into the wind may give us 10knots, towards our destination. + //Create the array to store angles for this wind speed if it doesn't exist. + if (!this.polarAngles.containsKey(trueWindSpeed)) { + this.polarAngles.put(trueWindSpeed, new ArrayList<>()); + } + //Add estimate to map. Pair newKeyPositive = new Pair(trueWindSpeed, relativeWindAngle); polarValues.put(newKeyPositive, boatSpeed); - double negativeAngle = -relativeWindAngle; - Pair newKeyNegative = new Pair(trueWindSpeed, negativeAngle); - polarValues.put(newKeyNegative, boatSpeed); + double negativeAngle = 360d - relativeWindAngle; + //This essentially does angle modulo 360, to get something in the interval [0, 360). + while (negativeAngle >= 360d) { + negativeAngle -= 360d; + } + //Ensure that the positive and negative angles aren't the same (e.g., pos = 0, neg = 360 - 0 = 0. + if (negativeAngle != relativeWindAngle) { + Pair newKeyNegative = new Pair(trueWindSpeed, negativeAngle); + polarValues.put(newKeyNegative, boatSpeed); + } //Add angle to angle list. - if (!this.polarAngles.contains(relativeWindAngle)) { - this.polarAngles.add(relativeWindAngle); + if (!this.polarAngles.get(trueWindSpeed).contains(relativeWindAngle)) { + this.polarAngles.get(trueWindSpeed).add(relativeWindAngle); } - if (!this.polarAngles.contains(negativeAngle)) { - this.polarAngles.add(negativeAngle); + if (!this.polarAngles.get(trueWindSpeed).contains(negativeAngle)) { + this.polarAngles.get(trueWindSpeed).add(negativeAngle); } - //System.out.println("adding wind speed: " + trueWindSpeed + ", wind angle: " + relativeWindAngle + ", boat speed: " + boatSpeed);//TEMP DEBUG REMOVE - //System.out.println("adding wind speed: " + trueWindSpeed + ", wind angle: " + negativeAngle + ", boat speed: " + boatSpeed);//TEMP DEBUG REMOVE - - } + /** * 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. If you don't care about bearing bounds, simple pass in lower = 0, upper = 360. * @param trueWindAngle The current true wind angle. @@ -80,7 +93,13 @@ public class Polars { //TODO we need to add interpolation between angles for a given wind speed (e.g., we have 0 deg, 30 deg, but the optimal bearing may be 17.3 degrees). //TODO we should also interpolate between wind speeds (e.g., we have 12kn and 16kn, but if the wind speed is actually 15.999kn, then we should interpolate to get a more accurate final value). - double polarWindSpeed = 0; + //Sorts polar angles. + for (ArrayList angles : this.polarAngles.values()) { + angles.sort(null); + } + + //-1 indicates that we haven't found any smaller wind speeds in our map. + double polarWindSpeed = -1; //Find the lower bound wind speed from the polar table. for (Pair key : this.polarValues.keySet()) { @@ -93,70 +112,109 @@ public class Polars { } } + //If we never found a smaller speed value (e.g., smallest speed in table is 4kn, user provided 2kn), then for now we give a vector with 0 speed towards destination. Later, this should interpolate between adjacent wind speeds. + if (polarWindSpeed == -1) { + return new VMG(0, destinationAngle); + } + + //Find the angle with the best VMG. + double bestVMGAngle = 0; double bestVMGVelocity = 0; - for (double polarAngle : this.polarAngles) { + //The list of polar angles for this wind speed. + ArrayList polarAngles = this.polarAngles.get(polarWindSpeed); - Pair key = new Pair<>(polarWindSpeed, polarAngle); + //For all angles in the accepted interval (in 1 degree increments). + for (double angle = 0; angle < 360; angle += 1) { - //System.out.println("selecting " + polarAngle + " degrees from wind dir, and " + polarWindSpeed + "knots wind speed.");//TEMP DEBUG REMOVE - - //We need to check that the map contains this (speed, angle) pair because some of the datafile entries have different angles in the same column (e.g., (16kn, 45 deg) and (20kn, 43 deg), but there is no (20kn, 45 deg). - if (this.polarValues.containsKey(key)) { + //This is the true bearing of the boat, if it went at the angle against the wind. + //For angle > 90 and angle < 270, it means that the boat is actually going _with_ the wind (gybe). + double trueBoatBearing = trueWindAngle + angle + 180d; + while (trueBoatBearing >= 360) { + trueBoatBearing -= 360; + } - //This is the velocity from the polar table at this wind speed/angle. - double estVelocity = this.polarValues.get(key); + //Check that the boat's bearing would actually be acceptable. + if ((trueBoatBearing <= bearingLowerBound) || (trueBoatBearing > bearingUpperBound)) { + //If the angle is too small or too great, don't use it - skip to the next iteration. + continue; + } - //System.out.println("speed is est. " + estVelocity + "knots.");//TEMP DEBUG REMOVE + //Basic linear interpolation. Find the nearest two angles from the table, and interpolate between them. - //This is the true bearing of the boat, if it went at the angle against the wind. - //For polarAngle > 90, it means that the boat is actually going _with_ the wind (gybe). - double trueBoatBearing = trueWindAngle + polarAngle + 180d; - while (trueBoatBearing >= 360) { - trueBoatBearing -= 360; + //Check which pair of adjacent points the angle is between. + boolean foundInterval = false; + double lowerBound = 0; + double upperBound = 0; + for (int i = 0; i < polarAngles.size() - 1; i++) { + if ((angle >= polarAngles.get(i)) && (angle < polarAngles.get(i + 1))) { + foundInterval = true; + lowerBound = polarAngles.get(i); + upperBound = polarAngles.get(i + 1); + break; } + } + + //Calculate how far between those points the angle is. + if (!foundInterval) { + //If we never found the interval, then it must be the "last" interval, between the i'th and 0'th values. + lowerBound = polarAngles.get(polarAngles.size() - 1); + upperBound = polarAngles.get(0); + } - //System.out.println("true boat bearing is " + trueBoatBearing + " degrees.");//TEMP DEBUG REMOVE + //This is the "distance" between the angle and its lower bound. + //I.e., L----A-----------U + // <----> is lowerDelta. + double lowerDelta = angle - lowerBound; + + //This is the "distance" between the upper and lower bound. + //I.e., L----A-----------U + // <----------------> is intervalDelta. + //This can potentially be negative if we have, e.g., lower = 340deg, upper = 0deg, delta = -340deg. + double intervalDelta = upperBound - lowerBound; + //If it _is_ negative, modulo it to make it positive. + //E.g., -340deg = +20deg. + if (intervalDelta < 0) { + intervalDelta += 360d; + } - //Check that the trueBoatBearing is actually within the accepted interval. - if ((trueBoatBearing <= bearingLowerBound) || (trueBoatBearing >= bearingUpperBound)) { - //If the angle is too small or too great, don't use it - skip to the next iteration. - continue; - } - else { - //If it is acceptable... + //This is how far between the lower and upper bounds the angle is, as a proportion (e.g., 0.5 = half-way, 0.9 = close to upper). + double interpolationScalar = lowerDelta / intervalDelta; - //System.out.println("this is in the acceptable range");//TEMP DEBUG REMOVE + //Get the estimated boat speeds for the lower and upper angles. + Pair lowerKey = new Pair<>(polarWindSpeed, lowerBound); + Pair upperKey = new Pair<>(polarWindSpeed, upperBound); + double lowerSpeed = this.polarValues.get(lowerKey); + double upperSpeed = this.polarValues.get(upperKey); + //Get the delta between upper and lower speeds. + double speedDelta = upperSpeed - lowerSpeed; - //This is the delta angle between the boat's true bearing and the destination. - double angleBetweenDestAndTack = trueBoatBearing - destinationAngle; - //This is the estimated velocity towards the target (e.g., angling away from the target reduces velocity). - double vmgTemp = Math.cos(Math.toRadians(angleBetweenDestAndTack)) * estVelocity; + //Calculate the speed at the interpolated angle. + double interpolatedSpeed = lowerSpeed + (speedDelta * interpolationScalar); - //System.out.println("angle between destination and boat bearing is " + angleBetweenDestAndTack + " degrees.");//TEMP DEBUG REMOVE - //System.out.println("this has an overall velocity of " + vmgTemp + "knots.");//TEMP DEBUG REMOVE - //Check that the velocity is better. - if (vmgTemp > bestVMGVelocity) { - //System.out.println("This is the new best velocity. Previous was " + bestVMGVelocity + "knots at " + bestVMGAngle + " degrees.");//TEMP DEBUG REMOVE - bestVMGVelocity = vmgTemp; - bestVMGAngle = trueBoatBearing; - } - } + //This is the delta angle between the boat's true bearing and the destination. + double angleBetweenDestAndTack = trueBoatBearing - destinationAngle; + //This is the estimated velocity towards the target (e.g., angling away from the target reduces velocity). + double vmgTemp = Math.cos(Math.toRadians(angleBetweenDestAndTack)) * interpolatedSpeed; + + + //Check that the velocity is better. + if (vmgTemp > bestVMGVelocity) { + bestVMGVelocity = vmgTemp; + bestVMGAngle = trueBoatBearing; } } - //System.out.println("VMG speed = " + bestVMGVelocity + " , VMG angle = " + bestVMGAngle);//TEMP DEBUG REMOVE //Create the VMG object and return it. return new VMG(bestVMGVelocity, bestVMGAngle); - } diff --git a/mock/src/test/java/seng302/Model/PolarsTest.java b/mock/src/test/java/seng302/Model/PolarsTest.java index c28e78f1..59680fab 100644 --- a/mock/src/test/java/seng302/Model/PolarsTest.java +++ b/mock/src/test/java/seng302/Model/PolarsTest.java @@ -34,10 +34,11 @@ public class PolarsTest { double speedEpsilon = 2;//Are these epsilons a bit too big? //Test 1. + //This test has a wind speed that is between two values from the table (12kn, 16kn, this is 15.9kn). double windAngle1 = 31.5; double destAngle1 = 65.32; - double windSpeed1 = 15;//knots - double vmgAngle1 = 88; + double windSpeed1 = 15.9;//knots + double vmgAngle1 = 88; //TODO the expected results need to be calculated and placed here. double vmgSpeed1 = 12; VMG calcVMG1 = polars.calculateVMG(windAngle1, windSpeed1, destAngle1, 0, 360); @@ -52,9 +53,10 @@ public class PolarsTest { //Test 2. + //This test has a wind speed much larger than any in the table (max from table is 30kn, this is 40kn). double windAngle2 = 200; double destAngle2 = 35; - double windSpeed2 = 20;//knots + double windSpeed2 = 40;//knots double vmgAngle2 = 88; double vmgSpeed2 = 12; @@ -68,6 +70,25 @@ public class PolarsTest { //assertEquals(calcVMGAngle2, vmgAngle2, angleEpsilon); //assertEquals(calcVMGSpeed2, vmgSpeed2, speedEpsilon); + + //Test 3. + //This test has a wind speed lower than any non-zero values from the table (table has 0kn, 4kn, this is 2kn). + double windAngle3 = 345; + double destAngle3 = 199; + double windSpeed3 = 2;//knots + double vmgAngle3 = 88; + double vmgSpeed3 = 12; + + VMG calcVMG3 = polars.calculateVMG(windAngle3, windSpeed3, destAngle3, 0, 360); + double calcVMGAngle3 = calcVMG3.getBearing(); + double calcVMGSpeed3 = calcVMG3.getSpeed(); + + System.out.println("VMG speed = " + calcVMGSpeed3 + " , VMG angle = " + calcVMGAngle3);//TEMP DEBUG REMOVE + + + //assertEquals(calcVMGAngle3, vmgAngle3, angleEpsilon); + //assertEquals(calcVMGSpeed3, vmgSpeed3, speedEpsilon); + } }