compileable but untested refactored version of RaceMap.timeChanged, working towards a solution for bug3378

Change-Id: Idc67121b9c1931e66453def87da8243250b9c9d2
This commit is contained in:
Axel Uhl committed 2015-12-14 13:34:00 +01:00
1 parent 68a1c76529
commit 61d1c2da2e
9 files changed
+251 -132

No files matched your search

@@ -0,0 +1,47 @@
package com.sap.sailing.gwt.ui.actions;
import java.util.Date;
import java.util.Map;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sse.gwt.client.async.AsyncAction;
public abstract class AbstractGetMapRelatedDataAction<T> implements AsyncAction<T> {
private final SailingServiceAsync sailingService;
private final RegattaAndRaceIdentifier raceIdentifier;
private final Map<CompetitorDTO, Date> from;
private final Map<CompetitorDTO, Date> to;
private final boolean extrapolate;
public AbstractGetMapRelatedDataAction(SailingServiceAsync sailingService,
RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, Date> from,
Map<CompetitorDTO, Date> to, boolean extrapolate) {
this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier;
this.from = from;
this.to = to;
this.extrapolate = extrapolate;
}
protected SailingServiceAsync getSailingService() {
return sailingService;
}
protected RegattaAndRaceIdentifier getRaceIdentifier() {
return raceIdentifier;
}
protected Map<CompetitorDTO, Date> getFrom() {
return from;
}
protected Map<CompetitorDTO, Date> getTo() {
return to;
}
protected boolean isExtrapolate() {
return extrapolate;
}
}
@@ -0,0 +1,43 @@
package com.sap.sailing.gwt.ui.actions;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.shared.CompactBoatPositionsDTO;
public class GetBoatPositionsAction extends AbstractGetMapRelatedDataAction<CompactBoatPositionsDTO> {
public GetBoatPositionsAction(SailingServiceAsync sailingService,
RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, Date> from,
Map<CompetitorDTO, Date> to, boolean extrapolate) {
super(sailingService, raceIdentifier, from, to, extrapolate);
}
@Override
public void execute(final AsyncCallback<CompactBoatPositionsDTO> callback) {
Map<String, Date> fromByCompetitorIdAsString = new HashMap<String, Date>();
for (Map.Entry<CompetitorDTO, Date> fromEntry : getFrom().entrySet()) {
fromByCompetitorIdAsString.put(fromEntry.getKey().getIdAsString(), fromEntry.getValue());
}
Map<String, Date> toByCompetitorIdAsString = new HashMap<String, Date>();
for (Map.Entry<CompetitorDTO, Date> toEntry : getTo().entrySet()) {
toByCompetitorIdAsString.put(toEntry.getKey().getIdAsString(), toEntry.getValue());
}
getSailingService().getBoatPositions(getRaceIdentifier(), fromByCompetitorIdAsString, toByCompetitorIdAsString,
isExtrapolate(), new AsyncCallback<CompactBoatPositionsDTO>() {
@Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
}
@Override
public void onSuccess(CompactBoatPositionsDTO result) {
callback.onSuccess(result);
}
});
}
}
@@ -11,43 +11,33 @@ import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
import com.sap.sailing.gwt.ui.shared.RaceMapDataDTO;
import com.sap.sse.gwt.client.async.AsyncAction;
public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
private final SailingServiceAsync sailingService;
private final Iterable<CompetitorDTO> allCompetitors;
private final RegattaAndRaceIdentifier raceIdentifier;
private final Map<CompetitorDTO, Date> from;
private final Map<CompetitorDTO, Date> to;
private final boolean extrapolate;
public class GetRaceMapDataAction extends AbstractGetMapRelatedDataAction<RaceMapDataDTO> {
private final Map<String, CompetitorDTO> competitorsByIdAsString;
private final Date date;
private final LegIdentifier simulationLegIdentifier;
public GetRaceMapDataAction(SailingServiceAsync sailingService, Iterable<CompetitorDTO> allCompetitors,
public GetRaceMapDataAction(SailingServiceAsync sailingService, Map<String, CompetitorDTO> competitorsByIdAsString,
RegattaAndRaceIdentifier raceIdentifier, Date date, Map<CompetitorDTO, Date> from,
Map<CompetitorDTO, Date> to, boolean extrapolate, LegIdentifier simulationLegIdentifier) {
this.allCompetitors = allCompetitors;
this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier;
super(sailingService, raceIdentifier, from, to, extrapolate);
this.competitorsByIdAsString = competitorsByIdAsString;
this.date = date;
this.from = from;
this.to = to;
this.extrapolate = extrapolate;
this.simulationLegIdentifier = simulationLegIdentifier;
}
@Override
public void execute(final AsyncCallback<RaceMapDataDTO> callback) {
Map<String, Date> fromByCompetitorIdAsString = new HashMap<String, Date>();
for (Map.Entry<CompetitorDTO, Date> fromEntry : from.entrySet()) {
for (Map.Entry<CompetitorDTO, Date> fromEntry : getFrom().entrySet()) {
fromByCompetitorIdAsString.put(fromEntry.getKey().getIdAsString(), fromEntry.getValue());
}
Map<String, Date> toByCompetitorIdAsString = new HashMap<String, Date>();
for (Map.Entry<CompetitorDTO, Date> toEntry : to.entrySet()) {
for (Map.Entry<CompetitorDTO, Date> toEntry : getTo().entrySet()) {
toByCompetitorIdAsString.put(toEntry.getKey().getIdAsString(), toEntry.getValue());
}
sailingService.getRaceMapData(raceIdentifier, date, fromByCompetitorIdAsString, toByCompetitorIdAsString,
extrapolate, simulationLegIdentifier, new AsyncCallback<CompactRaceMapDataDTO>() {
getSailingService().getRaceMapData(getRaceIdentifier(), date, fromByCompetitorIdAsString, toByCompetitorIdAsString,
isExtrapolate(), simulationLegIdentifier, new AsyncCallback<CompactRaceMapDataDTO>() {
@Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
@@ -55,7 +45,7 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
@Override
public void onSuccess(CompactRaceMapDataDTO result) {
callback.onSuccess(result.getRaceMapDataDTO(allCompetitors));
callback.onSuccess(result.getRaceMapDataDTO(competitorsByIdAsString));
}
});
}
@@ -45,6 +45,7 @@ import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.gwt.ui.adminconsole.RaceLogSetTrackingTimesDTO;
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
import com.sap.sailing.gwt.ui.shared.CompactBoatPositionsDTO;
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
@@ -158,6 +159,10 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString,
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate, LegIdentifier simulationLegIdentifier) throws NoWindException;
CompactBoatPositionsDTO getBoatPositions(RegattaAndRaceIdentifier raceIdentifier,
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
boolean extrapolate) throws NoWindException;
RaceTimesInfoDTO getRaceTimesInfo(RegattaAndRaceIdentifier raceIdentifier);
List<RaceTimesInfoDTO> getRaceTimesInfos(Collection<RegattaAndRaceIdentifier> raceIdentifiers);
@@ -612,4 +617,5 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
*/
Collection<CompetitorDTO> getCompetitorRegistrationsOnRaceLog(String leaderboardName, String raceColumnName,
String fleetName);
}
@@ -37,6 +37,7 @@ import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.gwt.ui.adminconsole.RaceLogSetTrackingTimesDTO;
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
import com.sap.sailing.gwt.ui.shared.CompactBoatPositionsDTO;
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
@@ -368,6 +369,10 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
boolean extrapolate, LegIdentifier simulationLegIdentifier, AsyncCallback<CompactRaceMapDataDTO> callback);
void getBoatPositions(RegattaAndRaceIdentifier raceIdentifier, Map<String, Date> fromPerCompetitorIdAsString,
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate,
AsyncCallback<CompactBoatPositionsDTO> callback);
void getReplicaInfo(AsyncCallback<ReplicationStateDTO> callback);
void startReplicatingFromMaster(String messagingHost, String masterName, String exchangeName, int servletPort,
@@ -753,4 +758,5 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
void copyCourseToOtherRaceLogs(Triple<String, String, String> fromTriple,
Set<Triple<String, String, String>> toTriples, AsyncCallback<Void> callback);
}
@@ -83,6 +83,7 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalablePosition;
import com.sap.sailing.gwt.ui.actions.GetBoatPositionsAction;
import com.sap.sailing.gwt.ui.actions.GetPolarAction;
import com.sap.sailing.gwt.ui.actions.GetRaceMapDataAction;
import com.sap.sailing.gwt.ui.actions.GetWindInfoAction;
@@ -100,6 +101,7 @@ import com.sap.sailing.gwt.ui.client.shared.filter.QuickRankProvider;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sailing.gwt.ui.shared.CompactBoatPositionsDTO;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO;
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
@@ -776,29 +778,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
final long transitionTimeInMillis = calculateTimeForPositionTransitionInMillis(newTime, oldTime);
final com.sap.sse.common.Util.Triple<Map<CompetitorDTO, Date>, Map<CompetitorDTO, Date>, Map<CompetitorDTO, Boolean>> fromAndToAndOverlap =
fixesAndTails.computeFromAndTo(newTime, competitorsToShow, settings.getEffectiveTailLengthInMilliseconds());
int requestID = ++boatPositionRequestIDCounter;
// For those competitors for which the tails don't overlap (and therefore will be replaced by the new tail coming from the server)
// we expect some potential delay in computing the full tail. Therefore, in those cases we fire two requests: one fetching only the
// boat positions at newTime with zero tail length; and another one fetching everything else.
// TODO bug3378: two calls that both request simulation and mark data wastes bandwidth and CPU; one of them should only use getBoatPositions to request missing pieces of tails; showBoatsOnMap must not remove canvases / tails if one of the two calls delivers only partial results
final GetRaceMapDataAction getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping = getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping(fromAndToAndOverlap, race, newTime);
final boolean updateMarksAndLinesExceptAdvantageLineInCallback;
if (getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping != null) {
asyncActionsExecutor.execute(getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping, GET_RACE_MAP_DATA_CATEGORY,
getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, requestID,
/* updateMarksAndLinesExceptAdvantageLineInCallback */ true));
updateMarksAndLinesExceptAdvantageLineInCallback = false; // don't do this again in the second call that mainly fetches
requestID = ++boatPositionRequestIDCounter;
} else {
updateMarksAndLinesExceptAdvantageLineInCallback = true;
}
// next, do the full thing; being the later call, if request throttling kicks in, the later call
// supersedes the earlier call which may get dropped then
GetRaceMapDataAction getRaceMapDataAction = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), race,
useNullAsTimePoint() ? null : newTime, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true, (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null));
asyncActionsExecutor.execute(getRaceMapDataAction, GET_RACE_MAP_DATA_CATEGORY,
getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, requestID,
updateMarksAndLinesExceptAdvantageLineInCallback));
// Request map data update, possibly in two calls; see method details
callGetRaceMapDataForAllOverlappingAndTipsOfNonOverlappingAndGetBoatPositionsForAllOthers(fromAndToAndOverlap, race, newTime, transitionTimeInMillis, competitorsToShow);
// draw the wind into the map, get the combined wind
List<String> windSourceTypeNames = new ArrayList<String>();
@@ -851,63 +832,79 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
/**
* We assume that overlapping segments usually don't require a lot of loading time as the most typical case will be to update a longer
* tail with a few new fixes that were received since the last time tick. Non-overlapping position requests typically occur for the
* first request when no fix at all is known for the competitor yet, or when the user has radically moved the time slider to some
* other time such that given the current tail length setting the new tail segment does not overlap with the old one, requiring a full
* load of the entire tail data for that competitor.<p>
* Requests updates for map data and, when received, updates the map structures accordingly.
* <p>
*
* For the non-overlapping requests, this method creates a separate request which only loads boat positions, quick ranks, sidelines and
* mark positions for the zero-length interval at <code>newTime</code>, assuming that this will work fairly fast and in particular in
* O(1) time regardless of tail length, compared to fetching the entire tail for all competitors.
*
* TODO bug 3378: This shall produce two calls: one complete GetRaceMapDataAction and another fetching of missing "long tails" which only needs to be carried out if the first call does not deliver everything requested by fromAndToAndOverlap
* The second call of GetRaceMapDataAction is this:
*
* GetRaceMapDataAction getRaceMapDataAction = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), race,
* useNullAsTimePoint() ? null : newTime, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(),
* true, // extrapolate
* (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null));
* asyncActionsExecutor.execute(getRaceMapDataAction, GET_RACE_MAP_DATA_CATEGORY,
* getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, requestID,
* updateMarksAndLinesExceptAdvantageLineInCallback));
* The update can happen in one or two round trips. We assume that overlapping segments usually don't require a lot
* of loading time as the most typical case will be to update a longer tail with a few new fixes that were received
* since the last time tick. These supposedly fast requests are handled by a {@link GetRaceMapDataAction} which also
* requests updates for mark positions, sidelines and quick ranks. The same request also loads boat positions for
* the zero-length interval at <code>newTime</code> for the non-overlapping tails assuming that this will work
* fairly fast and in particular in O(1) time regardless of tail length, compared to fetching the entire tail for
* all competitors. This will at least provide quick feedback about those competitors' positions even if loading
* their entire tail may take a little longer. The {@link GetRaceMapDataAction} therefore is intended to be a rather
* quick call.
* <p>
*
* Non-overlapping position requests typically occur for the first request when no fix at all is known for the
* competitor yet, or when the user has radically moved the time slider to some other time such that given the
* current tail length setting the new tail segment does not overlap with the old one, requiring a full load of the
* entire tail data for that competitor. For these non-overlapping requests, this method creates a
* {@link GetBoatPositionsAction} request loading the entire tail required, but not quick ranks, sidelines and mark
* positions. Updating the results of this call is done in {@link #updateBoatPositions(Date, long, Map, Iterable, Map)}.
* <p>
*/
private GetRaceMapDataAction getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping(
Triple<Map<CompetitorDTO, Date>, Map<CompetitorDTO, Date>, Map<CompetitorDTO, Boolean>> fromAndToAndOverlap,
RegattaAndRaceIdentifier race, Date newTime) {
Map<CompetitorDTO, Date> fromTimes = new HashMap<>();
Map<CompetitorDTO, Date> toTimes = new HashMap<>();
private void callGetRaceMapDataForAllOverlappingAndTipsOfNonOverlappingAndGetBoatPositionsForAllOthers(
final Triple<Map<CompetitorDTO, Date>, Map<CompetitorDTO, Date>, Map<CompetitorDTO, Boolean>> fromAndToAndOverlap,
RegattaAndRaceIdentifier race, final Date newTime, final long transitionTimeInMillis, final Iterable<CompetitorDTO> competitorsToShow) {
final Map<CompetitorDTO, Date> fromTimesForQuickCall = new HashMap<>();
final Map<CompetitorDTO, Date> toTimesForQuickCall = new HashMap<>();
final Map<CompetitorDTO, Date> fromTimesForNonOverlappingTailsCall = new HashMap<>();
final Map<CompetitorDTO, Date> toTimesForNonOverlappingTailsCall = new HashMap<>();
for (Map.Entry<CompetitorDTO, Boolean> e : fromAndToAndOverlap.getC().entrySet()) {
if (!e.getValue()) {
// no overlap; add competitor to request
fromTimes.put(e.getKey(), newTime);
toTimes.put(e.getKey(), newTime);
if (e.getValue()) {
// overlap: expect a quick response; add original request interval for the competitor
fromTimesForQuickCall.put(e.getKey(), fromAndToAndOverlap.getA().get(e.getKey()));
toTimesForQuickCall.put(e.getKey(), fromAndToAndOverlap.getB().get(e.getKey()));
} else {
// no overlap; add competitor to request with a zero-length interval asking only position at newTime, not the entire tail
fromTimesForQuickCall.put(e.getKey(), newTime);
toTimesForQuickCall.put(e.getKey(), newTime);
fromTimesForNonOverlappingTailsCall.put(e.getKey(), fromAndToAndOverlap.getA().get(e.getKey()));
toTimesForNonOverlappingTailsCall.put(e.getKey(), fromAndToAndOverlap.getB().get(e.getKey()));
}
}
final GetRaceMapDataAction result;
if (!fromTimes.isEmpty()) {
result = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(),
race, useNullAsTimePoint() ? null : newTime, fromTimes, toTimes, /* extrapolate */true, (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null));
} else {
result = null;
final Map<String, CompetitorDTO> competitorsByIdAsString = new HashMap<String, CompetitorDTO>();
for (CompetitorDTO competitor : competitorSelection.getAllCompetitors()) {
competitorsByIdAsString.put(competitor.getIdAsString(), competitor);
}
return result;
asyncActionsExecutor.execute(new GetRaceMapDataAction(sailingService, competitorsByIdAsString,
race, useNullAsTimePoint() ? null : newTime, fromTimesForQuickCall, toTimesForQuickCall, /* extrapolate */true,
(settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null)), GET_RACE_MAP_DATA_CATEGORY,
getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, ++boatPositionRequestIDCounter));
// next, if necessary, do the full thing; the two calls have different action classes, so throttling should not drop one for the other
asyncActionsExecutor.execute(new GetBoatPositionsAction(sailingService, race, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(),
/* extrapolate */ true), GET_RACE_MAP_DATA_CATEGORY,
new MarkedAsyncCallback<>(new AsyncCallback<CompactBoatPositionsDTO>() {
@Override
public void onFailure(Throwable t) {
errorReporter.reportError("Error obtaining racemap data: " + t.getMessage(), true /*silentMode */);
}
@Override
public void onSuccess(CompactBoatPositionsDTO result) {
updateBoatPositions(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, result.getBoatPositionsForCompetitors(competitorsByIdAsString));
}
}));
}
/**
* @param updateMarksAndLinesExceptAdvantageLineInCallback
* when <code>true</code>, mark positions, mark-related lines such as start line and course middle lines,
* three hull length circles and side lines are drawn; otherwise, only the boats, their info flags and
* the advantage line will be updated.
*/
private AsyncCallback<RaceMapDataDTO> getRaceMapDataCallback(
final Date newTime,
final long transitionTimeInMillis,
final Map<CompetitorDTO, Boolean> hasTailOverlapForCompetitor,
final Iterable<CompetitorDTO> competitorsToShow, final int requestID,
final boolean updateMarksAndLinesExceptAdvantageLineInCallback) {
return new AsyncCallback<RaceMapDataDTO>() {
final Iterable<CompetitorDTO> competitorsToShow, final int requestID) {
return new MarkedAsyncCallback<>(new AsyncCallback<RaceMapDataDTO>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Error obtaining racemap data: " + caught.getMessage(), true /*silentMode */);
@@ -916,28 +913,19 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
@Override
public void onSuccess(RaceMapDataDTO raceMapDataDTO) {
if (map != null && raceMapDataDTO != null) {
quickRanks = raceMapDataDTO.quickRanks;
competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber =
raceMapDataDTO.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber;
if (showViewSimulation && settings.isShowSimulationOverlay()) {
lastLegNumber = raceMapDataDTO.coursePositions.currentLegNumber;
simulationOverlay.updateLeg(Math.max(lastLegNumber,1), /* clearCanvas */ false, raceMapDataDTO.simulationResultVersion);
}
// process response only if not received out of order
if (startedProcessingRequestID < requestID) {
startedProcessingRequestID = requestID;
quickRanks = raceMapDataDTO.quickRanks;
competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber =
raceMapDataDTO.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber;
if (showViewSimulation && settings.isShowSimulationOverlay()) {
lastLegNumber = raceMapDataDTO.coursePositions.currentLegNumber;
simulationOverlay.updateLeg(Math.max(lastLegNumber, 1), /* clearCanvas */ false, raceMapDataDTO.simulationResultVersion);
}
// Do boat specific actions
Map<CompetitorDTO, List<GPSFixDTO>> boatData = raceMapDataDTO.boatPositions;
fixesAndTails.updateFixes(boatData, hasTailOverlapForCompetitor, RaceMap.this, transitionTimeInMillis);
Iterable<CompetitorDTO> competitorsForWhichNewFixesWereReveiced =
fixesAndTails.updateFixes(boatData, hasTailOverlapForCompetitor, RaceMap.this, transitionTimeInMillis);
if (!Util.isEmpty(competitorsForWhichNewFixesWereReveiced)) {
showBoatsOnMap(newTime, transitionTimeInMillis, competitorsForWhichNewFixesWereReveiced);
showCompetitorInfoOnMap(newTime, transitionTimeInMillis, competitorSelection.getSelectedFilteredCompetitors());
// even though the wind data is retrieved by a separate call, re-draw the advantage line because it needs to
// adjust to new boat positions
showAdvantageLine(competitorsToShow, newTime, transitionTimeInMillis);
}
updateBoatPositions(newTime, transitionTimeInMillis, hasTailOverlapForCompetitor, competitorsToShow, boatData);
if (douglasMarkers != null) {
removeAllMarkDouglasPeuckerpoints();
}
@@ -948,13 +936,11 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
if (requiresCoordinateSystemUpdateWhenCoursePositionAndWindDirectionIsKnown) {
updateCoordinateSystemFromSettings();
}
if (updateMarksAndLinesExceptAdvantageLineInCallback) {
// Do mark specific actions
showCourseMarksOnMap(raceMapDataDTO.coursePositions);
showCourseSidelinesOnMap(raceMapDataDTO.courseSidelines);
showStartAndFinishAndCourseMiddleLines(raceMapDataDTO.coursePositions);
showStartLineToFirstMarkTriangle(raceMapDataDTO.coursePositions);
}
// Do mark specific actions
showCourseMarksOnMap(raceMapDataDTO.coursePositions);
showCourseSidelinesOnMap(raceMapDataDTO.courseSidelines);
showStartAndFinishAndCourseMiddleLines(raceMapDataDTO.coursePositions);
showStartLineToFirstMarkTriangle(raceMapDataDTO.coursePositions);
// Rezoom the map
LatLngBounds zoomToBounds = null;
@@ -982,7 +968,22 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
lastTimeChangeBeforeInitialization = newTime;
}
}
};
});
}
private void updateBoatPositions(final Date newTime, final long transitionTimeInMillis,
final Map<CompetitorDTO, Boolean> hasTailOverlapForCompetitor,
final Iterable<CompetitorDTO> competitorsToShow, Map<CompetitorDTO, List<GPSFixDTO>> boatData) {
fixesAndTails.updateFixes(boatData, hasTailOverlapForCompetitor, RaceMap.this, transitionTimeInMillis);
Iterable<CompetitorDTO> competitorsForWhichNewFixesWereReveiced =
fixesAndTails.updateFixes(boatData, hasTailOverlapForCompetitor, RaceMap.this, transitionTimeInMillis);
if (!Util.isEmpty(competitorsForWhichNewFixesWereReveiced)) {
showBoatsOnMap(newTime, transitionTimeInMillis, competitorsForWhichNewFixesWereReveiced);
showCompetitorInfoOnMap(newTime, transitionTimeInMillis, competitorSelection.getSelectedFilteredCompetitors());
// even though the wind data is retrieved by a separate call, re-draw the advantage line because it needs to
// adjust to new boat positions
showAdvantageLine(competitorsToShow, newTime, transitionTimeInMillis);
}
}
private void showCourseSidelinesOnMap(List<SidelineDTO> sidelinesDTOs) {
@@ -291,6 +291,7 @@ import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
import com.sap.sailing.gwt.ui.adminconsole.RaceLogSetTrackingTimesDTO;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
import com.sap.sailing.gwt.ui.shared.CompactBoatPositionsDTO;
import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorRaceDataDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
@@ -1640,7 +1641,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
public CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date,
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
boolean extrapolate, LegIdentifier simulationLegIdentifier) throws NoWindException {
final Map<CompetitorDTO, List<GPSFixDTO>> boatPositions = getBoatPositions(raceIdentifier,
final Map<CompetitorDTO, List<GPSFixDTO>> boatPositions = getBoatPositionsInternal(raceIdentifier,
fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate);
final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date);
final List<SidelineDTO> courseSidelines = getCourseSidelines(raceIdentifier, date);
@@ -1670,6 +1671,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
return competitorBoats;
}
@Override
public CompactBoatPositionsDTO getBoatPositions(RegattaAndRaceIdentifier raceIdentifier,
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
boolean extrapolate) throws NoWindException {
return new CompactBoatPositionsDTO(getBoatPositionsInternal(raceIdentifier, fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate));
}
/**
* {@link LegType}s are cached within the method with a resolution of one minute. The cache key is a pair of
* {@link TrackedLegOfCompetitor} and {@link TimePoint}.
@@ -1688,7 +1697,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
* @return a map where for each competitor participating in the race the list of GPS fixes in increasing
* chronological order is provided. The last one is the last position at or before <code>date</code>.
*/
private Map<CompetitorDTO, List<GPSFixDTO>> getBoatPositions(RegattaAndRaceIdentifier raceIdentifier,
private Map<CompetitorDTO, List<GPSFixDTO>> getBoatPositionsInternal(RegattaAndRaceIdentifier raceIdentifier,
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
boolean extrapolate)
throws NoWindException {
@@ -0,0 +1,31 @@
package com.sap.sailing.gwt.ui.shared;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
public class CompactBoatPositionsDTO implements IsSerializable {
private Map<String, List<GPSFixDTO>> boatPositions;
CompactBoatPositionsDTO() {} // for GWT serialization only
public CompactBoatPositionsDTO(Map<CompetitorDTO, List<GPSFixDTO>> boatPositions) {
super();
this.boatPositions = new HashMap<>();
for (final Entry<CompetitorDTO, List<GPSFixDTO>> e : boatPositions.entrySet()) {
this.boatPositions.put(e.getKey().getIdAsString(), e.getValue());
}
}
public Map<CompetitorDTO, List<GPSFixDTO>> getBoatPositionsForCompetitors(Map<String, CompetitorDTO> competitorsByIdsAsStrings) {
final Map<CompetitorDTO, List<GPSFixDTO>> result = new HashMap<>();
for (final Entry<String, List<GPSFixDTO>> e : boatPositions.entrySet()) {
result.put(competitorsByIdsAsStrings.get(e.getKey()), e.getValue());
}
return result;
}
}
@@ -23,7 +23,7 @@ import com.sap.sse.common.Util;
*
*/
public class CompactRaceMapDataDTO implements IsSerializable {
private Map<String, List<GPSFixDTO>> boatPositionsByCompetitorIdAsString;
private CompactBoatPositionsDTO boatPositionsByCompetitorIdAsString;
private CoursePositionsDTO coursePositions;
private List<SidelineDTO> courseSidelines;
@@ -35,10 +35,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
public CompactRaceMapDataDTO(Map<CompetitorDTO, List<GPSFixDTO>> boatPositions, CoursePositionsDTO coursePositions,
List<SidelineDTO> courseSidelines, QuickRanksDTO quickRanks, long simulationResultVersion) {
this.boatPositionsByCompetitorIdAsString = new HashMap<String, List<GPSFixDTO>>();
for (Map.Entry<CompetitorDTO, List<GPSFixDTO>> e : boatPositions.entrySet()) {
this.boatPositionsByCompetitorIdAsString.put(e.getKey().getIdAsString(), e.getValue());
}
this.boatPositionsByCompetitorIdAsString = new CompactBoatPositionsDTO(boatPositions);
this.quickRanks = new ArrayList<CompactQuickRankDTO>(quickRanks == null ? 0 : Util.size(quickRanks.getQuickRanks()));
this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber = new LinkedHashMap<>();
Map<String, Integer> competitorIdAsStringToOneBasedLegNumber = new HashMap<>();
@@ -59,11 +56,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
this.simulationResultVersion = simulationResultVersion;
}
public RaceMapDataDTO getRaceMapDataDTO(Iterable<CompetitorDTO> competitors) {
Map<String, CompetitorDTO> competitorsByIdAsString = new HashMap<String, CompetitorDTO>();
for (CompetitorDTO competitor : competitors) {
competitorsByIdAsString.put(competitor.getIdAsString(), competitor);
}
public RaceMapDataDTO getRaceMapDataDTO(Map<String, CompetitorDTO> competitorsByIdAsString) {
RaceMapDataDTO result = new RaceMapDataDTO();
result.quickRanks = new LinkedHashMap<CompetitorDTO, QuickRankDTO>(this.quickRanks.size());
for (CompactQuickRankDTO compactQuickRank : this.quickRanks) {
@@ -74,14 +67,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
}
result.courseSidelines = courseSidelines;
result.coursePositions = coursePositions;
result.boatPositions = new HashMap<CompetitorDTO, List<GPSFixDTO>>();
for (Map.Entry<String, List<GPSFixDTO>> e : boatPositionsByCompetitorIdAsString.entrySet()) {
final CompetitorDTO competitor = competitorsByIdAsString.get(e.getKey());
if (competitor != null) {
// maybe null in case the competitor was added, e.g., by unsuppressing, while this call was underway
result.boatPositions.put(competitor, e.getValue());
}
}
result.boatPositions = boatPositionsByCompetitorIdAsString.getBoatPositionsForCompetitors(competitorsByIdAsString);
result.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber = new LinkedHashMap<>();
for (Entry<String, Integer> i : competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber.entrySet()) {
CompetitorDTO c = competitorsByIdAsString.get(i.getKey());