mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-26 15:36:40 +00:00
Merge remote-tracking branch 'origin/master' into buoyzone_drawing
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 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
This commit is contained in:
@@ -90,6 +90,10 @@ MAVEN_SETTINGS=$ACDIR/maven-settings.xml
|
||||
|
||||
if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
|
||||
# yield build so that we get updated product
|
||||
|
||||
# preserve old build log
|
||||
cp $ACDIR/build.log $ACDIR/build.log.old
|
||||
|
||||
cd $PROJECT_HOME/java
|
||||
if [ $gwtcompile -eq 1 ]; then
|
||||
echo "INFO: Compiling GWT (rm -rf com.sap.sailing.gwt.ui/com.sap.sailing.*)"
|
||||
@@ -116,7 +120,7 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
|
||||
extra="$extra -P no-debug.without-proxy"
|
||||
fi
|
||||
|
||||
echo "Using following command: mvn $extra -P no-debug.without-proxy -fae -s $MAVEN_SETTINGS $clean install"
|
||||
echo "Using following command: mvn $extra -fae -s $MAVEN_SETTINGS $clean install"
|
||||
mvn $extra -fae -s $MAVEN_SETTINGS $clean install 2>&1 | tee $ACDIR/build.log
|
||||
|
||||
echo "Build complete. Do not forget to install product..."
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface PolarSheetGenerationTriggerResponse extends Serializable{
|
||||
|
||||
public String getId();
|
||||
|
||||
public String getBoatClassName();
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface PolarSheetsData extends Serializable {
|
||||
|
||||
Number[][] getAveragedPolarDataByWindSpeed();
|
||||
|
||||
int getDataCount();
|
||||
|
||||
boolean isComplete();
|
||||
|
||||
Integer[] getDataCountPerAngleForWindspeed(int beaufort);
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface PolarSheetsHistogramData extends Serializable{
|
||||
|
||||
public int getAngle();
|
||||
|
||||
public int getDataCount();
|
||||
|
||||
public Number[] getyValues();
|
||||
|
||||
public Number[] getxValues();
|
||||
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
|
||||
|
||||
public class PolarSheetGenerationTriggerResponseImpl implements PolarSheetGenerationTriggerResponse {
|
||||
|
||||
private static final long serialVersionUID = -2160795576114448218L;
|
||||
private String id;
|
||||
private String boatClassName;
|
||||
|
||||
// For GWT serialization
|
||||
PolarSheetGenerationTriggerResponseImpl() {
|
||||
};
|
||||
|
||||
public PolarSheetGenerationTriggerResponseImpl(String id, String boatClassName) {
|
||||
this.id = id;
|
||||
this.boatClassName = boatClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBoatClassName() {
|
||||
return boatClassName;
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
|
||||
public class PolarSheetsDataImpl implements PolarSheetsData {
|
||||
|
||||
private static final long serialVersionUID = -4649254807341866894L;
|
||||
|
||||
private Number[][] averagedPolarDataByWindSpeed;
|
||||
|
||||
private boolean complete;
|
||||
|
||||
private int dataCount;
|
||||
|
||||
private Map<Integer,Integer[]> dataCountPerAngleForWindspeed;
|
||||
|
||||
//For GWT Serialization
|
||||
PolarSheetsDataImpl() {};
|
||||
|
||||
public PolarSheetsDataImpl(Number[][] averagedPolarDataByWindSpeed, boolean complete, int dataCount, Map<Integer,Integer[]> dataCountPerAngleForWindspeed) {
|
||||
this.averagedPolarDataByWindSpeed = averagedPolarDataByWindSpeed;
|
||||
this.complete = complete;
|
||||
this.dataCount = dataCount;
|
||||
this.dataCountPerAngleForWindspeed = dataCountPerAngleForWindspeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number[][] getAveragedPolarDataByWindSpeed() {
|
||||
return averagedPolarDataByWindSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataCount() {
|
||||
return dataCount;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer[] getDataCountPerAngleForWindspeed(int beaufort) {
|
||||
return dataCountPerAngleForWindspeed.get(beaufort);
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
|
||||
public class PolarSheetsHistogramDataImpl implements PolarSheetsHistogramData {
|
||||
|
||||
private static final long serialVersionUID = 7492650285773447757L;
|
||||
|
||||
private Number[] yValues;
|
||||
|
||||
private Number[] xValues;
|
||||
|
||||
private int angle;
|
||||
|
||||
private int dataCount;
|
||||
|
||||
//For GWT serialization
|
||||
PolarSheetsHistogramDataImpl() {}
|
||||
|
||||
public PolarSheetsHistogramDataImpl(int angle, Number[] xValues, Number[] yValues, int dataCount) {
|
||||
super();
|
||||
this.angle = angle;
|
||||
this.yValues = yValues;
|
||||
this.xValues = xValues;
|
||||
this.dataCount = dataCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number[] getyValues() {
|
||||
return yValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number[] getxValues() {
|
||||
return xValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAngle() {
|
||||
return angle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataCount() {
|
||||
return dataCount;
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -84,4 +84,6 @@ public interface MongoObjectFactory {
|
||||
|
||||
void storeRegattaForRaceID(String id, Regatta regatta);
|
||||
|
||||
void removeRegattaForRaceID(String raceIDAsString, Regatta regatta);
|
||||
|
||||
}
|
||||
|
||||
+7
@@ -467,4 +467,11 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
entry.put(FieldNames.REGATTA_NAME.name(), regatta.getName());
|
||||
regattaForRaceIDCollection.update(query, entry, /* upsrt */ true, /* multi */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRegattaForRaceID(String raceIDAsString, Regatta regatta) {
|
||||
DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name());
|
||||
DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString);
|
||||
regattaForRaceIDCollection.remove(query);
|
||||
}
|
||||
}
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.BoatClassImpl;
|
||||
import com.sap.sailing.domain.base.impl.BoatImpl;
|
||||
import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
||||
import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.TeamImpl;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.polarsheets.PerRaceAndCompetitorPolarSheetGenerationWorker;
|
||||
import com.sap.sailing.domain.polarsheets.PolarSheetGenerationWorker;
|
||||
import com.sap.sailing.domain.test.mock.MockedTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
|
||||
public class PolarSheetGenerationTest {
|
||||
|
||||
@Test
|
||||
public void testPolarSheetRawDataGeneration() throws InterruptedException {
|
||||
Executor executor = new ThreadPoolExecutor(/* corePoolSize */ 0,
|
||||
/* maximumPoolSize */ Runtime.getRuntime().availableProcessors(),
|
||||
/* keepAliveTime */ 60, TimeUnit.SECONDS,
|
||||
/* workQueue */ new LinkedBlockingQueue<Runnable>());
|
||||
|
||||
MockTrackedRaceForPolarSheetGeneration race = new MockTrackedRaceForPolarSheetGeneration();
|
||||
|
||||
TimePoint startTime = new MillisecondsTimePoint(1);
|
||||
TimePoint endTime = new MillisecondsTimePoint(4);
|
||||
//Only used for storing and exporting results in this test case:
|
||||
PolarSheetGenerationWorker resultContainer = new PolarSheetGenerationWorker(new HashSet<TrackedRace>(), executor);
|
||||
BoatClass forelle = new BoatClassImpl("Forelle", true);
|
||||
Competitor competitor = new CompetitorImpl(UUID.randomUUID(), "Hans Frantz", new TeamImpl("SAP", null, null), new BoatImpl("Schnelle Forelle", forelle, "GER000"));
|
||||
PerRaceAndCompetitorPolarSheetGenerationWorker task = new PerRaceAndCompetitorPolarSheetGenerationWorker(race, resultContainer, startTime, endTime, competitor);
|
||||
|
||||
executor.execute(task);
|
||||
|
||||
double timeUntilTimeout = 1000;
|
||||
while (!task.isDone() && timeUntilTimeout > 0) {
|
||||
Thread.sleep(100);
|
||||
timeUntilTimeout = timeUntilTimeout - 0.1;
|
||||
}
|
||||
|
||||
Assert.assertTrue(task.isDone());
|
||||
|
||||
PolarSheetsData data = resultContainer.getPolarData();
|
||||
Assert.assertEquals(4, data.getDataCount());
|
||||
Assert.assertEquals(4.0, data.getAveragedPolarDataByWindSpeed()[1][45]);
|
||||
Assert.assertEquals(2.0, data.getAveragedPolarDataByWindSpeed()[1][55]);
|
||||
Assert.assertEquals(6.0, data.getAveragedPolarDataByWindSpeed()[1][30]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class MockTrackedRaceForPolarSheetGeneration extends MockedTrackedRace {
|
||||
@Override
|
||||
public DynamicGPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor) {
|
||||
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = new MockDynamicGPSFixMovinTrackForPolarSheetGeneration<Competitor>(competitor, 0);
|
||||
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.0, 1.0), new MillisecondsTimePoint(1), new KnotSpeedWithBearingImpl(3.0, new DegreeBearingImpl(-45.0))));
|
||||
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.001, 1.001), new MillisecondsTimePoint(2), new KnotSpeedWithBearingImpl(5.0, new DegreeBearingImpl(-45.0))));
|
||||
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.002, 1.002), new MillisecondsTimePoint(3), new KnotSpeedWithBearingImpl(2.0, new DegreeBearingImpl(-55.0))));
|
||||
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.003, 1.003), new MillisecondsTimePoint(4), new KnotSpeedWithBearingImpl(6.0, new DegreeBearingImpl(-30.0))));
|
||||
return track;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind getWind(Position p, TimePoint at) {
|
||||
Wind wind = new WindImpl(p, at, new KnotSpeedWithBearingImpl(2.0, new DegreeBearingImpl(180.0)));
|
||||
return wind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition getRace() {
|
||||
BoatClass forelle = new BoatClassImpl("Forelle", true);
|
||||
RaceDefinition race = new RaceDefinitionImpl("Forelle1", new CourseImpl("ForelleCourse", new ArrayList<Waypoint>()), forelle, new ArrayList<Competitor>());
|
||||
return race;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class MockGPSFixMovingForPolarSheetGeneration extends GPSFixMovingImpl {
|
||||
|
||||
public MockGPSFixMovingForPolarSheetGeneration(Position position, TimePoint timePoint, SpeedWithBearing speed) {
|
||||
super(position, timePoint, speed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class MockDynamicGPSFixMovinTrackForPolarSheetGeneration<ItemType> extends DynamicGPSFixMovingTrackImpl<ItemType> {
|
||||
|
||||
public MockDynamicGPSFixMovinTrackForPolarSheetGeneration(ItemType trackedItem,
|
||||
long millisecondsOverWhichToAverage) {
|
||||
super(trackedItem, millisecondsOverWhichToAverage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValid(NavigableSet<GPSFixMoving> rawFixes, GPSFixMoving e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@ Export-Package: com.sap.sailing.domain.base,
|
||||
com.sap.sailing.domain.leaderboard,
|
||||
com.sap.sailing.domain.leaderboard.impl,
|
||||
com.sap.sailing.domain.leaderboard.meta,
|
||||
com.sap.sailing.domain.polarsheets,
|
||||
com.sap.sailing.domain.tracking,
|
||||
com.sap.sailing.domain.tracking.impl,
|
||||
com.sap.sailing.util,
|
||||
|
||||
+3
-9
@@ -29,12 +29,6 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
|
||||
private static final long serialVersionUID = 2370461218294770084L;
|
||||
private final Regatta regatta;
|
||||
|
||||
/**
|
||||
* If this member is <code>null</code>, {@link #getName()} will use the regatta name as the default name for this
|
||||
* leaderboard. Otherwise, the {@link #displayName} is used.
|
||||
*/
|
||||
private String displayName;
|
||||
|
||||
public RegattaLeaderboardImpl(Regatta regatta, SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(scoreCorrection, resultDiscardingRule);
|
||||
@@ -47,7 +41,7 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
|
||||
*/
|
||||
@Override
|
||||
public void setName(String newName) {
|
||||
displayName = newName;
|
||||
setDisplayName(newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,8 +52,8 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
|
||||
@Override
|
||||
public String getName() {
|
||||
String result;
|
||||
if (displayName != null) {
|
||||
result = displayName;
|
||||
if (getDisplayName() != null) {
|
||||
result = getDisplayName();
|
||||
} else {
|
||||
result = getRegatta().getName();
|
||||
}
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
|
||||
public interface BoatAndWindSpeed {
|
||||
|
||||
public Speed getBoatSpeed();
|
||||
|
||||
public Speed getWindSpeed();
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
|
||||
public class BoatAndWindSpeedImpl implements BoatAndWindSpeed{
|
||||
|
||||
private Speed boatSpeed;
|
||||
private Speed windSpeed;
|
||||
|
||||
|
||||
|
||||
public BoatAndWindSpeedImpl(Speed boatSpeed, Speed windSpeed) {
|
||||
this.boatSpeed = boatSpeed;
|
||||
this.windSpeed = windSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getBoatSpeed() {
|
||||
return boatSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getWindSpeed() {
|
||||
return windSpeed;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
|
||||
/**
|
||||
* Iterates through the fixes of one competitor in one tracked race and fills the {@link PolarSheetGenerationWorker}
|
||||
* with datapoints that are found for the speed of the boat and its angle to the wind
|
||||
*
|
||||
* @author D054528 Frederik Petersen
|
||||
*
|
||||
*/
|
||||
public class PerRaceAndCompetitorPolarSheetGenerationWorker implements Runnable{
|
||||
|
||||
private final TrackedRace race;
|
||||
|
||||
private final PolarSheetGenerationWorker polarSheetGenerationWorker;
|
||||
|
||||
private TimePoint startTime;
|
||||
|
||||
private TimePoint endTime;
|
||||
|
||||
private final Competitor competitor;
|
||||
|
||||
private boolean done = false;
|
||||
|
||||
public PerRaceAndCompetitorPolarSheetGenerationWorker(TrackedRace race,
|
||||
PolarSheetGenerationWorker polarSheetGenerationWorker, TimePoint startTime, TimePoint endTime,
|
||||
Competitor competitor) {
|
||||
super();
|
||||
this.race = race;
|
||||
this.polarSheetGenerationWorker = polarSheetGenerationWorker;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.competitor = competitor;
|
||||
optimizeStartTime();
|
||||
optimizeEndTime();
|
||||
}
|
||||
|
||||
private void optimizeEndTime() {
|
||||
NavigableSet<MarkPassing> markPassings = race.getMarkPassings(competitor);
|
||||
if (markPassings == null || markPassings.size() < 1) {
|
||||
return;
|
||||
}
|
||||
MarkPassing passedFinish = markPassings.last();
|
||||
TimePoint passedFinishTimePoint = passedFinish.getTimePoint();
|
||||
if (passedFinishTimePoint.before(endTime)) {
|
||||
endTime = passedFinishTimePoint;
|
||||
}
|
||||
}
|
||||
|
||||
private void optimizeStartTime() {
|
||||
NavigableSet<MarkPassing> markPassings = race.getMarkPassings(competitor);
|
||||
if (markPassings == null || markPassings.size() < 1) {
|
||||
return;
|
||||
}
|
||||
MarkPassing passedStart = markPassings.first();
|
||||
TimePoint passedStartTimePoint = passedStart.getTimePoint();
|
||||
if (passedStartTimePoint.after(startTime)) {
|
||||
startTime = passedStartTimePoint;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = race.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
Iterator<GPSFixMoving> fixesIterator = track.getFixesIterator(startTime, true);
|
||||
|
||||
while (fixesIterator.hasNext()) {
|
||||
GPSFixMoving fix = fixesIterator.next();
|
||||
if (fix.getTimePoint().after(endTime)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (track.hasDirectionChange(fix.getTimePoint(), race.getRace().getBoatClass()
|
||||
.getManeuverDegreeAngleThreshold())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SpeedWithBearing speedWithBearing = fix.getSpeed();
|
||||
Bearing bearing = speedWithBearing.getBearing();
|
||||
Position position = fix.getPosition();
|
||||
Wind wind = race.getWind(position, fix.getTimePoint());
|
||||
Bearing windBearing = wind.getFrom();
|
||||
double angleToWind = bearing.getDifferenceTo(windBearing).getDegrees();
|
||||
|
||||
polarSheetGenerationWorker.addPolarData(Math.round(angleToWind), speedWithBearing, wind);
|
||||
}
|
||||
|
||||
track.unlockAfterRead();
|
||||
done = true;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return done;
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetsDataImpl;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* Allows extracting data about average speed for each angle creating the foundation of polar-sheet generation. Tasks
|
||||
* are assigned to the executor per race & per competitor and the results are filled on the go to allow progress
|
||||
* indication in the polar-sheet itself.
|
||||
*
|
||||
* @author D054528 Frederik Petersen
|
||||
*
|
||||
*/
|
||||
public class PolarSheetGenerationWorker {
|
||||
|
||||
private final Set<PerRaceAndCompetitorPolarSheetGenerationWorker> workers;
|
||||
|
||||
private final List<List<BoatAndWindSpeed>> polarData;
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
/**
|
||||
* Will prepare the {@link PerRaceAndCompetitorPolarSheetGenerationWorker}s per race & per competitor. This includes
|
||||
* determining start and end time.
|
||||
*
|
||||
* @param trackedRaces
|
||||
* from which the data is to be collected
|
||||
* @param executor
|
||||
* executes the tasks upon {@link #startPolarSheetGeneration()}
|
||||
*/
|
||||
public PolarSheetGenerationWorker(Set<TrackedRace> trackedRaces, Executor executor) {
|
||||
polarData = initializePolarDataContainer();
|
||||
this.executor = executor;
|
||||
workers = new HashSet<PerRaceAndCompetitorPolarSheetGenerationWorker>();
|
||||
for (TrackedRace race : trackedRaces) {
|
||||
TimePoint startTime = race.getStartOfRace();
|
||||
TimePoint endTime = race.getEndOfRace();
|
||||
if (endTime == null) {
|
||||
// TODO Figure out if there is an alternative:
|
||||
endTime = race.getTimePointOfNewestEvent();
|
||||
}
|
||||
RaceDefinition raceDefinition = race.getRace();
|
||||
Iterable<Competitor> competitors = raceDefinition.getCompetitors();
|
||||
|
||||
for (Competitor competitor : competitors) {
|
||||
PerRaceAndCompetitorPolarSheetGenerationWorker task = new PerRaceAndCompetitorPolarSheetGenerationWorker(race, this, startTime, endTime, competitor);
|
||||
workers.add(task);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private List<List<BoatAndWindSpeed>> initializePolarDataContainer() {
|
||||
List<List<BoatAndWindSpeed>> container = new ArrayList<List<BoatAndWindSpeed>>();
|
||||
for (int i = 0; i < 360; i++) {
|
||||
container.add(new ArrayList<BoatAndWindSpeed>());
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the {@link PerRaceAndCompetitorPolarSheetGenerationWorker}s
|
||||
*/
|
||||
public void startPolarSheetGeneration() {
|
||||
for (Runnable task : workers) {
|
||||
executor.execute(task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called from {@link PerRaceAndCompetitorPolarSheetGenerationWorker} for adding a datapoint to the list of
|
||||
* results
|
||||
*
|
||||
* @param roundedAngle
|
||||
* boat's angle to the wind
|
||||
* @param boatSpeed
|
||||
* boat's speed in knots
|
||||
* @param windSpeed
|
||||
* wind's speed in knots
|
||||
*/
|
||||
protected void addPolarData(long roundedAngle, Speed boatSpeed, Speed windSpeed) {
|
||||
int angle = (int) roundedAngle;
|
||||
if (angle < 0) {
|
||||
angle = (360 + angle);
|
||||
}
|
||||
BoatAndWindSpeed speeds = new BoatAndWindSpeedImpl(boatSpeed, windSpeed);
|
||||
polarData.get(angle).add(speeds);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return results already averaged per angle. Also datacount overall and per angle. And a completion flag to show
|
||||
* if the complete polar sheet has been generated or if the current results are only an intermediate
|
||||
* product.
|
||||
*/
|
||||
public PolarSheetsData getPolarData() {
|
||||
Number[][] averagedPolarDataByWindSpeed = new Number[13][360];
|
||||
Integer[] dataCountPerAngle = new Integer[360];
|
||||
int dataCount = 0;
|
||||
Map<Integer, Integer[]> dataCountPerAngleForWindspeed = new HashMap<Integer, Integer[]>();
|
||||
for (int i = 0; i < 13; i++) {
|
||||
dataCountPerAngleForWindspeed.put(i, new Integer[360]);
|
||||
}
|
||||
for (int i = 0; i < 360; i++) {
|
||||
// Avoid Concurrent modification, lock would slow things down
|
||||
BoatAndWindSpeed[] values = polarData.get(i).toArray(new BoatAndWindSpeed[polarData.get(i).size()]);
|
||||
dataCount = dataCount + values.length;
|
||||
dataCountPerAngle[i] = values.length;
|
||||
double[] sumsPerWindSpeed = new double[13];
|
||||
int[] dataCountPerWindSpeed = new int[13];
|
||||
for (BoatAndWindSpeed singleDataPoint : values) {
|
||||
if (singleDataPoint != null) {
|
||||
int windSpeed = (int) singleDataPoint.getWindSpeed().getBeaufort();
|
||||
//Somehow beaufort sometimes gets bigger than twelve. TODO: Investigation
|
||||
if (windSpeed > 12) {
|
||||
windSpeed = 12;
|
||||
}
|
||||
//TODO enable different kinds of metrics for boats speed
|
||||
sumsPerWindSpeed[windSpeed] = sumsPerWindSpeed[windSpeed] + singleDataPoint.getBoatSpeed().getKnots();
|
||||
dataCountPerWindSpeed[windSpeed]++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < 13; j++) {
|
||||
Double average = sumsPerWindSpeed[j] / dataCountPerWindSpeed[j];
|
||||
if (average.isNaN()) {
|
||||
average = new Double(0);
|
||||
}
|
||||
averagedPolarDataByWindSpeed[j][i] = average;
|
||||
dataCountPerAngleForWindspeed.get(j)[i] = dataCountPerWindSpeed[j];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
boolean complete = true;
|
||||
for (PerRaceAndCompetitorPolarSheetGenerationWorker task : workers) {
|
||||
if (!task.isDone()) {
|
||||
complete = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PolarSheetsData data = new PolarSheetsDataImpl(averagedPolarDataByWindSpeed, complete, dataCount,
|
||||
dataCountPerAngleForWindspeed);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to present more detailed data.
|
||||
*
|
||||
* @return The complete set of datapoints that have been added. Can be quite big, depending on the amount of races
|
||||
* and competitors.
|
||||
*/
|
||||
public List<List<BoatAndWindSpeed>> getCompleteData() {
|
||||
return polarData;
|
||||
}
|
||||
|
||||
}
|
||||
+120
-116
@@ -5,10 +5,10 @@ import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.DouglasPeucker;
|
||||
@@ -41,41 +41,42 @@ import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
*/
|
||||
public interface TrackedRace extends Serializable {
|
||||
final long MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS = 30000;
|
||||
|
||||
|
||||
final long DEFAULT_LIVE_DELAY_IN_MILLISECONDS = 5000;
|
||||
|
||||
RaceDefinition getRace();
|
||||
|
||||
|
||||
RegattaAndRaceIdentifier getRaceIdentifier();
|
||||
|
||||
|
||||
/**
|
||||
* Computes the estimated start time for this race (not to be confused with the {@link #getStartOfTracking()} time point
|
||||
* which is expected to be before the race start time). When there are no {@link MarkPassing}s for the first mark, <code>null</code>
|
||||
* is returned. If there are mark passings for the first mark and the start time is less than
|
||||
* {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} before the first mark passing for the
|
||||
* Computes the estimated start time for this race (not to be confused with the {@link #getStartOfTracking()} time
|
||||
* point which is expected to be before the race start time). When there are no {@link MarkPassing}s for the first
|
||||
* mark, <code>null</code> is returned. If there are mark passings for the first mark and the start time is less
|
||||
* than {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} before the first mark passing for the
|
||||
* first mark. Otherwise, the first mark passing for the first mark minus
|
||||
* {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} is returned as the race start time.<p>
|
||||
* {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} is returned as the race start time.
|
||||
* <p>
|
||||
*
|
||||
* If no start time can be determined this way, <code>null</code> is returned.
|
||||
*/
|
||||
TimePoint getStartOfRace();
|
||||
|
||||
|
||||
/**
|
||||
* Determine the race end time is tricky. Boats may sink, stop, not finish, although they started the race. We therefore
|
||||
* cannot wait for all boats to reach the finish line.
|
||||
* The following rules are used to calculate the endOfRace:
|
||||
* Determine the race end time is tricky. Boats may sink, stop, not finish, although they started the race. We
|
||||
* therefore cannot wait for all boats to reach the finish line. The following rules are used to calculate the
|
||||
* endOfRace:
|
||||
* <ol>
|
||||
* <li>Returns <code>null</code> if no boat passed the finish line</li>
|
||||
* <li>Returns time of the last mark passing recorded for the finish line</li>
|
||||
* <li>TODO: Returns the time of the first passing of the finish line + the target window (defined in the competition rules)
|
||||
* if a target window has been defined for the race</li>
|
||||
* </ol>
|
||||
* <li>Returns <code>null</code> if no boat passed the finish line</li>
|
||||
* <li>Returns time of the last mark passing recorded for the finish line</li>
|
||||
* <li>TODO: Returns the time of the first passing of the finish line + the target window (defined in the
|
||||
* competition rules) if a target window has been defined for the race</li>
|
||||
* </ol>
|
||||
*/
|
||||
TimePoint getEndOfRace();
|
||||
|
||||
/**
|
||||
* Returns a list of the first and last mark passing times of all course waypoints. Callers wanting to iterate over the
|
||||
* result must <code>synchronize</code> on the result.
|
||||
* Returns a list of the first and last mark passing times of all course waypoints. Callers wanting to iterate over
|
||||
* the result must <code>synchronize</code> on the result.
|
||||
*/
|
||||
Iterable<Pair<Waypoint, Pair<TimePoint, TimePoint>>> getMarkPassingsTimes();
|
||||
|
||||
@@ -83,89 +84,84 @@ public interface TrackedRace extends Serializable {
|
||||
* Shorthand for <code>{@link #getStart()}.{@link TimePoint#compareTo(TimePoint) compareTo(at)} <= 0</code>
|
||||
*/
|
||||
boolean hasStarted(TimePoint at);
|
||||
|
||||
|
||||
/**
|
||||
* Clients can safely iterate over the iterable returned because it's a non-live copy of the tracked legs of this
|
||||
* tracked race. This implies that should an update to the underlying list of waypoints in this race's {@link Course}
|
||||
* take place after this method has returned, then this won't be reflected in the result returned. Callers should
|
||||
* obtain the {@link Course#lockForRead() course's read lock} while using the result of this call if they want to
|
||||
* ensure that no course update is applied concurrently.
|
||||
* tracked race. This implies that should an update to the underlying list of waypoints in this race's
|
||||
* {@link Course} take place after this method has returned, then this won't be reflected in the result returned.
|
||||
* Callers should obtain the {@link Course#lockForRead() course's read lock} while using the result of this call if
|
||||
* they want to ensure that no course update is applied concurrently.
|
||||
*/
|
||||
Iterable<TrackedLeg> getTrackedLegs();
|
||||
|
||||
|
||||
TrackedLeg getTrackedLeg(Leg leg);
|
||||
|
||||
|
||||
/**
|
||||
* Tracking information about the leg <code>competitor</code> is on at <code>timePoint</code>, or
|
||||
* <code>null</code> if the competitor hasn't started any leg yet at <code>timePoint</code> or has
|
||||
* already finished the race.
|
||||
* Tracking information about the leg <code>competitor</code> is on at <code>timePoint</code>, or <code>null</code>
|
||||
* if the competitor hasn't started any leg yet at <code>timePoint</code> or has already finished the race.
|
||||
*/
|
||||
TrackedLegOfCompetitor getCurrentLeg(Competitor competitor, TimePoint timePoint);
|
||||
|
||||
|
||||
/**
|
||||
* Tells which leg the leader at <code>timePoint</code> is on
|
||||
*/
|
||||
TrackedLeg getCurrentLeg(TimePoint timePoint);
|
||||
|
||||
|
||||
/**
|
||||
* Precondition: waypoint must still be part of {@link #getRace()}.{@link RaceDefinition#getCourse() getCourse()}.
|
||||
*/
|
||||
TrackedLeg getTrackedLegFinishingAt(Waypoint endOfLeg);
|
||||
|
||||
|
||||
/**
|
||||
* Precondition: waypoint must still be part of {@link #getRace()}.{@link RaceDefinition#getCourse() getCourse()}.
|
||||
*/
|
||||
TrackedLeg getTrackedLegStartingAt(Waypoint startOfLeg);
|
||||
|
||||
|
||||
/**
|
||||
* The raw, updating feed of a single competitor participating in this race
|
||||
*/
|
||||
GPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor);
|
||||
|
||||
|
||||
/**
|
||||
* Tells the leg on which the <code>competitor</code> was at time <code>at</code>.
|
||||
* If the competitor hasn't passed the start waypoint yet, <code>null</code> is
|
||||
* returned because the competitor was not yet on any leg at that point in time. If
|
||||
* the time point happens to be after the last fix received from that competitor,
|
||||
* the last known leg for that competitor is returned. If the time point is after the
|
||||
* competitor's mark passing for the finish line, <code>null</code> is returned.
|
||||
* For all legs except the last, if the time point equals a mark passing time point
|
||||
* of the leg's starting waypoint, that leg is returned. For the time point of
|
||||
* the mark passing for the finish line, the last leg is returned.
|
||||
* Tells the leg on which the <code>competitor</code> was at time <code>at</code>. If the competitor hasn't passed
|
||||
* the start waypoint yet, <code>null</code> is returned because the competitor was not yet on any leg at that point
|
||||
* in time. If the time point happens to be after the last fix received from that competitor, the last known leg for
|
||||
* that competitor is returned. If the time point is after the competitor's mark passing for the finish line,
|
||||
* <code>null</code> is returned. For all legs except the last, if the time point equals a mark passing time point
|
||||
* of the leg's starting waypoint, that leg is returned. For the time point of the mark passing for the finish line,
|
||||
* the last leg is returned.
|
||||
*/
|
||||
TrackedLegOfCompetitor getTrackedLeg(Competitor competitor, TimePoint at);
|
||||
|
||||
|
||||
TrackedLegOfCompetitor getTrackedLeg(Competitor competitor, Leg leg);
|
||||
|
||||
|
||||
/**
|
||||
* @return a sequential number counting the updates that occurred to this tracked race. Callers may use this to ask
|
||||
* for updates newer than such a sequence number.
|
||||
*/
|
||||
long getUpdateCount();
|
||||
|
||||
|
||||
int getRankDifference(Competitor competitor, Leg leg, TimePoint timePoint);
|
||||
|
||||
|
||||
/**
|
||||
* Computes the rank of the competitor in this race for the current time.
|
||||
* Computes the rank of the competitor in this race for the current time.
|
||||
*/
|
||||
int getRank(Competitor competitor) throws NoWindException;
|
||||
|
||||
|
||||
/**
|
||||
* Computes the rank of <code>competitor</code> in this race. A competitor is ahead of all
|
||||
* competitors that are one or more legs behind. Within the same leg, the rank is determined
|
||||
* by the windward distance to go and therefore depends on the assumptions of the wind direction
|
||||
* for the given <code>timePoint</code>. If the race hasn't {@link #hasStarted(TimePoint) started}
|
||||
* yet, the result is undefined.
|
||||
* Computes the rank of <code>competitor</code> in this race. A competitor is ahead of all competitors that are one
|
||||
* or more legs behind. Within the same leg, the rank is determined by the windward distance to go and therefore
|
||||
* depends on the assumptions of the wind direction for the given <code>timePoint</code>. If the race hasn't
|
||||
* {@link #hasStarted(TimePoint) started} yet, the result is undefined.
|
||||
*
|
||||
* @return <code>0</code> in case the competitor hasn't participated in the race; a rank starting
|
||||
* with <code>1</code> where rank <code>1</code> identifies the leader otherwise
|
||||
* @return <code>0</code> in case the competitor hasn't participated in the race; a rank starting with
|
||||
* <code>1</code> where rank <code>1</code> identifies the leader otherwise
|
||||
*/
|
||||
int getRank(Competitor competitor, TimePoint timePoint) throws NoWindException;
|
||||
|
||||
|
||||
/**
|
||||
* For a competitor, computes the distance (TODO not yet clear whether over ground or
|
||||
* projected onto wind direction) into the race <code>secondsIntoTheRace</code> after
|
||||
* the race {@link TrackedRace#getStart() started}.
|
||||
* For a competitor, computes the distance (TODO not yet clear whether over ground or projected onto wind direction)
|
||||
* into the race <code>secondsIntoTheRace</code> after the race {@link TrackedRace#getStart() started}.
|
||||
*/
|
||||
Distance getStartAdvantage(Competitor competitor, double secondsIntoTheRace);
|
||||
|
||||
@@ -183,14 +179,14 @@ public interface TrackedRace extends Serializable {
|
||||
Iterable<MarkPassing> getMarkPassingsInOrder(Waypoint waypoint);
|
||||
|
||||
/**
|
||||
* Obtains the {@link MarkPassing} for <code>competitor</code> passing <code>waypoint</code>. If no such
|
||||
* mark passing has been reported (yet), <code>null</code> is returned.
|
||||
* Obtains the {@link MarkPassing} for <code>competitor</code> passing <code>waypoint</code>. If no such mark
|
||||
* passing has been reported (yet), <code>null</code> is returned.
|
||||
*/
|
||||
MarkPassing getMarkPassing(Competitor competitor, Waypoint waypoint);
|
||||
|
||||
/**
|
||||
* Yields the track describing <code>mark</code>'s movement over time; never <code>null</code> because a
|
||||
* new track will be created in case no track was present for <code>mark</code> so far.
|
||||
* Yields the track describing <code>mark</code>'s movement over time; never <code>null</code> because a new track
|
||||
* will be created in case no track was present for <code>mark</code> so far.
|
||||
*/
|
||||
GPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark);
|
||||
|
||||
@@ -204,7 +200,7 @@ public interface TrackedRace extends Serializable {
|
||||
* is returned. Otherwise, the center of gravity between the mark positions is computed and returned.
|
||||
*/
|
||||
Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint);
|
||||
|
||||
|
||||
/**
|
||||
* Same as {@link #getWind(Position, TimePoint, Iterable) getWind(p, at, Collections.emptyList())}
|
||||
*/
|
||||
@@ -212,8 +208,8 @@ public interface TrackedRace extends Serializable {
|
||||
|
||||
/**
|
||||
* Obtains estimated interpolated wind information for a given position and time point. The information is taken
|
||||
* from all wind sources available except for those listed in <code>windSourcesToExclude</code>, using the confidences
|
||||
* of the wind values provided by the various sources during averaging.
|
||||
* from all wind sources available except for those listed in <code>windSourcesToExclude</code>, using the
|
||||
* confidences of the wind values provided by the various sources during averaging.
|
||||
*/
|
||||
Wind getWind(Position p, TimePoint at, Iterable<WindSource> windSourcesToExclude);
|
||||
|
||||
@@ -231,10 +227,11 @@ public interface TrackedRace extends Serializable {
|
||||
Iterable<WindSource> getWindSources();
|
||||
|
||||
/**
|
||||
* Same as {@link #getOrCreateWindTrack(WindSource, long) getOrCreateWindTrack(windSource, getMillisecondsOverWhichToAverageWind())}.
|
||||
* Same as {@link #getOrCreateWindTrack(WindSource, long) getOrCreateWindTrack(windSource,
|
||||
* getMillisecondsOverWhichToAverageWind())}.
|
||||
*/
|
||||
WindTrack getOrCreateWindTrack(WindSource windSource);
|
||||
|
||||
|
||||
WindTrack getOrCreateWindTrack(WindSource windSource, long delayForWindEstimationCacheInvalidation);
|
||||
|
||||
/**
|
||||
@@ -243,26 +240,26 @@ public interface TrackedRace extends Serializable {
|
||||
void waitForNextUpdate(int sinceUpdate) throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Time stamp of the start of the actual tracking.
|
||||
* The value can be null (e.g. if we have not received any signal from the tracking infrastructure)
|
||||
* Time stamp of the start of the actual tracking. The value can be null (e.g. if we have not received any signal
|
||||
* from the tracking infrastructure)
|
||||
*/
|
||||
TimePoint getStartOfTracking();
|
||||
|
||||
/**
|
||||
* Time stamp of the end of the actual tracking.
|
||||
* The value can be null (e.g. if we have not received any signal from the tracking infrastructure)
|
||||
* Time stamp of the end of the actual tracking. The value can be null (e.g. if we have not received any signal from
|
||||
* the tracking infrastructure)
|
||||
*/
|
||||
TimePoint getEndOfTracking();
|
||||
|
||||
/**
|
||||
* Regardless of the order in which events were received, this method returns the latest time point contained by any of
|
||||
* the events received and processed.
|
||||
* Regardless of the order in which events were received, this method returns the latest time point contained by any
|
||||
* of the events received and processed.
|
||||
*/
|
||||
TimePoint getTimePointOfNewestEvent();
|
||||
|
||||
/**
|
||||
* Regardless of the order in which events were received, this method returns the oldest time point contained by any of
|
||||
* the events received and processed.
|
||||
* Regardless of the order in which events were received, this method returns the oldest time point contained by any
|
||||
* of the events received and processed.
|
||||
*/
|
||||
TimePoint getTimePointOfOldestEvent();
|
||||
|
||||
@@ -274,17 +271,18 @@ public interface TrackedRace extends Serializable {
|
||||
* some tracking providers such as TracTrac. If the caller wants to iterate on the resulting collection or
|
||||
* construct a {@link SortedSet#headSet(Object)} or {@link SortedSet#tailSet(Object)} and then iterate over
|
||||
* that, the caller needs to invoke {@link #lockForRead(Iterable)} with the collection returned as parameter
|
||||
* because insertions into the competitor's mark passing collection will obtain the corresponding write lock.
|
||||
* because insertions into the competitor's mark passing collection will obtain the corresponding write
|
||||
* lock.
|
||||
*/
|
||||
NavigableSet<MarkPassing> getMarkPassings(Competitor competitor);
|
||||
|
||||
|
||||
void lockForRead(Iterable<MarkPassing> markPassings);
|
||||
|
||||
|
||||
void unlockAfterRead(Iterable<MarkPassing> markPassings);
|
||||
|
||||
/**
|
||||
* Time stamp that the event received last from the underlying push service carried on it.
|
||||
* Note that these times may not increase monotonically.
|
||||
* Time stamp that the event received last from the underlying push service carried on it. Note that these times may
|
||||
* not increase monotonically.
|
||||
*/
|
||||
TimePoint getTimePointOfLastEvent();
|
||||
|
||||
@@ -296,7 +294,7 @@ public interface TrackedRace extends Serializable {
|
||||
* Gets the current delay of incoming events to the real time of the events in milliseconds
|
||||
*/
|
||||
long getDelayToLiveInMillis();
|
||||
|
||||
|
||||
/**
|
||||
* Estimates the wind direction based on the observed boat courses at the time given for the position provided. The
|
||||
* estimate is based on the assumption that the boats which are on an upwind or a downwind leg sail with very
|
||||
@@ -321,13 +319,12 @@ public interface TrackedRace extends Serializable {
|
||||
* we may be able to also infer the wind speed from the boat tracks.
|
||||
*/
|
||||
Wind getEstimatedWindDirection(Position position, TimePoint timePoint);
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the <code>competitor</code> is sailing on port or starboard tack at the
|
||||
* <code>timePoint</code> requested. Note that this will have to retrieve information about the wind.
|
||||
* This, in turn, can lead to the current thread obtaining the monitor of the various wind tracks,
|
||||
* and, if the {@link WindSource#TRACK_BASED_ESTIMATION} source is used, also the monitors of the
|
||||
* competitors' GPS tracks.
|
||||
* Determines whether the <code>competitor</code> is sailing on port or starboard tack at the <code>timePoint</code>
|
||||
* requested. Note that this will have to retrieve information about the wind. This, in turn, can lead to the
|
||||
* current thread obtaining the monitor of the various wind tracks, and, if the
|
||||
* {@link WindSource#TRACK_BASED_ESTIMATION} source is used, also the monitors of the competitors' GPS tracks.
|
||||
*/
|
||||
Tack getTack(Competitor competitor, TimePoint timePoint) throws NoWindException;
|
||||
|
||||
@@ -345,30 +342,34 @@ public interface TrackedRace extends Serializable {
|
||||
* mark positions are not known (yet)
|
||||
*/
|
||||
Wind getDirectionFromStartToNextMark(TimePoint at);
|
||||
|
||||
|
||||
/**
|
||||
* Uses a {@link DouglasPeucker Douglas-Peucker} algorithm to approximate this track's fixes starting at
|
||||
* time <code>from</code> until time point <code>to</code> such that the maximum distance between the
|
||||
* track's fixes and the approximation is at most <code>maxDistance</code>.
|
||||
* Uses a {@link DouglasPeucker Douglas-Peucker} algorithm to approximate this track's fixes starting at time
|
||||
* <code>from</code> until time point <code>to</code> such that the maximum distance between the track's fixes and
|
||||
* the approximation is at most <code>maxDistance</code>.
|
||||
*/
|
||||
List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to);
|
||||
|
||||
/**
|
||||
* @return a non-<code>null</code> but perhaps empty list of the maneuvers that <code>competitor</code> performed in
|
||||
* this race between <code>from</code> and <code>to</code>.
|
||||
* this race between <code>from</code> and <code>to</code>. Depending on <code>waitForLatest</code> the
|
||||
* result is taken from the cache straight away (<code>waitForLatest==false</code>) or, if a re-calculation
|
||||
* for the <code>key</code> is still ongoing, the result of that ongoing re-calculation is returned.
|
||||
*/
|
||||
List<Maneuver> getManeuvers(Competitor competitor, TimePoint from, TimePoint to, boolean waitForLatest) throws NoWindException;
|
||||
List<Maneuver> getManeuvers(Competitor competitor, TimePoint from, TimePoint to, boolean waitForLatest)
|
||||
throws NoWindException;
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if this race is known to start with an {@link LegType#UPWIND upwind} leg.
|
||||
* If this is the case, the wind estimation may default to using the first leg's direction at race start
|
||||
* time as the direction the wind comes from.
|
||||
* @return <code>true</code> if this race is known to start with an {@link LegType#UPWIND upwind} leg. If this is
|
||||
* the case, the wind estimation may default to using the first leg's direction at race start time as the
|
||||
* direction the wind comes from.
|
||||
*/
|
||||
boolean raceIsKnownToStartUpwind();
|
||||
|
||||
/**
|
||||
* Many calculations require valid wind data. In order to prevent NoWindException's to be handled by those calculation
|
||||
* this method can be used to check whether the tracked race has sufficient wind information available.
|
||||
* Many calculations require valid wind data. In order to prevent NoWindException's to be handled by those
|
||||
* calculation this method can be used to check whether the tracked race has sufficient wind information available.
|
||||
*
|
||||
* @return <code>true</code> if {@link #getWind(Position, TimePoint)} delivers a (not null) wind fix.
|
||||
*/
|
||||
boolean hasWindData();
|
||||
@@ -380,23 +381,23 @@ public interface TrackedRace extends Serializable {
|
||||
boolean hasGPSData();
|
||||
|
||||
/**
|
||||
* Adds a race change listener to the set of listeners that will be notified about changes to this race.
|
||||
* The listener won't be serialized together with this object.
|
||||
* Adds a race change listener to the set of listeners that will be notified about changes to this race. The
|
||||
* listener won't be serialized together with this object.
|
||||
*/
|
||||
void addListener(RaceChangeListener listener);
|
||||
|
||||
|
||||
void removeListener(RaceChangeListener listener);
|
||||
|
||||
Distance getDistanceTraveled(Competitor competitor, TimePoint timePoint);
|
||||
|
||||
Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint) throws NoWindException;
|
||||
|
||||
|
||||
/**
|
||||
* Calls {@link #getWindWithConfidence(Position, TimePoint, Iterable)} and excludes those wind sources listed in
|
||||
* {@link #getWindSourcesToExclude}.
|
||||
*/
|
||||
WindWithConfidence<Pair<Position, TimePoint>> getWindWithConfidence(Position p, TimePoint at);
|
||||
|
||||
|
||||
/**
|
||||
* Lists those wind sources which by default are not considered in {@link #getWind(Position, TimePoint)} and
|
||||
* {@link #getWindWithConfidence(Position, TimePoint)}.
|
||||
@@ -406,8 +407,8 @@ public interface TrackedRace extends Serializable {
|
||||
/**
|
||||
* Loops over this tracked race's wind sources and from each asks its averaged wind for the position <code>p</code>
|
||||
* and time point <code>at</code>, using the particular wind source's averaging interval. The confidences delivered
|
||||
* by each wind source are used during computing the averaged result across the wind sources. The result has the averaged
|
||||
* confidence attached.
|
||||
* by each wind source are used during computing the averaged result across the wind sources. The result has the
|
||||
* averaged confidence attached.
|
||||
*/
|
||||
WindWithConfidence<Pair<Position, TimePoint>> getWindWithConfidence(Position p, TimePoint at,
|
||||
Iterable<WindSource> windSourcesToExclude);
|
||||
@@ -419,7 +420,8 @@ public interface TrackedRace extends Serializable {
|
||||
WindWithConfidence<TimePoint> getEstimatedWindDirectionWithConfidence(Position position, TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* After the call returns, {@link #getWindSourcesToExclude()} returns an iterable that equals <code>windSourcesToExclude</code>
|
||||
* After the call returns, {@link #getWindSourcesToExclude()} returns an iterable that equals
|
||||
* <code>windSourcesToExclude</code>
|
||||
*/
|
||||
void setWindSourcesToExclude(Iterable<? extends WindSource> windSourcesToExclude);
|
||||
|
||||
@@ -430,25 +432,27 @@ public interface TrackedRace extends Serializable {
|
||||
* if <code>true</code> and any cache update is currently going on, wait for the update to complete and
|
||||
* then fetch the updated value; otherwise, serve this requests from whatever is currently in the cache
|
||||
*/
|
||||
Distance getAverageCrossTrackError(Competitor competitor, TimePoint timePoint, boolean waitForLatestAnalysis) throws NoWindException;
|
||||
Distance getAverageCrossTrackError(Competitor competitor, TimePoint timePoint, boolean waitForLatestAnalysis)
|
||||
throws NoWindException;
|
||||
|
||||
WindStore getWindStore();
|
||||
|
||||
Competitor getOverallLeader(TimePoint timePoint) throws NoWindException;
|
||||
|
||||
/**
|
||||
* Returns the competitors of this tracked race, according to their ranking. Competitors whose {@link #getRank(Competitor)} is 0 will
|
||||
* be sorted "worst".
|
||||
* Returns the competitors of this tracked race, according to their ranking. Competitors whose
|
||||
* {@link #getRank(Competitor)} is 0 will be sorted "worst".
|
||||
*/
|
||||
List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) throws NoWindException;
|
||||
|
||||
Distance getAverageCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly, boolean waitForLatestAnalyses) throws NoWindException;
|
||||
Distance getAverageCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly,
|
||||
boolean waitForLatestAnalyses) throws NoWindException;
|
||||
|
||||
/**
|
||||
* When provided with a {@link WindStore} during construction, the tracked race will asynchronously load the wind
|
||||
* data for this tracked race from the wind store in a background thread and update this tracked race with the results.
|
||||
* Clients that want to wait for the wind loading process to complete can do so by calling this method which will block
|
||||
* until the wind loading has completed.
|
||||
* data for this tracked race from the wind store in a background thread and update this tracked race with the
|
||||
* results. Clients that want to wait for the wind loading process to complete can do so by calling this method
|
||||
* which will block until the wind loading has completed.
|
||||
*/
|
||||
void waitUntilWindLoadingComplete() throws InterruptedException;
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Fragment-Host: com.sap.sailing.gwt.ui
|
||||
Require-Bundle: com.sap.sailing.server,
|
||||
org.hamcrest.core;bundle-version="1.1.0"
|
||||
org.hamcrest.core;bundle-version="1.1.0",
|
||||
com.sap.sailing.expeditionconnector
|
||||
Bundle-ClassPath: .
|
||||
Import-Package: javax.jms;version="1.1.0",
|
||||
javax.servlet;version="2.5.0",
|
||||
|
||||
+727
@@ -0,0 +1,727 @@
|
||||
package com.sap.sailing.gwt.ui.test;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.RegattaListener;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
|
||||
|
||||
public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
private static final long serialVersionUID = 5827912985564121181L;
|
||||
private final WindTrack windTrack = new WindTrackImpl(/* millisecondsOverWhichToAverage */ 30000, /* useSpeed */ true, "TestWindTrack");
|
||||
|
||||
public WindTrack getWindTrack() {
|
||||
return windTrack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition getRace() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getStartOfRace() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<TrackedLeg> getTrackedLegs() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLeg getTrackedLeg(Leg leg) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLegOfCompetitor getCurrentLeg(Competitor competitor, TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLeg getCurrentLeg(TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLeg getTrackedLegFinishingAt(Waypoint endOfLeg) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLeg getTrackedLegStartingAt(Waypoint startOfLeg) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLegOfCompetitor getTrackedLeg(Competitor competitor, TimePoint at) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLegOfCompetitor getTrackedLeg(Competitor competitor, Leg leg) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUpdateCount() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRankDifference(Competitor competitor, Leg leg, TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRank(Competitor competitor) throws NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRank(Competitor competitor, TimePoint timePoint) throws NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getStartAdvantage(Competitor competitor, double secondsIntoTheRace) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<MarkPassing> getMarkPassingsInOrder(Waypoint waypoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkPassing getMarkPassing(Competitor competitor, Waypoint waypoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicGPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindTrack getOrCreateWindTrack(WindSource windSource, long delayForWindEstimationCacheInvalidation) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForNextUpdate(int sinceUpdate) throws InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getStartOfTracking() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePointOfNewestEvent() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<MarkPassing> getMarkPassings(Competitor competitor) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordFix(Competitor competitor, GPSFixMoving fix) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordWind(Wind wind, WindSource windSource) {
|
||||
if (windSource.getType() == WindSourceType.EXPEDITION) {
|
||||
windTrack.add(wind);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(RaceChangeListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMarkPassings(Competitor competitor, Iterable<MarkPassing> markPassings) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartTimeReceived(TimePoint start) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicGPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeWind(Wind wind, WindSource windSource) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePointOfLastEvent() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMillisecondsOverWhichToAverageSpeed(long millisecondsOverWhichToAverageSpeed) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMillisecondsOverWhichToAverageWind(long millisecondsOverWhichToAverageWind) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMillisecondsOverWhichToAverageSpeed() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMillisecondsOverWhichToAverageWind() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind getEstimatedWindDirection(Position position, TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStarted(TimePoint at) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTrackedRegatta getTrackedRegatta() {
|
||||
return new DynamicTrackedRegatta() {
|
||||
private static final long serialVersionUID = 2651590861333064588L;
|
||||
|
||||
@Override
|
||||
public Regatta getRegatta() {
|
||||
return new Regatta() {
|
||||
private static final long serialVersionUID = -4908774269425170811L;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "A Mocked Test Regatta";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getId() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceDefinition> getAllRaces() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatClass getBoatClass() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Competitor> getCompetitors() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRace(RaceDefinition race) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRace(RaceDefinition raceDefinition) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition getRaceByName(String raceName) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRegattaListener(RegattaListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRegattaListener(RegattaListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaIdentifier getRegattaIdentifier() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseName() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<? extends Series> getSeries() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Series getSeriesByName(String seriesName) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPersistent() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRaceColumnListener(RaceColumnListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRaceColumnListener(RaceColumnListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<TrackedRace> getTrackedRaces() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<TrackedRace> getTrackedRaces(BoatClass boatClass) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTrackedRace(TrackedRace trackedRace) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTrackedRace(TrackedRace trackedRace) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRaceListener(RaceListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNetPoints(Competitor competitor, TimePoint timePoint) throws NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTrackedRace getTrackedRace(RaceDefinition race) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTrackedRace getExistingTrackedRace(RaceDefinition race) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTrackedRace(RaceDefinition raceDefinition) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tack getTack(Competitor competitor, TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind getDirectionFromStartToNextMark(TimePoint at) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Maneuver> getManeuvers(Competitor competitor, TimePoint from, TimePoint to, boolean waitForLatest) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean raceIsKnownToStartUpwind() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRaceIsKnownToStartUpwind(boolean raceIsKnownToStartUpwind) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaAndRaceIdentifier getRaceIdentifier() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getEndOfRace() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getDistanceTraveled(Competitor competitor, TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint)
|
||||
throws NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind getWind(Position p, TimePoint at) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind getWind(Position p, TimePoint at, Iterable<WindSource> windSourcesToExclude) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<WindSource> getWindSources(WindSourceType type) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<WindSource> getWindSources() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindWithConfidence<Pair<Position, TimePoint>> getWindWithConfidence(Position p, TimePoint at,
|
||||
Iterable<WindSource> windSourcesToExclude) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindWithConfidence<TimePoint> getEstimatedWindDirectionWithConfidence(Position position, TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindWithConfidence<Pair<Position, TimePoint>> getWindWithConfidence(Position p, TimePoint at) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<WindSource> getWindSourcesToExclude() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getEndOfTracking() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePointOfOldestEvent() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartOfTrackingReceived(TimePoint startOfTrackingReceived) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEndOfTrackingReceived(TimePoint endOfTrackingReceived) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Pair<Waypoint, Pair<TimePoint, TimePoint>>> getMarkPassingsTimes() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageCrossTrackError(Competitor competitor, TimePoint timePoint, boolean waitForLatestAnalysis) throws NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindTrack getOrCreateWindTrack(WindSource windSource) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordFix(Mark mark, GPSFix fix) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(RaceChangeListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindStore getWindStore() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindSourcesToExclude(Iterable<? extends WindSource> windSourcesToExclude) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public Competitor getOverallLeader(TimePoint timePoint) throws NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelayToLiveInMillis() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDelayToLiveInMillis(long delayToLiveInMillis) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAndFixDelayToLiveInMillis(long delayToLiveInMillis) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly, boolean waitForLatestAnalyses)
|
||||
throws NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitUntilWindLoadingComplete() throws InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Mark> getMarks() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasWindData() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGPSData() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lockForRead(Iterable<MarkPassing> markPassings) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockAfterRead(Iterable<MarkPassing> markPassings) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedRaceStatus getStatus() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(TrackedRaceStatus newStatus) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitUntilNotLoading() {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
package com.sap.sailing.gwt.ui.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.UUID;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.BoatClassImpl;
|
||||
import com.sap.sailing.domain.base.impl.BoatImpl;
|
||||
import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
||||
import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.TeamImpl;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.ScoreCorrectionProvider;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.gwt.ui.client.SailingService;
|
||||
import com.sap.sailing.gwt.ui.server.SailingServiceImpl;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import com.sap.sailing.server.replication.ReplicationService;
|
||||
|
||||
public class PolarSheetGenerationServiceTest {
|
||||
|
||||
private static final String BOAT_CLASS = "Forelle";
|
||||
|
||||
@Test
|
||||
public void testPolarSheetGenerationService() throws InterruptedException {
|
||||
|
||||
SailingService service = new MockSailingServiceForPolarSheetGeneration();
|
||||
|
||||
List<RegattaAndRaceIdentifier> idList = new ArrayList<RegattaAndRaceIdentifier>();
|
||||
idList.add(new RegattaNameAndRaceName("IrgendeineRegatta", "IrgendeinRennen"));
|
||||
|
||||
PolarSheetGenerationTriggerResponse triggerData = service.generatePolarSheetForRaces(idList);
|
||||
Assert.assertNotNull(triggerData);
|
||||
Assert.assertEquals(BOAT_CLASS, triggerData.getBoatClassName());
|
||||
Assert.assertNotNull(triggerData.getId());
|
||||
|
||||
boolean complete = false;
|
||||
PolarSheetsData results = null;
|
||||
double timeOut = 10;
|
||||
while (!complete && timeOut > 0) {
|
||||
Thread.sleep(200);
|
||||
timeOut = timeOut - 0.2;
|
||||
results = service.getPolarSheetsGenerationResults(triggerData.getId());
|
||||
complete = results.isComplete();
|
||||
}
|
||||
|
||||
Assert.assertTrue(complete);
|
||||
Assert.assertNotNull(results);
|
||||
|
||||
Assert.assertEquals(4, results.getDataCount());
|
||||
Assert.assertEquals(4.0, results.getAveragedPolarDataByWindSpeed()[1][45]);
|
||||
Assert.assertEquals(2.0, results.getAveragedPolarDataByWindSpeed()[1][55]);
|
||||
Assert.assertEquals(6.0, results.getAveragedPolarDataByWindSpeed()[1][30]);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class MockSailingServiceForPolarSheetGeneration extends SailingServiceImpl {
|
||||
|
||||
@Override
|
||||
protected RacingEventService getService() {
|
||||
RacingEventService service = new MockRacingEventServiceForPolarSheetGeneration();
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServiceTracker<RacingEventService, RacingEventService> createAndOpenRacingEventServiceTracker(
|
||||
BundleContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServiceTracker<ReplicationService, ReplicationService> createAndOpenReplicationServiceTracker(
|
||||
BundleContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> createAndOpenScoreCorrectionProviderServiceTracker(
|
||||
BundleContext bundleContext) {;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class MockRacingEventServiceForPolarSheetGeneration extends RacingEventServiceImpl {
|
||||
|
||||
@Override
|
||||
public TrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier) {
|
||||
MockTrackedRaceForPolarSheetGeneration trackedRace = new MockTrackedRaceForPolarSheetGeneration();
|
||||
return trackedRace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class MockTrackedRaceForPolarSheetGeneration extends MockedTrackedRace {
|
||||
|
||||
|
||||
@Override
|
||||
public DynamicGPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor) {
|
||||
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = new MockDynamicGPSFixMovinTrackForPolarSheetGeneration<Competitor>(competitor, 0);
|
||||
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.0, 1.0), new MillisecondsTimePoint(1), new KnotSpeedWithBearingImpl(3.0, new DegreeBearingImpl(-45.0))));
|
||||
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.001, 1.001), new MillisecondsTimePoint(2), new KnotSpeedWithBearingImpl(5.0, new DegreeBearingImpl(-45.0))));
|
||||
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.002, 1.002), new MillisecondsTimePoint(3), new KnotSpeedWithBearingImpl(2.0, new DegreeBearingImpl(-55.0))));
|
||||
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.003, 1.003), new MillisecondsTimePoint(4), new KnotSpeedWithBearingImpl(6.0, new DegreeBearingImpl(-30.0))));
|
||||
|
||||
//Should not be taken into consideration because it happens after the race has ended
|
||||
track.addGPSFix(new GPSFixMovingImpl(new DegreePosition(2.0, 3.0), new MillisecondsTimePoint(7), new KnotSpeedWithBearingImpl(5.0, new DegreeBearingImpl(-45.0))));
|
||||
return track;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind getWind(Position p, TimePoint at) {
|
||||
Wind wind = new WindImpl(p, at, new KnotSpeedWithBearingImpl(2.0, new DegreeBearingImpl(180.0)));
|
||||
return wind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition getRace() {
|
||||
BoatClass forelle = new BoatClassImpl(BOAT_CLASS, true);
|
||||
Competitor competitor = new CompetitorImpl(UUID.randomUUID(), "Hans Frantz", new TeamImpl("SAP", null, null), new BoatImpl("Schnelle Forelle", forelle, "GER000"));
|
||||
ArrayList<Competitor> competitors = new ArrayList<Competitor>();
|
||||
competitors.add(competitor);
|
||||
RaceDefinition race = new RaceDefinitionImpl("Forelle1", new CourseImpl("ForelleCourse", new ArrayList<Waypoint>()), forelle, competitors);
|
||||
return race;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getStartOfRace() {
|
||||
return new MillisecondsTimePoint(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getEndOfRace() {
|
||||
return new MillisecondsTimePoint(5);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class MockGPSFixMovingForPolarSheetGeneration extends GPSFixMovingImpl {
|
||||
|
||||
public MockGPSFixMovingForPolarSheetGeneration(Position position, TimePoint timePoint, SpeedWithBearing speed) {
|
||||
super(position, timePoint, speed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class MockDynamicGPSFixMovinTrackForPolarSheetGeneration<ItemType> extends DynamicGPSFixMovingTrackImpl<ItemType> {
|
||||
|
||||
public MockDynamicGPSFixMovinTrackForPolarSheetGeneration(ItemType trackedItem,
|
||||
long millisecondsOverWhichToAverage) {
|
||||
super(trackedItem, millisecondsOverWhichToAverage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValid(NavigableSet<GPSFixMoving> rawFixes, GPSFixMoving e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2,4 +2,5 @@
|
||||
/.gwt
|
||||
/.generated
|
||||
/gwt-unitCache
|
||||
/extras
|
||||
/com.sap.sailing.gwt.ui.*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
entryPointModules=
|
||||
filesCopiedToWebInfLib=gwt-servlet.jar
|
||||
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDEwMjRtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5BZG1pbkNvbnNvbGU8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmRFZGl0aW5nPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJhY2VCb2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TcGVjdGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVXNlck1hbmFnZW1lbnQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVHZWaWV3PC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlZpZGVvUG9wdXA8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuWW91dHViZVBvcHVwPC9lbnRyeS1wb2ludC1tb2R1bGU+PC9nd3QtY29tcGlsZS1zZXR0aW5ncz4\=
|
||||
eclipse.preferences.version=1
|
||||
entryPointModules=
|
||||
filesCopiedToWebInfLib=gwt-servlet.jar
|
||||
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDEwMjRtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5BZG1pbkNvbnNvbGU8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmRFZGl0aW5nPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJhY2VCb2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TcGVjdGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVXNlck1hbmFnZW1lbnQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVHZWaWV3PC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlZpZGVvUG9wdXA8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuWW91dHViZVBvcHVwPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlBvbGFyU2hlZXRzPC9lbnRyeS1wb2ludC1tb2R1bGU+PC9nd3QtY29tcGlsZS1zZXR0aW5ncz4\=
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
@import url(fontface.css);
|
||||
@import url(CommonControls.css);
|
||||
|
||||
/** Add css rules here for your application. */
|
||||
/*
|
||||
body #calendar:after
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
*/
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
font-size: 1px;
|
||||
height: 0px;
|
||||
line-height: 0px;
|
||||
margin: -1px 0 0;
|
||||
width: 100%; }
|
||||
|
||||
.cover {
|
||||
left: -1000px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: -1000px; }
|
||||
|
||||
body {
|
||||
background: #fff;
|
||||
font-family: 'UbuntuRegular', Arial, Verdana, sans-serif;
|
||||
line-height: 1;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
padding: 85px 0 120px 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/** Example rules used by the template application (remove for your app) */
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: #777777;
|
||||
margin: 40px 0px 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: separate; }
|
||||
|
||||
.leaderboardMargin {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.leaderboardContent {
|
||||
}
|
||||
|
||||
.leaderboardContent td, .leaderboardContent th {
|
||||
vertical-align: bottom;
|
||||
line-height: 1.3;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.leaderboardContent-toolbar {
|
||||
|
||||
}
|
||||
|
||||
.leaderboardLabel {
|
||||
border-bottom: 2px solid #007dc0;
|
||||
font-weight: bold;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.refreshAndSettings {
|
||||
background: #f2f2f2;
|
||||
border-bottom: 2px solid #fff;
|
||||
border-top: 2px solid #fff;
|
||||
height: 30px; }
|
||||
|
||||
.refreshAndSettings table td {
|
||||
padding: 0 10px 0 0;}
|
||||
|
||||
.refreshAndSettings table table td{
|
||||
padding: 0 0 0 0;}
|
||||
|
||||
input.magnifier{
|
||||
display: block;
|
||||
margin: 3px auto 0 auto !important;
|
||||
}
|
||||
|
||||
body, table td, select, button {
|
||||
font-family: 'UbuntuLight', Arial, Verdana, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.busyIndicator-simpleBusyIndicator {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.errorLabel {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.abstractChartPanel-importantMessageOfChart {
|
||||
font-family: 'UbuntuBold',Arial,Verdana,sans-serif;
|
||||
font-size: 20px;
|
||||
height: 70px;
|
||||
margin: 0 auto;
|
||||
padding: 49px 0 0 80px;
|
||||
width: 300px;
|
||||
color: #7c7c7c;
|
||||
background: url(images/important-message.png) left center no-repeat;
|
||||
}
|
||||
|
||||
.LeaderboardHeader {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 400px;
|
||||
text-align: center;
|
||||
font-family: 'UbuntuRegular', Arial, Verdana, sans-serif;
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.leaderboardHeading {
|
||||
font-size: 16px;
|
||||
font-family: 'UbuntuRegular', Arial, Verdana, sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.gwt-DialogBox {
|
||||
z-index: 20;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<title>SAP Sailing Analytics Polar Sheets</title>
|
||||
<meta content='width = device-width, initial-scale = 1.0, user-scalable = yes' name='viewport'>
|
||||
<meta content='yes' name='apple-mobile-web-app-capable'>
|
||||
<meta content='black' name='apple-mobile-web-app-status-bar-style'>
|
||||
<!-- <link href='iphone-splash-screen.png' rel='apple-touch-startup-image'> -->
|
||||
<link href='images/sap-sailing-app-icon.png' rel='apple-touch-icon'>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/sap.ico" />
|
||||
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="highcharts/js/highcharts.js"></script>
|
||||
<script type="text/javascript" src="highcharts/js/highcharts-more.js"></script>
|
||||
|
||||
<!-- Optionally, add a highcharts theme file -->
|
||||
<script type="text/javascript" src="highcharts/js/themes/grid.js"></script>
|
||||
|
||||
<script type="text/javascript" language="javascript" src="com.sap.sailing.gwt.ui.PolarSheets/com.sap.sailing.gwt.ui.PolarSheets.nocache.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
|
||||
<!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
|
||||
<noscript>
|
||||
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
|
||||
Your web browser must have JavaScript enabled
|
||||
in order for this application to display correctly.
|
||||
</div>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,7 +4,7 @@
|
||||
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
||||
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
||||
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
||||
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/AdminConsole.html"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
@@ -48,7 +48,7 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/sapjvm_7"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx1024m -Xdebug -Xrunjdwp:transport=dt_socket,address=7999,server=y"/>
|
||||
</launchConfiguration>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
||||
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
||||
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
||||
<listEntry value="com.sap.sailing.gwt.ui.TvView"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/AdminConsole.html"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
@@ -47,7 +47,7 @@
|
||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/TvView.html com.sap.sailing.gwt.ui.TvView"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/TvView.html com.sap.sailing.gwt.ui.TvView -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -XX:MaxPermSize=512m"/>
|
||||
</launchConfiguration>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 18 KiB |
+32
@@ -0,0 +1,32 @@
|
||||
package com.sap.sailing.gwt.ui.actions;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
|
||||
public class GetPolarSheetDataByAngleAction extends DefaultAsyncAction<PolarSheetsHistogramData> {
|
||||
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final String polarSheetId;
|
||||
private final int angle;
|
||||
private final int windSpeed;
|
||||
|
||||
|
||||
|
||||
public GetPolarSheetDataByAngleAction(SailingServiceAsync sailingService,
|
||||
String polarSheetId, int angle, int windSpeed, AsyncCallback<PolarSheetsHistogramData> callback) {
|
||||
super(callback);
|
||||
this.sailingService = sailingService;
|
||||
this.polarSheetId = polarSheetId;
|
||||
this.angle = angle;
|
||||
this.windSpeed = windSpeed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(AsyncActionsExecutor asyncActionsExecutor) {
|
||||
sailingService.getPolarSheetData(polarSheetId, angle, windSpeed, (AsyncCallback<PolarSheetsHistogramData>) getWrapperCallback(asyncActionsExecutor));
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -14,6 +14,9 @@ import com.sap.sailing.domain.common.Color;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
@@ -283,4 +286,10 @@ public interface SailingService extends RemoteService {
|
||||
List<SwissTimingArchiveConfigurationDTO> getPreviousSwissTimingArchiveConfigurations();
|
||||
|
||||
void storeSwissTimingArchiveConfiguration(String swissTimingUrl);
|
||||
|
||||
PolarSheetGenerationTriggerResponse generatePolarSheetForRaces(List<RegattaAndRaceIdentifier> selectedRaces);
|
||||
|
||||
PolarSheetsData getPolarSheetsGenerationResults(String id);
|
||||
|
||||
PolarSheetsHistogramData getPolarSheetData(String polarSheetId, int angle, int windSpeed);
|
||||
}
|
||||
|
||||
Regular → Executable
+447
-438
@@ -1,438 +1,447 @@
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.Color;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingArchiveConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.CourseDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceCourseMarksDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceColumnInSeriesDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardEntryDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceMapDataDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.ReplicationStateDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaScoreCorrectionDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.ScoreCorrectionProviderDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingReplayRaceDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingRaceRecordDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.VenueDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||
|
||||
/**
|
||||
* The async counterpart of {@link SailingService}
|
||||
*/
|
||||
public interface SailingServiceAsync {
|
||||
|
||||
void getRegattas(AsyncCallback<List<RegattaDTO>> callback);
|
||||
|
||||
/**
|
||||
* The string returned in the callback's pair is the common event name
|
||||
*/
|
||||
void listTracTracRacesInEvent(String eventJsonURL, AsyncCallback<Pair<String, List<TracTracRaceRecordDTO>>> callback);
|
||||
|
||||
/**
|
||||
* @param regattaToAddTo
|
||||
* if <code>null</code>, an existing regatta by the name of the TracTrac event with the boat class name
|
||||
* appended in parentheses will be looked up; if not found, a default regatta with that name will be
|
||||
* created, with a single default series and a single default fleet. If a valid {@link RegattaIdentifier}
|
||||
* is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used
|
||||
* to add the races to. Otherwise, a default regatta as described above will be created and used.
|
||||
* @param liveURI
|
||||
* may be <code>null</code> or the empty string in which case the server will use the
|
||||
* {@link TracTracRaceRecordDTO#liveURI} from the <code>rr</code> race record.
|
||||
* @param simulateWithStartTimeNow
|
||||
* if <code>true</code>, the connector will adjust the time stamps of all events received such that the
|
||||
* first mark passing for the first waypoint will be set to "now." It will delay the forwarding of all
|
||||
* events received such that they seem to be sent in "real-time." So, more or less the time points attached
|
||||
* to the events sent to the receivers will again approximate the wall time.
|
||||
* @param storedURImay
|
||||
* be <code>null</code> or the empty string in which case the server will use the
|
||||
* {@link TracTracRaceRecordDTO#storedURI} from the <code>rr</code> race record.
|
||||
*/
|
||||
void trackWithTracTrac(RegattaIdentifier regattaToAddTo,
|
||||
Iterable<TracTracRaceRecordDTO> rrs, String liveURI, String storedURI, boolean trackWind, boolean correctWindByDeclination,
|
||||
boolean simulateWithStartTimeNow, AsyncCallback<Void> callback);
|
||||
|
||||
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs,
|
||||
String hostname, int port, boolean canSendRequests, boolean trackWind, boolean correctWindByDeclination,
|
||||
AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void replaySwissTimingRace(RegattaIdentifier regattaIdentifier, Iterable<SwissTimingReplayRaceDTO> replayRaces,
|
||||
boolean trackWind, boolean correctWindByDeclination, boolean simulateWithStartTimeNow,
|
||||
AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void getPreviousTracTracConfigurations(AsyncCallback<List<TracTracConfigurationDTO>> callback);
|
||||
|
||||
void storeTracTracConfiguration(String name, String jsonURL, String liveDataURI, String storedDataURI,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void stopTrackingEvent(RegattaIdentifier eventIdentifier, AsyncCallback<Void> callback);
|
||||
|
||||
void stopTrackingRaces(Iterable<RegattaAndRaceIdentifier> racesToStopTracking, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
/**
|
||||
* Untracks the race and removes it from the regatta. It will also be removed in all leaderboards
|
||||
* @param regattaNamesAndRaceNames The identifier for the regatta name, and the race name to remove
|
||||
*/
|
||||
void removeAndUntrackRaces(Iterable<RegattaNameAndRaceName> regattaNamesAndRaceNames, AsyncCallback<Void> callback);
|
||||
|
||||
void getRawWindFixes(RegattaAndRaceIdentifier raceIdentifier, Collection<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 getAveragedWindInfo(RegattaAndRaceIdentifier 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
|
||||
* whose {@link WindSource} name is contained in the <code>windSources</code> collection.
|
||||
*/
|
||||
void getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth, int numberOfFixes,
|
||||
double latDeg, double lngDeg, Collection<String> windSourceTypeNames,
|
||||
AsyncCallback<WindInfoForRaceDTO> callback);
|
||||
|
||||
/**
|
||||
* Same as {@link #getWindInfo(RegattaAndRaceIdentifier, 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 getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth, int numberOfFixes,
|
||||
Collection<String> windSourceTypeNames, AsyncCallback<WindInfoForRaceDTO> callback);
|
||||
|
||||
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind, AsyncCallback<Void> callback);
|
||||
|
||||
void removeWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO windDTO, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* @param from
|
||||
* for the list of competitors provided as keys of this map, requests the GPS fixes starting with the
|
||||
* date provided as value
|
||||
* @param to
|
||||
* for the list of competitors provided as keys (expected to be equal to the set of competitors used as
|
||||
* keys in the <code>from</code> parameter, requests the GPS fixes up to but excluding the date provided
|
||||
* as value
|
||||
* @param extrapolate
|
||||
* if <code>true</code> and no position is known for <code>date</code>, the last entry returned in the
|
||||
* list of GPS fixes will be obtained by extrapolating from the competitors last known position before
|
||||
* <code>date</code> and the estimated speed.
|
||||
* @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>.
|
||||
*/
|
||||
void getBoatPositions(RegattaAndRaceIdentifier raceIdentifier,
|
||||
Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
|
||||
boolean extrapolate, AsyncCallback<Map<CompetitorDTO, List<GPSFixDTO>>> callback);
|
||||
|
||||
void getRaceTimesInfo(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<RaceTimesInfoDTO> callback);
|
||||
|
||||
void getRaceTimesInfos(Collection<RegattaAndRaceIdentifier> raceIdentifiers, AsyncCallback<List<RaceTimesInfoDTO>> callback);
|
||||
|
||||
void getCoursePositions(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<CourseDTO> asyncCallback);
|
||||
|
||||
void getQuickRanks(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<List<QuickRankDTO>> callback);
|
||||
|
||||
/**
|
||||
* Returns a {@link LeaderboardDTO} will information about all races, their points and competitor display names
|
||||
* filled in. The column details are filled for the races whose named are provided in
|
||||
* <code>namesOfRacesForWhichToLoadLegDetails</code>.
|
||||
*
|
||||
* @param date
|
||||
* the time point for the leaderboard data to retrieve, or <code>null</code> for "live mode" which means
|
||||
* that the server will produce whatever it has ready for the currently active live delay set on the
|
||||
* server; in live mode, data served may be taken from caches that lag up to a few seconds.
|
||||
* @param namesOfRaceColumnsForWhichToLoadLegDetails
|
||||
* if <code>null</code>, no {@link LeaderboardEntryDTO#legDetails leg details} will be present in the
|
||||
* result ({@link LeaderboardEntryDTO#legDetails} will be <code>null</code> for all
|
||||
* {@link LeaderboardEntryDTO} objects contained). Otherwise, the {@link LeaderboardEntryDTO#legDetails}
|
||||
* list will contain one entry per leg of the race {@link com.sap.sailing.domain.base.Course} for those race columns whose
|
||||
* {@link com.sap.sailing.domain.base.RaceColumn#getType() name} is contained in <code>namesOfRacesForWhichToLoadLegDetails</code>.
|
||||
* For all other columns, {@link LeaderboardEntryDTO#legDetails} is <code>null</code>.
|
||||
*/
|
||||
void getLeaderboardByName(String leaderboardName, Date date,
|
||||
Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails,
|
||||
AsyncCallback<LeaderboardDTO> callback);
|
||||
|
||||
void getLeaderboardNames(AsyncCallback<List<String>> callback);
|
||||
|
||||
void getLeaderboards(AsyncCallback<List<StrippedLeaderboardDTO>> callback);
|
||||
|
||||
void getLeaderboardsByEvent(RegattaDTO regatta, AsyncCallback<List<StrippedLeaderboardDTO>> callback);
|
||||
|
||||
void getLeaderboardsByRace(RaceDTO race, AsyncCallback<List<StrippedLeaderboardDTO>> callback);
|
||||
|
||||
void updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName,
|
||||
int[] newDiscardingThreasholds, AsyncCallback<Void> callback);
|
||||
|
||||
void createFlexibleLeaderboard(String leaderboardName, int[] discardThresholds, ScoringSchemeType scoringSchemeType,
|
||||
AsyncCallback<StrippedLeaderboardDTO> asyncCallback);
|
||||
|
||||
void createRegattaLeaderboard(RegattaIdentifier regattaIdentifier, int[] discardThresholds,
|
||||
AsyncCallback<StrippedLeaderboardDTO> asyncCallback);
|
||||
|
||||
void removeLeaderboard(String leaderboardName, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void renameLeaderboard(String leaderboardName, String newLeaderboardName, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName, AsyncCallback<Void> callback);
|
||||
|
||||
void removeLeaderboardColumn(String leaderboardName, String columnName, AsyncCallback<Void> callback);
|
||||
|
||||
void connectTrackedRaceToLeaderboardColumn(String leaderboardName, String raceColumnName, String fleetName,
|
||||
RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> asyncCallback);
|
||||
|
||||
/**
|
||||
* The key set of the map returned contains all fleets of the race column identified by the combination of
|
||||
* <code>leaderboardName</code> and <code>raceColumnName</code>. If a value is <code>null</code>, there is no
|
||||
* tracked race currently linked to the fleet in the race column; otherwise, the value is the {@link RaceIdentifier}
|
||||
* of the tracked race currently connected for the fleet whose name is the key. The map returned is never <code>null</code>.
|
||||
*/
|
||||
void getRegattaAndRaceNameOfTrackedRaceConnectedToLeaderboardColumn(String leaderboardName, String raceColumnName,
|
||||
AsyncCallback<Map<String, RegattaAndRaceIdentifier>> callback);
|
||||
|
||||
void disconnectLeaderboardColumnFromTrackedRace(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void updateLeaderboardCarryValue(String leaderboardName, String competitorIdAsString, Double carriedPoints, AsyncCallback<Void> callback);
|
||||
|
||||
void updateLeaderboardMaxPointsReason(String leaderboardName, String competitorIdAsString, String raceColumnName,
|
||||
MaxPointsReason maxPointsReason, Date date, AsyncCallback<Triple<Double, Double, Boolean>> asyncCallback);
|
||||
|
||||
void updateLeaderboardScoreCorrection(String leaderboardName, String competitorIdAsString, String columnName,
|
||||
Double correctedScore, Date date, AsyncCallback<Triple<Double, Double, Boolean>> asyncCallback);
|
||||
|
||||
void updateLeaderboardScoreCorrectionMetadata(String leaderboardName, Date timePointOfLastCorrectionValidity,
|
||||
String comment, AsyncCallback<Void> callback);
|
||||
|
||||
void updateLeaderboardScoreCorrectionsAndMaxPointsReasons(BulkScoreCorrectionDTO updates,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void updateCompetitorDisplayNameInLeaderboard(String leaderboardName, String competitorID, String displayName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void moveLeaderboardColumnUp(String leaderboardName, String columnName, AsyncCallback<Void> callback);
|
||||
|
||||
void moveLeaderboardColumnDown(String leaderboardName, String columnName, AsyncCallback<Void> callback);
|
||||
|
||||
void updateIsMedalRace(String leaderboardName, String columnName, boolean isMedalRace, AsyncCallback<Void> callback);
|
||||
|
||||
void updateRaceDelayToLive(RegattaAndRaceIdentifier regattaAndRaceIdentifier, long delayToLiveInMs, AsyncCallback<Void> callback);
|
||||
|
||||
void updateRacesDelayToLive(List<RegattaAndRaceIdentifier> regattaAndRaceIdentifiers, long delayToLiveInMs, AsyncCallback<Void> callback);
|
||||
|
||||
void getPreviousSwissTimingConfigurations(AsyncCallback<List<SwissTimingConfigurationDTO>> asyncCallback);
|
||||
|
||||
void listSwissTimingRaces(String hostname, int port, boolean canSendRequests,
|
||||
AsyncCallback<List<SwissTimingRaceRecordDTO>> asyncCallback);
|
||||
|
||||
void storeSwissTimingConfiguration(String configName, String hostname, int port, boolean canSendRequests, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void sendSwissTimingDummyRace(String racMessage, String stlMesssage, String ccgMessage, AsyncCallback<Void> callback);
|
||||
|
||||
void getCountryCodes(AsyncCallback<String[]> callback);
|
||||
|
||||
void getDouglasPoints(RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
|
||||
double meters, AsyncCallback<Map<CompetitorDTO, List<GPSFixDTO>>> callback);
|
||||
|
||||
void getManeuvers(RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
|
||||
AsyncCallback<Map<CompetitorDTO, List<ManeuverDTO>>> callback);
|
||||
|
||||
void getLeaderboardGroups(boolean withGeoLocationData, AsyncCallback<List<LeaderboardGroupDTO>> callback);
|
||||
|
||||
void getLeaderboardGroupByName(String groupName, boolean withGeoLocationData,
|
||||
AsyncCallback<LeaderboardGroupDTO> callback);
|
||||
|
||||
/**
|
||||
* Renames the group with the name <code>oldName</code> to the <code>newName</code>.<br />
|
||||
* If there's no group with the name <code>oldName</code> or there's already a group with the name
|
||||
* <code>newName</code> a {@link IllegalArgumentException} is thrown.
|
||||
*/
|
||||
void renameLeaderboardGroup(String oldName, String newName, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* Removes the leaderboard group with the name <code>groupName</code> from the service and the persistant store.
|
||||
*/
|
||||
void removeLeaderboardGroup(String groupName, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* Creates a new group with the name <code>groupname</code>, the description <code>description</code> and an empty list of leaderboards.<br/>
|
||||
* @param displayGroupsInReverseOrder TODO
|
||||
*/
|
||||
void createLeaderboardGroup(String groupName, String description,
|
||||
boolean displayGroupsInReverseOrder, int[] overallLeaderboardDiscardThresholds,
|
||||
ScoringSchemeType overallLeaderboardScoringSchemeType, AsyncCallback<LeaderboardGroupDTO> callback);
|
||||
|
||||
/**
|
||||
* Updates the data of the group with the name <code>oldName</code>.
|
||||
*
|
||||
* @param oldName The old name of the group
|
||||
* @param newName The new name of the group
|
||||
* @param description The new description of the group
|
||||
* @param leaderboardNames The list of names of the new leaderboards of the group
|
||||
*/
|
||||
void updateLeaderboardGroup(String oldName, String newName, String description,
|
||||
List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType, AsyncCallback<Void> callback);
|
||||
|
||||
|
||||
void setRaceIsKnownToStartUpwind(RegattaAndRaceIdentifier raceIdentifier, boolean raceIsKnownToStartUpwind,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void setWindSourcesToExclude(RegattaAndRaceIdentifier raceIdentifier, Iterable<WindSource> windSourcesToExclude,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<CompetitorDTO, Date> from,
|
||||
Map<CompetitorDTO, Date> to, boolean extrapolate, AsyncCallback<RaceMapDataDTO> callback);
|
||||
|
||||
void getReplicaInfo(AsyncCallback<ReplicationStateDTO> callback);
|
||||
|
||||
void startReplicatingFromMaster(String masterName, String exchangeName, int servletPort, int messagingPort,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getEvents(AsyncCallback<List<EventDTO>> callback);
|
||||
|
||||
/**
|
||||
* Creates a {@link EventDTO} for the {@link com.sap.sailing.domain.base.Event} with the name <code>eventName</code>, which contains the
|
||||
* name, the description and a list with {@link RegattaDTO RegattaDTOs} contained in the event.<br />
|
||||
* If no event with the name <code>eventName</code> is known, an {@link IllegalArgumentException} is thrown.
|
||||
*/
|
||||
void getEventByName(String eventName, AsyncCallback<EventDTO> callback);
|
||||
|
||||
/**
|
||||
* Renames the event with the name <code>oldName</code> to the <code>newName</code>.<br />
|
||||
* If there's no event with the name <code>oldName</code> or there's already a event with the name
|
||||
* <code>newName</code> a {@link IllegalArgumentException} is thrown.
|
||||
*/
|
||||
void renameEvent(String oldName, String newName, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* Removes the event with the name <code>eventName</code> from the service and the persistence store.
|
||||
*/
|
||||
void removeEvent(String eventName, AsyncCallback<Void> callback);
|
||||
|
||||
void createEvent(String eventName, String description, String publicationUrl, boolean isPublic, AsyncCallback<EventDTO> callback);
|
||||
|
||||
void updateEvent(String eventName, Serializable id, VenueDTO venue, String publicationUrl, boolean isPublic,
|
||||
List<String> regattaNames, AsyncCallback<Void> callback);
|
||||
|
||||
void removeRegatta(RegattaIdentifier regattaIdentifier, AsyncCallback<Void> callback);
|
||||
|
||||
void addRaceColumnToSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<RaceColumnInSeriesDTO> callback);
|
||||
|
||||
void removeRaceColumnFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void moveRaceColumnInSeriesUp(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void moveRaceColumnInSeriesDown(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void createRegatta(String regattaName, String boatClassName,
|
||||
LinkedHashMap<String, Pair<List<Triple<String, Integer, Color>>, Boolean>> seriesNamesWithFleetNamesAndFleetOrderingAndMedal,
|
||||
boolean persistent, ScoringSchemeType scoringSchemeType, AsyncCallback<RegattaDTO> callback);
|
||||
|
||||
void addRaceColumnsToSeries(RegattaIdentifier regattaIdentifier, String seriesName, List<String> columnNames,
|
||||
AsyncCallback<List<RaceColumnInSeriesDTO>> callback);
|
||||
|
||||
void removeRaceColumnsFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, List<String> columnNames,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getScoreCorrectionProviderDTOs(AsyncCallback<Iterable<ScoreCorrectionProviderDTO>> callback);
|
||||
|
||||
void getScoreCorrections(String scoreCorrectionProviderName, String eventName, String boatClassName,
|
||||
Date timePointWhenResultPublished, AsyncCallback<RegattaScoreCorrectionDTO> asyncCallback);
|
||||
|
||||
void getWindSourcesInfo(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<WindInfoForRaceDTO> callback);
|
||||
|
||||
void getRaceCourse(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<List<ControlPointDTO>> callback);
|
||||
|
||||
void updateRaceCourse(RegattaAndRaceIdentifier raceIdentifier, List<ControlPointDTO> controlPoints, AsyncCallback<Void> callback);
|
||||
|
||||
void getFregResultUrls(AsyncCallback<List<String>> asyncCallback);
|
||||
|
||||
void removeFregURLs(Set<String> toRemove, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void addFragUrl(String result, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void getRaceCourseMarks(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<RaceCourseMarksDTO> callback);
|
||||
|
||||
void addColumnsToLeaderboard(String leaderboardName, List<Pair<String, Boolean>> columnsToAdd,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void removeLeaderboardColumns(String leaderboardName, List<String> columnsToRemove, AsyncCallback<Void> callback);
|
||||
|
||||
void getLeaderboard(String leaderboardName, AsyncCallback<StrippedLeaderboardDTO> callback);
|
||||
|
||||
void suppressCompetitorInLeaderboard(String leaderboardName, String competitorIdAsString, boolean suppressed, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double newFactor,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void listSwissTiminigReplayRaces(String swissTimingUrl, AsyncCallback<List<SwissTimingReplayRaceDTO>> asyncCallback);
|
||||
|
||||
void getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(String leaderboardName, Date date,
|
||||
AsyncCallback<List<Pair<String, List<CompetitorDTO>>>> callback);
|
||||
|
||||
void getCompetitorsRaceData(RegattaAndRaceIdentifier race, List<CompetitorDTO> competitors, Date from, Date to,
|
||||
long stepSize, DetailType detailType, String leaderboarGroupName, String leaderboardName, AsyncCallback<CompetitorsRaceDataDTO> callback);
|
||||
|
||||
/**
|
||||
* Finds out the names of all {@link com.sap.sailing.domain.leaderboard.MetaLeaderboard}s managed by this server that
|
||||
* {@link com.sap.sailing.domain.leaderboard.MetaLeaderboard#getLeaderboards() contain} the leaderboard identified by <code>leaderboardName</code>. The
|
||||
* names of those meta-leaderboards are returned. The list returned is never <code>null</code> but may be empty if no such
|
||||
* leaderboard is found.
|
||||
*/
|
||||
void getOverallLeaderboardNamesContaining(String leaderboardName, AsyncCallback<List<String>> asyncCallback);
|
||||
|
||||
void getPreviousSwissTimingArchiveConfigurations(
|
||||
AsyncCallback<List<SwissTimingArchiveConfigurationDTO>> asyncCallback);
|
||||
|
||||
void storeSwissTimingArchiveConfiguration(String swissTimingUrl, AsyncCallback<Void> asyncCallback);
|
||||
}
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.Color;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.CourseDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardEntryDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceColumnInSeriesDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceCourseMarksDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceMapDataDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaScoreCorrectionDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.ReplicationStateDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.ScoreCorrectionProviderDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingArchiveConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingRaceRecordDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingReplayRaceDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.VenueDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||
|
||||
/**
|
||||
* The async counterpart of {@link SailingService}
|
||||
*/
|
||||
public interface SailingServiceAsync {
|
||||
|
||||
void getRegattas(AsyncCallback<List<RegattaDTO>> callback);
|
||||
|
||||
/**
|
||||
* The string returned in the callback's pair is the common event name
|
||||
*/
|
||||
void listTracTracRacesInEvent(String eventJsonURL, AsyncCallback<Pair<String, List<TracTracRaceRecordDTO>>> callback);
|
||||
|
||||
/**
|
||||
* @param regattaToAddTo
|
||||
* if <code>null</code>, an existing regatta by the name of the TracTrac event with the boat class name
|
||||
* appended in parentheses will be looked up; if not found, a default regatta with that name will be
|
||||
* created, with a single default series and a single default fleet. If a valid {@link RegattaIdentifier}
|
||||
* is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used
|
||||
* to add the races to. Otherwise, a default regatta as described above will be created and used.
|
||||
* @param liveURI
|
||||
* may be <code>null</code> or the empty string in which case the server will use the
|
||||
* {@link TracTracRaceRecordDTO#liveURI} from the <code>rr</code> race record.
|
||||
* @param simulateWithStartTimeNow
|
||||
* if <code>true</code>, the connector will adjust the time stamps of all events received such that the
|
||||
* first mark passing for the first waypoint will be set to "now." It will delay the forwarding of all
|
||||
* events received such that they seem to be sent in "real-time." So, more or less the time points attached
|
||||
* to the events sent to the receivers will again approximate the wall time.
|
||||
* @param storedURImay
|
||||
* be <code>null</code> or the empty string in which case the server will use the
|
||||
* {@link TracTracRaceRecordDTO#storedURI} from the <code>rr</code> race record.
|
||||
*/
|
||||
void trackWithTracTrac(RegattaIdentifier regattaToAddTo,
|
||||
Iterable<TracTracRaceRecordDTO> rrs, String liveURI, String storedURI, boolean trackWind, boolean correctWindByDeclination,
|
||||
boolean simulateWithStartTimeNow, AsyncCallback<Void> callback);
|
||||
|
||||
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs,
|
||||
String hostname, int port, boolean canSendRequests, boolean trackWind, boolean correctWindByDeclination,
|
||||
AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void replaySwissTimingRace(RegattaIdentifier regattaIdentifier, Iterable<SwissTimingReplayRaceDTO> replayRaces,
|
||||
boolean trackWind, boolean correctWindByDeclination, boolean simulateWithStartTimeNow,
|
||||
AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void getPreviousTracTracConfigurations(AsyncCallback<List<TracTracConfigurationDTO>> callback);
|
||||
|
||||
void storeTracTracConfiguration(String name, String jsonURL, String liveDataURI, String storedDataURI,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void stopTrackingEvent(RegattaIdentifier eventIdentifier, AsyncCallback<Void> callback);
|
||||
|
||||
void stopTrackingRaces(Iterable<RegattaAndRaceIdentifier> racesToStopTracking, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
/**
|
||||
* Untracks the race and removes it from the regatta. It will also be removed in all leaderboards
|
||||
* @param regattaNamesAndRaceNames The identifier for the regatta name, and the race name to remove
|
||||
*/
|
||||
void removeAndUntrackRaces(Iterable<RegattaNameAndRaceName> regattaNamesAndRaceNames, AsyncCallback<Void> callback);
|
||||
|
||||
void getRawWindFixes(RegattaAndRaceIdentifier raceIdentifier, Collection<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 getAveragedWindInfo(RegattaAndRaceIdentifier 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
|
||||
* whose {@link WindSource} name is contained in the <code>windSources</code> collection.
|
||||
*/
|
||||
void getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth, int numberOfFixes,
|
||||
double latDeg, double lngDeg, Collection<String> windSourceTypeNames,
|
||||
AsyncCallback<WindInfoForRaceDTO> callback);
|
||||
|
||||
/**
|
||||
* Same as {@link #getWindInfo(RegattaAndRaceIdentifier, 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 getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth, int numberOfFixes,
|
||||
Collection<String> windSourceTypeNames, AsyncCallback<WindInfoForRaceDTO> callback);
|
||||
|
||||
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind, AsyncCallback<Void> callback);
|
||||
|
||||
void removeWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO windDTO, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* @param from
|
||||
* for the list of competitors provided as keys of this map, requests the GPS fixes starting with the
|
||||
* date provided as value
|
||||
* @param to
|
||||
* for the list of competitors provided as keys (expected to be equal to the set of competitors used as
|
||||
* keys in the <code>from</code> parameter, requests the GPS fixes up to but excluding the date provided
|
||||
* as value
|
||||
* @param extrapolate
|
||||
* if <code>true</code> and no position is known for <code>date</code>, the last entry returned in the
|
||||
* list of GPS fixes will be obtained by extrapolating from the competitors last known position before
|
||||
* <code>date</code> and the estimated speed.
|
||||
* @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>.
|
||||
*/
|
||||
void getBoatPositions(RegattaAndRaceIdentifier raceIdentifier,
|
||||
Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
|
||||
boolean extrapolate, AsyncCallback<Map<CompetitorDTO, List<GPSFixDTO>>> callback);
|
||||
|
||||
void getRaceTimesInfo(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<RaceTimesInfoDTO> callback);
|
||||
|
||||
void getRaceTimesInfos(Collection<RegattaAndRaceIdentifier> raceIdentifiers, AsyncCallback<List<RaceTimesInfoDTO>> callback);
|
||||
|
||||
void getCoursePositions(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<CourseDTO> asyncCallback);
|
||||
|
||||
void getQuickRanks(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<List<QuickRankDTO>> callback);
|
||||
|
||||
/**
|
||||
* Returns a {@link LeaderboardDTO} will information about all races, their points and competitor display names
|
||||
* filled in. The column details are filled for the races whose named are provided in
|
||||
* <code>namesOfRacesForWhichToLoadLegDetails</code>.
|
||||
*
|
||||
* @param date
|
||||
* the time point for the leaderboard data to retrieve, or <code>null</code> for "live mode" which means
|
||||
* that the server will produce whatever it has ready for the currently active live delay set on the
|
||||
* server; in live mode, data served may be taken from caches that lag up to a few seconds.
|
||||
* @param namesOfRaceColumnsForWhichToLoadLegDetails
|
||||
* if <code>null</code>, no {@link LeaderboardEntryDTO#legDetails leg details} will be present in the
|
||||
* result ({@link LeaderboardEntryDTO#legDetails} will be <code>null</code> for all
|
||||
* {@link LeaderboardEntryDTO} objects contained). Otherwise, the {@link LeaderboardEntryDTO#legDetails}
|
||||
* list will contain one entry per leg of the race {@link com.sap.sailing.domain.base.Course} for those race columns whose
|
||||
* {@link com.sap.sailing.domain.base.RaceColumn#getType() name} is contained in <code>namesOfRacesForWhichToLoadLegDetails</code>.
|
||||
* For all other columns, {@link LeaderboardEntryDTO#legDetails} is <code>null</code>.
|
||||
*/
|
||||
void getLeaderboardByName(String leaderboardName, Date date,
|
||||
Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails,
|
||||
AsyncCallback<LeaderboardDTO> callback);
|
||||
|
||||
void getLeaderboardNames(AsyncCallback<List<String>> callback);
|
||||
|
||||
void getLeaderboards(AsyncCallback<List<StrippedLeaderboardDTO>> callback);
|
||||
|
||||
void getLeaderboardsByEvent(RegattaDTO regatta, AsyncCallback<List<StrippedLeaderboardDTO>> callback);
|
||||
|
||||
void getLeaderboardsByRace(RaceDTO race, AsyncCallback<List<StrippedLeaderboardDTO>> callback);
|
||||
|
||||
void updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName,
|
||||
int[] newDiscardingThreasholds, AsyncCallback<Void> callback);
|
||||
|
||||
void createFlexibleLeaderboard(String leaderboardName, int[] discardThresholds, ScoringSchemeType scoringSchemeType,
|
||||
AsyncCallback<StrippedLeaderboardDTO> asyncCallback);
|
||||
|
||||
void createRegattaLeaderboard(RegattaIdentifier regattaIdentifier, int[] discardThresholds,
|
||||
AsyncCallback<StrippedLeaderboardDTO> asyncCallback);
|
||||
|
||||
void removeLeaderboard(String leaderboardName, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void renameLeaderboard(String leaderboardName, String newLeaderboardName, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName, AsyncCallback<Void> callback);
|
||||
|
||||
void removeLeaderboardColumn(String leaderboardName, String columnName, AsyncCallback<Void> callback);
|
||||
|
||||
void connectTrackedRaceToLeaderboardColumn(String leaderboardName, String raceColumnName, String fleetName,
|
||||
RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> asyncCallback);
|
||||
|
||||
/**
|
||||
* The key set of the map returned contains all fleets of the race column identified by the combination of
|
||||
* <code>leaderboardName</code> and <code>raceColumnName</code>. If a value is <code>null</code>, there is no
|
||||
* tracked race currently linked to the fleet in the race column; otherwise, the value is the {@link RaceIdentifier}
|
||||
* of the tracked race currently connected for the fleet whose name is the key. The map returned is never <code>null</code>.
|
||||
*/
|
||||
void getRegattaAndRaceNameOfTrackedRaceConnectedToLeaderboardColumn(String leaderboardName, String raceColumnName,
|
||||
AsyncCallback<Map<String, RegattaAndRaceIdentifier>> callback);
|
||||
|
||||
void disconnectLeaderboardColumnFromTrackedRace(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void updateLeaderboardCarryValue(String leaderboardName, String competitorIdAsString, Double carriedPoints, AsyncCallback<Void> callback);
|
||||
|
||||
void updateLeaderboardMaxPointsReason(String leaderboardName, String competitorIdAsString, String raceColumnName,
|
||||
MaxPointsReason maxPointsReason, Date date, AsyncCallback<Triple<Double, Double, Boolean>> asyncCallback);
|
||||
|
||||
void updateLeaderboardScoreCorrection(String leaderboardName, String competitorIdAsString, String columnName,
|
||||
Double correctedScore, Date date, AsyncCallback<Triple<Double, Double, Boolean>> asyncCallback);
|
||||
|
||||
void updateLeaderboardScoreCorrectionMetadata(String leaderboardName, Date timePointOfLastCorrectionValidity,
|
||||
String comment, AsyncCallback<Void> callback);
|
||||
|
||||
void updateLeaderboardScoreCorrectionsAndMaxPointsReasons(BulkScoreCorrectionDTO updates,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void updateCompetitorDisplayNameInLeaderboard(String leaderboardName, String competitorID, String displayName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void moveLeaderboardColumnUp(String leaderboardName, String columnName, AsyncCallback<Void> callback);
|
||||
|
||||
void moveLeaderboardColumnDown(String leaderboardName, String columnName, AsyncCallback<Void> callback);
|
||||
|
||||
void updateIsMedalRace(String leaderboardName, String columnName, boolean isMedalRace, AsyncCallback<Void> callback);
|
||||
|
||||
void updateRaceDelayToLive(RegattaAndRaceIdentifier regattaAndRaceIdentifier, long delayToLiveInMs, AsyncCallback<Void> callback);
|
||||
|
||||
void updateRacesDelayToLive(List<RegattaAndRaceIdentifier> regattaAndRaceIdentifiers, long delayToLiveInMs, AsyncCallback<Void> callback);
|
||||
|
||||
void getPreviousSwissTimingConfigurations(AsyncCallback<List<SwissTimingConfigurationDTO>> asyncCallback);
|
||||
|
||||
void listSwissTimingRaces(String hostname, int port, boolean canSendRequests,
|
||||
AsyncCallback<List<SwissTimingRaceRecordDTO>> asyncCallback);
|
||||
|
||||
void storeSwissTimingConfiguration(String configName, String hostname, int port, boolean canSendRequests, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void sendSwissTimingDummyRace(String racMessage, String stlMesssage, String ccgMessage, AsyncCallback<Void> callback);
|
||||
|
||||
void getCountryCodes(AsyncCallback<String[]> callback);
|
||||
|
||||
void getDouglasPoints(RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
|
||||
double meters, AsyncCallback<Map<CompetitorDTO, List<GPSFixDTO>>> callback);
|
||||
|
||||
void getManeuvers(RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
|
||||
AsyncCallback<Map<CompetitorDTO, List<ManeuverDTO>>> callback);
|
||||
|
||||
void getLeaderboardGroups(boolean withGeoLocationData, AsyncCallback<List<LeaderboardGroupDTO>> callback);
|
||||
|
||||
void getLeaderboardGroupByName(String groupName, boolean withGeoLocationData,
|
||||
AsyncCallback<LeaderboardGroupDTO> callback);
|
||||
|
||||
/**
|
||||
* Renames the group with the name <code>oldName</code> to the <code>newName</code>.<br />
|
||||
* If there's no group with the name <code>oldName</code> or there's already a group with the name
|
||||
* <code>newName</code> a {@link IllegalArgumentException} is thrown.
|
||||
*/
|
||||
void renameLeaderboardGroup(String oldName, String newName, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* Removes the leaderboard group with the name <code>groupName</code> from the service and the persistant store.
|
||||
*/
|
||||
void removeLeaderboardGroup(String groupName, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* Creates a new group with the name <code>groupname</code>, the description <code>description</code> and an empty list of leaderboards.<br/>
|
||||
* @param displayGroupsInReverseOrder TODO
|
||||
*/
|
||||
void createLeaderboardGroup(String groupName, String description,
|
||||
boolean displayGroupsInReverseOrder, int[] overallLeaderboardDiscardThresholds,
|
||||
ScoringSchemeType overallLeaderboardScoringSchemeType, AsyncCallback<LeaderboardGroupDTO> callback);
|
||||
|
||||
/**
|
||||
* Updates the data of the group with the name <code>oldName</code>.
|
||||
*
|
||||
* @param oldName The old name of the group
|
||||
* @param newName The new name of the group
|
||||
* @param description The new description of the group
|
||||
* @param leaderboardNames The list of names of the new leaderboards of the group
|
||||
*/
|
||||
void updateLeaderboardGroup(String oldName, String newName, String description,
|
||||
List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType, AsyncCallback<Void> callback);
|
||||
|
||||
|
||||
void setRaceIsKnownToStartUpwind(RegattaAndRaceIdentifier raceIdentifier, boolean raceIsKnownToStartUpwind,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void setWindSourcesToExclude(RegattaAndRaceIdentifier raceIdentifier, Iterable<WindSource> windSourcesToExclude,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<CompetitorDTO, Date> from,
|
||||
Map<CompetitorDTO, Date> to, boolean extrapolate, AsyncCallback<RaceMapDataDTO> callback);
|
||||
|
||||
void getReplicaInfo(AsyncCallback<ReplicationStateDTO> callback);
|
||||
|
||||
void startReplicatingFromMaster(String masterName, String exchangeName, int servletPort, int messagingPort,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getEvents(AsyncCallback<List<EventDTO>> callback);
|
||||
|
||||
/**
|
||||
* Creates a {@link EventDTO} for the {@link com.sap.sailing.domain.base.Event} with the name <code>eventName</code>, which contains the
|
||||
* name, the description and a list with {@link RegattaDTO RegattaDTOs} contained in the event.<br />
|
||||
* If no event with the name <code>eventName</code> is known, an {@link IllegalArgumentException} is thrown.
|
||||
*/
|
||||
void getEventByName(String eventName, AsyncCallback<EventDTO> callback);
|
||||
|
||||
/**
|
||||
* Renames the event with the name <code>oldName</code> to the <code>newName</code>.<br />
|
||||
* If there's no event with the name <code>oldName</code> or there's already a event with the name
|
||||
* <code>newName</code> a {@link IllegalArgumentException} is thrown.
|
||||
*/
|
||||
void renameEvent(String oldName, String newName, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* Removes the event with the name <code>eventName</code> from the service and the persistence store.
|
||||
*/
|
||||
void removeEvent(String eventName, AsyncCallback<Void> callback);
|
||||
|
||||
void createEvent(String eventName, String description, String publicationUrl, boolean isPublic, AsyncCallback<EventDTO> callback);
|
||||
|
||||
void updateEvent(String eventName, Serializable id, VenueDTO venue, String publicationUrl, boolean isPublic,
|
||||
List<String> regattaNames, AsyncCallback<Void> callback);
|
||||
|
||||
void removeRegatta(RegattaIdentifier regattaIdentifier, AsyncCallback<Void> callback);
|
||||
|
||||
void addRaceColumnToSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<RaceColumnInSeriesDTO> callback);
|
||||
|
||||
void removeRaceColumnFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void moveRaceColumnInSeriesUp(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void moveRaceColumnInSeriesDown(RegattaIdentifier regattaIdentifier, String seriesName, String columnName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void createRegatta(String regattaName, String boatClassName,
|
||||
LinkedHashMap<String, Pair<List<Triple<String, Integer, Color>>, Boolean>> seriesNamesWithFleetNamesAndFleetOrderingAndMedal,
|
||||
boolean persistent, ScoringSchemeType scoringSchemeType, AsyncCallback<RegattaDTO> callback);
|
||||
|
||||
void addRaceColumnsToSeries(RegattaIdentifier regattaIdentifier, String seriesName, List<String> columnNames,
|
||||
AsyncCallback<List<RaceColumnInSeriesDTO>> callback);
|
||||
|
||||
void removeRaceColumnsFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, List<String> columnNames,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getScoreCorrectionProviderDTOs(AsyncCallback<Iterable<ScoreCorrectionProviderDTO>> callback);
|
||||
|
||||
void getScoreCorrections(String scoreCorrectionProviderName, String eventName, String boatClassName,
|
||||
Date timePointWhenResultPublished, AsyncCallback<RegattaScoreCorrectionDTO> asyncCallback);
|
||||
|
||||
void getWindSourcesInfo(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<WindInfoForRaceDTO> callback);
|
||||
|
||||
void getRaceCourse(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<List<ControlPointDTO>> callback);
|
||||
|
||||
void updateRaceCourse(RegattaAndRaceIdentifier raceIdentifier, List<ControlPointDTO> controlPoints, AsyncCallback<Void> callback);
|
||||
|
||||
void getFregResultUrls(AsyncCallback<List<String>> asyncCallback);
|
||||
|
||||
void removeFregURLs(Set<String> toRemove, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void addFragUrl(String result, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void getRaceCourseMarks(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<RaceCourseMarksDTO> callback);
|
||||
|
||||
void addColumnsToLeaderboard(String leaderboardName, List<Pair<String, Boolean>> columnsToAdd,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void removeLeaderboardColumns(String leaderboardName, List<String> columnsToRemove, AsyncCallback<Void> callback);
|
||||
|
||||
void getLeaderboard(String leaderboardName, AsyncCallback<StrippedLeaderboardDTO> callback);
|
||||
|
||||
void suppressCompetitorInLeaderboard(String leaderboardName, String competitorIdAsString, boolean suppressed, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double newFactor,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void listSwissTiminigReplayRaces(String swissTimingUrl, AsyncCallback<List<SwissTimingReplayRaceDTO>> asyncCallback);
|
||||
|
||||
void getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(String leaderboardName, Date date,
|
||||
AsyncCallback<List<Pair<String, List<CompetitorDTO>>>> callback);
|
||||
|
||||
void getCompetitorsRaceData(RegattaAndRaceIdentifier race, List<CompetitorDTO> competitors, Date from, Date to,
|
||||
long stepSize, DetailType detailType, String leaderboarGroupName, String leaderboardName, AsyncCallback<CompetitorsRaceDataDTO> callback);
|
||||
|
||||
/**
|
||||
* Finds out the names of all {@link com.sap.sailing.domain.leaderboard.MetaLeaderboard}s managed by this server that
|
||||
* {@link com.sap.sailing.domain.leaderboard.MetaLeaderboard#getLeaderboards() contain} the leaderboard identified by <code>leaderboardName</code>. The
|
||||
* names of those meta-leaderboards are returned. The list returned is never <code>null</code> but may be empty if no such
|
||||
* leaderboard is found.
|
||||
*/
|
||||
void getOverallLeaderboardNamesContaining(String leaderboardName, AsyncCallback<List<String>> asyncCallback);
|
||||
|
||||
void getPreviousSwissTimingArchiveConfigurations(
|
||||
AsyncCallback<List<SwissTimingArchiveConfigurationDTO>> asyncCallback);
|
||||
|
||||
void storeSwissTimingArchiveConfiguration(String swissTimingUrl, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void generatePolarSheetForRaces(List<RegattaAndRaceIdentifier> selectedRaces, AsyncCallback<PolarSheetGenerationTriggerResponse> asyncCallback);
|
||||
|
||||
void getPolarSheetsGenerationResults(String id, AsyncCallback<PolarSheetsData> asyncCallback);
|
||||
|
||||
void getPolarSheetData(String polarSheetId, int angle, int windSpeed, AsyncCallback<PolarSheetsHistogramData> wrapperCallback);
|
||||
}
|
||||
|
||||
+5
-2
@@ -482,6 +482,8 @@ public interface StringMessages extends Messages {
|
||||
String gapChangeSinceLegStartInSecondsTooltip();
|
||||
String velocityMadeGoodInKnotsTooltip();
|
||||
String sideToWhichMarkAtLegStartWasRoundedTooltip();
|
||||
String generatePolarSheet();
|
||||
String polarSheetChart();
|
||||
String numberOfManeuversInRaceTooltip();
|
||||
String competitorColumnTooltip();
|
||||
String sailIdColumnTooltip();
|
||||
@@ -497,6 +499,7 @@ public interface StringMessages extends Messages {
|
||||
String overallRankTooltip();
|
||||
String noDataFound();
|
||||
String displayName();
|
||||
String buoyZone();
|
||||
String radiusInMeters();
|
||||
String histogram();
|
||||
String numberOfDataPoints();
|
||||
String angleAndTotalNumberOfDataPoints(int angle, int numberOfDataPoints);
|
||||
}
|
||||
|
||||
+6
-2
@@ -486,8 +486,11 @@ sideToWhichMarkAtLegStartWasRounded=Mark rounded to
|
||||
sideToWhichMarkAtLegStartWasRoundedTooltip=Side to which the mark at leg start was rounded.
|
||||
raceIsLive=Race {0} is live
|
||||
racesAreLive=Races {0} are live
|
||||
knotsUnit=kts
|
||||
scoringSchemeHighPointFirstGetsTen=High Point, winner gets 10 points
|
||||
knotsUnit=kts
|
||||
generatePolarSheet=Generate Polar Sheet
|
||||
polarSheetChart=Polar Sheet
|
||||
competitorColumnTooltip=Names of the members of this competitor.
|
||||
sailIdColumnTooltip=Shows the flag of the country and the sail number of the competitor.
|
||||
rankColumnTooltip=The overall rank of this competitor in the regatta.
|
||||
@@ -498,5 +501,6 @@ gpsData=GPS data
|
||||
status=Status
|
||||
noDataFound=No data found
|
||||
displayName=Display name
|
||||
buoyZone=Buoy zone
|
||||
radiusInMeters=Radius (m)
|
||||
histogram=Histogram
|
||||
numberOfDataPoints=Number of data points
|
||||
angleAndTotalNumberOfDataPoints=Angle: {0}; Total number of data-points: {1}
|
||||
+5
-2
@@ -489,6 +489,8 @@ raceIsLive=Rennen {0} ist live
|
||||
racesAreLive=Rennen {0} sind live
|
||||
scoringSchemeHighPointFirstGetsTen=High Point System, Gewinner erhält 10 Punkte
|
||||
knotsUnit=kn
|
||||
generatePolarSheet=Polardiagramm erstellen
|
||||
polarSheetChart=Polardiagramm
|
||||
competitorColumnTooltip=Namen der Segler dieses Teilnehmers
|
||||
sailIdColumnTooltip=Zeigt die Länderflagge und die Segelnummer des Teilnehmers
|
||||
rankColumnTooltip=Der Gesamtplatz des Teilnehmers in der Regatta
|
||||
@@ -499,5 +501,6 @@ gpsData=GPS-Daten
|
||||
status=Status
|
||||
noDataFound=Keine Daten gefunden
|
||||
displayName=Anzeigename
|
||||
buoyZone=Bojenzone
|
||||
radiusInMeters=Radius (m)
|
||||
histogram=Histogramm
|
||||
numberOfDataPoints=Anzahl Datenpunkte
|
||||
angleAndTotalNumberOfDataPoints=Winkel: {0}; Anzahl Datenpunkte: {1}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.sap.sailing.gwt.ui.polarsheets;
|
||||
|
||||
import com.sap.sailing.gwt.ui.adminconsole.AbstractTrackedRacesListComposite;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
||||
|
||||
public abstract class AbstractFilteredTrackedRacesList extends AbstractTrackedRacesListComposite {
|
||||
|
||||
private RaceFilter filter;
|
||||
|
||||
public AbstractFilteredTrackedRacesList(SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
RegattaRefresher regattaRefresher, RaceSelectionProvider raceSelectionProvider,
|
||||
StringMessages stringMessages, boolean hasMultiSelection, RaceFilter filter) {
|
||||
super(sailingService, errorReporter, regattaRefresher, raceSelectionProvider, stringMessages, hasMultiSelection);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean raceIsToBeAddedToList(RaceDTO race) {
|
||||
if (filter!=null) {
|
||||
return filter.compliesToFilter(race);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package com.sap.sailing.gwt.ui.polarsheets;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.Chart;
|
||||
import org.moxieapps.gwt.highcharts.client.Color;
|
||||
import org.moxieapps.gwt.highcharts.client.Point;
|
||||
import org.moxieapps.gwt.highcharts.client.Series;
|
||||
import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEventHandler;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.LinePlotOptions;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.SeriesPlotOptions;
|
||||
|
||||
import com.google.gwt.user.client.ui.RequiresResize;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public class PolarSheetsChartPanel extends SimplePanel implements RequiresResize {
|
||||
|
||||
private StringMessages stringMessages;
|
||||
private Chart chart;
|
||||
private Map<String, Series[]> seriesMap;
|
||||
|
||||
public PolarSheetsChartPanel(StringMessages stringMessages) {
|
||||
this.stringMessages = stringMessages;
|
||||
setPixelSize(800, 800);
|
||||
chart = createPolarSheetChart();
|
||||
seriesMap = new HashMap<String, Series[]>();
|
||||
setWidget(chart);
|
||||
}
|
||||
|
||||
private Chart createPolarSheetChart() {
|
||||
Chart polarSheetChart = new Chart().setType(Series.Type.LINE)
|
||||
.setLinePlotOptions(new LinePlotOptions().setLineWidth(1)).setZoomType(Chart.ZoomType.X_AND_Y)
|
||||
.setPolar(true).setSize(800, 800);
|
||||
polarSheetChart.setChartTitleText(stringMessages.polarSheetChart());
|
||||
polarSheetChart.getYAxis().setMin(0);
|
||||
return polarSheetChart;
|
||||
}
|
||||
|
||||
private void newSeriesArray(String name) {
|
||||
if (!seriesMap.containsKey(name)) {
|
||||
Series[] seriesPerWindSpeed = new Series[13];
|
||||
seriesMap.put(name, seriesPerWindSpeed);
|
||||
} else {
|
||||
// TODO exception handling
|
||||
}
|
||||
}
|
||||
|
||||
private void createSeriesForWindspeed(String name, int windSpeed) {
|
||||
Series[] seriesPerWindSpeed = seriesMap.get(name);
|
||||
Number[] forEachDeg = initializeDataForNewSeries();
|
||||
seriesPerWindSpeed[windSpeed] = chart.createSeries().setPoints(forEachDeg);
|
||||
seriesPerWindSpeed[windSpeed].setName(name + "-" + (windSpeed));
|
||||
chart.addSeries(seriesPerWindSpeed[windSpeed]);
|
||||
}
|
||||
|
||||
private Number[] initializeDataForNewSeries() {
|
||||
Number[] forEachDeg = new Number[360];
|
||||
return forEachDeg;
|
||||
}
|
||||
|
||||
private void addValuesToSeries(String seriesId, PolarSheetsData result) {
|
||||
if (seriesMap.containsKey(seriesId)) {
|
||||
for (int i = 0; i < 13; i++) {
|
||||
if (hasSufficientDataForWindspeed(result.getDataCountPerAngleForWindspeed(i), result.getDataCount())) {
|
||||
if (seriesMap.get(seriesId)[i] == null) {
|
||||
createSeriesForWindspeed(seriesId, i);
|
||||
}
|
||||
Series series = seriesMap.get(seriesId)[i];
|
||||
series.setPoints(result.getAveragedPolarDataByWindSpeed()[i], false);
|
||||
Point[] points = createPointsWithMarkerAlphaAccordingToDataCount(result, i);
|
||||
if (points != null) {
|
||||
series.setPoints(points);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSufficientDataForWindspeed(Integer[] dataCountPerAngleForWindspeed, int countOverall) {
|
||||
int sum = 0;
|
||||
for (int count : dataCountPerAngleForWindspeed) {
|
||||
sum = sum + count;
|
||||
}
|
||||
//TODO make configurable
|
||||
if (sum >= (0.05 * countOverall)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Point[] createPointsWithMarkerAlphaAccordingToDataCount(PolarSheetsData result, int beaufort) {
|
||||
Point[] points = new Point[360];
|
||||
List<Integer> dataCountList = Arrays.asList(result.getDataCountPerAngleForWindspeed(beaufort));
|
||||
Integer max = Collections.max(dataCountList);
|
||||
if (max <= 0) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < 360; i++) {
|
||||
points[i] = new Point(result.getAveragedPolarDataByWindSpeed()[beaufort][i]);
|
||||
if (points[i] == null) {
|
||||
points[i] = new Point(0);
|
||||
}
|
||||
double alpha = (double) dataCountList.get(i) / (double) max;
|
||||
int blue;
|
||||
int red;
|
||||
int radius;
|
||||
if (alpha > 0.2) {
|
||||
red = (int) (alpha * 255);
|
||||
blue = 0;
|
||||
radius = 4;
|
||||
} else {
|
||||
blue = (int) ((1 - alpha) * 255);
|
||||
red = 0;
|
||||
radius = 2;
|
||||
}
|
||||
|
||||
// Don't let the markers be invisible
|
||||
alpha = 0.5 + 0.5 * alpha;
|
||||
// TODO maybe set to series color. Not sure if this (highcharts-generated color) can be queried before
|
||||
// rendering
|
||||
points[i].setMarker(new Marker().setFillColor(new Color(red, 0, blue, alpha)).setRadius(radius));
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
public void removeSeries(String seriesId) {
|
||||
if (seriesMap.containsKey(seriesId)) {
|
||||
Series[] seriesPerWindSpeed = seriesMap.get(seriesId);
|
||||
for (Series series : seriesPerWindSpeed) {
|
||||
chart.removeSeries(series);
|
||||
}
|
||||
seriesMap.remove(seriesId);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllSeries() {
|
||||
chart.removeAllSeries();
|
||||
seriesMap.clear();
|
||||
}
|
||||
|
||||
public void setData(String id, PolarSheetsData result) {
|
||||
if (id == null) {
|
||||
// TODO Exception handling
|
||||
return;
|
||||
}
|
||||
if (!seriesMap.containsKey(id)) {
|
||||
newSeriesArray(id);
|
||||
}
|
||||
addValuesToSeries(id, result);
|
||||
chart.redraw();
|
||||
}
|
||||
|
||||
public void setSeriesPointMouseOverHandler(PointMouseOverEventHandler pointMouseOverHandler) {
|
||||
chart.setSeriesPlotOptions(new SeriesPlotOptions().setPointMouseOverEventHandler(pointMouseOverHandler));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResize() {
|
||||
chart.setSizeToMatchContainer();
|
||||
chart.redraw();
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.sap.sailing.gwt.ui.polarsheets;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.RootLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.sap.sailing.gwt.ui.client.AbstractEntryPoint;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaDisplayer;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
|
||||
public class PolarSheetsEntryPoint extends AbstractEntryPoint implements RegattaRefresher {
|
||||
|
||||
// private static final Logger logger =
|
||||
// Logger.getLogger(PolarSheetsEntryPoint.class.getName());
|
||||
|
||||
private Set<RegattaDisplayer> regattaDisplayers;
|
||||
|
||||
@Override
|
||||
protected void doOnModuleLoad() {
|
||||
super.doOnModuleLoad();
|
||||
regattaDisplayers = new HashSet<RegattaDisplayer>();
|
||||
createUI();
|
||||
fillRegattas();
|
||||
}
|
||||
|
||||
private void createUI() {
|
||||
RootPanel rootPanel = RootPanel.get();
|
||||
DockLayoutPanel mainPanel = new DockLayoutPanel(Unit.PX);
|
||||
RootLayoutPanel.get().add(mainPanel);
|
||||
ScrollPanel contentScrollPanel = new ScrollPanel();
|
||||
PolarSheetsPanel polarSheetsPanel = new PolarSheetsPanel(sailingService, this, stringMessages, this);
|
||||
polarSheetsPanel.addStyleName(PolarSheetsPanel.POLARSHEETS_STYLE);
|
||||
regattaDisplayers.add(polarSheetsPanel);
|
||||
contentScrollPanel.setWidget(polarSheetsPanel);
|
||||
mainPanel.add(contentScrollPanel);
|
||||
rootPanel.add(mainPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRegattas() {
|
||||
sailingService.getRegattas(new AsyncCallback<List<RegattaDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(List<RegattaDTO> result) {
|
||||
for (RegattaDisplayer regattaDisplayer : regattaDisplayers) {
|
||||
regattaDisplayer.fillRegattas(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
reportError("Remote Procedure Call getRegattas() - Failure");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.sap.sailing.gwt.ui.polarsheets;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.AxisTitle;
|
||||
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.Legend;
|
||||
import org.moxieapps.gwt.highcharts.client.Point;
|
||||
import org.moxieapps.gwt.highcharts.client.Series;
|
||||
import org.moxieapps.gwt.highcharts.client.Series.Type;
|
||||
import org.moxieapps.gwt.highcharts.client.labels.XAxisLabels;
|
||||
|
||||
import com.google.gwt.user.client.ui.RequiresResize;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public class PolarSheetsHistogramPanel extends SimplePanel implements RequiresResize{
|
||||
|
||||
private final Chart chart;
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public PolarSheetsHistogramPanel(StringMessages stringMessages) {
|
||||
this.stringMessages = stringMessages;
|
||||
setSize("100%", "100%");
|
||||
chart = createHistogramChart();
|
||||
chart.getElement().setAttribute("align", "top");
|
||||
setWidget(chart);
|
||||
}
|
||||
|
||||
private Chart createHistogramChart() {
|
||||
Chart histogramChart = new Chart().setType(Type.COLUMN).setZoomType(Chart.ZoomType.X).setWidth(800);
|
||||
histogramChart.setChartTitleText(stringMessages.histogram());
|
||||
histogramChart.getYAxis().setMin(0).setAxisTitle(new AxisTitle().setText(stringMessages.numberOfDataPoints()));
|
||||
histogramChart.getXAxis().setLabels(new XAxisLabels().setRotation(-90f).setY(10)).setAxisTitle(new AxisTitle().setText(
|
||||
stringMessages.speedInKnots()));
|
||||
histogramChart.setLegend(new Legend().setEnabled(false));
|
||||
return histogramChart;
|
||||
}
|
||||
|
||||
public void setData(PolarSheetsHistogramData data) {
|
||||
chart.removeAllSeries();
|
||||
chart.setTitle(new ChartTitle().setText(stringMessages.histogram()),
|
||||
new ChartSubtitle().setText(stringMessages.angleAndTotalNumberOfDataPoints(data.getAngle(), data.getDataCount())));
|
||||
Point[] points = toPoints(data);
|
||||
Series series = chart.createSeries();
|
||||
series.setPoints(points);
|
||||
chart.addSeries(series);
|
||||
}
|
||||
|
||||
private Point[] toPoints(PolarSheetsHistogramData data) {
|
||||
Number[] xValues = data.getxValues();
|
||||
Number[] yValues = data.getyValues();
|
||||
Point[] points = new Point[xValues.length];
|
||||
for (int i = 0; i < xValues.length; i++) {
|
||||
points[i] = new Point(xValues[i], yValues[i]);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResize() {
|
||||
chart.setSizeToMatchContainer();
|
||||
chart.redraw();
|
||||
}
|
||||
|
||||
}
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
package com.sap.sailing.gwt.ui.polarsheets;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEvent;
|
||||
import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEventHandler;
|
||||
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.Timer;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.actions.AsyncActionsExecutor;
|
||||
import com.sap.sailing.gwt.ui.actions.GetPolarSheetDataByAngleAction;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaDisplayer;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
|
||||
public class PolarSheetsPanel extends FormPanel implements RaceSelectionChangeListener, RegattaDisplayer {
|
||||
|
||||
// TODO UI stuff
|
||||
public static final String POLARSHEETS_STYLE = "polarSheets";
|
||||
|
||||
private FlowPanel mainPanel;
|
||||
private SailingServiceAsync sailingService;
|
||||
private PolarSheetsTrackedRacesList polarSheetsTrackedRacesList;
|
||||
private ErrorReporter errorReporter;
|
||||
private StringMessages stringMessages;
|
||||
private RaceSelectionModel raceSelectionProvider;
|
||||
private PolarSheetsEntryPoint polarSheetsEntryPoint;
|
||||
private List<RegattaAndRaceIdentifier> selectedRaces;
|
||||
private PolarSheetsChartPanel chartPanel;
|
||||
private PolarSheetsHistogramPanel histogramPanel;
|
||||
private AsyncActionsExecutor asyncActionsExecutor;
|
||||
|
||||
private Label polarSheetsGenerationLabel;
|
||||
private Label dataCountLabel;
|
||||
|
||||
//Dual mapping. Another solution would be using commons BidiMap.
|
||||
//But this would require to attach source code for gwt
|
||||
private Map<String,String> idNameMapping;
|
||||
private Map<String,String> nameIdMapping;
|
||||
|
||||
public PolarSheetsPanel(SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
StringMessages stringMessages, PolarSheetsEntryPoint polarSheetsEntryPoint) {
|
||||
this.polarSheetsEntryPoint = polarSheetsEntryPoint;
|
||||
this.sailingService = sailingService;
|
||||
this.errorReporter = errorReporter;
|
||||
this.stringMessages = stringMessages;
|
||||
|
||||
idNameMapping = new HashMap<String, String>();
|
||||
nameIdMapping = new HashMap<String, String>();
|
||||
|
||||
this.mainPanel = new FlowPanel();
|
||||
setSize("100%", "100%");
|
||||
|
||||
mainPanel.setSize("100%", "100%");
|
||||
setWidget(mainPanel);
|
||||
HorizontalPanel splitPanel = createSplitPanel();
|
||||
VerticalPanel leftPanel = addFilteredTrackedRacesList(splitPanel);
|
||||
polarSheetsGenerationLabel = createPolarSheetGenerationStatusLabel();
|
||||
leftPanel.add(polarSheetsGenerationLabel);
|
||||
dataCountLabel = new Label();
|
||||
leftPanel.add(dataCountLabel);
|
||||
VerticalPanel rightPanel = addPolarSheetsChartPanel(splitPanel);
|
||||
histogramPanel = new PolarSheetsHistogramPanel(stringMessages);
|
||||
histogramPanel.getElement().setAttribute("align", "top");
|
||||
rightPanel.add(histogramPanel);
|
||||
mainPanel.add(splitPanel);
|
||||
|
||||
asyncActionsExecutor = new AsyncActionsExecutor();
|
||||
setEventListenersForPolarSheetChart();
|
||||
}
|
||||
|
||||
private void setEventListenersForPolarSheetChart() {
|
||||
PointMouseOverEventHandler pointMouseOverHandler = new PointMouseOverEventHandler() {
|
||||
|
||||
@Override
|
||||
public boolean onMouseOver(PointMouseOverEvent pointMouseOverEvent) {
|
||||
int angle = (int) pointMouseOverEvent.getXAsLong();
|
||||
String polarSheetNameWithWind = pointMouseOverEvent.getSeriesName();
|
||||
String[] split = polarSheetNameWithWind.split("-");
|
||||
String polarSheetName = split[0] + "-" + split[1];
|
||||
String polarSheetId = nameIdMapping.get(polarSheetName);
|
||||
int windSpeed = Integer.parseInt(split[2]);
|
||||
|
||||
GetPolarSheetDataByAngleAction action = new GetPolarSheetDataByAngleAction(sailingService,
|
||||
polarSheetId, angle, windSpeed, new AsyncCallback<PolarSheetsHistogramData>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(PolarSheetsHistogramData result) {
|
||||
if (result != null) {
|
||||
histogramPanel.setData(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(caught.getLocalizedMessage());
|
||||
}
|
||||
|
||||
});
|
||||
asyncActionsExecutor.execute(action);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
chartPanel.setSeriesPointMouseOverHandler(pointMouseOverHandler);
|
||||
}
|
||||
|
||||
private Label createPolarSheetGenerationStatusLabel() {
|
||||
Label polarSheetsGenerationStatusLabel = new Label();
|
||||
return polarSheetsGenerationStatusLabel;
|
||||
}
|
||||
|
||||
private VerticalPanel addPolarSheetsChartPanel(HorizontalPanel splitPanel) {
|
||||
VerticalPanel verticalPanel = new VerticalPanel();
|
||||
verticalPanel.setSize("100%", "100%");
|
||||
chartPanel = new PolarSheetsChartPanel(stringMessages);
|
||||
verticalPanel.add(chartPanel);
|
||||
verticalPanel.setCellHeight(chartPanel, "800px");
|
||||
splitPanel.add(verticalPanel);
|
||||
splitPanel.setCellWidth(verticalPanel, "50%");
|
||||
return verticalPanel;
|
||||
}
|
||||
|
||||
private HorizontalPanel createSplitPanel() {
|
||||
HorizontalPanel splitPanel = new HorizontalPanel();
|
||||
splitPanel.setSize("100%", "100%");
|
||||
return splitPanel;
|
||||
}
|
||||
|
||||
private VerticalPanel addFilteredTrackedRacesList(HorizontalPanel splitPanel) {
|
||||
VerticalPanel trackedRacesPanel = new VerticalPanel();
|
||||
trackedRacesPanel.setWidth("100%");
|
||||
|
||||
createPolarSheetsTrackedRacesList();
|
||||
trackedRacesPanel.add(polarSheetsTrackedRacesList);
|
||||
|
||||
splitPanel.add(trackedRacesPanel);
|
||||
splitPanel.setCellWidth(trackedRacesPanel, "50%");
|
||||
return trackedRacesPanel;
|
||||
}
|
||||
|
||||
private void createPolarSheetsTrackedRacesList() {
|
||||
raceSelectionProvider = new RaceSelectionModel();
|
||||
ClickHandler polarSheetsGenerationButtonClickHandler = new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent arg0) {
|
||||
startPolarSheetGeneration();
|
||||
}
|
||||
};
|
||||
polarSheetsTrackedRacesList = new PolarSheetsTrackedRacesList(sailingService, errorReporter,
|
||||
polarSheetsEntryPoint, raceSelectionProvider, stringMessages, true, new RaceFilter(true, true),
|
||||
polarSheetsGenerationButtonClickHandler);
|
||||
raceSelectionProvider.addRaceSelectionChangeListener(this);
|
||||
}
|
||||
|
||||
protected void startPolarSheetGeneration() {
|
||||
// List conversion, to make List serializable
|
||||
final List<RegattaAndRaceIdentifier> selectedRacesInArrayList = new ArrayList<RegattaAndRaceIdentifier>();
|
||||
selectedRacesInArrayList.addAll(selectedRaces);
|
||||
polarSheetsTrackedRacesList.changeGenerationButtonState(false);
|
||||
sailingService.generatePolarSheetForRaces(selectedRacesInArrayList, new AsyncCallback<PolarSheetGenerationTriggerResponse>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(PolarSheetGenerationTriggerResponse result) {
|
||||
// TODO string messages
|
||||
setCompletionLabel("Generating...");
|
||||
startPullingResults(result.getId());
|
||||
addNameForPolarSheet(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(caught.getLocalizedMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void addNameForPolarSheet(PolarSheetGenerationTriggerResponse result) {
|
||||
String boatClassName = result.getBoatClassName();
|
||||
int index = 0;
|
||||
String name = "";
|
||||
do {
|
||||
index++;
|
||||
name = boatClassName + "-" + index;
|
||||
} while (nameIdMapping.containsKey(name));
|
||||
idNameMapping.put(result.getId(), name);
|
||||
nameIdMapping.put(name, result.getId());
|
||||
}
|
||||
|
||||
protected void startPullingResults(final String id) {
|
||||
|
||||
sailingService.getPolarSheetsGenerationResults(id, new AsyncCallback<PolarSheetsData>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(PolarSheetsData result) {
|
||||
// TODO string messages
|
||||
setCompletionLabel("Generating...");
|
||||
dataCountLabel.setText("DataCount: " + result.getDataCount());
|
||||
chartPanel.setData(idNameMapping.get(id), result);
|
||||
if (!result.isComplete()) {
|
||||
Timer timer = new Timer() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
startPullingResults(id);
|
||||
}
|
||||
};
|
||||
|
||||
timer.schedule(1500);
|
||||
|
||||
} else {
|
||||
// TODO string messages
|
||||
setCompletionLabel("Generation finished!");
|
||||
polarSheetsTrackedRacesList.changeGenerationButtonState(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(caught.getLocalizedMessage());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected void setCompletionLabel(String string) {
|
||||
polarSheetsGenerationLabel.setText(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRaceSelectionChange(List<RegattaAndRaceIdentifier> selectedRaces) {
|
||||
this.selectedRaces = selectedRaces;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRegattas(List<RegattaDTO> regattas) {
|
||||
polarSheetsTrackedRacesList.fillRegattas(regattas);
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.sap.sailing.gwt.ui.polarsheets;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
|
||||
public class PolarSheetsTrackedRacesList extends AbstractFilteredTrackedRacesList {
|
||||
|
||||
private Button btnPolarSheetGeneration;
|
||||
|
||||
public PolarSheetsTrackedRacesList(SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
RegattaRefresher regattaRefresher, RaceSelectionProvider raceSelectionProvider,
|
||||
StringMessages stringMessages, boolean hasMultiSelection, RaceFilter filter,
|
||||
ClickHandler polarSheetsGenerationButtonClickedHandler) {
|
||||
super(sailingService, errorReporter, regattaRefresher, raceSelectionProvider, stringMessages,
|
||||
hasMultiSelection, filter);
|
||||
btnPolarSheetGeneration.addClickHandler(polarSheetsGenerationButtonClickedHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addControlButtons(HorizontalPanel trackedRacesButtonPanel) {
|
||||
btnPolarSheetGeneration = new Button(stringMessages.generatePolarSheet());
|
||||
btnPolarSheetGeneration.ensureDebugId("PolarSheetGeneration");
|
||||
trackedRacesButtonPanel.add(btnPolarSheetGeneration);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeControlsReactToSelectionChange(List<RaceDTO> selectedRaces) {
|
||||
if (selectedRaces.isEmpty()) {
|
||||
btnPolarSheetGeneration.setEnabled(false);
|
||||
} else {
|
||||
btnPolarSheetGeneration.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeControlsReactToFillRegattas(List<RegattaDTO> regattas) {
|
||||
if (regattas.isEmpty()) {
|
||||
btnPolarSheetGeneration.setVisible(false);
|
||||
} else {
|
||||
btnPolarSheetGeneration.setVisible(true);
|
||||
btnPolarSheetGeneration.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the state of the generation-start button
|
||||
* @param enable
|
||||
*/
|
||||
public void changeGenerationButtonState(boolean enable) {
|
||||
btnPolarSheetGeneration.setEnabled(enable);
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.sap.sailing.gwt.ui.polarsheets;
|
||||
|
||||
import com.sap.sailing.gwt.ui.shared.RaceDTO;
|
||||
|
||||
public class RaceFilter {
|
||||
|
||||
private Boolean withGpsFixes;
|
||||
private Boolean withWindData;
|
||||
|
||||
|
||||
|
||||
|
||||
public RaceFilter(Boolean withGpsFixes, Boolean withWindData) {
|
||||
this.withGpsFixes = withGpsFixes;
|
||||
this.withWindData = withWindData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean compliesToFilter(RaceDTO race) {
|
||||
if (!compliesToGpsFixFilter(race) || !compliesToWindDataFilter(race)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean compliesToGpsFixFilter(RaceDTO race) {
|
||||
if (withGpsFixes!=null) {
|
||||
if (race.trackedRace.hasGPSData != withGpsFixes) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean compliesToWindDataFilter(RaceDTO race) {
|
||||
if (withGpsFixes!=null) {
|
||||
if (race.trackedRace.hasWindData != withWindData) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+121
-1
@@ -38,6 +38,8 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
@@ -75,6 +77,9 @@ import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindError;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Placemark;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RaceFetcher;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
@@ -96,6 +101,8 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KilometersPerHourSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetGenerationTriggerResponseImpl;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
@@ -109,6 +116,8 @@ import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
|
||||
import com.sap.sailing.domain.polarsheets.BoatAndWindSpeed;
|
||||
import com.sap.sailing.domain.polarsheets.PolarSheetGenerationWorker;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingArchiveConfiguration;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingConfiguration;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
@@ -304,6 +313,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
private final DomainFactory tractracDomainFactory;
|
||||
|
||||
private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory;
|
||||
|
||||
private final Map<String,PolarSheetGenerationWorker> polarSheetGenerationWorkers = new HashMap<String, PolarSheetGenerationWorker>();
|
||||
|
||||
public SailingServiceImpl() {
|
||||
BundleContext context = Activator.getDefault();
|
||||
@@ -353,7 +364,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
/**
|
||||
* Asks the OSGi system for registered score correction provider services
|
||||
*/
|
||||
private ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> createAndOpenScoreCorrectionProviderServiceTracker(
|
||||
protected ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> createAndOpenScoreCorrectionProviderServiceTracker(
|
||||
BundleContext bundleContext) {
|
||||
ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> tracker = new ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider>(bundleContext,
|
||||
ScoreCorrectionProvider.class.getName(),
|
||||
@@ -3095,4 +3106,113 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
swissTimingAdapterPersistence.storeSwissTimingArchiveConfiguration(swissTimingFactory.createSwissTimingArchiveConfiguration(
|
||||
swissTimingJsonUrl));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetGenerationTriggerResponse generatePolarSheetForRaces(List<RegattaAndRaceIdentifier> selectedRaces) {
|
||||
String id = UUID.randomUUID().toString();
|
||||
RacingEventService service = getService();
|
||||
Set<TrackedRace> trackedRaces = new HashSet<TrackedRace>();
|
||||
for (RegattaAndRaceIdentifier race : selectedRaces) {
|
||||
trackedRaces.add(service.getTrackedRace(race));
|
||||
}
|
||||
PolarSheetGenerationWorker genWorker = new PolarSheetGenerationWorker(trackedRaces, executor);
|
||||
polarSheetGenerationWorkers.put(id, genWorker);
|
||||
genWorker.startPolarSheetGeneration();
|
||||
String name = getCommonBoatClass(trackedRaces);
|
||||
return new PolarSheetGenerationTriggerResponseImpl(id, name);
|
||||
}
|
||||
|
||||
private String getCommonBoatClass(Set<TrackedRace> trackedRaces) {
|
||||
BoatClass boatClass = null;
|
||||
for (TrackedRace race : trackedRaces) {
|
||||
if (boatClass == null) {
|
||||
boatClass = race.getRace().getBoatClass();
|
||||
}
|
||||
if (!boatClass.getName().matches(race.getRace().getBoatClass().getName())) {
|
||||
return "Mixed";
|
||||
}
|
||||
}
|
||||
|
||||
return boatClass.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetsData getPolarSheetsGenerationResults(String id) {
|
||||
PolarSheetsData data = null;
|
||||
if (polarSheetGenerationWorkers.containsKey(id)) {
|
||||
PolarSheetGenerationWorker worker = polarSheetGenerationWorkers.get(id);
|
||||
data = worker.getPolarData();
|
||||
if (data.isComplete()) {
|
||||
polarSheetGenerationWorkers.remove(id);
|
||||
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
|
||||
if (httpServletRequest != null) {
|
||||
HttpSession session = httpServletRequest.getSession();
|
||||
session.setAttribute(id, worker.getCompleteData());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//TODO Exception handling
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetsHistogramData getPolarSheetData(String polarSheetId, int angle, int windSpeed) {
|
||||
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
|
||||
HttpSession session = httpServletRequest.getSession();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<List<BoatAndWindSpeed>> data = (List<List<BoatAndWindSpeed>>) session.getAttribute(polarSheetId);
|
||||
if (data == null) {
|
||||
//TODO exception handling
|
||||
return null;
|
||||
}
|
||||
List<BoatAndWindSpeed> dataForAngle = data.get(angle);
|
||||
if (dataForAngle.size() < 1) {
|
||||
//TODO exception handling
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Double> dataForAngleAndWindSpeed = new ArrayList<Double>();
|
||||
|
||||
for (BoatAndWindSpeed dataPoint: dataForAngle) {
|
||||
if (((int) dataPoint.getWindSpeed().getBeaufort()) == windSpeed) {
|
||||
dataForAngleAndWindSpeed.add(dataPoint.getBoatSpeed().getKnots());
|
||||
}
|
||||
}
|
||||
|
||||
if (dataForAngleAndWindSpeed.size() < 1) {
|
||||
//TODO exception handling
|
||||
return null;
|
||||
}
|
||||
|
||||
Double min = Collections.min(dataForAngleAndWindSpeed);
|
||||
Double max = Collections.max(dataForAngleAndWindSpeed);
|
||||
//TODO make number of columns dynamic to chart size
|
||||
int numberOfColumns = 20;
|
||||
double range = (max - min) / numberOfColumns;
|
||||
Double[] xValues = new Double[numberOfColumns];
|
||||
for (int i = 0; i < numberOfColumns; i++) {
|
||||
xValues[i] = min + i * range + ( 0.5 * range);
|
||||
}
|
||||
|
||||
Integer[] yValues = new Integer[numberOfColumns];
|
||||
for (Double dataPoint : dataForAngleAndWindSpeed) {
|
||||
int i = (int) (((dataPoint - min) / range));
|
||||
if (i == numberOfColumns) {
|
||||
//For max value
|
||||
i = 19;
|
||||
}
|
||||
if (yValues[i] == null) {
|
||||
yValues[i] = 0;
|
||||
}
|
||||
yValues[i]++;
|
||||
}
|
||||
|
||||
PolarSheetsHistogramData histogramData = new PolarSheetsHistogramDataImpl(angle, xValues, yValues, dataForAngleAndWindSpeed.size());
|
||||
|
||||
|
||||
return histogramData;
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.5.0/distro-source/core/src/gwt-module.dtd">
|
||||
<module>
|
||||
<stylesheet src="../PolarSheets.css" />
|
||||
<inherits name="com.google.gwt.user.User" />
|
||||
|
||||
<!-- Specify the paths for translatable code -->
|
||||
<extend-property name="locale" values="de" />
|
||||
|
||||
<source path="client" />
|
||||
<source path="polarsheets" />
|
||||
<source path='leaderboard' />
|
||||
<source path='raceboard' />
|
||||
<source path='adminconsole' />
|
||||
<source path='usermanagement' />
|
||||
<source path='shared' />
|
||||
<source path='common' />
|
||||
<source path='actions' />
|
||||
<entry-point class="com.sap.sailing.gwt.ui.polarsheets.PolarSheetsEntryPoint">
|
||||
</entry-point>
|
||||
|
||||
<!-- Google Maps API -->
|
||||
<inherits name='com.google.gwt.maps.GoogleMaps' />
|
||||
|
||||
<!-- Highcharts API -->
|
||||
<inherits name="org.moxieapps.gwt.highcharts.Highcharts" />
|
||||
|
||||
<!-- Other module inherits -->
|
||||
<inherits name="com.sap.sailing.domain.SailingDomain" />
|
||||
</module>
|
||||
+27
@@ -21,20 +21,26 @@ import org.junit.Test;
|
||||
import com.mongodb.MongoException;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.base.Venue;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
||||
import com.sap.sailing.domain.base.impl.CourseAreaImpl;
|
||||
import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.EventImpl;
|
||||
import com.sap.sailing.domain.base.impl.FleetImpl;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.SeriesImpl;
|
||||
import com.sap.sailing.domain.base.impl.VenueImpl;
|
||||
@@ -386,4 +392,25 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegattaRaceAssociationStore() throws Exception {
|
||||
BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("112er", /* typicallyStartsUpwind */ true);
|
||||
Regatta regatta = createRegatta("Cologne Masters", boatClass, /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT));
|
||||
|
||||
List<Competitor> competitors = new ArrayList<Competitor>();
|
||||
competitors.add(new CompetitorImpl("Axel", "Axel Uhl", null, null));
|
||||
Iterable<Waypoint> waypoints = Collections.emptyList();
|
||||
Course course = new CourseImpl("Course", waypoints);
|
||||
|
||||
RaceDefinition racedef = new RaceDefinitionImpl("M1", course, boatClass, competitors);
|
||||
regatta.addRace(racedef);
|
||||
|
||||
RacingEventServiceImpl evs = new RacingEventServiceImpl(getMongoService());
|
||||
assertNull(evs.getRememberedRegattaForRace(racedef.getId()));
|
||||
evs.raceAdded(regatta, racedef);
|
||||
assertNotNull(evs.getRememberedRegattaForRace(racedef.getId()));
|
||||
evs.removeRegatta(regatta);
|
||||
assertNull(evs.getRememberedRegattaForRace(racedef.getId()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -1080,6 +1080,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
public void removeRegatta(Regatta regatta) throws MalformedURLException, IOException, InterruptedException {
|
||||
for (RaceDefinition race : regatta.getAllRaces()) {
|
||||
removeRace(regatta, race);
|
||||
mongoObjectFactory.removeRegattaForRaceID(race.getName(), regatta);
|
||||
persistentRegattasForRaceIDs.remove(race.getId().toString());
|
||||
}
|
||||
if (regatta.isPersistent()) {
|
||||
mongoObjectFactory.removeRegatta(regatta);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
This is a test
|
||||
Reference in New Issue
Block a user