mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-01 01:44:08 +00:00
Merge remote-tracking branch 'origin/master' into bug2610
This commit is contained in:
commit
cbdb743001
8 files changed
+186
-32
No files matched your search
Executable → Regular
File mode changed.
+103
@@ -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;
|
||||
}
|
||||
}
|
||||
+23
-15
@@ -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
-5
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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 ***************
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user