Merge remote-tracking branch 'origin/master'

Conflicts:
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
This commit is contained in:
Lennart Hensler
2012-03-14 16:07:37 +01:00
21 changed files with 237 additions and 84 deletions
@@ -65,6 +65,7 @@ public class RaceStartedAndFinishedReceiver extends AbstractReceiverWithQueue<Ra
if (trackedRace.getStart() == null || !trackedRace.getStart().equals(start)) {
trackedRace.setStartTimeReceived(start);
}
// TODO forward race stop time, event.getB().getStopTime()
} else {
logger.warning("Couldn't find tracked race for race " + event.getA().getName()
+ ". Dropping start/stop event " + event);
@@ -555,8 +555,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
@Override
public Wind getWind(Position p, TimePoint at, Iterable<WindSource> windSourcesToExclude) {
final WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = getWindWithConfidence(p, at,
windSourcesToExclude);
final WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = getWindWithConfidence(p, at, windSourcesToExclude);
return windWithConfidence == null ? null : windWithConfidence.getObject();
}
@@ -576,6 +575,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
.createWindAverager(timeWeigherThatPretendsToAlsoWeighPositions);
List<WindWithConfidence<Pair<Position, TimePoint>>> windFixesWithConfidences = new ArrayList<WindWithConfidence<Pair<Position, TimePoint>>>();
for (WindSource windSource : getWindSources()) {
// TODO consider parallelizing
if (!Util.contains(windSourcesToExclude, windSource)) {
WindTrack track = getOrCreateWindTrack(windSource);
WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = track.getAveragedWindWithConfidence(
@@ -35,11 +35,11 @@ interface AdminConsoleResources extends ClientBundle {
@Source("com/sap/sailing/gwt/ui/client/images/reddot.png")
ImageResource reddotIcon();
@Source("com/sap/sailing/gwt/ui/client/images/windarrow.png")
ImageResource windDirectionIcon();
@Source("com/sap/sailing/gwt/ui/client/images/wind_combined.png")
ImageResource combinedWindIcon();
@Source("com/sap/sailing/gwt/ui/client/images/windsensor.png")
ImageResource windSensorIcon();
@Source("com/sap/sailing/gwt/ui/client/images/wind_expedition.png")
ImageResource expeditionWindIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boats/Blue_Port.png")
ImageResource lowlightedBoatIcon_Port();
@@ -72,7 +72,6 @@ public class CombinedWindPanel extends FlowPanel implements TimeListener, RaceSe
if (date != null) {
if (selectedRaces != null && !selectedRaces.isEmpty()) {
RaceIdentifier race = selectedRaces.get(selectedRaces.size() - 1);
if (race != null) {
// draw the wind into the map, get the combined wind
sailingService.getWindInfo(race, date, 1000L, 1, windSourceTypeNames,
@@ -115,7 +114,7 @@ public class CombinedWindPanel extends FlowPanel implements TimeListener, RaceSe
rotationDegOfWindSymbol = rotationDegOfWindSymbol - 360;
String transformedImageURL = transformer.getTransformedImageURL(rotationDegOfWindSymbol, 1.0);
windSymbolImage.setUrl(transformedImageURL);
windSymbolImage.setTitle(Math.round(windFromDeg) + " " + stringMessages.degreesShort());
windSymbolImage.setTitle(stringMessages.wind() + ": " + Math.round(windFromDeg) + " " + stringMessages.degreesShort());
textLabel.setText(numberFormat.format(speedInKnots) + " " + stringMessages.averageSpeedInKnotsUnit());
if(!isVisible())
@@ -532,6 +532,14 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
windSensorMarkers.put(windSource, windSensorMarker);
map.addOverlay(windSensorMarker);
} else {
double windFromDeg = windDTO.dampenedTrueWindFromDeg;
ImageTransformer transformer = imageResources.expeditionWindIconTransformer;
double rotationDegOfWindSymbol = 180.0 + windFromDeg;
if(rotationDegOfWindSymbol >= 360.0)
rotationDegOfWindSymbol = rotationDegOfWindSymbol - 360;
String transformedImageURL = transformer.getTransformedImageURL(rotationDegOfWindSymbol, 1.0);
windSensorMarker.setImage(transformedImageURL);
windSensorMarker.setLatLng(LatLng.newInstance(windDTO.position.latDeg, windDTO.position.lngDeg));
toRemoveWindSources.remove(windSource);
}
@@ -677,9 +685,19 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
double latDeg = windDTO.position.latDeg;
double lngDeg = windDTO.position.lngDeg;
MarkerOptions options = MarkerOptions.newInstance();
Icon icon = imageResources.windSensorIcon;
double windFromDeg = windDTO.dampenedTrueWindFromDeg;
ImageTransformer transformer = imageResources.expeditionWindIconTransformer;
double rotationDegOfWindSymbol = 180.0 + windFromDeg;
if(rotationDegOfWindSymbol >= 360.0)
rotationDegOfWindSymbol = rotationDegOfWindSymbol - 360;
String transformedImageURL = transformer.getTransformedImageURL(rotationDegOfWindSymbol, 1.0);
Icon icon = Icon.newInstance(transformedImageURL);
icon.setIconAnchor(Point.newInstance(7, 13));
options.setIcon(icon);
options.setTitle("Expedition wind sensor");
options.setTitle(stringMessages.wind() + ": " + Math.round(windFromDeg) + " " + stringMessages.degreesShort());
final Marker windSensorMarker = new Marker(LatLng.newInstance(latDeg, lngDeg), options);
windSensorMarker.addMarkerClickHandler(new MarkerClickHandler() {
@Override
@@ -713,7 +731,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
private String formatPosition(double lat, double lng) {
NumberFormat numberFormat = NumberFormat.getFormat("0.0");
String result = "Position: " + numberFormat.format(lat) + " lat, " + numberFormat.format(lng) + " lng";
String result = stringMessages.position() + ": " + numberFormat.format(lat) + " lat, " + numberFormat.format(lng) + " lng";
return result;
}
@@ -730,9 +748,11 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
private Widget getInfoWindowContent(WindDTO windDTO) {
NumberFormat numberFormat = NumberFormat.getFormat("0.0");
VerticalPanel result = new VerticalPanel();
NumberFormat numberFormat = NumberFormat.getFormat("0.000");
result.add(new Label("Wind: " + numberFormat.format(windDTO.dampenedTrueWindFromDeg) + " deg"));
result.add(new Label(stringMessages.windSource() + ": " + "Expedition"));
result.add(new Label(stringMessages.wind() + ": " + Math.round(windDTO.dampenedTrueWindFromDeg) + " " + stringMessages.degreesShort()));
result.add(new Label(stringMessages.windSpeed() + ": " + numberFormat.format(windDTO.dampenedTrueWindSpeedInKnots)));
result.add(new Label(formatPosition(windDTO.position.latDeg, windDTO.position.lngDeg)));
return result;
}
@@ -61,10 +61,13 @@ public class RaceMapResources {
* An arrow showing the combined wind depending on the wind direction
*/
protected ImageTransformer combinedWindIconTransformer;
protected Icon buoyIcon;
protected Icon windSensorIcon;
/**
* An arrow showing the wind provided by a wind sensor on a boat
*/
protected ImageTransformer expeditionWindIconTransformer;
protected Icon buoyIcon;
protected Map<Pair<ManeuverType, Tack>, Icon> maneuverIconsForTypeAndTargetTack;
@@ -83,7 +86,8 @@ public class RaceMapResources {
boatIconHighlightedPortTransformer = new ImageTransformer(resources.highlightedBoatIcon_Port());
boatIconStarboardTransformer = new ImageTransformer(resources.lowlightedBoatIcon_Starboard());
boatIconHighlightedStarboardTransformer = new ImageTransformer(resources.highlightedBoatIcon_Starboard());
combinedWindIconTransformer = new ImageTransformer(resources.windDirectionIcon());
combinedWindIconTransformer = new ImageTransformer(resources.combinedWindIcon());
expeditionWindIconTransformer = new ImageTransformer(resources.expeditionWindIcon());
}
/**
@@ -95,9 +99,6 @@ public class RaceMapResources {
buoyIcon = Icon.newInstance(resources.buoyIcon().getSafeUri().asString());
buoyIcon.setIconAnchor(Point.newInstance(4, 4));
windSensorIcon = Icon.newInstance(resources.windSensorIcon().getSafeUri().asString());
buoyIcon.setIconAnchor(Point.newInstance(0, 0));
Icon tackToStarboardIcon = Icon
.newInstance("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=T|00FF00|000000");
tackToStarboardIcon.setIconAnchor(Point.newInstance(10, 33));
@@ -162,7 +162,6 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
if (valueToValidate.getTailLengthInMilliseconds() < 0) {
errorMessage = stringMessages.tailLengthMustBeNonNegative();
}
return errorMessage;
}
};
@@ -12,6 +12,7 @@ import org.moxieapps.gwt.highcharts.client.Axis;
import org.moxieapps.gwt.highcharts.client.Chart;
import org.moxieapps.gwt.highcharts.client.ChartSubtitle;
import org.moxieapps.gwt.highcharts.client.ChartTitle;
import org.moxieapps.gwt.highcharts.client.Color;
import org.moxieapps.gwt.highcharts.client.Extremes;
import org.moxieapps.gwt.highcharts.client.Legend;
import org.moxieapps.gwt.highcharts.client.PlotLine;
@@ -44,8 +45,8 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeListener;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.client.WindSourceTypeFormatter;
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
import com.sap.sailing.gwt.ui.client.WindSourceTypeFormatter;
import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
@@ -53,9 +54,12 @@ import com.sap.sailing.gwt.ui.shared.components.Component;
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
public class WindChart extends SimplePanel implements Component<WindChartSettings>, RaceSelectionChangeListener, TimeListener, RequiresResize {
public static final long DEFAULT_RESOLUTION_IN_MILLISECONDS = 5000;
private static final int LINE_WIDTH = 1;
private final StringMessages stringMessages;
private final Set<WindSourceType> windSourceTypesToDisplay;
private long resolutionInMilliseconds;
/**
* Holds one series for each wind source for which data has been received.
@@ -132,6 +136,8 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
}
}));
chart.setBackgroundColor(new Color("#ebebec"));
if (allowTimeAdjust) {
chart.setClickEventHandler(new ChartClickEventHandler() {
@Override
@@ -345,7 +351,7 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
@Override
public SettingsDialogComponent<WindChartSettings> getSettingsDialogComponent() {
return new WindChartSettingsDialogComponent(new WindChartSettings(windSourceTypesToDisplay), stringMessages);
return new WindChartSettingsDialogComponent(new WindChartSettings(windSourceTypesToDisplay, resolutionInMilliseconds), stringMessages);
}
/**
@@ -354,6 +360,10 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
*/
@Override
public void updateSettings(WindChartSettings newSettings) {
if (newSettings.getResolutionInMilliseconds() != resolutionInMilliseconds) {
resolutionInMilliseconds = newSettings.getResolutionInMilliseconds();
clearCacheAndReload();
}
windSourceTypesToDisplay.clear();
windSourceTypesToDisplay.addAll(newSettings.getWindSourceTypesToDisplay());
chart.removeAllSeries(/* redraw */ false);
@@ -368,6 +378,13 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
chart.redraw();
}
private void clearCacheAndReload() {
timeOfEarliestRequestInMillis = null;
timeOfLatestRequestInMillis = null;
loadData(selectedRaceIdentifier, /* from */null, /* to */
new Date(System.currentTimeMillis() - timer.getLivePlayDelayInMillis()), /* append */false);
}
/**
* Creates the series for the <code>windSource</code> specified. If the series is created and needs to be visible
* based on the {@link #windSourceTypesToDisplay}, it is added to the chart.
@@ -390,28 +407,33 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
* of overwriting the existing series.
*/
private void loadData(final RaceIdentifier raceIdentifier, final Date from, final Date to, final boolean append) {
sailingService.getWindInfo(raceIdentifier,
// TODO Time interval should be determined by a selection in the chart but be at most 60s. See bug #121. Consider incremental updates for new data only.
from, to, // use race start and time of newest event as default time period
null, // retrieve data on all wind sources
new AsyncCallback<WindInfoForRaceDTO>() {
@Override
public void onSuccess(WindInfoForRaceDTO result) {
if (result != null) {
updateStripChartSeries(result, append);
} else {
if (!append) {
clearChart(); // no wind known for untracked race
if (raceIdentifier == null) {
clearChart();
} else {
sailingService.getWindInfo(raceIdentifier,
// TODO Time interval should be determined by a selection in the chart but be at most 60s. See bug #121.
// Consider incremental updates for new data only.
from, to, resolutionInMilliseconds, // use race start and time of newest event as default time period
null, // retrieve data on all wind sources
new AsyncCallback<WindInfoForRaceDTO>() {
@Override
public void onSuccess(WindInfoForRaceDTO result) {
if (result != null) {
updateStripChartSeries(result, append);
} else {
if (!append) {
clearChart(); // no wind known for untracked race
}
}
}
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(stringMessages.errorFetchingWindInformationForRace()+" " + raceIdentifier + ": "
+ caught.getMessage());
}
});
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(stringMessages.errorFetchingWindInformationForRace() + " "
+ raceIdentifier + ": " + caught.getMessage());
}
});
}
}
private void clearChart() {
@@ -423,10 +445,7 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
if (selectedRaces != null && !selectedRaces.isEmpty()) {
// show wind of first selected race
selectedRaceIdentifier = selectedRaces.iterator().next();
timeOfEarliestRequestInMillis = null;
timeOfLatestRequestInMillis = null;
loadData(selectedRaceIdentifier, /* from */null, /* to */
new Date(System.currentTimeMillis() - timer.getLivePlayDelayInMillis()), /* append */false);
clearCacheAndReload();
} else {
clearChart();
}
@@ -473,12 +492,16 @@ public class WindChart extends SimplePanel implements Component<WindChartSetting
private void updateTimeLine(Date date) {
if (allowTimeAdjust) {
Long x = date.getTime();
Extremes extremes = chart.getYAxis(0).getExtremes();
Point[] points = new Point[2];
points[0] = new Point(x, extremes.getDataMin());
points[1] = new Point(x, extremes.getDataMax());
timeLineSeries.setPoints(points);
ensureTimeLineIsVisible();
try {
Extremes extremes = chart.getYAxis(0).getExtremes();
Point[] points = new Point[2];
points[0] = new Point(x, extremes.getDataMin());
points[1] = new Point(x, extremes.getDataMax());
timeLineSeries.setPoints(points);
ensureTimeLineIsVisible();
} catch (NullPointerException e) {
// explicitly do nothing; it means that getExtremes() has thrown an exception, so we don't know how to set them
}
}
}
@@ -9,16 +9,32 @@ import com.sap.sailing.domain.common.WindSourceType;
public class WindChartSettings {
private final Set<WindSourceType> windSourceTypesToDisplay;
private final long resolutionInMilliseconds;
public WindChartSettings(Set<WindSourceType> windSourceTypesToDisplay) {
public WindChartSettings(Set<WindSourceType> windSourceTypesToDisplay, long resolutionInMilliseconds) {
this.windSourceTypesToDisplay = windSourceTypesToDisplay;
this.resolutionInMilliseconds = resolutionInMilliseconds;
}
/**
* Uses {@link WindChart#DEFAULT_RESOLUTION_IN_MILLISECONDS} as resolution
*/
public WindChartSettings(WindSourceType... windSourceTypesToDisplay) {
this(new HashSet<WindSourceType>(windSourceTypesToDisplay==null?new ArrayList<WindSourceType>():Arrays.asList(windSourceTypesToDisplay)));
this(WindChart.DEFAULT_RESOLUTION_IN_MILLISECONDS, windSourceTypesToDisplay);
}
public WindChartSettings(long resolutionInMilliseconds, WindSourceType... windSourceTypesToDisplay) {
this(new HashSet<WindSourceType>(windSourceTypesToDisplay == null ? new ArrayList<WindSourceType>()
: Arrays.asList(windSourceTypesToDisplay)), resolutionInMilliseconds);
}
public Set<WindSourceType> getWindSourceTypesToDisplay() {
return windSourceTypesToDisplay;
}
public long getResolutionInMilliseconds() {
return resolutionInMilliseconds;
}
}
@@ -7,17 +7,21 @@ import java.util.Set;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.IntegerBox;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.gwt.ui.client.DataEntryDialog;
import com.sap.sailing.gwt.ui.client.DataEntryDialog.Validator;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.WindSourceTypeFormatter;
import com.sap.sailing.gwt.ui.client.DataEntryDialog.Validator;
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
public class WindChartSettingsDialogComponent implements SettingsDialogComponent<WindChartSettings> {
private final WindChartSettings initialSettings;
private IntegerBox resolutionInSecondsBox;
private final Map<WindSourceType, CheckBox> checkboxes;
private final StringMessages stringMessages;
@@ -31,6 +35,11 @@ public class WindChartSettingsDialogComponent implements SettingsDialogComponent
@Override
public Widget getAdditionalWidget(DataEntryDialog<?> dialog) {
VerticalPanel vp = new VerticalPanel();
resolutionInSecondsBox = dialog.createIntegerBox((int) (initialSettings.getResolutionInMilliseconds()/1000), /* visibleLength */ 5);
HorizontalPanel hp = new HorizontalPanel();
hp.add(new Label(stringMessages.stepSizeInSeconds()));
hp.add(resolutionInSecondsBox);
vp.add(hp);
for (WindSourceType windSourceType : WindSourceType.values()) {
CheckBox checkbox = dialog.createCheckbox(WindSourceTypeFormatter.format(windSourceType, stringMessages));
checkboxes.put(windSourceType, checkbox);
@@ -48,18 +57,26 @@ public class WindChartSettingsDialogComponent implements SettingsDialogComponent
windSourceTypesToDisplay.add(e.getKey());
}
}
return new WindChartSettings(windSourceTypesToDisplay);
return new WindChartSettings(windSourceTypesToDisplay, resolutionInSecondsBox.getValue() == null ? -1 : resolutionInSecondsBox.getValue()*1000);
}
@Override
public Validator<WindChartSettings> getValidator() {
// with checkboxes only, nothing can go wrong :-)
return null;
return new Validator<WindChartSettings>() {
@Override
public String getErrorMessage(WindChartSettings valueToValidate) {
String errorMessage = null;
if (valueToValidate.getResolutionInMilliseconds() < 1) {
errorMessage = stringMessages.stepSizeMustBeGreaterThanNull();
}
return errorMessage;
}
};
}
@Override
public FocusWidget getFocusWidget() {
return checkboxes.values().iterator().next();
return resolutionInSecondsBox;
}
}
@@ -179,8 +179,8 @@ public class WindPanel extends FormPanel implements EventDisplayer, WindShower,
});
windSourceSelectionPanel.add(showConfigAnchor);
grid.setWidget(1, 0, windSourceSelectionPanel);
windChart = new WindChart(sailingService, /* race selection provider */ raceSelectionProvider,
new Timer(PlayModes.Replay), new WindChartSettings(WindSourceType.values()), stringMessages, errorReporter, false, false);
windChart = new WindChart(sailingService, /* race selection provider */raceSelectionProvider, new Timer(
PlayModes.Replay), new WindChartSettings(WindSourceType.values()), stringMessages, errorReporter, false, false);
grid.setWidget(2, 0, windChart.getEntryWidget());
grid.getCellFormatter().setVerticalAlignment(1, 1, HasVerticalAlignment.ALIGN_TOP);
this.setWidget(grid);
@@ -58,6 +58,12 @@ public interface SailingService extends RemoteService {
void setWind(RaceIdentifier raceIdentifier, WindDTO wind);
WindInfoForRaceDTO getWindInfo(RaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth,
int numberOfFixes, Collection<String> windSourceTypeNames) throws NoWindException;
WindInfoForRaceDTO getWindInfo(RaceIdentifier raceIdentifier, Date from, Date to, long resolutionInMilliseconds,
Collection<String> windSourceTypeNames);
Map<CompetitorDTO, List<GPSFixDTO>> getBoatPositions(RaceIdentifier raceIdentifier, Map<CompetitorDTO, Date> from,
Map<CompetitorDTO, Date> to, boolean extrapolate) throws NoWindException;
@@ -164,7 +170,4 @@ public interface SailingService extends RemoteService {
throws NoWindException;
void setRaceIsKnownToStartUpwind(RaceIdentifier raceIdentifier, boolean raceIsKnownToStartUpwind);
WindInfoForRaceDTO getWindInfo(RaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth,
int numberOfFixes, Collection<String> windSourceTypeNames) throws NoWindException;
}
@@ -69,12 +69,16 @@ public interface SailingServiceAsync {
*/
void removeAndUntrackRace(EventAndRaceIdentifier eventAndRaceidentifier, AsyncCallback<Void> callback);
/**
* @param windSources if <code>null</code>, information about all available wind sources will be provided
*/
void getWindInfo(RaceIdentifier raceIdentifier, Date from, Date to, WindSource[] windSources,
AsyncCallback<WindInfoForRaceDTO> callback);
/**
* @param from if <code>null</code>, the tracked race's start of tracking is used
* @param to if <code>null</code>, the tracked race's time point of newest event is used
*/
void getWindInfo(RaceIdentifier raceIdentifier, Date from, Date to, long resolutionInMilliseconds,
Collection<String> windSourceTypeNames, AsyncCallback<WindInfoForRaceDTO> callback);
/**
* @param windSourceTypeNames
* if <code>null</code>, data from all available wind sources will be returned, otherwise only from those
@@ -84,6 +88,22 @@ public interface SailingServiceAsync {
double latDeg, double lngDeg, Collection<String> windSourceTypeNames,
AsyncCallback<WindInfoForRaceDTO> callback);
/**
* Same as {@link #getWindInfo(RaceIdentifier, Date, long, int, double, double, Collection, AsyncCallback)}, only
* that the wind is not requested for a specific position, but instead the wind sources associated with the tracked
* race identified by <code>raceIdentifier</code> are requested to deliver their original position. This will in
* particular preserve the positions of actual measurements and will deliver the averaged positions for averaged /
* combined wind read-outs.
*
* @param from
* must not be <code>null</code>
* @param numberOfFixes
* no matter how great this value is chosen, never returns data beyond the newest event recorded in the
* race
*/
void getWindInfo(RaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth, int numberOfFixes,
Collection<String> windSourceTypeNames, AsyncCallback<WindInfoForRaceDTO> callback);
void setWind(RaceIdentifier raceIdentifier, WindDTO wind, AsyncCallback<Void> callback);
void removeWind(RaceIdentifier raceIdentifier, WindDTO windDTO, AsyncCallback<Void> callback);
@@ -286,12 +306,4 @@ public interface SailingServiceAsync {
void setRaceIsKnownToStartUpwind(RaceIdentifier raceIdentifier, boolean raceIsKnownToStartUpwind,
AsyncCallback<Void> callback);
/**
* Same as {@link #getWindInfo(RaceIdentifier, Date, long, int, double, double, Collection, AsyncCallback)}, only that the
* wind is not requested for a specific position, but instead the wind sources associated with the tracked race identified
* by <code>raceIdentifier</code> are requested to deliver their original position. This will in particular preserve the
* positions of actual measurements and will deliver the averaged positions for averaged / combined wind read-outs.
*/
void getWindInfo(RaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth, int numberOfFixes,
Collection<String> windSourceTypeNames, AsyncCallback<WindInfoForRaceDTO> callback);
}
@@ -272,4 +272,5 @@ public interface StringMessages extends Messages {
String expeditionWindSourceTypeName();
String webWindSourceTypeName();
String clickChartToSetTime();
String position();
}
@@ -266,4 +266,5 @@ courseBasedWindSourceTypeName=Course Layout
trackBasedEstimationWindSourceTypeName=Estimation
expeditionWindSourceTypeName=Measured
webWindSourceTypeName=Manual
clickChartToSetTime=Click on the chart to set the time
clickChartToSetTime=Click on the chart to set the time
position=Position
@@ -267,4 +267,5 @@ courseBasedWindSourceTypeName=Kurslayout
trackBasedEstimationWindSourceTypeName=Schätzung
expeditionWindSourceTypeName=Messung
webWindSourceTypeName=Manuell
clickChartToSetTime=Klicke auf das Diagramm um die Zeit zu setzen
clickChartToSetTime=Klicke auf das Diagramm um die Zeit zu setzen
position=Position
@@ -599,6 +599,33 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
return windDTO;
}
/**
* Uses <code>wind</code> for both, the non-dampened and dampened fields of the {@link WindDTO} object returned
*/
protected WindDTO createWindDTOFromAlreadyAveraged(Wind wind, WindTrack windTrack) {
WindDTO windDTO = new WindDTO();
windDTO.trueWindBearingDeg = wind.getBearing().getDegrees();
windDTO.trueWindFromDeg = wind.getBearing().reverse().getDegrees();
windDTO.trueWindSpeedInKnots = wind.getKnots();
windDTO.trueWindSpeedInMetersPerSecond = wind.getMetersPerSecond();
windDTO.dampenedTrueWindBearingDeg = wind.getBearing().getDegrees();
windDTO.dampenedTrueWindFromDeg = wind.getBearing().reverse().getDegrees();
windDTO.dampenedTrueWindSpeedInKnots = wind.getKnots();
windDTO.dampenedTrueWindSpeedInMetersPerSecond = wind.getMetersPerSecond();
if (wind.getPosition() != null) {
windDTO.position = new PositionDTO(wind.getPosition().getLatDeg(), wind.getPosition()
.getLngDeg());
}
if (wind.getTimePoint() != null) {
windDTO.timepoint = wind.getTimePoint().asMillis();
}
return windDTO;
}
/**
* Fetches the {@link WindTrack#getAveragedWind(Position, TimePoint) average wind} from all wind tracks or those identified
* by <code>windSourceTypeNames</code>
*/
@Override
public WindInfoForRaceDTO getWindInfo(RaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth,
int numberOfFixes, double latDeg, double lngDeg, Collection<String> windSourceTypeNames)
@@ -628,7 +655,7 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
for (int i = 0; i < numberOfFixes; i++) {
Wind wind = windTrack.getAveragedWind(position, timePoint);
if (wind != null) {
WindDTO windDTO = createWindDTO(wind, windTrack);
WindDTO windDTO = createWindDTOFromAlreadyAveraged(wind, windTrack);
windTrackInfoDTO.windFixes.add(windDTO);
}
timePoint = new MillisecondsTimePoint(timePoint.asMillis() + millisecondsStepWidth);
@@ -643,31 +670,39 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
public WindInfoForRaceDTO getWindInfo(RaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth,
int numberOfFixes, Collection<String> windSourceTypeNames)
throws NoWindException {
WindInfoForRaceDTO result = null;
assert from != null;
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
WindInfoForRaceDTO result = getWindInfo(new MillisecondsTimePoint(from), millisecondsStepWidth, numberOfFixes,
windSourceTypeNames, trackedRace);
return result;
}
private WindInfoForRaceDTO getWindInfo(TimePoint from, long millisecondsStepWidth, int numberOfFixes,
Collection<String> windSourceTypeNames, TrackedRace trackedRace) {
WindInfoForRaceDTO result = null;
if (trackedRace != null) {
TimePoint newestEvent = trackedRace.getTimePointOfNewestEvent();
result = new WindInfoForRaceDTO();
result.raceIsKnownToStartUpwind = trackedRace.raceIsKnownToStartUpwind();
Map<WindSource, WindTrackInfoDTO> windTrackInfoDTOs = new HashMap<WindSource, WindTrackInfoDTO>();
result.windTrackInfoByWindSource = windTrackInfoDTOs;
List<WindSource> windSourcesToDeliver = new ArrayList<WindSource>();
Util.addAll(trackedRace.getWindSources(), windSourcesToDeliver);
// TODO bug #375: add the combined wind; currently, CombinedWindTrackImpl just takes too long to return results...
windSourcesToDeliver.add(new WindSourceImpl(WindSourceType.COMBINED));
for (WindSource windSource : windSourcesToDeliver) {
// TODO consider parallelizing
if (windSourceTypeNames == null || windSourceTypeNames.contains(windSource.getType().name())) {
TimePoint fromTimePoint = new MillisecondsTimePoint(from);
WindTrackInfoDTO windTrackInfoDTO = new WindTrackInfoDTO();
windTrackInfoDTO.windFixes = new ArrayList<WindDTO>();
WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource);
windTrackInfoDTOs.put(windSource, windTrackInfoDTO);
windTrackInfoDTO.dampeningIntervalInMilliseconds = windTrack
.getMillisecondsOverWhichToAverageWind();
TimePoint timePoint = fromTimePoint;
for (int i = 0; i < numberOfFixes; i++) {
TimePoint timePoint = from;
for (int i = 0; i < numberOfFixes && timePoint.compareTo(newestEvent) < 0; i++) {
Wind wind = windTrack.getAveragedWind(null, timePoint);
if (wind != null) {
WindDTO windDTO = createWindDTO(wind, windTrack);
WindDTO windDTO = createWindDTOFromAlreadyAveraged(wind, windTrack);
windTrackInfoDTO.windFixes.add(windDTO);
}
timePoint = new MillisecondsTimePoint(timePoint.asMillis() + millisecondsStepWidth);
@@ -678,6 +713,30 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
return result;
}
@Override
public WindInfoForRaceDTO getWindInfo(RaceIdentifier raceIdentifier, Date from, Date to,
long resolutionInMilliseconds, Collection<String> windSourceTypeNames) {
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
WindInfoForRaceDTO result = null;
if (trackedRace != null) {
TimePoint fromTimePoint;
if (from == null) {
fromTimePoint = trackedRace.getStartOfTracking();
} else {
fromTimePoint = new MillisecondsTimePoint(from);
}
TimePoint toTimePoint;
if (to == null || to.getTime() > trackedRace.getTimePointOfNewestEvent().asMillis()) {
toTimePoint = trackedRace.getTimePointOfNewestEvent();
} else {
toTimePoint = new MillisecondsTimePoint(to);
}
int numberOfFixes = (int) ((toTimePoint.asMillis() - fromTimePoint.asMillis())/resolutionInMilliseconds);
result = getWindInfo(fromTimePoint, resolutionInMilliseconds, numberOfFixes, windSourceTypeNames, trackedRace);
}
return result;
}
@Override
public void setWind(RaceIdentifier raceIdentifier, WindDTO windDTO) {
DynamicTrackedRace trackedRace = (DynamicTrackedRace) getExistingTrackedRace(raceIdentifier);
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 B