mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-08 20:12:23 +00:00
Status: CodeReview with Axel
This commit is contained in:
1 parent
db16657ba0
commit
896b22fcca
4 files changed
+58
-47
No files matched your search
+13
-13
@@ -36,7 +36,7 @@ public class TestORCPerformanceCurve {
|
||||
private final boolean collectErrors = true;
|
||||
|
||||
private static final String RESOURCES = "resources/orc/";
|
||||
private static ORCPerformanceCurveCourse course;
|
||||
private static ORCPerformanceCurveCourse course1;
|
||||
private static ORCCertificateImporter importer;
|
||||
|
||||
@Rule
|
||||
@@ -61,7 +61,7 @@ public class TestORCPerformanceCurve {
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.03), new DegreeBearingImpl(15)));
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.03), new DegreeBearingImpl(165)));
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.17), new DegreeBearingImpl(180)));
|
||||
course = new ORCPerformanceCurveCourseImpl(legs);
|
||||
course1 = new ORCPerformanceCurveCourseImpl(legs);
|
||||
|
||||
// Local File:
|
||||
File fileGER = new File(RESOURCES + "GER2019.json");
|
||||
@@ -75,10 +75,10 @@ public class TestORCPerformanceCurve {
|
||||
public void testLagrangeInterpolation() throws FunctionEvaluationException {
|
||||
Double accuracy = 0.21;
|
||||
ORCCertificateImpl certificate = (ORCCertificateImpl) importer.getCertificate("GER 5549");
|
||||
ORCPerformanceCurveImpl performanceCurve = (ORCPerformanceCurveImpl) certificate.getPerformanceCurve(course);
|
||||
ORCPerformanceCurveImpl performanceCurve = (ORCPerformanceCurveImpl) certificate.getPerformanceCurve(course1);
|
||||
Double value = performanceCurve.getDurationPerNauticalMileAtTrueWindAngleAndSpeed(new KnotSpeedImpl(6), new DegreeBearingImpl(60)).asSeconds();
|
||||
|
||||
assertNotNull(course);
|
||||
assertNotNull(course1);
|
||||
assertNotNull(performanceCurve);
|
||||
assertEquals(value, performanceCurve.getLagrangeAllowancePerTrueWindSpeedAndAngle(new KnotSpeedImpl( 6),new DegreeBearingImpl( 60)).asSeconds(), 0.000001);
|
||||
|
||||
@@ -98,7 +98,7 @@ public class TestORCPerformanceCurve {
|
||||
assertEquals(345.0, performanceCurve.getLagrangeAllowancePerTrueWindSpeedAndAngle(new KnotSpeedImpl(16),new DegreeBearingImpl(98.3)).asSeconds(), accuracy);
|
||||
assertEquals(321.7, performanceCurve.getLagrangeAllowancePerTrueWindSpeedAndAngle(new KnotSpeedImpl(20),new DegreeBearingImpl(98.3)).asSeconds(), accuracy);
|
||||
|
||||
// TESTS of the corner areas of the polars
|
||||
// TESTS of the corner areas of the polar
|
||||
assertEquals(588.1, performanceCurve.getLagrangeAllowancePerTrueWindSpeedAndAngle(new KnotSpeedImpl( 6),new DegreeBearingImpl(138.7)).asSeconds(), accuracy);
|
||||
assertEquals(468.4, performanceCurve.getLagrangeAllowancePerTrueWindSpeedAndAngle(new KnotSpeedImpl( 8),new DegreeBearingImpl(138.7)).asSeconds(), accuracy);
|
||||
assertEquals(413.8, performanceCurve.getLagrangeAllowancePerTrueWindSpeedAndAngle(new KnotSpeedImpl(10),new DegreeBearingImpl(138.7)).asSeconds(), accuracy);
|
||||
@@ -137,7 +137,7 @@ public class TestORCPerformanceCurve {
|
||||
public void testPerformanceCurveInvertation() throws MaxIterationsExceededException, FunctionEvaluationException {
|
||||
Double accuracy = 0.1;
|
||||
ORCCertificateImpl certificate = (ORCCertificateImpl) importer.getCertificate("GER 5549");
|
||||
ORCPerformanceCurveImpl performanceCurve = (ORCPerformanceCurveImpl) certificate.getPerformanceCurve(course);
|
||||
ORCPerformanceCurveImpl performanceCurve = (ORCPerformanceCurveImpl) certificate.getPerformanceCurve(course1);
|
||||
|
||||
assertEquals( 11.5, performanceCurve.getImpliedWind(performanceCurve.getAllowancePerCourse(new KnotSpeedImpl( 11.5))).getKnots(), accuracy);
|
||||
assertEquals(17.23, performanceCurve.getImpliedWind(performanceCurve.getAllowancePerCourse(new KnotSpeedImpl(17.23))).getKnots(), accuracy);
|
||||
@@ -154,19 +154,19 @@ public class TestORCPerformanceCurve {
|
||||
@Test
|
||||
public void testImpliedWindSimple() throws MaxIterationsExceededException, FunctionEvaluationException {
|
||||
double accuracy = 0.000001;
|
||||
double courseLengthInNauticalMiles = course.getTotalLength().getNauticalMiles();
|
||||
double courseLengthInNauticalMiles = course1.getTotalLength().getNauticalMiles();
|
||||
ORCCertificate certificateMoana = importer.getCertificate("GER 5549");
|
||||
ORCCertificate certificateMilan = importer.getCertificate("GER 7323");
|
||||
ORCCertificate certificateTutima = importer.getCertificate("GER 5609");
|
||||
ORCCertificate certificateBank = importer.getCertificate("GER 5555");
|
||||
ORCCertificate certificateHaspa = importer.getCertificate("GER 6300");
|
||||
ORCCertificate certificateHalbtrocken = importer.getCertificate("GER 5564");
|
||||
ORCPerformanceCurve performanceCurveMoana = certificateMoana.getPerformanceCurve(course);
|
||||
ORCPerformanceCurve performanceCurveMilan = certificateMilan.getPerformanceCurve(course);
|
||||
ORCPerformanceCurve performanceCurveTutima = certificateTutima.getPerformanceCurve(course);
|
||||
ORCPerformanceCurve performanceCurveBank = certificateBank.getPerformanceCurve(course);
|
||||
ORCPerformanceCurve performanceCurveHaspa = certificateHaspa.getPerformanceCurve(course);
|
||||
ORCPerformanceCurve performanceCurveHalbtrocken = certificateHalbtrocken.getPerformanceCurve(course);
|
||||
ORCPerformanceCurve performanceCurveMoana = certificateMoana.getPerformanceCurve(course1);
|
||||
ORCPerformanceCurve performanceCurveMilan = certificateMilan.getPerformanceCurve(course1);
|
||||
ORCPerformanceCurve performanceCurveTutima = certificateTutima.getPerformanceCurve(course1);
|
||||
ORCPerformanceCurve performanceCurveBank = certificateBank.getPerformanceCurve(course1);
|
||||
ORCPerformanceCurve performanceCurveHaspa = certificateHaspa.getPerformanceCurve(course1);
|
||||
ORCPerformanceCurve performanceCurveHalbtrocken = certificateHalbtrocken.getPerformanceCurve(course1);
|
||||
|
||||
assertNotNull(performanceCurveMoana);
|
||||
assertNotNull(performanceCurveMilan);
|
||||
|
||||
+20
-6
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.orc;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
|
||||
/**
|
||||
* Extracts ORC-Certificates from different sources and different formats. Returns ORC-Certificate objects for given
|
||||
@@ -13,15 +14,28 @@ import java.util.Map;
|
||||
public interface ORCCertificateImporter {
|
||||
|
||||
/**
|
||||
* Returns an ORCCertificate object to a given sail number. If there is no certificate for the given id, the method
|
||||
* returns {@link null}.
|
||||
**/
|
||||
//TODO Better input specification on identification of certificate.
|
||||
* Creates an {@link ORCCertificate} object to a given sail number.
|
||||
*
|
||||
* @param sailnumber
|
||||
* as specified for the boat of the {@link Competitor) in the ORC files. The sailnumber commonly consists
|
||||
* out of an alphabetical national code (e.g. 'GER', 'GBR', 'SUI', ...) or an alphanumerical class code (e.g. 'F40',
|
||||
* 'X41', ...) and a numerical identification code.
|
||||
* @return {@code null}, if there isn't any data for the given sailnumber. Otherwise an {@link ORCCertificate}.
|
||||
*/
|
||||
ORCCertificate getCertificate(String sailnumber);
|
||||
|
||||
/**
|
||||
* Returns a map of ORCCertificate objects to a given array of sail numbers.
|
||||
**/
|
||||
* Creates an {@link Map} of {@link ORCCertificate} objects to the given sail numbers.
|
||||
* <p>
|
||||
* Same functionality as {@code getCertificate} for a single sailnumber, just for multiple elements.
|
||||
*
|
||||
* @param sailnumbers
|
||||
* represents an array of sailnumbers as specified for the boat of the {@link Competitor) in the ORC
|
||||
* files. The sailnumber commonly consists out of an alphabetical national code (e.g. 'GER', 'GBR', 'SUI', ...) or
|
||||
* an alphanumerical class code (e.g. 'F40', 'X41', ...) and a numerical identification code.
|
||||
* @return {@link Map} of {@link ORCCertificate} values and the sailnumber parameters as keys. The value equals
|
||||
* {@code null}, if there isn't any data for the given sailnumber.
|
||||
*/
|
||||
Map<String, ORCCertificate> getCertificates(String[] sailnumbers);
|
||||
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Speed;
|
||||
|
||||
// TODO Finish Comments for API
|
||||
|
||||
/**
|
||||
* For a {@link Competitor} and the {@link ORCPerformanceCurveCourse} which the competitor sailed until the creation of
|
||||
* an instance of an implementing class, this instance represents a so called "Perfromance Curve". This Curve is
|
||||
@@ -18,13 +16,13 @@ import com.sap.sse.common.Speed;
|
||||
* course. For a given windspeed the performance curve returns the allowance for the boat or in simpler words: how long
|
||||
* should the boat need for a nautical mile when sailing 100% performance.
|
||||
*
|
||||
* @author Daniel Lisunkin (i505543)
|
||||
* @author Daniel Lisunkin (i505543)˝
|
||||
*
|
||||
*/
|
||||
public interface ORCPerformanceCurve {
|
||||
|
||||
/**
|
||||
*
|
||||
* TODO Comment
|
||||
*
|
||||
* @param timePerNauticalMile equals the average duration the boat needed to conquer one mile on the sailed subcourse, => totalTime / course.getTotalLength()
|
||||
* @return
|
||||
@@ -33,7 +31,7 @@ public interface ORCPerformanceCurve {
|
||||
* @throws MaxIterationsExceededException
|
||||
* @throws FunctionEvaluationException
|
||||
*/
|
||||
Speed getImpliedWind(Duration timePerNauticalMile) throws ArgumentOutsideDomainException, MaxIterationsExceededException, FunctionEvaluationException;
|
||||
Speed getImpliedWind(Duration timePerNauticalMile) throws MaxIterationsExceededException, FunctionEvaluationException;
|
||||
|
||||
/**
|
||||
* TODO getComment done
|
||||
@@ -46,6 +44,7 @@ public interface ORCPerformanceCurve {
|
||||
Duration getCalculatedTime(ORCPerformanceCurve referenceBoat, Duration sailedDurationPerNauticalMile);
|
||||
|
||||
/**
|
||||
* TODO Comment
|
||||
*
|
||||
* @param impliedWind
|
||||
* @return
|
||||
|
||||
+21
-23
@@ -1,9 +1,7 @@
|
||||
package com.sap.sailing.domain.orc.impl;
|
||||
|
||||
import java.awt.List;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -134,24 +132,23 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
}
|
||||
|
||||
private Map<Speed, Duration> createAllowancePerLeg(ORCPerformanceCurveLeg leg) throws FunctionEvaluationException {
|
||||
Map<Speed, Duration> result = new HashMap<>();
|
||||
Double twa = leg.getTwa().getDegrees();
|
||||
|
||||
|
||||
for (Speed entry : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
final Map<Speed, Duration> result = new HashMap<>();
|
||||
final double twaDeg = leg.getTwa().getDegrees();
|
||||
final double twaRad = leg.getTwa().getRadians();
|
||||
for (final Speed entry : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
// Case switching on TWA (0. TWA == 0; 1. TWA < Beat; 2. Beat < TWA < Gybe; 3. Gybe < TWA; 4. TWA == 180)
|
||||
if (twa < beatAngles.get(entry).getDegrees()) {
|
||||
// Case 0 & 1 - result = beatVMG * distance / cos(TWA)
|
||||
result.put(entry, Duration.ONE_SECOND.times(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(entry, beatAngles.get(entry)).asSeconds() * leg.getLength().getNauticalMiles() * Math.abs(Math.cos(Math.toRadians(twa)))));
|
||||
} else if (twa > gybeAngles.get(entry).getDegrees()) {
|
||||
// Case 3 & 4 - result = runVMG * distance / cos(TWA)
|
||||
result.put(entry, Duration.ONE_SECOND.times(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(entry, gybeAngles.get(entry)).asSeconds() * leg.getLength().getNauticalMiles() * Math.abs(Math.cos(Math.toRadians(twa)))));
|
||||
// TODO (so ? beatAngles : gybeAngles)
|
||||
if (twaDeg <= beatAngles.get(entry).getDegrees()) {
|
||||
// Case 0 & 1 - result = beatVMG * distance * cos(TWA)
|
||||
result.put(entry, Duration.ONE_SECOND.times(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(entry, beatAngles.get(entry)).asSeconds() * leg.getLength().getNauticalMiles()));
|
||||
} else if (twaDeg >= gybeAngles.get(entry).getDegrees()) {
|
||||
// Case 3 & 4 - result = runVMG * distance * cos(TWA)
|
||||
result.put(entry, Duration.ONE_SECOND.times(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(entry, gybeAngles.get(entry)).asSeconds() * leg.getLength().getNauticalMiles()));
|
||||
} else {
|
||||
// Case 2 - result is given through the laGrange Interpolation, between the Beat and Gybe Angles
|
||||
result.put(entry, getLagrangeAllowancePerTrueWindSpeedAndAngle(entry, leg.getTwa()).times(leg.getLength().getNauticalMiles()));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -243,26 +240,27 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
private double[][] createPolarsPerTrueWindSpeed(Speed trueWindSpeed) {
|
||||
ArrayList<Double> resultWindAngles = new ArrayList<>();
|
||||
ArrayList<Double> resultAllowances = new ArrayList<>();
|
||||
|
||||
Bearing beatAngle = beatAngles.get(trueWindSpeed);
|
||||
Bearing gybeAngle = gybeAngles.get(trueWindSpeed);
|
||||
final Bearing TWO_DEGREES = new DegreeBearingImpl(2);
|
||||
final Bearing MINUS_TWO_DEGREES = new DegreeBearingImpl(-2);
|
||||
|
||||
resultWindAngles.add(beatAngle.add(new DegreeBearingImpl(-2)).getDegrees());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, beatAngle).divide(Math.cos(Math.toRadians(beatAngle.add(new DegreeBearingImpl(-2)).getDegrees()))).asSeconds());
|
||||
resultWindAngles.add(beatAngle.add(MINUS_TWO_DEGREES).getDegrees());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, beatAngle).divide(Math.cos(beatAngle.add(MINUS_TWO_DEGREES).getRadians())).asSeconds());
|
||||
resultWindAngles.add(beatAngle.getDegrees());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, beatAngle).asSeconds());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, beatAngle).divide(Math.cos(beatAngle.getRadians())).asSeconds());
|
||||
|
||||
for(Bearing twa : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES) {
|
||||
if(twa.compareTo(beatAngle) > 0 && twa.compareTo(gybeAngle) < 0) {
|
||||
for (Bearing twa : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES) {
|
||||
if (twa.compareTo(beatAngle) > 0 && twa.compareTo(gybeAngle) < 0) {
|
||||
resultWindAngles.add(twa.getDegrees());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, twa).asSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
resultWindAngles.add(gybeAngle.getDegrees());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, gybeAngle).asSeconds());
|
||||
resultWindAngles.add(gybeAngle.add(new DegreeBearingImpl(2)).getDegrees());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, gybeAngle).divide(Math.abs(Math.cos(Math.PI - Math.toRadians(gybeAngle.add(new DegreeBearingImpl(2)).getDegrees())))).asSeconds());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, gybeAngle).divide(Math.cos(Math.PI - gybeAngle.getRadians())).asSeconds());
|
||||
resultWindAngles.add(gybeAngle.add(TWO_DEGREES).getDegrees());
|
||||
resultAllowances.add(getDurationPerNauticalMileAtTrueWindAngleAndSpeed(trueWindSpeed, gybeAngle).divide(Math.cos(Math.PI - Math.toRadians(gybeAngle.add(TWO_DEGREES).getDegrees()))).asSeconds());
|
||||
|
||||
return new double[][] {resultWindAngles.stream().mapToDouble(d -> d).toArray(), resultAllowances.stream().mapToDouble(d -> d).toArray()};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user