mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-19 12:15:28 +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.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||||
import com.sap.sse.common.Bearing;
|
import com.sap.sse.common.Bearing;
|
||||||
import com.sap.sse.common.Distance;
|
import com.sap.sse.common.Distance;
|
||||||
import com.sap.sse.common.Duration;
|
import com.sap.sse.common.Duration;
|
||||||
import com.sap.sse.common.Speed;
|
import com.sap.sse.common.Speed;
|
||||||
import com.sap.sse.common.TimePoint;
|
import com.sap.sse.common.TimePoint;
|
||||||
import com.sap.sse.common.WithID;
|
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
|
* 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>
|
* <p>
|
||||||
* An ORC certificate is issued by the "Member National Authorities" of World Sailing and are available for insight at
|
* 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
|
* https://www.orc.org/index.asp . Other information about the whole scoring system and different variants are available
|
||||||
* too.
|
* too.
|
||||||
* <p>
|
* <p>
|
||||||
* One implementing class provides all necessary functionalities to score the Competitors with a choosen
|
* 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
|
* The {@link WithID} interface is to be implemented such that a {@link String} is produced as the ID that contains the
|
||||||
* contains the concatenation (without intermediate white space) of the {@code NatAuth}, the {@code CertNo}
|
* concatenation (without intermediate white space) of the {@code NatAuth}, the {@code CertNo} and the {@code BIN}
|
||||||
* and the {@code BIN} fields, as provided as single fields in the JSON representation, and as provided
|
* fields, as provided as single fields in the JSON representation, and as provided in the concatenated form in the
|
||||||
* in the concatenated form in the {@code NATCERTN.FILE_ID} column in the RMS format.
|
* {@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)
|
* @author Daniel Lisunkin (i505543)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface ORCCertificate extends WithID, Serializable {
|
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
|
* 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
|
* {@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();
|
Map<Speed, Map<Bearing, Speed>> getVelocityPredictionPerTrueWindSpeedAndAngle();
|
||||||
|
|
||||||
String getBoatName();
|
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.Collections;
|
||||||
import java.util.Map;
|
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.impl.NauticalMileDistance;
|
||||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||||
import com.sap.sse.common.Bearing;
|
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.Speed;
|
||||||
import com.sap.sse.common.TimePoint;
|
import com.sap.sse.common.TimePoint;
|
||||||
import com.sap.sse.common.Util;
|
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
|
* 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;
|
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);
|
public final static Distance NAUTICAL_MILE = new NauticalMileDistance(1);
|
||||||
|
|
||||||
private final String sailNumber;
|
private final String sailNumber;
|
||||||
@@ -60,7 +36,16 @@ public class ORCCertificateImpl implements ORCCertificate {
|
|||||||
private final Double cdl;
|
private final Double cdl;
|
||||||
private final TimePoint issueDate;
|
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;
|
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> circularRandomSpeedPredictionPerTrueWindSpeed;
|
||||||
|
|
||||||
private final Map<Speed, Speed> nonSpinnakerSpeedPredictionPerTrueWindSpeed;
|
private final Map<Speed, Speed> nonSpinnakerSpeedPredictionPerTrueWindSpeed;
|
||||||
|
private final Speed[] allowancesTrueWindSpeeds;
|
||||||
public ORCCertificateImpl(String idConsistingOfNatAuthCertNoAndBIN,
|
private final Bearing[] allowancesTrueWindAngles;
|
||||||
String sailnumber, String boatName, String boatClassName,
|
|
||||||
Distance length, Duration gph,
|
/**
|
||||||
Double cdl, TimePoint issueDate,
|
* Can be used to specify non-default TWS/TWA values for the time allowances / speed predictions.
|
||||||
Map<Speed, Map<Bearing, Speed>> velocityPredictionsPerTrueWindSpeedAndAngle,
|
*
|
||||||
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
* @param allowancesTrueWindSpeeds
|
||||||
Map<Speed, Duration> beatAllowancePerTrueWindSpeed, Map<Speed, Bearing> runAngles,
|
* a monotonously-increasing sequence of true wind speed (TWS) values for the matrix of time allowances /
|
||||||
Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed,
|
* 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, Duration> runAllowancePerTrueWindSpeed,
|
||||||
Map<Speed, Speed> windwardLeewardSpeedPredictionsPerTrueWindSpeed,
|
Map<Speed, Speed> windwardLeewardSpeedPredictionsPerTrueWindSpeed,
|
||||||
Map<Speed, Speed> longDistanceSpeedPredictionsPerTrueWindSpeed,
|
Map<Speed, Speed> longDistanceSpeedPredictionsPerTrueWindSpeed,
|
||||||
Map<Speed, Speed> circularRandomSpeedPredictionsPerTrueWindSpeed,
|
Map<Speed, Speed> circularRandomSpeedPredictionsPerTrueWindSpeed,
|
||||||
Map<Speed, Speed> nonSpinnakerSpeedPredictionsPerTrueWindSpeed) {
|
Map<Speed, Speed> nonSpinnakerSpeedPredictionsPerTrueWindSpeed) {
|
||||||
|
this.allowancesTrueWindAngles = allowancesTrueWindAngles;
|
||||||
|
this.allowancesTrueWindSpeeds = allowancesTrueWindSpeeds;
|
||||||
this.idConsistingOfNatAuthCertNoAndBIN = idConsistingOfNatAuthCertNoAndBIN;
|
this.idConsistingOfNatAuthCertNoAndBIN = idConsistingOfNatAuthCertNoAndBIN;
|
||||||
this.sailNumber = sailnumber;
|
this.sailNumber = sailnumber;
|
||||||
this.boatName = boatName;
|
this.boatName = boatName;
|
||||||
@@ -145,6 +144,32 @@ public class ORCCertificateImpl implements ORCCertificate {
|
|||||||
this.circularRandomSpeedPredictionPerTrueWindSpeed = Collections.unmodifiableMap(circularRandomSpeedPredictionsPerTrueWindSpeed);
|
this.circularRandomSpeedPredictionPerTrueWindSpeed = Collections.unmodifiableMap(circularRandomSpeedPredictionsPerTrueWindSpeed);
|
||||||
this.nonSpinnakerSpeedPredictionPerTrueWindSpeed = Collections.unmodifiableMap(nonSpinnakerSpeedPredictionsPerTrueWindSpeed);
|
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
|
@Override
|
||||||
public String getId() {
|
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 "+
|
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);
|
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);
|
assertNotNull(moana);
|
||||||
assertEquals(539.1, swan .getGPHInSecondsToTheMile(), 0.0000001);
|
assertEquals(539.1, swan .getGPHInSecondsToTheMile(), 0.0000001);
|
||||||
assertEquals(490.4, moana.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(862.2, swan .getWindwardLeewardSpeedPrediction().get(ORCCertificate.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(788.2, moana.getWindwardLeewardSpeedPrediction().get(ORCCertificate.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(861.0, swan .getLongDistanceSpeedPredictions().get(ORCCertificate.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(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);
|
assertNotNull(moana);
|
||||||
assertEquals(539.1, swan .getGPHInSecondsToTheMile(), 0.0000001);
|
assertEquals(539.1, swan .getGPHInSecondsToTheMile(), 0.0000001);
|
||||||
assertEquals(490.4, moana.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(862.2, swan .getWindwardLeewardSpeedPrediction().get(ORCCertificate.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(788.2, moana.getWindwardLeewardSpeedPrediction().get(ORCCertificate.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(861.0, swan .getLongDistanceSpeedPredictions().get(ORCCertificate.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(787.2, moana.getLongDistanceSpeedPredictions().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificateImpl.NAUTICAL_MILE).asSeconds(), 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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.common.orc.impl.ORCPerformanceCurveLegImpl;
|
||||||
import com.sap.sailing.domain.orc.impl.ORCCertificatesJsonImporter;
|
import com.sap.sailing.domain.orc.impl.ORCCertificatesJsonImporter;
|
||||||
import com.sap.sailing.domain.orc.impl.ORCPerformanceCurveImpl;
|
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.Duration;
|
||||||
|
import com.sap.sse.common.Speed;
|
||||||
import com.sap.sse.common.Util;
|
import com.sap.sse.common.Util;
|
||||||
import com.sap.sse.common.impl.DegreeBearingImpl;
|
import com.sap.sse.common.impl.DegreeBearingImpl;
|
||||||
|
|
||||||
@@ -49,6 +52,7 @@ public class TestORCPerformanceCurve {
|
|||||||
|
|
||||||
private static ORCPerformanceCurveCourse alturaCourse;
|
private static ORCPerformanceCurveCourse alturaCourse;
|
||||||
private static ORCCertificatesCollection importerLocal;
|
private static ORCCertificatesCollection importerLocal;
|
||||||
|
private static ORCCertificatesCollection importerWithSpecificBins;
|
||||||
private static ORCCertificatesCollection importerOnline;
|
private static ORCCertificatesCollection importerOnline;
|
||||||
|
|
||||||
private static final String RESOURCES = "resources/orc/";
|
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
|
@BeforeClass
|
||||||
public static void initialize() throws IOException, ParseException {
|
public static void initialize() throws IOException, ParseException {
|
||||||
List<ORCPerformanceCurveLeg> legs = new ArrayList<>();
|
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.03), new DegreeBearingImpl(165)));
|
||||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.17), new DegreeBearingImpl(180)));
|
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
|
alturaCourse = new ORCPerformanceCurveCourseImpl(legs); //this course is the same course as seen in the Altura "IMS Explanation" sheet
|
||||||
|
|
||||||
// Local File:
|
// Local File:
|
||||||
File fileGER = new File(RESOURCES + "GER2019.json");
|
File fileGER = new File(RESOURCES + "GER2019.json");
|
||||||
importerLocal = new ORCCertificatesJsonImporter().read(new FileInputStream(fileGER));
|
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:
|
// Online File:
|
||||||
importerOnline = new ORCCertificatesJsonImporter().read(new URL("https://data.orc.org/public/WPub.dll?action=DownRMS&CountryId=GER&ext=json").openStream());
|
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 ORCPerformanceCurveCourse course = new ORCPerformanceCurveCourseImpl(Arrays.asList(new ORCPerformanceCurveLegImpl(ORCCertificateImpl.NAUTICAL_MILE, new DegreeBearingImpl(twa))));
|
||||||
final ORCPerformanceCurve performanceCurve = new ORCPerformanceCurveImpl(certificate, course);
|
final ORCPerformanceCurve performanceCurve = new ORCPerformanceCurveImpl(certificate, course);
|
||||||
for (int i=0; i<expectedAllowancesPerTrueWindSpeed.length; i++) {
|
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
|
@Test
|
||||||
public void testSimpleConstructedCourse() throws FunctionEvaluationException {
|
public void testSimpleConstructedCourse() throws FunctionEvaluationException {
|
||||||
ORCCertificateImpl certificate = (ORCCertificateImpl) importerLocal.getCertificateById("GER140772GER5549");
|
ORCCertificate certificate = (ORCCertificate) importerLocal.getCertificateById("GER140772GER5549");
|
||||||
List<ORCPerformanceCurveLeg> legs = new ArrayList<>();
|
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(0)));
|
||||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.0), new DegreeBearingImpl(30)));
|
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 {
|
private void testAllowancePerCourse(ORCPerformanceCurve performanceCurve, double... allowancePerNauticalMileInSeconds) throws ArgumentOutsideDomainException {
|
||||||
for (int i=0; i<allowancePerNauticalMileInSeconds.length; i++) {
|
for (int i=0; i<allowancePerNauticalMileInSeconds.length; i++) {
|
||||||
assertEquals(allowancePerNauticalMileInSeconds[i]*performanceCurve.getCourse().getTotalLength().getNauticalMiles(),
|
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
|
@Test
|
||||||
public void testPerformanceCurveInversion() throws MaxIterationsExceededException, FunctionEvaluationException {
|
public void testPerformanceCurveInversion() throws MaxIterationsExceededException, FunctionEvaluationException {
|
||||||
Double accuracy = 0.1;
|
Double accuracy = 0.1;
|
||||||
ORCCertificateImpl certificate = (ORCCertificateImpl) importerLocal.getCertificateById("GER140772GER5549");
|
ORCCertificate certificate = (ORCCertificate) importerLocal.getCertificateById("GER140772GER5549");
|
||||||
ORCPerformanceCurveImpl performanceCurve = (ORCPerformanceCurveImpl) new ORCPerformanceCurveImpl(certificate, alturaCourse);
|
ORCPerformanceCurveImpl performanceCurve = (ORCPerformanceCurveImpl) new ORCPerformanceCurveImpl(certificate, alturaCourse);
|
||||||
testBackwardForward(accuracy, performanceCurve, 11.5);
|
testBackwardForward(accuracy, performanceCurve, 11.5);
|
||||||
testBackwardForward(accuracy, performanceCurve, 17.23);
|
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)
|
// Tests for the calculations with a more complex course which contains some special leg types. (circular random or other)
|
||||||
@Test
|
@Test
|
||||||
public void testComplexCourseImpliedWind() throws FunctionEvaluationException, MaxIterationsExceededException {
|
public void testComplexCourseImpliedWind() throws FunctionEvaluationException, MaxIterationsExceededException {
|
||||||
@@ -259,25 +297,28 @@ public class TestORCPerformanceCurve {
|
|||||||
list.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1), new DegreeBearingImpl(180)));
|
list.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1), new DegreeBearingImpl(180)));
|
||||||
ORCPerformanceCurveCourse complexCourse = new ORCPerformanceCurveCourseImpl(list);
|
ORCPerformanceCurveCourse complexCourse = new ORCPerformanceCurveCourseImpl(list);
|
||||||
|
|
||||||
double accuracy = 0.0001;
|
final double accuracy = 0.0001;
|
||||||
ORCCertificate certificateMoana = importerLocal.getCertificateById("GER140772GER5549");
|
ORCCertificate certificateMoana = importerLocal.getCertificateById("GER140772GER5549");
|
||||||
ORCCertificate certificateMilan = importerLocal.getCertificateById("GER166844GER7323");
|
ORCCertificate certificateMilan = importerLocal.getCertificateById("GER166844GER7323");
|
||||||
ORCCertificate certificateTutima = importerLocal.getCertificateById("GER140618GER5609");
|
ORCCertificate certificateTutima = importerLocal.getCertificateById("GER140618GER5609");
|
||||||
ORCCertificate certificateBank = importerLocal.getCertificateById("GER140755GER5555");
|
ORCCertificate certificateBank = importerLocal.getCertificateById("GER140755GER5555");
|
||||||
ORCCertificate certificateHaspa = importerLocal.getCertificateById("GER141411GER6300");
|
ORCCertificate certificateHaspa = importerLocal.getCertificateById("GER141411GER6300");
|
||||||
ORCCertificate certificateHalbtrocken = importerLocal.getCertificateById("GER141432GER5564");
|
ORCCertificate certificateHalbtrocken = importerLocal.getCertificateById("GER141432GER5564");
|
||||||
|
ORCCertificate certificateWithSpecificBins=importerWithSpecificBins.getCertificateById("GRA00073GR317");
|
||||||
ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, complexCourse);
|
ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, complexCourse);
|
ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, complexCourse);
|
ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveBank = new ORCPerformanceCurveImpl(certificateBank, complexCourse);
|
ORCPerformanceCurve performanceCurveBank = new ORCPerformanceCurveImpl(certificateBank, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveHaspa = new ORCPerformanceCurveImpl(certificateHaspa, complexCourse);
|
ORCPerformanceCurve performanceCurveHaspa = new ORCPerformanceCurveImpl(certificateHaspa, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveHalbtrocken = new ORCPerformanceCurveImpl(certificateHalbtrocken, 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.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.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(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(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(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(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
|
@Test
|
||||||
@@ -298,12 +339,14 @@ public class TestORCPerformanceCurve {
|
|||||||
ORCCertificate certificateBank = importerLocal.getCertificateById("GER140755GER5555");
|
ORCCertificate certificateBank = importerLocal.getCertificateById("GER140755GER5555");
|
||||||
ORCCertificate certificateHaspa = importerLocal.getCertificateById("GER141411GER6300");
|
ORCCertificate certificateHaspa = importerLocal.getCertificateById("GER141411GER6300");
|
||||||
ORCCertificate certificateHalbtrocken = importerLocal.getCertificateById("GER141432GER5564");
|
ORCCertificate certificateHalbtrocken = importerLocal.getCertificateById("GER141432GER5564");
|
||||||
|
ORCCertificate certificateWithSpecificBins=importerWithSpecificBins.getCertificateById("GRA00073GR317");
|
||||||
ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, complexCourse);
|
ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, complexCourse);
|
ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, complexCourse);
|
ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveBank = new ORCPerformanceCurveImpl(certificateBank, complexCourse);
|
ORCPerformanceCurve performanceCurveBank = new ORCPerformanceCurveImpl(certificateBank, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveHaspa = new ORCPerformanceCurveImpl(certificateHaspa, complexCourse);
|
ORCPerformanceCurve performanceCurveHaspa = new ORCPerformanceCurveImpl(certificateHaspa, complexCourse);
|
||||||
ORCPerformanceCurve performanceCurveHalbtrocken = new ORCPerformanceCurveImpl(certificateHalbtrocken, 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.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);
|
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.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(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(), 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;
|
package com.sap.sailing.domain.orc.impl;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
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 javax.xml.bind.DatatypeConverter;
|
||||||
|
|
||||||
import org.json.simple.JSONArray;
|
import org.json.simple.JSONArray;
|
||||||
import org.json.simple.JSONObject;
|
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.impl.MeterDistance;
|
||||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||||
import com.sap.sailing.domain.common.orc.impl.ORCCertificateImpl;
|
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 CIRCULAR_RANDOM = "CR";
|
||||||
private static final String NON_SPINNAKER = "NS";
|
private static final String NON_SPINNAKER = "NS";
|
||||||
private static final String EMPTY_CERT_NO = " ";
|
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;
|
private Map<String, JSONObject> certificateJsonObjectsByCertificateId;
|
||||||
|
|
||||||
@@ -79,18 +91,21 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ORCCertificate getCertificateById(String certificateId) {
|
public ORCCertificate getCertificateById(String certificateId) {
|
||||||
String boatName = null;
|
String boatName = null;
|
||||||
String boatclass = null;
|
String boatclass = null;
|
||||||
Distance length = null;
|
Distance length = null;
|
||||||
Duration gph = null;
|
Duration gph = null;
|
||||||
Double cdl = null;
|
Double cdl = null;
|
||||||
TimePoint issueDate = null;
|
TimePoint issueDate = null;
|
||||||
Map<Speed, Bearing> beatAngles = new HashMap<>();
|
final Map<Speed, Bearing> beatAngles = new HashMap<>();
|
||||||
Map<Speed, Bearing> gybeAngles = new HashMap<>();
|
final Map<Speed, Bearing> gybeAngles = new HashMap<>();
|
||||||
Map<Speed, Map<Bearing, Speed>> velocityPredictionPerTrueWindSpeedAndAngle = new HashMap<>();
|
final Map<Speed, Map<Bearing, Speed>> velocityPredictionPerTrueWindSpeedAndAngle = new HashMap<>();
|
||||||
Map<Bearing, Map<Speed, Duration>> allowanceDurationsPerTrueWindAngleAndSpeed = new HashMap<>(); //per nautical mile
|
final Map<Bearing, Map<Speed, Duration>> allowanceDurationsPerTrueWindAngleAndSpeed = new HashMap<>(); // per nautical mile
|
||||||
Map<String, Map<Speed, Duration>> predefinedAllowanceDurationsPerTrueWindSpeed = new HashMap<>(); //per nautical mile
|
final Map<String, Map<Speed, Duration>> predefinedAllowanceDurationsPerTrueWindSpeed = new HashMap<>(); // per nautical mile
|
||||||
JSONObject object = certificateJsonObjectsByCertificateId.get(certificateId);
|
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) {
|
if (object == null) {
|
||||||
// TODO Throw Exception for certificate by id not found. InvalidArgumentException?
|
// TODO Throw Exception for certificate by id not found. InvalidArgumentException?
|
||||||
return null;
|
return null;
|
||||||
@@ -98,84 +113,104 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
|
|||||||
String sailNumber = null;
|
String sailNumber = null;
|
||||||
for (Entry<Object, Object> entry : object.entrySet()) {
|
for (Entry<Object, Object> entry : object.entrySet()) {
|
||||||
switch ((String) entry.getKey()) {
|
switch ((String) entry.getKey()) {
|
||||||
case SAIL_NO:
|
case SAIL_NO:
|
||||||
sailNumber = entry.getValue() == null ? null : entry.getValue().toString();
|
sailNumber = entry.getValue() == null ? null : entry.getValue().toString();
|
||||||
break;
|
break;
|
||||||
case LOA:
|
case LOA:
|
||||||
length = new MeterDistance(((Number) entry.getValue()).doubleValue());
|
length = new MeterDistance(((Number) entry.getValue()).doubleValue());
|
||||||
break;
|
break;
|
||||||
case YACHT_NAME:
|
case YACHT_NAME:
|
||||||
boatName = entry.getValue()==null?null:entry.getValue().toString();
|
boatName = entry.getValue() == null ? null : entry.getValue().toString();
|
||||||
break;
|
break;
|
||||||
case CLASS:
|
case CLASS:
|
||||||
boatclass = (String) entry.getValue();
|
boatclass = (String) entry.getValue();
|
||||||
break;
|
break;
|
||||||
case GPH2:
|
case GPH2:
|
||||||
gph = new SecondsDurationImpl(((Number) entry.getValue()).doubleValue());
|
gph = new SecondsDurationImpl(((Number) entry.getValue()).doubleValue());
|
||||||
break;
|
break;
|
||||||
case CDL2:
|
case CDL2:
|
||||||
cdl = ((Number) entry.getValue()).doubleValue();
|
cdl = ((Number) entry.getValue()).doubleValue();
|
||||||
break;
|
break;
|
||||||
case ISSUE_DATE:
|
case ISSUE_DATE:
|
||||||
Date date = DatatypeConverter.parseDateTime((String) entry.getValue()).getTime();
|
Date date = DatatypeConverter.parseDateTime((String) entry.getValue()).getTime();
|
||||||
issueDate = new MillisecondsTimePoint(date);
|
issueDate = new MillisecondsTimePoint(date);
|
||||||
break;
|
break;
|
||||||
case ALLOWANCES:
|
case ALLOWANCES:
|
||||||
final JSONObject allowances = (JSONObject) object.get(ALLOWANCES);
|
final JSONObject allowances = (JSONObject) object.get(ALLOWANCES);
|
||||||
for (final Object aKey : allowances.keySet()) {
|
// calculating the TWA and TWS before calculating the other dependent values in allowances object
|
||||||
final JSONArray array = (JSONArray) allowances.get(aKey);
|
final Object windSpeedsObject = allowances.get(WIND_SPEEDS);
|
||||||
if (((String) aKey).equals(BEAT_ANGLE)) {
|
if (windSpeedsObject != null) {
|
||||||
for (int i = 0; i < array.size(); i++) {
|
final JSONArray twsArray = (JSONArray) windSpeedsObject;
|
||||||
beatAngles.put(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[i],
|
for (final Object twsObject : twsArray) {
|
||||||
new DegreeBearingImpl(((Number) array.get(i)).doubleValue()));
|
Double twsValue = ((Number) twsObject).doubleValue();
|
||||||
}
|
trueWindSpeedMap.put(twsValue, new KnotSpeedImpl(twsValue));
|
||||||
continue;
|
}
|
||||||
}
|
} else {
|
||||||
if (((String) aKey).equals(GYBE_ANGLE)) {
|
for (Speed speed : ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
||||||
for (int i = 0; i < array.size(); i++) {
|
trueWindSpeedMap.put(speed.getKnots(), speed);
|
||||||
gybeAngles.put(ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[i],
|
}
|
||||||
new DegreeBearingImpl(((Number) array.get(i)).doubleValue()));
|
}
|
||||||
}
|
final Double [] trueWindSpeedArray = new Double[trueWindSpeedMap.size()];
|
||||||
continue;
|
trueWindSpeedMap.keySet().toArray(trueWindSpeedArray);
|
||||||
}
|
for (final Object aKey : allowances.keySet()) {
|
||||||
Map<Speed, Duration> twsMap = new HashMap<>();
|
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++) {
|
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()));
|
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;
|
switch ((String) aKey) {
|
||||||
default:
|
case BEAT:
|
||||||
break;
|
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()) {
|
trueWindSpeedMap.values().forEach(tws -> velocityPredictionPerTrueWindSpeedAndAngle.put(tws, new HashMap<>()));
|
||||||
for (Speed keyTWS : allowanceDurationsPerTrueWindAngleAndSpeed.get(keyTWA).keySet()) {
|
for (final Bearing keyTWA : allowanceDurationsPerTrueWindAngleAndSpeed.keySet()) {
|
||||||
velocityPredictionPerTrueWindSpeedAndAngle.get(keyTWS).put(keyTWA,
|
for (final Speed keyTWS : allowanceDurationsPerTrueWindAngleAndSpeed.get(keyTWA).keySet()) {
|
||||||
ORCCertificateImpl.NAUTICAL_MILE
|
velocityPredictionPerTrueWindSpeedAndAngle.get(keyTWS).put(keyTWA, ORCCertificateImpl.NAUTICAL_MILE
|
||||||
.inTime(allowanceDurationsPerTrueWindAngleAndSpeed.get(keyTWA).get(keyTWS)));
|
.inTime(allowanceDurationsPerTrueWindAngleAndSpeed.get(keyTWA).get(keyTWS)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,20 +238,30 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
|
|||||||
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificateImpl.NAUTICAL_MILE
|
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificateImpl.NAUTICAL_MILE
|
||||||
.inTime(predefinedAllowanceDurationsPerTrueWindSpeed.get(NON_SPINNAKER).get(tws)));
|
.inTime(predefinedAllowanceDurationsPerTrueWindSpeed.get(NON_SPINNAKER).get(tws)));
|
||||||
}
|
}
|
||||||
return new ORCCertificateImpl(getId(object), sailNumber, boatName, boatclass, length, gph, cdl,
|
final Bearing[] dynamicAllowancesTrueWindAngles = trueWindAngleMap.values().toArray(new Bearing[trueWindAngleMap.values().size()]);
|
||||||
issueDate, velocityPredictionPerTrueWindSpeedAndAngle, beatAngles, beatVMGPredictionPerTrueWindSpeed,
|
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,
|
beatAllowancePerTrueWindSpeed, gybeAngles, runVMGPredictionPerTrueWindSpeed,
|
||||||
runAllowancePerTrueWindSpeed, windwardLeewardSpeedPredictionPerTrueWindSpeed,
|
runAllowancePerTrueWindSpeed, windwardLeewardSpeedPredictionPerTrueWindSpeed,
|
||||||
longDistanceSpeedPredictionPerTrueWindSpeed, circularRandomSpeedPredictionPerTrueWindSpeed,
|
longDistanceSpeedPredictionPerTrueWindSpeed, circularRandomSpeedPredictionPerTrueWindSpeed,
|
||||||
nonSpinnakerSpeedPredictionPerTrueWindSpeed);
|
nonSpinnakerSpeedPredictionPerTrueWindSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getId(JSONObject certificateAsJson) {
|
private String getId(JSONObject certificateAsJson) {
|
||||||
return getIdFromFields(certificateAsJson.get(NAT_AUTH).toString(),
|
return getIdFromFields(certificateAsJson.get(NAT_AUTH).toString(),
|
||||||
certificateAsJson.get(CERT_NO) == null ? EMPTY_CERT_NO : certificateAsJson.get(CERT_NO).toString(),
|
certificateAsJson.get(CERT_NO) == null ? EMPTY_CERT_NO : certificateAsJson.get(CERT_NO).toString(),
|
||||||
certificateAsJson.get(BIN).toString());
|
certificateAsJson.get(BIN).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getIdFromFields(final String natAuth, final String certNo, final String bin) {
|
private String getIdFromFields(final String natAuth, final String certNo, final String bin) {
|
||||||
return natAuth + certNo + 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> longDistanceSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||||
final Map<Speed, Speed> circularRandomSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
final Map<Speed, Speed> circularRandomSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||||
final Map<Speed, Speed> nonSpinnakerSpeedPredictionPerTrueWindSpeed = 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 windSpeed = Integer.toString((int) tws.getKnots());
|
||||||
String beatAngleKey = BEAT_ANGLE + windSpeed;
|
String beatAngleKey = BEAT_ANGLE + windSpeed;
|
||||||
String beatAllowanceKey = BEAT_ALLOWANCE + windSpeed;
|
String beatAllowanceKey = BEAT_ALLOWANCE + windSpeed;
|
||||||
@@ -147,7 +147,7 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect
|
|||||||
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificateImpl.NAUTICAL_MILE.inTime(
|
nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificateImpl.NAUTICAL_MILE.inTime(
|
||||||
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(nonSpinnakerKey)))));
|
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(nonSpinnakerKey)))));
|
||||||
Map<Bearing, Speed> velocityPredictionPerTrueWindAngle = new HashMap<>();
|
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;
|
String twaCoursesKey = TWA_COURSES + Integer.toString((int) twa.getDegrees()) + windSpeed;
|
||||||
velocityPredictionPerTrueWindAngle.put(twa, ORCCertificateImpl.NAUTICAL_MILE.inTime(
|
velocityPredictionPerTrueWindAngle.put(twa, ORCCertificateImpl.NAUTICAL_MILE.inTime(
|
||||||
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(twaCoursesKey)))));
|
new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(twaCoursesKey)))));
|
||||||
|
|||||||
+38
-17
@@ -71,6 +71,16 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
|||||||
* allowance in sec/nm.
|
* allowance in sec/nm.
|
||||||
*/
|
*/
|
||||||
private final UnivariateDifferentiableFunction functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse;
|
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
|
* 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 {
|
public ORCPerformanceCurveImpl(ORCCertificate certificate, ORCPerformanceCurveCourse course) throws FunctionEvaluationException {
|
||||||
this.course = course;
|
this.course = course;
|
||||||
|
this.trueWindAngles = certificate.getTrueWindAngles();
|
||||||
|
this.trueWindSpeeds = certificate.getTrueWindSpeeds();
|
||||||
functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse = createPerformanceCurve(certificate);
|
functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse = createPerformanceCurve(certificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,8 +112,8 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
|||||||
*/
|
*/
|
||||||
private UnivariateDifferentiableFunction createPerformanceCurve(ORCCertificate certificate) throws FunctionEvaluationException {
|
private UnivariateDifferentiableFunction createPerformanceCurve(ORCCertificate certificate) throws FunctionEvaluationException {
|
||||||
final Map<Speed, Duration> allowancesForCoursePerTrueWindSpeed = createAllowancesPerCourse(certificate);
|
final Map<Speed, Duration> allowancesForCoursePerTrueWindSpeed = createAllowancesPerCourse(certificate);
|
||||||
double[] xs = new double[ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS.length+2];
|
double[] xs = new double[certificate.getTrueWindSpeeds().length+2];
|
||||||
double[] ys = new double[ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS.length+2];
|
double[] ys = new double[certificate.getTrueWindSpeeds().length+2];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
xs[i] = 0; // see original Pascal code; the first "knot" is set to (0.0, 0.0)
|
xs[i] = 0; // see original Pascal code; the first "knot" is set to (0.0, 0.0)
|
||||||
ys[i] = 0;
|
ys[i] = 0;
|
||||||
@@ -142,7 +154,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
|||||||
for (final ORCPerformanceCurveLeg leg : course.getLegs()) {
|
for (final ORCPerformanceCurveLeg leg : course.getLegs()) {
|
||||||
allowancesPerLeg.put(leg, createAllowancePerLeg(leg, certificate));
|
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);
|
Duration allowancePerTws = new SecondsDurationImpl(0);
|
||||||
for (final ORCPerformanceCurveLeg leg : course.getLegs()) {
|
for (final ORCPerformanceCurveLeg leg : course.getLegs()) {
|
||||||
allowancePerTws = allowancePerTws.plus(allowancesPerLeg.get(leg).get(tws));
|
allowancePerTws = allowancePerTws.plus(allowancesPerLeg.get(leg).get(tws));
|
||||||
@@ -168,7 +180,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
|||||||
|
|
||||||
switch (leg.getType()) {
|
switch (leg.getType()) {
|
||||||
case TWA:
|
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)
|
// 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) {
|
if (leg.getTwa().abs().compareTo(beatAngles.get(tws)) <= 0) {
|
||||||
// Case 0 & 1 - result = beatVMG * distance * cos(TWA)
|
// Case 0 & 1 - result = beatVMG * distance * cos(TWA)
|
||||||
@@ -186,23 +198,23 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CIRCULAR_RANDOM:
|
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()));
|
result.put(tws, certificate.getCircularRandomSpeedPredictions().get(tws).getDuration(leg.getLength()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LONG_DISTANCE:
|
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()));
|
result.put(tws, certificate.getLongDistanceSpeedPredictions().get(tws).getDuration(leg.getLength()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WINDWARD_LEEWARD:
|
case WINDWARD_LEEWARD:
|
||||||
case WINDWARD_LEEWARD_REAL_LIVE:
|
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()));
|
result.put(tws, certificate.getWindwardLeewardSpeedPrediction().get(tws).getDuration(leg.getLength()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NON_SPINNAKER:
|
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()));
|
result.put(tws, certificate.getNonSpinnakerSpeedPredictions().get(tws).getDuration(leg.getLength()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -216,7 +228,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
|||||||
*/
|
*/
|
||||||
private double[][] createPolarsPerTrueWindSpeed(Speed trueWindSpeed, Map<Speed, Map<Bearing, Speed>> reachingSpeedPredictionsPerTrueWindSpeedAndAngle,
|
private double[][] createPolarsPerTrueWindSpeed(Speed trueWindSpeed, Map<Speed, Map<Bearing, Speed>> reachingSpeedPredictionsPerTrueWindSpeedAndAngle,
|
||||||
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
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> resultWindAngles = new ArrayList<>();
|
||||||
ArrayList<Double> resultSpeedsOverGroundInKnots = new ArrayList<>();
|
ArrayList<Double> resultSpeedsOverGroundInKnots = new ArrayList<>();
|
||||||
Bearing beatAngle = beatAngles.get(trueWindSpeed);
|
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()));
|
resultSpeedsOverGroundInKnots.add(beatVMGPredictionPerTrueWindSpeed.get(trueWindSpeed).getKnots() / Math.cos(beatAngle.add(MINUS_TWO_DEGREES).getRadians()));
|
||||||
resultWindAngles.add(beatAngle.getDegrees());
|
resultWindAngles.add(beatAngle.getDegrees());
|
||||||
resultSpeedsOverGroundInKnots.add(beatVMGPredictionPerTrueWindSpeed.get(trueWindSpeed).getKnots() / Math.cos(beatAngle.getRadians()));
|
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) {
|
if (twa.compareTo(beatAngle) > 0 && twa.compareTo(runAngle) < 0) {
|
||||||
resultWindAngles.add(twa.getDegrees());
|
resultWindAngles.add(twa.getDegrees());
|
||||||
resultSpeedsOverGroundInKnots.add(reachingSpeedPredictionsPerTrueWindSpeedAndAngle.get(trueWindSpeed).get(twa).getKnots());
|
resultSpeedsOverGroundInKnots.add(reachingSpeedPredictionsPerTrueWindSpeedAndAngle.get(trueWindSpeed).get(twa).getKnots());
|
||||||
@@ -251,14 +263,14 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
|||||||
@Override
|
@Override
|
||||||
public Speed getImpliedWind(Duration durationToCompleteCourse) throws MaxIterationsExceededException, FunctionEvaluationException{
|
public Speed getImpliedWind(Duration durationToCompleteCourse) throws MaxIterationsExceededException, FunctionEvaluationException{
|
||||||
final Speed averageSpeedOnCourse = getCourse().getTotalLength().inTime(durationToCompleteCourse);
|
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();
|
(tws->{ return functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse.value(tws.getKnots()); }).toArray();
|
||||||
final Speed result;
|
final Speed result;
|
||||||
// Corner cases for Allowance > Allowance(20kt) or Allowance < Allowance(6kt)
|
// Corner cases for Allowance > Allowance(20kt) or Allowance < Allowance(6kt)
|
||||||
if (averageSpeedOnCourse.getKnots() >= predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed[predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed.length-1]) {
|
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]) {
|
} else if (averageSpeedOnCourse.equals(Speed.NULL) || averageSpeedOnCourse.getKnots() <= predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed[0]) {
|
||||||
result = ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS[0];
|
result = trueWindSpeeds[0];
|
||||||
} else {
|
} else {
|
||||||
// find the polynomial splined function that produces the durationToCompleteCourse within its validity range
|
// 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, ...)
|
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,
|
final UnivariateDifferentiableFunction targetZeroFunction = FunctionUtils.add(functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse,
|
||||||
FunctionUtils.multiply((UnivariateDifferentiableFunction) averageSpeedInKnots,
|
FunctionUtils.multiply((UnivariateDifferentiableFunction) averageSpeedInKnots,
|
||||||
(UnivariateDifferentiableFunction) new Constant(-1)));
|
(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);
|
result = new KnotSpeedImpl(impliedWindSpeedInKnots);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -294,9 +306,18 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
|||||||
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
|
||||||
Map<Speed, Bearing> runAngles, Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed, Speed trueWindSpeed,
|
Map<Speed, Bearing> runAngles, Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed, Speed trueWindSpeed,
|
||||||
Bearing trueWindAngle) throws FunctionEvaluationException, IllegalArgumentException {
|
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;
|
final Speed result;
|
||||||
double[][] polarPoints = createPolarsPerTrueWindSpeed(trueWindSpeed, twaAllowances, beatAngles,
|
double[][] polarPoints = createPolarsPerTrueWindSpeed(trueWindSpeed, twaAllowances, beatAngles,
|
||||||
beatVMGPredictionPerTrueWindSpeed, runAngles, runVMGPredictionPerTrueWindSpeed);
|
beatVMGPredictionPerTrueWindSpeed, runAngles, runVMGPredictionPerTrueWindSpeed, trueWindAngles);
|
||||||
double[] twaPolarPoints = polarPoints[0];
|
double[] twaPolarPoints = polarPoints[0];
|
||||||
double[] speedsOverGroundInKnotsPolarPoints = polarPoints[1];
|
double[] speedsOverGroundInKnotsPolarPoints = polarPoints[1];
|
||||||
int i = -1; // after the loop, i equals the next higher available polar data for the given TWA
|
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
|
* 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.
|
* 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<>();
|
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));
|
result.put(tws, getAllowancePerCourse(tws));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
+14
-1
@@ -1,12 +1,15 @@
|
|||||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.orc.impl;
|
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.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||||
import com.google.gwt.user.client.rpc.SerializationException;
|
import com.google.gwt.user.client.rpc.SerializationException;
|
||||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
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.sailing.domain.common.orc.impl.ORCCertificateImpl;
|
||||||
import com.sap.sse.common.Bearing;
|
import com.sap.sse.common.Bearing;
|
||||||
import com.sap.sse.common.Distance;
|
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.getLongDistanceSpeedPredictions()));
|
||||||
streamWriter.writeObject(new HashMap<>(instance.getCircularRandomSpeedPredictions()));
|
streamWriter.writeObject(new HashMap<>(instance.getCircularRandomSpeedPredictions()));
|
||||||
streamWriter.writeObject(new HashMap<>(instance.getNonSpinnakerSpeedPredictions()));
|
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
|
@Override
|
||||||
@@ -88,7 +95,13 @@ public class ORCCertificateImpl_CustomFieldSerializer extends CustomFieldSeriali
|
|||||||
final Map<Speed, Speed> circularRandomSpeedPredictionsPerTrueWindSpeed = (Map<Speed, Speed>) streamReader.readObject();
|
final Map<Speed, Speed> circularRandomSpeedPredictionsPerTrueWindSpeed = (Map<Speed, Speed>) streamReader.readObject();
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
final Map<Speed, Speed> nonSpinnakerSpeedPredictionsPerTrueWindSpeed = (Map<Speed, Speed>) streamReader.readObject();
|
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,
|
cdl, issueDate, velocityPredictionsPerTrueWindSpeedAndAngle, beatAngles,
|
||||||
beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles,
|
beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles,
|
||||||
runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed,
|
runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed,
|
||||||
|
|||||||
+1
@@ -110,6 +110,7 @@ public class MarkPropertiesPanel extends FlowPanel {
|
|||||||
strings.add(t.getName());
|
strings.add(t.getName());
|
||||||
strings.add(t.getCommonMarkProperties().getShortName());
|
strings.add(t.getCommonMarkProperties().getShortName());
|
||||||
strings.add(t.getUuid().toString());
|
strings.add(t.getUuid().toString());
|
||||||
|
Util.addAll(t.getTags(), strings);
|
||||||
return 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.DockLayoutPanel;
|
||||||
import com.google.gwt.user.client.ui.FlowPanel;
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
import com.google.gwt.user.client.ui.Panel;
|
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.RequiresResize;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
import com.google.gwt.user.client.ui.WidgetCollection;
|
import com.google.gwt.user.client.ui.WidgetCollection;
|
||||||
@@ -202,7 +201,7 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
|||||||
*
|
*
|
||||||
* @author Simon Marcel Pamies, Axel Uhl
|
* @author Simon Marcel Pamies, Axel Uhl
|
||||||
*/
|
*/
|
||||||
abstract class Splitter extends AbsolutePanel implements RequiresResize, ProvidesResize {
|
abstract class Splitter extends AbsolutePanel {
|
||||||
protected final Widget target;
|
protected final Widget target;
|
||||||
|
|
||||||
private int offset;
|
private int offset;
|
||||||
@@ -319,7 +318,6 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
|||||||
syncedCenterSize = newCenterSize;
|
syncedCenterSize = newCenterSize;
|
||||||
centerSize = newCenterSize;
|
centerSize = newCenterSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.max(((LayoutData) target.getLayoutData()).size + centerSize, 0);
|
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 int getAbsolutePosition();
|
||||||
protected abstract double getCenterSize();
|
protected abstract double getCenterSize();
|
||||||
protected abstract int getEventPosition(Event event);
|
protected abstract int getEventPosition(Event event);
|
||||||
@@ -851,7 +844,7 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
|||||||
if (splitter != null) {
|
if (splitter != null) {
|
||||||
LayoutData layoutData = (LayoutData) widget.getLayoutData();
|
LayoutData layoutData = (LayoutData) widget.getLayoutData();
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
if(layoutData.size > 0) {
|
if (layoutData.size > 0) {
|
||||||
layoutData.oldSize = layoutData.size;
|
layoutData.oldSize = layoutData.size;
|
||||||
}
|
}
|
||||||
widget.setVisible(false);
|
widget.setVisible(false);
|
||||||
@@ -861,7 +854,6 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
splitter.setAssociatedWidgetSize(0, /* defer */false);
|
splitter.setAssociatedWidgetSize(0, /* defer */false);
|
||||||
|
|
||||||
// need to ensure visibility of dragger, do NOT use setVisible() as south/north splitter should be shown always
|
// need to ensure visibility of dragger, do NOT use setVisible() as south/north splitter should be shown always
|
||||||
splitter.setDraggerVisible(!hidden);
|
splitter.setDraggerVisible(!hidden);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+28
-4
@@ -1,8 +1,12 @@
|
|||||||
package com.sap.sailing.server.gateway.deserialization.racelog.impl;
|
package com.sap.sailing.server.gateway.deserialization.racelog.impl;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
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> longDistanceSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||||
Map<Speed, Speed> circularRandomSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
Map<Speed, Speed> circularRandomSpeedPredictionPerTrueWindSpeed = new HashMap<>();
|
||||||
Map<Speed, Speed> nonSpinnakerSpeedPredictionPerTrueWindSpeed = 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);
|
String twsKey = ORCCertificateJsonSerializer.speedToKnotsString(tws);
|
||||||
beatAngles.put(tws, new DegreeBearingImpl(
|
beatAngles.put(tws, new DegreeBearingImpl(
|
||||||
((Number) ((JSONObject) json.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_BEAT_ANGLES))
|
((Number) ((JSONObject) json.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_BEAT_ANGLES))
|
||||||
@@ -84,9 +92,8 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
|
|||||||
new KnotSpeedImpl(((Number) ((JSONObject) json
|
new KnotSpeedImpl(((Number) ((JSONObject) json
|
||||||
.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_NON_SPINNAKER_SPEED_PREDICTIONS))
|
.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_NON_SPINNAKER_SPEED_PREDICTIONS))
|
||||||
.get(twsKey)).doubleValue()));
|
.get(twsKey)).doubleValue()));
|
||||||
|
|
||||||
Map<Bearing, Speed> velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle = new HashMap<>();
|
Map<Bearing, Speed> velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle = new HashMap<>();
|
||||||
for (Bearing twa : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_ANGLES) {
|
for (Bearing twa : trueWindAngles) {
|
||||||
String twaKey = ORCCertificateJsonSerializer.bearingToDegreeString(twa);
|
String twaKey = ORCCertificateJsonSerializer.bearingToDegreeString(twa);
|
||||||
velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle.put(twa,
|
velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle.put(twa,
|
||||||
new KnotSpeedImpl(((Number) ((JSONObject) ((JSONObject) json
|
new KnotSpeedImpl(((Number) ((JSONObject) ((JSONObject) json
|
||||||
@@ -97,7 +104,7 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
|
|||||||
velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle);
|
velocityPredictionAtCurrentTrueWindSpeedPerTrueWindAngle);
|
||||||
}
|
}
|
||||||
final String idConsistingOfNatAuthCertNoAndBIN = json.get(ORCCertificateJsonSerializer.ORC_CERTIFICATE_ID).toString();
|
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,
|
boatName, boatclass, length, gph, cdl, issueDate, velocityPredictionsPerTrueWindSpeedAndAngle,
|
||||||
beatAngles, beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles,
|
beatAngles, beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles,
|
||||||
runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed,
|
runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed,
|
||||||
@@ -105,4 +112,21 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer<ORCCerti
|
|||||||
circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed);
|
circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed);
|
||||||
return certificate;
|
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;
|
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 org.json.simple.JSONObject;
|
||||||
|
|
||||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
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.sailing.server.gateway.serialization.JsonSerializer;
|
||||||
import com.sap.sse.common.Bearing;
|
import com.sap.sse.common.Bearing;
|
||||||
import com.sap.sse.common.Speed;
|
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_ID = "ID";
|
||||||
public static final String ORC_CERTIFICATE_LENGTH = "length";
|
public static final String ORC_CERTIFICATE_LENGTH = "length";
|
||||||
public static final String ORC_CERTIFICATE_ISSUE_DATE = "issueDate";
|
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_6KT = "ORC_CERTIFICATE_TWS_6KT";
|
||||||
public static final String ORC_CERTIFICATE_TWS_8KT = "ORC_CERTIFICATE_TWS_8KT";
|
public static final String ORC_CERTIFICATE_TWS_8KT = "ORC_CERTIFICATE_TWS_8KT";
|
||||||
public static final String ORC_CERTIFICATE_TWS_10KT = "ORC_CERTIFICATE_TWS_10KT";
|
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_14KT = "ORC_CERTIFICATE_TWS_14KT";
|
||||||
public static final String ORC_CERTIFICATE_TWS_16KT = "ORC_CERTIFICATE_TWS_16KT";
|
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_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_R52_PREDICTION = "ORC_CERTIFICATE_R52_PREDICTION";
|
||||||
public static final String ORC_CERTIFICATE_R60_PREDICTION = "ORC_CERTIFICATE_R60_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";
|
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_R120_PREDICTION = "ORC_CERTIFICATE_R120_PREDICTION";
|
||||||
public static final String ORC_CERTIFICATE_R135_PREDICTION = "ORC_CERTIFICATE_R135_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_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
|
@Override
|
||||||
public JSONObject serialize(ORCCertificate certificate) {
|
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_GPH, certificate.getGPHInSecondsToTheMile());
|
||||||
result.put(ORC_CERTIFICATE_CDL, certificate.getCDL());
|
result.put(ORC_CERTIFICATE_CDL, certificate.getCDL());
|
||||||
result.put(ORC_CERTIFICATE_LENGTH, certificate.getLengthOverAll().getMeters());
|
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 beatAngles = new JSONObject();
|
||||||
JSONObject runAngles = new JSONObject();
|
JSONObject runAngles = new JSONObject();
|
||||||
JSONObject beatAllowances = new JSONObject();
|
JSONObject beatAllowances = new JSONObject();
|
||||||
@@ -67,7 +75,7 @@ public class ORCCertificateJsonSerializer implements JsonSerializer<ORCCertifica
|
|||||||
JSONObject longDistancePredictions = new JSONObject();
|
JSONObject longDistancePredictions = new JSONObject();
|
||||||
JSONObject nonSpinnakerPredictions = new JSONObject();
|
JSONObject nonSpinnakerPredictions = new JSONObject();
|
||||||
JSONObject velocityPredictionsPerTrueWindSpeedAndAngle = new JSONObject();
|
JSONObject velocityPredictionsPerTrueWindSpeedAndAngle = new JSONObject();
|
||||||
for (Speed tws : ORCCertificateImpl.ALLOWANCES_TRUE_WIND_SPEEDS) {
|
for (Speed tws : certificate.getTrueWindSpeeds()) {
|
||||||
String keyTWS = speedToKnotsString(tws);
|
String keyTWS = speedToKnotsString(tws);
|
||||||
JSONObject velocityPredictionsPerTrueWindAngle = new JSONObject();
|
JSONObject velocityPredictionsPerTrueWindAngle = new JSONObject();
|
||||||
beatAngles.put(keyTWS, certificate.getBeatAngles().get(tws).getDegrees());
|
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());
|
circularRandomPredictions.put(keyTWS, certificate.getCircularRandomSpeedPredictions().get(tws).getKnots());
|
||||||
longDistancePredictions.put(keyTWS, certificate.getLongDistanceSpeedPredictions().get(tws).getKnots());
|
longDistancePredictions.put(keyTWS, certificate.getLongDistanceSpeedPredictions().get(tws).getKnots());
|
||||||
nonSpinnakerPredictions.put(keyTWS, certificate.getNonSpinnakerSpeedPredictions().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);
|
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);
|
velocityPredictionsPerTrueWindSpeedAndAngle.put(keyTWS, velocityPredictionsPerTrueWindAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.put(ORC_CERTIFICATE_BEAT_ANGLES, beatAngles);
|
result.put(ORC_CERTIFICATE_BEAT_ANGLES, beatAngles);
|
||||||
result.put(ORC_CERTIFICATE_RUN_ANGLES, runAngles);
|
result.put(ORC_CERTIFICATE_RUN_ANGLES, runAngles);
|
||||||
result.put(ORC_CERTIFICATE_BEAT_ALLOWANCES, beatAllowances);
|
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_CIRCULAR_RANDOM_SPEED_PREDICTIONS, circularRandomPredictions);
|
||||||
result.put(ORC_CERTIFICATE_NON_SPINNAKER_SPEED_PREDICTIONS, nonSpinnakerPredictions);
|
result.put(ORC_CERTIFICATE_NON_SPINNAKER_SPEED_PREDICTIONS, nonSpinnakerPredictions);
|
||||||
result.put(ORC_CERTIFICATE_TWA_SPEED_PREDICTIONS, velocityPredictionsPerTrueWindSpeedAndAngle);
|
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;
|
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) {
|
public static String speedToKnotsString(Speed speed) {
|
||||||
String result = null;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String bearingToDegreeString(Bearing bearing) {
|
public static String bearingToDegreeString(Bearing bearing) {
|
||||||
String result = null;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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())
|
? MillisecondsTimePoint.now().minus(trackedRace.getDelayToLiveInMillis())
|
||||||
: new MillisecondsTimePoint(resultTimePoint)));
|
: new MillisecondsTimePoint(resultTimePoint)));
|
||||||
trackedRaceInfo.put("delayToLiveInMillis", trackedRace.getDelayToLiveInMillis());
|
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);
|
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};
|
* 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
|
* otherwise return those race column names from {@code raceColumnsOfLeaderboard} that are also in
|
||||||
* {@code raceColumnNames}.
|
* {@code raceColumnNames}.
|
||||||
* @param leaderboard TODO
|
|
||||||
* @param showOnlyActiveRacesForCompetitorIds
|
* @param showOnlyActiveRacesForCompetitorIds
|
||||||
* {@code null}, or specifies zero or more competitor IDs, requesting that the result contained the race
|
* {@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
|
* column holding that competitor's "active" race at the time requested; see also the
|
||||||
|
|||||||
Reference in New Issue
Block a user