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
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.
@@ -250,10 +250,18 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
runVMGPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, RUN, tws));
runAllowancePerTrueWindSpeed.put(tws, predefinedAllowanceDurationsPerTrueWindSpeed.get(RUN).get(tws));
windwardLeewardSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, WINDWARD_LEEWARD, tws));
longDistanceSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, LONG_DISTANCE, tws));
circularRandomSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, CIRCULAR_RANDOM, tws));
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, NON_SPINNAKER, tws));
final Speed longDistanceSpeedPrediction = getSpeedPredictionFromTimeAllowance(predefinedAllowanceDurationsPerTrueWindSpeed, LONG_DISTANCE, tws);
if (longDistanceSpeedPrediction != null) {
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 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) {
speedPrediction = ORCCertificate.NAUTICAL_MILE.inTime(timeAllowance);
} else {
speedPrediction = new KnotSpeedImpl(Double.POSITIVE_INFINITY);
speedPrediction = null;
}
return speedPrediction;
}
@@ -163,12 +163,22 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect
runVMGPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(runAllowancePerTrueWindSpeed.get(tws)));
windwardLeewardSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(windwardLeewardKey)))));
longDistanceSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(longDistanceKey)))));
circularRandomSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(circularRandomKey)))));
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(nonSpinnakerKey)))));
// long-distance and non-spinnaker speed predictions are optional; newer certificates may not have them
final String longDistanceSecondsToTheMile = certificateValues.getValue(longDistanceKey);
if (longDistanceSecondsToTheMile != null) {
longDistanceSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificate.NAUTICAL_MILE.inTime(
new SecondsDurationImpl(Double.parseDouble(longDistanceSecondsToTheMile))));
}
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<>();
for (Bearing twa : ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES ) {
String twaCoursesKey = TWA_COURSES + Integer.toString((int) twa.getDegrees()) + windSpeed;
@@ -130,7 +130,7 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
} else {
final List<T> resultList = new ArrayList<>();
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);
result = tArray;
@@ -94,9 +94,15 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
beatVMGPredictions.put(keyTWS, certificate.getBeatVMGPredictions().get(tws).getKnots());
runVMGPredictions.put(keyTWS, certificate.getRunVMGPredictions().get(tws).getKnots());
windwardLeewardPredictions.put(keyTWS, certificate.getWindwardLeewardSpeedPrediction().get(tws).getKnots());
circularRandomPredictions.put(keyTWS, certificate.getCircularRandomSpeedPredictions().get(tws).getKnots());
longDistancePredictions.put(keyTWS, certificate.getLongDistanceSpeedPredictions().get(tws).getKnots());
nonSpinnakerPredictions.put(keyTWS, certificate.getNonSpinnakerSpeedPredictions().get(tws).getKnots());
if (certificate.getCircularRandomSpeedPredictions().containsKey(tws)) {
circularRandomPredictions.put(keyTWS, certificate.getCircularRandomSpeedPredictions().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()) {
String keyTWA = bearingToDegreeString(twa);
velocityPredictionsPerTrueWindAngle.put(keyTWA,