diff --git a/java/com.sap.sailing.dashboards.gwt/RibDashboard.css b/java/com.sap.sailing.dashboards.gwt/RibDashboard.css index ef3be51375d..cb096f5372f 100644 --- a/java/com.sap.sailing.dashboards.gwt/RibDashboard.css +++ b/java/com.sap.sailing.dashboards.gwt/RibDashboard.css @@ -22,7 +22,7 @@ } .highcharts-container { - position: absulute; + position: absolute; top: 0pt; bottom: 0pt; left: 0pt; @@ -38,11 +38,10 @@ width: 100%; bottom: 0pt; text-align: center; - font-weight: bold; font-size: 15pt; line-height: 30pt; color: black; - font-family: "Arial"; + font-family: 'Open Sans', Arial, Verdana, sans-serif; z-index: 2; } @@ -134,5 +133,5 @@ font-weight: bold; font-size: 13px; color: grey; - font-family: "Arial"; + font-family: 'Open Sans', Arial, Verdana, sans-serif; } \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/RibDashboard.html b/java/com.sap.sailing.dashboards.gwt/RibDashboard.html index 5d6d9768d35..eb761aa4f82 100644 --- a/java/com.sap.sailing.dashboards.gwt/RibDashboard.html +++ b/java/com.sap.sailing.dashboards.gwt/RibDashboard.html @@ -10,10 +10,12 @@ - - -
null when {@link RaceColumn} was linked to {@link TrackedRace}.
+ *
+ * @author Alexander Ries (D062114)
+ *
+ */
+public class RaceExecutionOrderProvdiderAttachDetachTest extends TrackBasedTest {
+ private FlexibleLeaderboard flexibleLeaderboard;
+ private RaceColumnInSeries raceColumnInSeries;
+ private Fleet fleet;
+ private TrackedRaceImpl trackedRace;
+ private Regatta regatta;
+ private Series series;
+
+ private final String REGATTA = "TestRegatta";
+ private final String RACE = "TestRace";
+ private final String FLEET = "TestFleet";
+ private final String BOATCLASS = "TestClass";
+ private final String SERIES = "TestSeries";
+ private final String FLEXIBLELEADERBOARD = "TestFlexibleLeaderboard";
+ private final String RACECOLUMN_SERIES = "TestSeriesRaceColumn";
+ private final String RACECOLUMN_FLEXIBLELEADERBOARD = "TestFlexibleLeaderboardRaceColumn";
+
+ @Test
+ public void testRaceExecutionOrderProviderAttachDetachWithRaceCollumn() {
+ trackedRace = createTestTrackedRace(REGATTA, RACE, BOATCLASS, Collections.null, the current {@link TrackedRace} would save the wind fixes earlier.
+ *
+ * @author Alexander Ries (D062114)
+ *
+ */
+public interface RaceExecutionOrderProvider {
+
+ /**
+ * Parameter race is a {@link TrackedRace} from which the method returns the previous
+ * {@link TrackedRace}s in the execution order of a {@link Regatta}. This expresses the fact that the races returned
+ * by this method must all have been finished before race can start.
+ */
+ SetreadObject method, the owner's fields may not all be initialized. The
+ * readResolve() method is usually a good place to do so.
+ */
+ void triggerUpdate();
+}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
index c98280a45e8..2a8c9168b16 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
@@ -275,6 +275,27 @@ public interface TrackedRace extends Serializable {
* is returned. Otherwise, the center of gravity between the mark positions is computed and returned.
*/
Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint);
+
+ /**
+ * Checks whether the {@link Wind#getTimePoint()} is in range of start and end {@link TimePoint}s plus extra time
+ * for wind recording. If, based on a {@link RaceExecutionOrderProvider}, there is no previous race that takes the
+ * wind fix, an extended time range lead (see
+ * {@link TrackedRaceImpl#EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS}) is used to record wind even a long
+ * time before the race start.
+ *
+ *
+ * A race does not record wind when both, {@link #getStartOfTracking()} and {@link #getStartOfRace()} are
+ * null. Wind is not recorded when it is after the later of {@link #getEndOfRace()} and
+ * {@link #getEndOfTracking()} and one of the two is not null.
+ *
+ *
+ * This default implementation returns true which may be useful for tests and mocked implementations; however, real
+ * implementations shall override this and provide a meaningful implementation according to the specification given
+ * above.
+ */
+ default boolean takesWindFix(Wind wind) {
+ return true;
+ }
/**
* Same as {@link #getWind(Position, TimePoint, Set) getWind(p, at, Collections.emptyList())}
@@ -652,9 +673,9 @@ public interface TrackedRace extends Serializable {
void detachRaceLog(Serializable identifier);
/**
- * Detaches all {@link RaceLog} instances from this race
+ * Detaches the link {@link RaceExecutionOrderProvider}
*/
- void detachAllRaceLogs();
+ void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider);
/**
* Attaches the passed race log with this {@link TrackedRace}.
@@ -674,6 +695,12 @@ public interface TrackedRace extends Serializable {
*/
void attachRegattaLog(RegattaLog regattaLog);
+ /**
+ * Attaches a {@link RaceExecutionOrderProvider} to make a {@link TrackedRace} aware
+ * which races are scheduled around it in the execution order of a {@link Regatta}.
+ * */
+ void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider);
+
/**
* Returns the attached race log event track for this race if any.
* Otherwise
+ *
+ * A race does not record wind when both, {@link #getStartOfTracking()} and {@link #getStartOfRace()} are null.
@@ -823,4 +850,5 @@ public interface TrackedRace extends Serializable {
Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, NoWindException;
void setPolarDataService(PolarDataService polarDataService);
+
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
index 59827408828..e1463636149 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
@@ -24,7 +24,6 @@ import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.Waypoint;
-import com.sap.sailing.domain.common.TimingConstants;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
@@ -658,17 +657,7 @@ DynamicTrackedRace, GPSTrackListenernull.
+ * Wind is not recorded when it is after the later of {@link #getEndOfRace()} and {@link #getEndOfTracking()} and one of the
+ * two is not null.
+ */
+ @Override
+ public boolean takesWindFix(Wind wind) {
+ final boolean result;
+ final TimePoint earliestStartTimePoint = Util.getEarliestOfTimePoints(getStartOfRace(), getStartOfTracking());
+ final TimePoint latestEndTimePoint = Util.getLatestOfTimePoints(getEndOfRace(), getEndOfTracking());
+ if (earliestStartTimePoint != null) {
+ // first check if the fix meets the criteria set by the latestEndTimePoint: either the latestEndTimePoint is null, meaning an
+ // open interval which will continue to accept late wind fixes, or the fix time point is before the latestEndTimePoint plus a grace
+ // interval:
+ if (latestEndTimePoint == null || wind.getTimePoint().minus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).before(latestEndTimePoint)) {
+ // then check, if fix is accepted anyway because it's after earliestStartTimePoint.minus(TIME_BEFORE_START_TO_TRACK_WIND_MILLIS)
+ // and before latestEndTimePoint.plus(IS_LIVE_GRACE_PERIOD_IN_MILLIS) or latestEndTimePoint is null. In this case, no expensive
+ // recursive check whether previous races take the fix are required.
+ if (wind.getTimePoint().plus(TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).after(earliestStartTimePoint)) {
+ result = true;
+ } else {
+ // if the fix is older than even the extended lead interval would accept, don't accept the fix:
+ if (wind.getTimePoint().plus(EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).before(earliestStartTimePoint)) {
+ result = false;
+ } else {
+ // the fix is in the critical interval between EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS and
+ // TIME_BEFORE_START_TO_TRACK_WIND_MILLIS before the earliestStartTimePoint; the fix shall only be accepted
+ // if no previous race exists that accepts it
+ result = noPreviousRaceTakesWind(wind);
+ }
+ }
+ } else {
+ result = false; // don't accept the fix if it's after the latest end time point plus some grace interval
+ }
+ } else {
+ result = false; // don't accept a fix if we don't have any start time information about the race
+ }
+ return result;
+ }
+
+ private boolean noPreviousRaceTakesWind(Wind wind) {
+ final boolean result;
+ Setnull {@link #raceListeners} collection) by
* a new one into which all other collection contents are copied.
*/
- private Object readResolve() {
+ private Object readResolve() throws ObjectStreamException {
TrackedRegattaImpl result = new TrackedRegattaImpl(this.regatta);
result.trackedRaces.putAll(this.trackedRaces);
result.trackedRacesByBoatClass.putAll(this.trackedRacesByBoatClass);
diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java
index 128b68ed781..9eca28dba48 100755
--- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java
+++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java
@@ -49,6 +49,7 @@ import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceAbortedListener;
import com.sap.sailing.domain.tracking.RaceChangeListener;
+import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
import com.sap.sailing.domain.tracking.TrackedLeg;
@@ -590,10 +591,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
return null;
}
- @Override
- public void detachAllRaceLogs() {
- }
-
@Override
public void invalidateStartTime() {
}
@@ -779,4 +776,12 @@ public class MockedTrackedRace implements DynamicTrackedRace {
public RankingMetric getRankingMetric() {
return null;
}
+
+ @Override
+ public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
+ }
+
+ @Override
+ public void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
+ }
}
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java
index dbef3735dcc..89587544b76 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java
@@ -106,10 +106,10 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
JSONArray jsonLeaderboards = new JSONArray();
Mapnull and the other
+ * !null, the TimePoint that is not !null gets returned. If both are null,
+ * null is the result.
+ */
+ public static TimePoint getEarliestOfTimePoints(TimePoint a, TimePoint b) {
+ TimePoint result = null;
+ if (a != null && b != null) {
+ result = a.before(b) ? a : b;
+ } else {
+ result = (a != null && b == null) ? a : (a == null && b != null) ? b : null;
+ }
+ return result;
+ }
+
+ /**
+ * Returns the latest {@link TimePoint} of a and b. If one of them is null and the other
+ * !null, the TimePoint that is not !null gets returned. If both are null,
+ * null is the result.
+ */
+ public static TimePoint getLatestOfTimePoints(TimePoint a, TimePoint b) {
+ TimePoint result = null;
+ if (a != null && b != null) {
+ result = a.after(b) ? a : b;
+ } else {
+ result = (a != null && b == null) ? a : (a == null && b != null) ? b : null;
+ }
+ return result;
+ }
+
+ /**
+ * Returns true if timePoint is after a an before b.
+ * If one of the parameters is null the method returns false.
+ */
+ public static boolean isTimePointInRangeOfTimePointsAandB(TimePoint timePoint, TimePoint a, TimePoint b) {
+ boolean result = false;
+ if (timePoint != null && a != null && b != null) {
+ result = timePoint.after(a) && timePoint.before(b);
+ }
+ return result;
+ }
}
\ No newline at end of file