From 41ce0c5430ef664ae7c2ddff01e4f5307e97e5b8 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 22 Mar 2016 14:40:25 +0100 Subject: [PATCH] started implementing the mark position-related services in SailingServiceImpl Change-Id: I37d1eaa1b04e40948bbeeaa1b845c995de60b4c6 --- .../sap/sailing/domain/base/BoatClass.java | 3 + .../domain/base/impl/BoatClassImpl.java | 2 +- .../domain/tracking/impl/TrackedRaceImpl.java | 44 +++++++----- .../shared/charts/EditMarkPositionPanel.java | 6 +- .../shared/charts/MarkPositionService.java | 22 ++++-- .../gwt/ui/server/SailingServiceImpl.java | 68 +++++++++++++++++-- 6 files changed, 113 insertions(+), 32 deletions(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/BoatClass.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/BoatClass.java index 890293a783b..4a16a087daf 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/BoatClass.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/BoatClass.java @@ -2,11 +2,14 @@ package com.sap.sailing.domain.base; import com.sap.sailing.domain.common.BoatHullType; import com.sap.sailing.domain.common.Distance; +import com.sap.sse.common.Duration; import com.sap.sse.common.IsManagedByCache; import com.sap.sse.common.Named; import com.sap.sse.common.TimePoint; public interface BoatClass extends Named, IsManagedByCache { + final Duration APPROXIMATE_AVERAGE_MANEUVER_DURATION = Duration.ONE_SECOND.times(8); // as discussed with Dennis Gehrlein + /** * The distance returned by this method should be appropriate for use in * {@link TrackedRace#approximate(Competitor, Distance, TimePoint, TimePoint)} so that penalty circles and other diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/BoatClassImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/BoatClassImpl.java index 7caeb1daed3..b035448b5cf 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/BoatClassImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/BoatClassImpl.java @@ -64,7 +64,7 @@ public class BoatClassImpl extends NamedImpl implements BoatClass { this.hullLength = hullLength; this.hullBeam = hullBeam; this.hullType = hullType; - approximateManeuverDurationInMilliseconds = 8000; // as discussed with Dennis Gehrlein + approximateManeuverDurationInMilliseconds = APPROXIMATE_AVERAGE_MANEUVER_DURATION.asMillis(); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index e410626b1e6..900a40d9176 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -3248,22 +3248,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl logger.info("Finished loading competitor tracks for " + getRace().getName()); logger.info("Started loading mark tracks for " + getRace().getName()); for (Mark mark : getMarksFromRegattaLogs()) { - try { - gpsFixStore.loadMarkTrack((DynamicGPSFixTrack) getOrCreateTrack(mark), - log, mark, startOfTimeWindowToLoad, endOfTimeWindowToLoad); - if (getOrCreateTrack(mark).getFirstRawFix() == null) { - logger.fine("Loading mark positions from outside of start/end of tracking interval ("+ - startOfTimeWindowToLoad+".."+endOfTimeWindowToLoad+ - ") because no fixes were found in that interval"); - // got an empty track for the mark; try again without constraining the mapping interval - // by start/end of tracking to at least attempt to get fixes at all in case there were any - // within the device mapping interval specified - gpsFixStore.loadMarkTrack((DynamicGPSFixTrack) getOrCreateTrack(mark), - log, mark, /* startOfTimeWindowToLoad */ null, /* endOfTimeWindowToLoad */ null); - } - } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { - logger.log(Level.WARNING, "Could not load track for " + mark, e); - } + final DynamicGPSFixTrack markTrack = (DynamicGPSFixTrack) getOrCreateTrack(mark); + loadMarkTrack(log, mark, markTrack, startOfTimeWindowToLoad, endOfTimeWindowToLoad); } logger.info("Finished loading mark tracks for " + getRace().getName()); } finally { @@ -3287,6 +3273,32 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } } + /** + * Loads the GPS fixes for a mark from the {@link #gpsFixStore} and adds them to {@code intoTrack}. The device + * mappings are expected to be found in {@code logWithDeviceMappings}. The fixes added have to be within + * {@code from} and {@code to}, inclusively, with one exception: if no fix is found within this interval at all, all + * fixes found for the mark are loaded to make sure that any position data that may give a hint for the interval + * requests is loaded. + */ + private void loadMarkTrack(final RegattaLog logWithDeviceMappings, Mark mark, + final DynamicGPSFixTrack intoTrack, final TimePoint from, final TimePoint to) { + try { + gpsFixStore.loadMarkTrack(intoTrack, logWithDeviceMappings, mark, from, to); + if (intoTrack.getFirstRawFix() == null) { + logger.fine("Loading mark positions from outside of start/end of tracking interval ("+ + from+".."+to+ + ") because no fixes were found in that interval"); + // got an empty track for the mark; try again without constraining the mapping interval + // by start/end of tracking to at least attempt to get fixes at all in case there were any + // within the device mapping interval specified + gpsFixStore.loadMarkTrack(intoTrack, + logWithDeviceMappings, mark, /* startOfTimeWindowToLoad */ null, /* endOfTimeWindowToLoad */ null); + } + } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { + logger.log(Level.WARNING, "Could not load track for " + mark, e); + } + } + /** * Tells if currently the race is loading GPS fixes from the {@link GPSFixStore}. Clients may {@link Object#wait()} on this * object and will be notified whenever a change of this flag's value occurs. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPositionPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPositionPanel.java index a22349a9063..90b0894cc5b 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPositionPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPositionPanel.java @@ -608,13 +608,13 @@ public class EditMarkPositionPanel extends AbstractRaceChart implements Componen @Override public void onSuccess(MarkTracksDTO markTracks) { - Map> result = new HashMap<>(); + Map> result = new HashMap<>(); for (MarkTrackDTO track : markTracks.getTracks()) { - result.put(track.mark, track.fixes); + result.put(track.getMark(), track.getFixes()); marks = new HashMap>(); raceFromTime = timeRangeWithZoomProvider.getFromTime(); raceToTime = timeRangeWithZoomProvider.getToTime(); - for (final Map.Entry> fixes : result.entrySet()) { + for (final Map.Entry> fixes : result.entrySet()) { Date fromTime = raceFromTime; Date toTime = raceToTime; PolylineOptions options = PolylineOptions.newInstance(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MarkPositionService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MarkPositionService.java index 62b2fba1c07..80d54ca184e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MarkPositionService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MarkPositionService.java @@ -1,7 +1,5 @@ package com.sap.sailing.gwt.ui.client.shared.charts; -import java.util.List; - import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sailing.domain.common.Position; import com.sap.sailing.gwt.ui.client.shared.charts.RaceIdentifierToLeaderboardRaceColumnAndFleetMapper.LeaderboardNameRaceColumnNameAndFleetName; @@ -10,15 +8,27 @@ import com.sap.sailing.gwt.ui.shared.MarkDTO; public interface MarkPositionService { public static class MarkTrackDTO { - public MarkDTO mark; - public List fixes; - public boolean thinnedOut; + private final MarkDTO mark; + private final Iterable fixes; + private final boolean thinnedOut; - public MarkTrackDTO(MarkDTO mark, List fixes, boolean thinnedOut) { + public MarkTrackDTO(MarkDTO mark, Iterable fixes, boolean thinnedOut) { this.mark = mark; this.fixes = fixes; this.thinnedOut = thinnedOut; } + + public MarkDTO getMark() { + return mark; + } + + public Iterable getFixes() { + return fixes; + } + + public boolean isThinnedOut() { + return thinnedOut; + } } public static class MarkTracksDTO { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 881a83e6303..49ba6fc6c7b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -274,6 +274,7 @@ import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.MarkPassingManeuver; import com.sap.sailing.domain.tracking.RaceHandle; import com.sap.sailing.domain.tracking.RaceTracker; +import com.sap.sailing.domain.tracking.Track; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; @@ -281,6 +282,7 @@ import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache; import com.sap.sailing.domain.tracking.WindPositionMode; import com.sap.sailing.domain.tracking.WindTrack; import com.sap.sailing.domain.tracking.WindWithConfidence; +import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl; import com.sap.sailing.domain.tractracadapter.RaceRecord; import com.sap.sailing.domain.tractracadapter.TracTracAdapter; import com.sap.sailing.domain.tractracadapter.TracTracAdapterFactory; @@ -6111,13 +6113,54 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S if (fleet != null) { for (final Mark mark : raceColumn.getMarks(fleet)) { final MarkDTO markDTO = convertToMarkDTO(mark, /* position */ null); - + final TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); + final GPSFixTrack markTrack; + if (trackedRace != null) { + markTrack = trackedRace.getOrCreateTrack(mark); + } else { + DynamicGPSFixTrackImpl writeableMarkTrack = new DynamicGPSFixTrackImpl(mark, BoatClass.APPROXIMATE_AVERAGE_MANEUVER_DURATION.asMillis()); + markTrack = writeableMarkTrack; + final RaceLog raceLog = raceColumn.getRaceLog(fleet); + final RegattaLog regattaLog = raceColumn.getRegattaLog(); + final TrackingTimesFinder trackingTimesFinder = new TrackingTimesFinder(raceLog); + final Pair trackingTimes = trackingTimesFinder.analyze(); + try { + getService().getGPSFixStore().loadMarkTrack(writeableMarkTrack, regattaLog, mark, trackingTimes.getA(), trackingTimes.getB()); + } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { + logger.info("Error trying to load mark track for mark "+mark+" from "+trackingTimes.getA()+" to "+trackingTimes.getB()); + } + } + Iterable gpsFixDTOTrack = convertToGPSFixDTOTrack(markTrack); + final MarkTrackDTO markTrackDTO = new MarkTrackDTO(markDTO, gpsFixDTOTrack, /* thinned out */ false); + markTracks.add(markTrackDTO); } } } } return new MarkTracksDTO(markTracks); } + + /** + * Uses all fixed from {@code track} with the outliers removed, {@link #convertToGPSFixDTO(GPSFix) converts} each + * of them to a {@link GPSFixDTO} and adds them to the resulting list. + */ + private Iterable convertToGPSFixDTOTrack(Track track) { + final List result = new ArrayList<>(); + for (final GPSFix fix : track.getFixes()) { + result.add(convertToGPSFixDTO(fix)); + } + return result; + } + + private GPSFixDTO convertToGPSFixDTO(GPSFix fix) { + final GPSFixDTO result; + if (fix == null) { + result = null; + } else { + result = new GPSFixDTO(fix.getTimePoint().asDate(), fix.getPosition()); + } + return result; + } @Override public boolean canRemoveMarkFix(String leaderboardName, String raceColumnName, String fleetName, @@ -6143,14 +6186,27 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public void removeMarkFix(String leaderboardName, String raceColumnName, String fleetName, String markIdAsString, - GPSFixDTO fix) { - // TODO Auto-generated method stub + public void removeMarkFix(String leaderboardName, String raceColumnName, String fleetName, String markIdAsString, GPSFixDTO fix) { + final Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + if (leaderboard != null) { + final RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); + if (raceColumn != null) { + final Fleet fleet = raceColumn.getFleetByName(fleetName); + if (fleet != null) { + final TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); + } else { + result = false; + } + } else { + result = false; + } + } + // TODO need to find all mappings that span fix's time point; revoke all those mappings and instead create two replacements that end before/start after fix's time point to skip it; + // TODO if an existing mapping starts at or ends with the fix's time point, only one or no replacement mapping may be required ("ping" case). } @Override - public void addMarkFix(String leaderboardName, String raceColumnName, String fleetName, String markIdAsString, - GPSFixDTO newFix) { + public void addMarkFix(String leaderboardName, String raceColumnName, String fleetName, String markIdAsString, GPSFixDTO newFix) { // TODO Auto-generated method stub }