diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationOnConstructedTracksTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationOnConstructedTracksTest.java
index 04bc19895b5..09c962b8fbd 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationOnConstructedTracksTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationOnConstructedTracksTest.java
@@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -18,6 +19,8 @@ import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.Competitor;
+import com.sap.sailing.domain.base.Distance;
+import com.sap.sailing.domain.base.Position;
import com.sap.sailing.domain.base.TimePoint;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
@@ -28,13 +31,18 @@ import com.sap.sailing.domain.base.impl.DegreePosition;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.NationalityImpl;
+import com.sap.sailing.domain.base.impl.NauticalMileDistance;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
+import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
+import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.MarkPassing;
+import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.Wind;
+import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
import com.sap.sailing.domain.tracking.impl.TrackBasedEstimationWindTrackImpl;
@@ -91,6 +99,52 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(bearingDeg))));
}
+ /**
+ * See bug #166
+ */
+ @Test
+ public void testWindEstimationCacheInvalidationAfterLegTypeChange() throws NoWindException {
+ initRace(2, new int[] { 1, 1 });
+ getTrackedRace().setRaceIsKnownToStartUpwind(false); // use only WEB wind to determine leg type
+ TimePoint now = getTrackedRace()
+ .getMarkPassingsInOrder(getTrackedRace().getRace().getCourse().getFirstWaypoint()).iterator().next()
+ .getTimePoint();
+ setBearingForCompetitor(competitors.get(0), now, 320);
+ setBearingForCompetitor(competitors.get(1), now, 50);
+ TrackedLeg firstLeg = getTrackedRace().getTrackedLeg(getTrackedRace().getRace().getCourse().getLegs().iterator().next());
+ assertEquals(LegType.UPWIND, firstLeg.getLegType(new MillisecondsTimePoint(MillisecondsTimePoint.now().asMillis()/2)));
+ final Map cachedFixes = new HashMap();
+ TrackBasedEstimationWindTrackImpl track = new TrackBasedEstimationWindTrackImpl(
+ getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000) {
+ @Override
+ protected void cache(TimePoint timePoint, Wind fix) {
+ super.cache(timePoint, fix);
+ if (fix != null) {
+ cachedFixes.put(timePoint, fix);
+ }
+ }
+ };
+ Wind estimatedWindDirection = track.getEstimatedWind(/* position */ null, now);
+ assertNotNull(estimatedWindDirection);
+ assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
+ assertFalse(cachedFixes.isEmpty());
+ assertEquals(185., cachedFixes.values().iterator().next().getBearing().getDegrees(), 0.00000001);
+ // now invert leg's type by moving the top mark along the wind from the leeward gate:
+ Iterator waypointsIter = getTrackedRace().getRace().getCourse().getWaypoints().iterator();
+ Waypoint leewardMark = waypointsIter.next();
+ Waypoint windwardMark = waypointsIter.next();
+ Position leewardGatePosition = getTrackedRace().getApproximatePosition(leewardMark, MillisecondsTimePoint.now());
+ Distance d = new NauticalMileDistance(1);
+ Wind wind = getTrackedRace().getWind(null, MillisecondsTimePoint.now(), WindSource.TRACK_BASED_ESTIMATION);
+ Position newWindwardMarkPosition = leewardGatePosition.translateGreatCircle(wind.getBearing(), d);
+ getTrackedRace().getOrCreateTrack(windwardMark.getBuoys().iterator().next()).addGPSFix(
+ new GPSFixImpl(newWindwardMarkPosition, MillisecondsTimePoint.now()));
+ assertEquals(LegType.DOWNWIND, firstLeg.getLegType(MillisecondsTimePoint.now()));
+ Wind estimatedWindDirectionDownwind = track.getEstimatedWind(/* position */ null, now);
+ assertNotNull(estimatedWindDirectionDownwind);
+ assertEquals(5., estimatedWindDirectionDownwind.getBearing().getDegrees(), 0.00000001);
+ }
+
@Test
public void testWindEstimationCaching() {
initRace(2, new int[] { 1, 1 });
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
index be74a4e7392..f68fd41ddcd 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
@@ -10,6 +10,7 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
+import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
@@ -45,6 +46,11 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
*/
private WindSource currentWindSource;
+ /**
+ * {@link #raceIsKnownToStartUpwind} (see also {@link #raceIsKnownToStartUpwind()}) is initialized based on the race's
+ * {@link RaceDefinition#getBoatClass()} boat class's {@link BoatClass#typicallyStartsUpwind()} result. It can be changed
+ * using {@link #setRaceIsKnownToStartUpwind(boolean)}.
+ */
public DynamicTrackedRaceImpl(TrackedEvent trackedEvent, RaceDefinition race,
WindStore windStore, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed) {
super(trackedEvent, race, windStore, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed);