Merge remote-tracking branch 'origin/master' into bug2610

This commit is contained in:
fmittag committed 2015-12-14 15:31:14 +01:00
commit cbdb743001
8 files changed
+186 -32

No files matched your search

File mode changed.
@@ -0,0 +1,103 @@
package com.sap.sailing.gwt.ui.client.shared.racemap;
import com.google.gwt.maps.client.base.LatLng;
import com.google.gwt.maps.client.mvc.MVCArray;
import com.google.gwt.maps.client.overlays.Polyline;
import com.google.gwt.user.client.Timer;
/**
* Moves a {@link Polyline} from its current position to a target position in a given duration with a fixed
* {@link #ANIMATION_PERIOD_MILLIS animation interval}. Since the timer may be triggered at non-exact intervals, the
* offset per animation tick is calculated based on the current time for each iteration.
* <p>
*
* If an animation is still going on, it is permissible for clients to invoke
* {@link #setNextPositionAndTransitionMillis(MVCArray, long)} which will have the effect that from its current position
* reached so far the {@link Polyline} will then be animated to the next target position in the specified time interval.
*
* @author Jonas Dann
*
*/
public class AdvantageLineAnimator extends Timer {
/**
* Time between two animation steps
*/
private static final int ANIMATION_PERIOD_MILLIS = 100;
/**
* The polyline to animate by updating its {@link Polyline#getPath() path}
*/
private final Polyline advantageLine;
/**
* The last time the coordinates in the {@link #advantageLine}'s path were updated
*/
private long lastTime;
/**
* The remaining time for the animation to move the {@link #advantageLine} to its {@link #nextPosition target
* position}. If <code>-1</code>, the {@link #advantageLine} will be moved to its {@link #nextPosition next target
* position} in one step.
*/
private long durationMillis = -1;
/**
* The "to-be" / target position to which to move the {@link #advantageLine}'s path gradually during the remaining
* {@link #durationMillis}.
*/
private MVCArray<LatLng> nextPosition;
public AdvantageLineAnimator(Polyline advantageLine) {
if (advantageLine == null) {
throw new NullPointerException("Advantage line must not be null");
}
this.advantageLine = advantageLine;
}
/**
* @param timeForPositionTransitionMillis if <code>-1</code> then no animation is requested and the {@link #advantageLine} will
* be moved to its {@link #nextPosition next target position} in one step.
*
* @param nextPosition the next target position for the {@link #advantageLine}; if <code>null</code>, no animation will happen at all
*/
public void setNextPositionAndTransitionMillis(MVCArray<LatLng> nextPosition, long timeForPositionTransitionMillis) {
if (nextPosition.getLength() != advantageLine.getPath().getLength()) {
throw new IllegalArgumentException("The next animation position for a polyline with "+advantageLine.getPath().getLength()+
" elements must have the same number of positions but did have "+nextPosition.getLength());
}
this.nextPosition = nextPosition;
this.lastTime = System.currentTimeMillis();
this.durationMillis = timeForPositionTransitionMillis;
this.scheduleRepeating(ANIMATION_PERIOD_MILLIS);
}
@Override
public void run() {
final long time = System.currentTimeMillis();
final double moveFactor; // how much of the delta to the nextPosition shall this tick move the advantage line?
if (durationMillis > 0) {
long deltaTime = time - lastTime;
moveFactor = Math.min(1.0, (double) deltaTime / (double) durationMillis); // don't overshoot
durationMillis -= deltaTime;
} else {
moveFactor = 1;
}
if (nextPosition != null) {
final MVCArray<LatLng> currentPosition = this.advantageLine.getPath();
for (int i = 0; i < nextPosition.getLength(); i++) {
final LatLng currentLatLng = currentPosition.get(i);
final LatLng nextLatLng = nextPosition.get(i);
currentPosition.setAt(i, LatLng.newInstance(currentLatLng.getLatitude() + (nextLatLng.getLatitude() - currentLatLng.getLatitude()) * moveFactor,
currentLatLng.getLongitude() + (nextLatLng.getLongitude() - currentLatLng.getLongitude()) * moveFactor));
}
}
if (durationMillis <= 0) {
cancel();
}
lastTime = time;
}
public void removeAnimation() {
this.durationMillis = -1;
}
}
@@ -178,6 +178,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
*/
private Polyline advantageLine;
private AdvantageLineAnimator advantageTimer;
/**
* The windward of two Polylines representing a triangle between startline and first mark.
*/
@@ -711,6 +713,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
for (CompetitorInfoOverlay infoOverlay : competitorInfoOverlays.values()) {
infoOverlay.removeCanvasPositionAndRotationTransition();
}
// remove the advantage line animation
if (advantageTimer != null) {
advantageTimer.removeAnimation();
}
}
public void redraw() {
@@ -767,6 +773,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
final Iterable<CompetitorDTO> competitorsToShow = getCompetitorsToShow();
if (race != null) {
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;
@@ -776,7 +783,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
GetRaceMapDataAction getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping = getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping(fromAndToAndOverlap, race, newTime);
if (getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping != null) {
asyncActionsExecutor.execute(getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping, GET_RACE_MAP_DATA_CATEGORY,
getRaceMapDataCallback(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID));
getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, requestID));
requestID = ++boatPositionRequestIDCounter;
}
// next, do the full thing; being the later call, if request throttling kicks in, the later call
@@ -784,7 +791,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
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(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID));
getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, requestID));
// draw the wind into the map, get the combined wind
List<String> windSourceTypeNames = new ArrayList<String>();
@@ -803,7 +810,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
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;
showAdvantageLine(competitorsToShow, newTime);
showAdvantageLine(competitorsToShow, newTime, transitionTimeInMillis);
for (WindSource windSource : windInfo.windTrackInfoByWindSource.keySet()) {
WindTrackInfoDTO windTrackInfoDTO = windInfo.windTrackInfoByWindSource.get(windSource);
switch (windSource.getType()) {
@@ -870,8 +877,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
private AsyncCallback<RaceMapDataDTO> getRaceMapDataCallback(
final Date oldTime,
final Date newTime,
final long transitionTimeInMillis,
final Map<CompetitorDTO, Boolean> hasTailOverlapForCompetitor,
final Iterable<CompetitorDTO> competitorsToShow, final int requestID) {
return new AsyncCallback<RaceMapDataDTO>() {
@@ -895,10 +902,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
startedProcessingRequestID = requestID;
// Do boat specific actions
Map<CompetitorDTO, List<GPSFixDTO>> boatData = raceMapDataDTO.boatPositions;
long timeForPositionTransitionMillis = calculateTimeForPositionTransition(newTime, oldTime);
fixesAndTails.updateFixes(boatData, hasTailOverlapForCompetitor, RaceMap.this, timeForPositionTransitionMillis);
showBoatsOnMap(newTime, timeForPositionTransitionMillis, getCompetitorsToShow());
showCompetitorInfoOnMap(newTime, timeForPositionTransitionMillis, competitorSelection.getSelectedFilteredCompetitors());
fixesAndTails.updateFixes(boatData, hasTailOverlapForCompetitor, RaceMap.this, transitionTimeInMillis);
showBoatsOnMap(newTime, transitionTimeInMillis, getCompetitorsToShow());
showCompetitorInfoOnMap(newTime, transitionTimeInMillis, competitorSelection.getSelectedFilteredCompetitors());
if (douglasMarkers != null) {
removeAllMarkDouglasPeuckerpoints();
}
@@ -916,7 +922,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
showStartLineToFirstMarkTriangle(raceMapDataDTO.coursePositions);
// 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);
showAdvantageLine(competitorsToShow, newTime, transitionTimeInMillis);
// Rezoom the map
LatLngBounds zoomToBounds = null;
@@ -1135,7 +1141,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
}
private long calculateTimeForPositionTransition(final Date newTime, final Date oldTime) {
private long calculateTimeForPositionTransitionInMillis(final Date newTime, final Date oldTime) {
final long timeForPositionTransitionMillis;
boolean hasTimeJumped = oldTime != null && Math.abs(oldTime.getTime() - newTime.getTime()) > 3*timer.getRefreshInterval();
if (timer.getPlayState() == PlayStates.Playing && !hasTimeJumped) {
@@ -1222,7 +1228,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
return null;
}
private void showAdvantageLine(Iterable<CompetitorDTO> competitorsToShow, Date date) {
private void showAdvantageLine(Iterable<CompetitorDTO> competitorsToShow, Date date, long timeForPositionTransitionMillis) {
if (map != null && lastRaceTimesInfo != null && quickRanks != null && lastCombinedWindTrackInfoDTO != null) {
boolean drawAdvantageLine = false;
if (settings.getHelpLinesSettings().isVisible(HelpLineTypes.ADVANTAGELINE)) {
@@ -1288,6 +1294,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
break;
}
MVCArray<LatLng> nextPath = MVCArray.newInstance();
LatLng advantageLinePos1 = calculatePositionAlongRhumbline(posAheadOfFirstBoat,
coordinateSystem.mapDegreeBearing(rotatedBearingDeg1), advantageLineLengthInKm / 2.0);
LatLng advantageLinePos2 = calculatePositionAlongRhumbline(posAheadOfFirstBoat,
@@ -1301,6 +1308,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
options.setStrokeOpacity(0.5);
advantageLine = Polyline.newInstance(options);
advantageTimer = new AdvantageLineAnimator(advantageLine);
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance();
pointsAsArray.insertAt(0, advantageLinePos1);
pointsAsArray.insertAt(1, advantageLinePos2);
@@ -1318,10 +1326,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
});
} else {
advantageLine.getPath().removeAt(1);
advantageLine.getPath().removeAt(0);
advantageLine.getPath().insertAt(0, advantageLinePos1);
advantageLine.getPath().insertAt(1, advantageLinePos2);
nextPath.push(advantageLinePos1);
nextPath.push(advantageLinePos2);
advantageTimer.setNextPositionAndTransitionMillis(nextPath, timeForPositionTransitionMillis);
advantageLineMouseOverHandler.setTrueWindBearing(bearingOfCombinedWindInDeg);
advantageLineMouseOverHandler.setDate(new Date(windFix.measureTimepoint));
}
@@ -1332,6 +1339,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
if (advantageLine != null) {
advantageLine.setMap(null);
advantageLine = null;
advantageTimer = null;
}
}
}
@@ -7,12 +7,14 @@
<h5 class="articleSubheadline">December 2015</h5>
<ul class="bulletList">
<li>The advantage line is now animated and moves smoothly with the boats.
</li>
<li>New line hover behavior in race map. When the mouse is moved onto a line, for example the start line, a transparent,
wider line is activated behind it that acts as a buffer for the thin line, where the text displayed by the hover is still shown.
This makes it easier to hover over the lines. These wider lines can be made semi transparent instead of transparent
by unticking the corresponding checkbox in the settings of the race map. Furthermore the stroke weight of the wider lines can be
configured in the same settings dialog.
</li>
wider line is activated behind it that acts as a buffer for the thin line, where the text displayed by the hover is still shown.
This makes it easier to hover over the lines. These wider lines can be made semi transparent instead of transparent
by unticking the corresponding checkbox in the settings of the race map. Furthermore the stroke weight of the wider lines can be
configured in the same settings dialog.
</li>
<li>The race viewer (RaceBoard.html) now intelligently chooses a layout that suits the screen size.
When only little horizontal space is available, only the sail number and nationality but not the
competitor's long name is displayed by default. When vertical space is scarce, competitor and wind
+12 -12
View File
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry exported="true" kind="lib" path="lib/TracAPI.jar">
<attributes>
<attribute name="javadoc_location" value="file:/data/SAP/sailing/workspace/java/com.tractrac.clientmodule/javadoc"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry exported="true" kind="lib" path="lib/TracAPI.jar" sourcepath="lib/TracAPI-src.jar">
<attributes>
<attribute name="javadoc_location" value="file:/data/SAP/sailing/workspace/java/com.tractrac.clientmodule/javadoc"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="output" path="bin"/>
</classpath>
+41
View File
@@ -15,6 +15,47 @@ It contains also some files:
- test.sh -> script that compiles the code in the src folder, creates the test.jar library and execute the code of the example.
- Manifest.txt -> manifest used to create the test.jar file
********************************************
************* TracAPI 3.1.0 ****************
********************************************
This is a final version. It fixes bugs in the implementation and it adds some new features.
These features add methods to the API breaking the backward compatibility. These changes are:
- The IRaceCompetitorListener interface implements a new method removeOffsetPositions. If
your app implements this interface, you have to implement this extra method.
This version provides a new JavaDoc version.
Release date: 11/12/2015
Build number: 11801
1) Features
- Adding the method IRaceCompetitorListener.removeOffsetPositions that is invoked
to invalidate a set of positions. It is used when the event administrator detects
an error in the snapping algorithm (in route sports) and he want to remove the wrong
positions (Requested by Chris Terkelsen, 26/11/2015)
- Adding the method IControl.getMapName() that contains the name that has to be used to
display the control on the map (Requested by Chris Terkelsen, 09/12/2015)
2) Bugs
- The static controls send a position event using the race start time instead the
event start time. (Reported by Jerome Soussens, 11/12/2015)
********************************************
************* TracAPI 3.0.14 ***************
********************************************
This is a final version. Only fixes bugs in the implementation
Release date: 29/09/2015
Build number: 11514
1) Bugs
- NullPointerException caused by a synchronization error (Reported by Jérome Soussens, 28/09/2015)
********************************************
************* TracAPI 3.0.13 ***************
Binary file not shown.
Binary file not shown.