mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-28 06:47:15 +00:00
Merge remote-tracking branch 'origin/master' into bug2610
This commit is contained in:
commit
96ca0d37fa
38 files changed
+438
-179
No files matched your search
@@ -94,8 +94,8 @@ public class TracTrac {
|
||||
new MillisecondsTimePoint(record.getTrackingStartTime().asMillis()),
|
||||
new MillisecondsTimePoint(record.getTrackingEndTime().asMillis()),
|
||||
raceLogStore, regattaLogStore,
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, /* simulateWithStartTimeNow */
|
||||
false, /*useTracTracMarkPassings*/ false,
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, /* offsetToStartTimeOfSimulatedRace */
|
||||
null, /*useTracTracMarkPassings*/ false,
|
||||
/* tracTracUsername */"", /* tracTracPassword */"", record.getRaceStatus(),
|
||||
record.getRaceVisibility());
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ public abstract class AbstractSpeedImpl implements Speed {
|
||||
|
||||
@Override
|
||||
public Duration getDuration(Distance distance) {
|
||||
return new MillisecondsDurationImpl((long) (1000 * distance.getMeters() / getMetersPerSecond()));
|
||||
return distance == null ? null : new MillisecondsDurationImpl((long) (1000 * distance.getMeters() / getMetersPerSecond()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-4
@@ -60,7 +60,7 @@ public class MultipleClassesInRegattaTest {
|
||||
httpAndHost
|
||||
+ "/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=cce678c8-97e6-11e0-9aed-406186cbf87c"),
|
||||
new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI),
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
|
||||
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
|
||||
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
|
||||
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
|
||||
@@ -71,7 +71,7 @@ public class MultipleClassesInRegattaTest {
|
||||
httpAndHost
|
||||
+ "/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=11290bd6-97e7-11e0-9aed-406186cbf87c"),
|
||||
new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI),
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
|
||||
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
|
||||
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
|
||||
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
|
||||
@@ -82,7 +82,7 @@ public class MultipleClassesInRegattaTest {
|
||||
httpAndHost
|
||||
+ "/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=39635b24-97e7-11e0-9aed-406186cbf87c"),
|
||||
new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI),
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
|
||||
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
|
||||
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
|
||||
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
|
||||
@@ -93,7 +93,7 @@ public class MultipleClassesInRegattaTest {
|
||||
httpAndHost
|
||||
+ "/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=04498426-7dfd-11e0-8236-406186cbf87c"),
|
||||
new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI),
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
|
||||
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
|
||||
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
|
||||
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ public class UnicodeCharactersInCompetitorNamesTest {
|
||||
+ TracTracConnectionConstants.PORT_STORED), new URI(
|
||||
"http://tracms.traclive.dk/update_course"),
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l,
|
||||
/* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
|
||||
/* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
|
||||
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
|
||||
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, "tracTest", "tracTest", "", "",
|
||||
new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class));
|
||||
|
||||
+15
-9
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.RaceCourseReceiver;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.Simulator;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.tractrac.model.lib.api.data.IPosition;
|
||||
@@ -95,7 +96,6 @@ public interface DomainFactory {
|
||||
* Fetch a race definition previously created by a call to {@link #getOrCreateRaceDefinitionAndTrackedRace}. If no such
|
||||
* race definition was created so far, the call blocks until such a definition is provided by a call to
|
||||
* {@link #getOrCreateRaceDefinitionAndTrackedRace}.
|
||||
* @param raceId TODO
|
||||
*/
|
||||
RaceDefinition getAndWaitForRaceDefinition(UUID raceId);
|
||||
|
||||
@@ -105,7 +105,6 @@ public interface DomainFactory {
|
||||
* A new {@link com.sap.sailing.domain.base.Regatta} is created if no event by
|
||||
* an equal name with a boat class with an equal name as the <code>event</code>'s
|
||||
* boat class exists yet.
|
||||
* @param trackedRegattaRegistry TODO
|
||||
*/
|
||||
com.sap.sailing.domain.base.Regatta getOrCreateDefaultRegatta(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
IRace race, TrackedRegattaRegistry trackedRegattaRegistry);
|
||||
@@ -134,27 +133,30 @@ public interface DomainFactory {
|
||||
* if <code>null</code>, all stored data until the "end of time" will be loaded that the event has
|
||||
* to provide, particularly for the mark positions which are stored per event, not per race; otherwise,
|
||||
* particularly the mark position loading will be constrained to this end time.
|
||||
* @param offsetToStartTimeOfSimulatedRace
|
||||
* if non-<code>null</code>, the {@link Simulator} will be used with this duration as start offset
|
||||
* @param windStore
|
||||
* Provides the capability to obtain the {@link WindTrack}s for the different wind sources. A trivial
|
||||
* implementation is {@link EmptyWindStore} which simply provides new, empty tracks. This is always
|
||||
* available but loses track of the wind, e.g., during server restarts.
|
||||
* @param raceLogResolver TODO
|
||||
*/
|
||||
TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
|
||||
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, SubscriberInitializationException;
|
||||
|
||||
/**
|
||||
* Same as {@link #createRaceTracker(URL, URI, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)}, only that
|
||||
* a predefined {@link Regatta} is used to hold the resulting races.
|
||||
* @param raceLogResolver TODO
|
||||
* Same as {@link #createRaceTracker(URL, URI, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)},
|
||||
* only that a predefined {@link Regatta} is used to hold the resulting races.
|
||||
*
|
||||
* @param offsetToStartTimeOfSimulatedRace
|
||||
* if non-<code>null</code>, the {@link Simulator} will be used with this duration as start offset
|
||||
*/
|
||||
RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
|
||||
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
|
||||
@@ -262,9 +264,13 @@ public interface DomainFactory {
|
||||
|
||||
Util.Pair<Iterable<com.sap.sailing.domain.base.Competitor>, BoatClass> getCompetitorsAndDominantBoatClass(IRace race);
|
||||
|
||||
/**
|
||||
* @param offsetToStartTimeOfSimulatedRace
|
||||
* if non-<code>null</code>, the {@link Simulator} will be used with this duration as start offset
|
||||
*/
|
||||
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI, URI storedURI,
|
||||
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility);
|
||||
/**
|
||||
* Removes all knowledge about <code>tractracRace</code> which includes removing it from the race cache, from the
|
||||
|
||||
+5
-2
@@ -17,6 +17,8 @@ import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackerManager;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.Simulator;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
@@ -65,12 +67,13 @@ public interface TracTracAdapter {
|
||||
* created, with a single default series and a single default fleet. If a valid {@link RegattaIdentifier}
|
||||
* is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used
|
||||
* to add the races to. Otherwise, a default regatta as described above will be created and used.
|
||||
* @param raceStatus
|
||||
* @param offsetToStartTimeOfSimulatedRace
|
||||
* if non-<code>null</code>, the {@link Simulator} will be used with this duration as start offset
|
||||
*/
|
||||
RaceHandle addTracTracRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, URL paramURL,
|
||||
URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint trackingStartTime,
|
||||
TimePoint trackingEndTime, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm,
|
||||
long timeoutForReceivingRaceDefinitionInMilliseconds, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm,
|
||||
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
|
||||
+7
-6
@@ -74,6 +74,7 @@ import com.sap.sailing.domain.tractracadapter.ReceiverType;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracConfiguration;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracControlPoint;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracRaceTracker;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -652,27 +653,27 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
@Override
|
||||
public TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
|
||||
String tracTracPassword, String raceStatus, String raceVisibility,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException,
|
||||
URISyntaxException, CreateModelException, SubscriberInitializationException {
|
||||
return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking,
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
|
||||
endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
|
||||
gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI,
|
||||
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
|
||||
String tracTracPassword, String raceStatus, String raceVisibility,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
|
||||
SubscriberInitializationException {
|
||||
return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, courseDesignUpdateURI,
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore,
|
||||
regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
|
||||
raceVisibility, trackedRegattaRegistry, raceLogResolver);
|
||||
}
|
||||
@@ -690,11 +691,11 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
@Override
|
||||
public RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI,
|
||||
URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
|
||||
long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, String tracTracUsername, String tracTracPassword, String raceStatus,
|
||||
String raceVisibility) {
|
||||
return new RaceTrackingConnectivityParametersImpl(paramURL, liveURI, storedURI, courseDesignUpdateURI,
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore,
|
||||
regattaLogStore, this, tracTracUsername, tracTracPassword, raceStatus, raceVisibility);
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -16,6 +16,7 @@ import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.tractrac.model.lib.api.event.CreateModelException;
|
||||
import com.tractrac.subscription.lib.api.SubscriberInitializationException;
|
||||
@@ -31,7 +32,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
|
||||
private final RegattaLogStore regattaLogStore;
|
||||
private final DomainFactory domainFactory;
|
||||
private final long delayToLiveInMillis;
|
||||
private final boolean simulateWithStartTimeNow;
|
||||
private final Duration offsetToStartTimeOfSimulatedRace;
|
||||
private final String tracTracUsername;
|
||||
private final String tracTracPassword;
|
||||
private final String raceStatus;
|
||||
@@ -40,7 +41,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
|
||||
|
||||
public RaceTrackingConnectivityParametersImpl(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
DomainFactory domainFactory, String tracTracUsername, String tracTracPassword, String raceStatus,
|
||||
String raceVisibility) {
|
||||
super();
|
||||
@@ -52,7 +53,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
|
||||
this.endOfTracking = endOfTracking;
|
||||
this.delayToLiveInMillis = delayToLiveInMillis;
|
||||
this.domainFactory = domainFactory;
|
||||
this.simulateWithStartTimeNow = simulateWithStartTimeNow;
|
||||
this.offsetToStartTimeOfSimulatedRace = offsetToStartTimeOfSimulatedRace;
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.regattaLogStore = regattaLogStore;
|
||||
this.tracTracUsername = tracTracUsername;
|
||||
@@ -67,7 +68,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
|
||||
GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException, URISyntaxException,
|
||||
CreateModelException, SubscriberInitializationException {
|
||||
RaceTracker tracker = domainFactory.createRaceTracker(paramURL, liveURI, storedURI, courseDesignUpdateURI,
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore,
|
||||
regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
|
||||
raceVisibility, trackedRegattaRegistry, raceLogResolver);
|
||||
return tracker;
|
||||
@@ -77,7 +78,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
|
||||
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
WindStore windStore, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws Exception {
|
||||
RaceTracker tracker = domainFactory.createRaceTracker(regatta, paramURL, liveURI, storedURI,
|
||||
courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm,
|
||||
courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm,
|
||||
raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
|
||||
raceVisibility, trackedRegattaRegistry, raceLogResolver);
|
||||
return tracker;
|
||||
|
||||
+6
-7
@@ -4,7 +4,6 @@ import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
@@ -57,13 +56,13 @@ public class RawPositionReceiver extends AbstractReceiverWithQueue<IRaceCompetit
|
||||
IRace race = event.getA().getRace();
|
||||
DynamicTrackedRace trackedRace = getTrackedRace(race);
|
||||
if (trackedRace != null) {
|
||||
GPSFixMoving fix = getDomainFactory().createGPSFixMoving(event.getB());
|
||||
if (getSimulator() != null) {
|
||||
fix = new GPSFixMovingImpl(fix.getPosition(), getSimulator().delay(
|
||||
fix.getTimePoint()), fix.getSpeed());
|
||||
}
|
||||
final GPSFixMoving fix = getDomainFactory().createGPSFixMoving(event.getB());
|
||||
Competitor competitor = getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor());
|
||||
trackedRace.recordFix(competitor, fix);
|
||||
if (getSimulator() != null) {
|
||||
getSimulator().scheduleCompetitorPosition(competitor, fix);
|
||||
} else {
|
||||
trackedRace.recordFix(competitor, fix);
|
||||
}
|
||||
} else {
|
||||
logger.warning("Couldn't find tracked race for race " + race.getName()
|
||||
+ ". Dropping raw position event " + event);
|
||||
|
||||
+41
-13
@@ -24,7 +24,9 @@ import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class Simulator {
|
||||
@@ -33,13 +35,15 @@ public class Simulator {
|
||||
private DynamicTrackedRace trackedRace;
|
||||
private final WindStore windStore;
|
||||
private boolean stopped;
|
||||
private long advanceInMillis = -1;
|
||||
private Duration advanceInMillis = Duration.NULL.minus(1);
|
||||
private Timer timer = new Timer("Timer for TracTrac Simulator");
|
||||
private final Duration offsetToStart;
|
||||
|
||||
public Simulator(WindStore windStore) {
|
||||
public Simulator(WindStore windStore, Duration offsetToStart) {
|
||||
super();
|
||||
assert windStore != null;
|
||||
this.windStore = windStore;
|
||||
this.offsetToStart = offsetToStart;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +73,7 @@ public class Simulator {
|
||||
/**
|
||||
* This is what everybody is waiting for :-). Notifies all waiters.
|
||||
*/
|
||||
public synchronized void setAdvanceInMillis(long advanceInMillis) {
|
||||
public synchronized void setAdvanceInMillis(Duration advanceInMillis) {
|
||||
this.advanceInMillis = advanceInMillis;
|
||||
notifyAll();
|
||||
}
|
||||
@@ -114,7 +118,7 @@ public class Simulator {
|
||||
* Waits until {@link #advanceInMillis} is set to something not equal to -1 which is its initial value. Unblocked by
|
||||
* {@link #setAdvanceInMillis(long)}.
|
||||
*/
|
||||
private synchronized long getAdvanceInMillis() {
|
||||
private synchronized Duration getAdvance() {
|
||||
while (!isAdvanceInMillisSet()) {
|
||||
try {
|
||||
wait(2000); // wait for two seconds, then re-evaluate whether there is a start time
|
||||
@@ -125,6 +129,16 @@ public class Simulator {
|
||||
}
|
||||
return advanceInMillis;
|
||||
}
|
||||
|
||||
private Duration getOffsetToStart() {
|
||||
final Duration result;
|
||||
if (offsetToStart != null) {
|
||||
result = offsetToStart;
|
||||
} else {
|
||||
result = Duration.NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms <code>timed</code>'s time point according to this simulator's delay and waits roughly until this time
|
||||
@@ -157,12 +171,12 @@ public class Simulator {
|
||||
* Like {@link #delay}, only that it doesn't wait until <code>timePoint</code> is reached in wall time.
|
||||
*/
|
||||
public TimePoint advance(TimePoint timePoint) {
|
||||
return new MillisecondsTimePoint(timePoint.asMillis()+getAdvanceInMillis());
|
||||
return timePoint.plus(getAdvance());
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@link #advanceInMillis} is already set to a non-negative value, it is left alone, and
|
||||
* {@link #delay(TimePoint)} is called. Otherwise, <code>time</code> is taken to be the original start time of the
|
||||
* {@link #advance(TimePoint)} is called. Otherwise, <code>time</code> is taken to be the original start time of the
|
||||
* race which is then used to compute {@link #advanceInMillis} such that
|
||||
* <code>time.asMillis() + advanceInMillis == System.currentTimeMillis()</code>.
|
||||
*/
|
||||
@@ -183,13 +197,13 @@ public class Simulator {
|
||||
if (isAdvanceInMillisSet()) {
|
||||
return advance(time);
|
||||
} else {
|
||||
setAdvanceInMillis(System.currentTimeMillis() - time.asMillis());
|
||||
setAdvanceInMillis(new MillisecondsDurationImpl(MillisecondsTimePoint.now().minus(time.asMillis()).plus(getOffsetToStart()).asMillis()));
|
||||
return advance(time);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAdvanceInMillisSet() {
|
||||
return advanceInMillis != -1;
|
||||
return !advanceInMillis.equals(Duration.NULL.minus(1));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,21 +252,35 @@ public class Simulator {
|
||||
// deliver an empty list now
|
||||
trackedRace.updateMarkPassings(competitor, markPassings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void scheduleCompetitorPosition(final Competitor competitor, GPSFixMoving competitorFix) {
|
||||
final RecordGPSFix<Competitor> recorder = (c, f)->trackedRace.recordFix(c, f);
|
||||
scheduleFixRecording(competitor, competitorFix, recorder);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private static interface RecordGPSFix<T> {
|
||||
void recordFix(T objectForFix, GPSFixMoving fix);
|
||||
}
|
||||
|
||||
public void scheduleMarkPosition(final Mark mark, GPSFixMoving markFix) {
|
||||
final TimePoint transformedTimepoint = advance(markFix.getTimePoint());
|
||||
final GPSFixMoving transformedMarkFix = new GPSFixMovingImpl(markFix.getPosition(), transformedTimepoint, markFix.getSpeed());
|
||||
final RecordGPSFix<Mark> recorder = (m, f)->trackedRace.recordFix(mark, f);
|
||||
scheduleFixRecording(mark, markFix, recorder);
|
||||
}
|
||||
|
||||
private <T> void scheduleFixRecording(final T object, GPSFixMoving fix, final RecordGPSFix<T> recorder) {
|
||||
final TimePoint transformedTimepoint = advance(fix.getTimePoint());
|
||||
final GPSFixMoving transformedMarkFix = new GPSFixMovingImpl(fix.getPosition(), transformedTimepoint, fix.getSpeed());
|
||||
long waitTime = getWaitTimeInMillisUntil(transformedMarkFix.getTimePoint());
|
||||
if (waitTime <= 0) {
|
||||
trackedRace.recordFix(mark, transformedMarkFix);
|
||||
recorder.recordFix(object, transformedMarkFix);
|
||||
} else {
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
trackedRace.recordFix(mark, transformedMarkFix);
|
||||
recorder.recordFix(object, transformedMarkFix);
|
||||
} catch (Exception e) {
|
||||
logger.throwing(Simulator.class.getName(), "scheduleMarkPosition", e);
|
||||
}
|
||||
|
||||
+4
-3
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.tractracadapter.JSONService;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceRecord;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracAdapter;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracConfiguration;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
@@ -56,7 +57,7 @@ public class TracTracAdapterImpl implements TracTracAdapter {
|
||||
getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
|
||||
courseDesignUpdateURI,
|
||||
/* startOfTracking */null,
|
||||
/* endOfTracking */null, delayToLiveInMillis, /* simulateWithStartTimeNow */false, /* ignoreTracTracMarkPassings */ false,
|
||||
/* endOfTracking */null, delayToLiveInMillis, /* offsetToStartTimeOfSimulatedRace */null, /* ignoreTracTracMarkPassings */ false,
|
||||
raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility),
|
||||
timeoutInMilliseconds);
|
||||
}
|
||||
@@ -65,13 +66,13 @@ public class TracTracAdapterImpl implements TracTracAdapter {
|
||||
public RaceHandle addTracTracRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, URL paramURL,
|
||||
URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword, String raceStatus,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword, String raceStatus,
|
||||
String raceVisibility) throws Exception {
|
||||
return trackerManager.addRace(
|
||||
regattaToAddTo,
|
||||
getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
|
||||
courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
|
||||
simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword,
|
||||
offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword,
|
||||
raceStatus, raceVisibility), timeoutInMilliseconds);
|
||||
}
|
||||
|
||||
|
||||
+13
-12
@@ -49,6 +49,7 @@ import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracRaceTracker;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.tractrac.model.lib.api.ModelLocator;
|
||||
@@ -253,26 +254,26 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
*/
|
||||
protected TracTracRaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
|
||||
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
|
||||
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
|
||||
throws URISyntaxException, MalformedURLException, FileNotFoundException, CreateModelException,
|
||||
SubscriberInitializationException {
|
||||
this(ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())), domainFactory, paramURL, liveURI,
|
||||
storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
|
||||
simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
|
||||
offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
|
||||
tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
|
||||
}
|
||||
|
||||
private TracTracRaceTrackerImpl(IRace tractracRace, DomainFactory domainFactory, URL paramURL, URI liveURI,
|
||||
URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
|
||||
long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
|
||||
String tracTracPassword, String raceStatus, String raceVisibility,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException, MalformedURLException,
|
||||
FileNotFoundException, SubscriberInitializationException {
|
||||
this(tractracRace, null, domainFactory, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking,
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
|
||||
endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
|
||||
gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
|
||||
}
|
||||
|
||||
@@ -284,14 +285,14 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
*/
|
||||
protected TracTracRaceTrackerImpl(Regatta regatta, DomainFactory domainFactory, URL paramURL, URI liveURI,
|
||||
URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
|
||||
long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean ignoreTracTracMarkPassings, RaceLogStore raceLogStore,
|
||||
long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean ignoreTracTracMarkPassings, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
|
||||
String tracTracPassword, String raceStatus, String raceVisibility,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException,
|
||||
MalformedURLException, FileNotFoundException, CreateModelException, SubscriberInitializationException {
|
||||
this(ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())), regatta, domainFactory, paramURL,
|
||||
liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
|
||||
simulateWithStartTimeNow, ignoreTracTracMarkPassings, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
|
||||
offsetToStartTimeOfSimulatedRace, ignoreTracTracMarkPassings, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
|
||||
tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
|
||||
}
|
||||
|
||||
@@ -300,15 +301,15 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
* @param regatta
|
||||
* if <code>null</code>, then <code>domainFactory.getOrCreateRegatta(tractracEvent)</code> will be used
|
||||
* to obtain a default regatta
|
||||
* @param simulateWithStartTimeNow
|
||||
* if <code>true</code>, the connector will adjust the time stamps of all events received such that the
|
||||
* @param offsetToStartTimeOfSimulatedRace
|
||||
* if not <code>null</code>, the connector will adjust the time stamps of all events received such that the
|
||||
* first mark passing for the first waypoint will be set to "now." It will delay the forwarding of all
|
||||
* events received such that they seem to be sent in "real-time." So, more or less the time points
|
||||
* events received such that they seem to be sent in "real-time" + <code>offsetToStartTimeOfSimulatedRace</code> So, more or less the time points
|
||||
* attached to the events sent to the receivers will again approximate the wall time.
|
||||
*/
|
||||
private TracTracRaceTrackerImpl(IRace tractracRace, final Regatta regatta, DomainFactory domainFactory,
|
||||
URL paramURL, URI liveURI, URI storedURI, URI tracTracUpdateURI, TimePoint startOfTracking,
|
||||
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm,
|
||||
TimePoint endOfTracking, long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore,
|
||||
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException, MalformedURLException,
|
||||
@@ -323,8 +324,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
this.gpsFixStore = gpsFixStore;
|
||||
this.domainFactory = domainFactory;
|
||||
this.lastProgressPerID = new HashMap<>();
|
||||
if (simulateWithStartTimeNow) {
|
||||
simulator = new Simulator(windStore);
|
||||
if (offsetToStartTimeOfSimulatedRace != null) {
|
||||
simulator = new Simulator(windStore, offsetToStartTimeOfSimulatedRace);
|
||||
// don't write the transformed wind fixes into the DB again... see also bug 1974
|
||||
this.windStore = EmptyWindStore.INSTANCE;
|
||||
} else {
|
||||
|
||||
@@ -43,4 +43,6 @@ public interface Course extends CourseBase {
|
||||
void update(Iterable<Util.Pair<ControlPoint, PassingInstruction>> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException;
|
||||
|
||||
int getNumberOfWaypoints();
|
||||
|
||||
Leg getLeg(int zeroBasedIndexOfWaypoint);
|
||||
}
|
||||
@@ -246,6 +246,11 @@ public class CourseImpl extends NamedImpl implements Course {
|
||||
return waypoints.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Leg getLeg(int zeroBasedIndexOfWaypoint) {
|
||||
return legs.get(zeroBasedIndexOfWaypoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
lockForRead();
|
||||
|
||||
+53
-50
@@ -13,7 +13,6 @@ import java.util.ConcurrentModificationException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
@@ -154,6 +153,7 @@ import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
import com.sap.sse.util.IdentityWrapper;
|
||||
import com.sap.sse.util.SmartFutureCache;
|
||||
import com.sap.sse.util.SmartFutureCache.AbstractCacheUpdater;
|
||||
import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
|
||||
@@ -183,7 +183,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
* By default, all wind sources are used, none are excluded. However, e.g., for performance reasons, particular wind
|
||||
* sources such as the track-based estimation wind source, may be excluded by adding them to this set.
|
||||
*/
|
||||
private final Set<WindSource> windSourcesToExclude;
|
||||
private final ConcurrentHashMap<WindSource, TrackedRaceImpl> windSourcesToExclude;
|
||||
|
||||
/**
|
||||
* Keeps the oldest timestamp that is fed into this tracked race, either from a boat fix, a mark fix, a race
|
||||
@@ -269,7 +269,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
*/
|
||||
private transient SmartFutureCache<Competitor, com.sap.sse.common.Util.Triple<TimePoint, TimePoint, List<Maneuver>>, EmptyUpdateInterval> maneuverCache;
|
||||
|
||||
private transient Map<TimePoint, Future<Wind>> directionFromStartToNextMarkCache;
|
||||
private transient ConcurrentHashMap<TimePoint, Future<Wind>> directionFromStartToNextMarkCache;
|
||||
|
||||
protected final MarkPassingCalculator markPassingCalculator;
|
||||
|
||||
@@ -354,7 +354,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
*/
|
||||
private final NamedReentrantReadWriteLock loadingFromGPSFixStoreLock;
|
||||
|
||||
private final Map<Iterable<MarkPassing>, NamedReentrantReadWriteLock> locksForMarkPassings;
|
||||
private final ConcurrentHashMap<IdentityWrapper<Iterable<MarkPassing>>, NamedReentrantReadWriteLock> locksForMarkPassings;
|
||||
|
||||
/**
|
||||
* Caches wind requests for a few seconds to accelerate access in live mode
|
||||
@@ -412,7 +412,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
rankingMetric = rankingMetricConstructor.apply(this);
|
||||
raceStates = new WeakHashMap<>();
|
||||
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
|
||||
locksForMarkPassings = new IdentityHashMap<>();
|
||||
locksForMarkPassings = new ConcurrentHashMap<IdentityWrapper<Iterable<MarkPassing>>, NamedReentrantReadWriteLock>();
|
||||
attachedRaceLogs = new ConcurrentHashMap<>();
|
||||
attachedRegattaLogs = new ConcurrentHashMap<>();
|
||||
attachedRaceExecutionOrderProviders = new ConcurrentHashMap<>();
|
||||
@@ -424,8 +424,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
+ race.getName(), /* fair */ false);
|
||||
this.cacheInvalidationTimerLock = new Object();
|
||||
this.updateCount = 0;
|
||||
this.windSourcesToExclude = new HashSet<WindSource>();
|
||||
this.directionFromStartToNextMarkCache = new HashMap<TimePoint, Future<Wind>>();
|
||||
this.windSourcesToExclude = new ConcurrentHashMap<>();
|
||||
this.directionFromStartToNextMarkCache = new ConcurrentHashMap<TimePoint, Future<Wind>>();
|
||||
this.millisecondsOverWhichToAverageSpeed = millisecondsOverWhichToAverageSpeed;
|
||||
this.delayToLiveInMillis = delayToLiveInMillis;
|
||||
this.startToNextMarkCacheInvalidationListeners = new ConcurrentHashMap<Mark, TrackedRaceImpl.StartToNextMarkCacheInvalidationListener>();
|
||||
@@ -624,7 +624,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
gpsFixStore = EmptyGPSFixStore.INSTANCE;
|
||||
competitorRankings = createCompetitorRankingsCache();
|
||||
competitorRankingsLocks = createCompetitorRankingsLockMap();
|
||||
directionFromStartToNextMarkCache = new HashMap<TimePoint, Future<Wind>>();
|
||||
directionFromStartToNextMarkCache = new ConcurrentHashMap<>();
|
||||
crossTrackErrorCache = new CrossTrackErrorCache(this);
|
||||
crossTrackErrorCache.invalidate();
|
||||
maneuverCache = createManeuverCache();
|
||||
@@ -1146,11 +1146,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
int indexOfWaypoint = getRace().getCourse().getIndexOfWaypoint(startOfLeg);
|
||||
if (indexOfWaypoint == -1) {
|
||||
throw new IllegalArgumentException("Waypoint " + startOfLeg + " not found in " + getRace().getCourse());
|
||||
} else if (indexOfWaypoint == Util.size(getRace().getCourse().getWaypoints()) - 1) {
|
||||
} else if (indexOfWaypoint == getRace().getCourse().getNumberOfWaypoints() - 1) {
|
||||
throw new IllegalArgumentException("Waypoint " + startOfLeg + " isn't start of any leg in "
|
||||
+ getRace().getCourse());
|
||||
}
|
||||
return trackedLegs.get(race.getCourse().getLegs().get(indexOfWaypoint));
|
||||
return trackedLegs.get(race.getCourse().getLeg(indexOfWaypoint));
|
||||
} finally {
|
||||
getRace().getCourse().unlockAfterRead();
|
||||
}
|
||||
@@ -1679,24 +1679,20 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
|
||||
@Override
|
||||
public Set<WindSource> getWindSourcesToExclude() {
|
||||
synchronized (windSourcesToExclude) {
|
||||
return Collections.unmodifiableSet(windSourcesToExclude);
|
||||
}
|
||||
return Collections.unmodifiableSet(windSourcesToExclude.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindSourcesToExclude(Iterable<? extends WindSource> windSourcesToExclude) {
|
||||
Set<WindSource> old = new HashSet<>(this.windSourcesToExclude);
|
||||
synchronized (this.windSourcesToExclude) {
|
||||
LockUtil.lockForRead(getSerializationLock());
|
||||
try {
|
||||
this.windSourcesToExclude.clear();
|
||||
for (WindSource windSourceToExclude : windSourcesToExclude) {
|
||||
this.windSourcesToExclude.add(windSourceToExclude);
|
||||
}
|
||||
} finally {
|
||||
LockUtil.unlockAfterRead(getSerializationLock());
|
||||
Set<WindSource> old = new HashSet<>(getWindSourcesToExclude());
|
||||
LockUtil.lockForRead(getSerializationLock());
|
||||
try {
|
||||
this.windSourcesToExclude.clear();
|
||||
for (WindSource windSourceToExclude : windSourcesToExclude) {
|
||||
this.windSourcesToExclude.put(windSourceToExclude, this);
|
||||
}
|
||||
} finally {
|
||||
LockUtil.unlockAfterRead(getSerializationLock());
|
||||
}
|
||||
if (!old.equals(this.windSourcesToExclude)) {
|
||||
clearAllCachesExceptManeuvers();
|
||||
@@ -1742,30 +1738,33 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
public Wind getDirectionFromStartToNextMark(final TimePoint at) {
|
||||
Future<Wind> future;
|
||||
FutureTask<Wind> newFuture = null;
|
||||
synchronized (directionFromStartToNextMarkCache) {
|
||||
future = directionFromStartToNextMarkCache.get(at);
|
||||
if (future == null) {
|
||||
newFuture = new FutureTask<Wind>(new Callable<Wind>() {
|
||||
@Override
|
||||
public Wind call() {
|
||||
Wind result;
|
||||
Leg firstLeg = getRace().getCourse().getFirstLeg();
|
||||
if (firstLeg != null) {
|
||||
Position firstLegEnd = getApproximatePosition(firstLeg.getTo(), at);
|
||||
Position firstLegStart = getApproximatePosition(firstLeg.getFrom(), at);
|
||||
if (firstLegStart != null && firstLegEnd != null) {
|
||||
result = new WindImpl(firstLegStart, at, new KnotSpeedWithBearingImpl(0.0,
|
||||
firstLegEnd.getBearingGreatCircle(firstLegStart)));
|
||||
future = directionFromStartToNextMarkCache.get(at);
|
||||
if (future == null) {
|
||||
synchronized (directionFromStartToNextMarkCache) {
|
||||
future = directionFromStartToNextMarkCache.get(at);
|
||||
if (future == null) {
|
||||
newFuture = new FutureTask<Wind>(new Callable<Wind>() {
|
||||
@Override
|
||||
public Wind call() {
|
||||
Wind result;
|
||||
Leg firstLeg = getRace().getCourse().getFirstLeg();
|
||||
if (firstLeg != null) {
|
||||
Position firstLegEnd = getApproximatePosition(firstLeg.getTo(), at);
|
||||
Position firstLegStart = getApproximatePosition(firstLeg.getFrom(), at);
|
||||
if (firstLegStart != null && firstLegEnd != null) {
|
||||
result = new WindImpl(firstLegStart, at, new KnotSpeedWithBearingImpl(0.0,
|
||||
firstLegEnd.getBearingGreatCircle(firstLegStart)));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
} else {
|
||||
result = null;
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
directionFromStartToNextMarkCache.put(at, newFuture);
|
||||
});
|
||||
directionFromStartToNextMarkCache.put(at, newFuture);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newFuture != null) {
|
||||
@@ -2062,15 +2061,19 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
}
|
||||
|
||||
protected NamedReentrantReadWriteLock getMarkPassingsLock(Iterable<MarkPassing> markPassings) {
|
||||
synchronized (locksForMarkPassings) {
|
||||
NamedReentrantReadWriteLock lock = locksForMarkPassings.get(markPassings);
|
||||
if (lock == null) {
|
||||
lock = new NamedReentrantReadWriteLock("mark passings lock for tracked race " + getRace().getName(), /* fair */
|
||||
false);
|
||||
locksForMarkPassings.put(markPassings, lock);
|
||||
final IdentityWrapper<Iterable<MarkPassing>> markPassingsIdentity = new IdentityWrapper<>(markPassings);
|
||||
NamedReentrantReadWriteLock lock = locksForMarkPassings.get(markPassingsIdentity);
|
||||
if (lock == null) {
|
||||
synchronized (locksForMarkPassings) {
|
||||
lock = locksForMarkPassings.get(markPassingsIdentity);
|
||||
if (lock == null) {
|
||||
lock = new NamedReentrantReadWriteLock(
|
||||
"mark passings lock for tracked race " + getRace().getName(), /* fair */false);
|
||||
locksForMarkPassings.put(markPassingsIdentity, lock);
|
||||
}
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
private void updateStartToNextMarkCacheInvalidationCacheListenersAfterWaypointRemoved(int zeroBasedIndex,
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ public class GwtTestCaseColumnToggling extends GWTTestCase {
|
||||
+ TracTracConnectionConstants.PORT_TUNNEL_STORED : "tcp://" + TracTracConnectionConstants.HOST_NAME
|
||||
+ ":" + TracTracConnectionConstants.PORT_STORED,
|
||||
COURSE_DESIGN_UPDATE_URI,
|
||||
false, false, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings */ false, TRACTRAC_USERNAME, TRACTRAC_PASSWORD, new AsyncCallback<Void>() {
|
||||
false, false, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings */ false, TRACTRAC_USERNAME, TRACTRAC_PASSWORD, new AsyncCallback<Void>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
|
||||
+4
-4
@@ -40,18 +40,18 @@ public class AddWindFixDialog extends DataEntryDialog<WindDTO> {
|
||||
if(windDTO.trueWindSpeedInKnots == null) {
|
||||
errorMessage = stringMessages.pleaseEnterAValue();
|
||||
} else if(windDTO.trueWindSpeedInKnots != null && (windDTO.trueWindSpeedInKnots < 0.0 || windDTO.trueWindSpeedInKnots > 100.0)) {
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.speedInKnots(), "0", "100");
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.speedInKnots(), 0, 100);
|
||||
} else if(windDTO.trueWindFromDeg == null){
|
||||
errorMessage = stringMessages.pleaseEnterAValue();
|
||||
} else if(windDTO.trueWindFromDeg != null && (windDTO.trueWindFromDeg < 0.0 || windDTO.trueWindFromDeg > 360.0)){
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.fromDeg(), "0", "360");
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.fromDeg(), 0, 360);
|
||||
} else if(windDTO.measureTimepoint == null) {
|
||||
errorMessage = stringMessages.pleaseEnterAValue();
|
||||
} else if(windDTO.position != null) {
|
||||
if(windDTO.position.getLatDeg() < -90.0 || windDTO.position.getLatDeg() > 90.0){
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.latitude(), "-90", "90");
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.latitude(), -90, 90);
|
||||
} else if(windDTO.position.getLngDeg() < -180.0 || windDTO.position.getLngDeg() > 180.0){
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.longitude(), "-180", "180");
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.longitude(), -180, 180);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -225,7 +225,7 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
declinationCheckbox.setValue(true);
|
||||
trackableRacesPanel.add(declinationCheckbox);
|
||||
|
||||
final CheckBox simulateWithStartTimeNow = new CheckBox(stringMessages.simulateWithStartTimeNow());
|
||||
final CheckBox simulateWithStartTimeNow = new CheckBox(stringMessages.simulateAsLiveRace());
|
||||
simulateWithStartTimeNow.setWordWrap(false);
|
||||
simulateWithStartTimeNow.setValue(false);
|
||||
trackableRacesPanel.add(simulateWithStartTimeNow);
|
||||
|
||||
+50
-21
@@ -24,6 +24,7 @@ import com.google.gwt.user.client.ui.CaptionPanel;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HTMLTable.ColumnFormatter;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
@@ -44,6 +45,7 @@ import com.sap.sailing.gwt.ui.client.shared.controls.SelectionCheckboxColumn;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.util.NaturalComparator;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
|
||||
@@ -83,7 +85,8 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
|
||||
private LabeledAbstractFilterablePanel<TracTracRaceRecordDTO> racesFilterablePanel;
|
||||
private CellTable<TracTracRaceRecordDTO> racesTable;
|
||||
|
||||
private static final String ZERO_AS_STRING = "0";
|
||||
|
||||
public TracTracEventManagementPanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
RegattaRefresher regattaRefresher, StringMessages stringMessages) {
|
||||
super(sailingService, regattaRefresher, errorReporter, new RaceSelectionModel(), true, stringMessages);
|
||||
@@ -229,17 +232,12 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
|
||||
protected HorizontalPanel createRacesPanel() {
|
||||
HorizontalPanel racesPanel = new HorizontalPanel();
|
||||
|
||||
CaptionPanel trackableRacesPanel = createTrackableRacesPanel();
|
||||
|
||||
racesPanel.add(trackableRacesPanel);
|
||||
racesPanel.setCellWidth(trackableRacesPanel, "50%");
|
||||
|
||||
CaptionPanel trackedRacesPanel = createTrackedRacesPanel();
|
||||
|
||||
racesPanel.add(trackedRacesPanel);
|
||||
racesPanel.setCellWidth(trackedRacesPanel, "50%");
|
||||
|
||||
return racesPanel;
|
||||
}
|
||||
|
||||
@@ -276,10 +274,32 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
correctWindCheckBox.setWordWrap(false);
|
||||
correctWindCheckBox.setValue(Boolean.TRUE);
|
||||
|
||||
final CheckBox simulateWithStartTimeNowCheckBox = new CheckBox(stringMessages.simulateWithStartTimeNow());
|
||||
final TextBox offsetToStartTimeOfSimulatedRaceTextBox = new TextBox();
|
||||
offsetToStartTimeOfSimulatedRaceTextBox.setWidth("40px");
|
||||
offsetToStartTimeOfSimulatedRaceTextBox.setEnabled(false);
|
||||
offsetToStartTimeOfSimulatedRaceTextBox.setValue(ZERO_AS_STRING);
|
||||
|
||||
final CheckBox simulateWithStartTimeNowCheckBox = new CheckBox(stringMessages.simulateAsLiveRace());
|
||||
simulateWithStartTimeNowCheckBox.ensureDebugId("SimulateWithStartTimeNowCheckBox");
|
||||
simulateWithStartTimeNowCheckBox.setWordWrap(false);
|
||||
simulateWithStartTimeNowCheckBox.setValue(Boolean.FALSE);
|
||||
simulateWithStartTimeNowCheckBox.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
offsetToStartTimeOfSimulatedRaceTextBox.setEnabled(simulateWithStartTimeNowCheckBox.getValue());
|
||||
offsetToStartTimeOfSimulatedRaceTextBox.setFocus(simulateWithStartTimeNowCheckBox.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
final FlowPanel simulateAsLiveRacePanel = new FlowPanel();
|
||||
simulateAsLiveRacePanel.add(simulateWithStartTimeNowCheckBox);
|
||||
|
||||
final Label offsetToStartLabel = new Label(stringMessages.simulateWithOffset());
|
||||
|
||||
final HorizontalPanel simulateWithOffsetPanel = new HorizontalPanel();
|
||||
simulateWithOffsetPanel.add(offsetToStartLabel);
|
||||
simulateWithOffsetPanel.add(offsetToStartTimeOfSimulatedRaceTextBox);
|
||||
|
||||
final CheckBox ignoreTracTracMarkPassingsCheckbox = new CheckBox(stringMessages.useInternalAlgorithm());
|
||||
ignoreTracTracMarkPassingsCheckbox.setWordWrap(false);
|
||||
ignoreTracTracMarkPassingsCheckbox.setValue(Boolean.FALSE);
|
||||
@@ -287,8 +307,9 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
layoutTable.setWidget(1, 0, trackSettingsLabel);
|
||||
layoutTable.setWidget(1, 1, trackWindCheckBox);
|
||||
layoutTable.setWidget(2, 1, correctWindCheckBox);
|
||||
layoutTable.setWidget(3, 1, simulateWithStartTimeNowCheckBox);
|
||||
layoutTable.setWidget(4, 1, ignoreTracTracMarkPassingsCheckbox);
|
||||
layoutTable.setWidget(3, 1, simulateAsLiveRacePanel);
|
||||
layoutTable.setWidget(4, 1, simulateWithOffsetPanel);
|
||||
layoutTable.setWidget(5, 1, ignoreTracTracMarkPassingsCheckbox);
|
||||
|
||||
// Filter
|
||||
Label racesFilterLabel = new Label(stringMessages.filterRacesByName() + ":");
|
||||
@@ -310,8 +331,8 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
}
|
||||
};
|
||||
racesFilterablePanel.getTextBox().ensureDebugId("TrackableRacesFilterTextBox");
|
||||
layoutTable.setWidget(5, 0, racesFilterLabel);
|
||||
layoutTable.setWidget(5, 1, racesFilterablePanel);
|
||||
layoutTable.setWidget(6, 0, racesFilterLabel);
|
||||
layoutTable.setWidget(6, 1, racesFilterablePanel);
|
||||
|
||||
// Races
|
||||
TextColumn<TracTracRaceRecordDTO> regattaNameColumn = new TextColumn<TracTracRaceRecordDTO>() {
|
||||
@@ -357,7 +378,6 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
}
|
||||
};
|
||||
raceVisibilityColumn.setSortable(true);
|
||||
|
||||
SelectionCheckboxColumn<TracTracRaceRecordDTO> selectionCheckboxColumn = new SelectionCheckboxColumn<TracTracRaceRecordDTO>(tableResources.cellTableStyle().cellTableCheckboxSelected(),
|
||||
tableResources.cellTableStyle().cellTableCheckboxDeselected(), tableResources.cellTableStyle().cellTableCheckboxColumnCell()) {
|
||||
@Override
|
||||
@@ -381,26 +401,24 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
raceNameColumn, boatClassColumn, raceStartTrackingColumn, raceStatusColumn));
|
||||
racesTable.setSelectionModel(selectionCheckboxColumn.getSelectionModel(), selectionCheckboxColumn.getSelectionManager());
|
||||
racesTable.setWidth("100%");
|
||||
|
||||
raceList.addDataDisplay(racesTable);
|
||||
|
||||
layoutTable.setWidget(6, 0, racesTable);
|
||||
cellFormatter.setColSpan(6, 0, 2);
|
||||
|
||||
Button startTrackingButton = new Button(stringMessages.startTracking());
|
||||
startTrackingButton.ensureDebugId("StartTrackingButton");
|
||||
startTrackingButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
Duration offsetToStartTimeOfSimulatedRace = null;
|
||||
if(simulateWithStartTimeNowCheckBox.getValue().booleanValue()) {
|
||||
offsetToStartTimeOfSimulatedRace = getMillisecondsDurationFromMinutesAsString(offsetToStartTimeOfSimulatedRaceTextBox.getValue());
|
||||
}
|
||||
trackSelectedRaces(trackWindCheckBox.getValue(), correctWindCheckBox.getValue(),
|
||||
simulateWithStartTimeNowCheckBox.getValue(), ignoreTracTracMarkPassingsCheckbox.getValue());
|
||||
offsetToStartTimeOfSimulatedRace, ignoreTracTracMarkPassingsCheckbox.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
layoutTable.setWidget(7, 1, startTrackingButton);
|
||||
|
||||
trackableRacesPanel.setContentWidget(layoutTable);
|
||||
|
||||
return trackableRacesPanel;
|
||||
}
|
||||
|
||||
@@ -462,6 +480,17 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
|
||||
return boatClassNames.substring(0, boatClassNames.length() - 2);
|
||||
}
|
||||
|
||||
private Duration getMillisecondsDurationFromMinutesAsString(String minutesAsString) {
|
||||
Duration result = null;
|
||||
if (minutesAsString != null) {
|
||||
Double minutesAsDouble = Double.parseDouble(minutesAsString);
|
||||
if (minutesAsDouble != null) {
|
||||
result = Duration.ONE_MINUTE.times(minutesAsDouble.longValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void fillConfigurations() {
|
||||
this.sailingService.getPreviousTracTracConfigurations(new MarkedAsyncCallback<List<TracTracConfigurationDTO>>(
|
||||
@@ -551,7 +580,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
}));
|
||||
}
|
||||
|
||||
private void trackSelectedRaces(boolean trackWind, boolean correctWind, final boolean simulateWithStartTimeNow, boolean ignoreTracTracMarkPassings) {
|
||||
private void trackSelectedRaces(boolean trackWind, boolean correctWind, final Duration offsetToStartTimeOfSimulatedRace, boolean ignoreTracTracMarkPassings) {
|
||||
String liveURI = liveURITextBox.getValue();
|
||||
String storedURI = storedURITextBox.getValue();
|
||||
String courseDesignUpdateURI = tracTracUpdateURITextBox.getValue();
|
||||
@@ -577,7 +606,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
}
|
||||
if (checkBoatClassOK(selectedRegatta, selectedRaces)) {
|
||||
sailingService.trackWithTracTrac(regattaIdentifier, selectedRaces, liveURI, storedURI,
|
||||
courseDesignUpdateURI, trackWind, correctWind, simulateWithStartTimeNow, ignoreTracTracMarkPassings, tractracUsername,
|
||||
courseDesignUpdateURI, trackWind, correctWind, offsetToStartTimeOfSimulatedRace, ignoreTracTracMarkPassings, tractracUsername,
|
||||
tractracPassword, new MarkedAsyncCallback<Void>(new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
|
||||
+2
-1
@@ -86,6 +86,7 @@ import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.VenueDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -116,7 +117,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
|
||||
void trackWithTracTrac(RegattaIdentifier regattaToAddTo, Iterable<TracTracRaceRecordDTO> rrs, String liveURI,
|
||||
String storedURI, String courseDesignUpdateURI, boolean trackWind, boolean correctWindByDeclination,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword) throws Exception;
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword) throws Exception;
|
||||
|
||||
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs, String hostname, int port,
|
||||
boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm) throws Exception;
|
||||
|
||||
+5
-4
@@ -78,6 +78,7 @@ import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.VenueDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -114,10 +115,10 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
* @param liveURI
|
||||
* may be <code>null</code> or the empty string in which case the server will use the
|
||||
* {@link TracTracRaceRecordDTO#liveURI} from the <code>rr</code> race record.
|
||||
* @param simulateWithStartTimeNow
|
||||
* if <code>true</code>, the connector will adjust the time stamps of all events received such that the
|
||||
* @param offsetToStartTimeOfSimulatedRace
|
||||
* if not <code>null</code>, the connector will adjust the time stamps of all events received such that the
|
||||
* first mark passing for the first waypoint will be set to "now." It will delay the forwarding of all
|
||||
* events received such that they seem to be sent in "real-time." So, more or less the time points
|
||||
* events received such that they seem to be sent in "real-time" plus the <code>offsetToStartTimeOfSimulatedRace</code>. So, more or less the time points
|
||||
* attached to the events sent to the receivers will again approximate the wall time.
|
||||
* @param useInternalMarkPassingAlgorithm
|
||||
* whether or not to ignore the TracTrac-provided mark passings; if <code>true</code>, a separate mark
|
||||
@@ -128,7 +129,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
*/
|
||||
void trackWithTracTrac(RegattaIdentifier regattaToAddTo, Iterable<TracTracRaceRecordDTO> rrs, String liveURI,
|
||||
String storedURI, String courseDesignUpdateURI, boolean trackWind, boolean correctWindByDeclination,
|
||||
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, String tracTracUsername,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, String tracTracUsername,
|
||||
String tracTracPassword, AsyncCallback<Void> callback);
|
||||
|
||||
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs,
|
||||
|
||||
+6
-2
@@ -361,7 +361,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
|
||||
String successfullyUpdatedScores();
|
||||
String errorUpdatingScoresForLeaderboard(String leaderboardName, String message);
|
||||
String maneuverTypesToShowWhenCompetitorIsClicked();
|
||||
String simulateWithStartTimeNow();
|
||||
String simulateAsLiveRace();
|
||||
String simulateWithOffset();
|
||||
String boatClassDoesNotMatchSelectedRegatta(String boatClass);
|
||||
String regattaExistForSelectedBoatClass();
|
||||
String reload();
|
||||
@@ -436,7 +437,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
|
||||
String overallDetailsToShow();
|
||||
String hhmmssUnit();
|
||||
String actionAddWindData();
|
||||
String valueMustBeBetweenMinMax(String name, String minValue, String maxValue);
|
||||
String valueMustBeBetweenMinMax(String name, int minValue, int maxValue);
|
||||
String valueMustBeGreaterThan(String name, String minValue);
|
||||
String optional();
|
||||
String pleaseEnterAValue();
|
||||
String latitude();
|
||||
@@ -1444,4 +1446,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
|
||||
String requiresValidRegatta();
|
||||
String couldNotObtainRace(String regattaLikeName, String raceColumnName, String fleetName, String technicalErrorMessage);
|
||||
String errorTryingToCreateEmbeddedMap(String message);
|
||||
String transparentBufferLineOnHover();
|
||||
String bufferLineStrokeWeight();
|
||||
}
|
||||
+6
-2
@@ -371,7 +371,8 @@ apply=Apply
|
||||
successfullyUpdatedScores=Successfully updated scores
|
||||
errorUpdatingScoresForLeaderboard=Error updating scores for leaderboard {0}: {1}
|
||||
maneuverTypesToShowWhenCompetitorIsClicked=Maneuver types to show when competitor is clicked
|
||||
simulateWithStartTimeNow=Simulate with "now" as start time
|
||||
simulateAsLiveRace=Simulate as live race
|
||||
simulateWithOffset=Offset before start in minutes:
|
||||
boatClassDoesNotMatchSelectedRegatta=The selected races contain boat classes which are not the same as the boat class ''{0}'' of the selected regatta. No races will be loaded.
|
||||
regattaExistForSelectedBoatClass=There is at least one regatta for the selected boat classes. Really create default regatta(s) for those race(s)?
|
||||
reload=Reload
|
||||
@@ -456,6 +457,7 @@ totalAverageSpeedOverGroundTooltip=Average speed over ground across the regatta.
|
||||
hhmmssUnit=hh:mm:ss
|
||||
actionAddWindData=Add wind data
|
||||
valueMustBeBetweenMinMax=The value of ''{0}'' must be between {1} and {2}.
|
||||
valueMustBeGreaterThan=The value of ''{0}'' must be greater than {1}.
|
||||
optional=optional
|
||||
pleaseEnterAValue=Please enter a value.
|
||||
latitude=Latitude
|
||||
@@ -1410,4 +1412,6 @@ selectALeaderboardGroup=Select a leaderboard group...
|
||||
pleaseSelect=Please select
|
||||
requiresValidRegatta=This page requires a valid regatta, race column and fleet name to identify the race to show.
|
||||
couldNotObtainRace=Could not obtain a race with name {1} for fleet {2} for a regatta with name {0}: {3}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
|
||||
bufferLineStrokeWeight=Buffer line stroke weight
|
||||
+7
-3
@@ -372,7 +372,8 @@ apply=Übernehmen
|
||||
successfullyUpdatedScores=Ergebnisse erfolgreich aktualisiert
|
||||
errorUpdatingScoresForLeaderboard=Fehler beim Aktualisieren der Ergebnisse für {0}: {1}
|
||||
maneuverTypesToShowWhenCompetitorIsClicked=Anzuzeigende Manövertypen für angeklickte Teilnehmer
|
||||
simulateWithStartTimeNow=Simulieren mit "jetzt" als Startzeit
|
||||
simulateAsLiveRace=Simuliere als Live Rennen
|
||||
simulateWithOffset=Zeit bis zum Start in Minuten:
|
||||
boatClassDoesNotMatchSelectedRegatta=Die ausgewählten Rennen enthalten eine Bootsklasse, die nicht der Bootsklasse der ausgewählten Regatta ''{0}'' entspricht. Es werden keine Rennen geladen.
|
||||
regattaExistForSelectedBoatClass=Es gibt mindestens eine Regatta zu den ausgewählten Bootsklassen. Dennoch Default-Regatta für diese(s) Rennen anlegen?
|
||||
reload=Neu laden
|
||||
@@ -456,7 +457,8 @@ totalAverageSpeedOverGround=\u2205 FüG
|
||||
totalAverageSpeedOverGroundTooltip=Durchschnittliche Fahrt über Grund über die gesamte Regatta.
|
||||
hhmmssUnit=hh:mm:ss
|
||||
actionAddWindData=Winddaten hinzufügen
|
||||
valueMustBeBetweenMinMax=Der Wert von ''{0}'' muß zwischen {1} und {2} sein.
|
||||
valueMustBeBetweenMinMax=Der Wert von ''{0}'' muss zwischen {1} und {2} sein.
|
||||
valueMustBeGreaterThan=Der Wert von ''{0}'' muss größer als {1} sein.
|
||||
optional=optional
|
||||
pleaseEnterAValue=Bitte geben Sie einen Wert ein.
|
||||
latitude=Breite
|
||||
@@ -1401,4 +1403,6 @@ selectALeaderboardGroup=Bitte eine Ranglisten-Gruppe auswählen...
|
||||
pleaseSelect=Bitte auswählen
|
||||
requiresValidRegatta=Diese Seite benötigt eine gültige Regatta, Rennspalte und einen gültigen Gruppennamen um die anzuzeigende Wettfahrt zu identifizieren.
|
||||
couldNotObtainRace=Wettfahrt namens {1} für Gruppe {2} in einer Regatta names {0} konnte nicht gefunden werden: {3}
|
||||
errorTryingToCreateEmbeddedMap=Fehler beim Erstellen der eingebetteten Karte: {0}
|
||||
errorTryingToCreateEmbeddedMap=Fehler beim Erstellen der eingebetteten Karte: {0}
|
||||
transparentBufferLineOnHover=Transparente Pufferlinien bei Maus über Hilfslinien
|
||||
bufferLineStrokeWeight=Linienbreite der Pufferlinien
|
||||
+6
-2
@@ -364,7 +364,8 @@ apply=Применить
|
||||
successfullyUpdatedScores=Очки обновлены успешно
|
||||
errorUpdatingScoresForLeaderboard=Ошибка обновления очков для таблицы лидеров {0}: {1}
|
||||
maneuverTypesToShowWhenCompetitorIsClicked=Типы маневров для отображения при нажатии на участника
|
||||
simulateWithStartTimeNow=Моделирования с "сейчас" в качестве времени начала
|
||||
simulateAsLiveRace=Simulate as live race
|
||||
simulateWithOffset=Offset before start in minutes:
|
||||
boatClassDoesNotMatchSelectedRegatta=Выбранные гонки содержат классы судов не соответствующие классу судов ''{0}'' выбранной регаты.
|
||||
regattaExistForSelectedBoatClass=Есть только одна регата для выбранных классов судов.
|
||||
reload=Перезагрузить
|
||||
@@ -440,6 +441,7 @@ totalAverageSpeedOverGroundTooltip=Средняя скорость относи
|
||||
hhmmssUnit=чч:мм:сс
|
||||
actionAddWindData=Добавить данные о ветре
|
||||
valueMustBeBetweenMinMax=Значение ''{0}''должно быть в пределах от {1} до {2}.
|
||||
valueMustBeGreaterThan=The value of ''{0}'' must be greater than {1}.
|
||||
optional=Дополнительно
|
||||
pleaseEnterAValue=Введите, пожалуйста, значение.
|
||||
latitude=Широта
|
||||
@@ -1340,4 +1342,6 @@ selectALeaderboardGroup=Select a leaderboard group...
|
||||
pleaseSelect=Please select
|
||||
requiresValidRegatta=This page requires a valid regatta, race column and fleet name to identify the race to show.
|
||||
couldNotObtainRace=Could not obtain a race with name {1} for fleet {2} for a regatta with name {0}: {3}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
|
||||
bufferLineStrokeWeight=Buffer line stroke weight
|
||||
+6
-2
@@ -538,6 +538,7 @@ connectors=Connectors
|
||||
dampeningInterval=Dampening Interval
|
||||
trackBasedEstimationWindSourceTypeTooltip=Calculated data from the competitor tracks
|
||||
valueMustBeBetweenMinMax=The value of ''{0}'' must be between {1} and {2}.
|
||||
valueMustBeGreaterThan=The value of ''{0}'' must be greater than {1}.
|
||||
orMultipleEmails=or multiple E-Mails separated by comma
|
||||
searchEvents=Search for events
|
||||
explainNoConnectionsFromReplicas=No connections from a replica found. You can connect replicas by using their AdminConsole.
|
||||
@@ -1072,7 +1073,8 @@ trackWind=Track Wind
|
||||
rawFixes=All fixes (including outliers)
|
||||
showCompetitorFullNameColumn=Show Competitor Full Name
|
||||
disableRaceFilter=Disable filter
|
||||
simulateWithStartTimeNow=Simulate with "now" as start time
|
||||
simulateAsLiveRace=Simulate as live race
|
||||
simulateWithOffset=Offset before start in minutes:
|
||||
polarSheetOutlierDetectionRadiusTooltip=The radius used in the distance based outlierndetection algorithm.
|
||||
noWindFixesAvailable=No Wind-Fixes available.
|
||||
correctScoreFor=Correct score for competitor {0} in race {1}
|
||||
@@ -1355,4 +1357,6 @@ selectALeaderboardGroup=Select a leaderboard group...
|
||||
pleaseSelect=Please select
|
||||
requiresValidRegatta=This page requires a valid regatta, race column and fleet name to identify the race to show.
|
||||
couldNotObtainRace=Could not obtain a race with name {1} for fleet {2} for a regatta with name {0}: {3}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
|
||||
bufferLineStrokeWeight=Buffer line stroke weight
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.sap.sailing.gwt.ui.client.shared.racemap;
|
||||
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.maps.client.events.click.ClickMapHandler;
|
||||
import com.google.gwt.maps.client.events.mouseout.MouseOutMapEvent;
|
||||
import com.google.gwt.maps.client.events.mouseout.MouseOutMapHandler;
|
||||
import com.google.gwt.maps.client.events.mouseover.MouseOverMapEvent;
|
||||
import com.google.gwt.maps.client.events.mouseover.MouseOverMapHandler;
|
||||
import com.google.gwt.maps.client.overlays.Polyline;
|
||||
import com.google.gwt.maps.client.overlays.PolylineOptions;
|
||||
|
||||
public class Hoverline {
|
||||
private static final double TRANSPARENT = 0;
|
||||
private static final double VISIBLE = 0.2d;
|
||||
|
||||
private final Polyline hoverline;
|
||||
private final PolylineOptions options;
|
||||
|
||||
public Hoverline(final Polyline polyline, PolylineOptions polylineOptions, final RaceMap map) {
|
||||
this.options = PolylineOptions.newInstance();
|
||||
this.options.setClickable(polylineOptions.getClickable());
|
||||
this.options.setGeodesic(polylineOptions.getGeodesic());
|
||||
this.options.setMap(polyline.getMap());
|
||||
this.options.setPath(polyline.getPath());
|
||||
this.options.setStrokeColor(polylineOptions.getStrokeColor());
|
||||
this.options.setZindex(polylineOptions.getZindex());
|
||||
this.hoverline = Polyline.newInstance(this.options);
|
||||
this.hoverline.setVisible(false);
|
||||
polyline.addMouseOverHandler(new MouseOverMapHandler() {
|
||||
@Override
|
||||
public void onEvent(MouseOverMapEvent event) {
|
||||
options.setStrokeOpacity(map.getSettings().getTransparentHoverlines() ? TRANSPARENT : VISIBLE);
|
||||
options.setStrokeWeight(map.getSettings().getHoverlineStrokeWeight());
|
||||
options.setVisible(true);
|
||||
hoverline.setOptions(options);
|
||||
}
|
||||
});
|
||||
hoverline.addMouseOutMoveHandler(new MouseOutMapHandler() {
|
||||
@Override
|
||||
public void onEvent(MouseOutMapEvent event) {
|
||||
hoverline.setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public HandlerRegistration addClickHandler(ClickMapHandler handler) {
|
||||
return this.hoverline.addClickHandler(handler);
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseOutMoveHandler(MouseOutMapHandler handler) {
|
||||
return this.hoverline.addMouseOutMoveHandler(handler);
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseOverHandler(MouseOverMapHandler handler) {
|
||||
return this.hoverline.addMouseOverHandler(handler);
|
||||
}
|
||||
}
|
||||
+19
-11
@@ -1158,7 +1158,6 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
Polyline tail = fixesAndTails.getTail(competitorDTO);
|
||||
if (tail == null) {
|
||||
tail = fixesAndTails.createTailAndUpdateIndices(competitorDTO, tailsFromTime, tailsToTime, this);
|
||||
tail.setMap(map);
|
||||
} else {
|
||||
fixesAndTails.updateTail(tail, competitorDTO, tailsFromTime, tailsToTime,
|
||||
(int) (timeForPositionTransitionMillis==-1?-1:timeForPositionTransitionMillis/2));
|
||||
@@ -1305,17 +1304,18 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
pointsAsArray.insertAt(0, advantageLinePos1);
|
||||
pointsAsArray.insertAt(1, advantageLinePos2);
|
||||
advantageLine.setPath(pointsAsArray);
|
||||
advantageLine.setMap(map);
|
||||
Hoverline advantageHoverline = new Hoverline(advantageLine, options, this);
|
||||
|
||||
advantageLineMouseOverHandler = new AdvantageLineMouseOverMapHandler(
|
||||
bearingOfCombinedWindInDeg, new Date(windFix.measureTimepoint));
|
||||
advantageLine.addMouseOverHandler(advantageLineMouseOverHandler);
|
||||
advantageLine.addMouseOutMoveHandler(new MouseOutMapHandler() {
|
||||
advantageHoverline.addMouseOutMoveHandler(new MouseOutMapHandler() {
|
||||
@Override
|
||||
public void onEvent(MouseOutMapEvent event) {
|
||||
map.setTitle("");
|
||||
}
|
||||
});
|
||||
advantageLine.setMap(map);
|
||||
} else {
|
||||
advantageLine.getPath().removeAt(1);
|
||||
advantageLine.getPath().removeAt(0);
|
||||
@@ -1561,20 +1561,20 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
pointsAsArray = MVCArray.newInstance();
|
||||
lineToShowOrRemoveOrUpdate = Polyline.newInstance(options);
|
||||
lineToShowOrRemoveOrUpdate.setPath(pointsAsArray);
|
||||
lineToShowOrRemoveOrUpdate.setMap(map);
|
||||
Hoverline lineToShowOrRemoveOrUpdateHoverline = new Hoverline(lineToShowOrRemoveOrUpdate, options, this);
|
||||
lineToShowOrRemoveOrUpdate.addMouseOverHandler(new MouseOverMapHandler() {
|
||||
@Override
|
||||
public void onEvent(MouseOverMapEvent event) {
|
||||
map.setTitle(lineInfoProvider.getLineInfo());
|
||||
}
|
||||
});
|
||||
lineToShowOrRemoveOrUpdate.addMouseOutMoveHandler(new MouseOutMapHandler() {
|
||||
lineToShowOrRemoveOrUpdateHoverline.addMouseOutMoveHandler(new MouseOutMapHandler() {
|
||||
@Override
|
||||
public void onEvent(MouseOutMapEvent event) {
|
||||
map.setTitle("");
|
||||
}
|
||||
});
|
||||
lineToShowOrRemoveOrUpdate.setMap(map);
|
||||
|
||||
} else {
|
||||
pointsAsArray = lineToShowOrRemoveOrUpdate.getPath();
|
||||
pointsAsArray.removeAt(1);
|
||||
@@ -2328,6 +2328,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
updateCoordinateSystemFromSettings();
|
||||
requiredRedraw = true;
|
||||
}
|
||||
if (newSettings.getTransparentHoverlines() != settings.getTransparentHoverlines()) {
|
||||
settings.setTransparentHoverlines(newSettings.getTransparentHoverlines());
|
||||
}
|
||||
if (newSettings.getHoverlineStrokeWeight() != settings.getHoverlineStrokeWeight()) {
|
||||
settings.setHoverlineStrokeWeight(newSettings.getHoverlineStrokeWeight());
|
||||
}
|
||||
if (requiredRedraw) {
|
||||
redraw();
|
||||
}
|
||||
@@ -2493,23 +2499,25 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
public Polyline createTail(final CompetitorDTO competitor, List<LatLng> points) {
|
||||
PolylineOptions options = createTailStyle(competitor, displayHighlighted(competitor));
|
||||
Polyline result = Polyline.newInstance(options);
|
||||
|
||||
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance(points.toArray(new LatLng[0]));
|
||||
result.setPath(pointsAsArray);
|
||||
|
||||
result.addClickHandler(new ClickMapHandler() {
|
||||
result.setMap(map);
|
||||
Hoverline resultHoverline = new Hoverline(result, options, this);
|
||||
final ClickMapHandler clickHandler = new ClickMapHandler() {
|
||||
@Override
|
||||
public void onEvent(ClickMapEvent event) {
|
||||
showCompetitorInfoWindow(competitor, event.getMouseEvent().getLatLng());
|
||||
}
|
||||
});
|
||||
};
|
||||
result.addClickHandler(clickHandler);
|
||||
resultHoverline.addClickHandler(clickHandler);
|
||||
result.addMouseOverHandler(new MouseOverMapHandler() {
|
||||
@Override
|
||||
public void onEvent(MouseOverMapEvent event) {
|
||||
map.setTitle(competitor.getSailID() + ", " + competitor.getName());
|
||||
}
|
||||
});
|
||||
result.addMouseOutMoveHandler(new MouseOutMapHandler() {
|
||||
resultHoverline.addMouseOutMoveHandler(new MouseOutMapHandler() {
|
||||
@Override
|
||||
public void onEvent(MouseOutMapEvent event) {
|
||||
map.setTitle("");
|
||||
|
||||
+22
@@ -19,6 +19,10 @@ public class RaceMapSettings extends AbstractSettings {
|
||||
private RaceMapZoomSettings zoomSettings;
|
||||
|
||||
private RaceMapHelpLinesSettings helpLinesSettings;
|
||||
|
||||
private boolean transparentHoverlines = true;
|
||||
|
||||
private int hoverlineStrokeWeight = 10;
|
||||
|
||||
private long tailLengthInMilliseconds = 100000l;
|
||||
|
||||
@@ -55,6 +59,8 @@ public class RaceMapSettings extends AbstractSettings {
|
||||
public RaceMapSettings(RaceMapSettings settings) {
|
||||
this.buoyZoneRadiusInMeters = settings.buoyZoneRadiusInMeters;
|
||||
this.helpLinesSettings = new RaceMapHelpLinesSettings(settings.getHelpLinesSettings().getVisibleHelpLineTypes());
|
||||
this.transparentHoverlines = settings.transparentHoverlines;
|
||||
this.hoverlineStrokeWeight = settings.hoverlineStrokeWeight;
|
||||
this.maneuverTypesToShow = settings.maneuverTypesToShow;
|
||||
this.showDouglasPeuckerPoints = settings.showDouglasPeuckerPoints;
|
||||
this.showOnlySelectedCompetitors = settings.showOnlySelectedCompetitors;
|
||||
@@ -153,6 +159,22 @@ public class RaceMapSettings extends AbstractSettings {
|
||||
public void setHelpLinesSettings(RaceMapHelpLinesSettings helpLinesSettings) {
|
||||
this.helpLinesSettings = helpLinesSettings;
|
||||
}
|
||||
|
||||
public boolean getTransparentHoverlines() {
|
||||
return this.transparentHoverlines;
|
||||
}
|
||||
|
||||
public void setTransparentHoverlines(boolean transparentHoverlines) {
|
||||
this.transparentHoverlines = transparentHoverlines;
|
||||
}
|
||||
|
||||
public int getHoverlineStrokeWeight() {
|
||||
return this.hoverlineStrokeWeight;
|
||||
}
|
||||
|
||||
public void setHoverlineStrokeWeight(int hoverlineStrokeWeight) {
|
||||
this.hoverlineStrokeWeight = hoverlineStrokeWeight;
|
||||
}
|
||||
|
||||
public boolean isShowSelectedCompetitorsInfo() {
|
||||
return showSelectedCompetitorsInfo;
|
||||
|
||||
+22
-2
@@ -24,11 +24,14 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.client.controls.IntegerBox;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator;
|
||||
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<RaceMapSettings> {
|
||||
private static final int MAX_BUOY_ZONE_RADIUS_IN_METERS = 100;
|
||||
private static final int MAX_STROKE_WEIGHT = 33;
|
||||
//Initializing the lists to prevent a null pointer exception in the first validation call
|
||||
private List<Util.Pair<CheckBox, ManeuverType>> checkboxAndManeuverType = new ArrayList<Util.Pair<CheckBox, ManeuverType>>();
|
||||
private List<Util.Pair<CheckBox, ZoomTypes>> checkboxAndZoomType = new ArrayList<Util.Pair<CheckBox,ZoomTypes>>();
|
||||
@@ -43,6 +46,8 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
|
||||
private CheckBox showSelectedCompetitorsInfoCheckBox;
|
||||
private LongBox tailLengthBox;
|
||||
private DoubleBox buoyZoneRadiusBox;
|
||||
private CheckBox transparentHoverlines;
|
||||
private IntegerBox hoverlineStrokeWeight;
|
||||
private boolean showViewSimulation;
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
@@ -211,6 +216,17 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
|
||||
vp.add(createHelpLineCheckBox(dialog, HelpLineTypes.STARTLINETOFIRSTMARKTRIANGLE));
|
||||
vp.add(createHelpLineCheckBox(dialog, HelpLineTypes.COURSEGEOMETRY));
|
||||
|
||||
transparentHoverlines = dialog.createCheckbox(stringMessages.transparentBufferLineOnHover());
|
||||
transparentHoverlines.setValue(initialSettings.getTransparentHoverlines());
|
||||
vp.add(transparentHoverlines);
|
||||
|
||||
HorizontalPanel hoverlineStrokeWeightPanel = new HorizontalPanel();
|
||||
Label hoverlineStrokeWeightLabel = new Label(stringMessages.bufferLineStrokeWeight() + ":");
|
||||
hoverlineStrokeWeightPanel.add(hoverlineStrokeWeightLabel);
|
||||
hoverlineStrokeWeight = dialog.createIntegerBox(initialSettings.getHoverlineStrokeWeight(), 3);
|
||||
hoverlineStrokeWeightPanel.add(hoverlineStrokeWeight);
|
||||
vp.add(hoverlineStrokeWeightPanel);
|
||||
|
||||
return vp;
|
||||
}
|
||||
|
||||
@@ -267,6 +283,8 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
|
||||
result.setBuoyZoneRadiusInMeters(value);
|
||||
}
|
||||
}
|
||||
result.setTransparentHoverlines(transparentHoverlines.getValue());
|
||||
result.setHoverlineStrokeWeight(hoverlineStrokeWeight.getValue());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -304,8 +322,10 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
|
||||
if (valueToValidate.getHelpLinesSettings().isVisible(HelpLineTypes.BOATTAILS) && valueToValidate.getTailLengthInMilliseconds() <= 0) {
|
||||
errorMessage = stringMessages.tailLengthMustBePositive();
|
||||
} else if (valueToValidate.getHelpLinesSettings().isVisible(HelpLineTypes.BUOYZONE)
|
||||
&& (valueToValidate.getBuoyZoneRadiusInMeters() < 0.0 || valueToValidate.getBuoyZoneRadiusInMeters() > 100.0)) {
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.buoyZone(), "0", "100");
|
||||
&& (valueToValidate.getBuoyZoneRadiusInMeters() < 0 || valueToValidate.getBuoyZoneRadiusInMeters() > MAX_BUOY_ZONE_RADIUS_IN_METERS)) {
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.buoyZone(), 0, 100);
|
||||
} else if (valueToValidate.getHoverlineStrokeWeight() < 0 || valueToValidate.getHoverlineStrokeWeight() > MAX_STROKE_WEIGHT) {
|
||||
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.bufferLineStrokeWeight(), 0, MAX_STROKE_WEIGHT);
|
||||
}
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1023,7 +1023,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
@Override
|
||||
public void trackWithTracTrac(RegattaIdentifier regattaToAddTo, Iterable<TracTracRaceRecordDTO> rrs, String liveURI, String storedURI,
|
||||
String courseDesignUpdateURI, boolean trackWind, final boolean correctWindByDeclination,
|
||||
final boolean simulateWithStartTimeNow, final boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword)
|
||||
final Duration offsetToStartTimeOfSimulatedRace, final boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword)
|
||||
throws Exception {
|
||||
logger.info("tracWithTracTrac for regatta " + regattaToAddTo + " for race records " + rrs + " with liveURI " + liveURI
|
||||
+ " and storedURI " + storedURI);
|
||||
@@ -1054,7 +1054,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
new URI(courseDesignUpdateURI), new MillisecondsTimePoint(record.getTrackingStartTime().asMillis()),
|
||||
new MillisecondsTimePoint(record.getTrackingEndTime().asMillis()),
|
||||
getRaceLogStore(), getRegattaLogStore(),
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, simulateWithStartTimeNow,
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, offsetToStartTimeOfSimulatedRace,
|
||||
useInternalMarkPassingAlgorithm, tracTracUsername, tracTracPassword, record.getRaceStatus(), record.getRaceVisibility());
|
||||
if (trackWind) {
|
||||
new Thread("Wind tracking starter for race " + record.getEventName() + "/" + record.getName()) {
|
||||
|
||||
+10
@@ -4,6 +4,16 @@
|
||||
<div id="mainContent">
|
||||
<h4 class="articleHeadline">What's New - SAP Sailing Analytics</h4>
|
||||
<div class="innerContent">
|
||||
<h5 class="articleSubheadline">December 2015</h5>
|
||||
|
||||
<ul class="bulletList">
|
||||
<li>New line hover behavior in race map. When the mouse is moved onto a line, for example the start line, a transparent,
|
||||
wider line is activated behind it that acts as a buffer for the thin line, where the text displayed by the hover is still shown.
|
||||
This makes it easier to hover over the lines. These wider lines can be made semi transparent instead of transparent
|
||||
by unticking the corresponding checkbox in the settings of the race map. Furthermore the stroke weight of the wider lines can be
|
||||
configured in the same settings dialog.
|
||||
</li>
|
||||
</ul>
|
||||
<h5 class="articleSubheadline">November 2015</h5>
|
||||
|
||||
<ul class="bulletList">
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ public class TrackRaceBoatCompetitorMetadataReplicationTest extends AbstractServ
|
||||
trackingParams = com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE
|
||||
.createTrackingConnectivityParameters(paramURL, liveURI, storedURI, courseDesignUpdateURI,
|
||||
startOfTracking, endOfTracking, /* delayToLiveInMillis */
|
||||
0l, /* simulateWithStartTimeNow */false, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
0l, /* offsetToStartTimeOfSimulatedRace */null, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, tracTracUsername, tracTracPassword, "", "");
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
|
||||
trackingParams = com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE
|
||||
.createTrackingConnectivityParameters(paramURL, liveURI, storedURI, courseDesignUpdateURI,
|
||||
startOfTracking, endOfTracking, /* delayToLiveInMillis */
|
||||
0l, /* simulateWithStartTimeNow */false, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
0l, /* offsetToStartTimeOfSimulatedRace */null, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, tracTracUsername, tracTracPassword, "", "");
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ import com.google.gwt.text.client.IntegerParser;
|
||||
import com.google.gwt.text.shared.Renderer;
|
||||
import com.google.gwt.user.client.ui.ValueBox;
|
||||
|
||||
/**
|
||||
* Renders integers in their box without any separators, non-localized, plain.
|
||||
*/
|
||||
public class IntegerBox extends ValueBox<Integer> {
|
||||
private static final Renderer<Integer> RENDERER = new Renderer<Integer>() {
|
||||
public String render(Integer object) {
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.sap.sse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A class providing static information about the running server.
|
||||
@@ -10,14 +12,16 @@ import java.io.FileReader;
|
||||
*
|
||||
*/
|
||||
public class ServerInfo {
|
||||
private static final Logger logger = Logger.getLogger(ServerInfo.class.getName());
|
||||
|
||||
public static String getBuildVersion() {
|
||||
String version = "Unknown or Development (" + ServerStartupConstants.SERVER_NAME + ")";
|
||||
File versionfile = new File(ServerStartupConstants.JETTY_HOME + File.separator + "version.txt");
|
||||
if (versionfile.exists()) {
|
||||
try {
|
||||
version = new BufferedReader(new FileReader(versionfile)).readLine();
|
||||
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(versionfile))) {
|
||||
version = bufferedReader.readLine();
|
||||
} catch (Exception ex) {
|
||||
/* ignore */
|
||||
logger.log(Level.WARNING, "Error trying to obtain version info", ex);
|
||||
}
|
||||
}
|
||||
return version;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.sap.sse.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Implements {@link Object#equals(Object)} and {@link Object#hashCode()} based on the wrapped object's
|
||||
* identity, no matter what the object itself defines as {@code equals} and {@code hashCode}.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class IdentityWrapper<T> implements Serializable {
|
||||
private static final long serialVersionUID = 3514488568026067341L;
|
||||
private final T t;
|
||||
|
||||
public IdentityWrapper(T t) {
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof IdentityWrapper<?>) ? ((IdentityWrapper<?>) obj).t == this.t : obj == t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IdentityWrapper for "+t;
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@
|
||||
<Arg name="threadpool">
|
||||
<New id="threadpool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
|
||||
<Arg name="minThreads" type="int">10</Arg>
|
||||
<Arg name="maxThreads" type="int">3000</Arg>
|
||||
<Arg name="maxThreads" type="int">64</Arg>
|
||||
<Arg name="idleTimeout" type="int">25000</Arg>
|
||||
<Set name="detailedDump">false</Set>
|
||||
</New>
|
||||
|
||||
Reference in new issue
Block a user