diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CombinedWindAsNavigableSet.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CombinedWindAsNavigableSet.java new file mode 100755 index 00000000000..333ace6b6b0 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CombinedWindAsNavigableSet.java @@ -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 createSubset(WindTrack track, TrackedRace trackedRace, TimePoint from, TimePoint to) { + return new CombinedWindAsNavigableSet(track, trackedRace, from, to, getResolutionInMilliseconds()); + } + +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/EstimatedWindFixesAsNavigableSet.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/EstimatedWindFixesAsNavigableSet.java deleted file mode 100755 index 44509069a69..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/EstimatedWindFixesAsNavigableSet.java +++ /dev/null @@ -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 null, {@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 null, 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 null - * @param to expected to be an integer multiple of {@link #getResolutionInMilliseconds()} or null - */ - 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 createSubset(WindTrack track, TrackedRace trackedRace, TimePoint from, TimePoint to) { - return new EstimatedWindFixesAsNavigableSet(track, trackedRace, from, to); - } - -} - diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackBasedEstimationWindTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackBasedEstimationWindTrackImpl.java index 00c498ca33b..8aebb1dd83b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackBasedEstimationWindTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackBasedEstimationWindTrackImpl.java @@ -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,11 +51,9 @@ import com.sap.sailing.util.impl.ArrayListNavigableSet; * @author Axel Uhl (d043530) * */ -public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements RaceChangeListener { - private final EstimatedWindFixesAsNavigableSet virtualInternalRawFixes; +public class TrackBasedEstimationWindTrackImpl extends VirtualWindTrackImpl implements RaceChangeListener { + private final VirtualWindFixesAsNavigableSet virtualInternalRawFixes; - private final TrackedRace trackedRace; - private final NavigableSet timePointsWithCachedNullResult; /** @@ -63,10 +62,9 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements private final HashSet 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(AbstractTimePoint.TIMEPOINT_COMPARATOR); this.timePointsWithCachedNullResultFastContains = new HashSet(); } @@ -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 getCachedFixes() { @@ -149,7 +152,7 @@ public class TrackBasedEstimationWindTrackImpl extends WindTrackImpl implements NavigableSet 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 getInternalRawFixes() { - return virtualInternalRawFixes; - } - - @Override - protected NavigableSet getInternalFixes() { - return new PartialNavigableSetView(getInternalRawFixes()) { - @Override - protected boolean isValid(Wind e) { - return e != null; - } - }; - } - /** * This redefinition avoids very long searches in case at is before the race start or after the race's * newest event. Should at 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 interval = trackedRace.getOrCreateTrack(buoy).getEstimatedPositionTimePeriodAffectedBy(fix); + Pair 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 null, {@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 null, 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 null + * @param to expected to be an integer multiple of {@link #getResolutionInMilliseconds()} or null + */ + 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 createSubset(WindTrack track, TrackedRace trackedRace, TimePoint from, TimePoint to) { + return new EstimatedWindFixesAsNavigableSet(trackedRace, from, to); + } + + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/VirtualWindFixesAsNavigableSet.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/VirtualWindFixesAsNavigableSet.java index 8d72532a401..d16ab52ab0b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/VirtualWindFixesAsNavigableSet.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/VirtualWindFixesAsNavigableSet.java @@ -52,7 +52,6 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl /** * @param from expected to be an integer multiple of {@link #resolutionInMilliseconds} or null * @param to expected to be an integer multiple of {@link #resolutionInMilliseconds} or null - * @param resolutionInMilliseconds TODO */ protected VirtualWindFixesAsNavigableSet(WindTrack track, TrackedRace trackedRace, TimePoint from, TimePoint to, long resolutionInMilliseconds) { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/VirtualWindTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/VirtualWindTrackImpl.java new file mode 100755 index 00000000000..040a20d7fbf --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/VirtualWindTrackImpl.java @@ -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 getInternalFixes() { + return new PartialNavigableSetView(getInternalRawFixes()) { + @Override + protected boolean isValid(Wind e) { + return e != null; + } + }; + } + + /** + * This redefinition avoids very long searches in case at is before the race start or after the race's + * newest event. Should at 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, null 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> estimatedWindUnsynchronized = getAveragedWindUnsynchronized(p, adjustedAt); + result = estimatedWindUnsynchronized == null ? null : estimatedWindUnsynchronized.getObject(); + } + return result; + } + +}