mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-18 11:49:09 +00:00
Merge branch 'master' into bug5195
This commit is contained in:
+55
-6
@@ -3,33 +3,67 @@ package com.sap.sailing.domain.common.orc;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sse.common.Bearing;
|
||||
import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Speed;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.WithID;
|
||||
import com.sap.sse.common.impl.DegreeBearingImpl;
|
||||
|
||||
/**
|
||||
* Represents semantically a real ORC certificate for a {@link Competitor}, which is used to rate different type of
|
||||
* boats for different insohre and offshore race conditions.
|
||||
* boats for different inshore and offshore race conditions.
|
||||
* <p>
|
||||
* An ORC certificate is issued by the "Member National Authorities" of World Sailing and are available for insight at
|
||||
* https://www.orc.org/index.asp . Other information about the whole scoring system and different variants are available
|
||||
* too.
|
||||
* <p>
|
||||
* One implementing class provides all necessary functionalities to score the Competitors with a choosen
|
||||
* {@link RankingMetric}.<p>
|
||||
* {@link RankingMetric}.
|
||||
* <p>
|
||||
*
|
||||
* The {@link WithID} interface is to be implemented such that a {@link String} is produced as the ID that
|
||||
* contains the concatenation (without intermediate white space) of the {@code NatAuth}, the {@code CertNo}
|
||||
* and the {@code BIN} fields, as provided as single fields in the JSON representation, and as provided
|
||||
* in the concatenated form in the {@code NATCERTN.FILE_ID} column in the RMS format.
|
||||
* The {@link WithID} interface is to be implemented such that a {@link String} is produced as the ID that contains the
|
||||
* concatenation (without intermediate white space) of the {@code NatAuth}, the {@code CertNo} and the {@code BIN}
|
||||
* fields, as provided as single fields in the JSON representation, and as provided in the concatenated form in the
|
||||
* {@code NATCERTN.FILE_ID} column in the RMS format.
|
||||
* <p>
|
||||
*
|
||||
* The certificate contains time allowances (or, conversely, speed predictions) for a combination of true wind speeds
|
||||
* (TWS) and true wind angles (TWA). There are defaults for the values used for the true wind speeds and the true wind
|
||||
* angles, forming a regular, fully populated matrix of allowances / speed predictions. These defaults can be found in
|
||||
* {@link #ALLOWANCES_TRUE_WIND_SPEEDS} and {@link #ALLOWANCES_TRUE_WIND_SPEEDS}.
|
||||
* <p>
|
||||
*
|
||||
* Certificates may also specify non-default values for the slots or "bins" of the matrix that describes the allowances
|
||||
* / speed predictions. As for the default values, the allowances matrix has to be fully populated. The values in the
|
||||
* TWS and TWA arrays are expected to be increasing monotonously.
|
||||
*
|
||||
* @author Daniel Lisunkin (i505543)
|
||||
*
|
||||
*/
|
||||
public interface ORCCertificate extends WithID, Serializable {
|
||||
/**
|
||||
* Equals the column heading of the allowances table of an ORC certificate. The speeds are set by the offshore
|
||||
* racing congress. The speeds occur in the array in ascending order.
|
||||
*
|
||||
* There are references in the persistance module. If the values change, there will be an adjustment needed
|
||||
* in {@link MongoObjectFactoryImpl.speedToKnotsString}.
|
||||
*/
|
||||
Speed[] ALLOWANCES_TRUE_WIND_SPEEDS = { new KnotSpeedImpl(6), new KnotSpeedImpl(8),
|
||||
new KnotSpeedImpl(10), new KnotSpeedImpl(12), new KnotSpeedImpl(14), new KnotSpeedImpl(16),
|
||||
new KnotSpeedImpl(20) };
|
||||
/**
|
||||
* Equals the line heading of the allowances table of an ORC certificate. The true wind angles are set by the
|
||||
* offshore racing congress. The angles occur in the array in ascending order.
|
||||
*
|
||||
* There are references in the persistance module. If the values change, there will be an adjustment needed
|
||||
* in {@link MongoObjectFactoryImpl.bearingToDegreeString}.
|
||||
*/
|
||||
Bearing[] ALLOWANCES_TRUE_WIND_ANGLES = { new DegreeBearingImpl(52), new DegreeBearingImpl(60),
|
||||
new DegreeBearingImpl(75), new DegreeBearingImpl(90), new DegreeBearingImpl(110),
|
||||
new DegreeBearingImpl(120), new DegreeBearingImpl(135), new DegreeBearingImpl(150) };
|
||||
/**
|
||||
* As the ID of an ORC certificate we use the concatenation (without intermediate white space) of the
|
||||
* {@code NatAuth}, the {@code CertNo} and the {@code BIN} fields, as provided as single fields in the JSON
|
||||
@@ -128,4 +162,19 @@ public interface ORCCertificate extends WithID, Serializable {
|
||||
Map<Speed, Map<Bearing, Speed>> getVelocityPredictionPerTrueWindSpeedAndAngle();
|
||||
|
||||
String getBoatName();
|
||||
|
||||
/**
|
||||
* @return the true wind speeds used for the matrix returned by
|
||||
* {@link #getVelocityPredictionPerTrueWindSpeedAndAngle()}. The {@link Speed} values returned by this
|
||||
* method form the key set of the map returned by {@link #getVelocityPredictionPerTrueWindSpeedAndAngle()}.
|
||||
*/
|
||||
Speed[] getTrueWindSpeeds();
|
||||
|
||||
/**
|
||||
* @return the true wind angles used for the matrix returned by
|
||||
* {@link #getVelocityPredictionPerTrueWindSpeedAndAngle()}. The {@link Bearing} values returned by this
|
||||
* method form the key set of all the maps returned as values in the map returned by
|
||||
* {@link #getVelocityPredictionPerTrueWindSpeedAndAngle()}.
|
||||
*/
|
||||
Bearing[] getTrueWindAngles();
|
||||
}
|
||||
+69
-34
@@ -3,7 +3,6 @@ package com.sap.sailing.domain.common.orc.impl;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sse.common.Bearing;
|
||||
@@ -12,7 +11,6 @@ import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Speed;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.DegreeBearingImpl;
|
||||
|
||||
/**
|
||||
* Holds an ORC boat certificate including various of the metrics found in it. Note that multiple different certificates
|
||||
@@ -28,28 +26,6 @@ public class ORCCertificateImpl implements ORCCertificate {
|
||||
|
||||
private final String idConsistingOfNatAuthCertNoAndBIN;
|
||||
|
||||
/**
|
||||
* Equals the column heading of the allowances table of an ORC certificate. The speeds are set by the offshore
|
||||
* racing congress. The speeds occur in the array in ascending order.
|
||||
*
|
||||
* There are references in the persistance module. If the values change, there will be an adjustment needed
|
||||
* in {@link MongoObjectFactoryImpl.speedToKnotsString}.
|
||||
*/
|
||||
public static final Speed[] ALLOWANCES_TRUE_WIND_SPEEDS = { new KnotSpeedImpl(6), new KnotSpeedImpl(8),
|
||||
new KnotSpeedImpl(10), new KnotSpeedImpl(12), new KnotSpeedImpl(14), new KnotSpeedImpl(16),
|
||||
new KnotSpeedImpl(20) };
|
||||
|
||||
/**
|
||||
* Equals the line heading of the allowances table of an ORC certificate. The true wind angles are set by the
|
||||
* offshore racing congress. The angles occur in the array in ascending order.
|
||||
*
|
||||
* There are references in the persistance module. If the values change, there will be an adjustment needed
|
||||
* in {@link MongoObjectFactoryImpl.bearingToDegreeString}.
|
||||
*/
|
||||
public static final Bearing[] ALLOWANCES_TRUE_WIND_ANGLES = { new DegreeBearingImpl(52), new DegreeBearingImpl(60),
|
||||
new DegreeBearingImpl(75), new DegreeBearingImpl(90), new DegreeBearingImpl(110),
|
||||
new DegreeBearingImpl(120), new DegreeBearingImpl(135), new DegreeBearingImpl(150) };
|
||||
|
||||
public final static Distance NAUTICAL_MILE = new NauticalMileDistance(1);
|
||||
|
||||
private final String sailNumber;
|
||||
@@ -60,7 +36,16 @@ public class ORCCertificateImpl implements ORCCertificate {
|
||||
private final Double cdl;
|
||||
private final TimePoint issueDate;
|
||||
|
||||
// TODO add meaningful Javadoc
|
||||
/**
|
||||
* The "core" of the certificate for performance curve scoring; the values in the map tell how fast the boat
|
||||
* described by this certificate is expected to sail for the true wind speed (TWS) provided by the key, and the true
|
||||
* wind angle (TWA) provided by the value map's key. This is the reciprocal of the duration it takes the boat to
|
||||
* sail a certain distance.
|
||||
* <p>
|
||||
*
|
||||
* The keys are the speeds as provided by {@link #allowancesTrueWindSpeeds}; the keys of the value maps are the
|
||||
* angles as provided by {@link #allowancesTrueWindAngles}.
|
||||
*/
|
||||
private final Map<Speed, Map<Bearing, Speed>> velocityPredictionPerTrueWindSpeedAndAngle;
|
||||
|
||||
/**
|
||||
@@ -110,20 +95,34 @@ public class ORCCertificateImpl implements ORCCertificate {
|
||||
private final Map<Speed, Speed> circularRandomSpeedPredictionPerTrueWindSpeed;
|
||||
|
||||
private final Map<Speed, Speed> nonSpinnakerSpeedPredictionPerTrueWindSpeed;
|
||||
|
||||
public ORCCertificateImpl(String idConsistingOfNatAuthCertNoAndBIN,
|
||||
String sailnumber, String boatName, String boatClassName,
|
||||
Distance length, Duration gph,
|
||||
Double cdl, TimePoint issueDate,
|
||||
Map<Speed, Map<Bearing, Speed>> velocityPredictionsPerTrueWindSpeedAndAngle,
|
||||
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
||||
Map<Speed, Duration> beatAllowancePerTrueWindSpeed, Map<Speed, Bearing> runAngles,
|
||||
Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed,
|
||||
private final Speed[] allowancesTrueWindSpeeds;
|
||||
private final Bearing[] allowancesTrueWindAngles;
|
||||
|
||||
/**
|
||||
* Can be used to specify non-default TWS/TWA values for the time allowances / speed predictions.
|
||||
*
|
||||
* @param allowancesTrueWindSpeeds
|
||||
* a monotonously-increasing sequence of true wind speed (TWS) values for the matrix of time allowances /
|
||||
* velocity predictions for this certificate. See also
|
||||
* {@link ORCCertificate#ALLOWANCES_TRUE_WIND_SPEEDS}.
|
||||
* @param allowancesTrueWindAngles
|
||||
* a monotonously-increasing sequence of true wind angle (TWA) values for the matrix of time allowances /
|
||||
* velocity predictions for this certificate. See also
|
||||
* {@link ORCCertificate#ALLOWANCES_TRUE_WIND_ANGLES}.
|
||||
*/
|
||||
public ORCCertificateImpl(Speed[] allowancesTrueWindSpeeds, Bearing[] allowancesTrueWindAngles,
|
||||
String idConsistingOfNatAuthCertNoAndBIN, String sailnumber, String boatName, String boatClassName,
|
||||
Distance length, Duration gph, Double cdl, TimePoint issueDate,
|
||||
Map<Speed, Map<Bearing, Speed>> velocityPredictionsPerTrueWindSpeedAndAngle, Map<Speed, Bearing> beatAngles,
|
||||
Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed, Map<Speed, Duration> beatAllowancePerTrueWindSpeed,
|
||||
Map<Speed, Bearing> runAngles, Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed,
|
||||
Map<Speed, Duration> runAllowancePerTrueWindSpeed,
|
||||
Map<Speed, Speed> windwardLeewardSpeedPredictionsPerTrueWindSpeed,
|
||||
Map<Speed, Speed> longDistanceSpeedPredictionsPerTrueWindSpeed,
|
||||
Map<Speed, Speed> circularRandomSpeedPredictionsPerTrueWindSpeed,
|
||||
Map<Speed, Speed> nonSpinnakerSpeedPredictionsPerTrueWindSpeed) {
|
||||
this.allowancesTrueWindAngles = allowancesTrueWindAngles;
|
||||
this.allowancesTrueWindSpeeds = allowancesTrueWindSpeeds;
|
||||
this.idConsistingOfNatAuthCertNoAndBIN = idConsistingOfNatAuthCertNoAndBIN;
|
||||
this.sailNumber = sailnumber;
|
||||
this.boatName = boatName;
|
||||
@@ -145,6 +144,32 @@ public class ORCCertificateImpl implements ORCCertificate {
|
||||
this.circularRandomSpeedPredictionPerTrueWindSpeed = Collections.unmodifiableMap(circularRandomSpeedPredictionsPerTrueWindSpeed);
|
||||
this.nonSpinnakerSpeedPredictionPerTrueWindSpeed = Collections.unmodifiableMap(nonSpinnakerSpeedPredictionsPerTrueWindSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the default TWS/TWA values from {@link ORCCertificate#ALLOWANCES_TRUE_WIND_SPEEDS} and
|
||||
* {@link ORCCertificate#ALLOWANCES_TRUE_WIND_ANGLES}, respectively, for the matrix of time allowances
|
||||
* or, conversely, the speed predictions.
|
||||
*/
|
||||
public ORCCertificateImpl(String idConsistingOfNatAuthCertNoAndBIN,
|
||||
String sailnumber, String boatName, String boatClassName,
|
||||
Distance length, Duration gph,
|
||||
Double cdl, TimePoint issueDate,
|
||||
Map<Speed, Map<Bearing, Speed>> velocityPredictionsPerTrueWindSpeedAndAngle,
|
||||
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
||||
Map<Speed, Duration> beatAllowancePerTrueWindSpeed, Map<Speed, Bearing> runAngles,
|
||||
Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed,
|
||||
Map<Speed, Duration> runAllowancePerTrueWindSpeed,
|
||||
Map<Speed, Speed> windwardLeewardSpeedPredictionsPerTrueWindSpeed,
|
||||
Map<Speed, Speed> longDistanceSpeedPredictionsPerTrueWindSpeed,
|
||||
Map<Speed, Speed> circularRandomSpeedPredictionsPerTrueWindSpeed,
|
||||
Map<Speed, Speed> nonSpinnakerSpeedPredictionsPerTrueWindSpeed) {
|
||||
this(ALLOWANCES_TRUE_WIND_SPEEDS, ALLOWANCES_TRUE_WIND_ANGLES, idConsistingOfNatAuthCertNoAndBIN, sailnumber,
|
||||
boatName, boatClassName, length, gph, cdl, issueDate, velocityPredictionsPerTrueWindSpeedAndAngle,
|
||||
beatAngles, beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles,
|
||||
runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed,
|
||||
windwardLeewardSpeedPredictionsPerTrueWindSpeed, longDistanceSpeedPredictionsPerTrueWindSpeed,
|
||||
circularRandomSpeedPredictionsPerTrueWindSpeed, nonSpinnakerSpeedPredictionsPerTrueWindSpeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
@@ -255,4 +280,14 @@ public class ORCCertificateImpl implements ORCCertificate {
|
||||
return "Certificate with ID \""+getId()+"\" for "+getSailNumber()+" / "+getBoatName() + " - Issued on: " + (getIssueDate()==null?"n/a":getIssueDate().asDate())+" with GPH "+
|
||||
Util.padPositiveValue(getGPHInSecondsToTheMile(), 1, 1, /* round */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed[] getTrueWindSpeeds() {
|
||||
return allowancesTrueWindSpeeds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing[] getTrueWindAngles() {
|
||||
return allowancesTrueWindAngles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
{
|
||||
"rms":[
|
||||
{
|
||||
"NatAuth":"GR",
|
||||
"BIN":"GR317",
|
||||
"CertNo":"A00073",
|
||||
"RefNo":"N\/A",
|
||||
"SailNo":"GRE-317",
|
||||
"YachtName":"AVANTES",
|
||||
"Class":"FIRST 31.7",
|
||||
"Builder":"BENETEAU",
|
||||
"Designer":"FINOT",
|
||||
"Address3":"I.O. HALKIDAS",
|
||||
"C_Type":"INTL",
|
||||
"Family":"ORC",
|
||||
"Division":"C",
|
||||
"IssueDate":"2020-02-05T12:54:23.484Z",
|
||||
"Age_Year":1998,
|
||||
"CrewWT":550,
|
||||
"LOA":9.49,
|
||||
"IMSL":9.003,
|
||||
"Draft":1.94,
|
||||
"MB":3.216,
|
||||
"Dspl_Measurement":3936,
|
||||
"Stability_Index":103.7,
|
||||
"Dynamic_Allowance":0.31,
|
||||
"GPH":678,
|
||||
"TMF_Inshore":0.9229,
|
||||
"ILCWA":731.4,
|
||||
"TMF_Offshore":0.9145,
|
||||
"OSN":656.1,
|
||||
"CDL":8.155,
|
||||
"TN_Offshore_Low":0.8578,
|
||||
"TN_Offshore_Medium":1.1292,
|
||||
"TN_Offshore_High":1.2751,
|
||||
"TN_Inshore_Low":0.6639,
|
||||
"TN_Inshore_Medium":0.9158,
|
||||
"TN_Inshore_High":1.0666,
|
||||
"TND_Offshore_Low":786.9,
|
||||
"TND_Offshore_Medium":597.8,
|
||||
"TND_Offshore_High":529.4,
|
||||
"TND_Inshore_Low":1016.7,
|
||||
"TND_Inshore_Medium":737.1,
|
||||
"TND_Inshore_High":632.9,
|
||||
"OSN_Jibs":688.6,
|
||||
"TMF_Jibs":0.8713,
|
||||
"Dspl_Sailing":4660,
|
||||
"WSS":22.41,
|
||||
"Area_Main":27.04,
|
||||
"Area_Jib":22.08,
|
||||
"Area_Sym":61.48,
|
||||
"Area_ASym":0,
|
||||
"GPH_Jibs":714.6,
|
||||
"GPH_Jibs_TOT":0.8396,
|
||||
"Allowances":{
|
||||
"WindSpeeds":[
|
||||
6.1,
|
||||
8.2,
|
||||
10.6,
|
||||
12.1,
|
||||
14.9,
|
||||
16.7,
|
||||
20.1
|
||||
],
|
||||
"Beat":[
|
||||
1175.6,
|
||||
968.7,
|
||||
854,
|
||||
780.9,
|
||||
752,
|
||||
744.6,
|
||||
744.9
|
||||
],
|
||||
"Run":[
|
||||
1074.7,
|
||||
847.7,
|
||||
716.4,
|
||||
628.3,
|
||||
566,
|
||||
526.9,
|
||||
480.1
|
||||
],
|
||||
"BeatAngle":[
|
||||
43.5,
|
||||
41.6,
|
||||
40.5,
|
||||
39.8,
|
||||
39,
|
||||
38.6,
|
||||
39
|
||||
],
|
||||
"GybeAngle":[
|
||||
146,
|
||||
150,
|
||||
153,
|
||||
158,
|
||||
178,
|
||||
180,
|
||||
180
|
||||
],
|
||||
"WL":[
|
||||
1125.2,
|
||||
908.2,
|
||||
785.2,
|
||||
704.6,
|
||||
659,
|
||||
635.8,
|
||||
612.5
|
||||
],
|
||||
"CR":[
|
||||
942.4,
|
||||
757.3,
|
||||
657.2,
|
||||
598.8,
|
||||
563,
|
||||
540.1,
|
||||
512.7
|
||||
],
|
||||
"OC":[
|
||||
1120.1,
|
||||
852,
|
||||
706,
|
||||
616.2,
|
||||
571.7,
|
||||
539.8,
|
||||
487.7
|
||||
],
|
||||
"NS":[
|
||||
1008.9,
|
||||
804,
|
||||
691.6,
|
||||
625.1,
|
||||
584.2,
|
||||
558,
|
||||
527.3
|
||||
],
|
||||
"OL":[
|
||||
1077.4,
|
||||
874.1,
|
||||
761.4,
|
||||
694.6,
|
||||
658.2,
|
||||
638.7,
|
||||
615.2
|
||||
],
|
||||
"R52.7":[
|
||||
767,
|
||||
645,
|
||||
577.3,
|
||||
544,
|
||||
530.1,
|
||||
525.8,
|
||||
525
|
||||
],
|
||||
"R64.4":[
|
||||
725.4,
|
||||
613.2,
|
||||
556.7,
|
||||
530.3,
|
||||
516.8,
|
||||
510.9,
|
||||
506.9
|
||||
],
|
||||
"R75":[
|
||||
697.1,
|
||||
589.3,
|
||||
541.9,
|
||||
519,
|
||||
502.9,
|
||||
490.9,
|
||||
480.5
|
||||
],
|
||||
"R90":[
|
||||
694.3,
|
||||
577.7,
|
||||
526.9,
|
||||
505.5,
|
||||
495.9,
|
||||
481.7,
|
||||
454.3
|
||||
],
|
||||
"R110":[
|
||||
688.6,
|
||||
568.4,
|
||||
520.4,
|
||||
493.9,
|
||||
469.8,
|
||||
450.8,
|
||||
430.3
|
||||
],
|
||||
"R120":[
|
||||
710.9,
|
||||
583.7,
|
||||
526.8,
|
||||
498.8,
|
||||
473.3,
|
||||
448.4,
|
||||
409.9
|
||||
],
|
||||
"R135":[
|
||||
788.3,
|
||||
640.5,
|
||||
556.1,
|
||||
517.8,
|
||||
492.5,
|
||||
466.8,
|
||||
416.9
|
||||
],
|
||||
"R150":[
|
||||
930.8,
|
||||
734.2,
|
||||
621.9,
|
||||
551.9,
|
||||
517.7,
|
||||
494,
|
||||
446.5
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+4
-4
@@ -37,9 +37,9 @@ public class TestORCCertificateImporterJSON {
|
||||
assertNotNull(moana);
|
||||
assertEquals(539.1, swan .getGPHInSecondsToTheMile(), 0.0000001);
|
||||
assertEquals(490.4, moana.getGPHInSecondsToTheMile(), 0.0000001);
|
||||
assertEquals(862.2, swan .getWindwardLeewardSpeedPrediction().get(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(788.2, moana.getWindwardLeewardSpeedPrediction().get(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(861.0, swan .getLongDistanceSpeedPredictions().get(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(787.2, moana.getLongDistanceSpeedPredictions().get(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(862.2, swan .getWindwardLeewardSpeedPrediction().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(788.2, moana.getWindwardLeewardSpeedPrediction().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(861.0, swan .getLongDistanceSpeedPredictions().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(787.2, moana.getLongDistanceSpeedPredictions().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -37,10 +37,10 @@ public class TestORCCertificateImporterRMS {
|
||||
assertNotNull(moana);
|
||||
assertEquals(539.1, swan .getGPHInSecondsToTheMile(), 0.0000001);
|
||||
assertEquals(490.4, moana.getGPHInSecondsToTheMile(), 0.0000001);
|
||||
assertEquals(862.2, swan .getWindwardLeewardSpeedPrediction().get(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(788.2, moana.getWindwardLeewardSpeedPrediction().get(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(861.0, swan .getLongDistanceSpeedPredictions().get(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(787.2, moana.getLongDistanceSpeedPredictions().get(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(862.2, swan .getWindwardLeewardSpeedPrediction().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(788.2, moana.getWindwardLeewardSpeedPrediction().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(861.0, swan .getLongDistanceSpeedPredictions().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
assertEquals(787.2, moana.getLongDistanceSpeedPredictions().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+51
-8
@@ -33,7 +33,10 @@ import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveCourseImpl;
|
||||
import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveLegImpl;
|
||||
import com.sap.sailing.domain.orc.impl.ORCCertificatesJsonImporter;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPerformanceCurveImpl;
|
||||
import com.sap.sse.common.Bearing;
|
||||
import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Speed;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.DegreeBearingImpl;
|
||||
|
||||
@@ -49,6 +52,7 @@ public class TestORCPerformanceCurve {
|
||||
|
||||
private static ORCPerformanceCurveCourse alturaCourse;
|
||||
private static ORCCertificatesCollection importerLocal;
|
||||
private static ORCCertificatesCollection importerWithSpecificBins;
|
||||
private static ORCCertificatesCollection importerOnline;
|
||||
|
||||
private static final String RESOURCES = "resources/orc/";
|
||||
@@ -66,6 +70,16 @@ public class TestORCPerformanceCurve {
|
||||
}
|
||||
}
|
||||
|
||||
public void assertEquals(String message, double a, double b, double accuracy) {
|
||||
try {
|
||||
Assert.assertEquals(message, a, b, accuracy);
|
||||
} catch (AssertionError e) {
|
||||
if (collectErrors) {
|
||||
collector.addError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void initialize() throws IOException, ParseException {
|
||||
List<ORCPerformanceCurveLeg> legs = new ArrayList<>();
|
||||
@@ -76,11 +90,12 @@ public class TestORCPerformanceCurve {
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.03), new DegreeBearingImpl(165)));
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.17), new DegreeBearingImpl(180)));
|
||||
alturaCourse = new ORCPerformanceCurveCourseImpl(legs); //this course is the same course as seen in the Altura "IMS Explanation" sheet
|
||||
|
||||
// Local File:
|
||||
File fileGER = new File(RESOURCES + "GER2019.json");
|
||||
importerLocal = new ORCCertificatesJsonImporter().read(new FileInputStream(fileGER));
|
||||
|
||||
// Local File new format with specific TWA/TWS bins:
|
||||
File fileWithSpecificBins = new File(RESOURCES + "newFormatCertificate.json");
|
||||
importerWithSpecificBins = new ORCCertificatesJsonImporter().read(new FileInputStream(fileWithSpecificBins));
|
||||
// Online File:
|
||||
importerOnline = new ORCCertificatesJsonImporter().read(new URL("https://data.orc.org/public/WPub.dll?action=DownRMS&CountryId=GER&ext=json").openStream());
|
||||
}
|
||||
@@ -120,13 +135,13 @@ public class TestORCPerformanceCurve {
|
||||
final ORCPerformanceCurveCourse course = new ORCPerformanceCurveCourseImpl(Arrays.asList(new ORCPerformanceCurveLegImpl(ORCCertificateImpl.NAUTICAL_MILE, new DegreeBearingImpl(twa))));
|
||||
final ORCPerformanceCurve performanceCurve = new ORCPerformanceCurveImpl(certificate, course);
|
||||
for (int i=0; i<expectedAllowancesPerTrueWindSpeed.length; i++) {
|
||||
assertEquals(expectedAllowancesPerTrueWindSpeed[i], performanceCurve.getAllowancePerCourse(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[i]).asSeconds(), accuracy);
|
||||
assertEquals(expectedAllowancesPerTrueWindSpeed[i], performanceCurve.getAllowancePerCourse(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[i]).asSeconds(), accuracy);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleConstructedCourse() throws FunctionEvaluationException {
|
||||
ORCCertificateImpl certificate = (ORCCertificateImpl) importerLocal.getCertificateById("GER140772GER5549");
|
||||
ORCCertificate certificate = (ORCCertificate) importerLocal.getCertificateById("GER140772GER5549");
|
||||
List<ORCPerformanceCurveLeg> legs = new ArrayList<>();
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.0), new DegreeBearingImpl(0)));
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.0), new DegreeBearingImpl(30)));
|
||||
@@ -142,14 +157,14 @@ public class TestORCPerformanceCurve {
|
||||
private void testAllowancePerCourse(ORCPerformanceCurve performanceCurve, double... allowancePerNauticalMileInSeconds) throws ArgumentOutsideDomainException {
|
||||
for (int i=0; i<allowancePerNauticalMileInSeconds.length; i++) {
|
||||
assertEquals(allowancePerNauticalMileInSeconds[i]*performanceCurve.getCourse().getTotalLength().getNauticalMiles(),
|
||||
performanceCurve.getAllowancePerCourse(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[i]).asSeconds(), 0.3);
|
||||
performanceCurve.getAllowancePerCourse(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[i]).asSeconds(), 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformanceCurveInversion() throws MaxIterationsExceededException, FunctionEvaluationException {
|
||||
Double accuracy = 0.1;
|
||||
ORCCertificateImpl certificate = (ORCCertificateImpl) importerLocal.getCertificateById("GER140772GER5549");
|
||||
ORCCertificate certificate = (ORCCertificate) importerLocal.getCertificateById("GER140772GER5549");
|
||||
ORCPerformanceCurveImpl performanceCurve = (ORCPerformanceCurveImpl) new ORCPerformanceCurveImpl(certificate, alturaCourse);
|
||||
testBackwardForward(accuracy, performanceCurve, 11.5);
|
||||
testBackwardForward(accuracy, performanceCurve, 17.23);
|
||||
@@ -247,6 +262,29 @@ public class TestORCPerformanceCurve {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowancesAndImpliedWindForSpecificBins() throws FunctionEvaluationException, MaxIterationsExceededException {
|
||||
final double highAccuracy = 0.01;
|
||||
final double allowanceAccuracy = 0.1;
|
||||
final Distance ONE_NAUTICAL_MILE = new NauticalMileDistance(1.0);
|
||||
final ORCCertificate certificateWithSpecificBins = importerWithSpecificBins.getCertificateById("GRA00073GR317");
|
||||
for (final Bearing twa : certificateWithSpecificBins.getTrueWindAngles()) {
|
||||
final ORCPerformanceCurveCourse singleLegOneMileCourseWithTwa = createSingleLegCourseWithTwa(twa);
|
||||
final ORCPerformanceCurve performanceCurveSpecificBins = new ORCPerformanceCurveImpl(certificateWithSpecificBins, singleLegOneMileCourseWithTwa);
|
||||
for (final Speed tws : certificateWithSpecificBins.getTrueWindSpeeds()) {
|
||||
final Duration duration = certificateWithSpecificBins.getVelocityPredictionPerTrueWindSpeedAndAngle().get(tws).get(twa).getDuration(ONE_NAUTICAL_MILE);
|
||||
assertEquals("mismatch for twa "+twa+", tws "+tws, duration.asSeconds(), performanceCurveSpecificBins.getAllowancePerCourse(tws).asSeconds(), allowanceAccuracy);
|
||||
assertEquals("mismatch for twa "+twa+", tws "+tws, tws.getKnots(), performanceCurveSpecificBins.getImpliedWind(duration).getKnots(), highAccuracy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ORCPerformanceCurveCourse createSingleLegCourseWithTwa(Bearing twa) {
|
||||
List<ORCPerformanceCurveLeg> list = new ArrayList<>();
|
||||
list.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1), twa));
|
||||
return new ORCPerformanceCurveCourseImpl(list);
|
||||
}
|
||||
|
||||
// Tests for the calculations with a more complex course which contains some special leg types. (circular random or other)
|
||||
@Test
|
||||
public void testComplexCourseImpliedWind() throws FunctionEvaluationException, MaxIterationsExceededException {
|
||||
@@ -259,25 +297,28 @@ public class TestORCPerformanceCurve {
|
||||
list.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1), new DegreeBearingImpl(180)));
|
||||
ORCPerformanceCurveCourse complexCourse = new ORCPerformanceCurveCourseImpl(list);
|
||||
|
||||
double accuracy = 0.0001;
|
||||
final double accuracy = 0.0001;
|
||||
ORCCertificate certificateMoana = importerLocal.getCertificateById("GER140772GER5549");
|
||||
ORCCertificate certificateMilan = importerLocal.getCertificateById("GER166844GER7323");
|
||||
ORCCertificate certificateTutima = importerLocal.getCertificateById("GER140618GER5609");
|
||||
ORCCertificate certificateBank = importerLocal.getCertificateById("GER140755GER5555");
|
||||
ORCCertificate certificateHaspa = importerLocal.getCertificateById("GER141411GER6300");
|
||||
ORCCertificate certificateHalbtrocken = importerLocal.getCertificateById("GER141432GER5564");
|
||||
ORCCertificate certificateWithSpecificBins=importerWithSpecificBins.getCertificateById("GRA00073GR317");
|
||||
ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveBank = new ORCPerformanceCurveImpl(certificateBank, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveHaspa = new ORCPerformanceCurveImpl(certificateHaspa, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveHalbtrocken = new ORCPerformanceCurveImpl(certificateHalbtrocken, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveSpecificBins = new ORCPerformanceCurveImpl(certificateWithSpecificBins, complexCourse);
|
||||
assertEquals(15.75777 , performanceCurveMilan .getImpliedWind(Duration.ONE_HOUR.times(1.0)).getKnots(), accuracy);
|
||||
assertEquals(15.27808 , performanceCurveBank .getImpliedWind(Duration.ONE_HOUR.times(1.25)).getKnots(), accuracy);
|
||||
assertEquals(15.10141 , performanceCurveMoana .getImpliedWind(Duration.ONE_HOUR.times(1.25)).getKnots(), accuracy);
|
||||
assertEquals(14.44527 , performanceCurveHaspa .getImpliedWind(Duration.ONE_HOUR.times(1.25)).getKnots(), accuracy);
|
||||
assertEquals(10.86927 , performanceCurveTutima .getImpliedWind(Duration.ONE_HOUR.times(1.5)).getKnots(), accuracy);
|
||||
assertEquals(9.13385 , performanceCurveHalbtrocken.getImpliedWind(Duration.ONE_HOUR.times(2.0)).getKnots(), accuracy);
|
||||
assertEquals(10.83989 , performanceCurveSpecificBins.getImpliedWind(Duration.ONE_HOUR.times(2.0)).getKnots(), accuracy);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -298,12 +339,14 @@ public class TestORCPerformanceCurve {
|
||||
ORCCertificate certificateBank = importerLocal.getCertificateById("GER140755GER5555");
|
||||
ORCCertificate certificateHaspa = importerLocal.getCertificateById("GER141411GER6300");
|
||||
ORCCertificate certificateHalbtrocken = importerLocal.getCertificateById("GER141432GER5564");
|
||||
ORCCertificate certificateWithSpecificBins=importerWithSpecificBins.getCertificateById("GRA00073GR317");
|
||||
ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveBank = new ORCPerformanceCurveImpl(certificateBank, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveHaspa = new ORCPerformanceCurveImpl(certificateHaspa, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveHalbtrocken = new ORCPerformanceCurveImpl(certificateHalbtrocken, complexCourse);
|
||||
ORCPerformanceCurve performanceCurveSpecificBins = new ORCPerformanceCurveImpl(certificateWithSpecificBins, complexCourse);
|
||||
|
||||
assertEquals(Duration.ONE_HOUR.times(1.0).asHours(), performanceCurveMilan.getAllowancePerCourse(new KnotSpeedImpl(15.75777)).asHours(), accuracy);
|
||||
assertEquals(Duration.ONE_HOUR.times(1.25).asHours(), performanceCurveBank.getAllowancePerCourse(new KnotSpeedImpl(15.27808)).asHours(), accuracy);
|
||||
@@ -311,7 +354,7 @@ public class TestORCPerformanceCurve {
|
||||
assertEquals(Duration.ONE_HOUR.times(1.25).asHours(), performanceCurveHaspa.getAllowancePerCourse(new KnotSpeedImpl(14.44527)).asHours(), accuracy);
|
||||
assertEquals(Duration.ONE_HOUR.times(1.5).asHours(), performanceCurveTutima.getAllowancePerCourse(new KnotSpeedImpl(10.86927)).asHours(), accuracy);
|
||||
assertEquals(Duration.ONE_HOUR.times(2.0).asHours(), performanceCurveHalbtrocken.getAllowancePerCourse(new KnotSpeedImpl(9.13385)).asHours(), accuracy);
|
||||
|
||||
assertEquals(Duration.ONE_HOUR.times(2.0).asHours(), performanceCurveSpecificBins.getAllowancePerCourse(new KnotSpeedImpl(10.83989)).asHours(), accuracy);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+131
-86
@@ -1,17 +1,22 @@
|
||||
package com.sap.sailing.domain.orc.impl;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.common.orc.impl.ORCCertificateImpl;
|
||||
@@ -57,6 +62,13 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
|
||||
private static final String CIRCULAR_RANDOM = "CR";
|
||||
private static final String NON_SPINNAKER = "NS";
|
||||
private static final String EMPTY_CERT_NO = " ";
|
||||
private static final String WIND_SPEEDS = "WindSpeeds";
|
||||
|
||||
/**
|
||||
* Pattern to recognize a true wind angle in the allowances section. Group 1 contains
|
||||
* the decimal number that represents the true wind angle in degrees.
|
||||
*/
|
||||
private static final Pattern twaPattern = Pattern.compile("R(\\d+(\\.\\d+)?)");
|
||||
|
||||
private Map<String, JSONObject> certificateJsonObjectsByCertificateId;
|
||||
|
||||
@@ -79,18 +91,21 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
|
||||
*/
|
||||
@Override
|
||||
public ORCCertificate getCertificateById(String certificateId) {
|
||||
String boatName = null;
|
||||
String boatName = null;
|
||||
String boatclass = null;
|
||||
Distance length = null;
|
||||
Duration gph = null;
|
||||
Double cdl = null;
|
||||
Distance length = null;
|
||||
Duration gph = null;
|
||||
Double cdl = null;
|
||||
TimePoint issueDate = null;
|
||||
Map<Speed, Bearing> beatAngles = new HashMap<>();
|
||||
Map<Speed, Bearing> gybeAngles = new HashMap<>();
|
||||
Map<Speed, Map<Bearing, Speed>> velocityPredictionPerTrueWindSpeedAndAngle = new HashMap<>();
|
||||
Map<Bearing, Map<Speed, Duration>> allowanceDurationsPerTrueWindAngleAndSpeed = new HashMap<>(); //per nautical mile
|
||||
Map<String, Map<Speed, Duration>> predefinedAllowanceDurationsPerTrueWindSpeed = new HashMap<>(); //per nautical mile
|
||||
JSONObject object = certificateJsonObjectsByCertificateId.get(certificateId);
|
||||
final Map<Speed, Bearing> beatAngles = new HashMap<>();
|
||||
final Map<Speed, Bearing> gybeAngles = new HashMap<>();
|
||||
final Map<Speed, Map<Bearing, Speed>> velocityPredictionPerTrueWindSpeedAndAngle = new HashMap<>();
|
||||
final Map<Bearing, Map<Speed, Duration>> allowanceDurationsPerTrueWindAngleAndSpeed = new HashMap<>(); // per nautical mile
|
||||
final Map<String, Map<Speed, Duration>> predefinedAllowanceDurationsPerTrueWindSpeed = new HashMap<>(); // per nautical mile
|
||||
final Map<Double, Speed> trueWindSpeedMap = new TreeMap<Double,Speed>(); // Using TreeMap implementation to save the TrueWindSpeed
|
||||
// so that it first sorts the entries as well as avoids duplicates
|
||||
final Map<Double, Bearing> trueWindAngleMap = new TreeMap<Double,Bearing>(); // Same like trueWindSpeedMap
|
||||
final JSONObject object = certificateJsonObjectsByCertificateId.get(certificateId);
|
||||
if (object == null) {
|
||||
// TODO Throw Exception for certificate by id not found. InvalidArgumentException?
|
||||
return null;
|
||||
@@ -98,84 +113,104 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
|
||||
String sailNumber = null;
|
||||
for (Entry<Object, Object> entry : object.entrySet()) {
|
||||
switch ((String) entry.getKey()) {
|
||||
case SAIL_NO:
|
||||
sailNumber = entry.getValue() == null ? null : entry.getValue().toString();
|
||||
break;
|
||||
case LOA:
|
||||
length = new MeterDistance(((Number) entry.getValue()).doubleValue());
|
||||
break;
|
||||
case YACHT_NAME:
|
||||
boatName = entry.getValue()==null?null:entry.getValue().toString();
|
||||
break;
|
||||
case CLASS:
|
||||
boatclass = (String) entry.getValue();
|
||||
break;
|
||||
case GPH2:
|
||||
gph = new SecondsDurationImpl(((Number) entry.getValue()).doubleValue());
|
||||
break;
|
||||
case CDL2:
|
||||
cdl = ((Number) entry.getValue()).doubleValue();
|
||||
break;
|
||||
case ISSUE_DATE:
|
||||
Date date = DatatypeConverter.parseDateTime((String) entry.getValue()).getTime();
|
||||
issueDate = new MillisecondsTimePoint(date);
|
||||
break;
|
||||
case ALLOWANCES:
|
||||
final JSONObject allowances = (JSONObject) object.get(ALLOWANCES);
|
||||
for (final Object aKey : allowances.keySet()) {
|
||||
final JSONArray array = (JSONArray) allowances.get(aKey);
|
||||
if (((String) aKey).equals(BEAT_ANGLE)) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
beatAngles.put(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[i],
|
||||
new DegreeBearingImpl(((Number) array.get(i)).doubleValue()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (((String) aKey).equals(GYBE_ANGLE)) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
gybeAngles.put(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[i],
|
||||
new DegreeBearingImpl(((Number) array.get(i)).doubleValue()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Map<Speed, Duration> twsMap = new HashMap<>();
|
||||
case SAIL_NO:
|
||||
sailNumber = entry.getValue() == null ? null : entry.getValue().toString();
|
||||
break;
|
||||
case LOA:
|
||||
length = new MeterDistance(((Number) entry.getValue()).doubleValue());
|
||||
break;
|
||||
case YACHT_NAME:
|
||||
boatName = entry.getValue() == null ? null : entry.getValue().toString();
|
||||
break;
|
||||
case CLASS:
|
||||
boatclass = (String) entry.getValue();
|
||||
break;
|
||||
case GPH2:
|
||||
gph = new SecondsDurationImpl(((Number) entry.getValue()).doubleValue());
|
||||
break;
|
||||
case CDL2:
|
||||
cdl = ((Number) entry.getValue()).doubleValue();
|
||||
break;
|
||||
case ISSUE_DATE:
|
||||
Date date = DatatypeConverter.parseDateTime((String) entry.getValue()).getTime();
|
||||
issueDate = new MillisecondsTimePoint(date);
|
||||
break;
|
||||
case ALLOWANCES:
|
||||
final JSONObject allowances = (JSONObject) object.get(ALLOWANCES);
|
||||
// calculating the TWA and TWS before calculating the other dependent values in allowances object
|
||||
final Object windSpeedsObject = allowances.get(WIND_SPEEDS);
|
||||
if (windSpeedsObject != null) {
|
||||
final JSONArray twsArray = (JSONArray) windSpeedsObject;
|
||||
for (final Object twsObject : twsArray) {
|
||||
Double twsValue = ((Number) twsObject).doubleValue();
|
||||
trueWindSpeedMap.put(twsValue, new KnotSpeedImpl(twsValue));
|
||||
}
|
||||
} else {
|
||||
for (Speed speed : ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
trueWindSpeedMap.put(speed.getKnots(), speed);
|
||||
}
|
||||
}
|
||||
final Double [] trueWindSpeedArray = new Double[trueWindSpeedMap.size()];
|
||||
trueWindSpeedMap.keySet().toArray(trueWindSpeedArray);
|
||||
for (final Object aKey : allowances.keySet()) {
|
||||
String keyString = (String) aKey;
|
||||
final Matcher matcher = twaPattern.matcher(keyString);
|
||||
if (matcher.lookingAt()) {
|
||||
final JSONArray array = (JSONArray) allowances.get(keyString);
|
||||
final Map<Speed, Duration> twsMap = new HashMap<>();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
twsMap.put(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[i],
|
||||
final Double allowanceValue = ((Number) array.get(i)).doubleValue();
|
||||
twsMap.put(trueWindSpeedMap.get(trueWindSpeedArray[i]), new SecondsDurationImpl(allowanceValue));
|
||||
}
|
||||
final Double trueWindAngleValue = Double.parseDouble(matcher.group(1));
|
||||
trueWindAngleMap.put(trueWindAngleValue, new DegreeBearingImpl(trueWindAngleValue));
|
||||
allowanceDurationsPerTrueWindAngleAndSpeed.put(trueWindAngleMap.get(trueWindAngleValue), twsMap);
|
||||
}
|
||||
}
|
||||
// Now read the various allowances, assuming we find values for the TWS "bins" identified above
|
||||
for (final Object aKey : allowances.keySet()) {
|
||||
final JSONArray array = (JSONArray) allowances.get(aKey);
|
||||
if (((String) aKey).equals(BEAT_ANGLE)) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
beatAngles.put(new KnotSpeedImpl(trueWindSpeedArray[i]),
|
||||
new DegreeBearingImpl(((Number) array.get(i)).doubleValue()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (((String) aKey).equals(GYBE_ANGLE)) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
gybeAngles.put(new KnotSpeedImpl(trueWindSpeedArray[i]),
|
||||
new DegreeBearingImpl(((Number) array.get(i)).doubleValue()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Map<Speed, Duration> twsMap = new HashMap<>();
|
||||
//ignore true wind angles key
|
||||
if (!twaPattern.matcher((String) aKey).lookingAt()) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
twsMap.put(new KnotSpeedImpl(trueWindSpeedArray[i]),
|
||||
new SecondsDurationImpl(((Number) array.get(i)).doubleValue()));
|
||||
}
|
||||
switch ((String) aKey) {
|
||||
case "R52":
|
||||
case "R60":
|
||||
case "R75":
|
||||
case "R90":
|
||||
case "R110":
|
||||
case "R120":
|
||||
case "R135":
|
||||
case "R150":
|
||||
allowanceDurationsPerTrueWindAngleAndSpeed.put(
|
||||
new DegreeBearingImpl(Integer.parseInt(((String) aKey).substring(1))), twsMap);
|
||||
break;
|
||||
case BEAT:
|
||||
case RUN:
|
||||
predefinedAllowanceDurationsPerTrueWindSpeed.put((String) aKey, twsMap);
|
||||
break;
|
||||
default:
|
||||
predefinedAllowanceDurationsPerTrueWindSpeed.put((String) aKey, twsMap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch ((String) aKey) {
|
||||
case BEAT:
|
||||
case RUN:
|
||||
predefinedAllowanceDurationsPerTrueWindSpeed.put((String) aKey, twsMap);
|
||||
break;
|
||||
default:
|
||||
predefinedAllowanceDurationsPerTrueWindSpeed.put((String) aKey, twsMap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
velocityPredictionPerTrueWindSpeedAndAngle.put(tws, new HashMap<>());
|
||||
}
|
||||
for (Bearing keyTWA : allowanceDurationsPerTrueWindAngleAndSpeed.keySet()) {
|
||||
for (Speed keyTWS : allowanceDurationsPerTrueWindAngleAndSpeed.get(keyTWA).keySet()) {
|
||||
velocityPredictionPerTrueWindSpeedAndAngle.get(keyTWS).put(keyTWA,
|
||||
ORCCertificateImpl.NAUTICAL_MILE
|
||||
trueWindSpeedMap.values().forEach(tws -> velocityPredictionPerTrueWindSpeedAndAngle.put(tws, new HashMap<>()));
|
||||
for (final Bearing keyTWA : allowanceDurationsPerTrueWindAngleAndSpeed.keySet()) {
|
||||
for (final Speed keyTWS : allowanceDurationsPerTrueWindAngleAndSpeed.get(keyTWA).keySet()) {
|
||||
velocityPredictionPerTrueWindSpeedAndAngle.get(keyTWS).put(keyTWA, ORCCertificateImpl.NAUTICAL_MILE
|
||||
.inTime(allowanceDurationsPerTrueWindAngleAndSpeed.get(keyTWA).get(keyTWS)));
|
||||
}
|
||||
}
|
||||
@@ -203,20 +238,30 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
|
||||
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificateImpl.NAUTICAL_MILE
|
||||
.inTime(predefinedAllowanceDurationsPerTrueWindSpeed.get(NON_SPINNAKER).get(tws)));
|
||||
}
|
||||
return new ORCCertificateImpl(getId(object), sailNumber, boatName, boatclass, length, gph, cdl,
|
||||
issueDate, velocityPredictionPerTrueWindSpeedAndAngle, beatAngles, beatVMGPredictionPerTrueWindSpeed,
|
||||
final Bearing[] dynamicAllowancesTrueWindAngles = trueWindAngleMap.values().toArray(new Bearing[trueWindAngleMap.values().size()]);
|
||||
final Speed[] dynamicAllowancesTrueWindSpeeds = trueWindSpeedMap.values().toArray(new Speed[trueWindSpeedMap.values().size()]);
|
||||
// replace array by the default arrays if they match; this will save the space for the dynamically-parsed arrays
|
||||
return new ORCCertificateImpl(
|
||||
Arrays.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS, dynamicAllowancesTrueWindSpeeds)
|
||||
? ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS
|
||||
: dynamicAllowancesTrueWindSpeeds,
|
||||
Arrays.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES, dynamicAllowancesTrueWindAngles)
|
||||
? ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES
|
||||
: dynamicAllowancesTrueWindAngles,
|
||||
getId(object), sailNumber, boatName, boatclass, length, gph, cdl, issueDate,
|
||||
velocityPredictionPerTrueWindSpeedAndAngle, beatAngles, beatVMGPredictionPerTrueWindSpeed,
|
||||
beatAllowancePerTrueWindSpeed, gybeAngles, runVMGPredictionPerTrueWindSpeed,
|
||||
runAllowancePerTrueWindSpeed, windwardLeewardSpeedPredictionPerTrueWindSpeed,
|
||||
longDistanceSpeedPredictionPerTrueWindSpeed, circularRandomSpeedPredictionPerTrueWindSpeed,
|
||||
nonSpinnakerSpeedPredictionPerTrueWindSpeed);
|
||||
}
|
||||
|
||||
|
||||
private String getId(JSONObject certificateAsJson) {
|
||||
return getIdFromFields(certificateAsJson.get(NAT_AUTH).toString(),
|
||||
certificateAsJson.get(CERT_NO) == null ? EMPTY_CERT_NO : certificateAsJson.get(CERT_NO).toString(),
|
||||
certificateAsJson.get(BIN).toString());
|
||||
}
|
||||
|
||||
|
||||
private String getIdFromFields(final String natAuth, final String certNo, final String bin) {
|
||||
return natAuth + certNo + bin;
|
||||
}
|
||||
|
||||
+2
-2
@@ -122,7 +122,7 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect
|
||||
final Map<Speed, Speed> longDistanceSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||
final Map<Speed, Speed> circularRandomSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||
final Map<Speed, Speed> nonSpinnakerSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||
for (Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (Speed tws : ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
String windSpeed = Integer.toString((int) tws.getKnots());
|
||||
String beatAngleKey = BEAT_ANGLE + windSpeed;
|
||||
String beatAllowanceKey = BEAT_ALLOWANCE + windSpeed;
|
||||
@@ -147,7 +147,7 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect
|
||||
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificateImpl.NAUTICAL_MILE.inTime(
|
||||
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(nonSpinnakerKey)))));
|
||||
Map<Bearing, Speed> velocityPredictionPerTrueWindAngle = new HashMap<>();
|
||||
for (Bearing twa : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES ) {
|
||||
for (Bearing twa : ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES ) {
|
||||
String twaCoursesKey = TWA_COURSES + Integer.toString((int) twa.getDegrees()) + windSpeed;
|
||||
velocityPredictionPerTrueWindAngle.put(twa, ORCCertificateImpl.NAUTICAL_MILE.inTime(
|
||||
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(twaCoursesKey)))));
|
||||
|
||||
+38
-17
@@ -71,6 +71,16 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
* allowance in sec/nm.
|
||||
*/
|
||||
private final UnivariateDifferentiableFunction functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse;
|
||||
|
||||
/**
|
||||
* The {@link ORCCertificate#getTrueWindAngles()} from the certificate
|
||||
*/
|
||||
private final Bearing[] trueWindAngles;
|
||||
|
||||
/**
|
||||
* The {@link ORCCertificate#getTrueWindSpeeds()} from the certificate
|
||||
*/
|
||||
private final Speed[] trueWindSpeeds;
|
||||
|
||||
/**
|
||||
* Accepts the simplified polar data, one "column" for each of the defined true wind speeds, where each column is a
|
||||
@@ -79,6 +89,8 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
*/
|
||||
public ORCPerformanceCurveImpl(ORCCertificate certificate, ORCPerformanceCurveCourse course) throws FunctionEvaluationException {
|
||||
this.course = course;
|
||||
this.trueWindAngles = certificate.getTrueWindAngles();
|
||||
this.trueWindSpeeds = certificate.getTrueWindSpeeds();
|
||||
functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse = createPerformanceCurve(certificate);
|
||||
}
|
||||
|
||||
@@ -100,8 +112,8 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
*/
|
||||
private UnivariateDifferentiableFunction createPerformanceCurve(ORCCertificate certificate) throws FunctionEvaluationException {
|
||||
final Map<Speed, Duration> allowancesForCoursePerTrueWindSpeed = createAllowancesPerCourse(certificate);
|
||||
double[] xs = new double[ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS.length+2];
|
||||
double[] ys = new double[ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS.length+2];
|
||||
double[] xs = new double[certificate.getTrueWindSpeeds().length+2];
|
||||
double[] ys = new double[certificate.getTrueWindSpeeds().length+2];
|
||||
int i = 0;
|
||||
xs[i] = 0; // see original Pascal code; the first "knot" is set to (0.0, 0.0)
|
||||
ys[i] = 0;
|
||||
@@ -142,7 +154,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
for (final ORCPerformanceCurveLeg leg : course.getLegs()) {
|
||||
allowancesPerLeg.put(leg, createAllowancePerLeg(leg, certificate));
|
||||
}
|
||||
for (final Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (final Speed tws : certificate.getTrueWindSpeeds()) {
|
||||
Duration allowancePerTws = new SecondsDurationImpl(0);
|
||||
for (final ORCPerformanceCurveLeg leg : course.getLegs()) {
|
||||
allowancePerTws = allowancePerTws.plus(allowancesPerLeg.get(leg).get(tws));
|
||||
@@ -168,7 +180,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
|
||||
switch (leg.getType()) {
|
||||
case TWA:
|
||||
for (final Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (final Speed tws : certificate.getTrueWindSpeeds()) {
|
||||
// Case switching on TWA (0. TWA == 0; 1. TWA < Beat; 2. Beat < TWA < Gybe; 3. Gybe < TWA; 4. TWA == 180)
|
||||
if (leg.getTwa().abs().compareTo(beatAngles.get(tws)) <= 0) {
|
||||
// Case 0 & 1 - result = beatVMG * distance * cos(TWA)
|
||||
@@ -186,23 +198,23 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
}
|
||||
break;
|
||||
case CIRCULAR_RANDOM:
|
||||
for (final Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (final Speed tws : certificate.getTrueWindSpeeds()) {
|
||||
result.put(tws, certificate.getCircularRandomSpeedPredictions().get(tws).getDuration(leg.getLength()));
|
||||
}
|
||||
break;
|
||||
case LONG_DISTANCE:
|
||||
for (final Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (final Speed tws : certificate.getTrueWindSpeeds()) {
|
||||
result.put(tws, certificate.getLongDistanceSpeedPredictions().get(tws).getDuration(leg.getLength()));
|
||||
}
|
||||
break;
|
||||
case WINDWARD_LEEWARD:
|
||||
case WINDWARD_LEEWARD_REAL_LIVE:
|
||||
for (final Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (final Speed tws : certificate.getTrueWindSpeeds()) {
|
||||
result.put(tws, certificate.getWindwardLeewardSpeedPrediction().get(tws).getDuration(leg.getLength()));
|
||||
}
|
||||
break;
|
||||
case NON_SPINNAKER:
|
||||
for (final Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (final Speed tws :certificate.getTrueWindSpeeds()) {
|
||||
result.put(tws, certificate.getNonSpinnakerSpeedPredictions().get(tws).getDuration(leg.getLength()));
|
||||
}
|
||||
break;
|
||||
@@ -216,7 +228,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
*/
|
||||
private double[][] createPolarsPerTrueWindSpeed(Speed trueWindSpeed, Map<Speed, Map<Bearing, Speed>> reachingSpeedPredictionsPerTrueWindSpeedAndAngle,
|
||||
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
||||
Map<Speed, Bearing> runAngles, Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed) {
|
||||
Map<Speed, Bearing> runAngles, Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed, Bearing[] trueWindAngles) {
|
||||
ArrayList<Double> resultWindAngles = new ArrayList<>();
|
||||
ArrayList<Double> resultSpeedsOverGroundInKnots = new ArrayList<>();
|
||||
Bearing beatAngle = beatAngles.get(trueWindSpeed);
|
||||
@@ -228,7 +240,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
resultSpeedsOverGroundInKnots.add(beatVMGPredictionPerTrueWindSpeed.get(trueWindSpeed).getKnots() / Math.cos(beatAngle.add(MINUS_TWO_DEGREES).getRadians()));
|
||||
resultWindAngles.add(beatAngle.getDegrees());
|
||||
resultSpeedsOverGroundInKnots.add(beatVMGPredictionPerTrueWindSpeed.get(trueWindSpeed).getKnots() / Math.cos(beatAngle.getRadians()));
|
||||
for (final Bearing twa : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES) {
|
||||
for (final Bearing twa : trueWindAngles) {
|
||||
if (twa.compareTo(beatAngle) > 0 && twa.compareTo(runAngle) < 0) {
|
||||
resultWindAngles.add(twa.getDegrees());
|
||||
resultSpeedsOverGroundInKnots.add(reachingSpeedPredictionsPerTrueWindSpeedAndAngle.get(trueWindSpeed).get(twa).getKnots());
|
||||
@@ -251,14 +263,14 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
@Override
|
||||
public Speed getImpliedWind(Duration durationToCompleteCourse) throws MaxIterationsExceededException, FunctionEvaluationException{
|
||||
final Speed averageSpeedOnCourse = getCourse().getTotalLength().inTime(durationToCompleteCourse);
|
||||
final double[] predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed = Arrays.stream(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS).mapToDouble
|
||||
final double[] predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed = Arrays.stream(trueWindSpeeds).mapToDouble
|
||||
(tws->{ return functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse.value(tws.getKnots()); }).toArray();
|
||||
final Speed result;
|
||||
// Corner cases for Allowance > Allowance(20kt) or Allowance < Allowance(6kt)
|
||||
if (averageSpeedOnCourse.getKnots() >= predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed[predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed.length-1]) {
|
||||
result = ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS.length-1];
|
||||
result = trueWindSpeeds[trueWindSpeeds.length-1];
|
||||
} else if (averageSpeedOnCourse.equals(Speed.NULL) || averageSpeedOnCourse.getKnots() <= predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed[0]) {
|
||||
result = ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0];
|
||||
result = trueWindSpeeds[0];
|
||||
} else {
|
||||
// find the polynomial splined function that produces the durationToCompleteCourse within its validity range
|
||||
int i = 1; // skip the auxiliary spline segment from (0.0, 0.0) to (6.0, ...)
|
||||
@@ -272,7 +284,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
final UnivariateDifferentiableFunction targetZeroFunction = FunctionUtils.add(functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse,
|
||||
FunctionUtils.multiply((UnivariateDifferentiableFunction) averageSpeedInKnots,
|
||||
(UnivariateDifferentiableFunction) new Constant(-1)));
|
||||
final double impliedWindSpeedInKnots = newtonSolver.solve(1000, targetZeroFunction, 10 /* knots of true wind speed */);
|
||||
final double impliedWindSpeedInKnots = newtonSolver.solve(1000, targetZeroFunction, 12 /* knots of true wind speed */);
|
||||
result = new KnotSpeedImpl(impliedWindSpeedInKnots);
|
||||
}
|
||||
return result;
|
||||
@@ -294,9 +306,18 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
||||
Map<Speed, Bearing> runAngles, Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed, Speed trueWindSpeed,
|
||||
Bearing trueWindAngle) throws FunctionEvaluationException, IllegalArgumentException {
|
||||
return getLagrangeSpeedPredictionForTrueWindSpeedAndAngle(twaAllowances, beatAngles,
|
||||
beatVMGPredictionPerTrueWindSpeed, runAngles, runVMGPredictionPerTrueWindSpeed, trueWindSpeed,
|
||||
trueWindAngle, trueWindAngles);
|
||||
}
|
||||
|
||||
public Speed getLagrangeSpeedPredictionForTrueWindSpeedAndAngle(Map<Speed, Map<Bearing, Speed>> twaAllowances,
|
||||
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
||||
Map<Speed, Bearing> runAngles, Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed, Speed trueWindSpeed,
|
||||
Bearing trueWindAngle, Bearing[] trueWindAngles) throws FunctionEvaluationException, IllegalArgumentException {
|
||||
final Speed result;
|
||||
double[][] polarPoints = createPolarsPerTrueWindSpeed(trueWindSpeed, twaAllowances, beatAngles,
|
||||
beatVMGPredictionPerTrueWindSpeed, runAngles, runVMGPredictionPerTrueWindSpeed);
|
||||
beatVMGPredictionPerTrueWindSpeed, runAngles, runVMGPredictionPerTrueWindSpeed, trueWindAngles);
|
||||
double[] twaPolarPoints = polarPoints[0];
|
||||
double[] speedsOverGroundInKnotsPolarPoints = polarPoints[1];
|
||||
int i = -1; // after the loop, i equals the next higher available polar data for the given TWA
|
||||
@@ -330,9 +351,9 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
* the {@link #course} (which may be a prefix of a longer course) at the true wind speed provided to the resulting
|
||||
* map as the key. Iteration order is in ascending true wind speeds.
|
||||
*/
|
||||
public LinkedHashMap<Speed, Duration> getAllowancesPerTrueWindSpeedsForCourse() throws ArgumentOutsideDomainException {
|
||||
private LinkedHashMap<Speed, Duration> getAllowancesPerTrueWindSpeedsForCourse() throws ArgumentOutsideDomainException {
|
||||
final LinkedHashMap<Speed, Duration> result = new LinkedHashMap<>();
|
||||
for (final Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (final Speed tws : trueWindSpeeds) {
|
||||
result.put(tws, getAllowancePerCourse(tws));
|
||||
}
|
||||
return result;
|
||||
|
||||
+14
-1
@@ -1,12 +1,15 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.orc.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.common.orc.impl.ORCCertificateImpl;
|
||||
import com.sap.sse.common.Bearing;
|
||||
import com.sap.sse.common.Distance;
|
||||
@@ -43,6 +46,10 @@ public class ORCCertificateImpl_CustomFieldSerializer extends CustomFieldSeriali
|
||||
streamWriter.writeObject(new HashMap<>(instance.getLongDistanceSpeedPredictions()));
|
||||
streamWriter.writeObject(new HashMap<>(instance.getCircularRandomSpeedPredictions()));
|
||||
streamWriter.writeObject(new HashMap<>(instance.getNonSpinnakerSpeedPredictions()));
|
||||
streamWriter.writeObject(Arrays.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES, instance.getTrueWindAngles()) ? null :
|
||||
Arrays.asList(instance.getTrueWindAngles()));
|
||||
streamWriter.writeObject(Arrays.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS, instance.getTrueWindSpeeds()) ? null :
|
||||
Arrays.asList(instance.getTrueWindSpeeds()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,7 +95,13 @@ public class ORCCertificateImpl_CustomFieldSerializer extends CustomFieldSeriali
|
||||
final Map<Speed, Speed> circularRandomSpeedPredictionsPerTrueWindSpeed = (Map<Speed, Speed>) streamReader.readObject();
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<Speed, Speed> nonSpinnakerSpeedPredictionsPerTrueWindSpeed = (Map<Speed, Speed>) streamReader.readObject();
|
||||
return new ORCCertificateImpl(idConsistingOfNatAuthCertNoAndBIN, sailnumber, boatName, boatclass, length, gph,
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Bearing> readTWAs = (List<Bearing>) streamReader.readObject();
|
||||
final Bearing[] trueWindAngles = readTWAs == null ? ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES : readTWAs.toArray(new Bearing[readTWAs.size()]);
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Speed> readTWSs = (List<Speed>) streamReader.readObject();
|
||||
final Speed[] trueWindSpeeds = readTWSs == null ? ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS : readTWSs.toArray(new Speed[readTWSs.size()]);
|
||||
return new ORCCertificateImpl(trueWindSpeeds,trueWindAngles,idConsistingOfNatAuthCertNoAndBIN, sailnumber, boatName, boatclass, length, gph,
|
||||
cdl, issueDate, velocityPredictionsPerTrueWindSpeedAndAngle, beatAngles,
|
||||
beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles,
|
||||
runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed,
|
||||
|
||||
+1
@@ -110,6 +110,7 @@ public class MarkPropertiesPanel extends FlowPanel {
|
||||
strings.add(t.getName());
|
||||
strings.add(t.getCommonMarkProperties().getShortName());
|
||||
strings.add(t.getUuid().toString());
|
||||
Util.addAll(t.getTags(), strings);
|
||||
return strings;
|
||||
}
|
||||
|
||||
|
||||
+2
-10
@@ -38,7 +38,6 @@ import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.ProvidesResize;
|
||||
import com.google.gwt.user.client.ui.RequiresResize;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.user.client.ui.WidgetCollection;
|
||||
@@ -202,7 +201,7 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
||||
*
|
||||
* @author Simon Marcel Pamies, Axel Uhl
|
||||
*/
|
||||
abstract class Splitter extends AbsolutePanel implements RequiresResize, ProvidesResize {
|
||||
abstract class Splitter extends AbsolutePanel {
|
||||
protected final Widget target;
|
||||
|
||||
private int offset;
|
||||
@@ -319,7 +318,6 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
||||
syncedCenterSize = newCenterSize;
|
||||
centerSize = newCenterSize;
|
||||
}
|
||||
|
||||
return Math.max(((LayoutData) target.getLayoutData()).size + centerSize, 0);
|
||||
}
|
||||
|
||||
@@ -376,11 +374,6 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResize() {
|
||||
setAssociatedWidgetSize(getTargetSize(), /* defer */ false);
|
||||
}
|
||||
|
||||
protected abstract int getAbsolutePosition();
|
||||
protected abstract double getCenterSize();
|
||||
protected abstract int getEventPosition(Event event);
|
||||
@@ -851,7 +844,7 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
||||
if (splitter != null) {
|
||||
LayoutData layoutData = (LayoutData) widget.getLayoutData();
|
||||
if (hidden) {
|
||||
if(layoutData.size > 0) {
|
||||
if (layoutData.size > 0) {
|
||||
layoutData.oldSize = layoutData.size;
|
||||
}
|
||||
widget.setVisible(false);
|
||||
@@ -861,7 +854,6 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
||||
}
|
||||
}
|
||||
splitter.setAssociatedWidgetSize(0, /* defer */false);
|
||||
|
||||
// need to ensure visibility of dragger, do NOT use setVisible() as south/north splitter should be shown always
|
||||
splitter.setDraggerVisible(!hidden);
|
||||
} else {
|
||||
|
||||
+28
-4
@@ -1,8 +1,12 @@
|
||||
package com.sap.sailing.server.gateway.deserialization.racelog.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
@@ -46,7 +50,11 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
|
||||
Map<Speed, Speed> longDistanceSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||
Map<Speed, Speed> circularRandomSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||
Map<Speed, Speed> nonSpinnakerSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||
for (Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
Speed[] trueWindSpeeds = convertJsonArrayOfDoublesToArrayOfObjectsOrReturnDefault(json.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_TRUE_WIND_SPEEDS_IN_KNOTS),
|
||||
ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS, speedInKnots->new KnotSpeedImpl(speedInKnots), new Speed[0]);
|
||||
Bearing[] trueWindAngles = convertJsonArrayOfDoublesToArrayOfObjectsOrReturnDefault(json.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_TRUE_WIND_ANGLES_IN_TRUE_DEGREES),
|
||||
ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES, twaInTrueDegrees->new DegreeBearingImpl(twaInTrueDegrees), new Bearing[0]);
|
||||
for (Speed tws : trueWindSpeeds) {
|
||||
String twsKey = ORCCertificateJsonSerializer.speedToKnotsString(tws);
|
||||
beatAngles.put(tws, new DegreeBearingImpl(
|
||||
((Number) ((JSONObject) json.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_BEAT_ANGLES))
|
||||
@@ -84,9 +92,8 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
|
||||
new KnotSpeedImpl(((Number) ((JSONObject) json
|
||||
.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_NON_SPINNAKER_SPEED_PREDICTIONS))
|
||||
.get(twsKey)).doubleValue()));
|
||||
|
||||
Map<Bearing, Speed> velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle = new HashMap<>();
|
||||
for (Bearing twa : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES) {
|
||||
for (Bearing twa : trueWindAngles) {
|
||||
String twaKey = ORCCertificateJsonSerializer.bearingToDegreeString(twa);
|
||||
velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle.put(twa,
|
||||
new KnotSpeedImpl(((Number) ((JSONObject) ((JSONObject) json
|
||||
@@ -97,7 +104,7 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
|
||||
velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle);
|
||||
}
|
||||
final String idConsistingOfNatAuthCertNoAndBIN = json.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_ID).toString();
|
||||
final ORCCertificate certificate = new ORCCertificateImpl(idConsistingOfNatAuthCertNoAndBIN, sailnumber,
|
||||
final ORCCertificate certificate = new ORCCertificateImpl(trueWindSpeeds,trueWindAngles,idConsistingOfNatAuthCertNoAndBIN, sailnumber,
|
||||
boatName, boatclass, length, gph, cdl, issueDate, velocityPredictionsPerTrueWindSpeedAndAngle,
|
||||
beatAngles, beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles,
|
||||
runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed,
|
||||
@@ -105,4 +112,21 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
|
||||
circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed);
|
||||
return certificate;
|
||||
}
|
||||
|
||||
private <T> T[] convertJsonArrayOfDoublesToArrayOfObjectsOrReturnDefault(final Object supposedJsonArray,
|
||||
final T[] defaults, final Function<Double, T> constructor, T[] array) {
|
||||
final T[] result;
|
||||
final JSONArray windAnglesJsonArray;
|
||||
if (supposedJsonArray == null || !(supposedJsonArray instanceof JSONArray) || (windAnglesJsonArray=(JSONArray) supposedJsonArray).isEmpty()) {
|
||||
result = defaults;
|
||||
} else {
|
||||
final List<T> resultList = new ArrayList<>();
|
||||
for (final Object number : windAnglesJsonArray) {
|
||||
resultList.add(constructor.apply((Double) number));
|
||||
}
|
||||
final T[] tArray = resultList.toArray(array);
|
||||
result = tArray;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+53
-22
@@ -1,9 +1,12 @@
|
||||
package com.sap.sailing.server.gateway.serialization.racelog.impl;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.common.orc.impl.ORCCertificateImpl;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
import com.sap.sse.common.Bearing;
|
||||
import com.sap.sse.common.Speed;
|
||||
@@ -28,6 +31,7 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
|
||||
public static final String ORC_CERTIFICATE_ID = "ID";
|
||||
public static final String ORC_CERTIFICATE_LENGTH = "length";
|
||||
public static final String ORC_CERTIFICATE_ISSUE_DATE = "issueDate";
|
||||
public static final String ORC_CERTIFICATE_TWS_KNOTS = "ORC_CERTIFICATE_TWS_{0}KT";
|
||||
public static final String ORC_CERTIFICATE_TWS_6KT = "ORC_CERTIFICATE_TWS_6KT";
|
||||
public static final String ORC_CERTIFICATE_TWS_8KT = "ORC_CERTIFICATE_TWS_8KT";
|
||||
public static final String ORC_CERTIFICATE_TWS_10KT = "ORC_CERTIFICATE_TWS_10KT";
|
||||
@@ -35,6 +39,8 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
|
||||
public static final String ORC_CERTIFICATE_TWS_14KT = "ORC_CERTIFICATE_TWS_14KT";
|
||||
public static final String ORC_CERTIFICATE_TWS_16KT = "ORC_CERTIFICATE_TWS_16KT";
|
||||
public static final String ORC_CERTIFICATE_TWS_20KT = "ORC_CERTIFICATE_TWS_20KT";
|
||||
|
||||
public static final String ORC_CERTIFICATE_R_PERDICTION = "ORC_CERTIFICATE_R{0}_PREDICTION";
|
||||
public static final String ORC_CERTIFICATE_R52_PREDICTION = "ORC_CERTIFICATE_R52_PREDICTION";
|
||||
public static final String ORC_CERTIFICATE_R60_PREDICTION = "ORC_CERTIFICATE_R60_PREDICTION";
|
||||
public static final String ORC_CERTIFICATE_R75_PREDICTION = "ORC_CERTIFICATE_R75_PREDICTION";
|
||||
@@ -43,6 +49,8 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
|
||||
public static final String ORC_CERTIFICATE_R120_PREDICTION = "ORC_CERTIFICATE_R120_PREDICTION";
|
||||
public static final String ORC_CERTIFICATE_R135_PREDICTION = "ORC_CERTIFICATE_R135_PREDICTION";
|
||||
public static final String ORC_CERTIFICATE_R150_PREDICTION = "ORC_CERTIFICATE_R150_PREDICTION";
|
||||
public static final String ORC_CERTIFICATE_TRUE_WIND_SPEEDS_IN_KNOTS = "trueWindSpeedsInKnots";
|
||||
public static final String ORC_CERTIFICATE_TRUE_WIND_ANGLES_IN_TRUE_DEGREES = "trueWindAnglesInTrueDegrees";
|
||||
|
||||
@Override
|
||||
public JSONObject serialize(ORCCertificate certificate) {
|
||||
@@ -54,8 +62,8 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
|
||||
result.put(ORC_CERTIFICATE_GPH, certificate.getGPHInSecondsToTheMile());
|
||||
result.put(ORC_CERTIFICATE_CDL, certificate.getCDL());
|
||||
result.put(ORC_CERTIFICATE_LENGTH, certificate.getLengthOverAll().getMeters());
|
||||
result.put(ORC_CERTIFICATE_ISSUE_DATE, certificate.getIssueDate()==null?null:certificate.getIssueDate().asMillis());
|
||||
|
||||
result.put(ORC_CERTIFICATE_ISSUE_DATE,
|
||||
certificate.getIssueDate() == null ? null : certificate.getIssueDate().asMillis());
|
||||
JSONObject beatAngles = new JSONObject();
|
||||
JSONObject runAngles = new JSONObject();
|
||||
JSONObject beatAllowances = new JSONObject();
|
||||
@@ -67,7 +75,7 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
|
||||
JSONObject longDistancePredictions = new JSONObject();
|
||||
JSONObject nonSpinnakerPredictions = new JSONObject();
|
||||
JSONObject velocityPredictionsPerTrueWindSpeedAndAngle = new JSONObject();
|
||||
for (Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
for (Speed tws : certificate.getTrueWindSpeeds()) {
|
||||
String keyTWS = speedToKnotsString(tws);
|
||||
JSONObject velocityPredictionsPerTrueWindAngle = new JSONObject();
|
||||
beatAngles.put(keyTWS, certificate.getBeatAngles().get(tws).getDegrees());
|
||||
@@ -80,13 +88,13 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
|
||||
circularRandomPredictions.put(keyTWS, certificate.getCircularRandomSpeedPredictions().get(tws).getKnots());
|
||||
longDistancePredictions.put(keyTWS, certificate.getLongDistanceSpeedPredictions().get(tws).getKnots());
|
||||
nonSpinnakerPredictions.put(keyTWS, certificate.getNonSpinnakerSpeedPredictions().get(tws).getKnots());
|
||||
for (Bearing twa : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES) {
|
||||
for (Bearing twa : certificate.getTrueWindAngles()) {
|
||||
String keyTWA = bearingToDegreeString(twa);
|
||||
velocityPredictionsPerTrueWindAngle.put(keyTWA, certificate.getVelocityPredictionPerTrueWindSpeedAndAngle().get(tws).get(twa).getKnots());
|
||||
velocityPredictionsPerTrueWindAngle.put(keyTWA,
|
||||
certificate.getVelocityPredictionPerTrueWindSpeedAndAngle().get(tws).get(twa).getKnots());
|
||||
}
|
||||
velocityPredictionsPerTrueWindSpeedAndAngle.put(keyTWS, velocityPredictionsPerTrueWindAngle);
|
||||
}
|
||||
|
||||
result.put(ORC_CERTIFICATE_BEAT_ANGLES, beatAngles);
|
||||
result.put(ORC_CERTIFICATE_RUN_ANGLES, runAngles);
|
||||
result.put(ORC_CERTIFICATE_BEAT_ALLOWANCES, beatAllowances);
|
||||
@@ -98,47 +106,70 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
|
||||
result.put(ORC_CERTIFICATE_CIRCULAR_RANDOM_SPEED_PREDICTIONS, circularRandomPredictions);
|
||||
result.put(ORC_CERTIFICATE_NON_SPINNAKER_SPEED_PREDICTIONS, nonSpinnakerPredictions);
|
||||
result.put(ORC_CERTIFICATE_TWA_SPEED_PREDICTIONS, velocityPredictionsPerTrueWindSpeedAndAngle);
|
||||
if (certificate.getTrueWindAngles() != ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES) {
|
||||
result.put(ORC_CERTIFICATE_TRUE_WIND_ANGLES_IN_TRUE_DEGREES, convertObjectsToJsonArrayOfDoubles(twa->twa.getDegrees(), certificate.getTrueWindAngles()));
|
||||
}
|
||||
if (certificate.getTrueWindSpeeds() != ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||
result.put(ORC_CERTIFICATE_TRUE_WIND_SPEEDS_IN_KNOTS, convertObjectsToJsonArrayOfDoubles(tws->tws.getKnots(), certificate.getTrueWindSpeeds()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private final <T> JSONArray convertObjectsToJsonArrayOfDoubles(Function<T, Double> converterToDouble, T... objects) {
|
||||
final JSONArray jsonArray = new JSONArray();
|
||||
for (T t : objects) {
|
||||
jsonArray.add(converterToDouble.apply(t));
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
public static String speedToKnotsString(Speed speed) {
|
||||
String result = null;
|
||||
if (speed.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0])) {
|
||||
if (speed.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0])) {
|
||||
result = ORC_CERTIFICATE_TWS_6KT;
|
||||
} else if (speed.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[1])) {
|
||||
} else if (speed.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[1])) {
|
||||
result = ORC_CERTIFICATE_TWS_8KT;
|
||||
} else if (speed.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[2])) {
|
||||
} else if (speed.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[2])) {
|
||||
result = ORC_CERTIFICATE_TWS_10KT;
|
||||
} else if (speed.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[3])) {
|
||||
} else if (speed.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[3])) {
|
||||
result = ORC_CERTIFICATE_TWS_12KT;
|
||||
} else if (speed.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[4])) {
|
||||
} else if (speed.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[4])) {
|
||||
result = ORC_CERTIFICATE_TWS_14KT;
|
||||
} else if (speed.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[5])) {
|
||||
} else if (speed.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[5])) {
|
||||
result = ORC_CERTIFICATE_TWS_16KT;
|
||||
} else if (speed.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[6])) {
|
||||
} else if (speed.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[6])) {
|
||||
result = ORC_CERTIFICATE_TWS_20KT;
|
||||
} else {
|
||||
String speedKnots = String.valueOf(speed.getKnots());
|
||||
speedKnots = speedKnots.replace(".", "P");
|
||||
result = MessageFormat.format(ORC_CERTIFICATE_TWS_KNOTS, speedKnots);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String bearingToDegreeString(Bearing bearing) {
|
||||
String result = null;
|
||||
if (bearing.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES[0])) {
|
||||
if (bearing.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES[0])) {
|
||||
result = ORC_CERTIFICATE_R52_PREDICTION;
|
||||
} else if (bearing.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES[1])) {
|
||||
} else if (bearing.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES[1])) {
|
||||
result = ORC_CERTIFICATE_R60_PREDICTION;
|
||||
} else if (bearing.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES[2])) {
|
||||
} else if (bearing.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES[2])) {
|
||||
result = ORC_CERTIFICATE_R75_PREDICTION;
|
||||
} else if (bearing.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES[3])) {
|
||||
} else if (bearing.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES[3])) {
|
||||
result = ORC_CERTIFICATE_R90_PREDICTION;
|
||||
} else if (bearing.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES[4])) {
|
||||
} else if (bearing.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES[4])) {
|
||||
result = ORC_CERTIFICATE_R110_PREDICTION;
|
||||
} else if (bearing.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES[5])) {
|
||||
} else if (bearing.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES[5])) {
|
||||
result = ORC_CERTIFICATE_R120_PREDICTION;
|
||||
} else if (bearing.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES[6])) {
|
||||
} else if (bearing.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES[6])) {
|
||||
result = ORC_CERTIFICATE_R135_PREDICTION;
|
||||
} else if (bearing.equals(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES[7])) {
|
||||
} else if (bearing.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES[7])) {
|
||||
result = ORC_CERTIFICATE_R150_PREDICTION;
|
||||
} else {
|
||||
String angleDegress = String.valueOf(bearing.getDegrees());
|
||||
angleDegress = angleDegress.replace(".", "P");
|
||||
result = MessageFormat.format(ORC_CERTIFICATE_R_PERDICTION, String.valueOf(angleDegress));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
{
|
||||
"rms":[
|
||||
{
|
||||
"NatAuth":"GR",
|
||||
"BIN":"GR317",
|
||||
"CertNo":"A00073",
|
||||
"RefNo":"N\/A",
|
||||
"SailNo":"GRE-317",
|
||||
"YachtName":"AVANTES",
|
||||
"Class":"FIRST 31.7",
|
||||
"Builder":"BENETEAU",
|
||||
"Designer":"FINOT",
|
||||
"Address3":"I.O. HALKIDAS",
|
||||
"C_Type":"INTL",
|
||||
"Family":"ORC",
|
||||
"Division":"C",
|
||||
"IssueDate":"2020-02-05T12:54:23.484Z",
|
||||
"Age_Year":1998,
|
||||
"CrewWT":550,
|
||||
"LOA":9.49,
|
||||
"IMSL":9.003,
|
||||
"Draft":1.94,
|
||||
"MB":3.216,
|
||||
"Dspl_Measurement":3936,
|
||||
"Stability_Index":103.7,
|
||||
"Dynamic_Allowance":0.31,
|
||||
"GPH":678,
|
||||
"TMF_Inshore":0.9229,
|
||||
"ILCWA":731.4,
|
||||
"TMF_Offshore":0.9145,
|
||||
"OSN":656.1,
|
||||
"CDL":8.155,
|
||||
"TN_Offshore_Low":0.8578,
|
||||
"TN_Offshore_Medium":1.1292,
|
||||
"TN_Offshore_High":1.2751,
|
||||
"TN_Inshore_Low":0.6639,
|
||||
"TN_Inshore_Medium":0.9158,
|
||||
"TN_Inshore_High":1.0666,
|
||||
"TND_Offshore_Low":786.9,
|
||||
"TND_Offshore_Medium":597.8,
|
||||
"TND_Offshore_High":529.4,
|
||||
"TND_Inshore_Low":1016.7,
|
||||
"TND_Inshore_Medium":737.1,
|
||||
"TND_Inshore_High":632.9,
|
||||
"OSN_Jibs":688.6,
|
||||
"TMF_Jibs":0.8713,
|
||||
"Dspl_Sailing":4660,
|
||||
"WSS":22.41,
|
||||
"Area_Main":27.04,
|
||||
"Area_Jib":22.08,
|
||||
"Area_Sym":61.48,
|
||||
"Area_ASym":0,
|
||||
"GPH_Jibs":714.6,
|
||||
"GPH_Jibs_TOT":0.8396,
|
||||
"Allowances":{
|
||||
"WindSpeeds":[
|
||||
6.1,
|
||||
8.2,
|
||||
10.6,
|
||||
12.1,
|
||||
14.9,
|
||||
16.7,
|
||||
20.1
|
||||
],
|
||||
"Beat":[
|
||||
1175.6,
|
||||
968.7,
|
||||
854,
|
||||
780.9,
|
||||
752,
|
||||
744.6,
|
||||
744.9
|
||||
],
|
||||
"Run":[
|
||||
1074.7,
|
||||
847.7,
|
||||
716.4,
|
||||
628.3,
|
||||
566,
|
||||
526.9,
|
||||
480.1
|
||||
],
|
||||
"BeatAngle":[
|
||||
43.5,
|
||||
41.6,
|
||||
40.5,
|
||||
39.8,
|
||||
39,
|
||||
38.6,
|
||||
39
|
||||
],
|
||||
"GybeAngle":[
|
||||
146,
|
||||
150,
|
||||
153,
|
||||
158,
|
||||
178,
|
||||
180,
|
||||
180
|
||||
],
|
||||
"WL":[
|
||||
1125.2,
|
||||
908.2,
|
||||
785.2,
|
||||
704.6,
|
||||
659,
|
||||
635.8,
|
||||
612.5
|
||||
],
|
||||
"CR":[
|
||||
942.4,
|
||||
757.3,
|
||||
657.2,
|
||||
598.8,
|
||||
563,
|
||||
540.1,
|
||||
512.7
|
||||
],
|
||||
"OC":[
|
||||
1120.1,
|
||||
852,
|
||||
706,
|
||||
616.2,
|
||||
571.7,
|
||||
539.8,
|
||||
487.7
|
||||
],
|
||||
"NS":[
|
||||
1008.9,
|
||||
804,
|
||||
691.6,
|
||||
625.1,
|
||||
584.2,
|
||||
558,
|
||||
527.3
|
||||
],
|
||||
"OL":[
|
||||
1077.4,
|
||||
874.1,
|
||||
761.4,
|
||||
694.6,
|
||||
658.2,
|
||||
638.7,
|
||||
615.2
|
||||
],
|
||||
"R52.7":[
|
||||
767,
|
||||
645,
|
||||
577.3,
|
||||
544,
|
||||
530.1,
|
||||
525.8,
|
||||
525
|
||||
],
|
||||
"R64.4":[
|
||||
725.4,
|
||||
613.2,
|
||||
556.7,
|
||||
530.3,
|
||||
516.8,
|
||||
510.9,
|
||||
508.9
|
||||
],
|
||||
"R75":[
|
||||
697.1,
|
||||
589.3,
|
||||
541.9,
|
||||
519,
|
||||
502.9,
|
||||
490.9,
|
||||
480.5
|
||||
],
|
||||
"R90":[
|
||||
694.3,
|
||||
577.7,
|
||||
526.9,
|
||||
505.5,
|
||||
495.9,
|
||||
481.7,
|
||||
454.3
|
||||
],
|
||||
"R110":[
|
||||
688.6,
|
||||
568.4,
|
||||
520.4,
|
||||
493.9,
|
||||
469.8,
|
||||
450.8,
|
||||
430.3
|
||||
],
|
||||
"R120":[
|
||||
710.9,
|
||||
583.7,
|
||||
526.8,
|
||||
498.8,
|
||||
473.3,
|
||||
448.4,
|
||||
409.9
|
||||
],
|
||||
"R135":[
|
||||
788.3,
|
||||
640.5,
|
||||
556.1,
|
||||
517.8,
|
||||
492.5,
|
||||
466.8,
|
||||
416.9
|
||||
],
|
||||
"R150":[
|
||||
930.8,
|
||||
734.2,
|
||||
621.9,
|
||||
551.9,
|
||||
517.7,
|
||||
494,
|
||||
446.5
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
{
|
||||
"rms": [
|
||||
{
|
||||
"NatAuth": "GRE",
|
||||
"BIN": "GR49735",
|
||||
"CertNo": "000021",
|
||||
"RefNo": "GRE01015829",
|
||||
"SailNo": "GRE-49735",
|
||||
"YachtName": "NEMO",
|
||||
"Class": "PHANTOM 34",
|
||||
"Builder": "Genzel",
|
||||
"Designer": "Streuer",
|
||||
"Address3": "NO RAHON",
|
||||
"C_Type": "CLUB",
|
||||
"Division": "C",
|
||||
"IssueDate": "2019-06-11T21:37:02.000Z",
|
||||
"Age_Year": 1988,
|
||||
"CrewWT": 400,
|
||||
"LOA": 10.3,
|
||||
"IMSL": 8.518,
|
||||
"Draft": 1.777,
|
||||
"MB": 3.15,
|
||||
"Dspl_Measurement": 6386,
|
||||
"Stability_Index": 131.7,
|
||||
"Dynamic_Allowance": 0.702,
|
||||
"GPH": 780.1,
|
||||
"TMF_Inshore": 0.8017,
|
||||
"ILCWA": 842,
|
||||
"TMF_Offshore": 0.798,
|
||||
"OSN": 751.9,
|
||||
"CDL": 7.056,
|
||||
"TN_Offshore_Low": 0.7209,
|
||||
"TN_Offshore_Medium": 0.9908,
|
||||
"TN_Offshore_High": 1.1542,
|
||||
"TN_Inshore_Low": 0.5529,
|
||||
"TN_Inshore_Medium": 0.7913,
|
||||
"TN_Inshore_High": 0.9571,
|
||||
"TND_Offshore_Low": 936.3,
|
||||
"TND_Offshore_Medium": 681.3,
|
||||
"TND_Offshore_High": 584.8,
|
||||
"TND_Inshore_Low": 1220.8,
|
||||
"TND_Inshore_Medium": 853,
|
||||
"TND_Inshore_High": 705.3,
|
||||
"Double_Handed_TOD": null,
|
||||
"Double_Handed_TOT": null,
|
||||
"OSN_Jibs": 751.9,
|
||||
"TMF_Jibs": 0.798,
|
||||
"Dspl_Sailing": 7116,
|
||||
"WSS": 27.39,
|
||||
"Area_Main": 24.97,
|
||||
"Area_Jib": 35.81,
|
||||
"Area_Sym": 0,
|
||||
"Area_ASym": 0,
|
||||
"GPH_Jibs": 780.1,
|
||||
"GPH_Jibs_TOT": 0.7691,
|
||||
"GPH_DH": 0,
|
||||
"GPH_DH_TOT": 0,
|
||||
"Allowances": {
|
||||
"Beat": [
|
||||
1363.4,
|
||||
1113.9,
|
||||
981.7,
|
||||
892.9,
|
||||
841.8,
|
||||
822.5,
|
||||
818.8
|
||||
],
|
||||
"Run": [
|
||||
1368.9,
|
||||
1036.8,
|
||||
849.8,
|
||||
734.8,
|
||||
653.5,
|
||||
592.3,
|
||||
531
|
||||
],
|
||||
"BeatAngle": [
|
||||
45.9,
|
||||
43.6,
|
||||
42.7,
|
||||
43.1,
|
||||
43.2,
|
||||
42.8,
|
||||
43
|
||||
],
|
||||
"GybeAngle": [
|
||||
167.1,
|
||||
167.8,
|
||||
168.9,
|
||||
170,
|
||||
170.1,
|
||||
171.4,
|
||||
175.4
|
||||
],
|
||||
"WL": [
|
||||
1366.2,
|
||||
1075.4,
|
||||
915.7,
|
||||
813.8,
|
||||
747.7,
|
||||
707.4,
|
||||
674.9
|
||||
],
|
||||
"CR": [
|
||||
1111.7,
|
||||
882.2,
|
||||
754.7,
|
||||
678,
|
||||
630.1,
|
||||
599.8,
|
||||
567.2
|
||||
],
|
||||
"OC": [
|
||||
1366.4,
|
||||
1009.6,
|
||||
820.8,
|
||||
702.4,
|
||||
636.3,
|
||||
593.1,
|
||||
536.8
|
||||
],
|
||||
"NS": [
|
||||
1111.7,
|
||||
882.2,
|
||||
754.7,
|
||||
678,
|
||||
630.1,
|
||||
599.8,
|
||||
567.2
|
||||
],
|
||||
"OL": [
|
||||
1299.8,
|
||||
1037,
|
||||
892.2,
|
||||
800.5,
|
||||
743.6,
|
||||
712.9,
|
||||
687.5
|
||||
],
|
||||
"R52": [
|
||||
866.3,
|
||||
724.9,
|
||||
642.2,
|
||||
586.7,
|
||||
561.7,
|
||||
553.2,
|
||||
549.9
|
||||
],
|
||||
"R60": [
|
||||
806.5,
|
||||
682.9,
|
||||
605,
|
||||
562.4,
|
||||
542.9,
|
||||
534.7,
|
||||
530.6
|
||||
],
|
||||
"R75": [
|
||||
763.8,
|
||||
648.6,
|
||||
578.1,
|
||||
545.2,
|
||||
527.6,
|
||||
516,
|
||||
505.8
|
||||
],
|
||||
"R90": [
|
||||
770.4,
|
||||
649.9,
|
||||
575.9,
|
||||
541.5,
|
||||
522.6,
|
||||
506.7,
|
||||
486.6
|
||||
],
|
||||
"R110": [
|
||||
841.2,
|
||||
690.9,
|
||||
599.3,
|
||||
550.4,
|
||||
525.7,
|
||||
508.1,
|
||||
476.4
|
||||
],
|
||||
"R120": [
|
||||
899.7,
|
||||
728.7,
|
||||
628.2,
|
||||
564.5,
|
||||
533.7,
|
||||
514.4,
|
||||
481.6
|
||||
],
|
||||
"R135": [
|
||||
1027.7,
|
||||
808.1,
|
||||
690.6,
|
||||
609.2,
|
||||
558.7,
|
||||
532,
|
||||
498
|
||||
],
|
||||
"R150": [
|
||||
1205.8,
|
||||
924.1,
|
||||
770,
|
||||
674,
|
||||
602.7,
|
||||
557.4,
|
||||
514.8
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.sap.sailing.server.gateway.deserialization.test.racelog;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.orc.ORCCertificatesCollection;
|
||||
import com.sap.sailing.domain.orc.ORCCertificatesImporter;
|
||||
import com.sap.sailing.server.gateway.deserialization.racelog.impl.ORCCertificateJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.impl.ORCCertificateJsonSerializer;
|
||||
import com.sap.sse.common.Bearing;
|
||||
import com.sap.sse.common.Speed;
|
||||
import com.sap.sse.common.impl.DegreeBearingImpl;
|
||||
|
||||
public class ORCCertificateJsonDeserializerTest {
|
||||
private ORCCertificateJsonSerializer serializer;
|
||||
private ORCCertificateJsonDeserializer deserializer;
|
||||
private static final String RESOURCES = "resources/rms/";
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
deserializer = new ORCCertificateJsonDeserializer();
|
||||
serializer = new ORCCertificateJsonSerializer();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewFormateOrcCertificateDeserializer() throws FileNotFoundException, IOException, ParseException {
|
||||
File fileGER = new File(RESOURCES + "newFormatCertificate.json");
|
||||
ORCCertificatesCollection importer = ORCCertificatesImporter.INSTANCE.read(new FileInputStream(fileGER));
|
||||
Iterator<ORCCertificate> iterator = importer.getCertificates().iterator();
|
||||
assertTrue(iterator.hasNext());
|
||||
ORCCertificate certificate = iterator.next();
|
||||
final Speed[] expectedTrueWindSpeeds = { new KnotSpeedImpl(6.1), new KnotSpeedImpl(8.2), new KnotSpeedImpl(10.6), new KnotSpeedImpl(12.1), new KnotSpeedImpl(14.9), new KnotSpeedImpl(16.7), new KnotSpeedImpl(20.1) };
|
||||
assertTrue(Arrays.equals(expectedTrueWindSpeeds, certificate.getTrueWindSpeeds()));
|
||||
final Bearing[] expectedTrueWindAngles = { new DegreeBearingImpl(52.7), new DegreeBearingImpl(64.4), new DegreeBearingImpl(75), new DegreeBearingImpl(90),
|
||||
new DegreeBearingImpl(110), new DegreeBearingImpl(120), new DegreeBearingImpl(135), new DegreeBearingImpl(150) };
|
||||
assertTrue(Arrays.equals(expectedTrueWindAngles, certificate.getTrueWindAngles()));
|
||||
JSONObject serializedCertificate = serializer.serialize(certificate);
|
||||
assertNotNull(serializedCertificate);
|
||||
ORCCertificate certificateAfterDeserialize = deserializer.deserialize(serializedCertificate);
|
||||
assertEquals(certificate.getId(), certificateAfterDeserialize.getId());
|
||||
assertTrue(Arrays.equals(expectedTrueWindSpeeds, certificateAfterDeserialize.getTrueWindSpeeds()));
|
||||
assertTrue(Arrays.equals(expectedTrueWindAngles, certificateAfterDeserialize.getTrueWindAngles()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrcCertificateOldFormatDeserializer() throws IOException, ParseException {
|
||||
File fileGER = new File(RESOURCES + "oldFormatCertificate.json");
|
||||
ORCCertificatesCollection importer = ORCCertificatesImporter.INSTANCE.read(new FileInputStream(fileGER));
|
||||
Iterator<ORCCertificate> iterator = importer.getCertificates().iterator();
|
||||
assertTrue(iterator.hasNext());
|
||||
ORCCertificate certificate = iterator.next();
|
||||
assertTrue(Arrays.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS, certificate.getTrueWindSpeeds()));
|
||||
assertTrue(Arrays.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES, certificate.getTrueWindAngles()));
|
||||
JSONObject serializedCertificate = serializer.serialize(certificate);
|
||||
assertNotNull(serializedCertificate);
|
||||
ORCCertificate certificateAfterDeserialize = deserializer.deserialize(serializedCertificate);
|
||||
assertEquals(certificate.getId(), certificateAfterDeserialize.getId());
|
||||
assertTrue(Arrays.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS, certificateAfterDeserialize.getTrueWindSpeeds()));
|
||||
assertTrue(Arrays.equals(ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES, certificateAfterDeserialize.getTrueWindAngles()));
|
||||
}
|
||||
}
|
||||
+4
@@ -185,6 +185,10 @@ public abstract class AbstractLeaderboardsResource extends AbstractSailingServer
|
||||
? MillisecondsTimePoint.now().minus(trackedRace.getDelayToLiveInMillis())
|
||||
: new MillisecondsTimePoint(resultTimePoint)));
|
||||
trackedRaceInfo.put("delayToLiveInMillis", trackedRace.getDelayToLiveInMillis());
|
||||
if (trackedRace.getStatus() != null) {
|
||||
trackedRaceInfo.put("status", trackedRace.getStatus().getStatus().toString());
|
||||
trackedRaceInfo.put("loadingProgress", trackedRace.getStatus().getLoadingProgress());
|
||||
}
|
||||
}
|
||||
fleetJson.put("trackedRace", trackedRaceInfo);
|
||||
}
|
||||
|
||||
-1
@@ -491,7 +491,6 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource {
|
||||
* If {@code raceColumnNames} is empty or {@code null}, return the names of all {@link raceColumnsOfLeaderboard};
|
||||
* otherwise return those race column names from {@code raceColumnsOfLeaderboard} that are also in
|
||||
* {@code raceColumnNames}.
|
||||
* @param leaderboard TODO
|
||||
* @param showOnlyActiveRacesForCompetitorIds
|
||||
* {@code null}, or specifies zero or more competitor IDs, requesting that the result contained the race
|
||||
* column holding that competitor's "active" race at the time requested; see also the
|
||||
|
||||
Reference in New Issue
Block a user