mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-30 17:36:40 +00:00
untangled the endless recursion regarding internalRawFixes in TrackBasedEstimationWindTrackImpl
This commit is contained in:
1 parent
c9c50fc8e2
commit
b0db50e3e0
5 files changed
+178
-83
No files matched your search
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CombinedWindAsNavigableSet.java
Executable
+39
@@ -0,0 +1,39 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
|
||||
/**
|
||||
* Delivers what {@link TrackedRace#getWind(Position, TimePoint)} delivers, as a navigable set.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CombinedWindAsNavigableSet extends VirtualWindFixesAsNavigableSet {
|
||||
|
||||
public CombinedWindAsNavigableSet(WindTrack track, TrackedRace trackedRace,
|
||||
long resolutionInMilliseconds) {
|
||||
super(track, trackedRace, resolutionInMilliseconds);
|
||||
}
|
||||
|
||||
public CombinedWindAsNavigableSet(WindTrack track, TrackedRace trackedRace,
|
||||
TimePoint from, TimePoint to, long resolutionInMilliseconds) {
|
||||
super(track, trackedRace, from, to, resolutionInMilliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Wind getWind(Position p, TimePoint timePoint) {
|
||||
return getTrackedRace().getWind(p, timePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableSet<Wind> createSubset(WindTrack track, TrackedRace trackedRace, TimePoint from, TimePoint to) {
|
||||
return new CombinedWindAsNavigableSet(track, trackedRace, from, to, getResolutionInMilliseconds());
|
||||
}
|
||||
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
|
||||
/**
|
||||
* Emulates a collection of {@link Wind} fixes for a {@link TrackedRace}, computed using
|
||||
* {@link TrackedRace#getEstimatedWindDirection(com.sap.sailing.domain.base.Position, TimePoint)}. If not constrained
|
||||
* by a {@link #from} and/or a {@link #to} time point, an equidistant time field is assumed, starting at
|
||||
* {@link TrackedRace#getStart()} and leading up to {@link TrackedRace#getTimePointOfNewestEvent()}. If
|
||||
* {@link TrackedRace#getStart()} returns <code>null</code>, {@link Long#MAX_VALUE} is used as the {@link #from}
|
||||
* time point, pushing the start to the more or less infinite future ("end of the universe"). If no event was
|
||||
* received yet and hence {@link TrackedRace#getTimePointOfNewestEvent()} returns <code>null</code>, the {@link #to}
|
||||
* end is assumed to be the beginning of the epoch (1970-01-01T00:00:00).
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class EstimatedWindFixesAsNavigableSet extends VirtualWindFixesAsNavigableSet {
|
||||
public EstimatedWindFixesAsNavigableSet(TrackBasedEstimationWindTrackImpl track, TrackedRace trackedRace) {
|
||||
this(track, trackedRace, null, null);
|
||||
}
|
||||
|
||||
protected TrackBasedEstimationWindTrackImpl getTrack() {
|
||||
return (TrackBasedEstimationWindTrackImpl) super.getTrack();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param from expected to be an integer multiple of {@link #getResolutionInMilliseconds()} or <code>null</code>
|
||||
* @param to expected to be an integer multiple of {@link #getResolutionInMilliseconds()} or <code>null</code>
|
||||
*/
|
||||
private EstimatedWindFixesAsNavigableSet(WindTrack track, TrackedRace trackedRace,
|
||||
TimePoint from, TimePoint to) {
|
||||
super(track, trackedRace, from, to, /* resolution in milliseconds */ 1000l);
|
||||
}
|
||||
|
||||
protected Wind getWind(Position p, TimePoint timePoint) {
|
||||
return getTrack().getEstimatedWindDirection(p, timePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableSet<Wind> createSubset(WindTrack track, TrackedRace trackedRace, TimePoint from, TimePoint to) {
|
||||
return new EstimatedWindFixesAsNavigableSet(track, trackedRace, from, to);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+59
-30
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.util.impl.ArrayListNavigableSet;
|
||||
|
||||
@@ -50,10 +51,8 @@ import com.sap.sailing.util.impl.ArrayListNavigableSet;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements RaceChangeListener {
|
||||
private final EstimatedWindFixesAsNavigableSet virtualInternalRawFixes;
|
||||
|
||||
private final TrackedRace trackedRace;
|
||||
public class TrackBasedEstimationWindTrackImpl extends VirtualWindTrackImpl implements RaceChangeListener {
|
||||
private final VirtualWindFixesAsNavigableSet virtualInternalRawFixes;
|
||||
|
||||
private final NavigableSet<TimePoint> timePointsWithCachedNullResult;
|
||||
|
||||
@@ -63,10 +62,9 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
private final HashSet<TimePoint> timePointsWithCachedNullResultFastContains;
|
||||
|
||||
public TrackBasedEstimationWindTrackImpl(TrackedRace trackedRace, long millisecondsOverWhichToAverage) {
|
||||
super(millisecondsOverWhichToAverage);
|
||||
this.trackedRace = trackedRace;
|
||||
super(trackedRace, millisecondsOverWhichToAverage);
|
||||
virtualInternalRawFixes = new EstimatedWindFixesAsNavigableSet(trackedRace);
|
||||
trackedRace.addListener(this);
|
||||
this.virtualInternalRawFixes = new EstimatedWindFixesAsNavigableSet(this, trackedRace);
|
||||
this.timePointsWithCachedNullResult = new ArrayListNavigableSet<TimePoint>(AbstractTimePoint.TIMEPOINT_COMPARATOR);
|
||||
this.timePointsWithCachedNullResultFastContains = new HashSet<TimePoint>();
|
||||
}
|
||||
@@ -79,7 +77,12 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
*/
|
||||
@Override
|
||||
public long getMillisecondsOverWhichToAverageWind() {
|
||||
return 2*virtualInternalRawFixes.getResolutionInMilliseconds()+2;
|
||||
return 2*getInternalRawFixes().getResolutionInMilliseconds()+2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VirtualWindFixesAsNavigableSet getInternalRawFixes() {
|
||||
return virtualInternalRawFixes;
|
||||
}
|
||||
|
||||
private NavigableSet<Wind> getCachedFixes() {
|
||||
@@ -149,7 +152,7 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
NavigableSet<Wind> cache = getCachedFixes();
|
||||
Wind cachedFix = cache.floor(getDummyFix(timePoint));
|
||||
if (cachedFix == null || !cachedFix.getTimePoint().equals(timePoint)) {
|
||||
result = trackedRace.getEstimatedWindDirection(p, timePoint);
|
||||
result = getTrackedRace().getEstimatedWindDirection(p, timePoint);
|
||||
cache(timePoint, result);
|
||||
} else {
|
||||
result = cachedFix;
|
||||
@@ -162,21 +165,6 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
return timePointsWithCachedNullResultFastContains.contains(timePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableSet<Wind> getInternalRawFixes() {
|
||||
return virtualInternalRawFixes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableSet<Wind> getInternalFixes() {
|
||||
return new PartialNavigableSetView<Wind>(getInternalRawFixes()) {
|
||||
@Override
|
||||
protected boolean isValid(Wind e) {
|
||||
return e != null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This redefinition avoids very long searches in case <code>at</code> is before the race start or after the race's
|
||||
* newest event. Should <code>at</code> be out of this range, it is set to the closest border of this range before
|
||||
@@ -187,8 +175,8 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
public Wind getAveragedWind(Position p, TimePoint at) {
|
||||
Wind result = null;
|
||||
TimePoint adjustedAt;
|
||||
TimePoint raceStartTimePoint = trackedRace.getStart();
|
||||
TimePoint timePointOfNewestEvent = trackedRace.getTimePointOfNewestEvent();
|
||||
TimePoint raceStartTimePoint = getTrackedRace().getStart();
|
||||
TimePoint timePointOfNewestEvent = getTrackedRace().getTimePointOfNewestEvent();
|
||||
if (raceStartTimePoint != null) {
|
||||
if (timePointOfNewestEvent != null) {
|
||||
if (at.compareTo(raceStartTimePoint) < 0) {
|
||||
@@ -223,7 +211,7 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
}
|
||||
|
||||
private void invalidateForNewWind(Wind wind) {
|
||||
long averagingInterval = trackedRace.getMillisecondsOverWhichToAverageWind();
|
||||
long averagingInterval = getTrackedRace().getMillisecondsOverWhichToAverageWind();
|
||||
Wind startOfInvalidation = getDummyFix(new MillisecondsTimePoint(wind.getTimePoint().asMillis()-averagingInterval));
|
||||
TimePoint endOfInvalidation = new MillisecondsTimePoint(wind.getTimePoint().asMillis()+averagingInterval);
|
||||
invalidateCache(startOfInvalidation, endOfInvalidation);
|
||||
@@ -241,7 +229,7 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
|
||||
@Override
|
||||
public void competitorPositionChanged(GPSFix fix, Competitor competitor) {
|
||||
long averagingInterval = trackedRace.getMillisecondsOverWhichToAverageSpeed();
|
||||
long averagingInterval = getTrackedRace().getMillisecondsOverWhichToAverageSpeed();
|
||||
Wind startOfInvalidation = getDummyFix(new MillisecondsTimePoint(fix.getTimePoint().asMillis()-averagingInterval));
|
||||
TimePoint endOfInvalidation = new MillisecondsTimePoint(fix.getTimePoint().asMillis()+averagingInterval);
|
||||
invalidateCache(startOfInvalidation, endOfInvalidation);
|
||||
@@ -249,7 +237,7 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
|
||||
@Override
|
||||
public void markPassingReceived(MarkPassing oldMarkPassing, MarkPassing markPassing) {
|
||||
long averagingInterval = trackedRace.getMillisecondsOverWhichToAverageSpeed();
|
||||
long averagingInterval = getTrackedRace().getMillisecondsOverWhichToAverageSpeed();
|
||||
Wind startOfInvalidation;
|
||||
TimePoint endOfInvalidation;
|
||||
if (oldMarkPassing == null) {
|
||||
@@ -273,10 +261,51 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements
|
||||
public void buoyPositionChanged(GPSFix fix, Buoy buoy) {
|
||||
// A buoy position change can mean a leg type change. The interval over which the wind estimation is affected
|
||||
// depends on how the GPS track computes the estimated buoy position. Ask it:
|
||||
Pair<TimePoint, TimePoint> interval = trackedRace.getOrCreateTrack(buoy).getEstimatedPositionTimePeriodAffectedBy(fix);
|
||||
Pair<TimePoint, TimePoint> interval = getTrackedRace().getOrCreateTrack(buoy).getEstimatedPositionTimePeriodAffectedBy(fix);
|
||||
Wind startOfInvalidation = interval.getA() == null ? null : getDummyFix(interval.getA());
|
||||
TimePoint endOfInvalidation = interval.getB();
|
||||
invalidateCache(startOfInvalidation, endOfInvalidation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulates a collection of {@link Wind} fixes for a {@link TrackedRace}, computed using
|
||||
* {@link TrackedRace#getEstimatedWindDirection(com.sap.sailing.domain.base.Position, TimePoint)}. If not constrained
|
||||
* by a {@link #from} and/or a {@link #to} time point, an equidistant time field is assumed, starting at
|
||||
* {@link TrackedRace#getStart()} and leading up to {@link TrackedRace#getTimePointOfNewestEvent()}. If
|
||||
* {@link TrackedRace#getStart()} returns <code>null</code>, {@link Long#MAX_VALUE} is used as the {@link #from}
|
||||
* time point, pushing the start to the more or less infinite future ("end of the universe"). If no event was
|
||||
* received yet and hence {@link TrackedRace#getTimePointOfNewestEvent()} returns <code>null</code>, the {@link #to}
|
||||
* end is assumed to be the beginning of the epoch (1970-01-01T00:00:00).
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class EstimatedWindFixesAsNavigableSet extends VirtualWindFixesAsNavigableSet {
|
||||
public EstimatedWindFixesAsNavigableSet(TrackedRace trackedRace) {
|
||||
this(trackedRace, null, null);
|
||||
}
|
||||
|
||||
protected TrackBasedEstimationWindTrackImpl getTrack() {
|
||||
return (TrackBasedEstimationWindTrackImpl) super.getTrack();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param from expected to be an integer multiple of {@link #getResolutionInMilliseconds()} or <code>null</code>
|
||||
* @param to expected to be an integer multiple of {@link #getResolutionInMilliseconds()} or <code>null</code>
|
||||
*/
|
||||
private EstimatedWindFixesAsNavigableSet(TrackedRace trackedRace,
|
||||
TimePoint from, TimePoint to) {
|
||||
super(TrackBasedEstimationWindTrackImpl.this, trackedRace, from, to, /* resolution in milliseconds */ 1000l);
|
||||
}
|
||||
|
||||
protected Wind getWind(Position p, TimePoint timePoint) {
|
||||
return getTrack().getEstimatedWindDirection(p, timePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableSet<Wind> createSubset(WindTrack track, TrackedRace trackedRace, TimePoint from, TimePoint to) {
|
||||
return new EstimatedWindFixesAsNavigableSet(trackedRace, from, to);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
-1
@@ -52,7 +52,6 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
|
||||
/**
|
||||
* @param from expected to be an integer multiple of {@link #resolutionInMilliseconds} or <code>null</code>
|
||||
* @param to expected to be an integer multiple of {@link #resolutionInMilliseconds} or <code>null</code>
|
||||
* @param resolutionInMilliseconds TODO
|
||||
*/
|
||||
protected VirtualWindFixesAsNavigableSet(WindTrack track, TrackedRace trackedRace,
|
||||
TimePoint from, TimePoint to, long resolutionInMilliseconds) {
|
||||
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
|
||||
/**
|
||||
* A virtual wind track based on some virtual sequence of raw wind fixes.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public abstract class VirtualWindTrackImpl extends WindTrackImpl {
|
||||
private final TrackedRace trackedRace;
|
||||
|
||||
protected VirtualWindTrackImpl(TrackedRace trackedRace, long millisecondsOverWhichToAverage) {
|
||||
super(millisecondsOverWhichToAverage);
|
||||
this.trackedRace = trackedRace;
|
||||
}
|
||||
|
||||
protected TrackedRace getTrackedRace() {
|
||||
return trackedRace;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableSet<Wind> getInternalFixes() {
|
||||
return new PartialNavigableSetView<Wind>(getInternalRawFixes()) {
|
||||
@Override
|
||||
protected boolean isValid(Wind e) {
|
||||
return e != null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This redefinition avoids very long searches in case <code>at</code> is before the race start or after the race's
|
||||
* newest event. Should <code>at</code> be out of this range, it is set to the closest border of this range before
|
||||
* calling the base class's implementation. If either race start or time of newest event are not known, the known
|
||||
* time point is used instead. If both time points are not known, <code>null</code> is returned immediately.
|
||||
*/
|
||||
@Override
|
||||
public Wind getAveragedWind(Position p, TimePoint at) {
|
||||
Wind result = null;
|
||||
TimePoint adjustedAt;
|
||||
TimePoint raceStartTimePoint = trackedRace.getStart();
|
||||
TimePoint timePointOfNewestEvent = trackedRace.getTimePointOfNewestEvent();
|
||||
if (raceStartTimePoint != null) {
|
||||
if (timePointOfNewestEvent != null) {
|
||||
if (at.compareTo(raceStartTimePoint) < 0) {
|
||||
adjustedAt = raceStartTimePoint;
|
||||
} else if (at.compareTo(timePointOfNewestEvent) > 0) {
|
||||
adjustedAt = timePointOfNewestEvent;
|
||||
} else {
|
||||
adjustedAt = at;
|
||||
}
|
||||
} else {
|
||||
adjustedAt = raceStartTimePoint;
|
||||
}
|
||||
} else {
|
||||
if (timePointOfNewestEvent != null) {
|
||||
adjustedAt = timePointOfNewestEvent;
|
||||
} else {
|
||||
adjustedAt = null;
|
||||
}
|
||||
}
|
||||
if (adjustedAt != null) {
|
||||
// we can use the unsynchronized version here because our getInternalFixes() method operates
|
||||
// only on a virtual sequence of wind fixes where no concurrency issues have to be observed
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> estimatedWindUnsynchronized = getAveragedWindUnsynchronized(p, adjustedAt);
|
||||
result = estimatedWindUnsynchronized == null ? null : estimatedWindUnsynchronized.getObject();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user