mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-15 08:41:01 +00:00
extract start time dynamically from attached race logs instead of updating startTimeReceived from race log events
This commit is contained in:
1 parent
4f069c839d
commit
86ff9e2c26
6 files changed
+76
-51
No files matched your search
+12
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
+4
@@ -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>
|
||||
*
|
||||
|
||||
+2
-21
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+40
-26
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user