diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificate.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificate.java index 25655fb96bd..06a6c98e595 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificate.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificate.java @@ -105,5 +105,7 @@ public interface ORCCertificate extends Serializable { public Map getRunVMGPredictions(); public Map> getVelocityPredictionPerTrueWindSpeedAndAngle(); + + public String getBoatName(); } \ No newline at end of file diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/impl/ORCCertificateImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/impl/ORCCertificateImpl.java index 453511737e7..a6eb866c5c9 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/impl/ORCCertificateImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/impl/ORCCertificateImpl.java @@ -50,10 +50,8 @@ public class ORCCertificateImpl implements ORCCertificate { public final static double PI = 3.14159265358979; - /** - * - */ private final String sailnumber; + private final String boatName; private final String boatclass; private final Distance lengthOverAll; private final Duration gph; @@ -110,17 +108,17 @@ public class ORCCertificateImpl implements ORCCertificate { private final Map nonSpinnakerSpeedPredictionPerTrueWindSpeed; - // TODO Comment on Constructor - public ORCCertificateImpl(String sailnumber, String boatclass, Distance length, Duration gph, - Double cdl, Map> velocityPredictionsPerTrueWindSpeedAndAngle, - Map beatAngles, Map beatVMGPredictionPerTrueWindSpeed, - Map beatAllowancePerTrueWindSpeed, Map runAngles, - Map runVMGPredictionPerTrueWindSpeed, Map runAllowancePerTrueWindSpeed, + public ORCCertificateImpl(String sailnumber, String boatName, String boatclass, Distance length, + Duration gph, Double cdl, + Map> velocityPredictionsPerTrueWindSpeedAndAngle, Map beatAngles, + Map beatVMGPredictionPerTrueWindSpeed, Map beatAllowancePerTrueWindSpeed, + Map runAngles, Map runVMGPredictionPerTrueWindSpeed, + Map runAllowancePerTrueWindSpeed, Map windwardLeewardSpeedPredictionsPerTrueWindSpeed, Map longDistanceSpeedPredictionsPerTrueWindSpeed, - Map circularRandomSpeedPredictionsPerTrueWindSpeed, - Map nonSpinnakerSpeedPredictionsPerTrueWindSpeed) { + Map circularRandomSpeedPredictionsPerTrueWindSpeed, Map nonSpinnakerSpeedPredictionsPerTrueWindSpeed) { this.sailnumber = sailnumber; + this.boatName = boatName; this.boatclass = boatclass; this.lengthOverAll = length; this.gph = gph; @@ -139,6 +137,11 @@ public class ORCCertificateImpl implements ORCCertificate { this.nonSpinnakerSpeedPredictionPerTrueWindSpeed = Collections.unmodifiableMap(nonSpinnakerSpeedPredictionsPerTrueWindSpeed); } + @Override + public String getBoatName() { + return boatName; + } + @Override public double getGPH() { return gph.asSeconds(); @@ -222,4 +225,9 @@ public class ORCCertificateImpl implements ORCCertificate { public Map getRunVMGPredictions() { return runVMGPredictionPerTrueWindSpeed; } + + @Override + public String toString() { + return ""+getSailnumber()+" / "+getBoatName(); + } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/ORCPerformanceCurveRankingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/ORCPerformanceCurveRankingTest.java index fcb6a71df6d..c2f456dd239 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/ORCPerformanceCurveRankingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/ORCPerformanceCurveRankingTest.java @@ -3,28 +3,56 @@ package com.sap.sailing.domain.orc; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.UUID; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.rules.Timeout; +import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; +import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCLegDataEventImpl; +import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCScratchBoatEventImpl; +import com.sap.sailing.domain.abstractlog.orc.impl.RegattaLogORCCertificateAssignmentEventImpl; +import com.sap.sailing.domain.abstractlog.race.CompetitorResult; +import com.sap.sailing.domain.abstractlog.race.CompetitorResult.MergeState; +import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl; +import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl; +import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningConfirmedEventImpl; +import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; +import com.sap.sailing.domain.base.Boat; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.WindSourceType; import com.sap.sailing.domain.common.impl.DegreePosition; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; +import com.sap.sailing.domain.common.impl.NauticalMileDistance; import com.sap.sailing.domain.common.impl.WindImpl; import com.sap.sailing.domain.common.impl.WindSourceImpl; +import com.sap.sailing.domain.common.orc.ORCCertificate; +import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLegTypes; import com.sap.sailing.domain.orc.impl.ORCPerformanceCurveRankingMetric; import com.sap.sailing.domain.test.OnlineTracTracBasedTest; import com.sap.sailing.domain.tractracadapter.ReceiverType; +import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; import com.sap.sse.common.impl.DegreeBearingImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.common.impl.SecondsDurationImpl; /** * See bug 5122; Test cases for {@link ORCPerformanceCurveRankingMetric} @@ -35,6 +63,17 @@ import com.sap.sse.common.impl.MillisecondsTimePoint; public class ORCPerformanceCurveRankingTest extends OnlineTracTracBasedTest { final static MillisecondsTimePoint TIME_14_30_00 = new MillisecondsTimePoint(1555849800000l); final static MillisecondsTimePoint TIME_14_30_12 = new MillisecondsTimePoint(1555849812000l); + + private final static DateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); + private ORCPerformanceCurveRankingMetric rankingMetric; + private RaceLog raceLog; + private RegattaLog regattaLog; + private LogEventAuthorImpl author; + + @Rule + public TestRule getTimeoutRule() { + return Timeout.millis(100 * 60 * 1000); + } public ORCPerformanceCurveRankingTest() throws MalformedURLException, URISyntaxException { } @@ -47,33 +86,110 @@ public class ORCPerformanceCurveRankingTest extends OnlineTracTracBasedTest { @Before public void setUp() throws Exception { super.setUp(); - URI storedUri = new URI("file:///"+new File("resources/orc/worlds2019/c5a516a0-69f7-0137-dd9c-60a44ce903c3.mtb").getCanonicalPath().replace('\\', '/')); - super.setUp(new URL("file:///"+new File("resources/orc/worlds2019/c5a516a0-69f7-0137-dd9c-60a44ce903c3.txt").getCanonicalPath()), - /* liveUri */ null, /* storedUri */ storedUri, + URI storedUri = new URI("file:///"+new File("resources/orc/worlds2019/348f93c0-6798-0137-b07e-60a44ce903c3.mtb").getCanonicalPath().replace('\\', '/')); + super.setUp(new URL("file:///"+new File("resources/orc/worlds2019/348f93c0-6798-0137-b07e-60a44ce903c3.txt").getCanonicalPath()), + /* liveUri */ null, /* storedUri */ storedUri, ORCPerformanceCurveRankingMetric::new, new ReceiverType[] { ReceiverType.MARKPASSINGS, ReceiverType.RACECOURSE, ReceiverType.RAWPOSITIONS, ReceiverType.MARKPOSITIONS, ReceiverType.RACECOURSE, ReceiverType.RACESTARTFINISH }); getTrackedRace().recordWind(new WindImpl(/* position */ new DegreePosition(44.37670797575265, 8.925960855558515), TIME_14_30_00, new KnotSpeedWithBearingImpl(7.5, new DegreeBearingImpl(246).reverse())), new WindSourceImpl(WindSourceType.WEB)); + raceLog = new RaceLogImpl(UUID.randomUUID()); + regattaLog = getTrackedRace().getTrackedRegatta().getRegatta().getRegattaLog(); + getTrackedRace().attachRegattaLog(regattaLog); + getTrackedRace().attachRaceLog(raceLog); + rankingMetric = (ORCPerformanceCurveRankingMetric) getTrackedRace().getRankingMetric(); final ORCCertificatesCollection certificates = ORCCertificatesImporter.INSTANCE.read( - getClass().getClassLoader().getResourceAsStream("resources/orc/worlds2019/orcWorlds2019ClassA.json")); + getClass().getClassLoader().getResourceAsStream("orc/worlds2019/orcWorlds2019ClassA.json")); assertNotNull(certificates); assertFalse(Util.isEmpty(certificates.getSailNumbers())); + author = new LogEventAuthorImpl("Testcase", 1); + for (final Competitor competitor : getTrackedRace().getRace().getCompetitors()) { + final Boat boat = getTrackedRace().getRace().getBoatOfCompetitor(competitor); + ORCCertificate certificate; + if (boat.getSailID().equals("Air is blue")) { + certificate = certificates.getCertificateBySailNumber("ITA5252"); + } else { + certificate = certificates.getCertificateBySailNumber(boat.getSailID()); + if (certificate == null) { + certificate = certificates.getCertificateByBoatName(boat.getName() == null ? boat.getSailID() : boat.getName()); + } + } + assertNotNull("Couldn't find a certificate for boat "+boat, certificate); + final RegattaLogEvent certificateAssignment = new RegattaLogORCCertificateAssignmentEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), + author, UUID.randomUUID(), certificate, boat); + regattaLog.add(certificateAssignment); + assertSame(certificate, rankingMetric.getCertificate(boat)); + } + final RaceLog raceLog = getTrackedRace().getAttachedRaceLogs().iterator().next(); + final int numberOfLegs = getTrackedRace().getRace().getCourse().getNumberOfWaypoints()-1; + for (int oneBasedLegNumber = 1; oneBasedLegNumber <= numberOfLegs; oneBasedLegNumber++) { + raceLog.add(new RaceLogORCLegDataEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, + UUID.randomUUID(), /* pPassId */ 0, oneBasedLegNumber, /* twa */ null, + new NauticalMileDistance(126).scale(1.0/numberOfLegs), + ORCPerformanceCurveLegTypes.LONG_DISTANCE)); + } + /* + * Maestro Yachting Ltd with boat Maestro=Maestro + * Hurakan LTD with boat XIO=XIO + * JD Maribor?anka with boat Generali (Assilina I=Generali (Assilina I + * Roman Puchtev with boat Alemaro=Alemaro + * Giovanni Sylos Labini with boat Luduan reloaded=Luduan reloaded + * Sandro Paniccia with boat Altair 3=Altair 3 + * Gianclaudio Bassetti with boat WB Seven=WB Seven + * SoLeVi Ltd / G. Petrochilos with boat Ex Officio=Ex Officio + * Markos Kashiouris / IRONFX Racing LTD with boat IRONFX=IRONFX + * Roberto Monti with boat Air is blue=Air is blue + * Valentin Zavadnikov with boat Synergy=Synergy + * Francesco Pison with boat Brava=Brava + * JK Orsan with boat Dubrovnik=Dubrovnik + */ + setFinishingTime("Air is blue", "2019-06-04T01:49:45+0200"); + setFinishingTime("XIO", "2019-06-04T01:44:45+0200"); + setFinishingTime("Generali (Assilina I", "2019-06-04T03:07:24+0200"); + setFinishingTime("Altair 3", "2019-06-04T04:22:50+0200"); + setFinishingTime("Synergy", "2019-06-04T03:57:06+0200"); + setFinishingTime("Ex Officio", "2019-06-04T07:13:07+0200"); + setFinishingTime("Luduan reloaded", "2019-06-04T08:10:43+0200"); + setFinishingTime("WB Seven", "2019-06-04T08:16:45+0200"); + setFinishingTime("Maestro", "2019-06-04T08:23:07+0200"); + setFinishingTime("IRONFX", "2019-06-04T07:15:36+0200"); + setFinishingTime("Dubrovnik", "2019-06-04T08:09:12+0200"); + setFinishingTime("Brava", "2019-06-04T07:54:14+0200"); + setFinishingTime("Alemaro", "2019-06-04T10:44:15+0200"); + raceLog.add(new RaceLogORCScratchBoatEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(), /* passId */ 0, getCompetitor("Air is blue"))); } + private void setFinishingTime(String boatName, String finishingTimeInISOFormat) throws ParseException { + final Competitor competitor = getCompetitor(boatName); + final TimePoint finishingTimePoint = new MillisecondsTimePoint(isoDateFormat.parse(finishingTimeInISOFormat)); + final CompetitorResultsImpl positionedCompetitors = new CompetitorResultsImpl(); + final CompetitorResult competitorResult = new CompetitorResultImpl( + competitor.getId(), competitor.getName(), competitor.getShortName(), boatName, + getTrackedRace().getBoatOfCompetitor(competitor).getSailID(), /* oneBasedRank==0 means let ranking metric decide */ 0, + /* maxPointsReason */ null, /* score */ null, finishingTimePoint, /* comment */ null, MergeState.OK); + positionedCompetitors.add(competitorResult); + final RaceLogEvent result = new RaceLogFinishPositioningConfirmedEventImpl(MillisecondsTimePoint.now(), author, /* passId */ 0, + positionedCompetitors); + raceLog.add(result); + } + @Test - public void testVadnaiLead() { - Competitor vadnai = getCompetitorByName("Benjamin Vadnai"); - Competitor lewis = getCompetitorByName("Andrew Lewis"); - Competitor lynch = getCompetitorByName("Finn Lynch"); - Competitor blanco = getCompetitorByName("Joaquín Blanco"); - assertEquals(1, getTrackedRace().getRank(vadnai, TIME_14_30_00)); - assertEquals(2, getTrackedRace().getRank(lewis, TIME_14_30_00)); - assertEquals(3, getTrackedRace().getRank(lynch, TIME_14_30_00)); - assertEquals(4, getTrackedRace().getRank(blanco, TIME_14_30_00)); - assertEquals(1, getTrackedRace().getRank(vadnai, TIME_14_30_12)); - assertEquals(2, getTrackedRace().getRank(lewis, TIME_14_30_12)); - assertEquals(3, getTrackedRace().getRank(lynch, TIME_14_30_12)); - assertEquals(4, getTrackedRace().getRank(blanco, TIME_14_30_12)); + public void testBasicRankingMetricProperties() { + final SecondsDurationImpl scratchBoatDuration = new SecondsDurationImpl(14*3600 + 49*60 + 45); + assertEquals(scratchBoatDuration.asSeconds(), + rankingMetric.getCorrectedTime(getCompetitor("Air is blue"), MillisecondsTimePoint.now()).asSeconds(), 0.000001); + assertEquals(scratchBoatDuration.plus(new SecondsDurationImpl(9*60 + 49)).asSeconds(), + rankingMetric.getCorrectedTime(getCompetitor("XIO"), MillisecondsTimePoint.now()).asSeconds(), 0.000001); + } + + private Competitor getCompetitor(String boatName) { + for (final Competitor competitor : getTrackedRace().getRace().getCompetitors()) { + final Boat boatOfCompetitor = getTrackedRace().getBoatOfCompetitor(competitor); + if (Util.equalsWithNull(boatOfCompetitor.getName(), boatName) || Util.equalsWithNull(boatOfCompetitor.getSailID(), boatName)) { + return competitor; + } + } + return null; } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificate.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificate.java deleted file mode 100644 index 18fa821a7a6..00000000000 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificate.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.sap.sailing.domain.orc; - -public class TestORCCertificate { - -} diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificateImporterJSON.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificateImporterJSON.java index 363871fadc8..65c4d797fe4 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificateImporterJSON.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificateImporterJSON.java @@ -22,15 +22,15 @@ public class TestORCCertificateImporterJSON { public void testSimpleLocalJSONFileRead() throws IOException, ParseException { File fileGER = new File(RESOURCES + "GER2019.json"); ORCCertificatesCollection importer = ORCCertificatesImporter.INSTANCE.read(new FileInputStream(fileGER)); - ORCCertificate milan = importer.getCertificate(" ger 7323"); + ORCCertificate milan = importer.getCertificateBySailNumber(" ger 7323"); assertNotNull(milan); } @Test public void testSimpleOnlineJSONFileRead() throws IOException, ParseException { ORCCertificatesCollection importer = ORCCertificatesImporter.INSTANCE.read(new URL("https://data.orc.org/public/WPub.dll?action=DownRMS&CountryId=GER&ext=json").openStream()); - ORCCertificate swan = importer.getCertificate(" GER 5335"); - ORCCertificate moana = importer.getCertificate("ger 55 49 "); + ORCCertificate swan = importer.getCertificateBySailNumber(" GER 5335"); + ORCCertificate moana = importer.getCertificateBySailNumber("ger 55 49 "); assertNotNull(swan); assertNotNull(moana); assertEquals(539.1, swan .getGPH(), 0.0000001); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificateImporterRMS.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificateImporterRMS.java index 2d8d38131df..52b7f9578c3 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificateImporterRMS.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCCertificateImporterRMS.java @@ -21,15 +21,15 @@ public class TestORCCertificateImporterRMS { public void testSimpleLocalRMSFileRead() throws IOException, ParseException { File fileGER = new File(RESOURCES + "GER2019.rms"); ORCCertificatesCollection certificates = ORCCertificatesImporter.INSTANCE.read(new FileInputStream(fileGER)); - ORCCertificate milan = certificates.getCertificate(" ger 7323"); + ORCCertificate milan = certificates.getCertificateBySailNumber(" ger 7323"); assertNotNull(milan); } @Test public void testSimpleOnlineRMSFileRead() throws IOException, ParseException { ORCCertificatesCollection importer = ORCCertificatesImporter.INSTANCE.read(new URL("https://data.orc.org/public/WPub.dll?action=DownRMS&CountryId=GER&ext=rms").openStream()); - ORCCertificate swan = importer.getCertificate(" GER 5335"); - ORCCertificate moana = importer.getCertificate("ger 55 49 "); + ORCCertificate swan = importer.getCertificateBySailNumber(" GER 5335"); + ORCCertificate moana = importer.getCertificateBySailNumber("ger 55 49 "); assertNotNull(swan); assertNotNull(moana); assertEquals(539.1, swan .getGPH(), 0.0000001); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCPerformanceCurve.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCPerformanceCurve.java index 2e5a5318c40..b76e2a32806 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCPerformanceCurve.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/TestORCPerformanceCurve.java @@ -84,31 +84,31 @@ public class TestORCPerformanceCurve { @Test public void testLagrangeInterpolation60() throws FunctionEvaluationException { - ORCCertificate certificate = importerLocal.getCertificate("GER 5549"); + ORCCertificate certificate = importerLocal.getCertificateBySailNumber("GER 5549"); testAllowancePerLeg(certificate, 60.0, 498.4); } @Test public void testLagrangeInterpolation62_5() throws FunctionEvaluationException { - ORCCertificate certificate = importerLocal.getCertificate("GER 5549"); + ORCCertificate certificate = importerLocal.getCertificateBySailNumber("GER 5549"); testAllowancePerLeg(certificate, 62.5, 492.2, 425.0, 403.6, 393.1, 386.7, 382.6, 371.4); } @Test public void testLagrangeInterpolation98_3() throws FunctionEvaluationException { - ORCCertificate certificate = importerLocal.getCertificate("GER 5549"); + ORCCertificate certificate = importerLocal.getCertificateBySailNumber("GER 5549"); testAllowancePerLeg(certificate, 98.3, 483.6, 418.7, 394.8, 377.9, 360.2, 345.0, 321.7); } @Test public void testLagrangeInterpolation120() throws FunctionEvaluationException { - ORCCertificate certificate = importerLocal.getCertificate("GER 5549"); + ORCCertificate certificate = importerLocal.getCertificateBySailNumber("GER 5549"); testAllowancePerLeg(certificate, 120.0, 506); } @Test public void testLagrangeInterpolation138_7() throws FunctionEvaluationException { - ORCCertificate certificate = importerLocal.getCertificate("GER 5549"); + ORCCertificate certificate = importerLocal.getCertificateBySailNumber("GER 5549"); testAllowancePerLeg(certificate, 138.7, 588.1, 468.4, 413.8, 382.6, 355.1, 326.4, 275.4); } @@ -123,7 +123,7 @@ public class TestORCPerformanceCurve { @Test public void testSimpleConstructedCourse() throws FunctionEvaluationException { - ORCCertificateImpl certificate = (ORCCertificateImpl) importerLocal.getCertificate("GER 5549"); + ORCCertificateImpl certificate = (ORCCertificateImpl) importerLocal.getCertificateBySailNumber("GER 5549"); List legs = new ArrayList<>(); legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.0), new DegreeBearingImpl(0))); legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.0), new DegreeBearingImpl(30))); @@ -146,7 +146,7 @@ public class TestORCPerformanceCurve { @Test public void testPerformanceCurveInversion() throws MaxIterationsExceededException, FunctionEvaluationException { Double accuracy = 0.1; - ORCCertificateImpl certificate = (ORCCertificateImpl) importerLocal.getCertificate("GER 5549"); + ORCCertificateImpl certificate = (ORCCertificateImpl) importerLocal.getCertificateBySailNumber("GER 5549"); ORCPerformanceCurveImpl performanceCurve = (ORCPerformanceCurveImpl) new ORCPerformanceCurveImpl(certificate, alturaCourse); testBackwardForward(accuracy, performanceCurve, 11.5); testBackwardForward(accuracy, performanceCurve, 17.23); @@ -175,12 +175,12 @@ public class TestORCPerformanceCurve { @Test public void testImpliedWind() throws MaxIterationsExceededException, FunctionEvaluationException { double accuracy = 0.0001; - ORCCertificate certificateMoana = importerLocal.getCertificate("GER 5549"); - ORCCertificate certificateMilan = importerLocal.getCertificate("GER 7323"); - ORCCertificate certificateTutima = importerLocal.getCertificate("GER 5609"); - ORCCertificate certificateBank = importerLocal.getCertificate("GER 5555"); - ORCCertificate certificateHaspa = importerLocal.getCertificate("GER 6300"); - ORCCertificate certificateHalbtrocken = importerLocal.getCertificate("GER 5564"); + ORCCertificate certificateMoana = importerLocal.getCertificateBySailNumber("GER 5549"); + ORCCertificate certificateMilan = importerLocal.getCertificateBySailNumber("GER 7323"); + ORCCertificate certificateTutima = importerLocal.getCertificateBySailNumber("GER 5609"); + ORCCertificate certificateBank = importerLocal.getCertificateBySailNumber("GER 5555"); + ORCCertificate certificateHaspa = importerLocal.getCertificateBySailNumber("GER 6300"); + ORCCertificate certificateHalbtrocken = importerLocal.getCertificateBySailNumber("GER 5564"); ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, alturaCourse); ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, alturaCourse); ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, alturaCourse); @@ -212,12 +212,12 @@ public class TestORCPerformanceCurve { @Test public void testAllowances() throws FunctionEvaluationException { double accuracy = 0.00001; - ORCCertificate certificateMoana = importerLocal.getCertificate("GER 5549"); - ORCCertificate certificateMilan = importerLocal.getCertificate("GER 7323"); - ORCCertificate certificateTutima = importerLocal.getCertificate("GER 5609"); - ORCCertificate certificateBank = importerLocal.getCertificate("GER 5555"); - ORCCertificate certificateHaspa = importerLocal.getCertificate("GER 6300"); - ORCCertificate certificateHalbtrocken = importerLocal.getCertificate("GER 5564"); + ORCCertificate certificateMoana = importerLocal.getCertificateBySailNumber("GER 5549"); + ORCCertificate certificateMilan = importerLocal.getCertificateBySailNumber("GER 7323"); + ORCCertificate certificateTutima = importerLocal.getCertificateBySailNumber("GER 5609"); + ORCCertificate certificateBank = importerLocal.getCertificateBySailNumber("GER 5555"); + ORCCertificate certificateHaspa = importerLocal.getCertificateBySailNumber("GER 6300"); + ORCCertificate certificateHalbtrocken = importerLocal.getCertificateBySailNumber("GER 5564"); ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, alturaCourse); ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, alturaCourse); ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, alturaCourse); @@ -235,12 +235,12 @@ public class TestORCPerformanceCurve { // Tests to make sure, that the structure of the certificate files didn't change and performance curves can be build @Test public void testOnlineImport() throws FunctionEvaluationException { - ORCCertificate certificateMoana = importerOnline.getCertificate("GER 5549"); - ORCCertificate certificateMilan = importerOnline.getCertificate("GER 7323"); - ORCCertificate certificateTutima = importerOnline.getCertificate("GER 5609"); - ORCCertificate certificateBank = importerOnline.getCertificate("GER 5555"); - ORCCertificate certificateHaspa = importerOnline.getCertificate("GER 6300"); - ORCCertificate certificateHalbtrocken = importerOnline.getCertificate("GER 5564"); + ORCCertificate certificateMoana = importerOnline.getCertificateBySailNumber("GER 5549"); + ORCCertificate certificateMilan = importerOnline.getCertificateBySailNumber("GER 7323"); + ORCCertificate certificateTutima = importerOnline.getCertificateBySailNumber("GER 5609"); + ORCCertificate certificateBank = importerOnline.getCertificateBySailNumber("GER 5555"); + ORCCertificate certificateHaspa = importerOnline.getCertificateBySailNumber("GER 6300"); + ORCCertificate certificateHalbtrocken = importerOnline.getCertificateBySailNumber("GER 5564"); new ORCPerformanceCurveImpl(certificateMoana, alturaCourse); new ORCPerformanceCurveImpl(certificateMilan, alturaCourse); new ORCPerformanceCurveImpl(certificateTutima, alturaCourse); @@ -262,12 +262,12 @@ public class TestORCPerformanceCurve { ORCPerformanceCurveCourse complexCourse = new ORCPerformanceCurveCourseImpl(list); double accuracy = 0.0001; - ORCCertificate certificateMoana = importerLocal.getCertificate("GER 5549"); - ORCCertificate certificateMilan = importerLocal.getCertificate("GER 7323"); - ORCCertificate certificateTutima = importerLocal.getCertificate("GER 5609"); - ORCCertificate certificateBank = importerLocal.getCertificate("GER 5555"); - ORCCertificate certificateHaspa = importerLocal.getCertificate("GER 6300"); - ORCCertificate certificateHalbtrocken = importerLocal.getCertificate("GER 5564"); + ORCCertificate certificateMoana = importerLocal.getCertificateBySailNumber("GER 5549"); + ORCCertificate certificateMilan = importerLocal.getCertificateBySailNumber("GER 7323"); + ORCCertificate certificateTutima = importerLocal.getCertificateBySailNumber("GER 5609"); + ORCCertificate certificateBank = importerLocal.getCertificateBySailNumber("GER 5555"); + ORCCertificate certificateHaspa = importerLocal.getCertificateBySailNumber("GER 6300"); + ORCCertificate certificateHalbtrocken = importerLocal.getCertificateBySailNumber("GER 5564"); ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, complexCourse); ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, complexCourse); ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, complexCourse); @@ -294,12 +294,12 @@ public class TestORCPerformanceCurve { ORCPerformanceCurveCourse complexCourse = new ORCPerformanceCurveCourseImpl(list); double accuracy = 0.00001; - ORCCertificate certificateMoana = importerLocal.getCertificate("GER 5549"); - ORCCertificate certificateMilan = importerLocal.getCertificate("GER 7323"); - ORCCertificate certificateTutima = importerLocal.getCertificate("GER 5609"); - ORCCertificate certificateBank = importerLocal.getCertificate("GER 5555"); - ORCCertificate certificateHaspa = importerLocal.getCertificate("GER 6300"); - ORCCertificate certificateHalbtrocken = importerLocal.getCertificate("GER 5564"); + ORCCertificate certificateMoana = importerLocal.getCertificateBySailNumber("GER 5549"); + ORCCertificate certificateMilan = importerLocal.getCertificateBySailNumber("GER 7323"); + ORCCertificate certificateTutima = importerLocal.getCertificateBySailNumber("GER 5609"); + ORCCertificate certificateBank = importerLocal.getCertificateBySailNumber("GER 5555"); + ORCCertificate certificateHaspa = importerLocal.getCertificateBySailNumber("GER 6300"); + ORCCertificate certificateHalbtrocken = importerLocal.getCertificateBySailNumber("GER 5564"); ORCPerformanceCurve performanceCurveMoana = new ORCPerformanceCurveImpl(certificateMoana, complexCourse); ORCPerformanceCurve performanceCurveMilan = new ORCPerformanceCurveImpl(certificateMilan, complexCourse); ORCPerformanceCurve performanceCurveTutima = new ORCPerformanceCurveImpl(certificateTutima, complexCourse); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java index 8165ff456cc..ac1f27a6259 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java @@ -31,6 +31,8 @@ import com.sap.sailing.domain.common.impl.DegreePosition; import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver; import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore; +import com.sap.sailing.domain.ranking.OneDesignRankingMetric; +import com.sap.sailing.domain.ranking.RankingMetricConstructor; import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore; import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet; import com.sap.sailing.domain.tracking.DynamicTrackedRace; @@ -116,7 +118,12 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest i protected void setUp(URL paramUrl, URI liveUri, URI storedUri, ReceiverType... receiverTypes) throws MalformedURLException, IOException, InterruptedException, URISyntaxException, SubscriberInitializationException, CreateModelException { - setUpWithoutLaunchingController(paramUrl, liveUri, storedUri); + setUp(paramUrl, liveUri, storedUri, OneDesignRankingMetric::new, receiverTypes); + } + + protected void setUp(URL paramUrl, URI liveUri, URI storedUri, RankingMetricConstructor rankingMetricConstructor, ReceiverType... receiverTypes) + throws MalformedURLException, IOException, InterruptedException, URISyntaxException, SubscriberInitializationException, CreateModelException { + setUpWithoutLaunchingController(paramUrl, liveUri, storedUri, rankingMetricConstructor); finishSetUp(receiverTypes); } @@ -246,7 +253,7 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest i final URI storedUri) throws MalformedURLException, FileNotFoundException, URISyntaxException, SubscriberInitializationException, CreateModelException { final URL paramUrl = getParamUrl(regattaName, raceId); - setUpWithoutLaunchingController(paramUrl, liveUri, storedUri); + setUpWithoutLaunchingController(paramUrl, liveUri, storedUri, OneDesignRankingMetric::new); } @@ -255,14 +262,14 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest i } - protected void setUpWithoutLaunchingController(final URL paramUrl, final URI liveUri, final URI storedUri) + protected void setUpWithoutLaunchingController(final URL paramUrl, final URI liveUri, final URI storedUri, RankingMetricConstructor rankingMetricConstructor) throws FileNotFoundException, MalformedURLException, URISyntaxException, SubscriberInitializationException, CreateModelException { super.setUp(paramUrl, liveUri, storedUri); if (domainFactory == null) { domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl((srlid)->null)); } domainEvent = domainFactory.getOrCreateDefaultRegatta(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, - getTracTracRace(), /* trackedRegattaRegistry */ null); + getTracTracRace(), /* trackedRegattaRegistry */ null, rankingMetricConstructor); trackedRegatta = new DynamicTrackedRegattaImpl(domainEvent); } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java index e59f4edb4b8..a5dbf23d937 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java @@ -30,6 +30,8 @@ import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver; import com.sap.sailing.domain.racelog.RaceLogStore; +import com.sap.sailing.domain.ranking.OneDesignRankingMetric; +import com.sap.sailing.domain.ranking.RankingMetricConstructor; import com.sap.sailing.domain.regattalog.RegattaLogStore; import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet; import com.sap.sailing.domain.tracking.DynamicTrackedRace; @@ -107,6 +109,13 @@ public interface DomainFactory { */ RaceDefinition getAndWaitForRaceDefinition(UUID raceId); + /** + * Calls {@link #getOrCreateDefaultRegatta(RaceLogStore, RegattaLogStore, IRace, TrackedRegattaRegistry, RankingMetricConstructor)} + * using {@link OneDesignRankingMetric} for the ranking metric constructor. + */ + com.sap.sailing.domain.base.Regatta getOrCreateDefaultRegatta(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, + IRace race, TrackedRegattaRegistry trackedRegattaRegistry); + /** * Creates an {@link com.sap.sailing.domain.base.Regatta event} from a * TracTrac event description. It doesn't have {@link RaceDefinition}s yet. @@ -114,9 +123,9 @@ public interface DomainFactory { * an equal name with a boat class with an equal name as the event's * boat class exists yet. */ - com.sap.sailing.domain.base.Regatta getOrCreateDefaultRegatta(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, - IRace race, TrackedRegattaRegistry trackedRegattaRegistry); - + Regatta getOrCreateDefaultRegatta(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, IRace race, + TrackedRegattaRegistry trackedRegattaRegistry, RankingMetricConstructor rankingMetricConstructor); + /** * Creates a race tracked for the specified URL/URIs and starts receiving all available existing and future push * data from there. Receiving continues until {@link TracTracRaceTracker#stop(boolean)} is called. diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java index 971487a53e3..b09579ca09c 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java @@ -62,6 +62,8 @@ import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.domain.racelog.RaceLogStore; +import com.sap.sailing.domain.ranking.OneDesignRankingMetric; +import com.sap.sailing.domain.ranking.RankingMetricConstructor; import com.sap.sailing.domain.regattalog.RegattaLogStore; import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet; import com.sap.sailing.domain.tracking.DynamicTrackedRace; @@ -439,6 +441,12 @@ public class DomainFactoryImpl implements DomainFactory { @Override public Regatta getOrCreateDefaultRegatta(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, IRace race, TrackedRegattaRegistry trackedRegattaRegistry) { + return getOrCreateDefaultRegatta(raceLogStore, regattaLogStore, race, trackedRegattaRegistry, OneDesignRankingMetric::new); + } + + @Override + public Regatta getOrCreateDefaultRegatta(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, + IRace race, TrackedRegattaRegistry trackedRegattaRegistry, RankingMetricConstructor rankingMetricConstructor) { synchronized (regattaCache) { // FIXME Dialog with Lasse by Skype on 2011-06-17: // [6:20:04 PM] Axel Uhl: Lasse, can Event.getCompetitorClassList() ever produce more than one result? @@ -471,6 +479,7 @@ public class DomainFactoryImpl implements DomainFactory { trackedRegattaRegistry, // use the low-point system as the default scoring scheme getBaseDomainFactory().createScoringScheme(ScoringSchemeType.LOW_POINT), race.getId(), null, + /* controlTrackingFromStartAndFinishTimes */ false, rankingMetricConstructor, /* registrationLinkSecret */ UUID.randomUUID().toString()); regattaCache.put(key, result); weakDefaultRegattaCache.put(race, result); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCCertificatesCollection.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCCertificatesCollection.java index 5b719e5a6c5..d5ad1ef33ca 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCCertificatesCollection.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCCertificatesCollection.java @@ -13,7 +13,7 @@ import com.sap.sailing.domain.common.orc.ORCCertificate; **/ public interface ORCCertificatesCollection { /** - * Tells the sail numbers that can be used as key in {@link #getCertificate(String)} and {@link #getCertificates(String[])} + * Tells the sail numbers that can be used as key in {@link #getCertificateBySailNumber(String)} and {@link #getCertificates(String[])} * and for which certificates are available in this object. */ Iterable getSailNumbers(); @@ -27,7 +27,13 @@ public interface ORCCertificatesCollection { * 'X41', ...) and a numerical identification code. * @return {@code null}, if there isn't any data for the given sailnumber. Otherwise an {@link ORCCertificate}. */ - ORCCertificate getCertificate(String sailnumber); + ORCCertificate getCertificateBySailNumber(String sailnumber); + + ORCCertificate getCertificateByBoatName(String boatName); + + Iterable getBoatNames(); + + Iterable getCertificates(); /** * Creates an {@link Map} of {@link ORCCertificate} objects to the given sail numbers. @@ -42,5 +48,4 @@ public interface ORCCertificatesCollection { * {@code null}, if there isn't any data for the given sailnumber. */ Map getCertificates(String[] sailnumbers); - } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/AbstractORCCertificatesCollection.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/AbstractORCCertificatesCollection.java index d757d9606b9..04088cc2fab 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/AbstractORCCertificatesCollection.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/AbstractORCCertificatesCollection.java @@ -1,6 +1,12 @@ package com.sap.sailing.domain.orc.impl; +import java.util.HashMap; +import java.util.Map; + +import com.sap.sailing.domain.common.orc.ORCCertificate; +import com.sap.sailing.domain.common.orc.impl.ORCCertificateImpl; import com.sap.sailing.domain.orc.ORCCertificatesCollection; +import com.sap.sse.common.Util; public abstract class AbstractORCCertificatesCollection implements ORCCertificatesCollection { @@ -11,6 +17,55 @@ public abstract class AbstractORCCertificatesCollection implements ORCCertificat * for a sail number is maximized, while still minimizing the chances for a false match. */ protected String getCanonicalizedSailNumber(String sailNumber) { - return sailNumber.replaceAll(" ", "").toUpperCase(); + return sailNumber.replaceAll(" ", "").replaceAll("-", "").toUpperCase(); } + + /** + * Only the first 16 characters after removing spaces and other special characters such as parentheses and dashes + * are compared case-insensitively. + */ + protected String getCanonicalizedBoatName(String boatName) { + final String replaced = boatName.toUpperCase().replaceAll("[^A-Z0-9]", ""); + return replaced.substring(0, Math.min(replaced.length(), 16)); + } + + /** + * Returns a {@link Map} of {@link ORCCertificateImpl} keyed by the {@link String} sailnumbers, which were given as + * an input inside an array. + */ + @Override + public Map getCertificates(String[] sailnumbers) { + Map result = new HashMap<>(); + for (String sailnumber : sailnumbers) { + result.put(sailnumber, getCertificateBySailNumber(sailnumber)); + } + return result; + } + + @Override + public ORCCertificate getCertificateByBoatName(String boatName) { + final String canonicalizedBoatNameToSearchFor = getCanonicalizedBoatName(boatName); + for (final ORCCertificate certificate : getCertificates()) { + if (canonicalizedBoatNameToSearchFor.equals(getCanonicalizedBoatName(certificate.getBoatName()))) { + return certificate; + } + } + return null; + } + + @Override + public Iterable getCertificates() { + return Util.map(getSailNumbers(), sailNumber->getCertificateBySailNumber(sailNumber)); + } + + @Override + public Iterable getBoatNames() { + return Util.map(getCertificates(), c->getCanonicalizedBoatName(c.getBoatName())); + } + + @Override + public String toString() { + return Util.joinStrings(", ", Util.map(getCertificates(), c->c.toString())); + } + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionJSON.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionJSON.java index cc80052c72f..df261a9efdc 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionJSON.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionJSON.java @@ -47,7 +47,12 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec public ORCCertificatesCollectionJSON(Map data) { this.data = new HashMap<>(); for (final Entry e : data.entrySet()) { - this.data.put(getCanonicalizedSailNumber(e.getKey()), e.getValue()); + if (this.data.put(getCanonicalizedSailNumber(e.getKey()), e.getValue()) != null) { + throw new IllegalArgumentException( + "Certificate sail numbers in collection not unique after canonicalization: " + e.getKey() + + " is canonicalized to " + getCanonicalizedSailNumber(e.getKey()) + + " for which a certificate is already in the collection."); + } } } @@ -56,7 +61,8 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec * given key, the method returns {@link null}. */ @Override - public ORCCertificate getCertificate(String sailnumber) { + public ORCCertificate getCertificateBySailNumber(String sailnumber) { + String boatName = null; String boatclass = null; Distance length = null; Duration gph = null; @@ -77,6 +83,9 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec case "LOA": length = new MeterDistance(((Number) entry.getValue()).doubleValue()); break; + case "YachtName": + boatName = entry.getValue().toString(); + break; case "Class": boatclass = (String) entry.getValue(); break; @@ -168,27 +177,12 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificateImpl.NAUTICAL_MILE .inTime(predefinedAllowanceDurationsPerTrueWindSpeed.get(NON_SPINNAKER).get(tws))); } - return new ORCCertificateImpl(searchString, boatclass, length, gph, cdl, - velocityPredictionPerTrueWindSpeedAndAngle, beatAngles, beatVMGPredictionPerTrueWindSpeed, - beatAllowancePerTrueWindSpeed, gybeAngles, runVMGPredictionPerTrueWindSpeed, - runAllowancePerTrueWindSpeed, windwardLeewardSpeedPredictionPerTrueWindSpeed, - longDistanceSpeedPredictionPerTrueWindSpeed, circularRandomSpeedPredictionPerTrueWindSpeed, - nonSpinnakerSpeedPredictionPerTrueWindSpeed); - } - - /** - * Returns a {@link Map} of {@link ORCCertificateImpl} keyed by the {@link String} sailnumbers, which were given as - * an input inside an array. - */ - @Override - public Map getCertificates(String[] sailnumbers) { - Map result = new HashMap<>(); - - for (String sailnumber : sailnumbers) { - result.put(sailnumber, getCertificate(sailnumber)); - } - - return result; + return new ORCCertificateImpl(searchString, boatName, boatclass, length, gph, + cdl, velocityPredictionPerTrueWindSpeedAndAngle, beatAngles, + beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, gybeAngles, + runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed, + windwardLeewardSpeedPredictionPerTrueWindSpeed, longDistanceSpeedPredictionPerTrueWindSpeed, + circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionRMS.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionRMS.java index ee659c0eb16..92f5bbe4490 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionRMS.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionRMS.java @@ -44,6 +44,7 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect private static final String GPH = "GPH"; private static final String LENGTH = "LOA"; private static final String BOATCLASS = "TYPE"; + private static final String BOATNAME = "NAME"; private static final String RUN_ALLOWANCE = "D"; private static final String RUN_ANGLE = "DA"; private static final String BEAT_ALLOWANCE = "UP"; @@ -79,16 +80,17 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect return Collections.unmodifiableSet(certificateValuesBySailnumber.keySet()); } - public ORCCertificateValues getValuesForSailnumber(String sailnumber) { + private ORCCertificateValues getValuesForSailnumber(String sailnumber) { String searchString = getCanonicalizedSailNumber(sailnumber); return certificateValuesBySailnumber.containsKey(searchString) ? new ORCCertificateValues(searchString) : null; } @Override - public ORCCertificate getCertificate(String sailnumber) { + public ORCCertificate getCertificateBySailNumber(String sailnumber) { String searchString = getCanonicalizedSailNumber(sailnumber); ORCCertificateValues certificateValues = getValuesForSailnumber(searchString); final String boatclass = certificateValues.getValue(BOATCLASS); + final String boatName = certificateValues.getValue(BOATNAME); final Distance length = new MeterDistance(Double.parseDouble(certificateValues.getValue(LENGTH))); final Duration gph = new SecondsDurationImpl(Double.parseDouble(certificateValues.getValue(GPH))); final Double cdl = Double.parseDouble(certificateValues.getValue(CDL)); @@ -135,21 +137,12 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect } velocityPredictionsPerTrueWindSpeedAndAngle.put(tws, velocityPredictionPerTrueWindAngle); } - return new ORCCertificateImpl(searchString, boatclass, length, gph, cdl, - velocityPredictionsPerTrueWindSpeedAndAngle, beatAngles, beatVMGPredictionPerTrueWindSpeed, - beatAllowancePerTrueWindSpeed, runAngles, runVMGPredictionPerTrueWindSpeed, - runAllowancePerTrueWindSpeed, windwardLeewardSpeedPredictionPerTrueWindSpeed, - longDistanceSpeedPredictionPerTrueWindSpeed, circularRandomSpeedPredictionPerTrueWindSpeed, - nonSpinnakerSpeedPredictionPerTrueWindSpeed); - } - - @Override - public Map getCertificates(String[] sailnumbers) { - Map result = new HashMap<>(); - for (String sailnumber : sailnumbers) { - result.put(sailnumber, getCertificate(sailnumber)); - } - return result; + return new ORCCertificateImpl(searchString, boatName, boatclass, length, gph, + cdl, velocityPredictionsPerTrueWindSpeedAndAngle, beatAngles, + beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles, + runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed, + windwardLeewardSpeedPredictionPerTrueWindSpeed, longDistanceSpeedPredictionPerTrueWindSpeed, + circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveRankingMetric.java index db87186a7ce..c55b1766409 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveRankingMetric.java @@ -32,7 +32,9 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor; import com.sap.sailing.domain.abstractlog.regatta.impl.BaseRegattaLogEventVisitor; import com.sap.sailing.domain.base.Boat; import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.CourseListener; import com.sap.sailing.domain.base.Leg; +import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.orc.ORCCertificate; import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse; @@ -129,6 +131,17 @@ public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric { updateScratchBoatFromLogs(); } }); + trackedRace.getRace().getCourse().addCourseListener(new CourseListener() { + @Override + public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) { + updateCourseFromRaceLogs(); + } + + @Override + public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) { + updateCourseFromRaceLogs(); + } + }); } } @@ -172,8 +185,15 @@ public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric { public void visit(RaceLogRevokeEvent event) { if (event.getRevokedEventType().equals(RaceLogORCLegDataEventImpl.class.getName())) { updateCourseFromRaceLogs(); + } else if (event.getRevokedEventType().equals(RaceLogORCLegDataEventImpl.class.getName())) { + updateScratchBoatFromLogs(); } } + + @Override + public void visit(RaceLogORCScratchBoatEvent event) { + updateScratchBoatFromLogs(); + } }; } diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingRegattaORCCertificateAssignmengtEvent.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingRegattaORCCertificateAssignmengtEvent.java index 902b96c1964..1b679530d5b 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingRegattaORCCertificateAssignmengtEvent.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingRegattaORCCertificateAssignmengtEvent.java @@ -87,7 +87,7 @@ public class TestStoringAndLoadingRegattaORCCertificateAssignmengtEvent extends @Test public void test() throws JsonDeserializationException, ParseException { RaceLogORCCertificateAssignmentEvent expectedEvent = new RaceLogORCCertificateAssignmentEventImpl(MillisecondsTimePoint.now(), expectedEventTime, author, - expectedId, expectedPassId, importer.getCertificate("GER 5549"), boat); + expectedId, expectedPassId, importer.getCertificateBySailNumber("GER 5549"), boat); Document dbObject = mongoFactory.storeRaceLogEntry(logIdentifier, expectedEvent); RaceLogORCCertificateAssignmentEvent actualEvent = loadEvent(dbObject); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingRegattaORCCertificateAssignmentEvent.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingRegattaORCCertificateAssignmentEvent.java index baed096df8e..79cefd786de 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingRegattaORCCertificateAssignmentEvent.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingRegattaORCCertificateAssignmentEvent.java @@ -83,7 +83,7 @@ public class TestStoringAndLoadingRegattaORCCertificateAssignmentEvent extends A @Test public void test() throws JsonDeserializationException, ParseException { RaceLogORCCertificateAssignmentEvent expectedEvent = new RaceLogORCCertificateAssignmentEventImpl(MillisecondsTimePoint.now(), expectedEventTime, author, - expectedId, expectedPassId, importer.getCertificate("GER 5549"), competitor); + expectedId, expectedPassId, importer.getCertificateBySailNumber("GER 5549"), competitor); Document dbObject = mongoFactory.storeRaceLogEntry(logIdentifier, expectedEvent); RaceLogORCCertificateAssignmentEvent actualEvent = loadEvent(dbObject); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/ORCCertificateJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/ORCCertificateJsonDeserializer.java index cd366ba9a40..4fe2cb0a8b2 100755 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/ORCCertificateJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/ORCCertificateJsonDeserializer.java @@ -24,6 +24,7 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer