added tests for RaceLog-based ORC PCS leg definitions

Change-Id: Iddb5c41079fea3de8428f45597a6d79f8d02bee4
This commit is contained in:
Axel Uhl committed 2019-09-13 16:03:00 +02:00
1 parent a34966fc75
commit f00585d4cd
14 files changed
+279 -47

No files matched your search

@@ -22,7 +22,8 @@ public interface ORCPerformanceCurveCourse {
/** /**
* @return summed up {@link Distance} of all {@link ORCPerformanceCurveLeg}s of an implementing instance of this * @return summed up {@link Distance} of all {@link ORCPerformanceCurveLeg}s of an implementing instance of this
* class * class; {@code null} in case the length currently cannot be determined, e.g., because no explicit lengths
* have been set and the positions of one or more waypoints are unknown.
*/ */
default Distance getTotalLength() { default Distance getTotalLength() {
Distance result = Distance.NULL; Distance result = Distance.NULL;
@@ -1,50 +1,40 @@
package com.sap.sailing.domain.common.orc.impl; package com.sap.sailing.domain.common.orc.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse; import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg; import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg;
import com.sap.sse.common.Distance; import com.sap.sse.common.Util;
public class ORCPerformanceCurveCourseImpl implements ORCPerformanceCurveCourse { public class ORCPerformanceCurveCourseImpl implements ORCPerformanceCurveCourse {
private final List<ORCPerformanceCurveLeg> legs; private final Iterable<ORCPerformanceCurveLeg> legs;
private final Distance totalLength;
public ORCPerformanceCurveCourseImpl(List<ORCPerformanceCurveLeg> legs) { public ORCPerformanceCurveCourseImpl(Iterable<ORCPerformanceCurveLeg> legs) {
this.legs = Collections.unmodifiableList(legs); this.legs = legs;
Distance myTotalLength = Distance.NULL;
for (ORCPerformanceCurveLeg leg : legs) {
myTotalLength = myTotalLength.add(leg.getLength());
}
totalLength = myTotalLength;
}
public ORCPerformanceCurveLeg getLeg(int i) {
return legs.get(i);
} }
@Override @Override
public Distance getTotalLength() { public Iterable<ORCPerformanceCurveLeg> getLegs() {
return totalLength;
}
@Override
public List<ORCPerformanceCurveLeg> getLegs() {
return legs; return legs;
} }
@Override @Override
public ORCPerformanceCurveCourse subcourse(int lastFinishedLegOneBased, double shareOfCurrentLeg) { public ORCPerformanceCurveCourse subcourse(int lastFinishedLegOneBased, double shareOfCurrentLeg) {
// does function for empty courses, returns again empty course // does function for empty courses, returns again empty course
if (lastFinishedLegOneBased >= legs.size()) { if (lastFinishedLegOneBased >= Util.size(legs)) {
return this; return this;
} else { } else {
List<ORCPerformanceCurveLeg> resultLegs = new ArrayList<>(); List<ORCPerformanceCurveLeg> resultLegs = new ArrayList<>();
resultLegs.addAll(legs.subList(0, lastFinishedLegOneBased)); int count = 0;
ORCPerformanceCurveLeg lastFinishedLeg = legs.get(lastFinishedLegOneBased); ORCPerformanceCurveLeg lastFinishedLeg = null;
for (final ORCPerformanceCurveLeg leg : getLegs()) {
if (count++ >= lastFinishedLegOneBased) {
lastFinishedLeg = leg;
break;
}
resultLegs.add(leg);
}
resultLegs.add(lastFinishedLeg.scale(shareOfCurrentLeg)); resultLegs.add(lastFinishedLeg.scale(shareOfCurrentLeg));
return new ORCPerformanceCurveCourseImpl(resultLegs); return new ORCPerformanceCurveCourseImpl(resultLegs);
} }
@@ -52,6 +42,6 @@ public class ORCPerformanceCurveCourseImpl implements ORCPerformanceCurveCourse
@Override @Override
public String toString() { public String toString() {
return "[legs=" + legs + ", totalLength=" + totalLength + "]"; return "[legs=" + legs + ", totalLength=" + getTotalLength().getNauticalMiles() + "NM]";
} }
} }
@@ -41,7 +41,7 @@ public class ORCPerformanceCurveLegImpl implements ORCPerformanceCurveLeg {
@Override @Override
public String toString() { public String toString() {
return "[length=" + length.getNauticalMiles() + "NM, "+(twa==null?type.name():"TWA=" + twa.getDegrees() + "°")+"]"; return "[length=" + length.getNauticalMiles() + "NM, "+(twa==null?type.name():"TWA=" + twa)+"]";
} }
@Override @Override
@@ -1019,7 +1019,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
Document result = new Document(); Document result = new Document();
storeRaceLogEventProperties(event, result); storeRaceLogEventProperties(event, result);
result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogORCLegDataEvent.class.getSimpleName()); result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogORCLegDataEvent.class.getSimpleName());
result.put(FieldNames.ORC_LEG_NR.name(), event.getLegNr()); result.put(FieldNames.ORC_LEG_NR.name(), event.getOneBasedLegNumber());
result.put(FieldNames.ORC_LEG_LENGTH_IN_NAUTICAL_MILES.name(), event.getLength().getNauticalMiles()); result.put(FieldNames.ORC_LEG_LENGTH_IN_NAUTICAL_MILES.name(), event.getLength().getNauticalMiles());
result.put(FieldNames.ORC_LEG_TWA_IN_DEG.name(), event.getTwa().getDegrees()); result.put(FieldNames.ORC_LEG_TWA_IN_DEG.name(), event.getTwa().getDegrees());
result.put(FieldNames.ORC_LEG_TYPE.name(), event.getType().name()); result.put(FieldNames.ORC_LEG_TYPE.name(), event.getType().name());
@@ -25,7 +25,7 @@ public interface RevokeEvent<VisitorT> extends AbstractLogEvent<VisitorT> {
String getReason(); String getReason();
/** /**
* {@link Class#getSimpleName() Simple class name} of the revoked event. * {@link Class#getName() Fully-qualified class name} of the revoked event.
*/ */
String getRevokedEventType(); String getRevokedEventType();
} }
@@ -12,10 +12,10 @@ import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveLegImpl;
import com.sap.sse.common.Distance; import com.sap.sse.common.Distance;
/** /**
* Returns a map with unique entries per {@link RaceLogORCLegDataEvent#getLegNr() leg number} where the * Returns a map with unique entries per {@link RaceLogORCLegDataEvent#getOneBasedLegNumber() one-based leg number}
* relevant valid leg data is converted to the {@link ORCPerformanceCurveLeg} data. Note that for legs * where the relevant valid leg data is converted to the {@link ORCPerformanceCurveLeg} data. Note that for legs for
* for which no entry is found no adapter to any tracked race or tracked leg is created implicitly. Only * which no entry is found no adapter to any tracked race or tracked leg is created implicitly. Only entries with
* entries with explicit race log events are returned. * explicit race log events are returned.
* *
* @author Axel Uhl (D043530) * @author Axel Uhl (D043530)
* *
@@ -40,7 +40,7 @@ public class RaceLogORCLegDataAnalyzer extends RaceLogAnalyzer<Map<Integer, ORCP
} else { } else {
leg = new ORCPerformanceCurveLegImpl(length, legDataEvent.getType()); leg = new ORCPerformanceCurveLegImpl(length, legDataEvent.getType());
} }
result.put(legDataEvent.getLegNr(), leg); result.put(legDataEvent.getOneBasedLegNumber(), leg);
} }
} }
return result; return result;
@@ -23,6 +23,6 @@ public interface RaceLogORCLegDataEvent extends RaceLogEvent, Revokable {
public Bearing getTwa(); public Bearing getTwa();
public int getLegNr(); public int getOneBasedLegNumber();
} }
@@ -15,15 +15,15 @@ public class RaceLogORCLegDataEventImpl extends RaceLogEventImpl implements Race
private static final long serialVersionUID = -5063350268001993185L; private static final long serialVersionUID = -5063350268001993185L;
private final int legNr; private final int oneBasedLegNumber;
private final Bearing twa; private final Bearing twa;
private final Distance length; private final Distance length;
private final ORCPerformanceCurveLegTypes type; private final ORCPerformanceCurveLegTypes type;
public RaceLogORCLegDataEventImpl(TimePoint createdAt, TimePoint logicalTimePoint, AbstractLogEventAuthor author, public RaceLogORCLegDataEventImpl(TimePoint createdAt, TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Serializable pId, int pPassId, int legNr, Bearing twa, Distance length, ORCPerformanceCurveLegTypes type) { Serializable pId, int pPassId, int oneBasedLegNumber, Bearing twa, Distance length, ORCPerformanceCurveLegTypes type) {
super(createdAt, logicalTimePoint, author, pId, pPassId); super(createdAt, logicalTimePoint, author, pId, pPassId);
this.legNr = legNr; this.oneBasedLegNumber = oneBasedLegNumber;
this.twa = twa; this.twa = twa;
this.length = length; this.length = length;
this.type = type; this.type = type;
@@ -36,12 +36,12 @@ public class RaceLogORCLegDataEventImpl extends RaceLogEventImpl implements Race
@Override @Override
public String getShortInfo() { public String getShortInfo() {
return "ORCLegData, legNr= " + legNr + ", twa: " + twa.getDegrees() + ", length: " + length.getNauticalMiles(); return "ORCLegData, oneBasedLegNumber= " + oneBasedLegNumber + ", twa: " + twa.getDegrees() + ", length: " + length.getNauticalMiles();
} }
@Override @Override
public int getLegNr() { public int getOneBasedLegNumber() {
return legNr; return oneBasedLegNumber;
} }
@Override @Override
@@ -0,0 +1,211 @@
package com.sap.sailing.domain.orc;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.util.Map;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCCertificateAssignmentEvent;
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataEvent;
import com.sap.sailing.domain.abstractlog.orc.RegattaLogORCCertificateAssignmentEvent;
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCCertificateAssignmentEventImpl;
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCLegDataEventImpl;
import com.sap.sailing.domain.abstractlog.orc.impl.RegattaLogORCCertificateAssignmentEventImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
import com.sap.sailing.domain.common.orc.ORCCertificate;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLegTypes;
import com.sap.sailing.domain.orc.impl.ORCPerformanceCurveLegAdapter;
import com.sap.sailing.domain.orc.impl.ORCPerformanceCurveRankingMetric;
import com.sap.sailing.domain.test.TrackBasedTest;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.DegreeBearingImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
/**
* An {@link ORCPerformanceCurveRankingMetric} observes its {@link TrackedRace} for the regatta log
* and the race logs, regarding the attachment and detachment of such logs, as well as regarding
* the appearance of new certificate assignment events in those logs. This test verifies that
* the dynamics work as expected.
*
* @author Axel Uhl (d043530)
*
*/
public class TestORCRankingMetricCollaborationWithRaceLogAndRegattaLog {
private Boat boat1, boat2;
private CompetitorWithBoat competitor1, competitor2;
private DynamicTrackedRaceImpl trackedRace;
private RaceLog raceLog;
private RegattaLog regattaLog;
private ORCPerformanceCurveRankingMetric rankingMetric;
private AbstractLogEventAuthor authorP1 = new LogEventAuthorImpl("Test Author P1", 1);
private AbstractLogEventAuthor authorP2 = new LogEventAuthorImpl("Test Author P2", 2);
@Before
public void setUp() {
final RaceLogResolver raceLogResolver = createRaceLogResolver();
competitor1 = TrackBasedTest.createCompetitorWithBoat("C1");
competitor2 = TrackBasedTest.createCompetitorWithBoat("C2");
final Map<Competitor, Boat> competitorsAndBoats = TrackBasedTest.createCompetitorAndBoatsMap(competitor1, competitor2);
boat1 = competitorsAndBoats.get(competitor1);
boat2 = competitorsAndBoats.get(competitor2);
trackedRace = TrackBasedTest.createTestTrackedRace("TestRegatta", "TestRace", "F18", competitorsAndBoats,
MillisecondsTimePoint.now(), /* useMarkPassingCalculator */ false, raceLogResolver, ORCPerformanceCurveRankingMetric::new);
regattaLog = trackedRace.getTrackedRegatta().getRegatta().getRegattaLog();
trackedRace.attachRegattaLog(regattaLog);
assertSame(regattaLog, trackedRace.getAttachedRegattaLogs().iterator().next());
raceLog = new RaceLogImpl(UUID.randomUUID());
rankingMetric = (ORCPerformanceCurveRankingMetric) trackedRace.getRankingMetric();
}
private void attachRaceLog() {
trackedRace.attachRaceLog(raceLog);
}
private RaceLogResolver createRaceLogResolver() {
return new RaceLogResolver() {
@Override
public RaceLog resolve(SimpleRaceLogIdentifier identifier) {
return null;
}
};
}
@Test
public void testCertificateAssignments() {
// no logs attached; therefore no certs
assertNoCertificate(boat1);
assertNoCertificate(boat2);
attachRaceLog();
// empty race log attached, still no certs:
assertNoCertificate(boat1);
assertNoCertificate(boat2);
ORCCertificate boat1RegattaCert1 = mock(ORCCertificate.class);
regattaLog.add(createRegattaLogCertificateAssignmentEvent(boat1RegattaCert1, boat1, authorP1));
assertCertificate(boat1, boat1RegattaCert1);
ORCCertificate boat1RegattaCert2 = mock(ORCCertificate.class);
regattaLog.add(createRegattaLogCertificateAssignmentEvent(boat1RegattaCert2, boat1, authorP2));
// the priority for Cert2 was 2 and therefore the P1 assignment still takes precedence
assertCertificate(boat1, boat1RegattaCert1);
regattaLog.add(createRegattaLogCertificateAssignmentEvent(boat1RegattaCert2, boat1, authorP1));
assertCertificate(boat1, boat1RegattaCert2);
ORCCertificate boat2RegattaCert1 = mock(ORCCertificate.class);
regattaLog.add(createRegattaLogCertificateAssignmentEvent(boat2RegattaCert1, boat2, authorP2));
assertCertificate(boat2, boat2RegattaCert1);
// now override on race log level:
ORCCertificate boat1RaceCert1 = mock(ORCCertificate.class);
raceLog.add(createRaceLogCertificateAssignmentEvent(boat1RaceCert1, boat1, authorP2));
assertCertificate(boat1, boat1RaceCert1);
trackedRace.detachRaceLog(raceLog.getId());
// after detaching race log, boat1 must have defaulted again to the regatta log's definition
assertCertificate(boat1, boat1RegattaCert2);
}
@Test
public void testNoCourseDefinitionsInRaceLog() {
final ORCPerformanceCurveCourse orcCourse = rankingMetric.getTotalCourse();
assertEquals(trackedRace.getRace().getCourse().getLegs().size(), Util.size(orcCourse.getLegs()));
for (final ORCPerformanceCurveLeg leg : orcCourse.getLegs()) {
assertTrue(leg instanceof ORCPerformanceCurveLegAdapter); // only adapters, no explicit leg specification yet
}
}
@Test
public void testOneLegDefinitionInRaceLog() throws NotRevokableException {
attachRaceLog();
final double lengthInNauticalMiles = 1.7;
final double twaInDegrees = 2.0;
final RaceLogORCLegDataEvent firstLegSpecificationEvent = createLegSpecificationEvent(
/* one-based leg number */ 1, ORCPerformanceCurveLegTypes.TWA, /* distance in nautical miles */ lengthInNauticalMiles,
/* TWA */ twaInDegrees, authorP2);
raceLog.add(firstLegSpecificationEvent);
final ORCPerformanceCurveCourse orcCourse = rankingMetric.getTotalCourse();
assertEquals(trackedRace.getRace().getCourse().getLegs().size(), Util.size(orcCourse.getLegs()));
final ORCPerformanceCurveLeg firstLeg = orcCourse.getLegs().iterator().next();
assertFalse(firstLeg instanceof ORCPerformanceCurveLegAdapter);
assertEquals(lengthInNauticalMiles, firstLeg.getLength().getNauticalMiles(), 0.000001);
assertEquals(twaInDegrees, firstLeg.getTwa().getDegrees(), 0.0000001);
// now revoke event and ensure that the course defaults back to all adapters:
raceLog.revokeEvent(authorP2, firstLegSpecificationEvent);
assertEquals(trackedRace.getRace().getCourse().getLegs().size(), Util.size(rankingMetric.getTotalCourse().getLegs()));
for (final ORCPerformanceCurveLeg leg : rankingMetric.getTotalCourse().getLegs()) {
assertTrue(leg instanceof ORCPerformanceCurveLegAdapter); // only adapters, no explicit leg specification anymore
}
}
@Test
public void testHigherPriorityLegDefinitionInRaceLogWins() throws NotRevokableException {
attachRaceLog();
final double lengthInNauticalMiles = 1.7;
final double twaP1InDegrees = 1.0;
final double twaP2InDegrees = 2.0;
final RaceLogORCLegDataEvent firstLegP2SpecificationEvent = createLegSpecificationEvent(
/* one-based leg number */ 1, ORCPerformanceCurveLegTypes.TWA, /* distance in nautical miles */ lengthInNauticalMiles,
/* TWA */ twaP2InDegrees, authorP2);
raceLog.add(firstLegP2SpecificationEvent);
final RaceLogORCLegDataEvent firstLegP1SpecificationEvent = createLegSpecificationEvent(
/* one-based leg number */ 1, ORCPerformanceCurveLegTypes.TWA, /* distance in nautical miles */ lengthInNauticalMiles,
/* TWA */ twaP1InDegrees, authorP1);
raceLog.add(firstLegP1SpecificationEvent);
final ORCPerformanceCurveCourse orcCourse = rankingMetric.getTotalCourse();
assertEquals(trackedRace.getRace().getCourse().getLegs().size(), Util.size(orcCourse.getLegs()));
final ORCPerformanceCurveLeg firstLeg = orcCourse.getLegs().iterator().next();
assertFalse(firstLeg instanceof ORCPerformanceCurveLegAdapter);
assertEquals(lengthInNauticalMiles, firstLeg.getLength().getNauticalMiles(), 0.000001);
assertEquals(twaP1InDegrees, firstLeg.getTwa().getDegrees(), 0.0000001);
// now revoke P1 event and ensure that the course defaults to the P2 definition:
raceLog.revokeEvent(authorP1, firstLegP1SpecificationEvent);
assertEquals(trackedRace.getRace().getCourse().getLegs().size(), Util.size(rankingMetric.getTotalCourse().getLegs()));
assertEquals(twaP2InDegrees, rankingMetric.getTotalCourse().getLegs().iterator().next().getTwa().getDegrees(), 0.0000001);
}
private RaceLogORCLegDataEvent createLegSpecificationEvent(int oneBasedLegNumber,
ORCPerformanceCurveLegTypes legType, double lengthInNauticalMiles, double twaInDegrees,
AbstractLogEventAuthor author) {
return new RaceLogORCLegDataEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author,
UUID.randomUUID(), /* pass */ 0, oneBasedLegNumber, new DegreeBearingImpl(twaInDegrees),
new NauticalMileDistance(lengthInNauticalMiles), legType);
}
private RaceLogORCCertificateAssignmentEvent createRaceLogCertificateAssignmentEvent(
ORCCertificate certificate, Boat boat, AbstractLogEventAuthor author) {
return new RaceLogORCCertificateAssignmentEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(), /* pass */ 0, certificate, boat);
}
private RegattaLogORCCertificateAssignmentEvent createRegattaLogCertificateAssignmentEvent(
ORCCertificate certificate, Boat boat, AbstractLogEventAuthor author) {
return new RegattaLogORCCertificateAssignmentEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(), certificate, boat);
}
private void assertNoCertificate(Boat boat) {
final ORCCertificate certificate = rankingMetric.getCertificate(boat);
assertNull(certificate);
}
private void assertCertificate(Boat boat, ORCCertificate expectedCertificate) {
final ORCCertificate certificate = rankingMetric.getCertificate(boat);
assertSame(expectedCertificate, certificate);
}
}
@@ -50,4 +50,9 @@ public class ORCPerformanceCurveLegAdapter implements ORCPerformanceCurveLeg {
} }
}; };
} }
@Override
public String toString() {
return "ORCPerformanceCurveLegAdapter for "+trackedLeg.getLeg()+": length="+getLength().getNauticalMiles()+"NM, TWA="+getTwa();
}
} }
@@ -1,8 +1,10 @@
package com.sap.sailing.domain.orc.impl; package com.sap.sailing.domain.orc.impl;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -13,8 +15,10 @@ import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataAnalyzer;
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataEvent; import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataEvent;
import com.sap.sailing.domain.abstractlog.orc.RegattaLogORCCertificateAssignmentEvent; import com.sap.sailing.domain.abstractlog.orc.RegattaLogORCCertificateAssignmentEvent;
import com.sap.sailing.domain.abstractlog.orc.RegattaLogORCCertificateAssignmentFinder; import com.sap.sailing.domain.abstractlog.orc.RegattaLogORCCertificateAssignmentFinder;
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCLegDataEventImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor; import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor; import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
@@ -27,6 +31,7 @@ import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.orc.ORCCertificate; import com.sap.sailing.domain.common.orc.ORCCertificate;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse; import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg; import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg;
import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveCourseImpl;
import com.sap.sailing.domain.ranking.AbstractRankingMetric; import com.sap.sailing.domain.ranking.AbstractRankingMetric;
import com.sap.sailing.domain.ranking.RankingMetric; import com.sap.sailing.domain.ranking.RankingMetric;
import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLeg;
@@ -37,6 +42,7 @@ import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
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.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric { public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric {
private static final long serialVersionUID = -7814822523533929816L; private static final long serialVersionUID = -7814822523533929816L;
@@ -62,6 +68,7 @@ public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric {
super(trackedRace); super(trackedRace);
boatsById = initBoatsById(); boatsById = initBoatsById();
updateCertificatesFromLogs(); updateCertificatesFromLogs();
updateCourseFromRaceLogs();
certificatesFromRaceLogUpdater = createCertificatesFromRaceLogUpdater(); certificatesFromRaceLogUpdater = createCertificatesFromRaceLogUpdater();
certificatesFromRegattaLogUpdater = createCertificatesFromRegattaLogUpdater(); certificatesFromRegattaLogUpdater = createCertificatesFromRegattaLogUpdater();
if (trackedRace != null) { if (trackedRace != null) {
@@ -101,13 +108,20 @@ public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric {
return new BaseRaceLogEventVisitor() { return new BaseRaceLogEventVisitor() {
@Override @Override
public void visit(RaceLogORCLegDataEvent orcLegDataEventImpl) { public void visit(RaceLogORCLegDataEvent orcLegDataEventImpl) {
updateCertificatesFromLogs(); updateCourseFromRaceLogs();
} }
@Override @Override
public void visit(RaceLogORCCertificateAssignmentEvent event) { public void visit(RaceLogORCCertificateAssignmentEvent event) {
updateCertificatesFromLogs(); updateCertificatesFromLogs();
} }
@Override
public void visit(RaceLogRevokeEvent event) {
if (event.getRevokedEventType().equals(RaceLogORCLegDataEventImpl.class.getName())) {
updateCourseFromRaceLogs();
}
}
}; };
} }
@@ -143,7 +157,18 @@ public class ORCPerformanceCurveRankingMetric extends AbstractRankingMetric {
for (final RaceLog raceLog : getTrackedRace().getAttachedRaceLogs()) { for (final RaceLog raceLog : getTrackedRace().getAttachedRaceLogs()) {
legsWithDefinitions.putAll(new RaceLogORCLegDataAnalyzer(raceLog).analyze()); legsWithDefinitions.putAll(new RaceLogORCLegDataAnalyzer(raceLog).analyze());
} }
// TODO continue here, taking only those definitions up to the true number of legs in the race's course and fill the blanks with tracked leg adapters final Iterable<Leg> legs = getTrackedRace().getRace().getCourse().getLegs();
int oneBasedLegNumber = 1;
final List<ORCPerformanceCurveLeg> performanceCurveLegs = new ArrayList<>(Util.size(legs));
for (final Leg leg : legs) {
performanceCurveLegs.add(legsWithDefinitions.computeIfAbsent(oneBasedLegNumber, i->new ORCPerformanceCurveLegAdapter(getTrackedRace().getTrackedLeg(leg))));
oneBasedLegNumber++;
}
totalCourse = new ORCPerformanceCurveCourseImpl(performanceCurveLegs);
}
public ORCPerformanceCurveCourse getTotalCourse() {
return totalCourse;
} }
@Override @Override
@@ -445,7 +445,6 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
RaceLogResolver raceLogResolver) { RaceLogResolver raceLogResolver) {
super(race, trackedRegatta, windStore, millisecondsOverWhichToAverageWind); super(race, trackedRegatta, windStore, millisecondsOverWhichToAverageWind);
this.raceLogResolver = raceLogResolver; this.raceLogResolver = raceLogResolver;
rankingMetric = rankingMetricConstructor.apply(this);
raceStates = new WeakHashMap<>(); raceStates = new WeakHashMap<>();
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2); shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
locksForMarkPassings = new ConcurrentHashMap<IdentityWrapper<Iterable<MarkPassing>>, NamedReentrantReadWriteLock>(); locksForMarkPassings = new ConcurrentHashMap<IdentityWrapper<Iterable<MarkPassing>>, NamedReentrantReadWriteLock>();
@@ -579,6 +578,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.log(Level.SEVERE, "Waiting for loading from stores to finish was interrupted", e); logger.log(Level.SEVERE, "Waiting for loading from stores to finish was interrupted", e);
} }
rankingMetric = rankingMetricConstructor.apply(this);
} }
@Override @Override
@@ -29,7 +29,7 @@ public class RaceLogORCLegDataEventSerializer extends BaseRaceLogEventSerializer
public JSONObject serialize(RaceLogEvent object) { public JSONObject serialize(RaceLogEvent object) {
RaceLogORCLegDataEvent legData = (RaceLogORCLegDataEvent) object; RaceLogORCLegDataEvent legData = (RaceLogORCLegDataEvent) object;
JSONObject result = super.serialize(legData); JSONObject result = super.serialize(legData);
result.put(ORC_LEG_NR, legData.getLegNr()); result.put(ORC_LEG_NR, legData.getOneBasedLegNumber());
result.put(ORC_LEG_LENGTH, legData.getLength().getNauticalMiles()); result.put(ORC_LEG_LENGTH, legData.getLength().getNauticalMiles());
result.put(ORC_LEG_TWA, legData.getTwa().getDegrees()); result.put(ORC_LEG_TWA, legData.getTwa().getDegrees());
result.put(ORC_LEG_TYPE, legData.getType().name()); result.put(ORC_LEG_TYPE, legData.getType().name());
@@ -101,7 +101,7 @@ public class RaceLogEventDeserializerTest {
assertEquals(originalEvent.getClass(), newEvent.getClass()); assertEquals(originalEvent.getClass(), newEvent.getClass());
assertEquals(originalEvent.getId(), newEvent.getId()); assertEquals(originalEvent.getId(), newEvent.getId());
assertEquals(originalEvent.getShortInfo(), newEvent.getShortInfo()); assertEquals(originalEvent.getShortInfo(), newEvent.getShortInfo());
assertEquals(originalEvent.getLegNr(), newEvent.getLegNr()); assertEquals(originalEvent.getOneBasedLegNumber(), newEvent.getOneBasedLegNumber());
assertEquals(originalEvent.getTwa(), newEvent.getTwa()); assertEquals(originalEvent.getTwa(), newEvent.getTwa());
assertEquals(originalEvent.getType(), newEvent.getType()); assertEquals(originalEvent.getType(), newEvent.getType());
assertEquals(originalEvent.getLength(), newEvent.getLength()); assertEquals(originalEvent.getLength(), newEvent.getLength());