extract start time dynamically from attached race logs instead of updating startTimeReceived from race log events

This commit is contained in:
Axel Uhl committed 2013-06-07 23:22:56 +02:00
1 parent 4f069c839d
commit 86ff9e2c26
6 files changed
+76 -51

No files matched your search

@@ -787,4 +787,16 @@ public class MockedTrackedRace implements DynamicTrackedRace {
// TODO Auto-generated method stub
}
@Override
public void invalidateStartTime() {
// TODO Auto-generated method stub
}
@Override
public void invalidateEndTime() {
// TODO Auto-generated method stub
}
}
@@ -88,4 +88,8 @@ public interface DynamicTrackedRace extends TrackedRace {
* the new course design to be published
*/
void onCourseDesignChangedByRaceCommittee(CourseBase courseDesign);
void invalidateStartTime();
void invalidateEndTime();
}
@@ -51,10 +51,12 @@ public interface TrackedRace extends Serializable {
/**
* Computes the estimated start time for this race (not to be confused with the {@link #getStartOfTracking()} time
* point which is expected to be before the race start time). When there are no {@link MarkPassing}s for the first
* mark, <code>null</code> is returned. If there are mark passings for the first mark and the start time is less
* than {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} before the first mark passing for the
* first mark. Otherwise, the first mark passing for the first mark minus
* point which is expected to be before the race start time). The highest precedence take the
* {@link #attachedRaceLogs race logs} and their start time events, followed by the field {@link #startTimeReceived}
* which can explicitly be set using {@link #setStartTimeReceived(TimePoint)}. When there are no {@link MarkPassing}s
* for the first mark, <code>null</code> is returned. If there are mark passings for the first mark and the start
* time is less than {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} before the first mark
* passing for the first mark. Otherwise, the first mark passing for the first mark minus
* {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} is returned as the race start time.
* <p>
*
@@ -1,7 +1,6 @@
package com.sap.sailing.domain.tracking.impl;
import com.sap.sailing.domain.base.CourseBase;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogCourseAreaChangedEvent;
import com.sap.sailing.domain.racelog.RaceLogCourseDesignChangedEvent;
@@ -17,15 +16,12 @@ import com.sap.sailing.domain.racelog.RaceLogStartProcedureChangedEvent;
import com.sap.sailing.domain.racelog.RaceLogStartTimeEvent;
import com.sap.sailing.domain.racelog.analyzing.impl.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.racelog.analyzing.impl.RaceStatusAnalyzer;
import com.sap.sailing.domain.racelog.analyzing.impl.StartTimeFinder;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
private DynamicTrackedRace trackedRace;
private StartTimeFinder startTimeFinder;
private RaceStatusAnalyzer statusAnalyzer;
private LastPublishedCourseDesignFinder courseDesignFinder;
@@ -36,7 +32,8 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
public void addTo(RaceLog raceLog) {
raceLog.addListener(this);
startTimeFinder = new StartTimeFinder(raceLog);
trackedRace.invalidateStartTime();
trackedRace.invalidateEndTime();
courseDesignFinder = new LastPublishedCourseDesignFinder(raceLog);
statusAnalyzer = new RaceStatusAnalyzer(raceLog);
analyze();
@@ -55,24 +52,10 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
}
private void analyze() {
analyzeStartTime();
analyzeStatus();
analyzeCourseDesign();
}
private void analyzeStartTime() {
TimePoint startTime = startTimeFinder.getStartTime();
// Because this code can be triggered by an obsolete (delayed) event or on an empty pass...
// ... the current pass's start time might be null
if (startTime != null) {
// ... or setStartTimeReceived(TimePoint) might be called more than once with the same start time.
trackedRace.setStartTimeReceived(startTime);
} else {
// TODO: Can we somehow withdraw a previously set start time?
}
}
private void analyzeStatus() {
/* RaceLogRaceStatus newStatus = */statusAnalyzer.getStatus();
@@ -92,13 +75,11 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
@Override
public void visit(RaceLogPassChangeEvent event) {
analyzeStartTime();
analyzeStatus();
}
@Override
public void visit(RaceLogStartTimeEvent event) {
analyzeStartTime();
analyzeStatus();
}
@@ -72,6 +72,7 @@ import com.sap.sailing.domain.confidence.Weigher;
import com.sap.sailing.domain.confidence.impl.HyperbolicTimeDifferenceWeigher;
import com.sap.sailing.domain.confidence.impl.PositionAndTimePointWeigher;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.analyzing.impl.StartTimeFinder;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
@@ -257,6 +258,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation) {
super();
locksForMarkPassings = new IdentityHashMap<>();
attachedRaceLogs = new HashMap<>();
this.status = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.PREPARED, 0.0);
this.statusNotifier = new Object[0];
this.serializationLock = new NamedReentrantReadWriteLock("Serialization lock for tracked race "
@@ -366,6 +368,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
*/
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
attachedRaceLogs = new HashMap<>();
markPassingsTimes = new ArrayList<Pair<Waypoint, Pair<TimePoint, TimePoint>>>();
cacheInvalidationTimerLock = new Object();
windStore = EmptyWindStore.INSTANCE;
@@ -452,11 +455,11 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
return endOfTrackingReceived;
}
protected void invalidateStartTime() {
public void invalidateStartTime() {
startTime = null;
}
protected void invalidateEndTime() {
public void invalidateEndTime() {
endTime = null;
}
@@ -467,35 +470,46 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
/**
* Calculates the start time of the race from various sources
* Calculates the start time of the race from various sources. The highest precedence take the {@link #attachedRaceLogs race logs},
* followed by the field {@link #startTimeReceived} which can explicitly be set using {@link #setStartTimeReceived(TimePoint)}.
* If that does not provide any start time either, a start time is attempted to be inferred from the time points
* of the start mark passing events.
*/
@Override
public TimePoint getStartOfRace() {
if (startTime == null) {
startTime = startTimeReceived;
// If not null, check if the first mark passing for the start line is too much after the startTimeReceived;
// if so, return an adjusted, later start time.
// If no official start time was received, try to estimate the start time using the mark passings for the
// start line.
final Waypoint firstWaypoint = getRace().getCourse().getFirstWaypoint();
if (firstWaypoint != null) {
if (startTimeReceived != null) {
TimePoint timeOfFirstMarkPassing = getFirstPassingTime(firstWaypoint);
if (timeOfFirstMarkPassing != null) {
long startTimeReceived2timeOfFirstMarkPassingFirstMark = timeOfFirstMarkPassing.asMillis()
- startTimeReceived.asMillis();
if (startTimeReceived2timeOfFirstMarkPassingFirstMark > MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS) {
startTime = new MillisecondsTimePoint(timeOfFirstMarkPassing.asMillis()
- MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS);
} else {
startTime = startTimeReceived;
for (RaceLog raceLog : attachedRaceLogs.values()) {
startTime = new StartTimeFinder(raceLog).getStartTime();
if (startTime != null) {
break;
}
}
if (startTime == null) {
startTime = startTimeReceived;
// If not null, check if the first mark passing for the start line is too much after the
// startTimeReceived; if so, return an adjusted, later start time.
// If no official start time was received, try to estimate the start time using the mark passings for
// the start line.
final Waypoint firstWaypoint = getRace().getCourse().getFirstWaypoint();
if (firstWaypoint != null) {
if (startTimeReceived != null) {
TimePoint timeOfFirstMarkPassing = getFirstPassingTime(firstWaypoint);
if (timeOfFirstMarkPassing != null) {
long startTimeReceived2timeOfFirstMarkPassingFirstMark = timeOfFirstMarkPassing.asMillis()
- startTimeReceived.asMillis();
if (startTimeReceived2timeOfFirstMarkPassingFirstMark > MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS) {
startTime = new MillisecondsTimePoint(timeOfFirstMarkPassing.asMillis()
- MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS);
} else {
startTime = startTimeReceived;
}
}
} else {
final NavigableSet<MarkPassing> markPassingsForFirstWaypointInOrder = getMarkPassingsInOrderAsNavigableSet(firstWaypoint);
if (markPassingsForFirstWaypointInOrder != null) {
startTime = calculateStartOfRaceFromMarkPassings(markPassingsForFirstWaypointInOrder,
getRace().getCompetitors());
}
}
} else {
final NavigableSet<MarkPassing> markPassingsForFirstWaypointInOrder = getMarkPassingsInOrderAsNavigableSet(firstWaypoint);
if (markPassingsForFirstWaypointInOrder != null) {
startTime = calculateStartOfRaceFromMarkPassings(markPassingsForFirstWaypointInOrder, getRace()
.getCompetitors());
}
}
}
@@ -789,4 +789,16 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
public void invalidateStartTime() {
// TODO Auto-generated method stub
}
@Override
public void invalidateEndTime() {
// TODO Auto-generated method stub
}
}