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);