added target time estimation option

This commit is contained in:
Kai Boernert
2017-07-11 10:49:34 +02:00
parent e117737f84
commit 16197cbaac
19 changed files with 149 additions and 14 deletions
@@ -167,7 +167,7 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
defaultRaceMapSettings.isShowSelectedCompetitorsInfo(), defaultRaceMapSettings.isShowWindStreamletColors(),
defaultRaceMapSettings.isShowWindStreamletOverlay(), defaultRaceMapSettings.isShowSimulationOverlay(),
defaultRaceMapSettings.isShowMapControls(), defaultRaceMapSettings.getManeuverTypesToShow(),
defaultRaceMapSettings.isShowDouglasPeuckerPoints());
defaultRaceMapSettings.isShowDouglasPeuckerPoints(),defaultRaceMapSettings.isShowTargetEstimation());
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(sailingServiceAsync,
@@ -104,6 +104,7 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.mail.MailException;
import com.sap.sse.gwt.client.ServerInfoDTO;
import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtService;
@@ -680,4 +681,5 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
void setEliminatedCompetitors(String leaderboardName, Set<CompetitorDTO> eliminatedCompetitors);
Duration getEstimatedTargetTime(MillisecondsTimePoint millisecondsTimePoint, RegattaAndRaceIdentifier raceIdentifier);
}
@@ -93,6 +93,7 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.ServerInfoRetriever;
import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtServiceAsync;
import com.sap.sse.gwt.client.media.ImageDTO;
@@ -838,4 +839,8 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
void setEliminatedCompetitors(String leaderboardName, Set<CompetitorDTO> eliminatedCompetitors,
AsyncCallback<Void> callback);
void getEstimatedTargetTime(MillisecondsTimePoint millisecondsTimePoint, RegattaAndRaceIdentifier raceIdentifier,
AsyncCallback<Duration> asyncCallback);
}
@@ -1816,4 +1816,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String documentSettingsId();
String settingsForId(String id);
String userProfileSettingsTabDescription();
String estimatedEndtime();
String showTargetEstimation();
}
@@ -1799,3 +1799,5 @@ resetToDefault=Reset to default
resetToDefaultInProgress=In resetting...
settingsRemoved=Default settings restored
settingsRemovedError=Could not restore default settings
estimatedEndtime=~race end:
showTargetEstimation=Show estimated race end time
@@ -1782,3 +1782,5 @@ resetToDefault=Auf Standard zurücksetzen
resetToDefaultInProgress=Setze zurück...
settingsRemoved=Standardeinstellungen wiederhergestellt
settingsRemovedError=Fehler beim Widerherstellen der Standardeinstellungen
estimatedEndtime=~Rennende:
showTargetEstimation=Zeige geschätztes Rennende an
@@ -53,7 +53,7 @@ public class CombinedWindPanel extends FlowPanel {
oldRaceMapSettings.isShowSelectedCompetitorsInfo(), oldRaceMapSettings.isShowWindStreamletColors(),
newShowStreamletsOverlaySetting, oldRaceMapSettings.isShowSimulationOverlay(),
oldRaceMapSettings.isShowMapControls(), oldRaceMapSettings.getManeuverTypesToShow(),
oldRaceMapSettings.isShowDouglasPeuckerPoints());
oldRaceMapSettings.isShowDouglasPeuckerPoints(),oldRaceMapSettings.isShowTargetEstimation());
map.updateSettings(newRaceMapSettings);
}
});
@@ -0,0 +1,38 @@
package com.sap.sailing.gwt.ui.client.shared.racemap;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sse.common.Duration;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.async.AsyncAction;
public class GetTargetTimeAction implements AsyncAction<Duration> {
private MillisecondsTimePoint millisecondsTimePoint;
private RegattaAndRaceIdentifier raceIdentifier;
private SailingServiceAsync sailingService;
public GetTargetTimeAction(SailingServiceAsync sailingService, MillisecondsTimePoint millisecondsTimePoint, RegattaAndRaceIdentifier raceIdentifier) {
this.millisecondsTimePoint = millisecondsTimePoint;
this.raceIdentifier = raceIdentifier;
this.sailingService = sailingService;
}
@Override
public void execute(AsyncCallback<Duration> callback) {
sailingService.getEstimatedTargetTime(millisecondsTimePoint,raceIdentifier,new AsyncCallback<Duration>() {
@Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
}
@Override
public void onSuccess(Duration result) {
callback.onSuccess(result);
}
});
}
}
@@ -34,4 +34,17 @@ body {
.trueNorthIndicatorPanel {
margin-top: 10px;
}
.estimatedTargettime{
font-size: 19px;
color:black;
background-color:rgba(255,255,255,0.75);
border:1px solid #c9caca;
border-radius:4px;
text-align: left;
height:30px;
padding-right: 8px;
padding-left: 8px;
margin-bottom: 10px;
}
@@ -129,11 +129,13 @@ import com.sap.sailing.gwt.ui.shared.racemap.GoogleMapStyleHelper;
import com.sap.sailing.gwt.ui.shared.racemap.RaceSimulationOverlay;
import com.sap.sailing.gwt.ui.shared.racemap.WindStreamletsRaceboardOverlay;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.filter.Filter;
import com.sap.sse.common.filter.FilterSet;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.RGBColor;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
@@ -157,6 +159,8 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
private static final String COMPACT_HEADER_STYLE = "compactHeader";
public static final Color WATER_COLOR = new RGBColor(0, 67, 125);
private static final long DELAY_ESTIMATION_UPDATE = 10000;
private static final DateTimeFormat TARGET_TIME_ESTIMATION_FORMAT = DateTimeFormat.getFormat("HH:mm");
private AbsolutePanel rootPanel = new AbsolutePanel();
@@ -417,6 +421,9 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
* {@link #showAdvantageLine(Iterable, Date, long)} drawing procedure} needs to be triggered.
*/
private CompetitorDTO advantageLineCompetitor;
private Date lastUpdateOfTargetEstimation = new Date(0);
protected Label targetEstimationOverlay;
private RaceMapStyle raceMapStyle;
private class AdvantageLineUpdater implements QuickRanksListener {
@Override
@@ -473,7 +480,7 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
panelForLeftHeaderLabels = new AbsolutePanel();
panelForRightHeaderLabels = new AbsolutePanel();
initializeData(settings.isShowMapControls(), showHeaderPanel);
RaceMapStyle raceMapStyle = raceMapResources.raceMapStyle();
raceMapStyle = raceMapResources.raceMapStyle();
raceMapStyle.ensureInjected();
combinedWindPanel = new CombinedWindPanel(this, raceMapImageManager, raceMapStyle, stringMessages, coordinateSystem);
combinedWindPanel.setVisible(false);
@@ -857,7 +864,8 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
public void onSuccess(WindInfoForRaceDTO windInfo) {
List<com.sap.sse.common.Util.Pair<WindSource, WindTrackInfoDTO>> windSourcesToShow = new ArrayList<com.sap.sse.common.Util.Pair<WindSource, WindTrackInfoDTO>>();
if (windInfo != null) {
lastCombinedWindTrackInfoDTO = windInfo;
lastCombinedWindTrackInfoDTO = windInfo;
updateTargetTimeEstimation(newTime);
showAdvantageLine(competitorsToShow, newTime, transitionTimeInMillis);
for (WindSource windSource : windInfo.windTrackInfoByWindSource.keySet()) {
WindTrackInfoDTO windTrackInfoDTO = windInfo.windTrackInfoByWindSource.get(windSource);
@@ -891,6 +899,36 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
}
}
protected void updateTargetTimeEstimation(Date newTime) {
if(settings.isShowTargetEstimation() && lastUpdateOfTargetEstimation.getTime() + DELAY_ESTIMATION_UPDATE < newTime.getTime()){
//we have wind, try to estimate time now
lastUpdateOfTargetEstimation = newTime;
asyncActionsExecutor.execute(new GetTargetTimeAction(sailingService,new MillisecondsTimePoint(newTime),raceIdentifier), new AsyncCallback<Duration>(){
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Error obtaining targettime: " + caught.getMessage(), true /*silentMode */);
}
@Override
public void onSuccess(Duration result) {
if(result == null){
//server could not determine time
return;
}
if(targetEstimationOverlay == null){
targetEstimationOverlay = new Label("");
targetEstimationOverlay.setStyleName(raceMapStyle.estimatedTargettime());
map.setControls(ControlPosition.BOTTOM_LEFT, targetEstimationOverlay);
}
long endTime = lastRaceTimesInfo.getStartOfRace().getTime()+result.asMillis();
Date endDate = new Date(endTime);
targetEstimationOverlay.setText(stringMessages.estimatedEndtime() + " "+ TARGET_TIME_ESTIMATION_FORMAT.format(endDate));
}
});
}
}
/**
* Requests updates for map data and, when received, updates the map structures accordingly.
* <p>
@@ -2592,6 +2630,9 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
requiresUpdateCoordinateSystem = true;
requiresRedraw = true;
}
if(!newSettings.isShowTargetEstimation() && targetEstimationOverlay != null){
targetEstimationOverlay.removeFromParent();
}
this.settings = newSettings;
if (requiresUpdateCoordinateSystem) {
@@ -47,12 +47,12 @@ public class RaceMapLifecycle implements ComponentLifecycle<RaceMapSettings> {
@Override
public RaceMapSettings extractUserSettings(RaceMapSettings settings) {
RaceMapSettings defaultSettings = createDefaultSettings();
return new RaceMapSettings(settings.getZoomSettings(), settings.getHelpLinesSettings(), settings.getTransparentHoverlines(), settings.getHoverlineStrokeWeight(), settings.getTailLengthInMilliseconds(), settings.isWindUp(), defaultSettings.getBuoyZoneRadius(), settings.isShowOnlySelectedCompetitors(), settings.isShowSelectedCompetitorsInfo(), settings.isShowWindStreamletColors(), settings.isShowWindStreamletOverlay(), settings.isShowSimulationOverlay(), settings.isShowMapControls(), settings.getManeuverTypesToShow(), settings.isShowDouglasPeuckerPoints());
return new RaceMapSettings(settings.getZoomSettings(), settings.getHelpLinesSettings(), settings.getTransparentHoverlines(), settings.getHoverlineStrokeWeight(), settings.getTailLengthInMilliseconds(), settings.isWindUp(), defaultSettings.getBuoyZoneRadius(), settings.isShowOnlySelectedCompetitors(), settings.isShowSelectedCompetitorsInfo(), settings.isShowWindStreamletColors(), settings.isShowWindStreamletOverlay(), settings.isShowSimulationOverlay(), settings.isShowMapControls(), settings.getManeuverTypesToShow(), settings.isShowDouglasPeuckerPoints(),settings.isShowTargetEstimation());
}
@Override
public RaceMapSettings extractDocumentSettings(RaceMapSettings settings) {
RaceMapSettings defaultSettings = createDefaultSettings();
return new RaceMapSettings(settings.getZoomSettings(), settings.getHelpLinesSettings(), settings.getTransparentHoverlines(), settings.getHoverlineStrokeWeight(), settings.getTailLengthInMilliseconds(), settings.isWindUp(), defaultSettings.getBuoyZoneRadius(), settings.isShowOnlySelectedCompetitors(), settings.isShowSelectedCompetitorsInfo(), settings.isShowWindStreamletColors(), settings.isShowWindStreamletOverlay(), settings.isShowSimulationOverlay(), settings.isShowMapControls(), settings.getManeuverTypesToShow(), settings.isShowDouglasPeuckerPoints());
return new RaceMapSettings(settings.getZoomSettings(), settings.getHelpLinesSettings(), settings.getTransparentHoverlines(), settings.getHoverlineStrokeWeight(), settings.getTailLengthInMilliseconds(), settings.isWindUp(), defaultSettings.getBuoyZoneRadius(), settings.isShowOnlySelectedCompetitors(), settings.isShowSelectedCompetitorsInfo(), settings.isShowWindStreamletColors(), settings.isShowWindStreamletOverlay(), settings.isShowSimulationOverlay(), settings.isShowMapControls(), settings.getManeuverTypesToShow(), settings.isShowDouglasPeuckerPoints(),settings.isShowTargetEstimation());
}
}
@@ -69,6 +69,8 @@ public class RaceMapSettings extends AbstractGenericSerializableSettings {
*/
private BooleanSetting windUp;
private BooleanSetting showEstimatedRaceEnd;
@Override
protected void addChildSettings() {
showMapControls = new BooleanSetting(PARAM_SHOW_MAPCONTROLS, this, true);
@@ -86,6 +88,7 @@ public class RaceMapSettings extends AbstractGenericSerializableSettings {
showSelectedCompetitorsInfo = new BooleanSetting("showSelectedCompetitorsInfo", this, true);
maneuverTypesToShow = new EnumSetSetting<>("maneuverTypesToShow", this, getDefaultManeuvers(), ManeuverType::valueOf);
showDouglasPeuckerPoints = new BooleanSetting("showDouglasPeuckerPoints", this, false);
showEstimatedRaceEnd = new BooleanSetting("showEstimatedRaceEnd", this, false);
}
public RaceMapSettings() {
@@ -95,7 +98,7 @@ public class RaceMapSettings extends AbstractGenericSerializableSettings {
Boolean transparentHoverlines, Integer hoverlineStrokeWeight, Long tailLengthInMilliseconds, Boolean windUp,
Distance buoyZoneRadius, Boolean showOnlySelectedCompetitors, Boolean showSelectedCompetitorsInfo,
Boolean showWindStreamletColors, Boolean showWindStreamletOverlay, Boolean showSimulationOverlay,
Boolean showMapControls, Collection<ManeuverType> maneuverTypesToShow, Boolean showDouglasPeuckerPoints) {
Boolean showMapControls, Collection<ManeuverType> maneuverTypesToShow, Boolean showDouglasPeuckerPoints,Boolean showEstimatedRaceEnd) {
this.zoomSettings.init(zoomSettings);
this.helpLinesSettings.init(helpLinesSettings);
this.transparentHoverlines.setValue(transparentHoverlines);
@@ -111,6 +114,7 @@ public class RaceMapSettings extends AbstractGenericSerializableSettings {
this.showMapControls.setValue(showMapControls);
this.maneuverTypesToShow.setValues(maneuverTypesToShow);
this.showDouglasPeuckerPoints.setValue(showDouglasPeuckerPoints);
this.showEstimatedRaceEnd.setValue(showEstimatedRaceEnd);
}
public static RaceMapSettings getDefaultWithShowMapControls(boolean showMapControlls) {
@@ -139,7 +143,7 @@ public class RaceMapSettings extends AbstractGenericSerializableSettings {
/* showSimulationOverlay */ showSimulationOverlay,
/* showMapControls */ showMapControls,
/* maneuverTypesToShow */ getDefaultManeuvers(),
/* showDouglasPeuckerPoints */ false);
/* showDouglasPeuckerPoints */ false,false);
}
private static Set<HelpLineTypes> createHelpLineSettings(boolean showCourseGeometry) {
@@ -260,7 +264,7 @@ public class RaceMapSettings extends AbstractGenericSerializableSettings {
settings.isShowWindStreamletOverlay(),
settings.isShowSimulationOverlay(), settings.isShowMapControls(),
settings.getManeuverTypesToShow(),
settings.isShowDouglasPeuckerPoints());
settings.isShowDouglasPeuckerPoints(),settings.isShowTargetEstimation());
return newRaceMapSettings;
}
@@ -297,4 +301,8 @@ public class RaceMapSettings extends AbstractGenericSerializableSettings {
public Set<ManeuverType> getManeuverTypesToShow() {
return Util.createSet(maneuverTypesToShow.getValues());
}
public boolean isShowTargetEstimation() {
return showEstimatedRaceEnd.getValue();
}
}
@@ -60,6 +60,7 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
private final RaceMapSettings initialSettings;
private ArrayList<CheckBox> disableOnlySelectedWhenAreFalse;
private CheckBox showTargetEstimation;
public RaceMapSettingsDialogComponent(RaceMapSettings settings, StringMessages stringMessages, boolean isSimulationEnabled) {
this.isSimulationEnabled = isSimulationEnabled;
@@ -97,6 +98,11 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
}
});
showTargetEstimation = dialog.createCheckbox(stringMessages.showTargetEstimation());
showTargetEstimation.ensureDebugId("showTargetEstimationCheckBox");
showTargetEstimation.setValue(initialSettings.isShowTargetEstimation());
vp.add(showTargetEstimation);
if (isSimulationEnabled) {
showSimulationOverlayCheckbox = dialog.createCheckbox(stringMessages.showSimulationOverlay());
showSimulationOverlayCheckbox.ensureDebugId("showSimulationOverlayCheckBox");
@@ -291,7 +297,7 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
transparentHoverlines.getValue(), hoverlineStrokeWeight.getValue(), tailLengthInMilliseconds, windUpCheckbox.getValue(),
buoyZoneRadius, showOnlySelectedCompetitorsCheckBox.getValue(), showSelectedCompetitorsInfoCheckBox.getValue(),
showWindStreamletColorsCheckbox.getValue(), showWindStreamletOverlayCheckbox.getValue(), showSimulationOverlay,
initialSettings.isShowMapControls(), maneuverTypesToShow, showDouglasPeuckerPointsCheckBox.getValue());
initialSettings.isShowMapControls(), maneuverTypesToShow, showDouglasPeuckerPointsCheckBox.getValue(),showTargetEstimation.getValue());
}
private RaceMapZoomSettings getZoomSettings() {
@@ -18,4 +18,5 @@ public interface RaceMapStyle extends CssResource {
public String raceMapIndicatorPanelCanvas();
public String combinedWindPanel();
public String trueNorthIndicatorPanel();
public String estimatedTargettime();
}
@@ -53,7 +53,7 @@ public class TrueNorthIndicatorPanel extends FlowPanel {
oldRaceMapSettings.isShowSelectedCompetitorsInfo(), oldRaceMapSettings.isShowWindStreamletColors(),
oldRaceMapSettings.isShowWindStreamletOverlay(), oldRaceMapSettings.isShowSimulationOverlay(),
oldRaceMapSettings.isShowMapControls(), oldRaceMapSettings.getManeuverTypesToShow(),
oldRaceMapSettings.isShowDouglasPeuckerPoints());
oldRaceMapSettings.isShowDouglasPeuckerPoints(),oldRaceMapSettings.isShowTargetEstimation());
map.updateSettings(newRaceMapSettings);
}
});
@@ -117,7 +117,7 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
defaultRaceMapSettings.isShowSelectedCompetitorsInfo(), defaultRaceMapSettings.isShowWindStreamletColors(),
defaultRaceMapSettings.isShowWindStreamletOverlay(), defaultRaceMapSettings.isShowSimulationOverlay(),
defaultRaceMapSettings.isShowMapControls(), defaultRaceMapSettings.getManeuverTypesToShow(),
defaultRaceMapSettings.isShowDouglasPeuckerPoints());
defaultRaceMapSettings.isShowDouglasPeuckerPoints(),defaultRaceMapSettings.isShowTargetEstimation());
sailingService.getRaceIdentifier(regattaLikeName, raceColumnName, fleetName, new AsyncCallback<RegattaAndRaceIdentifier>() {
@Override
@@ -80,7 +80,7 @@ public class StartAnalysisMode extends RaceBoardModeWithPerRaceCompetitors {
defaultSettings.isShowSimulationOverlay(),
defaultSettings.isShowMapControls(),
defaultSettings.getManeuverTypesToShow(),
defaultSettings.isShowDouglasPeuckerPoints());
defaultSettings.isShowDouglasPeuckerPoints(),defaultSettings.isShowTargetEstimation());
((RaceBoardComponentContext) raceMap.getComponentContext()).addModesPatching(raceMap, additiveSettings, new OnSettingsReloadedCallback<RaceMapSettings>() {
@@ -76,7 +76,7 @@ public class WinningLanesMode extends RaceBoardModeWithPerRaceCompetitors {
defaultSettings.isShowSimulationOverlay(),
defaultSettings.isShowMapControls(),
defaultSettings.getManeuverTypesToShow(),
defaultSettings.isShowDouglasPeuckerPoints());
defaultSettings.isShowDouglasPeuckerPoints(),defaultSettings.isShowTargetEstimation());
((RaceBoardComponentContext) raceMap.getComponentContext()).addModesPatching(raceMap, additiveSettings, new OnSettingsReloadedCallback<RaceMapSettings>() {
@@ -6556,4 +6556,19 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
getService().apply(new UpdateEliminatedCompetitorsInLeaderboard(leaderboardName, newEliminatedCompetitors));
}
@Override
public Duration getEstimatedTargetTime(MillisecondsTimePoint millisecondsTimePoint,
RegattaAndRaceIdentifier raceIdentifier) {
DynamicTrackedRace race = getTrackedRace(raceIdentifier);
if(race != null){
try {
return race.getEstimatedTimeToComplete(millisecondsTimePoint).getExpectedDuration();
} catch (NotEnoughDataHasBeenAddedException | NoWindException e) {
e.printStackTrace();
return null;
}
}
return null;
}
}