mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-16 17:21:00 +00:00
Move updateStartAndEndOfTracking to TrackedRaceImpl and set up some more handlers in DynamicTrackedRaceLogListener
This commit is contained in:
1 parent
5da62f3b86
commit
6b135f7978
10 files changed
+175
-49
No files matched your search
+2
-48
@@ -75,9 +75,7 @@ import com.sap.sailing.domain.tracking.impl.TrackedRaceStatusImpl;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.WithID;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
import difflib.PatchFailedException;
|
||||
|
||||
@@ -239,50 +237,6 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
|
||||
return new RegattaLogDeviceMarkMappingFinder(params.getRegattaLog()).analyze();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use mapping time ranges to set time start and end of tracking time for race
|
||||
*/
|
||||
private void updateStartAndEndOfTracking() {
|
||||
// TODO bug 3196: this would need to be evaluated lazily in TrackedRaceImpl.getStartOfTracking / getEndOfTracking
|
||||
final Pair<TimePoint, TimePoint> trackingTimesFromRaceLog = trackedRace.getTrackingTimesFromRaceLogs();
|
||||
if (trackingTimesFromRaceLog == null) {
|
||||
TimePoint earliestMappingStart = new MillisecondsTimePoint(Long.MAX_VALUE);
|
||||
TimePoint latestMappingEnd = new MillisecondsTimePoint(Long.MIN_VALUE);
|
||||
for (List<? extends DeviceMapping<?>> list : competitorMappings.values()) {
|
||||
for (DeviceMapping<?> mapping : list) {
|
||||
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
|
||||
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
|
||||
}
|
||||
}
|
||||
for (List<? extends DeviceMapping<?>> list : markMappings.values()) {
|
||||
for (DeviceMapping<?> mapping : list) {
|
||||
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
|
||||
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
|
||||
}
|
||||
}
|
||||
trackedRace.setStartOfTrackingReceived(earliestMappingStart == null ? TimePoint.BeginningOfTime : earliestMappingStart);
|
||||
trackedRace.setEndOfTrackingReceived(latestMappingEnd == null ? TimePoint.EndOfTime : latestMappingEnd);
|
||||
}
|
||||
}
|
||||
|
||||
private TimePoint getUpdatedEarliestMappingStart(TimePoint earliestMappingStart, final TimePoint from) {
|
||||
if (from == null) {
|
||||
earliestMappingStart = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
|
||||
} else if (earliestMappingStart != null && from.before(earliestMappingStart)) {
|
||||
earliestMappingStart = from;
|
||||
}
|
||||
return earliestMappingStart;
|
||||
}
|
||||
|
||||
private TimePoint getUpdatedLatestMappingEnd(TimePoint latestMappingEnd, final TimePoint to) {
|
||||
if (to == null) {
|
||||
latestMappingEnd = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
|
||||
} else if (latestMappingEnd != null && to.after(latestMappingEnd)) {
|
||||
latestMappingEnd = to;
|
||||
}
|
||||
return latestMappingEnd;
|
||||
}
|
||||
|
||||
private <ItemT extends WithID, FixT extends GPSFix> boolean hasMappingAlreadyBeenLoaded(
|
||||
DeviceMapping<ItemT> newMapping, List<DeviceMapping<ItemT>> oldMappings) {
|
||||
if (oldMappings == null) {
|
||||
@@ -355,7 +309,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
|
||||
markMappingsByDevices.clear();
|
||||
markMappingsByDevices.putAll(transformToMappingsByDevice(markMappings));
|
||||
|
||||
updateStartAndEndOfTracking();
|
||||
trackedRace.updateStartAndEndOfTracking();
|
||||
}
|
||||
|
||||
private void onDeviceMarkMappingEvent(RegattaLogDeviceMarkMappingEvent event) {
|
||||
@@ -429,7 +383,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
|
||||
competitorMappings.putAll(newMappings);
|
||||
competitorMappingsByDevices.clear();
|
||||
competitorMappingsByDevices.putAll(transformToMappingsByDevice(competitorMappings));
|
||||
updateStartAndEndOfTracking();
|
||||
trackedRace.updateStartAndEndOfTracking();
|
||||
}
|
||||
|
||||
private void onStartTrackingEvent(RaceLogStartTrackingEvent event) {
|
||||
|
||||
+8
@@ -1029,4 +1029,12 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
@Override
|
||||
public void updateMarkPassingsAfterRaceLogChanges() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStartAndEndOfTracking() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishedTimeChangedByRaceCommittee(TimePoint newFinishedTime) {
|
||||
}
|
||||
}
|
||||
+4
@@ -649,4 +649,8 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStartAndEndOfTracking() {
|
||||
}
|
||||
}
|
||||
+1
@@ -128,6 +128,7 @@ public interface DynamicTrackedRace extends TrackedRace {
|
||||
void onCourseDesignChangedByRaceCommittee(CourseBase courseDesign);
|
||||
|
||||
void onStartTimeChangedByRaceCommittee(TimePoint newStartTime);
|
||||
void onFinishedTimeChangedByRaceCommittee(TimePoint newFinishedTime);
|
||||
|
||||
void onAbortedByRaceCommittee(Flags flag);
|
||||
|
||||
|
||||
@@ -865,6 +865,10 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
|
||||
default Pair<TimePoint, TimePoint> getTrackingTimesFromRaceLogs() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Pair<TimePoint, TimePoint> getStartAndFinishedTimeFromRaceLogs() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all marks found in the {@link #markTracks} map and the mark device mappings and mark
|
||||
@@ -875,4 +879,15 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
|
||||
default Iterable<Mark> getMarksFromRegattaLogs() {
|
||||
return getMarks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces update of start and end of tracking.
|
||||
* Adheres to the following precedence order
|
||||
*
|
||||
* 1) RaceLogStartOfTrackingEvent/RaceLogEndOfTrackingEvent
|
||||
* 2) RaceLogStartTimeEvent - x Minutes, Race finished + x Minutes
|
||||
* 3) Earliest Mapping, Latest Mapping (of Marks and Competitors)
|
||||
* 4) Leave previously (manually set start/end of tracking)
|
||||
*/
|
||||
public void updateStartAndEndOfTracking();
|
||||
}
|
||||
+7
-1
@@ -978,6 +978,13 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.INFO, "Exception trying to notify race status change listeners about start time change", e);
|
||||
}
|
||||
updateStartAndEndOfTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishedTimeChangedByRaceCommittee(TimePoint newFinishedTime) {
|
||||
logger.info("Finished time of race "+getRace().getName()+" updated by race committee to "+newFinishedTime);
|
||||
updateStartAndEndOfTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1010,5 +1017,4 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
||||
public DynamicGPSFixTrack<Mark, GPSFix> getTrack(Mark mark) {
|
||||
return (DynamicGPSFixTrack<Mark, GPSFix>) super.getTrack(mark);
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmed
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
|
||||
@@ -31,6 +32,7 @@ import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sailing.domain.markpassingcalculation.MarkPassingUpdateListener;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.RaceLogWindFixDeclinationHelper;
|
||||
@@ -309,6 +311,14 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor {
|
||||
markPassingUpdateListener.removeFixedPassing(revokedEvent.getInvolvedBoats().get(0),
|
||||
((RaceLogFixedMarkPassingEvent) revokedEvent).getZeroBasedIndexOfPassedWaypoint());
|
||||
}
|
||||
if (revokedEvent instanceof RaceLogDependentStartTimeEvent || revokedEvent instanceof RaceLogStartTimeEvent){
|
||||
analyzeStartTime(null);
|
||||
}
|
||||
if (revokedEvent instanceof RaceLogRaceStatusEvent){
|
||||
if (((RaceLogRaceStatusEvent) revokedEvent).getNextStatus().equals(RaceLogRaceStatus.FINISHED)){
|
||||
trackedRace.invalidateEndTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,4 +336,11 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor {
|
||||
public void visit(RaceLogEndOfTrackingEvent event) {
|
||||
trackedRace.setEndOfTrackingReceived(event.getLogicalTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogRaceStatusEvent event) {
|
||||
if (event.getNextStatus().equals(RaceLogRaceStatus.FINISHED)){
|
||||
trackedRace.invalidateEndTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
+109
@@ -40,6 +40,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.FinishedTimeFinder;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TrackingTimesFinder;
|
||||
@@ -49,6 +50,8 @@ import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMarkMappingFinder;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
@@ -111,6 +114,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.ranking.RankingMetric;
|
||||
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
|
||||
@@ -156,6 +160,8 @@ import difflib.Patch;
|
||||
import difflib.PatchFailedException;
|
||||
|
||||
public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials implements CourseListener {
|
||||
private static final int TRACKING_BUFFER_IN_MINUTES = 5;
|
||||
|
||||
private static final long serialVersionUID = -4825546964220003507L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TrackedRaceImpl.class.getName());
|
||||
@@ -722,11 +728,100 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
|
||||
@Override
|
||||
public TimePoint getStartOfTracking() {
|
||||
updateStartAndEndOfTracking();//FIXME: unclear whether change listeners etc similar to DynamicTrackedRace can be used here for caching and invalidation
|
||||
return startOfTrackingReceived;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use mapping time ranges to set time start and end of tracking time for race
|
||||
*/
|
||||
public void updateStartAndEndOfTracking() {
|
||||
final Pair<TimePoint, TimePoint> trackingTimesFromRaceLog = this.getTrackingTimesFromRaceLogs();
|
||||
final Pair<TimePoint, TimePoint> startAndFinishedTimesFromRaceLog = this.getStartAndFinishedTimeFromRaceLogs();
|
||||
|
||||
boolean startOfTrackingFound = false;
|
||||
boolean endOfTrackingFound = false;
|
||||
|
||||
if (trackingTimesFromRaceLog != null){
|
||||
if (trackingTimesFromRaceLog.getA() != null){
|
||||
setStartOfTrackingReceived(trackingTimesFromRaceLog.getA(), false);
|
||||
startOfTrackingFound = true;
|
||||
}
|
||||
if (trackingTimesFromRaceLog.getB() != null){
|
||||
setEndOfTrackingReceived(trackingTimesFromRaceLog.getB(), false);
|
||||
endOfTrackingFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!startOfTrackingFound || !endOfTrackingFound){
|
||||
if (startAndFinishedTimesFromRaceLog != null){
|
||||
if (!startOfTrackingFound && startAndFinishedTimesFromRaceLog.getA() != null){
|
||||
setStartOfTrackingReceived(startAndFinishedTimesFromRaceLog.getA().minus(Duration.ONE_MINUTE.times(TRACKING_BUFFER_IN_MINUTES)), false);
|
||||
startOfTrackingFound = true;
|
||||
}
|
||||
if (!endOfTrackingFound && startAndFinishedTimesFromRaceLog.getB() != null){
|
||||
setEndOfTrackingReceived(startAndFinishedTimesFromRaceLog.getB().plus(Duration.ONE_MINUTE.times(TRACKING_BUFFER_IN_MINUTES)), false);
|
||||
endOfTrackingFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!startOfTrackingFound || !endOfTrackingFound){
|
||||
TimePoint earliestMappingStart = new MillisecondsTimePoint(Long.MAX_VALUE);
|
||||
TimePoint latestMappingEnd = new MillisecondsTimePoint(Long.MIN_VALUE);
|
||||
Map<Mark, List<DeviceMapping<Mark>>> markMappings = new HashMap<Mark, List<DeviceMapping<Mark>>>();
|
||||
Map<Competitor, List<DeviceMapping<Competitor>>> competitorMappings = new HashMap<Competitor, List<DeviceMapping<Competitor>>>();
|
||||
for (RegattaLog regattaLog: attachedRegattaLogs.values()){
|
||||
competitorMappings.putAll(new RegattaLogDeviceCompetitorMappingFinder(regattaLog).analyze());
|
||||
markMappings.putAll(new RegattaLogDeviceMarkMappingFinder(regattaLog).analyze());
|
||||
}
|
||||
for (List<? extends DeviceMapping<?>> list : competitorMappings.values()) {
|
||||
for (DeviceMapping<?> mapping : list) {
|
||||
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
|
||||
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
|
||||
}
|
||||
}
|
||||
for (List<? extends DeviceMapping<?>> list : markMappings.values()) {
|
||||
for (DeviceMapping<?> mapping : list) {
|
||||
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
|
||||
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
|
||||
}
|
||||
}
|
||||
|
||||
if (!startOfTrackingFound && earliestMappingStart != null){
|
||||
setStartOfTrackingReceived(earliestMappingStart, false);
|
||||
}
|
||||
|
||||
if (!endOfTrackingFound && latestMappingEnd != null){
|
||||
setEndOfTrackingReceived(latestMappingEnd, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TimePoint getUpdatedEarliestMappingStart(TimePoint earliestMappingStart, final TimePoint from) {
|
||||
if (from == null) {
|
||||
earliestMappingStart = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
|
||||
} else if (earliestMappingStart != null && from.before(earliestMappingStart)) {
|
||||
earliestMappingStart = from;
|
||||
}
|
||||
return earliestMappingStart;
|
||||
}
|
||||
|
||||
private TimePoint getUpdatedLatestMappingEnd(TimePoint latestMappingEnd, final TimePoint to) {
|
||||
if (to == null) {
|
||||
latestMappingEnd = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
|
||||
} else if (latestMappingEnd != null && to.after(latestMappingEnd)) {
|
||||
latestMappingEnd = to;
|
||||
}
|
||||
return latestMappingEnd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public TimePoint getEndOfTracking() {
|
||||
updateStartAndEndOfTracking();//FIXME: unclear whether change listeners etc similar to DynamicTrackedRace can be used here for caching and invalidation
|
||||
return endOfTrackingReceived;
|
||||
}
|
||||
|
||||
@@ -762,6 +857,20 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<TimePoint, TimePoint> getStartAndFinishedTimeFromRaceLogs() {
|
||||
//Only one of the RaceLogs should have valid data, so one doesn't have to compare all the
|
||||
//start/finished time values in order to find the earliest startTime/latestFinishedTime
|
||||
for (final RaceLog raceLog : attachedRaceLogs.values()) {
|
||||
TimePoint startTime = new StartTimeFinder(raceLogResolver, raceLog).analyze().getStartTime();
|
||||
TimePoint finishedTime = new FinishedTimeFinder(raceLog).analyze();
|
||||
if (startTime != null || finishedTime != null){
|
||||
return new Util.Pair<TimePoint, TimePoint>(startTime, finishedTime);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the start time of the race from various sources. The highest precedence take the {@link #attachedRaceLogs race logs},
|
||||
|
||||
+8
@@ -790,4 +790,12 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
@Override
|
||||
public void updateMarkPassingsAfterRaceLogChanges() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStartAndEndOfTracking() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishedTimeChangedByRaceCommittee(TimePoint newFinishedTime) {
|
||||
}
|
||||
}
|
||||
+4
@@ -624,4 +624,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
|
||||
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStartAndEndOfTracking() {
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user