Merge branch 'master' into bug4693

This commit is contained in:
Steffen Schaefer
2018-08-02 11:08:11 +02:00
3 changed files with 64 additions and 7 deletions
@@ -53,6 +53,13 @@ public interface CandidateFinder {
*/
Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> getCandidateDeltasAfterRaceStartTimeChange();
/**
* Notifies this finder about the race's start of tracking time having changed. In case of a race that infers
* the race start time from the start mark passings, a change in start of tracking needs to adjust the time range
* in which candidates are considered valid.
*/
Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> getCandidateDeltasAfterStartOfTrackingChange();
/**
* Notifies this finder about the race's finished time having changed. The candidates collections are adjusted
* accordingly: new candidates may be added if the finished time was moved to a later point in time and therefore
@@ -195,6 +195,25 @@ public class MarkPassingUpdateListener extends AbstractRaceChangeListener {
});
}
@Override
public void startOfTrackingChanged(TimePoint oldStartOfTracking, TimePoint newStartOfTracking) {
markPassingCalculator.enqueueUpdate(new StorePositionUpdateStrategy() {
@Override
public void storePositionUpdate(Map<Competitor, List<GPSFix>> competitorFixes,
Map<Mark, List<GPSFix>> markFixes, List<Waypoint> addedWaypoints, List<Waypoint> removedWaypoints,
IntHolder smallestChangedWaypointIndex,
List<Triple<Competitor, Integer, TimePoint>> fixedMarkPassings,
List<Pair<Competitor, Integer>> removedMarkPassings,
List<Pair<Competitor, Integer>> suppressedMarkPassings, List<Competitor> unSuppressedMarkPassings, CandidateFinder candidateFinder, CandidateChooser candidateChooser) {
final Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> newAndRemovedCandidatesPerCompetitor =
candidateFinder.getCandidateDeltasAfterStartOfTrackingChange();
for (final Entry<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> i : newAndRemovedCandidatesPerCompetitor.entrySet()) {
candidateChooser.calculateMarkPassDeltas(i.getKey(), i.getValue().getA(), i.getValue().getB());
}
}
});
}
@Override
public void finishedTimeChanged(TimePoint oldFinishedTime, TimePoint newFinishedTime) {
markPassingCalculator.enqueueUpdate(new StorePositionUpdateStrategy() {
@@ -37,6 +37,7 @@ import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPositionAtTimePointCache;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.MarkPositionAtTimePointCacheImpl;
import com.sap.sailing.domain.tracking.impl.TimedComparator;
import com.sap.sse.common.Bearing;
@@ -1455,12 +1456,26 @@ public class CandidateFinderImpl implements CandidateFinder {
/**
* If the {@link #race}'s regatta is configured to infer the start times from start mark passings then {@code null}
* must be tolerated as a value for {@code from}, leading to an open interval starting at the
* {@link TimePoint#BeginningOfTime beginning of time}. However, if the start time is expected to be set and not
* inferred, mark passings need to be detected only from the start minus some tolerance interval. In this case,
* an interval that has {@code null} as its {@code from} time point and thus is considered empty will be returned.
* It hence returns {@code null} from its {@link TimeRangeWithNullStartMeaningEmpty#getTimeRangeOrNull()} method.
* {@link TrackedRace#getStartOfTracking()} or, if not set, the {@link TimePoint#BeginningOfTime beginning of time}.
* However, if the start time is expected to be set and not inferred, mark passings need to be detected only from
* the start minus some tolerance interval. In this case, an interval that has {@code null} as its {@code from} time
* point and thus is considered empty will be returned. It hence returns {@code null} from its
* {@link TimeRangeWithNullStartMeaningEmpty#getTimeRangeOrNull()} method.
*/
private TimeRangeWithNullStartMeaningEmpty getTimeRangeOrNull(TimePoint from, TimePoint to) {
final TimePoint effectiveFrom = getEffectiveFrom(from);
return new TimeRangeWithNullStartMeaningEmpty(effectiveFrom, to);
}
/**
* If the {@link #race}'s regatta is configured to infer the start times from start mark passings then {@code null}
* must be tolerated as a value for {@code from}, leading to an open interval starting at the
* {@link TrackedRace#getStartOfTracking()} or, if not set, the {@link TimePoint#BeginningOfTime beginning of time}.
* However, if the start time is expected to be set and not inferred, mark passings need to be detected only from
* the start minus some tolerance interval. In this case, for an interval that has {@code null} as its {@code from} time
* point and thus is considered empty, {@code null} will be returned.
*/
private TimePoint getEffectiveFrom(TimePoint from) {
final TimePoint effectiveFrom;
if (from == null && race.getTrackedRegatta().getRegatta().useStartTimeInference()) {
// need to check the whole track to be able to find start mark passings
@@ -1470,15 +1485,22 @@ public class CandidateFinderImpl implements CandidateFinder {
} else {
effectiveFrom = from;
}
return new TimeRangeWithNullStartMeaningEmpty(effectiveFrom, to);
return effectiveFrom;
}
@Override
public Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> getCandidateDeltasAfterRaceStartTimeChange() {
final Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> result;
final TimePoint newNonInferredStartTime = race.getStartOfRace(/* inferred */ false);
final TimePoint newTimePointWhenToStartConsideringCandidates = getTimePointWhenToStartConsideringCandidates(newNonInferredStartTime);
final TimeRangeWithNullStartMeaningEmpty newTimeRange = timeRangeForValidCandidates.getWithNewFrom(newTimePointWhenToStartConsideringCandidates);
final TimePoint newEffectiveTimePointWhenToStartConsideringCandidates = getEffectiveFrom(newTimePointWhenToStartConsideringCandidates);
final TimeRangeWithNullStartMeaningEmpty newTimeRange = timeRangeForValidCandidates.getWithNewFrom(newEffectiveTimePointWhenToStartConsideringCandidates);
return getCandidateDeltasAfterTimingChange(newEffectiveTimePointWhenToStartConsideringCandidates, newTimeRange);
}
private Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> getCandidateDeltasAfterTimingChange(
final TimePoint newTimePointWhenToStartConsideringCandidates,
final TimeRangeWithNullStartMeaningEmpty newTimeRange) {
final Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> result;
if (!Util.equalsWithNull(newTimeRange, timeRangeForValidCandidates)) {
if (newTimeRange.getTimeRangeOrNull() == null) {
result = clearAllCandidates();
@@ -1499,6 +1521,15 @@ public class CandidateFinderImpl implements CandidateFinder {
return result;
}
@Override
public Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> getCandidateDeltasAfterStartOfTrackingChange() {
final TimePoint newNonInferredStartTime = race.getStartOfRace(/* inferred */ false);
final TimePoint newTimePointWhenToStartConsideringCandidates = getTimePointWhenToStartConsideringCandidates(newNonInferredStartTime);
final TimePoint newEffectiveTimePointWhenToStartConsideringCandidates = getEffectiveFrom(newTimePointWhenToStartConsideringCandidates);
final TimeRangeWithNullStartMeaningEmpty newTimeRange = timeRangeForValidCandidates.getWithNewFrom(newEffectiveTimePointWhenToStartConsideringCandidates);
return getCandidateDeltasAfterTimingChange(newEffectiveTimePointWhenToStartConsideringCandidates, newTimeRange);
}
@Override
public Map<Competitor, Pair<Iterable<Candidate>, Iterable<Candidate>>> getCandidateDeltasAfterRaceFinishedTimeChange(
TimePoint oldFinishedTime, TimePoint newFinishedTime) {