Merge branch 'master' into translation

This commit is contained in:
Benjamin Barth committed 2016-05-02 16:00:26 +02:00
commit 79b25789b4
45 files changed
+446 -201

No files matched your search

@@ -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,4 +1,4 @@
package com.sap.sailing.simulator;
package com.sap.sailing.domain.common;
public enum PathType {
OMNISCIENT("1#Omniscient"),
@@ -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.
@@ -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
@@ -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;
}
/**
@@ -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(),
@@ -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));
@@ -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);
@@ -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;
@@ -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) {
@@ -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;
@@ -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();
}
@@ -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
@@ -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
@@ -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() {
@@ -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);
}
@@ -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());
}
@@ -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()) {
@@ -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>();
@@ -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() {
@@ -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();
}
}
@@ -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;
}
@@ -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);
@@ -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) {
@@ -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;
@@ -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;
@@ -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;
@@ -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;