bug6147: ignore long-distance, non-spinnaker, or circular-random values if not present; no GPH defaults to 0.0 now

This commit is contained in:
Axel Uhl
2025-07-01 11:33:37 +02:00
parent 7c8366c94c
commit 10c73b9533
5 changed files with 40 additions and 16 deletions
@@ -209,7 +209,7 @@ public class ORCCertificateImpl implements ORCCertificate {
@Override @Override
public double getGPHInSecondsToTheMile() { public double getGPHInSecondsToTheMile() {
return gph==null ? -1 : gph.asSeconds(); return gph==null ? 0 : gph.asSeconds();
} }
// Please do not try to calculate these combined allowances and instead use the provided values from the certificate. // Please do not try to calculate these combined allowances and instead use the provided values from the certificate.
@@ -250,10 +250,18 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
runVMGPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, RUN, tws)); runVMGPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, RUN, tws));
runAllowancePerTrueWindSpeed.put(tws, predefinedAllowanceDurationsPerTrueWindSpeed.get(RUN).get(tws)); runAllowancePerTrueWindSpeed.put(tws, predefinedAllowanceDurationsPerTrueWindSpeed.get(RUN).get(tws));
windwardLeewardSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, WINDWARD_LEEWARD, tws)); windwardLeewardSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, WINDWARD_LEEWARD, tws));
longDistanceSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, LONG_DISTANCE, tws)); final Speed longDistanceSpeedPrediction = getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, LONG_DISTANCE, tws);
circularRandomSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, CIRCULAR_RANDOM, tws)); if (longDistanceSpeedPrediction != null) {
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, NON_SPINNAKER, tws)); longDistanceSpeedPredictionPerTrueWindSpeed.put(tws, longDistanceSpeedPrediction);
}
final Speed circularRandomSpeedPrediction = getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, CIRCULAR_RANDOM, tws);
if (circularRandomSpeedPrediction != null) {
circularRandomSpeedPredictionPerTrueWindSpeed.put(tws, circularRandomSpeedPrediction);
}
final Speed nonSpinnakerSpeedPrediction = getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, NON_SPINNAKER, tws);
if (nonSpinnakerSpeedPrediction != null) {
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, nonSpinnakerSpeedPrediction);
}
} }
final Bearing[] dynamicAllowancesTrueWindAngles = trueWindAngleMap.values().toArray(new Bearing[trueWindAngleMap.values().size()]); final Bearing[] dynamicAllowancesTrueWindAngles = trueWindAngleMap.values().toArray(new Bearing[trueWindAngleMap.values().size()]);
final Speed[] dynamicAllowancesTrueWindSpeeds = trueWindSpeedMap.values().toArray(new Speed[trueWindSpeedMap.values().size()]); final Speed[] dynamicAllowancesTrueWindSpeeds = trueWindSpeedMap.values().toArray(new Speed[trueWindSpeedMap.values().size()]);
@@ -285,7 +293,7 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
if (timeAllowances != null && (timeAllowance = timeAllowances.get(tws)) != null) { if (timeAllowances != null && (timeAllowance = timeAllowances.get(tws)) != null) {
speedPrediction = ORCCertificate.NAUTICAL_MILE.inTime(timeAllowance); speedPrediction = ORCCertificate.NAUTICAL_MILE.inTime(timeAllowance);
} else { } else {
speedPrediction = new KnotSpeedImpl(Double.POSITIVE_INFINITY); speedPrediction = null;
} }
return speedPrediction; return speedPrediction;
} }
@@ -163,12 +163,22 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect
runVMGPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(runAllowancePerTrueWindSpeed.get(tws))); runVMGPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(runAllowancePerTrueWindSpeed.get(tws)));
windwardLeewardSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime( windwardLeewardSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(windwardLeewardKey))))); new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(windwardLeewardKey)))));
longDistanceSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime( // long-distance and non-spinnaker speed predictions are optional; newer certificates may not have them
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(longDistanceKey))))); final String longDistanceSecondsToTheMile = certificateValues.getValue(longDistanceKey);
circularRandomSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime( if (longDistanceSecondsToTheMile != null) {
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(circularRandomKey))))); longDistanceSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime( new SecondsDurationImpl(Double.parseDouble(longDistanceSecondsToTheMile))));
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(nonSpinnakerKey))))); }
final String circularRandomSecondsToTheMile = certificateValues.getValue(circularRandomKey);
if (circularRandomSecondsToTheMile != null) {
circularRandomSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
new SecondsDurationImpl(Double.parseDouble(circularRandomSecondsToTheMile))));
}
final String nonSpinnakerSecondsToTheMile = certificateValues.getValue(nonSpinnakerKey);
if (nonSpinnakerSecondsToTheMile != null) {
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
new SecondsDurationImpl(Double.parseDouble(nonSpinnakerSecondsToTheMile))));
}
Map<Bearing, Speed> velocityPredictionPerTrueWindAngle = new HashMap<>(); Map<Bearing, Speed> velocityPredictionPerTrueWindAngle = new HashMap<>();
for (Bearing twa : ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES ) { for (Bearing twa : ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES ) {
String twaCoursesKey = TWA_COURSES + Integer.toString((int) twa.getDegrees()) + windSpeed; String twaCoursesKey = TWA_COURSES + Integer.toString((int) twa.getDegrees()) + windSpeed;
@@ -130,7 +130,7 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
} else { } else {
final List<T> resultList = new ArrayList<>(); final List<T> resultList = new ArrayList<>();
for (final Object number : windAnglesJsonArray) { for (final Object number : windAnglesJsonArray) {
resultList.add(constructor.apply((Double) number)); resultList.add(constructor.apply(number==null ? null : ((Number) number).doubleValue()));
} }
final T[] tArray = resultList.toArray(array); final T[] tArray = resultList.toArray(array);
result = tArray; result = tArray;
@@ -94,9 +94,15 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
beatVMGPredictions.put(keyTWS, certificate.getBeatVMGPredictions().get(tws).getKnots()); beatVMGPredictions.put(keyTWS, certificate.getBeatVMGPredictions().get(tws).getKnots());
runVMGPredictions.put(keyTWS, certificate.getRunVMGPredictions().get(tws).getKnots()); runVMGPredictions.put(keyTWS, certificate.getRunVMGPredictions().get(tws).getKnots());
windwardLeewardPredictions.put(keyTWS, certificate.getWindwardLeewardSpeedPrediction().get(tws).getKnots()); windwardLeewardPredictions.put(keyTWS, certificate.getWindwardLeewardSpeedPrediction().get(tws).getKnots());
circularRandomPredictions.put(keyTWS, certificate.getCircularRandomSpeedPredictions().get(tws).getKnots()); if (certificate.getCircularRandomSpeedPredictions().containsKey(tws)) {
longDistancePredictions.put(keyTWS, certificate.getLongDistanceSpeedPredictions().get(tws).getKnots()); circularRandomPredictions.put(keyTWS, certificate.getCircularRandomSpeedPredictions().get(tws).getKnots());
nonSpinnakerPredictions.put(keyTWS, certificate.getNonSpinnakerSpeedPredictions().get(tws).getKnots()); }
if (certificate.getLongDistanceSpeedPredictions().containsKey(tws)) {
longDistancePredictions.put(keyTWS, certificate.getLongDistanceSpeedPredictions().get(tws).getKnots());
}
if (certificate.getNonSpinnakerSpeedPredictions().containsKey(tws)) {
nonSpinnakerPredictions.put(keyTWS, certificate.getNonSpinnakerSpeedPredictions().get(tws).getKnots());
}
for (Bearing twa : certificate.getTrueWindAngles()) { for (Bearing twa : certificate.getTrueWindAngles()) {
String keyTWA = bearingToDegreeString(twa); String keyTWA = bearingToDegreeString(twa);
velocityPredictionsPerTrueWindAngle.put(keyTWA, velocityPredictionsPerTrueWindAngle.put(keyTWA,