bug5110: starting to become tolerant against missing mark passings and tracks

Change-Id: I3c4ba40b3cf6cf3bec3b41ce26cd76c85eb476ea
This commit is contained in:
Axel Uhl committed 2019-09-10 18:07:25 +02:00
1 parent f6c30f0420
commit 203fa053d6
1 file changed
+63 -11
@@ -443,8 +443,8 @@ public abstract class AbstractRankingMetric implements RankingMetric {
getTrackedRace().getRace().getCourse().getIndexOfWaypoint(legTo.getTrackedLeg().getLeg().getFrom());
final Duration result;
if (legWho == null || legTo == null ||
!(legWho.hasStartedLeg(timePoint) || legWho.hasFinishedLeg(timePoint)) ||
!(legTo.hasStartedLeg(timePoint) || legTo.hasFinishedLeg(timePoint))) {
!(isAssumedToHaveStartedLeg(timePoint, legWho) || isAssumedToHaveFinishedLeg(timePoint, legWho)) ||
!(isAssumedToHaveStartedLeg(timePoint, legTo) || isAssumedToHaveFinishedLeg(timePoint, legTo))) {
result = null;
} else {
final Competitor who = legWho.getCompetitor();
@@ -453,7 +453,7 @@ public abstract class AbstractRankingMetric implements RankingMetric {
// the same competitor requires no time to reach its own position; it's already there;
// however, if the competitor has already finished the leg at or before timePoint, the duration will
// have to be negative, even if who==to
if (legWho.hasFinishedLeg(timePoint)) {
if (isAssumedToHaveFinishedLeg(timePoint, legWho)) {
result = timePoint.until(legWho.getFinishTime());
} else {
result = Duration.NULL;
@@ -491,7 +491,7 @@ public abstract class AbstractRankingMetric implements RankingMetric {
if (lastWaypoint != null && getTrackedRace().getRace().getCourse().getNumberOfWaypoints() > 1) { // could be an empty course
final TrackedLeg lastTrackedLeg = getTrackedRace().getTrackedLegFinishingAt(lastWaypoint);
TrackedLegOfCompetitor whosLastTrackedLeg = lastTrackedLeg.getTrackedLeg(who);
if (whosLastTrackedLeg.hasFinishedLeg(timePoint)) {
if (isAssumedToHaveFinishedLeg(timePoint, whosLastTrackedLeg)) {
currentLegWho = whosLastTrackedLeg;
}
}
@@ -521,18 +521,18 @@ public abstract class AbstractRankingMetric implements RankingMetric {
*/
protected Duration getPredictedDurationToEndOfLegOrTo(TimePoint timePoint, final TrackedLegOfCompetitor legWho, final TrackedLegOfCompetitor legTo,
WindLegTypeAndLegBearingCache cache) {
assert legWho.hasStartedLeg(timePoint) || legWho.hasFinishedLeg(timePoint);
assert legTo.hasStartedLeg(timePoint) || legTo.hasFinishedLeg(timePoint);
assert isAssumedToHaveStartedLeg(timePoint, legWho) || isAssumedToHaveFinishedLeg(timePoint, legWho);
assert isAssumedToHaveStartedLeg(timePoint, legTo) || isAssumedToHaveFinishedLeg(timePoint, legTo);
final Duration toEndOfLegOrTo;
if (legTo.hasFinishedLeg(timePoint)) {
if (isAssumedToHaveFinishedLeg(timePoint, legTo)) {
// calculate actual time it takes who to reach the end of the leg starting at timePoint:
final TimePoint whosLegFinishTime = legWho.getFinishTime();
if (whosLegFinishTime != null && !whosLegFinishTime.after(timePoint)) {
// who's leg finishing time is known and is already reached at timePoint; we don't need to extrapolate
toEndOfLegOrTo = timePoint.until(whosLegFinishTime);
} else {
assert getWindwardDistanceTraveled(legTo.getCompetitor(), legTo.hasFinishedLeg(timePoint)?legTo.getFinishTime():timePoint, cache).compareTo(
getWindwardDistanceTraveled(legWho.getCompetitor(), legWho.hasFinishedLeg(timePoint)?legWho.getFinishTime():timePoint, cache)) >= 0;
assert getWindwardDistanceTraveled(legTo.getCompetitor(), isAssumedToHaveFinishedLeg(timePoint, legTo)?legTo.getFinishTime():timePoint, cache).compareTo(
getWindwardDistanceTraveled(legWho.getCompetitor(), isAssumedToHaveFinishedLeg(timePoint, legWho)?legWho.getFinishTime():timePoint, cache)) >= 0;
// estimate who's leg finishing time by extrapolating with the average VMG (if available) or the current VMG
// (if no average VMG can currently be computed, e.g., because the time point is exactly at the leg start)
final Position positionOfEndOfLeg = getTrackedRace().getApproximatePosition(legWho.getLeg().getTo(), timePoint);
@@ -628,8 +628,8 @@ public abstract class AbstractRankingMetric implements RankingMetric {
count = count || trackedLeg.getLeg().getFrom() == from;
if (count) {
final TrackedLegOfCompetitor trackedLegOfCompetitor = trackedLeg.getTrackedLeg(competitor);
if (trackedLegOfCompetitor.hasStartedLeg(timePoint)) {
if (!trackedLegOfCompetitor.hasFinishedLeg(timePoint)) {
if (isAssumedToHaveStartedLeg(timePoint, trackedLegOfCompetitor)) {
if (!isAssumedToHaveFinishedLeg(timePoint, trackedLegOfCompetitor)) {
// partial distance sailed:
final Position estimatedPosition = getTrackedRace().getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolate */ true);
if (estimatedPosition != null) {
@@ -668,6 +668,58 @@ public abstract class AbstractRankingMetric implements RankingMetric {
return result;
}
/**
* The {@link Competitor} of the {@code trackedLegOfCompetitor} is assumed to have started the leg specified by
* {@code trackedLegOfCompetitor} if the competitor has a mark passing for the leg's end waypoint or any waypoint
* of the course thereafter that is at or before {@code timePoint}. This assumes the possibility that mark passings
* may be missing for in-between waypoints. In particular, it is possible that a finish mark passing has been
* derived from an official finishing time even though mark passings in between or even the entire track are
* missing, so asking whether a leg has been finished can be answered with {@code true} if the {@code timePoint}
* is at of after that finish mark passing.
*/
private boolean isAssumedToHaveFinishedLeg(TimePoint timePoint, final TrackedLegOfCompetitor trackedLegOfCompetitor) {
final Waypoint legEndWaypoint = trackedLegOfCompetitor.getLeg().getTo();
final MarkPassing markPassing = findMarkPassingForWaypointOrSuccessorAtOrBeforeTimePoint(timePoint,
trackedLegOfCompetitor, legEndWaypoint);
return markPassing != null;
}
/**
* The {@link Competitor} of the {@code trackedLegOfCompetitor} is assumed to have started the leg specified by
* {@code trackedLegOfCompetitor} if the competitor has a mark passing for the leg's start waypoint or any waypoint
* of the course thereafter that is at or before {@code timePoint}. This assumes the possibility that mark passings
* may be missing for in-between waypoints. In particular, it is possible that a finish mark passing has been
* derived from an official finishing time even though mark passings in between or even the entire track are
* missing, so asking whether a leg has been started can be answered with {@code true} if the {@code timePoint}
* is at of after that finish mark passing.
*/
private boolean isAssumedToHaveStartedLeg(TimePoint timePoint, final TrackedLegOfCompetitor trackedLegOfCompetitor) {
final Waypoint legStartWaypoint = trackedLegOfCompetitor.getLeg().getFrom();
final MarkPassing markPassing = findMarkPassingForWaypointOrSuccessorAtOrBeforeTimePoint(timePoint,
trackedLegOfCompetitor, legStartWaypoint);
return markPassing != null;
}
private MarkPassing findMarkPassingForWaypointOrSuccessorAtOrBeforeTimePoint(TimePoint timePoint,
final TrackedLegOfCompetitor trackedLegOfCompetitor, final Waypoint legStartWaypoint) {
final Iterable<Waypoint> waypoints = getTrackedRace().getRace().getCourse().getWaypoints();
boolean checkForMarkPassing = false;
MarkPassing markPassing = null;
for (final Waypoint waypoint : waypoints) {
if (waypoint == legStartWaypoint) {
checkForMarkPassing = true; // from here on, check for mark passings for the waypoint
}
if (checkForMarkPassing) {
final MarkPassing markPassingCandidate = getTrackedRace().getMarkPassing(trackedLegOfCompetitor.getCompetitor(), waypoint);
if (markPassingCandidate != null && !markPassingCandidate.getTimePoint().after(timePoint)) {
markPassing = markPassingCandidate;
break;
}
}
}
return markPassing;
}
/**
* @return <code>null</code> if no competitor has started the leg yet; the first competitor to finish the leg if any
* has already finished the leg at <code>timePoint</code>; or the competitor with the greatest windward