consolidated acquisition of mark position from tracked races, regatta log and race logs

This commit is contained in:
Axel Uhl committed 2015-03-23 22:25:40 +01:00
1 parent 7500d8ed96
commit 29284adfa4
8 files changed
+97 -66

No files matched your search

@@ -120,7 +120,6 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, AbstractLog<?, ?> log, Mark mark) public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, AbstractLog<?, ?> log, Mark mark)
throws NoCorrespondingServiceRegisteredException, TransformationException{ throws NoCorrespondingServiceRegisteredException, TransformationException{
List<DeviceMapping<Mark>> mappings = new DeviceMarkMappingFinder<>(log).analyze().get(mark); List<DeviceMapping<Mark>> mappings = new DeviceMarkMappingFinder<>(log).analyze().get(mark);
if (mappings != null) { if (mappings != null) {
for (DeviceMapping<Mark> mapping : mappings) { for (DeviceMapping<Mark> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/); loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
@@ -6,8 +6,8 @@ import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series; import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.common.Renamable; import com.sap.sailing.domain.common.Renamable;
import com.sap.sailing.domain.regattalike.HasRegattaLike;
import com.sap.sailing.domain.regattalike.IsRegattaLike; import com.sap.sailing.domain.regattalike.IsRegattaLike;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRace;
/** /**
@@ -23,7 +23,7 @@ import com.sap.sailing.domain.tracking.TrackedRace;
* @author Axel Uhl (D043530) * @author Axel Uhl (D043530)
* *
*/ */
public interface FlexibleLeaderboard extends Leaderboard, Renamable, HasRegattaLike, IsRegattaLike { public interface FlexibleLeaderboard extends LeaderboardThatHasRegattaLike, Renamable, IsRegattaLike {
/** /**
* Moves the column with the name <code>name</code> up. * Moves the column with the name <code>name</code> up.
* @param name The name of the column to move. * @param name The name of the column to move.
@@ -2,8 +2,8 @@ package com.sap.sailing.domain.leaderboard;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.Renamable; import com.sap.sailing.domain.common.Renamable;
import com.sap.sailing.domain.regattalike.HasRegattaLike; import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
public interface RegattaLeaderboard extends Leaderboard, Renamable, HasRegattaLike { public interface RegattaLeaderboard extends Renamable, LeaderboardThatHasRegattaLike {
Regatta getRegatta(); Regatta getRegatta();
} }
@@ -0,0 +1,6 @@
package com.sap.sailing.domain.regattalike;
import com.sap.sailing.domain.leaderboard.Leaderboard;
public interface LeaderboardThatHasRegattaLike extends Leaderboard, HasRegattaLike {
}
@@ -71,14 +71,12 @@ import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.gate.Readon
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.rrs26.ReadonlyRRS26RacingProcedure; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.rrs26.ReadonlyRRS26RacingProcedure;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent; import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.DefinedMarkFinder; import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.DefinedMarkFinder;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogLastPingMappingEventFinder;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogOpenEndedDeviceMappingCloser; import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogOpenEndedDeviceMappingCloser;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer; import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceCompetitorMappingFinder; import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMarkMappingFinder; import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMarkMappingFinder;
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer; import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
@@ -220,6 +218,7 @@ import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl; import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl;
import com.sap.sailing.domain.regattalike.HasRegattaLike; import com.sap.sailing.domain.regattalike.HasRegattaLike;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.regattalog.RegattaLogStore; import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.swisstimingadapter.StartList; import com.sap.sailing.domain.swisstimingadapter.StartList;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingAdapter; import com.sap.sailing.domain.swisstimingadapter.SwissTimingAdapter;
@@ -253,7 +252,6 @@ import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache;
import com.sap.sailing.domain.tracking.WindPositionMode; import com.sap.sailing.domain.tracking.WindPositionMode;
import com.sap.sailing.domain.tracking.WindTrack; import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence; import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
import com.sap.sailing.domain.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl; import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.tracking.impl.WindImpl; import com.sap.sailing.domain.tracking.impl.WindImpl;
@@ -4884,28 +4882,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
return existing; return existing;
} }
} }
Serializable id = UUID.randomUUID(); Serializable id = UUID.randomUUID();
return baseDomainFactory.getOrCreateMark(id, dto.getName(), dto.type, dto.color, dto.shape, dto.pattern); return baseDomainFactory.getOrCreateMark(id, dto.getName(), dto.type, dto.color, dto.shape, dto.pattern);
} }
/** /**
* Also finds the last position of the marks, if set by pinging them * Also finds the last position of the marks, if set by pinging them
*/ */
private Collection<MarkDTO> convertToMarkDTOs(RaceLog raceLog, Iterable<Mark> marks) { private Collection<MarkDTO> convertToMarkDTOs(LeaderboardThatHasRegattaLike leaderboard, RaceLog raceLog, Iterable<Mark> marks) {
List<MarkDTO> dtos = new ArrayList<MarkDTO>(); List<MarkDTO> dtos = new ArrayList<MarkDTO>();
final TimePoint now = MillisecondsTimePoint.now();
for (Mark mark : marks) { for (Mark mark : marks) {
DynamicGPSFixTrackImpl<Mark> track = new DynamicGPSFixTrackImpl<Mark>(mark, 0); final Position lastPos = getService().getMarkPosition(mark, leaderboard, now, raceLog);
DeviceMappingEvent<?, Mark> lastPingMappingEvent = new RaceLogLastPingMappingEventFinder<Mark>(raceLog, mark).analyze();
if (lastPingMappingEvent != null) {
try {
getService().getGPSFixStore().loadMarkTrack(track, DeviceMappingImpl.convertToDeviceMapping(lastPingMappingEvent));
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not convert to Mark DTO: " + mark);
}
}
Position lastPos = track.getLastRawFix() == null ? null : track.getLastRawFix().getPosition();
dtos.add(convertToMarkDTO(mark, lastPos)); dtos.add(convertToMarkDTO(mark, lastPos));
} }
return dtos; return dtos;
@@ -4924,14 +4912,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
public Iterable<MarkDTO> getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName) { public Iterable<MarkDTO> getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName) {
RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
Iterable<Mark> marks = new DefinedMarkFinder(raceLog).analyze(); Iterable<Mark> marks = new DefinedMarkFinder(raceLog).analyze();
return convertToMarkDTOs(raceLog, marks); return convertToMarkDTOs((LeaderboardThatHasRegattaLike) getService().getLeaderboardByName(leaderboardName), raceLog, marks);
} }
@Override @Override
public Iterable<MarkDTO> getMarksInRaceLogsAndTrackedRaces(String leaderboardName) { public Iterable<MarkDTO> getMarksInRaceLogsAndTrackedRaces(String leaderboardName) {
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
if (leaderboard == null) { if (leaderboard == null) {
//TODO: implement proper Exception Handling // TODO: implement proper Exception Handling
return null; return null;
} }
Set<MarkDTO> markDTOs = new HashSet<>(); Set<MarkDTO> markDTOs = new HashSet<>();
@@ -4948,7 +4936,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
marksById.put(markFromTrackedRace.getId(), markFromTrackedRace); marksById.put(markFromTrackedRace.getId(), markFromTrackedRace);
} }
} }
Util.addAll(convertToMarkDTOs(raceLog, marksById.values()), markDTOs); Util.addAll(convertToMarkDTOs(
(LeaderboardThatHasRegattaLike) getService().getLeaderboardByName(leaderboardName),
raceLog, marksById.values()), markDTOs);
} }
} }
return markDTOs; return markDTOs;
@@ -54,6 +54,7 @@ import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LeaderboardNameConstants; import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.FleetDTO; import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.domain.common.dto.LeaderboardDTO; import com.sap.sailing.domain.common.dto.LeaderboardDTO;
@@ -64,18 +65,16 @@ import com.sap.sailing.domain.common.racelog.RaceLogServletConstants;
import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants; import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants;
import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl; import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl;
import com.sap.sailing.domain.regattalike.HasRegattaLike; import com.sap.sailing.domain.regattalike.HasRegattaLike;
import com.sap.sailing.domain.regattalike.IsRegattaLike; import com.sap.sailing.domain.regattalike.IsRegattaLike;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
import com.sap.sailing.domain.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
import com.sap.sailing.domain.tracking.impl.GPSFixTrackImpl; import com.sap.sailing.domain.tracking.impl.GPSFixTrackImpl;
import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventService;
@@ -654,9 +653,10 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
return Response.status(Status.NOT_FOUND).entity("Could not find a mark with ID '" + markId + "'.") return Response.status(Status.NOT_FOUND).entity("Could not find a mark with ID '" + markId + "'.")
.type(MediaType.TEXT_PLAIN).build(); .type(MediaType.TEXT_PLAIN).build();
} }
MillisecondsTimePoint now = MillisecondsTimePoint.now();
GPSFix lastKnownFix = getLastKnownFix(leaderboard, mark, regattaLog); Position lastKnownPosition = getService().getMarkPosition(mark,
(LeaderboardThatHasRegattaLike) leaderboard, now,
/* raceLog==null means use all race logs */ null);
GPSFix fix = null; GPSFix fix = null;
try { try {
Object requestBody = JSONValue.parseWithException(json); Object requestBody = JSONValue.parseWithException(json);
@@ -671,11 +671,11 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
RaceLogTrackingAdapter adapter = getRaceLogTrackingAdapter(); RaceLogTrackingAdapter adapter = getRaceLogTrackingAdapter();
RacingEventService service = getService(); RacingEventService service = getService();
try { try {
if (lastKnownFix != null) { if (lastKnownPosition != null) {
// ping again to avoid interpolation, avoid filtering by paying attention to maxSpeedForSmoothing // ping again to avoid interpolation, avoid filtering by paying attention to maxSpeedForSmoothing
final Distance distance = lastKnownFix.getPosition().getDistance(fix.getPosition()); final Distance distance = lastKnownPosition.getDistance(fix.getPosition());
final Duration minDuration = GPSFixTrackImpl.getDefaultMaxSpeedForSmoothing().getDuration(distance); final Duration minDuration = GPSFixTrackImpl.getDefaultMaxSpeedForSmoothing().getDuration(distance);
final GPSFix repeatedFixAvoidingCreepingMark = new GPSFixImpl(lastKnownFix.getPosition(), fix.getTimePoint().minus(minDuration)); final GPSFix repeatedFixAvoidingCreepingMark = new GPSFixImpl(lastKnownPosition, fix.getTimePoint().minus(minDuration));
adapter.pingMark(regattaLog, mark, repeatedFixAvoidingCreepingMark, service); adapter.pingMark(regattaLog, mark, repeatedFixAvoidingCreepingMark, service);
} }
adapter.pingMark(regattaLog, mark, fix, service); adapter.pingMark(regattaLog, mark, fix, service);
@@ -684,43 +684,12 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
logger.log(Level.WARNING, "Could not ping mark " + mark.getName()); logger.log(Level.WARNING, "Could not ping mark " + mark.getName());
} }
if (lastKnownFix != null) { if (lastKnownPosition != null) {
JSONObject lastKnownFixJson = fixSerializer.serialize(lastKnownFix); JSONObject lastKnownFixJson = fixSerializer.serialize(new GPSFixImpl(lastKnownPosition, now));
String fixJson = lastKnownFixJson.toJSONString(); String fixJson = lastKnownFixJson.toJSONString();
return Response.ok(fixJson, MediaType.APPLICATION_JSON).build(); return Response.ok(fixJson, MediaType.APPLICATION_JSON).build();
} else { } else {
return Response.ok().build(); return Response.ok().build();
} }
} }
/**
* Looks at the mark tracks in the tracked races attached to the <code>leaderboard</code>
* and if it doesn't find the <code>mark</code> requested there, looks in the <code>regattaLog</code>
* for device mappings for the mark and tried to load fixes from the {@link GPSFixStore}.
* The latter is only necessary if the mark isn't found in any tracked race because should there
* be a tracked race in the leaderboard that has the mark, it will also have received the fixes
* from the {@link GPSFixStore} through the regatta log mapping.
*/
private GPSFix getLastKnownFix(Leaderboard leaderboard, Mark mark, RegattaLog regattaLog) {
GPSFixTrack<Mark, GPSFix> track = null;
for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) {
if (Util.contains(trackedRace.getMarks(), mark)) {
track = trackedRace.getOrCreateTrack(mark);
break;
}
}
if (track == null) { // not found in any tracked race, or no tracked races found
// try to load from store
DynamicGPSFixTrackImpl<Mark> loadedTrack = new DynamicGPSFixTrackImpl<Mark>(mark, 0);
track = loadedTrack;
try {
getService().getGPSFixStore().loadMarkTrack(loadedTrack, regattaLog, mark);
} catch (Exception e) {
logger.log(Level.WARNING, "Couldn't load mark track for mark "+mark, e);
return null;
}
}
GPSFix lastKnownFix = track.getLastFixAtOrBefore(MillisecondsTimePoint.now());
return lastKnownFix;
}
} }
@@ -24,6 +24,7 @@ import com.sap.sailing.domain.base.EventBase;
import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.LeaderboardSearchResult; import com.sap.sailing.domain.base.LeaderboardSearchResult;
import com.sap.sailing.domain.base.LeaderboardSearchResultBase; import com.sap.sailing.domain.base.LeaderboardSearchResultBase;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
@@ -35,6 +36,7 @@ import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier;
import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration; import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
import com.sap.sailing.domain.common.DataImportProgress; import com.sap.sailing.domain.common.DataImportProgress;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RaceFetcher; import com.sap.sailing.domain.common.RaceFetcher;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaFetcher; import com.sap.sailing.domain.common.RegattaFetcher;
@@ -54,6 +56,7 @@ import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.persistence.DomainObjectFactory; import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory; import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.RaceListener; import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.RaceTracker; import com.sap.sailing.domain.tracking.RaceTracker;
@@ -124,6 +127,22 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
*/ */
Leaderboard getLeaderboardByName(String name); Leaderboard getLeaderboardByName(String name);
/**
* Looks at the mark tracks in the tracked races attached to the <code>leaderboard</code>. If it doesn't find a
* track for the <code>mark</code> requested there which has fixes before and after <code>timePoint</code> (to
* ensure that no track cropping has taken place, removing the fixes for the interesting time period), looks in the
* leaderboard's regatta log and the specific <code>raceLog</code> (if provided) or all race logs attached to the
* leaderboard (if not provided) for device mappings for the mark and tries to load fixes from the
* {@link GPSFixStore}. The latter is only necessary if the mark isn't found in any tracked race with fixes
* surrounding <code>timePoint</code> because should there be a tracked race in the leaderboard that has the mark
* then it will also have received the fixes from the {@link GPSFixStore} through the regatta log mapping.
* <p>
*
* @return the position obtained by interpolation but never extrapolation from the track identified as described
* above
*/
Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint, RaceLog raceLog);
/** /**
* Stops tracking all races of the regatta specified. This will also stop tracking wind for all races of this regatta. * Stops tracking all races of the regatta specified. This will also stop tracking wind for all races of this regatta.
* See {@link #stopTrackingWind(Regatta, RaceDefinition)}. If there were multiple calls to * See {@link #stopTrackingWind(Regatta, RaceDefinition)}. If there were multiple calls to
@@ -581,4 +600,5 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
FileStorageManagementService getFileStorageManagementService(); FileStorageManagementService getFileStorageManagementService();
ClassLoader getCombinedMasterDataClassLoader(); ClassLoader getCombinedMasterDataClassLoader();
} }
@@ -43,6 +43,7 @@ import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
@@ -85,6 +86,7 @@ import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl; import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl;
import com.sap.sailing.domain.common.DataImportProgress; import com.sap.sailing.domain.common.DataImportProgress;
import com.sap.sailing.domain.common.LeaderboardNameConstants; import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaIdentifier; import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.RegattaName; import com.sap.sailing.domain.common.RegattaName;
@@ -125,11 +127,13 @@ import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.regattalike.IsRegattaLike; import com.sap.sailing.domain.regattalike.IsRegattaLike;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.regattalog.RegattaLogStore; import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving; import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceChangeListener; import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.RaceHandle; import com.sap.sailing.domain.tracking.RaceHandle;
@@ -144,6 +148,7 @@ import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTracker; import com.sap.sailing.domain.tracking.WindTracker;
import com.sap.sailing.domain.tracking.WindTrackerFactory; import com.sap.sailing.domain.tracking.WindTrackerFactory;
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener; import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory; import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
import com.sap.sailing.polars.PolarDataService; import com.sap.sailing.polars.PolarDataService;
@@ -970,6 +975,48 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
return leaderboardsByName.get(name); return leaderboardsByName.get(name);
} }
@Override
public Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint, RaceLog raceLog) {
GPSFixTrack<Mark, GPSFix> track = null;
for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) {
if (Util.contains(trackedRace.getMarks(), mark)) {
GPSFixTrack<Mark, GPSFix> trackCandidate = trackedRace.getOrCreateTrack(mark);
if (spansTimePoint(trackCandidate, timePoint)) {
track = trackCandidate;
break;
}
}
}
if (track == null) { // no spanning track found in any tracked race, or no tracked races found
// try to load from store
DynamicGPSFixTrackImpl<Mark> loadedTrack = new DynamicGPSFixTrackImpl<Mark>(mark, 0);
track = loadedTrack;
Set<AbstractLog<?, ?>> logs = new HashSet<>();
logs.add(leaderboard.getRegattaLike().getRegattaLog());
if (raceLog == null) { // no race log explicitly provided --> use all race logs
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (Fleet fleet : raceColumn.getFleets()) {
logs.add(raceColumn.getRaceLog(fleet));
}
}
} else {
logs.add(raceLog);
}
for (AbstractLog<?, ?> log : logs) {
try {
getGPSFixStore().loadMarkTrack(loadedTrack, log, mark);
} catch (Exception e) {
logger.log(Level.WARNING, "Couldn't load mark track for mark " + mark + " from log " + log, e);
}
}
}
return track.getEstimatedPosition(timePoint, /* extrapolate */ false);
}
private boolean spansTimePoint(GPSFixTrack<Mark, GPSFix> track, TimePoint timePoint) {
return track.getLastFixAtOrBefore(timePoint) != null && track.getFirstFixAtOrAfter(timePoint) != null;
}
@Override @Override
public Map<String, Leaderboard> getLeaderboards() { public Map<String, Leaderboard> getLeaderboards() {
return Collections.unmodifiableMap(new HashMap<String, Leaderboard>(leaderboardsByName)); return Collections.unmodifiableMap(new HashMap<String, Leaderboard>(leaderboardsByName));