aff9a32e93028de89f8a06f2814d3061a7a1a7be
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseChangeBasedTrackApproximationTest.java
| ... | ... | @@ -1,7 +1,15 @@ |
| 1 | 1 | package com.sap.sailing.domain.test; |
| 2 | 2 | |
| 3 | +import static org.junit.jupiter.api.Assertions.assertEquals; |
|
| 4 | +import static org.junit.jupiter.api.Assertions.assertFalse; |
|
| 3 | 5 | import static org.junit.jupiter.api.Assertions.assertTrue; |
| 4 | 6 | |
| 7 | +import java.io.File; |
|
| 8 | +import java.net.MalformedURLException; |
|
| 9 | +import java.net.URI; |
|
| 10 | +import java.net.URISyntaxException; |
|
| 11 | +import java.net.URL; |
|
| 12 | + |
|
| 5 | 13 | import org.junit.jupiter.api.BeforeEach; |
| 6 | 14 | import org.junit.jupiter.api.Test; |
| 7 | 15 | |
| ... | ... | @@ -15,24 +23,80 @@ import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; |
| 15 | 23 | import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; |
| 16 | 24 | import com.sap.sailing.domain.tracking.impl.CourseChangeBasedTrackApproximation; |
| 17 | 25 | import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl; |
| 26 | +import com.sap.sailing.domain.tractracadapter.ReceiverType; |
|
| 18 | 27 | import com.sap.sse.common.TimePoint; |
| 19 | 28 | import com.sap.sse.common.Util; |
| 20 | 29 | import com.sap.sse.common.impl.DegreeBearingImpl; |
| 21 | 30 | import com.sap.sse.common.impl.MillisecondsDurationImpl; |
| 22 | 31 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 23 | 32 | |
| 24 | -public class CourseChangeBasedTrackApproximationTest { |
|
| 33 | +public class CourseChangeBasedTrackApproximationTest extends OnlineTracTracBasedTest { |
|
| 25 | 34 | private DynamicGPSFixTrack<Competitor, GPSFixMoving> track; |
| 26 | 35 | private CourseChangeBasedTrackApproximation approximation; |
| 27 | 36 | |
| 37 | + public CourseChangeBasedTrackApproximationTest() throws MalformedURLException, URISyntaxException { |
|
| 38 | + super(); |
|
| 39 | + } |
|
| 40 | + |
|
| 28 | 41 | @BeforeEach |
| 29 | - public void setUp() throws InterruptedException { |
|
| 42 | + public void setUp() throws Exception { |
|
| 43 | + super.setUp(); |
|
| 44 | + URI storedUri = new URI("file:///" + new File("resources/event_20110609_KielerWoch-505_Race_2.mtb").getCanonicalPath().replace('\\', '/')); |
|
| 45 | + super.setUp( |
|
| 46 | + new URL("file:///" + new File("resources/event_20110609_KielerWoch-505_Race_2.txt").getCanonicalPath()), |
|
| 47 | + /* liveUri */ null, /* storedUri */ storedUri, |
|
| 48 | + new ReceiverType[] { ReceiverType.RACECOURSE, ReceiverType.RAWPOSITIONS }); |
|
| 49 | + assertFalse(Util.isEmpty(getTrackedRace().getRace().getCompetitors())); |
|
| 50 | + final DynamicGPSFixTrack<Competitor, GPSFixMoving> sampleTrack = getTrackedRace().getTrack(getTrackedRace().getRace().getCompetitors().iterator().next()); |
|
| 51 | + sampleTrack.lockForRead(); |
|
| 52 | + try { |
|
| 53 | + assertFalse(Util.isEmpty(sampleTrack.getRawFixes())); |
|
| 54 | + } finally { |
|
| 55 | + sampleTrack.unlockAfterRead(); |
|
| 56 | + } |
|
| 30 | 57 | final CompetitorWithBoat competitor = TrackBasedTest.createCompetitorWithBoat("Someone"); |
| 31 | 58 | track = new DynamicGPSFixMovingTrackImpl<Competitor>(competitor, |
| 32 | 59 | /* millisecondsOverWhichToAverage */5000, /* lossless compaction */true); |
| 33 | 60 | approximation = new CourseChangeBasedTrackApproximation(track, competitor.getBoat().getBoatClass()); |
| 34 | 61 | } |
| 35 | 62 | |
| 63 | + /** |
|
| 64 | + * During the work on bug5959 (https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=5959) we identified an issue |
|
| 65 | + * with early vs. late initialization of the approximation. When initializing the |
|
| 66 | + * {@link CourseChangeBasedTrackApproximation} objects before adding any fixes to the track, we received different |
|
| 67 | + * results than when initializing it after adding fixes and first trying to compute maneuvers. This goes against the |
|
| 68 | + * specification that the approximation should be independent of when it is initialized.<p> |
|
| 69 | + * |
|
| 70 | + * To conduct the test, we take the fixes from a loaded competitor track, create a new {@link DynamicGPSFixMovingTrackImpl}, |
|
| 71 | + * construct a {@link CourseChangeBasedTrackApproximation} based on this track (early initialization), then copy all fixes |
|
| 72 | + * from the loaded competitor track to the new test track (which adds these fixes to the approximation), then create a second |
|
| 73 | + * {@link CourseChangeBasedTrackApproximation} which will then add all fixes in one sweep. Then, we compare the results of |
|
| 74 | + * {@link CourseChangeBasedTrackApproximation#approximate(TimePoint, TimePoint)} for the duration of the entire track, |
|
| 75 | + * expecting them to be equal. |
|
| 76 | + */ |
|
| 77 | + @Test |
|
| 78 | + public void testNoDiffBetweenEarlyAndLateInitialization() { |
|
| 79 | + final CompetitorWithBoat sampleCompetitor = (CompetitorWithBoat) getTrackedRace().getRace().getCompetitors().iterator().next(); |
|
| 80 | + final DynamicGPSFixTrack<Competitor, GPSFixMoving> sampleTrack = getTrackedRace().getTrack(sampleCompetitor); |
|
| 81 | + final DynamicGPSFixTrack<Competitor, GPSFixMoving> trackCopy = new DynamicGPSFixMovingTrackImpl<Competitor>(sampleCompetitor, /* millisecondsOverWhichToAverage */ 15000); |
|
| 82 | + final CourseChangeBasedTrackApproximation earlyInitApproximation = new CourseChangeBasedTrackApproximation(trackCopy, sampleCompetitor.getBoat().getBoatClass()); |
|
| 83 | + final TimePoint from = sampleTrack.getFirstRawFix().getTimePoint(); |
|
| 84 | + final TimePoint to = sampleTrack.getLastRawFix().getTimePoint(); |
|
| 85 | + sampleTrack.lockForRead(); |
|
| 86 | + try { |
|
| 87 | + for (final GPSFixMoving fix : sampleTrack.getRawFixes()) { |
|
| 88 | + trackCopy.add(fix); |
|
| 89 | + } |
|
| 90 | + } finally { |
|
| 91 | + sampleTrack.unlockAfterRead(); |
|
| 92 | + } |
|
| 93 | + final CourseChangeBasedTrackApproximation lateInitApproximation = new CourseChangeBasedTrackApproximation(trackCopy, sampleCompetitor.getBoat().getBoatClass()); |
|
| 94 | + final Iterable<GPSFixMoving> earlyInitResult = earlyInitApproximation.approximate(from, to); |
|
| 95 | + final Iterable<GPSFixMoving> lateInitResult = lateInitApproximation.approximate(from, to); |
|
| 96 | + assertEquals(Util.size(earlyInitResult), Util.size(lateInitResult)); |
|
| 97 | + assertEquals(Util.asSet(earlyInitResult), Util.asSet(lateInitResult)); |
|
| 98 | + } |
|
| 99 | + |
|
| 36 | 100 | @Test |
| 37 | 101 | public void simpleTackRecognition() { |
| 38 | 102 | final GPSFixMoving start = fix(10000l, 0, 0, 5, 0); |
| ... | ... | @@ -51,7 +115,6 @@ public class CourseChangeBasedTrackApproximationTest { |
| 51 | 115 | for (int i=0; i<20; i++) { |
| 52 | 116 | track.add(next = travel(next, 1000 /*ms*/, 5 /* knots */, 270 /*deg COG*/)); |
| 53 | 117 | } |
| 54 | - |
|
| 55 | 118 | Iterable<GPSFixMoving> candidates = approximation.approximate(start.getTimePoint(), next.getTimePoint()); |
| 56 | 119 | assertTrue(Util.size(candidates) >= 1); |
| 57 | 120 | for (final GPSFixMoving candidate : candidates) { |
| ... | ... | @@ -68,5 +131,4 @@ public class CourseChangeBasedTrackApproximationTest { |
| 68 | 131 | return new GPSFixMovingImpl(fix.getPosition().translateGreatCircle(new DegreeBearingImpl(cogDeg), new KnotSpeedImpl(speedInKnots).travel(new MillisecondsDurationImpl(durationInMillis))), |
| 69 | 132 | fix.getTimePoint().plus(durationInMillis), new KnotSpeedWithBearingImpl(speedInKnots, new DegreeBearingImpl(cogDeg)), /* optionalTrueHeading */ null); |
| 70 | 133 | } |
| 71 | - |
|
| 72 | 134 | } |
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
| ... | ... | @@ -743,7 +743,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { |
| 743 | 743 | } |
| 744 | 744 | |
| 745 | 745 | @Override |
| 746 | - public List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) { |
|
| 746 | + public List<GPSFixMoving> approximate(Competitor competitor, TimePoint from, TimePoint to) { |
|
| 747 | 747 | return null; |
| 748 | 748 | } |
| 749 | 749 |
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java
| ... | ... | @@ -371,7 +371,7 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace { |
| 371 | 371 | } |
| 372 | 372 | |
| 373 | 373 | @Override |
| 374 | - public List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) { |
|
| 374 | + public List<GPSFixMoving> approximate(Competitor competitor, TimePoint from, TimePoint to) { |
|
| 375 | 375 | return null; |
| 376 | 376 | } |
| 377 | 377 |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ApproximatedFixesCalculatorImpl.java
| ... | ... | @@ -19,9 +19,8 @@ public class ApproximatedFixesCalculatorImpl implements ApproximatedFixesCalcula |
| 19 | 19 | @Override |
| 20 | 20 | public Iterable<GPSFixMoving> approximate(TimePoint earliestStart, TimePoint latestEnd) { |
| 21 | 21 | return trackedRace.approximate(competitor, |
| 22 | - trackedRace.getRace().getBoatOfCompetitor(competitor).getBoatClass() |
|
| 23 | - .getMaximumDistanceForCourseApproximation(), |
|
| 24 | - earliestStart, latestEnd); |
|
| 22 | + earliestStart, |
|
| 23 | + latestEnd); |
|
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | } |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DummyTrackedRace.java
| ... | ... | @@ -315,7 +315,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { |
| 315 | 315 | } |
| 316 | 316 | |
| 317 | 317 | @Override |
| 318 | - public List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) { |
|
| 318 | + public List<GPSFixMoving> approximate(Competitor competitor, TimePoint from, TimePoint to) { |
|
| 319 | 319 | return null; |
| 320 | 320 | } |
| 321 | 321 |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
| ... | ... | @@ -659,7 +659,7 @@ public interface TrackedRace |
| 659 | 659 | * If the precondition that the {@code competitor} must be {@link RaceDefinition#getCompetitors() part of} the |
| 660 | 660 | * {@link #getRace() race} isn't met, a {@code NullPointerException} will result. |
| 661 | 661 | */ |
| 662 | - Iterable<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to); |
|
| 662 | + Iterable<GPSFixMoving> approximate(Competitor competitor, TimePoint from, TimePoint to); |
|
| 663 | 663 | |
| 664 | 664 | /** |
| 665 | 665 | * @return a non-<code>null</code> but perhaps empty list of the maneuvers that <code>competitor</code> performed in |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
| ... | ... | @@ -343,8 +343,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 343 | 343 | private transient SmartFutureCache<Competitor, List<Maneuver>, EmptyUpdateInterval> maneuverCache; |
| 344 | 344 | |
| 345 | 345 | /** |
| 346 | - * The values of this map are used by the {@link #approximate(Competitor, Distance, TimePoint, TimePoint)} method and |
|
| 347 | - * maintain state to accelerate the {@link #approximate(Competitor, Distance, TimePoint, TimePoint)} method, also in |
|
| 346 | + * The values of this map are used by the {@link #approximate(Competitor, TimePoint, TimePoint)} method and |
|
| 347 | + * maintain state to accelerate the {@link #approximate(Competitor, TimePoint, TimePoint)} method, also in |
|
| 348 | 348 | * live scenarios when the contents of the competitors' {@link #tracks} changes dynamically. |
| 349 | 349 | */ |
| 350 | 350 | private final Map<Competitor, CourseChangeBasedTrackApproximation> maneuverApproximators; |
| ... | ... | @@ -2880,10 +2880,10 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 2880 | 2880 | } |
| 2881 | 2881 | |
| 2882 | 2882 | @Override |
| 2883 | - public Iterable<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) { |
|
| 2883 | + public Iterable<GPSFixMoving> approximate(Competitor competitor, TimePoint from, TimePoint to) { |
|
| 2884 | 2884 | return maneuverApproximators.get(competitor).approximate(from, to); |
| 2885 | 2885 | } |
| 2886 | - |
|
| 2886 | + |
|
| 2887 | 2887 | protected void triggerManeuverCacheRecalculationForAllCompetitors() { |
| 2888 | 2888 | if (cachesSuspended) { |
| 2889 | 2889 | triggerManeuverCacheInvalidationForAllCompetitors = true; |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
| ... | ... | @@ -211,7 +211,7 @@ public interface SailingService extends RemoteService, RemoteReplicationService |
| 211 | 211 | SwissTimingEventRecordDTO getRacesOfSwissTimingEvent(String eventJsonURL) throws UnauthorizedException, Exception; |
| 212 | 212 | |
| 213 | 213 | Map<CompetitorDTO, List<GPSFixDTOWithSpeedWindTackAndLegType>> getDouglasPoints( |
| 214 | - RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, TimeRange> competitorTimeRanges, double meters) |
|
| 214 | + RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, TimeRange> competitorTimeRanges) |
|
| 215 | 215 | throws NoWindException, UnauthorizedException; |
| 216 | 216 | |
| 217 | 217 | Map<CompetitorDTO, List<ManeuverDTO>> getManeuvers(RegattaAndRaceIdentifier raceIdentifier, |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
| ... | ... | @@ -206,7 +206,6 @@ import com.sap.sailing.domain.common.dto.TrackedRaceDTO; |
| 206 | 206 | import com.sap.sailing.domain.common.impl.KilometersPerHourSpeedImpl; |
| 207 | 207 | import com.sap.sailing.domain.common.impl.KnotSpeedImpl; |
| 208 | 208 | import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; |
| 209 | -import com.sap.sailing.domain.common.impl.MeterDistance; |
|
| 210 | 209 | import com.sap.sailing.domain.common.impl.WindSourceImpl; |
| 211 | 210 | import com.sap.sailing.domain.common.media.MediaTrack; |
| 212 | 211 | import com.sap.sailing.domain.common.orc.ImpliedWindSource; |
| ... | ... | @@ -2809,13 +2808,12 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet |
| 2809 | 2808 | |
| 2810 | 2809 | @Override |
| 2811 | 2810 | public Map<CompetitorDTO, List<GPSFixDTOWithSpeedWindTackAndLegType>> getDouglasPoints( |
| 2812 | - RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, TimeRange> competitorTimeRanges, double meters) |
|
| 2811 | + RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, TimeRange> competitorTimeRanges) |
|
| 2813 | 2812 | throws NoWindException { |
| 2814 | 2813 | final Map<CompetitorDTO, List<GPSFixDTOWithSpeedWindTackAndLegType>> result = new HashMap<>(); |
| 2815 | 2814 | final TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier); |
| 2816 | 2815 | getSecurityService().checkCurrentUserReadPermission(trackedRace); |
| 2817 | 2816 | if (trackedRace != null) { |
| 2818 | - final MeterDistance maxDistance = new MeterDistance(meters); |
|
| 2819 | 2817 | for (Competitor competitor : trackedRace.getRace().getCompetitors()) { |
| 2820 | 2818 | final CompetitorDTO competitorDTO = baseDomainFactory.convertToCompetitorDTO(competitor); |
| 2821 | 2819 | if (competitorTimeRanges.containsKey(competitorDTO)) { |
| ... | ... | @@ -2823,8 +2821,8 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet |
| 2823 | 2821 | final GPSFixTrack<Competitor, GPSFixMoving> gpsFixTrack = trackedRace.getTrack(competitor); |
| 2824 | 2822 | // Distance for DouglasPeucker |
| 2825 | 2823 | final TimeRange timeRange = competitorTimeRanges.get(competitorDTO); |
| 2826 | - final Iterable<GPSFixMoving> gpsFixApproximation = trackedRace.approximate(competitor, maxDistance, |
|
| 2827 | - timeRange.from(), timeRange.to()); |
|
| 2824 | + final Iterable<GPSFixMoving> gpsFixApproximation = trackedRace.approximate(competitor, timeRange.from(), |
|
| 2825 | + timeRange.to()); |
|
| 2828 | 2826 | final List<GPSFixDTOWithSpeedWindTackAndLegType> gpsFixDouglasList = new ArrayList<>(); |
| 2829 | 2827 | GPSFix fix = null; |
| 2830 | 2828 | for (GPSFix next : gpsFixApproximation) { |
java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PathGeneratorTracTrac.java
| ... | ... | @@ -216,7 +216,7 @@ public class PathGeneratorTracTrac extends PathGeneratorBase { |
| 216 | 216 | Wind endWind = trackedRace.getWind(endPosition, endTime); |
| 217 | 217 | this.raceCourse.addLast(new TimedPositionWithSpeedImpl(endTime, endPosition, endWind)); |
| 218 | 218 | |
| 219 | - Iterable<GPSFixMoving> gpsFixes = trackedRace.approximate(competitor, maxDistance, startTime, endTime); |
|
| 219 | + Iterable<GPSFixMoving> gpsFixes = trackedRace.approximate(competitor, startTime, endTime); |
|
| 220 | 220 | Iterator<GPSFixMoving> gpsIter = gpsFixes.iterator(); |
| 221 | 221 | |
| 222 | 222 | while (gpsIter.hasNext()) { |