mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-30 15:57:11 +00:00
Merge branch 'master' into translation
This commit is contained in:
commit
79b25789b4
45 files changed
+446
-201
No files matched your search
+18
-4
@@ -14,20 +14,34 @@ package com.sap.sailing.domain.common;
|
||||
public enum PassingInstruction {
|
||||
None(1, 2),
|
||||
Port(1),
|
||||
Single_Unknown(1),
|
||||
Starboard(1),
|
||||
Single_Unknown(1),
|
||||
Gate(2),
|
||||
Line(2),
|
||||
Offset(2),
|
||||
FixedBearing(1);
|
||||
|
||||
/**
|
||||
* Those values relevant for picking by a user when creating a waypoint; for example, this list
|
||||
* does not include the {@link #None} or the {@link #Single_Unknown} literals. No guarantees
|
||||
* made as to the ordering. The enum literals may change, be extended, have elements inserted or
|
||||
* removed at any time!
|
||||
*/
|
||||
public static PassingInstruction[] relevantValues() {
|
||||
PassingInstruction[] uiValues = new PassingInstruction[PassingInstruction.values().length - 1];
|
||||
|
||||
final PassingInstruction[] uselessValues = new PassingInstruction[] { None, Single_Unknown, Offset, FixedBearing };
|
||||
PassingInstruction[] uiValues = new PassingInstruction[PassingInstruction.values().length - uselessValues.length];
|
||||
int i = 0;
|
||||
for (PassingInstruction p : PassingInstruction.values()) {
|
||||
if (p != PassingInstruction.None)
|
||||
boolean useless = false;
|
||||
for (PassingInstruction u : uselessValues) {
|
||||
if (u == p) {
|
||||
useless = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!useless) {
|
||||
uiValues[i++] = p;
|
||||
}
|
||||
}
|
||||
return uiValues;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.simulator;
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
public enum PathType {
|
||||
OMNISCIENT("1#Omniscient"),
|
||||
+59
@@ -1605,6 +1605,65 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
assertEquals(0., leaderboard1.getTotalPoints(c[0], beforeStartOfR1), 0.00000001); // not even the R1 scores apply before the start time of R1
|
||||
}
|
||||
|
||||
/**
|
||||
* When a DNS score correction is made then both, the MaxPointsReason and the score shall apply at the start of the race.
|
||||
*/
|
||||
@Test
|
||||
public void testDNSScoreAppliesBeforeEndOfRace() throws NoWindException {
|
||||
Competitor[] c = createCompetitors(4).toArray(new Competitor[0]);
|
||||
final TimePoint endOfR1 = MillisecondsTimePoint.now();
|
||||
final TimePoint withinR1 = endOfR1.minus(1000);
|
||||
final TimePoint startOfR1 = withinR1.minus(10000);
|
||||
final TimePoint beforeStartOfR1 = startOfR1.minus(10000);
|
||||
final TimePoint afterEndOfR1 = endOfR1.plus(1000);
|
||||
FlexibleLeaderboard leaderboard1 = new FlexibleLeaderboardImpl("Leaderboard 1", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new LowPoint(), null);
|
||||
leaderboard1.addRace(new MockedTrackedRaceWithStartTimeAndRanks(startOfR1, Arrays.asList(c)) {
|
||||
private static final long serialVersionUID = 8705622361027154428L;
|
||||
public TimePoint getEndOfRace() {
|
||||
return endOfR1;
|
||||
}
|
||||
}, "R1", /* medalRace */false);
|
||||
leaderboard1.getScoreCorrection().correctScore(c[0], leaderboard1.getRaceColumnByName("R1"), 123.);
|
||||
leaderboard1.getScoreCorrection().setMaxPointsReason(c[0], leaderboard1.getRaceColumnByName("R1"), MaxPointsReason.DNS);
|
||||
assertEquals(MaxPointsReason.NONE, leaderboard1.getMaxPointsReason(c[0], leaderboard1.getRaceColumnByName("R1"), beforeStartOfR1));
|
||||
assertEquals(MaxPointsReason.DNS, leaderboard1.getMaxPointsReason(c[0], leaderboard1.getRaceColumnByName("R1"), withinR1));
|
||||
assertEquals(MaxPointsReason.DNS, leaderboard1.getMaxPointsReason(c[0], leaderboard1.getRaceColumnByName("R1"), afterEndOfR1));
|
||||
assertNull(leaderboard1.getNetPoints(c[0], leaderboard1.getRaceColumnByName("R1"), beforeStartOfR1));
|
||||
assertEquals(123., leaderboard1.getNetPoints(c[0], leaderboard1.getRaceColumnByName("R1"), withinR1), 0.00000001);
|
||||
assertEquals(123., leaderboard1.getNetPoints(c[0], leaderboard1.getRaceColumnByName("R1"), afterEndOfR1), 0.00000001);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a DNS score correction is made then both, the MaxPointsReason and the score shall apply at the start of the race.
|
||||
*/
|
||||
@Test
|
||||
public void testDNFScoreDoesNotApplyBeforeEndOfRace() throws NoWindException {
|
||||
Competitor[] c = createCompetitors(4).toArray(new Competitor[0]);
|
||||
final TimePoint endOfR1 = MillisecondsTimePoint.now();
|
||||
final TimePoint withinR1 = endOfR1.minus(1000);
|
||||
final TimePoint startOfR1 = withinR1.minus(10000);
|
||||
final TimePoint beforeStartOfR1 = startOfR1.minus(10000);
|
||||
final TimePoint afterEndOfR1 = endOfR1.plus(1000);
|
||||
FlexibleLeaderboard leaderboard1 = new FlexibleLeaderboardImpl("Leaderboard 1", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new LowPoint(), null);
|
||||
leaderboard1.addRace(new MockedTrackedRaceWithStartTimeAndRanks(startOfR1, Arrays.asList(c)) {
|
||||
private static final long serialVersionUID = 8705622361027154428L;
|
||||
public TimePoint getEndOfRace() {
|
||||
return endOfR1;
|
||||
}
|
||||
}, "R1", /* medalRace */false);
|
||||
leaderboard1.getScoreCorrection().correctScore(c[0], leaderboard1.getRaceColumnByName("R1"), 123.);
|
||||
leaderboard1.getScoreCorrection().setMaxPointsReason(c[0], leaderboard1.getRaceColumnByName("R1"), MaxPointsReason.DNF);
|
||||
assertEquals(MaxPointsReason.NONE, leaderboard1.getMaxPointsReason(c[0], leaderboard1.getRaceColumnByName("R1"), beforeStartOfR1));
|
||||
assertEquals(MaxPointsReason.NONE, leaderboard1.getMaxPointsReason(c[0], leaderboard1.getRaceColumnByName("R1"), withinR1));
|
||||
assertEquals(MaxPointsReason.DNF, leaderboard1.getMaxPointsReason(c[0], leaderboard1.getRaceColumnByName("R1"), afterEndOfR1));
|
||||
assertNull(leaderboard1.getNetPoints(c[0], leaderboard1.getRaceColumnByName("R1"), beforeStartOfR1));
|
||||
assertEquals(1.0, leaderboard1.getNetPoints(c[0], leaderboard1.getRaceColumnByName("R1"), withinR1), 0.00000001); // tracked rank is 1
|
||||
assertEquals(123., leaderboard1.getNetPoints(c[0], leaderboard1.getRaceColumnByName("R1"), afterEndOfR1), 0.00000001);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A test case for bug 1802. Competitors that didn't have a fleet (null fleet) were sorted to the end of the column even
|
||||
* if they had a score correction assigned.
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ public class MarkPassingCalculatorPerformanceTest extends AbstractMockedRaceMark
|
||||
time = System.currentTimeMillis() - time;
|
||||
result.put("FinderPerformance", time);
|
||||
System.out.println(time);
|
||||
Assert.assertTrue(time < 5000);
|
||||
Assert.assertTrue("Time expected to be less than 5000ms but was "+time+"ms", time < 5000);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+8
-13
@@ -38,24 +38,19 @@ public abstract class AbstractHighPointFirstGetsFixedOr8AndLastBreaksTie extends
|
||||
|
||||
@Override
|
||||
public int compareByBetterScore(Competitor o1, List<Util.Pair<RaceColumn, Double>> o1Scores, Competitor o2, List<Util.Pair<RaceColumn, Double>> o2Scores, boolean nullScoresAreBetter, TimePoint timePoint) {
|
||||
int o1Wins = getWins(o1Scores);
|
||||
int o2Wins = getWins(o2Scores);
|
||||
int result = o2Wins - o1Wins;
|
||||
return result;
|
||||
Double o1Highest = getHighestScore(o1Scores);
|
||||
Double o2Highest = getHighestScore(o2Scores);
|
||||
return o2Highest.compareTo(o1Highest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts a competitor's wins by comparing the scores to {@link #MAX_POINTS} which is the score attributed to a race
|
||||
* won
|
||||
*/
|
||||
private int getWins(List<com.sap.sse.common.Util.Pair<RaceColumn, Double>> scores) {
|
||||
int wins = 0;
|
||||
private double getHighestScore(List<com.sap.sse.common.Util.Pair<RaceColumn, Double>> scores) {
|
||||
double highestScore = 0;
|
||||
for (com.sap.sse.common.Util.Pair<RaceColumn, Double> score : scores) {
|
||||
if (Math.abs(score.getB() - getScoreForRaceWinner() * score.getA().getFactor()) < 0.0000001) {
|
||||
wins++;
|
||||
if ((score.getB() * score.getA().getFactor()) > highestScore) {
|
||||
highestScore = score.getB() * score.getA().getFactor();
|
||||
}
|
||||
}
|
||||
return wins;
|
||||
return highestScore;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-23
@@ -439,11 +439,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
@Override
|
||||
public Double getNetPoints(final Competitor competitor, final RaceColumn raceColumn, final TimePoint timePoint) {
|
||||
return getScoreCorrection().getCorrectedScore(
|
||||
new Callable<Integer>() {
|
||||
public Integer call() throws NoWindException {
|
||||
return getTrackedRank(competitor, raceColumn, timePoint);
|
||||
}
|
||||
}, competitor,
|
||||
()->getTrackedRank(competitor, raceColumn, timePoint), competitor,
|
||||
raceColumn, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme()).getCorrectedScore();
|
||||
}
|
||||
|
||||
@@ -684,21 +680,13 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
@Override
|
||||
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint,
|
||||
Set<RaceColumn> discardedRaceColumns) throws NoWindException {
|
||||
Callable<Integer> trackedRankProvider = new Callable<Integer>() {
|
||||
public Integer call() throws NoWindException {
|
||||
return getTrackedRank(competitor, race, timePoint);
|
||||
}
|
||||
};
|
||||
Callable<Integer> trackedRankProvider = ()->getTrackedRank(competitor, race, timePoint);
|
||||
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, race,
|
||||
timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
|
||||
boolean discarded = isDiscarded(competitor, race, timePoint, discardedRaceColumns);
|
||||
final Double correctedScore = correctedResults.getCorrectedScore();
|
||||
return new EntryImpl(trackedRankProvider, correctedScore, new Callable<Double>() {
|
||||
@Override
|
||||
public Double call() {
|
||||
return correctedResults.getUncorrectedScore();
|
||||
}
|
||||
}, correctedResults.isCorrected(), discarded ? DOUBLE_0 : correctedScore == null ? null
|
||||
return new EntryImpl(trackedRankProvider, correctedScore, ()->correctedResults.getUncorrectedScore(),
|
||||
correctedResults.isCorrected(), discarded ? DOUBLE_0 : correctedScore == null ? null
|
||||
: Double.valueOf(correctedScore * race.getFactor()), correctedResults.getMaxPointsReason(), discarded,
|
||||
race.getFleetOfCompetitor(competitor));
|
||||
}
|
||||
@@ -756,12 +744,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
Map<Competitor, Set<RaceColumn>> discardedRaces = new HashMap<Competitor, Set<RaceColumn>>();
|
||||
for (final RaceColumn raceColumn : getRaceColumns()) {
|
||||
for (final Competitor competitor : getCompetitors()) {
|
||||
Callable<Integer> trackedRankProvider = new Callable<Integer>() {
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
return getTrackedRank(competitor, raceColumn, timePoint);
|
||||
}
|
||||
};
|
||||
Callable<Integer> trackedRankProvider = ()->getTrackedRank(competitor, raceColumn, timePoint);
|
||||
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, raceColumn,
|
||||
timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
|
||||
Set<RaceColumn> discardedRacesForCompetitor = discardedRaces.get(competitor);
|
||||
@@ -772,7 +755,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
boolean discarded = discardedRacesForCompetitor.contains(raceColumn);
|
||||
final Double correctedScore = correctedResults.getCorrectedScore();
|
||||
Entry entry = new EntryImpl(trackedRankProvider, correctedScore,
|
||||
new Callable<Double>() { @Override public Double call() { return correctedResults.getUncorrectedScore(); } },
|
||||
()->correctedResults.getUncorrectedScore(),
|
||||
correctedResults.isCorrected(),
|
||||
discarded ? DOUBLE_0 : (correctedScore==null?null:
|
||||
Double.valueOf((correctedScore * raceColumn.getFactor()))), correctedResults.getMaxPointsReason(),
|
||||
|
||||
+61
-22
@@ -324,11 +324,39 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
|
||||
@Override
|
||||
public MaxPointsReason getMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
MaxPointsReason result = maxPointsReasons.get(raceColumn.getKey(competitor));
|
||||
if (result == null || !isMaxPointsReasonApplicable(result, timePoint, raceColumn, competitor)) {
|
||||
result = MaxPointsReason.NONE;
|
||||
return getAnnotatedMaxPointsReason(competitor, raceColumn, timePoint).getMaxPointsReason();
|
||||
}
|
||||
|
||||
private static class AnnotatedMaxPointsReason {
|
||||
private final MaxPointsReason maxPointsReason;
|
||||
private final boolean maxPointsReasonExistsButIsNotApplicableForTimePoint;
|
||||
public AnnotatedMaxPointsReason(MaxPointsReason maxPointsReason,
|
||||
boolean maxPointsReasonExistsButIsNotApplicableForTimePoint) {
|
||||
super();
|
||||
this.maxPointsReason = maxPointsReason;
|
||||
this.maxPointsReasonExistsButIsNotApplicableForTimePoint = maxPointsReasonExistsButIsNotApplicableForTimePoint;
|
||||
}
|
||||
return result;
|
||||
public MaxPointsReason getMaxPointsReason() {
|
||||
return maxPointsReason;
|
||||
}
|
||||
public boolean isMaxPointsReasonExistsButIsNotApplicableForTimePoint() {
|
||||
return maxPointsReasonExistsButIsNotApplicableForTimePoint;
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotatedMaxPointsReason getAnnotatedMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
MaxPointsReason maxPointsReason = maxPointsReasons.get(raceColumn.getKey(competitor));
|
||||
boolean maxPointsReasonExistsButIsNotApplicableForTimePoint;
|
||||
if (maxPointsReason == null) {
|
||||
maxPointsReason = MaxPointsReason.NONE;
|
||||
maxPointsReasonExistsButIsNotApplicableForTimePoint = false;
|
||||
} else if (!isMaxPointsReasonApplicable(maxPointsReason, timePoint, raceColumn, competitor)) {
|
||||
maxPointsReason = MaxPointsReason.NONE;
|
||||
maxPointsReasonExistsButIsNotApplicableForTimePoint = true;
|
||||
} else {
|
||||
maxPointsReasonExistsButIsNotApplicableForTimePoint = false;
|
||||
}
|
||||
return new AnnotatedMaxPointsReason(maxPointsReason, maxPointsReasonExistsButIsNotApplicableForTimePoint);
|
||||
}
|
||||
|
||||
private boolean isMaxPointsReasonApplicable(MaxPointsReason maxPointsReason, TimePoint timePoint, RaceColumn raceColumn, Competitor competitor) {
|
||||
@@ -360,15 +388,21 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
final NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher,
|
||||
final ScoringScheme scoringScheme) {
|
||||
Double result;
|
||||
final MaxPointsReason maxPointsReason = getMaxPointsReason(competitor, raceColumn, timePoint);
|
||||
if (maxPointsReason == MaxPointsReason.NONE) {
|
||||
result = getCorrectedNonMaxedScore(competitor, raceColumn, trackedRankProvider, scoringScheme, numberOfCompetitorsInLeaderboardFetcher, timePoint);
|
||||
final AnnotatedMaxPointsReason maxPointsReason = getAnnotatedMaxPointsReason(competitor, raceColumn, timePoint);
|
||||
if (maxPointsReason.getMaxPointsReason() == MaxPointsReason.NONE) {
|
||||
// could be that there is a MaxPointsReason that just doesn't apply yet at timePoint; in this
|
||||
// case ignore the score correction and deliver the uncorrected result
|
||||
if (maxPointsReason.isMaxPointsReasonExistsButIsNotApplicableForTimePoint()) {
|
||||
result = getUncorrectedScore(competitor, raceColumn, trackedRankProvider, scoringScheme, numberOfCompetitorsInLeaderboardFetcher, timePoint);
|
||||
} else {
|
||||
result = getCorrectedNonMaxedScore(competitor, raceColumn, trackedRankProvider, scoringScheme, numberOfCompetitorsInLeaderboardFetcher, timePoint);
|
||||
}
|
||||
} else {
|
||||
// allow explicit override even when max points reason is specified; calculation may be wrong,
|
||||
// e.g., in case we have an untracked race and the number of competitors is estimated incorrectly
|
||||
Double correctedNonMaxedScore = correctedScores.get(raceColumn.getKey(competitor));
|
||||
if (correctedNonMaxedScore == null) {
|
||||
result = scoringScheme.getPenaltyScore(raceColumn, competitor, maxPointsReason,
|
||||
result = scoringScheme.getPenaltyScore(raceColumn, competitor, maxPointsReason.getMaxPointsReason(),
|
||||
getNumberOfCompetitorsInRace(raceColumn, competitor, numberOfCompetitorsInLeaderboardFetcher),
|
||||
numberOfCompetitorsInLeaderboardFetcher);
|
||||
} else {
|
||||
@@ -379,7 +413,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
return new Result() {
|
||||
@Override
|
||||
public MaxPointsReason getMaxPointsReason() {
|
||||
return maxPointsReason;
|
||||
return maxPointsReason.getMaxPointsReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -446,25 +480,30 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
Double correctedNonMaxedScore = correctedScores.get(raceColumn.getKey(competitor));
|
||||
Double result;
|
||||
if (correctedNonMaxedScore == null || isCertainlyBeforeRaceFinish(timePoint, raceColumn, competitor)) {
|
||||
try {
|
||||
int trackedRank = trackedRankProvider.call();
|
||||
result = scoringScheme.getScoreForRank(leaderboard, raceColumn, competitor,
|
||||
trackedRank, new Callable<Integer>() {
|
||||
@Override
|
||||
public Integer call() {
|
||||
return getNumberOfCompetitorsInRace(raceColumn, competitor, numberOfCompetitorsInLeaderboardFetcher);
|
||||
}
|
||||
}, numberOfCompetitorsInLeaderboardFetcher, timePoint);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception while computing corrected non maxed score", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
result = getUncorrectedScore(competitor, raceColumn, trackedRankProvider, scoringScheme,
|
||||
numberOfCompetitorsInLeaderboardFetcher, timePoint);
|
||||
} else {
|
||||
result = correctedNonMaxedScore;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Double getUncorrectedScore(final Competitor competitor, final RaceColumn raceColumn,
|
||||
Callable<Integer> trackedRankProvider, ScoringScheme scoringScheme,
|
||||
final NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) {
|
||||
final Double result;
|
||||
try {
|
||||
int trackedRank = trackedRankProvider.call();
|
||||
result = scoringScheme.getScoreForRank(leaderboard, raceColumn, competitor,
|
||||
trackedRank, ()->getNumberOfCompetitorsInRace(raceColumn, competitor, numberOfCompetitorsInLeaderboardFetcher),
|
||||
numberOfCompetitorsInLeaderboardFetcher, timePoint);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception while computing uncorrected score", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getExplicitScoreCorrection(Competitor competitor, RaceColumn raceColumn) {
|
||||
return correctedScores.get(raceColumn.getKey(competitor));
|
||||
|
||||
+9
-1
@@ -1398,7 +1398,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint, WindLegTypeAndLegBearingCache cache) {
|
||||
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint unadjustedTimePoint, WindLegTypeAndLegBearingCache cache) {
|
||||
final TimePoint timePoint;
|
||||
// normalize the time point to get cache hits when asking for time points that are later than
|
||||
// the last time point affected by any event received for this tracked race
|
||||
if (Util.compareToWithNull(unadjustedTimePoint, getTimePointOfNewestEvent(), /* nullIsLess */ true) <= 0) {
|
||||
timePoint = unadjustedTimePoint;
|
||||
} else {
|
||||
timePoint = getTimePointOfNewestEvent();
|
||||
}
|
||||
NamedReentrantReadWriteLock readWriteLock;
|
||||
synchronized (competitorRankingsLocks) {
|
||||
readWriteLock = competitorRankingsLocks.get(timePoint);
|
||||
|
||||
+13
-7
@@ -429,6 +429,15 @@ public class RaceContext {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private TimePoint getLiveTimePoint() {
|
||||
return new MillisecondsTimePoint(getLiveTimePointInMillis());
|
||||
}
|
||||
|
||||
private long getLiveTimePointInMillis() {
|
||||
final Long liveDelay = leaderboard.getDelayToLiveInMillis();
|
||||
return System.currentTimeMillis() - (liveDelay == null ? 0l : liveDelay);
|
||||
}
|
||||
|
||||
private SimpleCompetitorDTO getWinnerOrNull() {
|
||||
if (getLiveRaceViewState() != RaceViewState.FINISHED) {
|
||||
// We can't reliably calculate the winner for non finished races
|
||||
@@ -436,10 +445,7 @@ public class RaceContext {
|
||||
}
|
||||
// TODO do not calculate the winner if the blue flag is currently shown.
|
||||
try {
|
||||
TimePoint finishTime = trackedRace.getEndOfRace();
|
||||
if (finishTime == null) {
|
||||
finishTime = HomeServiceUtil.getLiveTimePoint();
|
||||
}
|
||||
TimePoint finishTime = getLiveTimePoint();
|
||||
List<Competitor> competitors = leaderboard.getCompetitorsFromBestToWorst(raceColumn, finishTime);
|
||||
if (competitors == null || competitors.isEmpty()) {
|
||||
return null;
|
||||
@@ -542,7 +548,7 @@ public class RaceContext {
|
||||
if (finishTime != null && now.after(finishTime)) {
|
||||
return RaceViewState.FINISHED;
|
||||
}
|
||||
if(raceLog != null) {
|
||||
if (raceLog != null) {
|
||||
RaceLogFlagEvent abortingFlagEvent = checkForAbortFlagEvent();
|
||||
if (abortingFlagEvent != null) {
|
||||
Flags upperFlag = abortingFlagEvent.getUpperFlag();
|
||||
@@ -558,10 +564,10 @@ public class RaceContext {
|
||||
}
|
||||
}
|
||||
ScoreCorrection scoreCorrection = leaderboard.getScoreCorrection();
|
||||
if(trackedRace == null && scoreCorrection != null && scoreCorrection.hasCorrectionForNonTrackedFleet(raceColumn)) {
|
||||
if (trackedRace == null && scoreCorrection != null && scoreCorrection.hasCorrectionForNonTrackedFleet(raceColumn)) {
|
||||
return RaceViewState.FINISHED;
|
||||
}
|
||||
if(startTime != null) {
|
||||
if (startTime != null) {
|
||||
return RaceViewState.RUNNING;
|
||||
}
|
||||
return RaceViewState.PLANNED;
|
||||
|
||||
-10
@@ -449,16 +449,6 @@ public final class HomeServiceUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static TimePoint getLiveTimePoint() {
|
||||
return new MillisecondsTimePoint(getLiveTimePointInMillis());
|
||||
}
|
||||
|
||||
public static long getLiveTimePointInMillis() {
|
||||
// TODO better solution
|
||||
long livePlayDelayInMillis = 15_000;
|
||||
return System.currentTimeMillis() - livePlayDelayInMillis;
|
||||
}
|
||||
|
||||
public static String getCourseAreaNameForRegattaIdThereIsMoreThanOne(EventBase event, Leaderboard leaderboard) {
|
||||
/** The course area will not be shown if there is only one course area defined for the event */
|
||||
if (Util.size(event.getVenue().getCourseAreas()) <= 1) {
|
||||
|
||||
+2
-2
@@ -47,9 +47,9 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
|
||||
private final Duration initialTimeAfterRaceStartInReplayMode;
|
||||
|
||||
public RaceTimePanel(UserService userService, Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages,
|
||||
RaceTimesInfoProvider raceTimesInfoProvider, boolean canReplayWhileLiveIsPossible, boolean isScreenLargeEnoughToOfferChartSupport,
|
||||
RaceTimesInfoProvider raceTimesInfoProvider, boolean canReplayWhileLiveIsPossible, boolean forcePaddingRightToAlignToCharts,
|
||||
RegattaAndRaceIdentifier selectedRaceIdentifier, Duration initialTimeAfterRaceStartInReplayMode) {
|
||||
super(timer, timeRangeProvider, stringMessages, canReplayWhileLiveIsPossible, isScreenLargeEnoughToOfferChartSupport);
|
||||
super(timer, timeRangeProvider, stringMessages, canReplayWhileLiveIsPossible, forcePaddingRightToAlignToCharts);
|
||||
this.userService = userService;
|
||||
this.raceTimesInfoProvider = raceTimesInfoProvider;
|
||||
selectedRace = null;
|
||||
|
||||
+8
@@ -1578,4 +1578,12 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String perHours();
|
||||
String pleaseSelectAValidWindPattern();
|
||||
String downwindLegsNotSupported();
|
||||
String raceLeader();
|
||||
String opportunistLeft();
|
||||
String opportunistRight();
|
||||
String oneTurnerLeft();
|
||||
String oneTurnerRight();
|
||||
String current();
|
||||
String simulationLegendAlgorithmTimedOutText();
|
||||
String simulationLegendMixedLegText();
|
||||
}
|
||||
+9
-1
@@ -1553,4 +1553,12 @@ currentBearing=Current Bearing
|
||||
percentUnit=%
|
||||
perHours=per hr
|
||||
pleaseSelectAValidWindPattern=Please select a valid wind pattern.
|
||||
downwindLegsNotSupported=Downwind legs are NOT supported yet. Sorry about that :)
|
||||
downwindLegsNotSupported=Downwind legs are NOT supported yet. Sorry about that :)
|
||||
raceLeader=Race Leader
|
||||
opportunistLeft=Opportunist Left
|
||||
opportunistRight=Opportunist Right
|
||||
oneTurnerLeft=1-Turner Left
|
||||
oneTurnerRight=1-Turner Right
|
||||
current=Current
|
||||
simulationLegendAlgorithmTimedOutText = out-of-bounds
|
||||
simulationLegendMixedLegText = ambiguous wind
|
||||
+10
-2
@@ -1526,7 +1526,7 @@ baseBearing=Mittlere Richtung
|
||||
raceCourseDiff=Rennkurs Abweichung
|
||||
baseSpeed=Mittlere Geschwindigkeit
|
||||
probability=Wahrscheinlichkeit
|
||||
gustSize=Böenstärke
|
||||
gustSize=Böengröße
|
||||
averageSpeed=Mittlere Geschwindigkeit
|
||||
speedVariance=Geschwindigkeitsvarianz
|
||||
averageDirection=Mittlere Richtung
|
||||
@@ -1538,4 +1538,12 @@ currentBearing=Strömungsrichtung
|
||||
percentUnit=%
|
||||
pleaseSelectAValidWindPattern=Bitte ein gültiges Wind-Muster auswählen.
|
||||
downwindLegsNotSupported=Vorwind Legs werden aktuell leider NICHT unterstützt.
|
||||
perHours=pro Stunde
|
||||
perHours=pro Stunde
|
||||
raceLeader=Führender
|
||||
opportunistLeft=Opportunist links
|
||||
opportunistRight=Opportunist rechts
|
||||
oneTurnerLeft=1-Wenden-Kurs links
|
||||
oneTurnerRight=1-Wenden-Kurs rechts
|
||||
current=Strömung
|
||||
simulationLegendAlgorithmTimedOutText=außerhalb des zul. Bereichs
|
||||
simulationLegendMixedLegText=mehrdeutiger Wind
|
||||
+18
-7
@@ -89,17 +89,20 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
private static ClientResources resources = GWT.create(ClientResources.class);
|
||||
protected static TimePanelCss timePanelCss = TimePanelCssResources.INSTANCE.css();
|
||||
|
||||
private final boolean forcePaddingRightToAlignToCharts;
|
||||
/**
|
||||
* @param isScreenLargeEnoughToOfferChartSupport
|
||||
* if <code>true</code>, the right padding will be set such that the time panel lines up with charts such
|
||||
* as the competitor chart or the wind chart shown above it
|
||||
* @param forcePaddingRightToAlignToCharts
|
||||
* if <code>true</code>, the right padding will always be set such that the time panel lines up with
|
||||
* charts such as the competitor chart or the wind chart shown above it, otherwise the padding depends
|
||||
* on the flag set by {@link #setLiveGenerallyPossible(boolean)}
|
||||
*/
|
||||
public TimePanel(Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages,
|
||||
boolean canReplayWhileLiveIsPossible, boolean isScreenLargeEnoughToOfferChartSupport) {
|
||||
boolean canReplayWhileLiveIsPossible, boolean forcePaddingRightToAlignToCharts) {
|
||||
this.timer = timer;
|
||||
this.timeRangeProvider = timeRangeProvider;
|
||||
this.stringMessages = stringMessages;
|
||||
this.canReplayWhileLiveIsPossible = canReplayWhileLiveIsPossible;
|
||||
this.forcePaddingRightToAlignToCharts = forcePaddingRightToAlignToCharts;
|
||||
timer.addTimeListener(this);
|
||||
timer.addPlayStateListener(this);
|
||||
timeRangeProvider.addTimeRangeChangeListener(this);
|
||||
@@ -111,9 +114,6 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
timePanelSliderFlowWrapper = new FlowPanel();
|
||||
timePanelSlider.setStyleName("timePanelSlider");
|
||||
timePanelSlider.getElement().getStyle().setPaddingLeft(66, Unit.PX);
|
||||
if (isScreenLargeEnoughToOfferChartSupport) {
|
||||
timePanelSlider.getElement().getStyle().setPaddingRight(66, Unit.PX);
|
||||
}
|
||||
timePanelSliderFlowWrapper.add(timePanelSlider);
|
||||
|
||||
playSpeedImg = resources.timesliderPlaySpeedIcon();
|
||||
@@ -555,8 +555,19 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
|
||||
*/
|
||||
protected void setLiveGenerallyPossible(boolean possible) {
|
||||
backToLivePlayButton.setVisible(possible);
|
||||
updateTimeSliderPadding(possible);
|
||||
updatePlayPauseButtonsVisibility(timer.getPlayMode());
|
||||
}
|
||||
|
||||
private void updateTimeSliderPadding(boolean backToLivePlayButtonVisible) {
|
||||
Style timePanelStyle = timePanelSlider.getElement().getStyle();
|
||||
if (backToLivePlayButtonVisible || forcePaddingRightToAlignToCharts) {
|
||||
timePanelStyle.setPaddingRight(66, Unit.PX);
|
||||
} else {
|
||||
timePanelStyle.clearPaddingRight();
|
||||
}
|
||||
timeSlider.onResize();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T getSettings() {
|
||||
|
||||
+9
-8
@@ -5,7 +5,6 @@ import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Document;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
@@ -17,6 +16,7 @@ import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.RootLayoutPanel;
|
||||
import com.sap.sailing.gwt.common.client.formfactor.DeviceDetector;
|
||||
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
|
||||
import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel;
|
||||
import com.sap.sailing.gwt.ui.client.MediaService;
|
||||
@@ -97,11 +97,12 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
|
||||
sailingService.getRaceboardData(regattaName, raceName, leaderboardName, leaderboardGroupName, eventId, new AsyncCallback<RaceboardDataDTO>() {
|
||||
@Override
|
||||
public void onSuccess(RaceboardDataDTO result) {
|
||||
// Determine if the screen is large enough to display charts such as the competitor chart or the wind chart.
|
||||
// This decision is made once based on the initial screen height. Resizing the window afterwards will have
|
||||
// no impact on the chart support, i.e. they are available/unavailable based on the initial decision.
|
||||
boolean isScreenLargeEnoughToOfferChartSupport = Document.get().getClientHeight() >= 600;
|
||||
checkUrlParameters(result, showMapControls, isScreenLargeEnoughToOfferChartSupport);
|
||||
// Determine if the charts, such as the competitor chart or the wind chart, the edit marks
|
||||
// panels, such as mark passing and mark position editors and manage media buttons should be shown.
|
||||
// Automatic selection of attached video (if any) also depends on this flag.
|
||||
// The decision is made once during initial page load based on the device type (mobile or not).
|
||||
boolean showChartMarkEditMediaButtonsAndVideo = !DeviceDetector.isMobile();
|
||||
checkUrlParameters(result, showMapControls, showChartMarkEditMediaButtonsAndVideo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,7 +140,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
|
||||
}
|
||||
|
||||
private void checkUrlParameters(RaceboardDataDTO raceboardData, boolean showMapControls,
|
||||
boolean isScreenLargeEnoughToOfferChartSupport) {
|
||||
boolean showChartMarkEditMediaButtonsAndVideo) {
|
||||
if (!raceboardData.isValidLeaderboard()) {
|
||||
createErrorPage(getStringMessages().noSuchLeaderboard());
|
||||
return;
|
||||
@@ -170,7 +171,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
|
||||
RaceBoardPanel raceBoardPanel = new RaceBoardPanel(sailingService, mediaService, getUserService(), asyncActionsExecutor,
|
||||
raceboardData.getCompetitorAndTheirBoats(), timer, selectedRace.getRaceIdentifier(), leaderboardName, leaderboardGroupName, eventId,
|
||||
raceboardViewConfig, RaceBoardEntryPoint.this, getStringMessages(), userAgent, raceTimesInfoProvider, showMapControls,
|
||||
isScreenLargeEnoughToOfferChartSupport);
|
||||
showChartMarkEditMediaButtonsAndVideo);
|
||||
|
||||
createRaceBoardInOneScreenMode(raceBoardPanel, raceboardViewConfig);
|
||||
}
|
||||
|
||||
+34
-34
@@ -37,7 +37,6 @@ import com.sap.sailing.gwt.ui.client.CompetitorColorProviderImpl;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory;
|
||||
import com.sap.sailing.gwt.ui.client.GlobalNavigationPanel;
|
||||
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
|
||||
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimePanel;
|
||||
@@ -133,17 +132,18 @@ public class RaceBoardPanel extends SimplePanel implements LeaderboardUpdateList
|
||||
* @param eventId
|
||||
* an optional event that can be used for "back"-navigation in case the race board shows a race in the
|
||||
* context of an event; may be <code>null</code>.
|
||||
* @param isScreenLargeEnoughToOfferChartSupport
|
||||
* if the screen is large enough to display charts such as the competitor chart or the wind chart, a
|
||||
* padding is provided for the RaceTimePanel that aligns its right border with that of the charts, and
|
||||
* the charts are created. This decision is made once on startup in the {@link RaceBoardEntryPoint} class.
|
||||
* @param showChartMarkEditMediaButtonsAndVideo
|
||||
* if <code>true</code> charts, such as the competitor chart or the wind chart, (as well as edit mark
|
||||
* panels and manage media buttons) are shown and a padding is provided for the RaceTimePanel that
|
||||
* aligns its right border with that of the chart. Otherwise those components will be hidden.
|
||||
* This decision is made once on startup in the {@link RaceBoardEntryPoint} class.
|
||||
*/
|
||||
public RaceBoardPanel(SailingServiceAsync sailingService, MediaServiceAsync mediaService,
|
||||
UserService userService, AsyncActionsExecutor asyncActionsExecutor, Map<CompetitorDTO, BoatDTO> competitorsAndTheirBoats,
|
||||
public RaceBoardPanel(SailingServiceAsync sailingService, MediaServiceAsync mediaService, UserService userService,
|
||||
AsyncActionsExecutor asyncActionsExecutor, Map<CompetitorDTO, BoatDTO> competitorsAndTheirBoats,
|
||||
Timer timer, RegattaAndRaceIdentifier selectedRaceIdentifier, String leaderboardName,
|
||||
String leaderboardGroupName, UUID eventId, RaceBoardViewConfiguration raceboardViewConfiguration,
|
||||
ErrorReporter errorReporter, final StringMessages stringMessages,
|
||||
UserAgentDetails userAgent, RaceTimesInfoProvider raceTimesInfoProvider, boolean showMapControls, boolean isScreenLargeEnoughToOfferChartSupport) {
|
||||
ErrorReporter errorReporter, final StringMessages stringMessages, UserAgentDetails userAgent,
|
||||
RaceTimesInfoProvider raceTimesInfoProvider, boolean showMapControls, boolean showChartMarkEditMediaButtonsAndVideo) {
|
||||
this.sailingService = sailingService;
|
||||
this.mediaService = mediaService;
|
||||
this.stringMessages = stringMessages;
|
||||
@@ -220,7 +220,7 @@ public class RaceBoardPanel extends SimplePanel implements LeaderboardUpdateList
|
||||
leaderboardPanel.setTitle(stringMessages.leaderboard());
|
||||
leaderboardPanel.getElement().getStyle().setMarginLeft(6, Unit.PX);
|
||||
leaderboardPanel.getElement().getStyle().setMarginTop(10, Unit.PX);
|
||||
createOneScreenView(leaderboardName, leaderboardGroupName, eventId, mainPanel, showMapControls, isScreenLargeEnoughToOfferChartSupport, isScreenLargeEnoughToInitiallyDisplayLeaderboard, raceMap, userService); // initializes the raceMap field
|
||||
createOneScreenView(leaderboardName, leaderboardGroupName, eventId, mainPanel, showMapControls, showChartMarkEditMediaButtonsAndVideo, isScreenLargeEnoughToInitiallyDisplayLeaderboard, raceMap, userService); // initializes the raceMap field
|
||||
leaderboardPanel.addLeaderboardUpdateListener(this);
|
||||
// in case the URL configuration contains the name of a competitors filter set we try to activate it
|
||||
// FIXME the competitorsFilterSets has now moved to CompetitorSearchTextBox (which should probably be renamed); pass on the parameters to the LeaderboardPanel and see what it does with it
|
||||
@@ -234,52 +234,52 @@ public class RaceBoardPanel extends SimplePanel implements LeaderboardUpdateList
|
||||
}
|
||||
}
|
||||
timePanel = new RaceTimePanel(userService, timer, timeRangeWithZoomModel, stringMessages, raceTimesInfoProvider,
|
||||
false, isScreenLargeEnoughToOfferChartSupport, selectedRaceIdentifier, getConfiguration().getInitialDurationAfterRaceStartInReplay());
|
||||
false, showChartMarkEditMediaButtonsAndVideo, selectedRaceIdentifier, getConfiguration().getInitialDurationAfterRaceStartInReplay());
|
||||
timeRangeWithZoomModel.addTimeZoomChangeListener(timePanel);
|
||||
raceTimesInfoProvider.addRaceTimesInfoProviderListener(timePanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event
|
||||
* an optional event; may be <code>null</code> or else can be used to show some context information in
|
||||
* the {@link GlobalNavigationPanel}.
|
||||
* @param isScreenLargeEnoughToOfferChartSupport
|
||||
* if the screen is large enough to display charts such as the competitor chart or the wind chart, a
|
||||
* padding is provided for the RaceTimePanel that aligns its right border with that of the charts, and
|
||||
* the charts are created.
|
||||
*/
|
||||
private void createOneScreenView(String leaderboardName, String leaderboardGroupName, UUID event, FlowPanel mainPanel,
|
||||
boolean showMapControls, boolean isScreenLargeEnoughToOfferChartSupport, boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard,
|
||||
boolean showMapControls, boolean showChartMarkEditMediaButtonsAndVideo, boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard,
|
||||
RaceMap raceMap, UserService userService) {
|
||||
// create the default leaderboard and select the right race
|
||||
raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceMap);
|
||||
List<Component<?>> components = new ArrayList<Component<?>>();
|
||||
if (isScreenLargeEnoughToOfferChartSupport) {
|
||||
competitorChart = new MultiCompetitorRaceChart(sailingService, asyncActionsExecutor, competitorSelectionProvider, selectedRaceIdentifier,
|
||||
if (showChartMarkEditMediaButtonsAndVideo) {
|
||||
competitorChart = new MultiCompetitorRaceChart(sailingService, asyncActionsExecutor, competitorSelectionProvider, selectedRaceIdentifier,
|
||||
timer, timeRangeWithZoomModel, stringMessages, errorReporter, true, true, leaderboardGroupName, leaderboardName);
|
||||
competitorChart.getEntryWidget().setTitle(stringMessages.competitorCharts());
|
||||
competitorChart.setVisible(false);
|
||||
components.add(competitorChart);
|
||||
windChart = new WindChart(sailingService, selectedRaceIdentifier, timer, timeRangeWithZoomModel, new WindChartSettings(),
|
||||
|
||||
windChart = new WindChart(sailingService, selectedRaceIdentifier, timer, timeRangeWithZoomModel, new WindChartSettings(),
|
||||
stringMessages, asyncActionsExecutor, errorReporter, /* compactChart */ true);
|
||||
windChart.setVisible(false);
|
||||
windChart.getEntryWidget().setTitle(stringMessages.windChart());
|
||||
components.add(windChart);
|
||||
}
|
||||
|
||||
editMarkPassingPanel = new EditMarkPassingsPanel(sailingService, selectedRaceIdentifier,
|
||||
stringMessages, competitorSelectionProvider, errorReporter, timer);
|
||||
editMarkPassingPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
|
||||
editMarkPassingPanel.getEntryWidget().setTitle(stringMessages.editMarkPassings());
|
||||
components.add(editMarkPassingPanel);
|
||||
editMarkPositionPanel = new EditMarkPositionPanel(raceMap, leaderboardPanel, selectedRaceIdentifier, leaderboardName, stringMessages, sailingService, timer, timeRangeWithZoomModel,
|
||||
asyncActionsExecutor, errorReporter);
|
||||
editMarkPositionPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
|
||||
components.add(editMarkPositionPanel);
|
||||
boolean autoSelectMedia = getConfiguration().isAutoSelectMedia();
|
||||
if (showChartMarkEditMediaButtonsAndVideo) {
|
||||
editMarkPassingPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
|
||||
editMarkPassingPanel.getEntryWidget().setTitle(stringMessages.editMarkPassings());
|
||||
components.add(editMarkPassingPanel);
|
||||
}
|
||||
|
||||
editMarkPositionPanel = new EditMarkPositionPanel(raceMap, leaderboardPanel, selectedRaceIdentifier, leaderboardName,
|
||||
stringMessages, sailingService, timer, timeRangeWithZoomModel, asyncActionsExecutor, errorReporter);
|
||||
if (showChartMarkEditMediaButtonsAndVideo) {
|
||||
editMarkPositionPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
|
||||
components.add(editMarkPositionPanel);
|
||||
}
|
||||
|
||||
boolean autoSelectMedia = getConfiguration().isAutoSelectMedia() && showChartMarkEditMediaButtonsAndVideo;
|
||||
MediaPlayerManagerComponent mediaPlayerManagerComponent = new MediaPlayerManagerComponent(
|
||||
selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, userService, stringMessages,
|
||||
errorReporter, userAgent, this, autoSelectMedia);
|
||||
leaderboardAndMapViewer = new SideBySideComponentViewer(leaderboardPanel, raceMap, mediaPlayerManagerComponent, components, stringMessages, userService, editMarkPassingPanel, editMarkPositionPanel);
|
||||
leaderboardAndMapViewer = new SideBySideComponentViewer(leaderboardPanel, raceMap, mediaPlayerManagerComponent,
|
||||
components, stringMessages, userService, editMarkPassingPanel, editMarkPositionPanel);
|
||||
this.setupUserManagementControlPanel(userService);
|
||||
componentViewers.add(leaderboardAndMapViewer);
|
||||
for (ComponentViewer componentViewer : componentViewers) {
|
||||
@@ -287,7 +287,7 @@ public class RaceBoardPanel extends SimplePanel implements LeaderboardUpdateList
|
||||
}
|
||||
boolean showLeaderboard = getConfiguration().isShowLeaderboard() && isScreenLargeEnoughToInitiallyDisplayLeaderboard;
|
||||
setLeaderboardVisible(showLeaderboard);
|
||||
if (isScreenLargeEnoughToOfferChartSupport) {
|
||||
if (showChartMarkEditMediaButtonsAndVideo) {
|
||||
setWindChartVisible(getConfiguration().isShowWindChart());
|
||||
setCompetitorChartVisible(getConfiguration().isShowCompetitorsChart());
|
||||
}
|
||||
|
||||
+2
-2
@@ -158,6 +158,7 @@ import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.NotFoundException;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.domain.common.PolarSheetsXYDiagramData;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RaceFetcher;
|
||||
@@ -430,7 +431,6 @@ import com.sap.sailing.server.operationaltransformation.UpdateServerConfiguratio
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateSpecificRegatta;
|
||||
import com.sap.sailing.server.simulation.SimulationService;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationResults;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
@@ -1494,7 +1494,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
PathDTO[] pathDTOs = new PathDTO[noOfPaths];
|
||||
int index = noOfPaths - 1;
|
||||
for (Entry<PathType, Path> entry : paths.entrySet()) {
|
||||
pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
|
||||
pathDTOs[index] = new PathDTO(entry.getKey());
|
||||
// fill pathDTO with path points where speed is true wind speed
|
||||
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
|
||||
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
|
||||
|
||||
+2
-2
@@ -19,6 +19,7 @@ import java.util.logging.Logger;
|
||||
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
@@ -61,7 +62,6 @@ import com.sap.sailing.server.simulation.SimulationServiceFactory;
|
||||
import com.sap.sailing.simulator.BoatClassProperties;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.Simulator;
|
||||
@@ -949,7 +949,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
|
||||
// NOTE: pathName convention is: sort-digit + "#" + path-name
|
||||
// pathsAndNames is TreeMap which ensures sorting
|
||||
pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
|
||||
pathDTOs[index] = new PathDTO(entry.getKey());
|
||||
|
||||
// fill pathDTO with path points where speed is true wind speed
|
||||
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
|
||||
|
||||
+14
-2
@@ -2,19 +2,31 @@ package com.sap.sailing.gwt.ui.shared;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.domain.common.dto.NamedDTO;
|
||||
|
||||
public class PathDTO extends NamedDTO {
|
||||
private static final long serialVersionUID = 2381814072763342186L;
|
||||
private static final long serialVersionUID = 4926185583314563898L;
|
||||
private List<SimulatorWindDTO> points;
|
||||
private boolean algorithmTimedOut;
|
||||
private boolean mixedLeg;
|
||||
private PathType pathType;
|
||||
|
||||
public PathDTO() {
|
||||
protected PathDTO() {
|
||||
}
|
||||
|
||||
public PathDTO(PathType pathType) {
|
||||
super(pathType.getTxtId());
|
||||
this.pathType = pathType;
|
||||
}
|
||||
|
||||
public PathDTO(final String name) {
|
||||
super(name);
|
||||
this.pathType = null;
|
||||
}
|
||||
|
||||
public PathType getPathType() {
|
||||
return pathType;
|
||||
}
|
||||
|
||||
public List<SimulatorWindDTO> getPoints() {
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.PathDTO;
|
||||
|
||||
public class PathNameFormatter {
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public PathNameFormatter(StringMessages stringMessages) {
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
public String format(PathDTO path) {
|
||||
switch (path.getPathType()) {
|
||||
case OMNISCIENT: return stringMessages.omniscient();
|
||||
case OPPORTUNIST_LEFT: return stringMessages.opportunistLeft();
|
||||
case OPPORTUNIST_RIGHT: return stringMessages.opportunistRight();
|
||||
case ONE_TURNER_LEFT: return stringMessages.oneTurnerLeft();
|
||||
case ONE_TURNER_RIGHT: return stringMessages.oneTurnerRight();
|
||||
}
|
||||
// fallback, if no path type is specified
|
||||
return path.getName();
|
||||
}
|
||||
|
||||
}
|
||||
+8
-7
@@ -56,6 +56,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final AsyncActionsExecutor asyncActionsExecutor;
|
||||
private final ColorPalette colors;
|
||||
private final PathNameFormatter pathNameFormatter;
|
||||
private SimulatorResultsDTO simulationResult;
|
||||
private Boolean[] visiblePaths;
|
||||
private PathDTO racePath;
|
||||
@@ -70,6 +71,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
this.stringMessages = stringMessages;
|
||||
this.asyncActionsExecutor = asyncActionsExecutor;
|
||||
this.colors = new ColorPaletteGenerator();
|
||||
this.pathNameFormatter = new PathNameFormatter(stringMessages);
|
||||
}
|
||||
|
||||
public void updateLeg(int newLeg, boolean clearCanvas, long newVersion) {
|
||||
@@ -225,7 +227,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
double timewidth = txtmet.getWidth();
|
||||
double txtmaxwidth = 0.0;
|
||||
if (racePath != null) {
|
||||
txtmet = context2d.measureText(racePath.getName().split("#")[1]);
|
||||
txtmet = context2d.measureText(stringMessages.raceLeader());
|
||||
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
|
||||
}
|
||||
boolean containsTimeOut = false;
|
||||
@@ -238,7 +240,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
if (path.getMixedLeg()) {
|
||||
containsMixedLeg = true;
|
||||
}
|
||||
txtmet = context2d.measureText(path.getName().split("#")[1]);
|
||||
txtmet = context2d.measureText(pathNameFormatter.format(path));
|
||||
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
|
||||
}
|
||||
double newwidth = 0;
|
||||
@@ -268,13 +270,13 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
int canvasHeight = (int)Math.ceil(yOffset + rectHeight*(paths.length + (racePath == null? 0 : 1)));
|
||||
setCanvasSize(canvas, canvasWidth, canvasHeight);
|
||||
if (racePath != null) {
|
||||
drawRectangleWithText(context2d, xOffset, yOffset, null,
|
||||
racePath.getName().split("#")[1], getFormattedTime(racePath.getPathTime()), txtmaxwidth, timewidth, deltaTime, true);
|
||||
drawRectangleWithText(context2d, xOffset, yOffset, null, stringMessages.raceLeader(),
|
||||
getFormattedTime(racePath.getPathTime()), txtmaxwidth, timewidth, deltaTime, true);
|
||||
}
|
||||
for (PathDTO path : paths) {
|
||||
String timeText = (path.getMixedLeg() ? mixedLegText : (path.getAlgorithmTimedOut() ? algorithmTimedOutText : getFormattedTime(path.getPathTime())));
|
||||
drawRectangleWithText(context2d, xOffset, yOffset + (paths.length-index-(racePath==null?1:0)) * rectHeight, this.colors.getColor(paths.length-1-index),
|
||||
path.getName().split("#")[1], timeText, txtmaxwidth, timewidth, (path.getMixedLeg()?deltaMixedLeg:(path.getAlgorithmTimedOut()?deltaTimeOut:deltaTime)), visiblePaths[paths.length-1-index]);
|
||||
pathNameFormatter.format(path), timeText, txtmaxwidth, timewidth, (path.getMixedLeg()?deltaMixedLeg:(path.getAlgorithmTimedOut()?deltaTimeOut:deltaTime)), visiblePaths[paths.length-1-index]);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -350,12 +352,11 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
simulationResult = result;
|
||||
PathDTO[] paths = result.getPaths();
|
||||
if (result.getLegDuration() > 0) {
|
||||
racePath = new PathDTO();
|
||||
racePath = new PathDTO("0#Race Leader");
|
||||
List<SimulatorWindDTO> racePathPoints = new ArrayList<SimulatorWindDTO>();
|
||||
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint));
|
||||
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint + result.getLegDuration()));
|
||||
racePath.setPoints(racePathPoints);
|
||||
racePath.setName("0#Race Leader");
|
||||
} else {
|
||||
racePath = null;
|
||||
}
|
||||
|
||||
+10
-3
@@ -11,6 +11,7 @@ import com.google.gwt.i18n.client.TimeZone;
|
||||
import com.google.gwt.maps.client.MapWidget;
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.CoordinateSystem;
|
||||
import com.sap.sailing.gwt.ui.simulator.racemap.FullCanvasOverlay;
|
||||
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
|
||||
@@ -22,6 +23,8 @@ import com.sap.sailing.simulator.util.SailingSimulatorConstants;
|
||||
*
|
||||
*/
|
||||
public class PathLegendCanvasOverlay extends FullCanvasOverlay {
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private List<PathCanvasOverlay> pathOverlays;
|
||||
|
||||
@@ -43,13 +46,17 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
|
||||
private String algorithmTimedOutText = "out-of-bounds";
|
||||
private String mixedLegText = "ambiguous wind";
|
||||
|
||||
public PathLegendCanvasOverlay(MapWidget map, int zIndex, char mode, CoordinateSystem coordinateSystem) {
|
||||
public PathLegendCanvasOverlay(MapWidget map, int zIndex, char mode, CoordinateSystem coordinateSystem,
|
||||
StringMessages stringMessages) {
|
||||
super(map, zIndex, coordinateSystem);
|
||||
this.stringMessages = stringMessages;
|
||||
this.mode = mode;
|
||||
if (this.mode == SailingSimulatorConstants.ModeEvent) {
|
||||
yOffset = 170;
|
||||
}
|
||||
setPathOverlays(null);
|
||||
this.algorithmTimedOutText = stringMessages.simulationLegendAlgorithmTimedOutText();
|
||||
this.mixedLegText = stringMessages.simulationLegendMixedLegText();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,7 +145,7 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
|
||||
double cY = yOffset + (pathOverlays.size()-1) * rectHeight + 75.0;
|
||||
context2d.setGlobalAlpha(0.80);
|
||||
context2d.setFillStyle("white");
|
||||
double bgWidth = 100.0;
|
||||
double bgWidth = 120.0;
|
||||
double bgHeight = 70.0;
|
||||
if (this.curSpeed == 0.0) {
|
||||
bgHeight = 20.0;
|
||||
@@ -148,7 +155,7 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
|
||||
context2d.setFont(textFont);
|
||||
context2d.setFillStyle(textColor);
|
||||
//TextMetrics txtmet;
|
||||
String cText = "Current: " + SimulatorMainPanel.formatSliderValue(curSpeed) + "kn";
|
||||
String cText = stringMessages.current() + ": " + stringMessages.knotsValue(curSpeed);
|
||||
txtmet = context2d.measureText(cText);
|
||||
double txtwidth = txtmet.getWidth();
|
||||
context2d.fillText(cText, cX-(txtwidth/2.0), cY-25);
|
||||
|
||||
+6
-3
@@ -50,6 +50,7 @@ import com.sap.sailing.gwt.ui.shared.WindFieldDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindFieldGenParamsDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.GoogleMapAPIKey;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.GoogleMapStyleHelper;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.PathNameFormatter;
|
||||
import com.sap.sailing.gwt.ui.simulator.util.ColorPalette;
|
||||
import com.sap.sailing.gwt.ui.simulator.util.ColorPaletteGenerator;
|
||||
import com.sap.sailing.gwt.ui.simulator.util.SimulatorResources;
|
||||
@@ -110,7 +111,8 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
|
||||
private static Logger LOGGER = Logger.getLogger(SimulatorMap.class.getName());
|
||||
private static boolean SHOW_ONLY_PATH_POLYLINE = false;
|
||||
private char raceCourseDirection;
|
||||
private final CoordinateSystem coordinateSystem;
|
||||
private final CoordinateSystem coordinateSystem;
|
||||
private final PathNameFormatter pathNameFormatter;
|
||||
|
||||
public enum ViewName {
|
||||
SUMMARY, REPLAY, WINDDISPLAY
|
||||
@@ -182,7 +184,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
|
||||
}
|
||||
|
||||
ReplayPathCanvasOverlay replayPathCanvasOverlay = new ReplayPathCanvasOverlay(map, SimulatorMapOverlaysZIndexes.PATH_ZINDEX,
|
||||
pathName.split("#")[1], timer, windParams, algorithmTimedOut, currentPath.getMixedLeg(), coordinateSystem);
|
||||
pathNameFormatter.format(currentPath), timer, windParams, algorithmTimedOut, currentPath.getMixedLeg(), coordinateSystem);
|
||||
replayPathCanvasOverlays.add(replayPathCanvasOverlay);
|
||||
replayPathCanvasOverlay.setPathColor(colorPalette.getColor(Integer.parseInt(pathName.split("#")[0])-1));
|
||||
|
||||
@@ -337,6 +339,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
|
||||
TimePanel<TimePanelSettings> timePanel, WindFieldGenParamsDTO windParams,
|
||||
SimpleBusyIndicator busyIndicator, char mode, SimulatorMainPanel parent, boolean showMapControls, CoordinateSystem coordinateSystem) {
|
||||
this.coordinateSystem = coordinateSystem;
|
||||
this.pathNameFormatter = new PathNameFormatter(stringMessages);
|
||||
this.simulatorService = simulatorSvc;
|
||||
this.stringMessages = stringMessages;
|
||||
this.errorReporter = errorReporter;
|
||||
@@ -595,7 +598,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
|
||||
windLineCanvasOverlay = new WindLineCanvasOverlay(map, SimulatorMapOverlaysZIndexes.WINDLINE_ZINDEX, timer, coordinateSystem);
|
||||
}
|
||||
replayPathCanvasOverlays = new ArrayList<PathCanvasOverlay>();
|
||||
legendCanvasOverlay = new PathLegendCanvasOverlay(map, SimulatorMapOverlaysZIndexes.PATHLEGEND_ZINDEX, mode, coordinateSystem);
|
||||
legendCanvasOverlay = new PathLegendCanvasOverlay(map, SimulatorMapOverlaysZIndexes.PATHLEGEND_ZINDEX, mode, coordinateSystem, stringMessages);
|
||||
Window.addResizeHandler(new ResizeHandler() {
|
||||
@Override
|
||||
public void onResize(ResizeEvent event) {
|
||||
|
||||
+1
-1
@@ -4,8 +4,8 @@ import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.SimulationResults;
|
||||
|
||||
|
||||
+1
-1
@@ -26,6 +26,7 @@ import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.LegIdentifierImpl;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
@@ -42,7 +43,6 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.SimulationResults;
|
||||
|
||||
+1
-1
@@ -11,10 +11,10 @@ import junit.framework.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagram49STG;
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.sap.sailing.simulator;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.sap.sailing.simulator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.simulator.impl.SparseSimulationDataException;
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -4,8 +4,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.common.PathType;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.RaceProperties;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.Simulator;
|
||||
|
||||
Reference in new issue
Block a user