Merge remote-tracking branch 'origin/master'

This commit is contained in:
fmittag
2012-03-09 15:38:34 +01:00
18 changed files with 161 additions and 67 deletions
@@ -12,39 +12,46 @@ public enum WindSourceType {
/**
* Manually entered via a web form or received through a REST service call, e.g., from BeTomorrow's estimation
*/
WEB(true),
WEB(true, 0.9),
/**
* Measured using wind sensors
*/
EXPEDITION(true),
EXPEDITION(true, 0.9),
/**
* Estimates wind conditions by analyzing the boat tracks; may not have results for all time points, e.g.,
* because at a given time point all boats may sail on the same tack and hence no averaging between the
* two tacks is possible. This is the more likely to happen the smaller the fleet tracked is.
*/
TRACK_BASED_ESTIMATION(false),
TRACK_BASED_ESTIMATION(false, 0.5),
/**
* Inferred from the race course layout if the course is known to have its first leg be an upwind leg
*/
COURSE_BASED(false),
COURSE_BASED(false, 0.3),
/**
* Wind estimation combined from all other wind sources, using <code>TrackedRace.getWind(...)</code>, based on
* confidences
*/
COMBINED(false);
COMBINED(false, 0.9);
private final boolean canBeStored;
private WindSourceType(boolean canBeStored) {
private final double baseConfidence;
private WindSourceType(boolean canBeStored, double baseConfidence) {
this.canBeStored = canBeStored;
this.baseConfidence = baseConfidence;
}
public boolean canBeStored() {
return canBeStored;
}
public double getBaseConfidence() {
return baseConfidence;
}
}
@@ -93,7 +93,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
@Override
public WindTrack loadWindTrack(Event event, RaceDefinition race, WindSource windSource, long millisecondsOverWhichToAverage) {
WindTrack result = new WindTrackImpl(millisecondsOverWhichToAverage);
WindTrack result = new WindTrackImpl(millisecondsOverWhichToAverage, windSource.getType().getBaseConfidence());
try {
BasicDBObject query = new BasicDBObject();
query.put(FieldNames.EVENT_NAME.name(), event.getName());
@@ -289,7 +289,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
WindTrack track = result.get(windSource);
if (track == null) {
track = new WindTrackImpl(millisecondsOverWhichToAverageWind);
track = new WindTrackImpl(millisecondsOverWhichToAverageWind, windSource.getType().getBaseConfidence());
result.put(windSource, track);
}
track.add(wind);
@@ -109,7 +109,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(/* position */ null, now);
// less precision because downwind estimation has less confidence
assertEquals(180., estimatedWindDirection.getBearing().getDegrees(), 0.2);
CombinedWindTrackImpl combinedTrack = new CombinedWindTrackImpl(getTrackedRace());
CombinedWindTrackImpl combinedTrack = new CombinedWindTrackImpl(getTrackedRace(), WindSourceType.COMBINED.getBaseConfidence());
Wind combinedWindDirection = combinedTrack.getAveragedWind(/* position */ null, now);
assertEquals(180., combinedWindDirection.getBearing().getDegrees(), 0.2); // a bit less precise as course-based wind isn't exactly 180deg
}
@@ -132,7 +132,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
assertEquals(LegType.UPWIND, firstLeg.getLegType(new MillisecondsTimePoint(MillisecondsTimePoint.now().asMillis())));
final Map<TimePoint, Wind> cachedFixes = new HashMap<TimePoint, Wind>();
TrackBasedEstimationWindTrackImpl track = new TrackBasedEstimationWindTrackImpl(
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000) {
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000, WindSourceType.TRACK_BASED_ESTIMATION.getBaseConfidence()) {
@Override
protected void cache(TimePoint timePoint, Wind fix) {
super.cache(timePoint, fix);
@@ -172,7 +172,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
setBearingForCompetitor(competitors.get(1), checkTime, 50);
final Map<TimePoint, Wind> cachedFixes = new HashMap<TimePoint, Wind>();
TrackBasedEstimationWindTrackImpl track = new TrackBasedEstimationWindTrackImpl(
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000) {
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000, WindSourceType.TRACK_BASED_ESTIMATION.getBaseConfidence()) {
@Override
protected void cache(TimePoint timePoint, Wind fix) {
super.cache(timePoint, fix);
@@ -58,7 +58,7 @@ public class WindEstimationOnKielerWoche505Race2DataTest extends OnlineTracTracB
// hence have a direction change.
TimePoint middle = new MillisecondsTimePoint(1308839492322l);
TrackBasedEstimationWindTrackImpl estimatedWindTrack = new TrackBasedEstimationWindTrackImpl(getTrackedRace(),
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND);
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, WindSourceType.TRACK_BASED_ESTIMATION.getBaseConfidence());
Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(/* position */ null, middle);
assertNotNull(estimatedWindDirection);
Wind estimationBasedOnTrack = estimatedWindTrack.getAveragedWind(null, middle);
@@ -2,11 +2,13 @@ package com.sap.sailing.domain.tracking.impl;
import java.util.NavigableSet;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
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;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl.DummyWind;
/**
* Delivers what {@link TrackedRace#getWind(Position, TimePoint)} delivers, as a navigable set.
@@ -35,4 +37,16 @@ public class CombinedWindAsNavigableSet extends VirtualWindFixesAsNavigableSet {
return new CombinedWindAsNavigableSet(track, trackedRace, from, to, getResolutionInMilliseconds());
}
/**
* Time point up to and including which the GPS fixes are considered in the race's tracks. Returns the value of
* {@link #to} unless it is <code>null</code>. In this case, the time point of the
* {@link TrackedRace#getAssumedEnd() assumed end of race},
* {@link #ceilingToResolution(Wind) ceiled to the resolution of this set} will be returned instead. If no valid
* time of a newest event can be obtained from the race, <code>MillisecondsTimePoint(1)</code> is returned instead.
*/
protected TimePoint getTo() {
return getToInternal() == null ? getTrackedRace().getAssumedEnd() == null ? new MillisecondsTimePoint(1)
: ceilingToResolution(new DummyWind(getTrackedRace().getAssumedEnd())) : getToInternal();
}
}
@@ -14,8 +14,8 @@ import com.sap.sailing.domain.tracking.impl.TrackBasedEstimationWindTrackImpl.Es
public class CombinedWindTrackImpl extends VirtualWindTrackImpl {
private CombinedWindAsNavigableSet virtualInternalRawFixes;
public CombinedWindTrackImpl(TrackedRace trackedRace) {
super(trackedRace, /* millisecondsOverWhichToAverage not used, see overridden method */ -1);
public CombinedWindTrackImpl(TrackedRace trackedRace, double baseConfidence) {
super(trackedRace, /* millisecondsOverWhichToAverage not used, see overridden method */ -1, baseConfidence);
virtualInternalRawFixes = new CombinedWindAsNavigableSet(this, trackedRace, /* resolutionInMilliseconds */ 10000l);
}
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking.impl;
import java.util.NavigableSet;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.Wind;
@@ -19,11 +20,17 @@ import com.sap.sailing.util.impl.UnmodifiableNavigableSet;
*
*/
public class CourseBasedWindTrackImpl extends WindTrackImpl {
/**
* The first leg's direction will be measured this many milliseconds before the estimated race start time,
* at estimated race start time and this many milliseconds after estimated race start time.
*/
private final long MILLISECONDS_AROUND_START_TO_TRACK = 30000l;
private final TrackedRace trackedRace;
private static final NavigableSet<Wind> empty = new UnmodifiableNavigableSet<Wind>(new ArrayListNavigableSet<Wind>(WindComparator.INSTANCE));
public CourseBasedWindTrackImpl(TrackedRace trackedRace, long millisecondsOverWhichToAverage) {
super(millisecondsOverWhichToAverage);
public CourseBasedWindTrackImpl(TrackedRace trackedRace, long millisecondsOverWhichToAverage, double baseConfidence) {
super(millisecondsOverWhichToAverage, baseConfidence);
this.trackedRace = trackedRace;
}
@@ -33,10 +40,13 @@ public class CourseBasedWindTrackImpl extends WindTrackImpl {
if (trackedRace.raceIsKnownToStartUpwind()) {
TimePoint startTime = trackedRace.getStart();
if (startTime != null) {
result = new ArrayListNavigableSet<Wind>(1, WindComparator.INSTANCE);
final Wind directionFromStartToNextMark = trackedRace.getDirectionFromStartToNextMark(startTime);
if (directionFromStartToNextMark != null) {
result.add(directionFromStartToNextMark);
result = new ArrayListNavigableSet<Wind>(3, WindComparator.INSTANCE);
for (long t = startTime.asMillis() - MILLISECONDS_AROUND_START_TO_TRACK; t <= startTime.asMillis()
+ MILLISECONDS_AROUND_START_TO_TRACK; t += MILLISECONDS_AROUND_START_TO_TRACK) {
final Wind directionFromStartToNextMark = trackedRace.getDirectionFromStartToNextMark(new MillisecondsTimePoint(t));
if (directionFromStartToNextMark != null) {
result.add(directionFromStartToNextMark);
}
}
} else {
result = empty;
@@ -4,6 +4,7 @@ import java.util.Collections;
import java.util.Map;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.tracking.TrackedEvent;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindStore;
@@ -17,9 +18,10 @@ public class EmptyWindStore implements WindStore {
long millisecondsOverWhichToAverage) {
switch (windSource.getType()) {
case COURSE_BASED:
return new CourseBasedWindTrackImpl(trackedRace, millisecondsOverWhichToAverage);
return new CourseBasedWindTrackImpl(trackedRace, millisecondsOverWhichToAverage, WindSourceType.COURSE_BASED.getBaseConfidence());
case TRACK_BASED_ESTIMATION:
return new TrackBasedEstimationWindTrackImpl(trackedRace, millisecondsOverWhichToAverage);
return new TrackBasedEstimationWindTrackImpl(trackedRace, millisecondsOverWhichToAverage,
WindSourceType.TRACK_BASED_ESTIMATION.getBaseConfidence());
default:
return new WindTrackImpl(millisecondsOverWhichToAverage);
}
@@ -61,8 +61,8 @@ public class TrackBasedEstimationWindTrackImpl extends VirtualWindTrackImpl impl
*/
private final HashSet<TimePoint> timePointsWithCachedNullResultFastContains;
public TrackBasedEstimationWindTrackImpl(TrackedRace trackedRace, long millisecondsOverWhichToAverage) {
super(trackedRace, millisecondsOverWhichToAverage);
public TrackBasedEstimationWindTrackImpl(TrackedRace trackedRace, long millisecondsOverWhichToAverage, double baseConfidence) {
super(trackedRace, millisecondsOverWhichToAverage, baseConfidence);
virtualInternalRawFixes = new EstimatedWindFixesAsNavigableSet(trackedRace);
trackedRace.addListener(this);
this.timePointsWithCachedNullResult = new ArrayListNavigableSet<TimePoint>(AbstractTimePoint.TIMEPOINT_COMPARATOR);
@@ -161,20 +161,22 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
}
private Wind getWindOnLeg(TimePoint at) {
Wind wind;
Position approximateLegStartPosition = getTrackedRace().getOrCreateTrack(
getLeg().getFrom().getBuoys().iterator().next()).getEstimatedPosition(at, false);
Position approximateLegEndPosition = getTrackedRace().getOrCreateTrack(
getLeg().getTo().getBuoys().iterator().next()).getEstimatedPosition(at, false);
if (approximateLegStartPosition == null || approximateLegEndPosition == null) {
throw new RuntimeException("No mark positions received yet for leg "+getLeg()+
". Can't determine wind direction since position is not known.");
wind = null;
} else {
// exclude track-based estimation; it is itself based on the leg type which is based on the getWindOnLeg
// result which
// would therefore lead to an endless recursion without further tricks being applied
wind = getWind(approximateLegStartPosition.translateGreatCircle(
approximateLegStartPosition.getBearingGreatCircle(approximateLegEndPosition),
approximateLegStartPosition.getDistance(approximateLegEndPosition).scale(0.5)), at,
getTrackedRace().getWindSources(WindSourceType.TRACK_BASED_ESTIMATION));
}
// exclude track-based estimation; it is itself based on the leg type which is based on the getWindOnLeg result which
// would therefore lead to an endless recursion without further tricks being applied
Wind wind = getWind(
approximateLegStartPosition.translateGreatCircle(approximateLegStartPosition.getBearingGreatCircle(approximateLegEndPosition),
approximateLegStartPosition.getDistance(approximateLegEndPosition).scale(0.5)), at,
getTrackedRace().getWindSources(WindSourceType.TRACK_BASED_ESTIMATION));
return wind;
}
@@ -134,7 +134,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
*/
private final Map<WindSource, WindTrack> windTracks;
private Wind directionFromStartToNextMarkCache;
private final Map<TimePoint, Wind> directionFromStartToNextMarkCache;
private final Map<Buoy, GPSFixTrack<Buoy, GPSFix>> buoyTracks;
@@ -152,6 +152,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
this.updateCount = 0;
this.race = race;
this.windStore = windStore;
this.directionFromStartToNextMarkCache = new HashMap<TimePoint, Wind>();
this.millisecondsOverWhichToAverageSpeed = millisecondsOverWhichToAverageSpeed;
this.millisecondsOverWhichToAverageWind = millisecondsOverWhichToAverageWind;
this.startToNextMarkCacheInvalidationListeners = new HashMap<Buoy, TrackedRaceImpl.StartToNextMarkCacheInvalidationListener>();
@@ -523,7 +524,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
public WindTrack getOrCreateWindTrack(WindSource windSource) {
WindTrack result;
if (windSource.getType() == WindSourceType.COMBINED) {
result = new CombinedWindTrackImpl(this);
result = new CombinedWindTrackImpl(this, WindSourceType.COMBINED.getBaseConfidence());
} else {
synchronized (windTracks) {
result = windTracks.get(windSource);
@@ -591,18 +592,21 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
@Override
public Wind getDirectionFromStartToNextMark(TimePoint at) {
Wind result = directionFromStartToNextMarkCache;
if (result == null) {
Leg firstLeg = getRace().getCourse().getLegs().iterator().next();
Position firstLegEnd = getApproximatePosition(firstLeg.getTo(), at);
Position firstLegStart = getApproximatePosition(firstLeg.getFrom(), at);
if (firstLegStart != null && firstLegEnd != null) {
result = new WindImpl(firstLegStart, at, new KnotSpeedWithBearingImpl(1.0,
firstLegEnd.getBearingGreatCircle(firstLegStart)));
final Wind finalResult = result;
directionFromStartToNextMarkCache = finalResult;
} else {
result = null;
Wind result;
synchronized (directionFromStartToNextMarkCache) {
result = directionFromStartToNextMarkCache.get(at);
if (result == null) {
Leg firstLeg = getRace().getCourse().getLegs().iterator().next();
Position firstLegEnd = getApproximatePosition(firstLeg.getTo(), at);
Position firstLegStart = getApproximatePosition(firstLeg.getFrom(), at);
if (firstLegStart != null && firstLegEnd != null) {
result = new WindImpl(firstLegStart, at, new KnotSpeedWithBearingImpl(1.0,
firstLegEnd.getBearingGreatCircle(firstLegStart)));
final Wind finalResult = result;
directionFromStartToNextMarkCache.put(at, finalResult);
} else {
result = null;
}
}
}
return result;
@@ -686,7 +690,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
if (zeroBasedIndex < 2) {
// the observing listener on any previous buoy will be GCed; we need to ensure
// that the cache is recomputed
directionFromStartToNextMarkCache = null;
clearDirectionFromStartToNextMarkCache();
Iterator<Waypoint> waypointsIter = getRace().getCourse().getWaypoints().iterator();
waypointsIter.next(); // skip first
if (waypointsIter.hasNext()) {
@@ -700,6 +704,12 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
addStartToNextMarkCacheInvalidationListener(waypointThatGotAdded);
}
private void clearDirectionFromStartToNextMarkCache() {
synchronized (directionFromStartToNextMarkCache) {
directionFromStartToNextMarkCache.clear();
}
}
private void addStartToNextMarkCacheInvalidationListener(Waypoint waypoint) {
for (Buoy buoy : waypoint.getBuoys()) {
addStartToNextMarkCacheInvalidationListener(buoy);
@@ -756,7 +766,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
if (zeroBasedIndex < 2) {
// the observing listener on any previous buoy will be GCed; we need to ensure
// that the cache is recomputed
directionFromStartToNextMarkCache = null;
clearDirectionFromStartToNextMarkCache();
stopAndRemoveStartToNextMarkCacheInvalidationListener(waypointThatGotRemoved);
Iterator<Waypoint> waypointsIter = getRace().getCourse().getWaypoints().iterator();
waypointsIter.next(); // skip first
@@ -1253,7 +1263,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
@Override
public void gpsFixReceived(GPSFix fix, Buoy buoy) {
directionFromStartToNextMarkCache = null;
clearDirectionFromStartToNextMarkCache();
}
@Override
@@ -74,7 +74,7 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
protected TimePoint lowerToResolution(Wind w) {
TimePoint result;
final TimePoint timePointOfLastEvent = trackedRace.getTimePointOfLastEvent();
final TimePoint timePointOfLastEvent = getTrackedRace().getTimePointOfLastEvent();
if (timePointOfLastEvent == null) {
// nothing received yet; "lowering" to end of time
result = new MillisecondsTimePoint((Long.MAX_VALUE - 1) / getResolutionInMilliseconds()
@@ -90,7 +90,7 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
protected TimePoint floorToResolution(Wind w) {
TimePoint result;
final TimePoint timePointOfLastEvent = trackedRace.getTimePointOfLastEvent();
final TimePoint timePointOfLastEvent = getTrackedRace().getTimePointOfLastEvent();
if (timePointOfLastEvent == null) {
// nothing received yet; "lowering" to end of time
result = new MillisecondsTimePoint((Long.MAX_VALUE - 1) / getResolutionInMilliseconds()
@@ -106,7 +106,7 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
protected TimePoint ceilingToResolution(Wind w) {
TimePoint result;
final TimePoint startOfTracking = trackedRace.getStartOfTracking();
final TimePoint startOfTracking = getTrackedRace().getStartOfTracking();
if (startOfTracking == null) {
// no start of tracking yet; "ceiling" to beginning of time
result = new MillisecondsTimePoint(0);
@@ -121,7 +121,7 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
protected TimePoint higherToResolution(Wind w) {
TimePoint result;
final TimePoint startOfTracking = trackedRace.getStartOfTracking();
final TimePoint startOfTracking = getTrackedRace().getStartOfTracking();
if (startOfTracking == null) {
// no start of tracking yet; "ceiling" to beginning of time
result = new MillisecondsTimePoint(0);
@@ -141,9 +141,9 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
* will be returned instead. If no valid start time can be obtained from the race, <code>Long.MAX_VALUE</code> is
* returned instead.
*/
private TimePoint getFrom() {
return from == null ? trackedRace.getStart() == null ? new MillisecondsTimePoint(Long.MAX_VALUE)
: floorToResolution(new DummyWind(trackedRace.getStart())) : from;
protected TimePoint getFrom() {
return from == null ? getTrackedRace().getStart() == null ? new MillisecondsTimePoint(Long.MAX_VALUE)
: floorToResolution(new DummyWind(getTrackedRace().getStart())) : from;
}
/**
@@ -153,9 +153,9 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
* {@link #ceilingToResolution(Wind) ceiled to the resolution of this set} will be returned instead. If no valid
* time of a newest event can be obtained from the race, <code>MillisecondsTimePoint(1)</code> is returned instead.
*/
private TimePoint getTo() {
return to == null ? trackedRace.getTimePointOfNewestEvent() == null ? new MillisecondsTimePoint(1)
: ceilingToResolution(new DummyWind(trackedRace.getTimePointOfNewestEvent())) : to;
protected TimePoint getTo() {
return getToInternal() == null ? getTrackedRace().getTimePointOfNewestEvent() == null ? new MillisecondsTimePoint(1)
: ceilingToResolution(new DummyWind(getTrackedRace().getTimePointOfNewestEvent())) : getToInternal();
}
@Override
@@ -242,7 +242,7 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
@Override
public NavigableSet<Wind> subSet(Wind fromElement, boolean fromInclusive, Wind toElement, boolean toInclusive) {
return createSubset(track, trackedRace, fromInclusive ? ceilingToResolution(fromElement)
return createSubset(track, getTrackedRace(), fromInclusive ? ceilingToResolution(fromElement)
: higherToResolution(fromElement), toInclusive ? floorToResolution(toElement)
: lowerToResolution(toElement));
}
@@ -254,13 +254,13 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
@Override
public NavigableSet<Wind> headSet(Wind toElement, boolean inclusive) {
return createSubset(track, trackedRace, /* from */ null,
return createSubset(track, getTrackedRace(), /* from */ null,
inclusive ? ceilingToResolution(toElement) : lowerToResolution(toElement));
}
@Override
public NavigableSet<Wind> tailSet(Wind fromElement, boolean inclusive) {
return createSubset(track, trackedRace, inclusive ? floorToResolution(fromElement)
return createSubset(track, getTrackedRace(), inclusive ? floorToResolution(fromElement)
: higherToResolution(fromElement),
/* to */ null);
}
@@ -335,5 +335,9 @@ public abstract class VirtualWindFixesAsNavigableSet extends AbstractUnmodifiabl
T[] tResult = (T[]) result;
return tResult;
}
protected TimePoint getToInternal() {
return to;
}
}
@@ -20,8 +20,8 @@ import com.sap.sailing.domain.tracking.WindWithConfidence;
public abstract class VirtualWindTrackImpl extends WindTrackImpl {
private final TrackedRace trackedRace;
protected VirtualWindTrackImpl(TrackedRace trackedRace, long millisecondsOverWhichToAverage) {
super(millisecondsOverWhichToAverage);
protected VirtualWindTrackImpl(TrackedRace trackedRace, long millisecondsOverWhichToAverage, double baseConfidence) {
super(millisecondsOverWhichToAverage, baseConfidence);
this.trackedRace = trackedRace;
}
@@ -37,11 +37,24 @@ import com.sap.sailing.util.impl.ArrayListNavigableSet;
public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
private final static Logger logger = Logger.getLogger(WindTrackImpl.class.getName());
private final static double DEFAULT_BASE_CONFIDENCE = 0.9;
private final double baseConfidence;
private long millisecondsOverWhichToAverage;
private final Set<WindListener> listeners;
public WindTrackImpl(long millisecondsOverWhichToAverage) {
this(millisecondsOverWhichToAverage, DEFAULT_BASE_CONFIDENCE);
}
/**
* @param baseConfidence
* the confidence to attribute to the raw wind fixes in this track
*/
public WindTrackImpl(long millisecondsOverWhichToAverage, double baseConfidence) {
super(new ArrayListNavigableSet<Timed>(WindComparator.INSTANCE));
this.baseConfidence = baseConfidence;
this.millisecondsOverWhichToAverage = millisecondsOverWhichToAverage;
listeners = new HashSet<WindListener>();
}
@@ -209,7 +222,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
* represent <em>the truth</em>. 0.0 means "no relevance at all."
*/
private double getBaseConfidence() {
return /* confidence */ 0.9;
return baseConfidence;
}
@Override
@@ -129,3 +129,6 @@ body, table td, select, button {
margin-top: 7px;
}
.errorLabel {
color: #FF0000;
}
+5 -1
View File
@@ -247,4 +247,8 @@ input.magnifier {
.breadcrumbPanel-NextArrow {
display: none;
}
}
.errorLabel {
color: #FF0000;
}
@@ -343,3 +343,7 @@ input.magnifier {
background: #c0bebe;
font-family: 'UbuntuRegular', Arial, Verdana, sans-serif
}
.errorLabel {
color: #FF0000;
}
@@ -20,6 +20,8 @@ import org.moxieapps.gwt.highcharts.client.ToolTipData;
import org.moxieapps.gwt.highcharts.client.ToolTipFormatter;
import org.moxieapps.gwt.highcharts.client.events.ChartClickEvent;
import org.moxieapps.gwt.highcharts.client.events.ChartClickEventHandler;
import org.moxieapps.gwt.highcharts.client.events.ChartSelectionEvent;
import org.moxieapps.gwt.highcharts.client.events.ChartSelectionEventHandler;
import org.moxieapps.gwt.highcharts.client.plotOptions.LinePlotOptions;
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
@@ -61,6 +63,7 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
private final ErrorReporter errorReporter;
private final SailingServiceAsync sailingService;
private final Chart chart;
private boolean ignoreClickOnce;
private final Timer timer;
private final DateTimeFormat dateFormat = DateTimeFormat.getFormat("HH:mm:ss");
@@ -114,10 +117,28 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
chart.setClickEventHandler(new ChartClickEventHandler() {
@Override
public boolean onClick(ChartClickEvent chartClickEvent) {
WindChart.this.timer.setTime(chartClickEvent.getXAxisValueAsLong());
if (ignoreClickOnce) {
ignoreClickOnce = false;
} else {
WindChart.this.timer.setTime(chartClickEvent.getXAxisValueAsLong());
}
return true;
}
});
chart.setSelectionEventHandler(new ChartSelectionEventHandler() {
@Override
public boolean onSelection(ChartSelectionEvent chartSelectionEvent) {
try {
chartSelectionEvent.getXAxisMaxAsLong();
chartSelectionEvent.getXAxisMinAsLong();
ignoreClickOnce = true;
return true;
} catch (Throwable t) {
chart.redraw();
return true;
}
}
});
chart.getXAxis().setType(Axis.Type.DATE_TIME).setMaxZoom(10000) // ten seconds
.setAxisTitleText(stringMessages.time());
chart.getYAxis(0).setAxisTitleText(stringMessages.fromDeg()).setStartOnTick(false).setShowFirstLabel(false);