pInvolvedBoats, int pPassId, Integer indexOfFirstSuppressedWaypoint) {
+ super(createdAt, author, logicalTimePoint, pId, pInvolvedBoats, pPassId);
+ this.indexOfFirstSuppressedWaypoint = indexOfFirstSuppressedWaypoint;
+
+ }
+
+ @Override
+ public void accept(RaceLogEventVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public Integer getZeroBasedIndexOfFirstSuppressedWaypoint() {
+ return indexOfFirstSuppressedWaypoint;
+ }
+
+ @Override
+ public String getShortInfo() {
+ return getInvolvedBoats().get(0).getName()+" at mark "+getZeroBasedIndexOfFirstSuppressedWaypoint();
+ }
+}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/CourseDataImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/CourseDataImpl.java
index 55b482d480e..6d956701058 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/CourseDataImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/CourseDataImpl.java
@@ -49,7 +49,7 @@ public class CourseDataImpl extends NamedImpl implements CourseBase {
public int getIndexOfWaypoint(Waypoint waypoint) {
return this.waypoints.indexOf(waypoint);
}
-
+
@Override
public Waypoint getFirstWaypoint() {
return this.waypoints.get(0);
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java
old mode 100644
new mode 100755
index b0b7c62bd6b..e36d5b33927
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java
@@ -1,147 +1,171 @@
-package com.sap.sailing.domain.tracking;
-
-import java.io.Serializable;
-import java.util.Iterator;
-import java.util.concurrent.locks.ReadWriteLock;
-
-import com.sap.sailing.domain.base.Timed;
-import com.sap.sse.common.Duration;
-import com.sap.sse.common.TimePoint;
-
-/**
- * A track records {@link Timed} items for an object of type ItemType. It allows clients to ask for a value
- * close to a given {@link TimePoint}. The track manages a time-based set of raw fixes. An implementation may have an
- * understanding of how to eliminate outliers. For example, if a track implementation knows it's tracking boats, it may
- * consider fixes that the boat cannot possibly have reached due to its speed and direction change limitations as
- * outliers. The set of fixes with outliers filtered out can be obtained using {@link #getFixes} whereas
- * {@link #getRawFixes()} returns the unfiltered, raw fixes. If an implementation has no idea what an outlier is,
- * both methods will return the same fix sequence.
- *
- * With tracks, concurrency is an important issue. Threads may want to modify a track while other threads may want to
- * read from it. Several methods such as {@link #getLastFixAtOrBefore(TimePoint)} return a single fix and can manage
- * concurrency internally. However, those methods returning a collection of fixes, such as {@link #getFixes()} or an
- * iterator over a collection of fixes, such as {@link #getFixesIterator(TimePoint, boolean)}, need special treatment.
- * Until we internalize such iterations (see bug 824, http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=824),
- * callers need to manage a read lock which is part of a {@link ReadWriteLock} managed by this track. Callers do so
- * by calling {@link #lockForRead} and {@link #unlockAfterRead}.
- *
- * @author Axel Uhl (d043530)
- */
-public interface Track extends Serializable {
- /**
- * Locks this track for reading by the calling thread. If the thread already holds the lock for this track,
- * the hold count will be incremented. Make sure to call {@link #unlockAfterRead()} in a finally
- * block to release the lock under all possible circumstances. Failure to do so will inevitably lead to
- * deadlocks!
- */
- void lockForRead();
-
- /**
- * Decrements the hold count for this track's read lock for the calling thread. If it goes to zero, the lock will be
- * released and other readers or a writer can obtain the lock. Make sure to call this method in a
- * finally block for each {@link #lockForRead()} invocation.
- */
- void unlockAfterRead();
-
- /**
- * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
- * will be thrown in case the caller has failed to do so.
- *
- * @return the smoothened fixes
- */
- Iterable getFixes();
-
- /**
- * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
- * will be thrown in case the caller has failed to do so.
- *
- * @return The smoothened fixes between from and to.
- */
- Iterable getFixes(TimePoint from, boolean fromInclusive, TimePoint to, boolean toInclusive);
-
- /**
- * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
- * will be thrown in case the caller has failed to do so.
- */
- Iterable getRawFixes();
-
- FixType getLastFixAtOrBefore(TimePoint timePoint);
-
- FixType getLastFixBefore(TimePoint timePoint);
-
- FixType getLastRawFixAtOrBefore(TimePoint timePoint);
-
- FixType getFirstFixAtOrAfter(TimePoint timePoint);
-
- FixType getFirstRawFixAtOrAfter(TimePoint timePoint);
-
- FixType getLastRawFixBefore(TimePoint timePoint);
-
- FixType getFirstRawFixAfter(TimePoint timePoint);
-
- FixType getFirstFixAfter(TimePoint timePoint);
-
- /**
- * The first fix in this track or null if the track is empty. The fix returned may
- * be an outlier that is not returned by calls operating on the smoothened version of the track.
- */
- FixType getFirstRawFix();
-
- /**
- * The last fix in this track or null if the track is empty. The fix returned may
- * be an outlier that is not returned by calls operating on the smoothened version of the track.
- */
- FixType getLastRawFix();
-
- /**
- * Returns an iterator starting at the first fix after startingAt (or "at or after" in case
- * inclusive is true). The fixes returned by the iterator are the smoothened fixes (see
- * also {@link #getFixes()}, without any smoothening or dampening applied.
- *
- * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
- * will be thrown in case the caller has failed to do so.
- */
- Iterator getFixesIterator(TimePoint startingAt, boolean inclusive);
-
- /**
- * Returns an iterator starting at the first raw fix after startingAt (or "at or after" in case
- * inclusive is true). The fixes returned by the iterator are the raw fixes (see also
- * {@link #getRawFixes()}, without any smoothening or dampening applied.
- *
- * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
- * will be thrown in case the caller has failed to do so.
- */
- Iterator getRawFixesIterator(TimePoint startingAt, boolean inclusive);
-
- /**
- * Returns a descending iterator starting at the first fix before startingAt (or "at or before" in case
- * inclusive is true). The fixes returned by the iterator are the smoothened fixes (see
- * also {@link #getFixes()}, without any smoothening or dampening applied.
- *
- * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
- * will be thrown in case the caller has failed to do so.
- */
- Iterator getFixesDescendingIterator(TimePoint startingAt, boolean inclusive);
-
- /**
- * Returns a descending iterator starting at the first raw fix before startingAt (or "at or before" in case
- * inclusive is true). The fixes returned by the iterator are the raw fixes (see also
- * {@link #getRawFixes()}, without any smoothening or dampening applied.
- *
- * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
- * will be thrown in case the caller has failed to do so.
- */
- Iterator getRawFixesDescendingIterator(TimePoint startingAt, boolean inclusive);
-
- /**
- * @return the average duration between two fixes (outliers removed) in this track or null if there is not
- * more than one fix in the track
- */
- Duration getAverageIntervalBetweenFixes();
-
- /**
- * @return the average duration between two fixes (outliers not removed) in this track or null if there is not
- * more than one raw fix in the track
- */
- Duration getAverageIntervalBetweenRawFixes();
-}
+package com.sap.sailing.domain.tracking;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.concurrent.locks.ReadWriteLock;
+
+import com.sap.sailing.domain.base.Timed;
+import com.sap.sse.common.Duration;
+import com.sap.sse.common.TimePoint;
+
+/**
+ * A track records {@link Timed} items for an object of type ItemType. It allows clients to ask for a value
+ * close to a given {@link TimePoint}. The track manages a time-based set of raw fixes. An implementation may have an
+ * understanding of how to eliminate outliers. For example, if a track implementation knows it's tracking boats, it may
+ * consider fixes that the boat cannot possibly have reached due to its speed and direction change limitations as
+ * outliers. The set of fixes with outliers filtered out can be obtained using {@link #getFixes} whereas
+ * {@link #getRawFixes()} returns the unfiltered, raw fixes. If an implementation has no idea what an outlier is,
+ * both methods will return the same fix sequence.
+ *
+ * With tracks, concurrency is an important issue. Threads may want to modify a track while other threads may want to
+ * read from it. Several methods such as {@link #getLastFixAtOrBefore(TimePoint)} return a single fix and can manage
+ * concurrency internally. However, those methods returning a collection of fixes, such as {@link #getFixes()} or an
+ * iterator over a collection of fixes, such as {@link #getFixesIterator(TimePoint, boolean)}, need special treatment.
+ * Until we internalize such iterations (see bug 824, http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=824),
+ * callers need to manage a read lock which is part of a {@link ReadWriteLock} managed by this track. Callers do so
+ * by calling {@link #lockForRead} and {@link #unlockAfterRead}.
+ *
+ * @author Axel Uhl (d043530)
+ */
+public interface Track extends Serializable {
+ /**
+ * Locks this track for reading by the calling thread. If the thread already holds the lock for this track,
+ * the hold count will be incremented. Make sure to call {@link #unlockAfterRead()} in a finally
+ * block to release the lock under all possible circumstances. Failure to do so will inevitably lead to
+ * deadlocks!
+ */
+ void lockForRead();
+
+ /**
+ * Decrements the hold count for this track's read lock for the calling thread. If it goes to zero, the lock will be
+ * released and other readers or a writer can obtain the lock. Make sure to call this method in a
+ * finally block for each {@link #lockForRead()} invocation.
+ */
+ void unlockAfterRead();
+
+ /**
+ * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
+ * will be thrown in case the caller has failed to do so.
+ *
+ * @return the smoothened fixes
+ */
+ Iterable getFixes();
+
+ /**
+ * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
+ * will be thrown in case the caller has failed to do so.
+ *
+ * @return The smoothened fixes between from and to.
+ */
+ Iterable getFixes(TimePoint from, boolean fromInclusive, TimePoint to, boolean toInclusive);
+
+ /**
+ * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
+ * will be thrown in case the caller has failed to do so.
+ */
+ Iterable getRawFixes();
+
+ /**
+ * Returns null if no such fix exists.
+ */
+ FixType getLastFixAtOrBefore(TimePoint timePoint);
+
+ /**
+ * Returns null if no such fix exists.
+ */
+ FixType getLastFixBefore(TimePoint timePoint);
+
+ /**
+ * Returns null if no such fix exists.
+ */
+ FixType getLastRawFixAtOrBefore(TimePoint timePoint);
+
+ /**
+ * Returns null if no such fix exists.
+ */
+ FixType getFirstFixAtOrAfter(TimePoint timePoint);
+
+ /**
+ * Returns null if no such fix exists.
+ */
+ FixType getFirstRawFixAtOrAfter(TimePoint timePoint);
+
+ /**
+ * Returns null if no such fix exists.
+ */
+ FixType getLastRawFixBefore(TimePoint timePoint);
+
+ /**
+ * Returns null if no such fix exists.
+ */
+ FixType getFirstRawFixAfter(TimePoint timePoint);
+
+ /**
+ * Returns null if no such fix exists.
+ */
+ FixType getFirstFixAfter(TimePoint timePoint);
+
+ /**
+ * The first fix in this track or null if the track is empty. The fix returned may
+ * be an outlier that is not returned by calls operating on the smoothened version of the track.
+ */
+ FixType getFirstRawFix();
+
+ /**
+ * The last fix in this track or null if the track is empty. The fix returned may
+ * be an outlier that is not returned by calls operating on the smoothened version of the track.
+ */
+ FixType getLastRawFix();
+
+ /**
+ * Returns an iterator starting at the first fix after startingAt (or "at or after" in case
+ * inclusive is true). The fixes returned by the iterator are the smoothened fixes (see
+ * also {@link #getFixes()}, without any smoothening or dampening applied.
+ *
+ * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
+ * will be thrown in case the caller has failed to do so.
+ */
+ Iterator getFixesIterator(TimePoint startingAt, boolean inclusive);
+
+ /**
+ * Returns an iterator starting at the first raw fix after startingAt (or "at or after" in case
+ * inclusive is true). The fixes returned by the iterator are the raw fixes (see also
+ * {@link #getRawFixes()}, without any smoothening or dampening applied.
+ *
+ * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
+ * will be thrown in case the caller has failed to do so.
+ */
+ Iterator getRawFixesIterator(TimePoint startingAt, boolean inclusive);
+
+ /**
+ * Returns a descending iterator starting at the first fix before startingAt (or "at or before" in case
+ * inclusive is true). The fixes returned by the iterator are the smoothened fixes (see
+ * also {@link #getFixes()}, without any smoothening or dampening applied.
+ *
+ * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
+ * will be thrown in case the caller has failed to do so.
+ */
+ Iterator getFixesDescendingIterator(TimePoint startingAt, boolean inclusive);
+
+ /**
+ * Returns a descending iterator starting at the first raw fix before startingAt (or "at or before" in case
+ * inclusive is true). The fixes returned by the iterator are the raw fixes (see also
+ * {@link #getRawFixes()}, without any smoothening or dampening applied.
+ *
+ * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception
+ * will be thrown in case the caller has failed to do so.
+ */
+ Iterator getRawFixesDescendingIterator(TimePoint startingAt, boolean inclusive);
+
+ /**
+ * @return the average duration between two fixes (outliers removed) in this track or null if there is not
+ * more than one fix in the track
+ */
+ Duration getAverageIntervalBetweenFixes();
+
+ /**
+ * @return the average duration between two fixes (outliers not removed) in this track or null if there is not
+ * more than one raw fix in the track
+ */
+ Duration getAverageIntervalBetweenRawFixes();
+}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/DomainFactory.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/DomainFactory.java
index 162b2aa1d33..3ecfdd0b314 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/DomainFactory.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/DomainFactory.java
@@ -62,7 +62,7 @@ public interface DomainFactory {
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(String hostname, int port, String raceID,
String raceName, String raceDescription, BoatClass boatClass, StartList startList,
long delayToLiveInMillis, SwissTimingFactory swissTimingFactory, DomainFactory domainFactory,
- RaceLogStore raceLogStore, RegattaLogStore regattaLogStore);
+ RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm);
ControlPoint getOrCreateControlPoint(Iterable devices);
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingAdapter.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingAdapter.java
index 4742b2337af..4d75dbecd80 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingAdapter.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingAdapter.java
@@ -25,10 +25,11 @@ public interface SwissTimingAdapter {
* 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 useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark passing / split times
*/
RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, String raceID,
String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
- StartList startList, RaceLogStore logStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds)
+ StartList startList, RaceLogStore logStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm)
throws InterruptedException, UnknownHostException, IOException, ParseException, Exception;
StartList readStartListForRace(String raceId, RegattaResults regattaResults);
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java
index db22f45b03d..ec4dfc7bb83 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java
@@ -50,15 +50,18 @@ public interface SwissTimingFactory {
SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname, int port);
- SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
- StartList startList, long delayToLiveInMillis, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
- WindStore windStore, GPSFixStore gpsFixStore,
- DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException, UnknownHostException,
+ SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription,
+ BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
+ RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore,
+ boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
+ TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException, UnknownHostException,
IOException, ParseException;
- RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
- StartList startList, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException, InterruptedException,
- IOException, ParseException;
+ RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
+ BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
+ WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm,
+ DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException,
+ InterruptedException, IOException, ParseException;
Race createRace(String raceId, String raceName, String description, BoatClass boatClass);
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java
index 673737f2f5b..03950c8f79f 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java
@@ -357,10 +357,10 @@ public class DomainFactoryImpl implements DomainFactory {
public RaceTrackingConnectivityParameters createTrackingConnectivityParameters(String hostname, int port,
String raceID, String raceName, String raceDescription, BoatClass boatClass, StartList startList,
long delayToLiveInMillis, SwissTimingFactory swissTimingFactory, DomainFactory domainFactory,
- RaceLogStore raceLogStore, RegattaLogStore regattaLogStore) {
+ RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm) {
return new SwissTimingTrackingConnectivityParameters(hostname, port, raceID, raceName, raceDescription,
boatClass, startList, delayToLiveInMillis, swissTimingFactory, domainFactory, raceLogStore,
- regattaLogStore);
+ regattaLogStore, useInternalMarkPassingAlgorithm);
}
}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingAdapterImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingAdapterImpl.java
index 3ffb30e48ba..5068ea0a08e 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingAdapterImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingAdapterImpl.java
@@ -69,12 +69,13 @@ public class SwissTimingAdapterImpl implements SwissTimingAdapter {
@Override
public RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo,
String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
- StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds)
+ StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds,
+ boolean useInternalMarkPassingAlgorithm)
throws Exception {
return trackerManager.addRace(regattaToAddTo, swissTimingDomainFactory.createTrackingConnectivityParameters(
hostname, port, raceID, raceName, raceDescription, boatClass, startList,
DEFAULT_SWISSTIMING_LIVE_DELAY_IN_MILLISECONDS, swissTimingFactory, swissTimingDomainFactory,
- raceLogStore, regattaLogStore), timeoutInMilliseconds);
+ raceLogStore, regattaLogStore, useInternalMarkPassingAlgorithm), timeoutInMilliseconds);
}
@Override
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java
index 5b194038bdb..3e54a269946 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java
@@ -91,21 +91,21 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
public SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription,
BoatClass boatClass, String hostname, int port,
StartList startList, long delayToLiveInMillis, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
- WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory,
- TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException,
+ WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm,
+ DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException,
UnknownHostException, IOException, ParseException {
return new SwissTimingRaceTrackerImpl(raceID, raceName, raceDescription, boatClass, hostname, port, startList,
raceLogStore, regattaLogStore, windStore, gpsFixStore, domainFactory, this,
- trackedRegattaRegistry, delayToLiveInMillis);
+ trackedRegattaRegistry, delayToLiveInMillis, useInternalMarkPassingAlgorithm);
}
@Override
public RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname,
- int port, StartList startList, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory,
- TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException,
+ int port, StartList startList, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm,
+ DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException,
InterruptedException, IOException, ParseException {
return new SwissTimingRaceTrackerImpl(regatta, raceID, raceName, raceDescription, boatClass, hostname, port, startList, windStore, gpsFixStore, domainFactory,
- this, trackedRegattaRegistry, delayToLiveInMillis);
+ this, trackedRegattaRegistry, delayToLiveInMillis, useInternalMarkPassingAlgorithm);
}
@Override
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java
index c99fb4ff1a3..7cd61b900e5 100644
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java
@@ -82,6 +82,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
private final WindStore windStore;
private final GPSFixStore gpsFixStore;
private final boolean startListFromManage2Sail;
+ private final boolean useInternalMarkPassingAlgorithm;
/**
* Starts out as null and is set when the race definition has been created. When this happens, this object is
@@ -108,17 +109,17 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
protected SwissTimingRaceTrackerImpl(String raceID, String raceName, String raceDescription, BoatClass boatClass,
String hostname, int port, StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory, SwissTimingFactory factory,
- TrackedRegattaRegistry trackedRegattaRegistry, long delayToLiveInMillis) throws InterruptedException,
+ TrackedRegattaRegistry trackedRegattaRegistry, long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException,
UnknownHostException, IOException, ParseException {
this(domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore, raceID,
boatClass, trackedRegattaRegistry), raceID, raceName,
raceDescription, boatClass, hostname, port, startList, windStore, gpsFixStore, domainFactory, factory, trackedRegattaRegistry,
- delayToLiveInMillis);
+ delayToLiveInMillis, useInternalMarkPassingAlgorithm);
}
protected SwissTimingRaceTrackerImpl(Regatta regatta, String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, int port, StartList startList,
WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory, SwissTimingFactory factory,
- TrackedRegattaRegistry trackedRegattaRegistry, long delayToLiveInMillis) throws InterruptedException,
+ TrackedRegattaRegistry trackedRegattaRegistry, long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException,
UnknownHostException, IOException, ParseException {
super();
this.tmdMessageQueue = new TMDMessageQueue(this);
@@ -138,6 +139,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
this.delayToLiveInMillis = delayToLiveInMillis;
this.competitorsByBoatId = new HashMap();
+ this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
}
@Override
@@ -328,69 +330,72 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
public void receivedTimingData(String raceID, String boatID,
List> markIndicesRanksAndTimesSinceStartInMilliseconds) {
assert this.raceID.equals(raceID);
- if (isTrackedRaceStillReachable()) {
- Competitor competitor = getCompetitorByBoatIDAndRaceIDOrBoatClass(boatID, raceID, boatClass);
- if (competitor == null) {
- logger.info("Received timing data for boat ID " + boatID + " in race " + raceID
- + " but couldn't find a competitor with that boat ID in this race. Ignoring.");
- } else {
- // the list of mark indices and time stamps is partial and usually only shows the last mark passing;
- // we need to use this to *update* the competitor's mark passings list, not *replace* it
- TreeMap markPassingsByMarkIndex = new TreeMap();
- // now fill with the already existing mark passings for the competitor identified by boatID...
- NavigableSet markPassings = trackedRace.getMarkPassings(competitor);
- trackedRace.lockForRead(markPassings);
- try {
- for (MarkPassing markPassing : markPassings) {
- markPassingsByMarkIndex.put(
- trackedRace.getRace().getCourse().getIndexOfWaypoint(markPassing.getWaypoint()),
- markPassing);
- }
- } finally {
- trackedRace.unlockAfterRead(markPassings);
- }
- // ...and then overwrite those for which we received "new evidence"
- for (com.sap.sse.common.Util.Triple markIndexRankAndTimeSinceStartInMilliseconds : markIndicesRanksAndTimesSinceStartInMilliseconds) {
- Waypoint waypoint = Util.get(trackedRace.getRace().getCourse().getWaypoints(),
- markIndexRankAndTimeSinceStartInMilliseconds.getA());
- // If the rank and time information is empty, we interpret this by clearing the mark rounding if any
- // (see
- // also bug 1911):
- if (markIndexRankAndTimeSinceStartInMilliseconds.getC() == null) {
- markPassingsByMarkIndex.remove(markIndexRankAndTimeSinceStartInMilliseconds.getA());
- } else {
- // update mark passing only if we have a start time; guessed start times don't make sense and
- // for the start line would lead subsequent calls to getStartOfRace() return that guessed start
- // time
- // which then cannot be identified as "guessed" anymore...
- if (trackedRace.getStartOfRace() != null) {
- final TimePoint startTime = trackedRace.getStartOfRace();
- MillisecondsTimePoint timePoint = new MillisecondsTimePoint(startTime.asMillis()
- + markIndexRankAndTimeSinceStartInMilliseconds.getC());
- MarkPassing markPassing = domainFactory.createMarkPassing(timePoint, waypoint,
- getCompetitorByBoatIDAndRaceIDOrBoatClass(boatID, raceID, boatClass));
- markPassingsByMarkIndex.put(markIndexRankAndTimeSinceStartInMilliseconds.getA(),
+ if (!useInternalMarkPassingAlgorithm) {
+ if (isTrackedRaceStillReachable()) {
+ Competitor competitor = getCompetitorByBoatIDAndRaceIDOrBoatClass(boatID, raceID, boatClass);
+ if (competitor == null) {
+ logger.info("Received timing data for boat ID " + boatID + " in race " + raceID
+ + " but couldn't find a competitor with that boat ID in this race. Ignoring.");
+ } else {
+ // the list of mark indices and time stamps is partial and usually only shows the last mark passing;
+ // we need to use this to *update* the competitor's mark passings list, not *replace* it
+ TreeMap markPassingsByMarkIndex = new TreeMap();
+ // now fill with the already existing mark passings for the competitor identified by boatID...
+ NavigableSet markPassings = trackedRace.getMarkPassings(competitor);
+ trackedRace.lockForRead(markPassings);
+ try {
+ for (MarkPassing markPassing : markPassings) {
+ markPassingsByMarkIndex.put(
+ trackedRace.getRace().getCourse().getIndexOfWaypoint(markPassing.getWaypoint()),
markPassing);
+ }
+ } finally {
+ trackedRace.unlockAfterRead(markPassings);
+ }
+ // ...and then overwrite those for which we received "new evidence"
+ for (com.sap.sse.common.Util.Triple markIndexRankAndTimeSinceStartInMilliseconds : markIndicesRanksAndTimesSinceStartInMilliseconds) {
+ Waypoint waypoint = Util.get(trackedRace.getRace().getCourse().getWaypoints(),
+ markIndexRankAndTimeSinceStartInMilliseconds.getA());
+ // If the rank and time information is empty, we interpret this by clearing the mark rounding if
+ // any (see also bug 1911):
+ if (markIndexRankAndTimeSinceStartInMilliseconds.getC() == null) {
+ markPassingsByMarkIndex.remove(markIndexRankAndTimeSinceStartInMilliseconds.getA());
} else {
- //
- logger.warning("Received mark passing with time relative to start of race "
- + trackedRace.getRace().getName() + " before having received a race start time."
- + " Queueing message for re-application when a start time has been received.");
- tmdMessageQueue.enqueue(raceID, boatID, markIndicesRanksAndTimesSinceStartInMilliseconds);
+ // update mark passing only if we have a start time; guessed start times don't make sense and
+ // for the start line would lead subsequent calls to getStartOfRace() return that guessed
+ // start time which then cannot be identified as "guessed" anymore...
+ if (trackedRace.getStartOfRace() != null) {
+ final TimePoint startTime = trackedRace.getStartOfRace();
+ MillisecondsTimePoint timePoint = new MillisecondsTimePoint(startTime.asMillis()
+ + markIndexRankAndTimeSinceStartInMilliseconds.getC());
+ MarkPassing markPassing = domainFactory.createMarkPassing(timePoint, waypoint,
+ getCompetitorByBoatIDAndRaceIDOrBoatClass(boatID, raceID, boatClass));
+ markPassingsByMarkIndex.put(markIndexRankAndTimeSinceStartInMilliseconds.getA(),
+ markPassing);
+ } else {
+ logger.warning("Received mark passing with time relative to start of race "
+ + trackedRace.getRace().getName()
+ + " before having received a race start time."
+ + " Queueing message for re-application when a start time has been received.");
+ tmdMessageQueue.enqueue(raceID, boatID,
+ markIndicesRanksAndTimesSinceStartInMilliseconds);
+ }
}
}
+ trackedRace.updateMarkPassings(competitor, markPassingsByMarkIndex.values());
+ }
+ } else {
+ if (!loggedIgnore) {
+ logger.info("Ignoring timing data "
+ + markIndicesRanksAndTimesSinceStartInMilliseconds
+ + " for SwissTiming race "
+ + raceID
+ + " because tracked race is no longer reachable. Was the race removed but is still tracked? "
+ + "(Future occurrences of this message will be suppressed)");
+ loggedIgnore = true;
}
- trackedRace.updateMarkPassings(competitor, markPassingsByMarkIndex.values());
- }
- } else {
- if (!loggedIgnore) {
- logger.info("Ignoring timing data " + markIndicesRanksAndTimesSinceStartInMilliseconds + " for SwissTiming race " + raceID
- + " because tracked race is no longer reachable. Was the race removed but is still tracked? "+
- "(Future occurrences of this message will be suppressed)");
- loggedIgnore = true;
}
}
-
}
@Override
@@ -470,7 +475,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
// we already know our single RaceDefinition
assert SwissTimingRaceTrackerImpl.this.race == race;
}
- });
+ }, useInternalMarkPassingAlgorithm);
logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName());
}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java
index 96f68297d16..7045b444af6 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java
@@ -27,10 +27,12 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
private final RegattaLogStore regattaLogStore;
private final long delayToLiveInMillis;
private final StartList startList;
+ private final boolean useInternalMarkPassingAlgorithm;
public SwissTimingTrackingConnectivityParameters(String hostname, int port, String raceID, String raceName,
String raceDescription, BoatClass boatClass, StartList startList, long delayToLiveInMillis,
- SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore) {
+ SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, RaceLogStore raceLogStore,
+ RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm) {
super();
this.hostname = hostname;
this.port = port;
@@ -44,21 +46,23 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
this.domainFactory = domainFactory;
this.raceLogStore = raceLogStore;
this.regattaLogStore = regattaLogStore;
+ this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
}
@Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
GPSFixStore gpsFixStore) throws Exception {
return swissTimingFactory.createRaceTracker(raceID, raceName, raceDescription, boatClass, hostname, port,
- startList, delayToLiveInMillis, raceLogStore, regattaLogStore, windStore, gpsFixStore, domainFactory,
- trackedRegattaRegistry);
+ startList, delayToLiveInMillis, raceLogStore, regattaLogStore, windStore, gpsFixStore, useInternalMarkPassingAlgorithm,
+ domainFactory, trackedRegattaRegistry);
}
@Override
- public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, GPSFixStore gpsFixStore)
- throws Exception {
- return swissTimingFactory.createRaceTracker(regatta, raceID, raceName, raceDescription, boatClass, hostname, port, startList, delayToLiveInMillis, windStore, gpsFixStore, domainFactory,
- trackedRegattaRegistry);
+ public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
+ WindStore windStore, GPSFixStore gpsFixStore) throws Exception {
+ return swissTimingFactory.createRaceTracker(regatta, raceID, raceName, raceDescription, boatClass, hostname,
+ port, startList, delayToLiveInMillis, windStore, gpsFixStore, useInternalMarkPassingAlgorithm,
+ domainFactory, trackedRegattaRegistry);
}
@Override
diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingReplayAdapterServiceTest.java b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingReplayAdapterServiceTest.java
index f46eaf3e03c..e67c8f56bfd 100644
--- a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingReplayAdapterServiceTest.java
+++ b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingReplayAdapterServiceTest.java
@@ -178,7 +178,7 @@ public class SwissTimingReplayAdapterServiceTest {
@Test
public void testRaceData_SAW010955_20120802_WithDomainAdapter() throws Exception {
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, DomainFactory.INSTANCE,
- new DummyTrackedRegattaRegistry());
+ new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false);
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW005906.20120805.replay"), replayListener);
Iterable extends TrackedRace> trackedRaces = replayListener.getTrackedRaces();
assertFalse(Util.isEmpty(trackedRaces));
@@ -192,7 +192,7 @@ public class SwissTimingReplayAdapterServiceTest {
@Test
public void testStartPerformanceDetection() throws Exception {
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, DomainFactory.INSTANCE,
- new DummyTrackedRegattaRegistry());
+ new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false);
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW005906.20120805.replay"), replayListener);
Iterable extends TrackedRace> trackedRaces = replayListener.getTrackedRaces();
TrackedRace trackedRace = trackedRaces.iterator().next();
diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayService.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayService.java
index 194ebeb8a38..7000cd9e137 100755
--- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayService.java
+++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayService.java
@@ -39,7 +39,8 @@ public interface SwissTimingReplayService {
* @param regatta
* the regatta to which the race shall be added; if null, a default regatta will be
* created/used
+ * @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark rounding / split times
*/
- void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry);
+ void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm);
}
diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceImpl.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceImpl.java
index e375689fbfc..35215a778d8 100644
--- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceImpl.java
@@ -143,8 +143,8 @@ public class SwissTimingReplayServiceImpl implements SwissTimingReplayService {
}
@Override
- public void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry) {
- SwissTimingReplayListener listener = new SwissTimingReplayToDomainAdapter(regatta, domainFactory, trackedRegattaRegistry);
+ public void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm) {
+ SwissTimingReplayListener listener = new SwissTimingReplayToDomainAdapter(regatta, domainFactory, trackedRegattaRegistry, useInternalMarkPassingAlgorithm);
loadRaceData(link, listener);
}
}
diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java
index 2d409415b0e..134b445e6db 100755
--- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java
+++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java
@@ -133,13 +133,17 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
private final Map lastNextMark;
private RaceStatus lastRaceStatus;
+
+ private final boolean useInternalMarkPassingAlgorithm;
/**
* @param regatta
* the regatta to associate the race(s) received by the listener with, or null to force the
* use / creation of a default regatta per race
+ * @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark rounding / split times
*/
- public SwissTimingReplayToDomainAdapter(Regatta regatta, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) {
+ public SwissTimingReplayToDomainAdapter(Regatta regatta, DomainFactory domainFactory,
+ TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm) {
this.regatta = regatta;
this.trackedRegattaRegistry = trackedRegattaRegistry;
racePerRaceID = new HashMap<>();
@@ -153,6 +157,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
windAtControlPoint = new HashMap<>();
lastNextMark = new HashMap<>();
this.domainFactory = domainFactory;
+ this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
}
public Iterable getTrackedRaces() {
@@ -260,7 +265,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
short trueWindDirectionInDegrees) {
final List markNames = new ArrayList<>();
markNames.add(id1.trim());
- if (id2 != null) {
+ if (id2 != null && !id2.trim().isEmpty()) {
markNames.add(id2.trim());
}
final ControlPoint controlPoint = domainFactory.getOrCreateControlPoint(markNames);
@@ -311,7 +316,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
createTrackedRace(race, Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS,
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND,
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
- /* raceDefinitionSetToUpdate */ null);
+ /* raceDefinitionSetToUpdate */ null, useInternalMarkPassingAlgorithm);
trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0));
TimePoint bestStartTimeKnownSoFar = bestStartTimePerRaceID.get(currentRaceID);
if (bestStartTimeKnownSoFar != null) {
@@ -349,7 +354,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
trackedRace.recordFix(competitor, fix);
Course course = trackedRace.getRace().getCourse();
// record a mark passing, but not if the mark passing has happened longer than 30s before the race start
- if (bestStartTimePerRaceID.get(currentRaceID) != null &&
+ if (!useInternalMarkPassingAlgorithm && bestStartTimePerRaceID.get(currentRaceID) != null &&
!bestStartTimePerRaceID.get(currentRaceID).after(
raceTimePoint.plus(THRESHOLD_FOR_EARLIEST_MARK_PASSING_BEFORE_START_IN_MILLIS)) &&
(!lastNextMark.containsKey(competitor) || lastNextMark.get(competitor) != nextMark) && nextMark > 0) {
diff --git a/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_5.mtb b/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_5.mtb
new file mode 100755
index 00000000000..adae6c1cef3
Binary files /dev/null and b/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_5.mtb differ
diff --git a/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_5.txt b/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_5.txt
new file mode 100755
index 00000000000..c58a32592d0
--- /dev/null
+++ b/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_5.txt
@@ -0,0 +1,685 @@
+stored-uri:datafiles/event_20130424_IDMStarboo-Race_5.mtb
+StartReplay:1
+
+// Input from params_static:
+
+// Input from event_parameters:
+
+CompMarkerUUID:1
+PopUpRow1Type:Name
+PopUpRow1Name:
+PopUpRow2Type:Ini
+PopUpRow2Name:Sail
+PopUpRow3Type:RowNumber
+PopUpRow3Name:Rank
+PopUpRow4Type:BoatSpeed
+PopUpRow4Name:Knots
+PopUpRow5Type:Heading
+PopUpRow5Name:Head
+PopUpRow6Type:BoatAfter
+PopUpRow6Name:After
+CodanIsSponsor:0
+DefaultTailLength:60
+APzoomChangeTime:2500
+disableAutoProduce:0
+autoProduce:1
+APstartLineShowOfLeg:0.25
+APsideOfStartLine:0.30
+APstartSwitch:0.8
+APwholeLegBehindMarks:0.15
+APmarkSwitch:0.13
+APmarkZoomBehindMarks:0.10
+APmarkZoomInFrontOfMarks:0.20
+PopupMarkerUUID:2
+ManualUrl:http://www.tractrac.com/files/userguide_sailing.pdf
+Marker1UUID:1
+Marker1Type:RGBMarkerFactory
+Marker1Directional:1
+Marker1Image:markers/boat_FF0000_big.png
+Marker1Length:5
+Marker1MinPixelSize:30
+Startlocation:8.122902,51.486942
+MaxDiffTime:1200
+MaxMetersPerSecond:20
+PrecisionMeters:20
+ShortAvgTime:180
+LongAvgTime:900
+TimeZone:2
+CompMarkerTimeout:60
+FramesPerSecond:8
+replayspeedup:5
+MatchRaceClock:0
+MatchRaceClockNo:3
+MatchRaceClockSpacing:300
+Minimap:1
+MinimapUseLayers:2
+Minimapgeorect:8.033638,51.51558,8.18676,51.460852
+MinimapMarkerUUID:2
+Marker4UUID:2
+Marker4Type:RGBmarkerFactory
+Marker4Directional:1
+Marker4Image:markers/boat_FF0000_small.png
+MetersPerPixel:18
+MetersPerPixelMax:30
+MetersPerPixelMin:0.05
+isMatchRace:0
+weatherEnabled:0
+showRaceClock:1
+BackGroundImage:graphics/background.jpg
+DisableRotation:0
+ControlPointMarkerRadius:21
+disableselection:0
+disableleaderline:0
+DisableChangeRace:0
+ResultColumn1Name:#
+ResultColumn1Size:20
+ResultColumn1Type:RowNumber
+ResultColumn2Size:20
+ResultColumn2Type:ColorMarker
+ResultColumn3Name:sail
+ResultColumn3Size:45
+ResultColumn3Type:Ini
+ResultColumn4Name:name
+ResultColumn4Size:110
+ResultColumn4Type:Name
+ResultColumn5Name:after
+ResultColumn5Size:45
+ResultColumn5Type:BoatAfter
+ResultColumn6Name:kts
+ResultColumn6Size:40
+ResultColumn6Type:BoatSpeed
+DisableLeaderboard:0
+DisableAnalysis:0
+TableFontSize:11
+//live-uri:tcp://germanmaster.traclive.dk:4400
+//stored-uri:tcp://germanmaster.traclive.dk:4401
+compInitialsFontSize:11
+AutoRotate:0
+MassStart:0
+SegmentFile:segments.php
+StartType:Mass
+ReCalcDirAndSpeed:0
+RaceHandicapSystem:NONE
+TeamCompetitionType:NONE
+LiveDelaySecs: 20
+
+//-------- AUTO GENERATED PARAMETERS START ----------------
+
+EventID:e1995602-acc8-11e2-89c0-10bf48d758ce
+EventName:IDM Starboot 2013
+EventDB:event_20130424_IDMStarboo
+EventStartTime:2013-04-24 10:00:00
+EventEndTime:2013-05-05 23:00:00
+
+RaceID:5e8fc7c6-b409-11e2-8561-10bf48d758ce
+RaceName:Race 5
+RaceStartTime:2013-05-04 12:50:00
+RaceEndTime:
+RaceTrackingStartTime:2013-05-04 12:44:00
+RaceTrackingEndTime:2013-05-04 13:46:15
+RaceDefaultRouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+RaceHandicapSystem:NONE
+
+Class1UUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Class1Name:Star
+
+Team1UUID:3a798f60-b3f1-11e2-8561-10bf48d758ce
+Team1Name:Team
+Team1Comp1UUID:87a8f43c-b3f2-11e2-8561-10bf48d758ce
+Team1Comp2UUID:8999a2dc-b3f2-11e2-8561-10bf48d758ce
+Team1Comp3UUID:84737a80-b3f2-11e2-8561-10bf48d758ce
+Team1Comp4UUID:84f68cf4-b3f2-11e2-8561-10bf48d758ce
+Team1Comp5UUID:8ba307da-b3f2-11e2-8561-10bf48d758ce
+Team1Comp6UUID:85dac766-b3f2-11e2-8561-10bf48d758ce
+Team1Comp7UUID:82ddec3c-b3f2-11e2-8561-10bf48d758ce
+Team1Comp8UUID:88920d16-b3f2-11e2-8561-10bf48d758ce
+Team1Comp9UUID:88e60efc-b3f2-11e2-8561-10bf48d758ce
+Team1Comp10UUID:86286462-b3f2-11e2-8561-10bf48d758ce
+Team1Comp11UUID:86c9c3fc-b3f2-11e2-8561-10bf48d758ce
+Team1Comp12UUID:8939a094-b3f2-11e2-8561-10bf48d758ce
+Team1Comp13UUID:83a1f6fe-b3f2-11e2-8561-10bf48d758ce
+Team1Comp14UUID:8cadf6d0-b3f2-11e2-8561-10bf48d758ce
+Team1Comp15UUID:858f812a-b3f2-11e2-8561-10bf48d758ce
+Team1Comp16UUID:8c003dba-b3f2-11e2-8561-10bf48d758ce
+Team1Comp17UUID:867dd88e-b3f2-11e2-8561-10bf48d758ce
+Team1Comp18UUID:8cfb82c4-b3f2-11e2-8561-10bf48d758ce
+Team1Comp19UUID:83cc72c6-b3f2-11e2-8561-10bf48d758ce
+Team1Comp20UUID:883da6ea-b3f2-11e2-8561-10bf48d758ce
+Team1Comp21UUID:8339fee6-b3f2-11e2-8561-10bf48d758ce
+Team1Comp22UUID:843187ec-b3f2-11e2-8561-10bf48d758ce
+Team1Comp23UUID:8c57247c-b3f2-11e2-8561-10bf48d758ce
+Team1Comp24UUID:8a3c52b6-b3f2-11e2-8561-10bf48d758ce
+Team1Comp25UUID:875c9aec-b3f2-11e2-8561-10bf48d758ce
+Team1Comp26UUID:8b05a148-b3f2-11e2-8561-10bf48d758ce
+Team1Comp27UUID:83023b82-b3f2-11e2-8561-10bf48d758ce
+Team1Comp28UUID:87f4d898-b3f2-11e2-8561-10bf48d758ce
+Team1Comp29UUID:89e9dd1a-b3f2-11e2-8561-10bf48d758ce
+Team1Comp30UUID:8aaca2a0-b3f2-11e2-8561-10bf48d758ce
+Team1Comp31UUID:83550484-b3f2-11e2-8561-10bf48d758ce
+Team1Comp32UUID:837c17cc-b3f2-11e2-8561-10bf48d758ce
+Team1Comp33UUID:83237d2e-b3f2-11e2-8561-10bf48d758ce
+Team1Comp34UUID:83fa5e70-b3f2-11e2-8561-10bf48d758ce
+Team1Comp35UUID:871283e4-b3f2-11e2-8561-10bf48d758ce
+Team1Comp36UUID:8b56f32c-b3f2-11e2-8561-10bf48d758ce
+Team1Comp37UUID:84b5e8d4-b3f2-11e2-8561-10bf48d758ce
+Team1Comp38UUID:853ca13a-b3f2-11e2-8561-10bf48d758ce
+Team1Comp39UUID:8d50d12a-b3f2-11e2-8561-10bf48d758ce
+
+Comp1UUID:82ddec3c-b3f2-11e2-8561-10bf48d758ce
+Comp1Name:Fallais, Dominik,Fallais, Simo
+Comp1NameShort:GER7
+Comp1Color:000080
+Comp1Nationality:GER
+Comp1Description:0
+Comp1Handicap:1.0000000000
+Comp1HandicapDistance:0.00000
+Comp1StartTime:2013-05-04 12:50:00
+Comp1ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp1RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp2UUID:83023b82-b3f2-11e2-8561-10bf48d758ce
+Comp2Name:Nolte, Robin,Dieckmann, Hennin
+Comp2NameShort:GER433
+Comp2Color:000000
+Comp2Nationality:GER
+Comp2Description:0
+Comp2Handicap:1.0000000000
+Comp2HandicapDistance:0.00000
+Comp2StartTime:2013-05-04 12:50:00
+Comp2ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp2RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp3UUID:83237d2e-b3f2-11e2-8561-10bf48d758ce
+Comp3Name:Seekamp, Jan,Müller Gösta
+Comp3NameShort:GER1122
+Comp3Color:00FF00
+Comp3Nationality:GER
+Comp3Description:0
+Comp3Handicap:1.0000000000
+Comp3HandicapDistance:0.00000
+Comp3StartTime:2013-05-04 12:50:00
+Comp3ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp3RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp4UUID:8339fee6-b3f2-11e2-8561-10bf48d758ce
+Comp4Name:Luxa, Claus-Peter,Röttger, Rol
+Comp4NameShort:GER7013
+Comp4Color:800000
+Comp4Nationality:GER
+Comp4Description:0
+Comp4Handicap:1.0000000000
+Comp4HandicapDistance:0.00000
+Comp4StartTime:2013-05-04 12:50:00
+Comp4ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp4RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp5UUID:83550484-b3f2-11e2-8561-10bf48d758ce
+Comp5Name:Schulte, Gert,Schulte, Gerrit
+Comp5NameShort:GER7417
+Comp5Color:FFFF00
+Comp5Nationality:GER
+Comp5Description:0
+Comp5Handicap:1.0000000000
+Comp5HandicapDistance:0.00000
+Comp5StartTime:2013-05-04 12:50:00
+Comp5ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp5RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp6UUID:837c17cc-b3f2-11e2-8561-10bf48d758ce
+Comp6Name:Seefelder, Jürgen,Seefelder, N
+Comp6NameShort:GER7616
+Comp6Color:00FFFF
+Comp6Nationality:GER
+Comp6Description:0
+Comp6Handicap:1.0000000000
+Comp6HandicapDistance:0.00000
+Comp6StartTime:2013-05-04 12:50:00
+Comp6ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp6RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp7UUID:83a1f6fe-b3f2-11e2-8561-10bf48d758ce
+Comp7Name:Hoffmann, Peter,Theis, Nina
+Comp7NameShort:GER7693
+Comp7Color:0000FF
+Comp7Nationality:GER
+Comp7Description:0
+Comp7Handicap:1.0000000000
+Comp7HandicapDistance:0.00000
+Comp7StartTime:2013-05-04 12:50:00
+Comp7ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp7RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp8UUID:83cc72c6-b3f2-11e2-8561-10bf48d758ce
+Comp8Name:Kohler, Thomas,Roszinski, Dr.
+Comp8NameShort:GER7727
+Comp8Color:800080
+Comp8Nationality:GER
+Comp8Description:0
+Comp8Handicap:1.0000000000
+Comp8HandicapDistance:0.00000
+Comp8StartTime:2013-05-04 12:50:00
+Comp8ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp8RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp9UUID:83fa5e70-b3f2-11e2-8561-10bf48d758ce
+Comp9Name:Spehr, Helge,Spehr, Jesper
+Comp9NameShort:GER7747
+Comp9Color:008080
+Comp9Nationality:GER
+Comp9Description:0
+Comp9Handicap:1.0000000000
+Comp9HandicapDistance:0.00000
+Comp9StartTime:2013-05-04 12:50:00
+Comp9ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp9RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp10UUID:843187ec-b3f2-11e2-8561-10bf48d758ce
+Comp10Name:Massler, Julian,Seeberger, Uli
+Comp10NameShort:GER7860
+Comp10Color:808000
+Comp10Nationality:GER
+Comp10Description:0
+Comp10Handicap:1.0000000000
+Comp10HandicapDistance:0.00000
+Comp10StartTime:2013-05-04 12:50:00
+Comp10ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp10RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp11UUID:84737a80-b3f2-11e2-8561-10bf48d758ce
+Comp11Name:Behn, Philip,Kaerger, Andreas
+Comp11NameShort:GER7866
+Comp11Color:FF0000
+Comp11Nationality:GER
+Comp11Description:0
+Comp11Handicap:1.0000000000
+Comp11HandicapDistance:0.00000
+Comp11StartTime:2013-05-04 12:50:00
+Comp11ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp11RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp12UUID:84b5e8d4-b3f2-11e2-8561-10bf48d758ce
+Comp12Name:Tusch, Frank,Winkelmann, Sven
+Comp12NameShort:GER7897
+Comp12Color:FFFFFF
+Comp12Nationality:GER
+Comp12Description:0
+Comp12Handicap:1.0000000000
+Comp12HandicapDistance:0.00000
+Comp12StartTime:2013-05-04 12:50:00
+Comp12ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp12RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp13UUID:84f68cf4-b3f2-11e2-8561-10bf48d758ce
+Comp13Name:Bode, Klaus,Bode, Alexander
+Comp13NameShort:GER7898
+Comp13Color:FF00FF
+Comp13Nationality:GER
+Comp13Description:0
+Comp13Handicap:1.0000000000
+Comp13HandicapDistance:0.00000
+Comp13StartTime:2013-05-04 12:50:00
+Comp13ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp13RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp14UUID:853ca13a-b3f2-11e2-8561-10bf48d758ce
+Comp14Name:Vater, Ulrich,Nolte, Andreas
+Comp14NameShort:GER7971
+Comp14Color:008000
+Comp14Nationality:GER
+Comp14Description:0
+Comp14Handicap:1.0000000000
+Comp14HandicapDistance:0.00000
+Comp14StartTime:2013-05-04 12:50:00
+Comp14ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp14RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp15UUID:858f812a-b3f2-11e2-8561-10bf48d758ce
+Comp15Name:Janson, Jürgen,Schulte, Axel
+Comp15NameShort:GER7981
+Comp15Color:000080
+Comp15Nationality:GER
+Comp15Description:0
+Comp15Handicap:1.0000000000
+Comp15HandicapDistance:0.00000
+Comp15StartTime:2013-05-04 12:50:00
+Comp15ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp15RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp16UUID:85dac766-b3f2-11e2-8561-10bf48d758ce
+Comp16Name:Diercks, Jochen,Braasch, Herbe
+Comp16NameShort:GER8055
+Comp16Color:000000
+Comp16Nationality:GER
+Comp16Description:0
+Comp16Handicap:1.0000000000
+Comp16HandicapDistance:0.00000
+Comp16StartTime:2013-05-04 12:50:00
+Comp16ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp16RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp17UUID:86286462-b3f2-11e2-8561-10bf48d758ce
+Comp17Name:Hagen, Alexander,Hasche, Marko
+Comp17NameShort:GER8093
+Comp17Color:00FF00
+Comp17Nationality:GER
+Comp17Description:0
+Comp17Handicap:1.0000000000
+Comp17HandicapDistance:0.00000
+Comp17StartTime:2013-05-04 12:50:00
+Comp17ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp17RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp18UUID:867dd88e-b3f2-11e2-8561-10bf48d758ce
+Comp18Name:Kappes, Klaus,Rutz, Steffen
+Comp18NameShort:GER8122
+Comp18Color:800000
+Comp18Nationality:GER
+Comp18Description:0
+Comp18Handicap:1.0000000000
+Comp18HandicapDistance:0.00000
+Comp18StartTime:2013-05-04 12:50:00
+Comp18ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp18RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp19UUID:86c9c3fc-b3f2-11e2-8561-10bf48d758ce
+Comp19Name:Hannemann, Uwe,Dahms, Anette
+Comp19NameShort:GER8124
+Comp19Color:FFFF00
+Comp19Nationality:GER
+Comp19Description:0
+Comp19Handicap:1.0000000000
+Comp19HandicapDistance:0.00000
+Comp19StartTime:2013-05-04 12:50:00
+Comp19ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp19RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp20UUID:871283e4-b3f2-11e2-8561-10bf48d758ce
+Comp20Name:Stoll, Bernd,Stoll, Barbara
+Comp20NameShort:GER8147
+Comp20Color:00FFFF
+Comp20Nationality:GER
+Comp20Description:0
+Comp20Handicap:1.0000000000
+Comp20HandicapDistance:0.00000
+Comp20StartTime:2013-05-04 12:50:00
+Comp20ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp20RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp21UUID:875c9aec-b3f2-11e2-8561-10bf48d758ce
+Comp21Name:Meyer, Klaus,Müller, Jörg
+Comp21NameShort:GER8179
+Comp21Color:0000FF
+Comp21Nationality:GER
+Comp21Description:0
+Comp21Handicap:1.0000000000
+Comp21HandicapDistance:0.00000
+Comp21StartTime:2013-05-04 12:50:00
+Comp21ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp21RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp22UUID:87a8f43c-b3f2-11e2-8561-10bf48d758ce
+Comp22Name:Antrecht, Alexander,Schwill, F
+Comp22NameShort:GER8190
+Comp22Color:800080
+Comp22Nationality:GER
+Comp22Description:0
+Comp22Handicap:1.0000000000
+Comp22HandicapDistance:0.00000
+Comp22StartTime:2013-05-04 12:50:00
+Comp22ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp22RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp23UUID:87f4d898-b3f2-11e2-8561-10bf48d758ce
+Comp23Name:Pieper, Josef,Vockel, Ralf
+Comp23NameShort:GER8233
+Comp23Color:008080
+Comp23Nationality:GER
+Comp23Description:0
+Comp23Handicap:1.0000000000
+Comp23HandicapDistance:0.00000
+Comp23StartTime:2013-05-04 12:50:00
+Comp23ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp23RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp24UUID:883da6ea-b3f2-11e2-8561-10bf48d758ce
+Comp24Name:König, Kilian,Schäfer, Kai
+Comp24NameShort:GER8301
+Comp24Color:808000
+Comp24Nationality:GER
+Comp24Description:0
+Comp24Handicap:1.0000000000
+Comp24HandicapDistance:0.00000
+Comp24StartTime:2013-05-04 12:50:00
+Comp24ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp24RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp25UUID:88920d16-b3f2-11e2-8561-10bf48d758ce
+Comp25Name:Glunde, Arnd,Beltz, Marcel
+Comp25NameShort:GER8321
+Comp25Color:FF0000
+Comp25Nationality:GER
+Comp25Description:0
+Comp25Handicap:1.0000000000
+Comp25HandicapDistance:0.00000
+Comp25StartTime:2013-05-04 12:50:00
+Comp25ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp25RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp26UUID:88e60efc-b3f2-11e2-8561-10bf48d758ce
+Comp26Name:Griese, Achim,Marcour, Michael
+Comp26NameShort:GER8340
+Comp26Color:FFFFFF
+Comp26Nationality:GER
+Comp26Description:0
+Comp26Handicap:1.0000000000
+Comp26HandicapDistance:0.00000
+Comp26StartTime:2013-05-04 12:50:00
+Comp26ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp26RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp27UUID:8939a094-b3f2-11e2-8561-10bf48d758ce
+Comp27Name:Hellmich, Joachim,Lacher, Stef
+Comp27NameShort:GER8412
+Comp27Color:FF00FF
+Comp27Nationality:GER
+Comp27Description:0
+Comp27Handicap:1.0000000000
+Comp27HandicapDistance:0.00000
+Comp27StartTime:2013-05-04 12:50:00
+Comp27ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp27RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp28UUID:8999a2dc-b3f2-11e2-8561-10bf48d758ce
+Comp28Name:Babendererde, Johannes,Voigt,
+Comp28NameShort:GER8433
+Comp28Color:008000
+Comp28Nationality:GER
+Comp28Description:0
+Comp28Handicap:1.0000000000
+Comp28HandicapDistance:0.00000
+Comp28StartTime:2013-05-04 12:50:00
+Comp28ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp28RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp29UUID:89e9dd1a-b3f2-11e2-8561-10bf48d758ce
+Comp29Name:Polgar, Johannes,Koy, Markus
+Comp29NameShort:GER8442
+Comp29Color:000080
+Comp29Nationality:GER
+Comp29Description:0
+Comp29Handicap:1.0000000000
+Comp29HandicapDistance:0.00000
+Comp29StartTime:2013-05-04 12:50:00
+Comp29ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp29RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp30UUID:8a3c52b6-b3f2-11e2-8561-10bf48d758ce
+Comp30Name:Merkelbach, Hubert,Kleen, Frit
+Comp30NameShort:GER8450
+Comp30Color:000000
+Comp30Nationality:GER
+Comp30Description:0
+Comp30Handicap:1.0000000000
+Comp30HandicapDistance:0.00000
+Comp30StartTime:2013-05-04 12:50:00
+Comp30ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp30RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp31UUID:8aaca2a0-b3f2-11e2-8561-10bf48d758ce
+Comp31Name:Schmidt, Reinhard,Hentschel, N
+Comp31NameShort:GER8478
+Comp31Color:00FF00
+Comp31Nationality:GER
+Comp31Description:0
+Comp31Handicap:1.0000000000
+Comp31HandicapDistance:0.00000
+Comp31StartTime:2013-05-04 12:50:00
+Comp31ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp31RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp32UUID:8b05a148-b3f2-11e2-8561-10bf48d758ce
+Comp32Name:Müllejans, Christian,Morf, Kar
+Comp32NameShort:ITA8400
+Comp32Color:800000
+Comp32Nationality:ITA
+Comp32Description:0
+Comp32Handicap:1.0000000000
+Comp32HandicapDistance:0.00000
+Comp32StartTime:2013-05-04 12:50:00
+Comp32ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp32RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp33UUID:8b56f32c-b3f2-11e2-8561-10bf48d758ce
+Comp33Name:Tennigkeit, Alexander,Schöller
+Comp33NameShort:SUI7948
+Comp33Color:FFFF00
+Comp33Nationality:SUI
+Comp33Description:0
+Comp33Handicap:1.0000000000
+Comp33HandicapDistance:0.00000
+Comp33StartTime:2013-05-04 12:50:00
+Comp33ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp33RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp34UUID:8ba307da-b3f2-11e2-8561-10bf48d758ce
+Comp34Name:Bondar, Pavlo,Malzev, Konstant
+Comp34NameShort:UKR8119
+Comp34Color:00FFFF
+Comp34Nationality:UKR
+Comp34Description:0
+Comp34Handicap:1.0000000000
+Comp34HandicapDistance:0.00000
+Comp34StartTime:2013-05-04 12:50:00
+Comp34ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp34RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp35UUID:8c003dba-b3f2-11e2-8561-10bf48d758ce
+Comp35Name:Jensen, Johnny
+Comp35NameShort:DEN8124
+Comp35Color:0000FF
+Comp35Nationality:DEN
+Comp35Description:0
+Comp35Handicap:1.0000000000
+Comp35HandicapDistance:0.00000
+Comp35StartTime:2013-05-04 12:50:00
+Comp35ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp35RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp36UUID:8c57247c-b3f2-11e2-8561-10bf48d758ce
+Comp36Name:Mellis, Jörg,Flugel, Falko
+Comp36NameShort:GER816
+Comp36Color:800080
+Comp36Nationality:GER
+Comp36Description:0
+Comp36Handicap:1.0000000000
+Comp36HandicapDistance:0.00000
+Comp36StartTime:2013-05-04 12:50:00
+Comp36ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp36RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp37UUID:8cadf6d0-b3f2-11e2-8561-10bf48d758ce
+Comp37Name:Hülsmann, Thorsten
+Comp37NameShort:GER7897
+Comp37Color:008080
+Comp37Nationality:GER
+Comp37Description:0
+Comp37Handicap:1.0000000000
+Comp37HandicapDistance:0.00000
+Comp37StartTime:2013-05-04 12:50:00
+Comp37ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp37RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp38UUID:8cfb82c4-b3f2-11e2-8561-10bf48d758ce
+Comp38Name:Kleine, Frieder
+Comp38NameShort:GER8301
+Comp38Color:808000
+Comp38Nationality:GER
+Comp38Description:0
+Comp38Handicap:1.0000000000
+Comp38HandicapDistance:0.00000
+Comp38StartTime:2013-05-04 12:50:00
+Comp38ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp38RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp39UUID:8d50d12a-b3f2-11e2-8561-10bf48d758ce
+Comp39Name:von Linde, Florian,Steffens, T
+Comp39NameShort:GER8419
+Comp39Color:FF0000
+Comp39Nationality:GER
+Comp39Description:0
+Comp39Handicap:1.0000000000
+Comp39HandicapDistance:0.00000
+Comp39StartTime:2013-05-04 12:50:00
+Comp39ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp39RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+ControlPoint1UUID:166ab660-b3f3-11e2-8561-10bf48d758ce
+ControlPoint1Name:Start/Ziel
+ControlPoint1HasTwoPoints:1
+ControlPoint1ShortName:St
+ControlPoint1Mark1Lon:8.076407
+ControlPoint1Mark1Lat:51.482072
+ControlPoint1Mark2Lon:8.073195
+ControlPoint1Mark2Lat:51.479408
+
+ControlPoint2UUID:2b5bde8c-b3f3-11e2-8561-10bf48d758ce
+ControlPoint2Name:Luvtonne
+ControlPoint2HasTwoPoints:0
+ControlPoint2ShortName:Lu
+ControlPoint2Mark1Lon:8.064945
+ControlPoint2Mark1Lat:51.485257
+
+ControlPoint3UUID:3f999718-b3f3-11e2-8561-10bf48d758ce
+ControlPoint3Name:Offset Luvtonne
+ControlPoint3HasTwoPoints:0
+ControlPoint3ShortName:Of
+ControlPoint3Mark1Lon:8.064112
+ControlPoint3Mark1Lat:51.484790
+
+ControlPoint4UUID:b160887a-b3f3-11e2-8561-10bf48d758ce
+ControlPoint4Name:Leegate
+ControlPoint4HasTwoPoints:1
+ControlPoint4ShortName:Le
+ControlPoint4Mark1Lon:8.076623
+ControlPoint4Mark1Lat:51.480175
+ControlPoint4Mark2Lon:8.076272
+ControlPoint4Mark2Lat:51.479722
+
+
+SegmentFile:segments.php
+Route1UUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+Route1Description:Windward-Leeward - 3 Laps
+Route1Length:0
+Route1ControlPoint1UUID:166ab660-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint2UUID:2b5bde8c-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint3UUID:3f999718-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint4UUID:b160887a-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint5UUID:2b5bde8c-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint6UUID:3f999718-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint7UUID:b160887a-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint8UUID:2b5bde8c-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint9UUID:3f999718-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint10UUID:b160887a-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint11UUID:166ab660-b3f3-11e2-8561-10bf48d758ce
+
+//-------- AUTO GENERATED PARAMETERS END ------------------
diff --git a/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_6.mtb b/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_6.mtb
new file mode 100755
index 00000000000..d271984959a
Binary files /dev/null and b/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_6.mtb differ
diff --git a/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_6.txt b/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_6.txt
new file mode 100755
index 00000000000..e76cb6d0d04
--- /dev/null
+++ b/java/com.sap.sailing.domain.test/resources/event_20130424_IDMStarboo-Race_6.txt
@@ -0,0 +1,685 @@
+stored-uri:datafiles/event_20130424_IDMStarboo-Race_6.mtb
+StartReplay:1
+
+// Input from params_static:
+
+// Input from event_parameters:
+
+CompMarkerUUID:1
+PopUpRow1Type:Name
+PopUpRow1Name:
+PopUpRow2Type:Ini
+PopUpRow2Name:Sail
+PopUpRow3Type:RowNumber
+PopUpRow3Name:Rank
+PopUpRow4Type:BoatSpeed
+PopUpRow4Name:Knots
+PopUpRow5Type:Heading
+PopUpRow5Name:Head
+PopUpRow6Type:BoatAfter
+PopUpRow6Name:After
+CodanIsSponsor:0
+DefaultTailLength:60
+APzoomChangeTime:2500
+disableAutoProduce:0
+autoProduce:1
+APstartLineShowOfLeg:0.25
+APsideOfStartLine:0.30
+APstartSwitch:0.8
+APwholeLegBehindMarks:0.15
+APmarkSwitch:0.13
+APmarkZoomBehindMarks:0.10
+APmarkZoomInFrontOfMarks:0.20
+PopupMarkerUUID:2
+ManualUrl:http://www.tractrac.com/files/userguide_sailing.pdf
+Marker1UUID:1
+Marker1Type:RGBMarkerFactory
+Marker1Directional:1
+Marker1Image:markers/boat_FF0000_big.png
+Marker1Length:5
+Marker1MinPixelSize:30
+Startlocation:8.122902,51.486942
+MaxDiffTime:1200
+MaxMetersPerSecond:20
+PrecisionMeters:20
+ShortAvgTime:180
+LongAvgTime:900
+TimeZone:2
+CompMarkerTimeout:60
+FramesPerSecond:8
+replayspeedup:5
+MatchRaceClock:0
+MatchRaceClockNo:3
+MatchRaceClockSpacing:300
+Minimap:1
+MinimapUseLayers:2
+Minimapgeorect:8.033638,51.51558,8.18676,51.460852
+MinimapMarkerUUID:2
+Marker4UUID:2
+Marker4Type:RGBmarkerFactory
+Marker4Directional:1
+Marker4Image:markers/boat_FF0000_small.png
+MetersPerPixel:18
+MetersPerPixelMax:30
+MetersPerPixelMin:0.05
+isMatchRace:0
+weatherEnabled:0
+showRaceClock:1
+BackGroundImage:graphics/background.jpg
+DisableRotation:0
+ControlPointMarkerRadius:21
+disableselection:0
+disableleaderline:0
+DisableChangeRace:0
+ResultColumn1Name:#
+ResultColumn1Size:20
+ResultColumn1Type:RowNumber
+ResultColumn2Size:20
+ResultColumn2Type:ColorMarker
+ResultColumn3Name:sail
+ResultColumn3Size:45
+ResultColumn3Type:Ini
+ResultColumn4Name:name
+ResultColumn4Size:110
+ResultColumn4Type:Name
+ResultColumn5Name:after
+ResultColumn5Size:45
+ResultColumn5Type:BoatAfter
+ResultColumn6Name:kts
+ResultColumn6Size:40
+ResultColumn6Type:BoatSpeed
+DisableLeaderboard:0
+DisableAnalysis:0
+TableFontSize:11
+//live-uri:tcp://germanmaster.traclive.dk:4400
+//stored-uri:tcp://germanmaster.traclive.dk:4401
+compInitialsFontSize:11
+AutoRotate:0
+MassStart:0
+SegmentFile:segments.php
+StartType:Mass
+ReCalcDirAndSpeed:0
+RaceHandicapSystem:NONE
+TeamCompetitionType:NONE
+LiveDelaySecs: 20
+
+//-------- AUTO GENERATED PARAMETERS START ----------------
+
+EventID:e1995602-acc8-11e2-89c0-10bf48d758ce
+EventName:IDM Starboot 2013
+EventDB:event_20130424_IDMStarboo
+EventStartTime:2013-04-24 10:00:00
+EventEndTime:2013-05-05 23:00:00
+
+RaceID:5ee63a52-b409-11e2-8561-10bf48d758ce
+RaceName:Race 6
+RaceStartTime:2013-05-04 14:00:00
+RaceEndTime:
+RaceTrackingStartTime:2013-05-04 13:48:11
+RaceTrackingEndTime:2013-05-04 14:58:38
+RaceDefaultRouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+RaceHandicapSystem:NONE
+
+Class1UUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Class1Name:Star
+
+Team1UUID:3a798f60-b3f1-11e2-8561-10bf48d758ce
+Team1Name:Team
+Team1Comp1UUID:87a8f43c-b3f2-11e2-8561-10bf48d758ce
+Team1Comp2UUID:8999a2dc-b3f2-11e2-8561-10bf48d758ce
+Team1Comp3UUID:84737a80-b3f2-11e2-8561-10bf48d758ce
+Team1Comp4UUID:84f68cf4-b3f2-11e2-8561-10bf48d758ce
+Team1Comp5UUID:8ba307da-b3f2-11e2-8561-10bf48d758ce
+Team1Comp6UUID:85dac766-b3f2-11e2-8561-10bf48d758ce
+Team1Comp7UUID:82ddec3c-b3f2-11e2-8561-10bf48d758ce
+Team1Comp8UUID:88920d16-b3f2-11e2-8561-10bf48d758ce
+Team1Comp9UUID:88e60efc-b3f2-11e2-8561-10bf48d758ce
+Team1Comp10UUID:86286462-b3f2-11e2-8561-10bf48d758ce
+Team1Comp11UUID:86c9c3fc-b3f2-11e2-8561-10bf48d758ce
+Team1Comp12UUID:8939a094-b3f2-11e2-8561-10bf48d758ce
+Team1Comp13UUID:83a1f6fe-b3f2-11e2-8561-10bf48d758ce
+Team1Comp14UUID:8cadf6d0-b3f2-11e2-8561-10bf48d758ce
+Team1Comp15UUID:858f812a-b3f2-11e2-8561-10bf48d758ce
+Team1Comp16UUID:8c003dba-b3f2-11e2-8561-10bf48d758ce
+Team1Comp17UUID:867dd88e-b3f2-11e2-8561-10bf48d758ce
+Team1Comp18UUID:8cfb82c4-b3f2-11e2-8561-10bf48d758ce
+Team1Comp19UUID:83cc72c6-b3f2-11e2-8561-10bf48d758ce
+Team1Comp20UUID:883da6ea-b3f2-11e2-8561-10bf48d758ce
+Team1Comp21UUID:8339fee6-b3f2-11e2-8561-10bf48d758ce
+Team1Comp22UUID:843187ec-b3f2-11e2-8561-10bf48d758ce
+Team1Comp23UUID:8c57247c-b3f2-11e2-8561-10bf48d758ce
+Team1Comp24UUID:8a3c52b6-b3f2-11e2-8561-10bf48d758ce
+Team1Comp25UUID:875c9aec-b3f2-11e2-8561-10bf48d758ce
+Team1Comp26UUID:8b05a148-b3f2-11e2-8561-10bf48d758ce
+Team1Comp27UUID:83023b82-b3f2-11e2-8561-10bf48d758ce
+Team1Comp28UUID:87f4d898-b3f2-11e2-8561-10bf48d758ce
+Team1Comp29UUID:89e9dd1a-b3f2-11e2-8561-10bf48d758ce
+Team1Comp30UUID:8aaca2a0-b3f2-11e2-8561-10bf48d758ce
+Team1Comp31UUID:83550484-b3f2-11e2-8561-10bf48d758ce
+Team1Comp32UUID:837c17cc-b3f2-11e2-8561-10bf48d758ce
+Team1Comp33UUID:83237d2e-b3f2-11e2-8561-10bf48d758ce
+Team1Comp34UUID:83fa5e70-b3f2-11e2-8561-10bf48d758ce
+Team1Comp35UUID:871283e4-b3f2-11e2-8561-10bf48d758ce
+Team1Comp36UUID:8b56f32c-b3f2-11e2-8561-10bf48d758ce
+Team1Comp37UUID:84b5e8d4-b3f2-11e2-8561-10bf48d758ce
+Team1Comp38UUID:853ca13a-b3f2-11e2-8561-10bf48d758ce
+Team1Comp39UUID:8d50d12a-b3f2-11e2-8561-10bf48d758ce
+
+Comp1UUID:82ddec3c-b3f2-11e2-8561-10bf48d758ce
+Comp1Name:Fallais, Dominik,Fallais, Simo
+Comp1NameShort:GER7
+Comp1Color:000080
+Comp1Nationality:GER
+Comp1Description:0
+Comp1Handicap:1.0000000000
+Comp1HandicapDistance:0.00000
+Comp1StartTime:2013-05-04 14:00:00
+Comp1ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp1RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp2UUID:83023b82-b3f2-11e2-8561-10bf48d758ce
+Comp2Name:Nolte, Robin,Dieckmann, Hennin
+Comp2NameShort:GER433
+Comp2Color:000000
+Comp2Nationality:GER
+Comp2Description:0
+Comp2Handicap:1.0000000000
+Comp2HandicapDistance:0.00000
+Comp2StartTime:2013-05-04 14:00:00
+Comp2ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp2RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp3UUID:83237d2e-b3f2-11e2-8561-10bf48d758ce
+Comp3Name:Seekamp, Jan,Müller Gösta
+Comp3NameShort:GER1122
+Comp3Color:00FF00
+Comp3Nationality:GER
+Comp3Description:0
+Comp3Handicap:1.0000000000
+Comp3HandicapDistance:0.00000
+Comp3StartTime:2013-05-04 14:00:00
+Comp3ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp3RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp4UUID:8339fee6-b3f2-11e2-8561-10bf48d758ce
+Comp4Name:Luxa, Claus-Peter,Röttger, Rol
+Comp4NameShort:GER7013
+Comp4Color:800000
+Comp4Nationality:GER
+Comp4Description:0
+Comp4Handicap:1.0000000000
+Comp4HandicapDistance:0.00000
+Comp4StartTime:2013-05-04 14:00:00
+Comp4ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp4RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp5UUID:83550484-b3f2-11e2-8561-10bf48d758ce
+Comp5Name:Schulte, Gert,Schulte, Gerrit
+Comp5NameShort:GER7417
+Comp5Color:FFFF00
+Comp5Nationality:GER
+Comp5Description:0
+Comp5Handicap:1.0000000000
+Comp5HandicapDistance:0.00000
+Comp5StartTime:2013-05-04 14:00:00
+Comp5ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp5RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp6UUID:837c17cc-b3f2-11e2-8561-10bf48d758ce
+Comp6Name:Seefelder, Jürgen,Seefelder, N
+Comp6NameShort:GER7616
+Comp6Color:00FFFF
+Comp6Nationality:GER
+Comp6Description:0
+Comp6Handicap:1.0000000000
+Comp6HandicapDistance:0.00000
+Comp6StartTime:2013-05-04 14:00:00
+Comp6ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp6RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp7UUID:83a1f6fe-b3f2-11e2-8561-10bf48d758ce
+Comp7Name:Hoffmann, Peter,Theis, Nina
+Comp7NameShort:GER7693
+Comp7Color:0000FF
+Comp7Nationality:GER
+Comp7Description:0
+Comp7Handicap:1.0000000000
+Comp7HandicapDistance:0.00000
+Comp7StartTime:2013-05-04 14:00:00
+Comp7ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp7RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp8UUID:83cc72c6-b3f2-11e2-8561-10bf48d758ce
+Comp8Name:Kohler, Thomas,Roszinski, Dr.
+Comp8NameShort:GER7727
+Comp8Color:800080
+Comp8Nationality:GER
+Comp8Description:0
+Comp8Handicap:1.0000000000
+Comp8HandicapDistance:0.00000
+Comp8StartTime:2013-05-04 14:00:00
+Comp8ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp8RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp9UUID:83fa5e70-b3f2-11e2-8561-10bf48d758ce
+Comp9Name:Spehr, Helge,Spehr, Jesper
+Comp9NameShort:GER7747
+Comp9Color:008080
+Comp9Nationality:GER
+Comp9Description:0
+Comp9Handicap:1.0000000000
+Comp9HandicapDistance:0.00000
+Comp9StartTime:2013-05-04 14:00:00
+Comp9ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp9RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp10UUID:843187ec-b3f2-11e2-8561-10bf48d758ce
+Comp10Name:Massler, Julian,Seeberger, Uli
+Comp10NameShort:GER7860
+Comp10Color:808000
+Comp10Nationality:GER
+Comp10Description:0
+Comp10Handicap:1.0000000000
+Comp10HandicapDistance:0.00000
+Comp10StartTime:2013-05-04 14:00:00
+Comp10ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp10RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp11UUID:84737a80-b3f2-11e2-8561-10bf48d758ce
+Comp11Name:Behn, Philip,Kaerger, Andreas
+Comp11NameShort:GER7866
+Comp11Color:FF0000
+Comp11Nationality:GER
+Comp11Description:0
+Comp11Handicap:1.0000000000
+Comp11HandicapDistance:0.00000
+Comp11StartTime:2013-05-04 14:00:00
+Comp11ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp11RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp12UUID:84b5e8d4-b3f2-11e2-8561-10bf48d758ce
+Comp12Name:Tusch, Frank,Winkelmann, Sven
+Comp12NameShort:GER7897
+Comp12Color:FFFFFF
+Comp12Nationality:GER
+Comp12Description:0
+Comp12Handicap:1.0000000000
+Comp12HandicapDistance:0.00000
+Comp12StartTime:2013-05-04 14:00:00
+Comp12ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp12RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp13UUID:84f68cf4-b3f2-11e2-8561-10bf48d758ce
+Comp13Name:Bode, Klaus,Bode, Alexander
+Comp13NameShort:GER7898
+Comp13Color:FF00FF
+Comp13Nationality:GER
+Comp13Description:0
+Comp13Handicap:1.0000000000
+Comp13HandicapDistance:0.00000
+Comp13StartTime:2013-05-04 14:00:00
+Comp13ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp13RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp14UUID:853ca13a-b3f2-11e2-8561-10bf48d758ce
+Comp14Name:Vater, Ulrich,Nolte, Andreas
+Comp14NameShort:GER7971
+Comp14Color:008000
+Comp14Nationality:GER
+Comp14Description:0
+Comp14Handicap:1.0000000000
+Comp14HandicapDistance:0.00000
+Comp14StartTime:2013-05-04 14:00:00
+Comp14ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp14RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp15UUID:858f812a-b3f2-11e2-8561-10bf48d758ce
+Comp15Name:Janson, Jürgen,Schulte, Axel
+Comp15NameShort:GER7981
+Comp15Color:000080
+Comp15Nationality:GER
+Comp15Description:0
+Comp15Handicap:1.0000000000
+Comp15HandicapDistance:0.00000
+Comp15StartTime:2013-05-04 14:00:00
+Comp15ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp15RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp16UUID:85dac766-b3f2-11e2-8561-10bf48d758ce
+Comp16Name:Diercks, Jochen,Braasch, Herbe
+Comp16NameShort:GER8055
+Comp16Color:000000
+Comp16Nationality:GER
+Comp16Description:0
+Comp16Handicap:1.0000000000
+Comp16HandicapDistance:0.00000
+Comp16StartTime:2013-05-04 14:00:00
+Comp16ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp16RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp17UUID:86286462-b3f2-11e2-8561-10bf48d758ce
+Comp17Name:Hagen, Alexander,Hasche, Marko
+Comp17NameShort:GER8093
+Comp17Color:00FF00
+Comp17Nationality:GER
+Comp17Description:0
+Comp17Handicap:1.0000000000
+Comp17HandicapDistance:0.00000
+Comp17StartTime:2013-05-04 14:00:00
+Comp17ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp17RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp18UUID:867dd88e-b3f2-11e2-8561-10bf48d758ce
+Comp18Name:Kappes, Klaus,Rutz, Steffen
+Comp18NameShort:GER8122
+Comp18Color:800000
+Comp18Nationality:GER
+Comp18Description:0
+Comp18Handicap:1.0000000000
+Comp18HandicapDistance:0.00000
+Comp18StartTime:2013-05-04 14:00:00
+Comp18ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp18RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp19UUID:86c9c3fc-b3f2-11e2-8561-10bf48d758ce
+Comp19Name:Hannemann, Uwe,Dahms, Anette
+Comp19NameShort:GER8124
+Comp19Color:FFFF00
+Comp19Nationality:GER
+Comp19Description:0
+Comp19Handicap:1.0000000000
+Comp19HandicapDistance:0.00000
+Comp19StartTime:2013-05-04 14:00:00
+Comp19ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp19RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp20UUID:871283e4-b3f2-11e2-8561-10bf48d758ce
+Comp20Name:Stoll, Bernd,Stoll, Barbara
+Comp20NameShort:GER8147
+Comp20Color:00FFFF
+Comp20Nationality:GER
+Comp20Description:0
+Comp20Handicap:1.0000000000
+Comp20HandicapDistance:0.00000
+Comp20StartTime:2013-05-04 14:00:00
+Comp20ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp20RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp21UUID:875c9aec-b3f2-11e2-8561-10bf48d758ce
+Comp21Name:Meyer, Klaus,Müller, Jörg
+Comp21NameShort:GER8179
+Comp21Color:0000FF
+Comp21Nationality:GER
+Comp21Description:0
+Comp21Handicap:1.0000000000
+Comp21HandicapDistance:0.00000
+Comp21StartTime:2013-05-04 14:00:00
+Comp21ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp21RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp22UUID:87a8f43c-b3f2-11e2-8561-10bf48d758ce
+Comp22Name:Antrecht, Alexander,Schwill, F
+Comp22NameShort:GER8190
+Comp22Color:800080
+Comp22Nationality:GER
+Comp22Description:0
+Comp22Handicap:1.0000000000
+Comp22HandicapDistance:0.00000
+Comp22StartTime:2013-05-04 14:00:00
+Comp22ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp22RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp23UUID:87f4d898-b3f2-11e2-8561-10bf48d758ce
+Comp23Name:Pieper, Josef,Vockel, Ralf
+Comp23NameShort:GER8233
+Comp23Color:008080
+Comp23Nationality:GER
+Comp23Description:0
+Comp23Handicap:1.0000000000
+Comp23HandicapDistance:0.00000
+Comp23StartTime:2013-05-04 14:00:00
+Comp23ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp23RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp24UUID:883da6ea-b3f2-11e2-8561-10bf48d758ce
+Comp24Name:König, Kilian,Schäfer, Kai
+Comp24NameShort:GER8301
+Comp24Color:808000
+Comp24Nationality:GER
+Comp24Description:0
+Comp24Handicap:1.0000000000
+Comp24HandicapDistance:0.00000
+Comp24StartTime:2013-05-04 14:00:00
+Comp24ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp24RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp25UUID:88920d16-b3f2-11e2-8561-10bf48d758ce
+Comp25Name:Glunde, Arnd,Beltz, Marcel
+Comp25NameShort:GER8321
+Comp25Color:FF0000
+Comp25Nationality:GER
+Comp25Description:0
+Comp25Handicap:1.0000000000
+Comp25HandicapDistance:0.00000
+Comp25StartTime:2013-05-04 14:00:00
+Comp25ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp25RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp26UUID:88e60efc-b3f2-11e2-8561-10bf48d758ce
+Comp26Name:Griese, Achim,Marcour, Michael
+Comp26NameShort:GER8340
+Comp26Color:FFFFFF
+Comp26Nationality:GER
+Comp26Description:0
+Comp26Handicap:1.0000000000
+Comp26HandicapDistance:0.00000
+Comp26StartTime:2013-05-04 14:00:00
+Comp26ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp26RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp27UUID:8939a094-b3f2-11e2-8561-10bf48d758ce
+Comp27Name:Hellmich, Joachim,Lacher, Stef
+Comp27NameShort:GER8412
+Comp27Color:FF00FF
+Comp27Nationality:GER
+Comp27Description:0
+Comp27Handicap:1.0000000000
+Comp27HandicapDistance:0.00000
+Comp27StartTime:2013-05-04 14:00:00
+Comp27ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp27RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp28UUID:8999a2dc-b3f2-11e2-8561-10bf48d758ce
+Comp28Name:Babendererde, Johannes,Voigt,
+Comp28NameShort:GER8433
+Comp28Color:008000
+Comp28Nationality:GER
+Comp28Description:0
+Comp28Handicap:1.0000000000
+Comp28HandicapDistance:0.00000
+Comp28StartTime:2013-05-04 14:00:00
+Comp28ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp28RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp29UUID:89e9dd1a-b3f2-11e2-8561-10bf48d758ce
+Comp29Name:Polgar, Johannes,Koy, Markus
+Comp29NameShort:GER8442
+Comp29Color:000080
+Comp29Nationality:GER
+Comp29Description:0
+Comp29Handicap:1.0000000000
+Comp29HandicapDistance:0.00000
+Comp29StartTime:2013-05-04 14:00:00
+Comp29ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp29RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp30UUID:8a3c52b6-b3f2-11e2-8561-10bf48d758ce
+Comp30Name:Merkelbach, Hubert,Kleen, Frit
+Comp30NameShort:GER8450
+Comp30Color:000000
+Comp30Nationality:GER
+Comp30Description:0
+Comp30Handicap:1.0000000000
+Comp30HandicapDistance:0.00000
+Comp30StartTime:2013-05-04 14:00:00
+Comp30ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp30RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp31UUID:8aaca2a0-b3f2-11e2-8561-10bf48d758ce
+Comp31Name:Schmidt, Reinhard,Hentschel, N
+Comp31NameShort:GER8478
+Comp31Color:00FF00
+Comp31Nationality:GER
+Comp31Description:0
+Comp31Handicap:1.0000000000
+Comp31HandicapDistance:0.00000
+Comp31StartTime:2013-05-04 14:00:00
+Comp31ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp31RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp32UUID:8b05a148-b3f2-11e2-8561-10bf48d758ce
+Comp32Name:Müllejans, Christian,Morf, Kar
+Comp32NameShort:ITA8400
+Comp32Color:800000
+Comp32Nationality:ITA
+Comp32Description:0
+Comp32Handicap:1.0000000000
+Comp32HandicapDistance:0.00000
+Comp32StartTime:2013-05-04 14:00:00
+Comp32ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp32RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp33UUID:8b56f32c-b3f2-11e2-8561-10bf48d758ce
+Comp33Name:Tennigkeit, Alexander,Schöller
+Comp33NameShort:SUI7948
+Comp33Color:FFFF00
+Comp33Nationality:SUI
+Comp33Description:0
+Comp33Handicap:1.0000000000
+Comp33HandicapDistance:0.00000
+Comp33StartTime:2013-05-04 14:00:00
+Comp33ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp33RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp34UUID:8ba307da-b3f2-11e2-8561-10bf48d758ce
+Comp34Name:Bondar, Pavlo,Malzev, Konstant
+Comp34NameShort:UKR8119
+Comp34Color:00FFFF
+Comp34Nationality:UKR
+Comp34Description:0
+Comp34Handicap:1.0000000000
+Comp34HandicapDistance:0.00000
+Comp34StartTime:2013-05-04 14:00:00
+Comp34ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp34RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp35UUID:8c003dba-b3f2-11e2-8561-10bf48d758ce
+Comp35Name:Jensen, Johnny
+Comp35NameShort:DEN8124
+Comp35Color:0000FF
+Comp35Nationality:DEN
+Comp35Description:0
+Comp35Handicap:1.0000000000
+Comp35HandicapDistance:0.00000
+Comp35StartTime:2013-05-04 14:00:00
+Comp35ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp35RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp36UUID:8c57247c-b3f2-11e2-8561-10bf48d758ce
+Comp36Name:Mellis, Jörg,Flugel, Falko
+Comp36NameShort:GER816
+Comp36Color:800080
+Comp36Nationality:GER
+Comp36Description:0
+Comp36Handicap:1.0000000000
+Comp36HandicapDistance:0.00000
+Comp36StartTime:2013-05-04 14:00:00
+Comp36ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp36RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp37UUID:8cadf6d0-b3f2-11e2-8561-10bf48d758ce
+Comp37Name:Hülsmann, Thorsten
+Comp37NameShort:GER7897
+Comp37Color:008080
+Comp37Nationality:GER
+Comp37Description:0
+Comp37Handicap:1.0000000000
+Comp37HandicapDistance:0.00000
+Comp37StartTime:2013-05-04 14:00:00
+Comp37ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp37RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp38UUID:8cfb82c4-b3f2-11e2-8561-10bf48d758ce
+Comp38Name:Kleine, Frieder
+Comp38NameShort:GER8301
+Comp38Color:808000
+Comp38Nationality:GER
+Comp38Description:0
+Comp38Handicap:1.0000000000
+Comp38HandicapDistance:0.00000
+Comp38StartTime:2013-05-04 14:00:00
+Comp38ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp38RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+Comp39UUID:8d50d12a-b3f2-11e2-8561-10bf48d758ce
+Comp39Name:von Linde, Florian,Steffens, T
+Comp39NameShort:GER8419
+Comp39Color:FF0000
+Comp39Nationality:GER
+Comp39Description:0
+Comp39Handicap:1.0000000000
+Comp39HandicapDistance:0.00000
+Comp39StartTime:2013-05-04 14:00:00
+Comp39ClassUUID:dbe67500-b308-11e2-8561-10bf48d758ce
+Comp39RouteUUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+
+ControlPoint1UUID:166ab660-b3f3-11e2-8561-10bf48d758ce
+ControlPoint1Name:Start/Ziel
+ControlPoint1HasTwoPoints:1
+ControlPoint1ShortName:St
+ControlPoint1Mark1Lon:8.076375
+ControlPoint1Mark1Lat:51.481972
+ControlPoint1Mark2Lon:8.074255
+ControlPoint1Mark2Lat:51.480293
+
+ControlPoint2UUID:2b5bde8c-b3f3-11e2-8561-10bf48d758ce
+ControlPoint2Name:Luvtonne
+ControlPoint2HasTwoPoints:0
+ControlPoint2ShortName:Lu
+ControlPoint2Mark1Lon:8.064938
+ControlPoint2Mark1Lat:51.485242
+
+ControlPoint3UUID:3f999718-b3f3-11e2-8561-10bf48d758ce
+ControlPoint3Name:Offset Luvtonne
+ControlPoint3HasTwoPoints:0
+ControlPoint3ShortName:Of
+ControlPoint3Mark1Lon:8.064113
+ControlPoint3Mark1Lat:51.484798
+
+ControlPoint4UUID:b160887a-b3f3-11e2-8561-10bf48d758ce
+ControlPoint4Name:Leegate
+ControlPoint4HasTwoPoints:1
+ControlPoint4ShortName:Le
+ControlPoint4Mark1Lon:8.076637
+ControlPoint4Mark1Lat:51.480125
+ControlPoint4Mark2Lon:8.077277
+ControlPoint4Mark2Lat:51.480682
+
+
+SegmentFile:segments.php
+Route1UUID:e2f725ce-b3f3-11e2-8561-10bf48d758ce
+Route1Description:Windward-Leeward - 3 Laps
+Route1Length:0
+Route1ControlPoint1UUID:166ab660-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint2UUID:2b5bde8c-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint3UUID:3f999718-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint4UUID:b160887a-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint5UUID:2b5bde8c-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint6UUID:3f999718-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint7UUID:b160887a-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint8UUID:2b5bde8c-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint9UUID:3f999718-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint10UUID:b160887a-b3f3-11e2-8561-10bf48d758ce
+Route1ControlPoint11UUID:166ab660-b3f3-11e2-8561-10bf48d758ce
+
+//-------- AUTO GENERATED PARAMETERS END ------------------
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java
index f40799cb99d..b609ccd57a4 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java
@@ -303,7 +303,7 @@ public class CourseTest {
new RaceDefinitionImpl("Test Race", course, new BoatClassImpl("49er", /* upwind start */true), hasso),
Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,/* delayToLiveInMillis */3000,
/* millisecondsOverWhichToAverageWind */30000,
- /* millisecondsOverWhichToAverageSpeed */8000);
+ /* millisecondsOverWhichToAverageSpeed */8000, /*useMarkPassingCalculator*/ false);
assertLegStructure(course, trackedRace);
course.removeWaypoint(0);
assertLegStructure(course, trackedRace);
@@ -334,7 +334,7 @@ public class CourseTest {
hasso), Collections. emptyList(),
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 3000,
/* millisecondsOverWhichToAverageWind */ 30000,
- /* millisecondsOverWhichToAverageSpeed */ 8000);
+ /* millisecondsOverWhichToAverageSpeed */ 8000, /*useMarkPassingCalculator*/ false);
assertLegStructure(course, trackedRace);
final WaypointImpl wp1_5 = new WaypointImpl(new MarkImpl("Test Mark 1.5"));
assertWaypointIndexes(course);
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java
index 74de470e028..4434046c244 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java
@@ -80,7 +80,7 @@ public class CourseUpdateDuringNonAtomicSerializationTest implements Serializabl
trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections. emptySet(),
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,
/* delayToLiveInMillis */10000, /* millisecondsOverWhichToAverageWind */30000, /* millisecondsOverWhichToAverageSpeed */
- 7000) {
+ 7000, /*useMarkPassingCalculator*/ false) {
private static final long serialVersionUID = 9114777576548711763L;
@Override
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateTest.java
index e2932e41b28..b7f07a53906 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateTest.java
@@ -88,7 +88,7 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
}
},
/* delayToLiveInMillis */0l, /* millisecondsOverWhichToAverageWind */30000, /* simulator */null, /* courseDesignUpdateURI */
- null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber()) {
+ null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/false) {
@Override
protected void handleEvent(Triple event) {
super.handleEvent(event);
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java
index b05c4afee5e..9e2febd92db 100644
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java
@@ -137,7 +137,7 @@ public class LeaderboardCourseChangeTest {
TrackedRegatta mockedTrackedRegatta = createMockedTrackedRegatta(regatta);
RaceDefinition mockedRace = createMockedRace(course, boatClass);
TrackedRace spyedTrackedRace = spy(new DynamicTrackedRaceImpl(mockedTrackedRegatta, mockedRace,
- new HashSet(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000));
+ new HashSet(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000, /*useMarkPassingCalculator*/ false));
return spyedTrackedRace;
}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java
index 5c9b12bbc5a..f25fe97ef2c 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java
@@ -57,7 +57,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 */
+ /* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
@@ -68,7 +68,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 */
+ /* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
@@ -79,7 +79,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 */
+ /* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
@@ -90,7 +90,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 */
+ /* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java
index 5918eda0c56..37a59dba5e8 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java
@@ -114,7 +114,7 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest {
for (Receiver r : domainFactory.getUpdateReceivers(trackedRegatta, getTracTracRace(), EmptyWindStore.INSTANCE, /* delayToLiveInMillis */0l, /* simulator */null, createRaceDefinitionSet(),
/* trackedRegattaRegistry */null,
/* courseDesignUpdateURI */null, /* tracTracUsername */null, null, /* tracTracPassword */
- getEventSubscriber(), getRaceSubscriber(), receiverTypes)) {
+ getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, receiverTypes)) {
receivers.add(r);
}
getRaceSubscriber().subscribeConnectionStatus(new IConnectionStatusListener() {
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java
index d735ef24847..ab900d9e77c 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java
@@ -1,378 +1,378 @@
-package com.sap.sailing.domain.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.GregorianCalendar;
-import java.util.Iterator;
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.base.ControlPoint;
-import com.sap.sailing.domain.base.Course;
-import com.sap.sailing.domain.base.DomainFactory;
-import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.base.RaceDefinition;
-import com.sap.sailing.domain.base.Regatta;
-import com.sap.sailing.domain.base.Sideline;
-import com.sap.sailing.domain.base.Waypoint;
-import com.sap.sailing.domain.base.impl.BoatClassImpl;
-import com.sap.sailing.domain.base.impl.CompetitorImpl;
-import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl;
-import com.sap.sailing.domain.base.impl.CourseImpl;
-import com.sap.sailing.domain.base.impl.MarkImpl;
-import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
-import com.sap.sailing.domain.base.impl.RegattaImpl;
-import com.sap.sailing.domain.base.impl.WaypointImpl;
-import com.sap.sailing.domain.common.Bearing;
-import com.sap.sailing.domain.common.Distance;
-import com.sap.sailing.domain.common.LegType;
-import com.sap.sailing.domain.common.NoWindException;
-import com.sap.sailing.domain.common.Position;
-import com.sap.sailing.domain.common.ScoringSchemeType;
-import com.sap.sailing.domain.common.WindSourceType;
-import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
-import com.sap.sailing.domain.common.impl.DegreePosition;
-import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
-import com.sap.sailing.domain.common.impl.WindSourceImpl;
-import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
-import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
-import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
-import com.sap.sailing.domain.tracking.MarkPassing;
-import com.sap.sailing.domain.tracking.TrackedLeg;
-import com.sap.sailing.domain.tracking.TrackedRegatta;
-import com.sap.sailing.domain.tracking.WindPositionMode;
-import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
-import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
-import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
-import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
-import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
-import com.sap.sailing.domain.tracking.impl.WindImpl;
-import com.sap.sse.common.TimePoint;
-import com.sap.sse.common.impl.MillisecondsTimePoint;
-
-public class ReachingLegTest extends TrackBasedTest {
- private List competitors;
- private CompetitorImpl plattner;
- private CompetitorImpl hunger;
- private MillisecondsTimePoint start;
- private Competitor schomaeker;
-
- /**
- * Creates the race and two competitors ({@link #plattner} and {@link #hunger}) and sets the start line passing for both of them
- * to {@link #start}.
- */
- @Before
- public void setUp() {
- competitors = new ArrayList();
- hunger = createCompetitor("Wolfgang Hunger");
- competitors.add(hunger);
- plattner = createCompetitor("Dr. Hasso Plattner");
- competitors.add(plattner);
- schomaeker = createCompetitor("Meike Schom�ker");
- competitors.add(schomaeker);
- start = new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime());
- setTrackedRace(createTrackedRace("Kieler Woche", "505 Race 2", "505", competitors, start));
- List hungersMarkPassings = createMarkPassings(hunger, start);
- getTrackedRace().updateMarkPassings(hunger, hungersMarkPassings);
- List plattnersMarkPassings = createMarkPassings(plattner, start);
- getTrackedRace().updateMarkPassings(plattner, plattnersMarkPassings);
- }
-
- protected DynamicTrackedRaceImpl createTrackedRace(String regattaName, String raceName, String boatClassName,
- Iterable competitors, TimePoint timePointForFixes) {
- BoatClassImpl boatClass = new BoatClassImpl(boatClassName, /* typicallyStartsUpwind */ true);
- Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
- RegattaImpl.getDefaultName(regattaName, boatClass.getName()), boatClass, /*startDate*/ null, /*endDate*/ null, /* trackedRegattaRegistry */ null,
- DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), "123", null);
- TrackedRegatta trackedRegatta = new DynamicTrackedRegattaImpl(regatta);
- List waypoints = new ArrayList();
- // create a two-lap upwind/downwind course:
- MarkImpl left = new MarkImpl("Left lee gate buoy");
- MarkImpl right = new MarkImpl("Right lee gate buoy");
- ControlPoint leeGate = new ControlPointWithTwoMarksImpl(left, right, "Lee Gate");
- Mark windwardMark = new MarkImpl("Windward mark");
- Mark offsetMark = new MarkImpl("Offset mark");
- waypoints.add(new WaypointImpl(leeGate));
- waypoints.add(new WaypointImpl(windwardMark));
- waypoints.add(new WaypointImpl(offsetMark));
- waypoints.add(new WaypointImpl(leeGate));
- Course course = new CourseImpl(raceName, waypoints);
- RaceDefinition race = new RaceDefinitionImpl(raceName, course, boatClass, competitors);
- DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections. emptyList(), EmptyWindStore.INSTANCE,
- EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0,
- /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
- /* delay for wind estimation cache invalidation */ 0);
- // in this simplified artificial course, the top mark is exactly north of the right leeward gate, the offset
- // mark is slightly west of the top mark; wind from the north makes the leg from top to offset a reaching leg
- Position leftPosition = new DegreePosition(0, -0.00001);
- Position rightPosition = new DegreePosition(0, 0.00001);
- Position topPosition = new DegreePosition(1, 0);
- Position offsetPosition = new DegreePosition(1, -0.0001);
- TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix time
- trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(leftPosition, new MillisecondsTimePoint(0)));
- trackedRace.getOrCreateTrack(right).addGPSFix(new GPSFixImpl(rightPosition, new MillisecondsTimePoint(0)));
- trackedRace.getOrCreateTrack(windwardMark).addGPSFix(new GPSFixImpl(topPosition, new MillisecondsTimePoint(0)));
- trackedRace.getOrCreateTrack(offsetMark).addGPSFix(new GPSFixImpl(offsetPosition, new MillisecondsTimePoint(0)));
- trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(leftPosition, afterTheRace));
- trackedRace.getOrCreateTrack(right).addGPSFix(new GPSFixImpl(rightPosition, afterTheRace));
- trackedRace.getOrCreateTrack(windwardMark).addGPSFix(new GPSFixImpl(topPosition, afterTheRace));
- trackedRace.getOrCreateTrack(offsetMark).addGPSFix(new GPSFixImpl(offsetPosition, afterTheRace));
- trackedRace.recordWind(new WindImpl(topPosition, timePointForFixes, new KnotSpeedWithBearingImpl(
- /* speedInKnots */14.7, new DegreeBearingImpl(180))), new WindSourceImpl(WindSourceType.WEB));
- return trackedRace;
- }
-
- @Test
- public void testSecondLegIsReaching() throws NoWindException {
- Iterator legIter = getTrackedRace().getTrackedLegs().iterator();
- assertEquals(LegType.UPWIND, legIter.next().getLegType(start));
- assertEquals(LegType.REACHING, legIter.next().getLegType(start));
- assertEquals(LegType.DOWNWIND, legIter.next().getLegType(start));
- }
-
- @Test
- public void testHungerInReachingPlattnerInUpwind() {
- // give Hunger a mark passing for the windward mark, putting him into the reaching leg
- final MillisecondsTimePoint whenHungerFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
- getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenHungerFinishedUpwind));
- assertEquals(
- getTrackedRace().getRace().getCourse().getLegs().get(1),
- getTrackedRace().getTrackedLeg(hunger,
- new MillisecondsTimePoint(whenHungerFinishedUpwind.asMillis() + 10000)).getLeg());
- assertEquals(
- getTrackedRace().getRace().getCourse().getLegs().get(0),
- getTrackedRace().getTrackedLeg(plattner,
- new MillisecondsTimePoint(whenHungerFinishedUpwind.asMillis() + 10000)).getLeg());
- }
-
- @Test
- public void testHungerAndPlattnerInReaching() {
- // give Hunger and Plattner a mark passing for the windward mark, putting both of them into the reaching leg
- final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
- getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
- getTrackedRace().updateMarkPassings(plattner, createMarkPassings(plattner, start, whenBothFinishedUpwind));
- assertEquals(
- getTrackedRace().getRace().getCourse().getLegs().get(1),
- getTrackedRace().getTrackedLeg(hunger,
- new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis() + 10000)).getLeg());
- assertEquals(
- getTrackedRace().getRace().getCourse().getLegs().get(1),
- getTrackedRace().getTrackedLeg(plattner,
- new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis() + 10000)).getLeg());
- }
-
- @Test
- public void testDistanceWithHungerAndPlattnerInReaching() throws NoWindException {
- // give Hunger and Plattner a mark passing for the windward mark, putting both of them into the reaching leg
- final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
- final MillisecondsTimePoint timePointInReaching = new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis()+10000);
- Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointInReaching);
- Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointInReaching);
- Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
- assertTrue(distanceOfReachingLeg.getMeters() > 0);
- getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
- getTrackedRace().updateMarkPassings(plattner, createMarkPassings(plattner, start, whenBothFinishedUpwind));
- getTrackedRace().recordFix(
- hunger,
- new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- getTrackedRace().recordFix(
- plattner,
- new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- assertEquals(0.,
- getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
- .getDistance(offsetMarkPos).getMeters(), 0.00001);
- assertEquals(0.,
- getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
- .getDistance(windwardMarkPos).getMeters(), 0.00001);
- Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE);
- Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE);
- assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001);
- assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001);
- }
-
- @Test
- public void testDistanceWithHungerInReachingAndPlattnerInUpwind() throws NoWindException {
- // give Hunger and Plattner a mark passing for the windward mark, putting both of them into the reaching leg
- final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
- final MillisecondsTimePoint timePointInReaching = new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis()+10000);
- Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointInReaching);
- Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointInReaching);
- Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
- assertTrue(distanceOfReachingLeg.getMeters() > 0);
- getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
- getTrackedRace().recordFix(
- hunger,
- new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- getTrackedRace().recordFix(
- plattner,
- new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- assertEquals(0.,
- getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
- .getDistance(offsetMarkPos).getMeters(), 0.00001);
- assertEquals(0.,
- getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
- .getDistance(windwardMarkPos).getMeters(), 0.00001);
- Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE);
- Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE);
- assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001);
- assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001);
- }
-
- @Test
- public void testDistanceWithHungerInDownwindAndPlattnerInReaching() throws NoWindException {
- // give Hunger and Plattner a mark passing for the windward mark, putting both of them into the reaching leg
- final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
- final MillisecondsTimePoint timePointInReaching = new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis()+10000);
- Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointInReaching);
- Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointInReaching);
- Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
- assertTrue(distanceOfReachingLeg.getMeters() > 0);
- getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
- getTrackedRace().recordFix(
- hunger,
- new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- getTrackedRace().recordFix(
- plattner,
- new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- assertEquals(0.,
- getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
- .getDistance(offsetMarkPos).getMeters(), 0.00001);
- assertEquals(0.,
- getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
- .getDistance(windwardMarkPos).getMeters(), 0.00001);
- Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE);
- Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE);
- assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001);
- assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001);
- }
-
- @Test
- public void testDistanceWithHungerInDownwindAndPlattnerInUpwindWithReachingInBetween() throws NoWindException {
- // give Hunger a mark passing for the windward mark, consume Plattner is stuck at the starting line, putting
- // the empty reaching leg between the two; see if the reaching leg's non-windward distance is counted, and if
- // Plattner's distance is accumulated correctly
- final MillisecondsTimePoint whenHungerFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
- final MillisecondsTimePoint whenHungerFinishedReaching = new MillisecondsTimePoint(whenHungerFinishedUpwind.asMillis()+10000);
- final MillisecondsTimePoint timePointToConsider = new MillisecondsTimePoint(whenHungerFinishedReaching.asMillis()+10000);
- Position leewardPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getFrom(), timePointToConsider);
- Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointToConsider);
- Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointToConsider);
- Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
- Distance windwardDistanceOfUpwindLeg = leewardPos.getDistance(windwardMarkPos);
- assertTrue(distanceOfReachingLeg.getMeters() > 0);
- getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenHungerFinishedUpwind, whenHungerFinishedReaching));
- getTrackedRace().recordFix(
- hunger,
- new GPSFixMovingImpl(offsetMarkPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- getTrackedRace().recordFix(
- plattner,
- new GPSFixMovingImpl(leewardPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(0))));
- assertEquals(0.,
- getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
- .getDistance(offsetMarkPos).getMeters(), 0.00001);
- assertEquals(0.,
- getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
- .getDistance(leewardPos).getMeters(), 0.00001);
- Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointToConsider, WindPositionMode.LEG_MIDDLE);
- Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE);
- assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001);
- assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001);
- }
-
- @Test
- public void testWindwardDistanceToOverallLeaderWithHungerFirstAtWindwardMarkButSecondAfterReachingLeg() throws NoWindException {
- // Hunger finished first upwind before Schomaeker; Schomaeker finished reaching before Hunger, leading now;
- // Schoemaeker made it half through the downwind while Hunger got stuck at the offset mark
- final MillisecondsTimePoint whenHungerFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
- final MillisecondsTimePoint whenSchomaekerFinishedUpwind = new MillisecondsTimePoint(whenHungerFinishedUpwind.asMillis()+1000);
- final MillisecondsTimePoint whenSchomaekerFinishedReaching = new MillisecondsTimePoint(whenSchomaekerFinishedUpwind.asMillis()+10000);
- final MillisecondsTimePoint whenHungerFinishedReaching = new MillisecondsTimePoint(whenSchomaekerFinishedReaching.asMillis()+1000);
- final MillisecondsTimePoint timePointToConsider = new MillisecondsTimePoint(whenHungerFinishedReaching.asMillis()+10000);
-
- Position leewardPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getFrom(), timePointToConsider);
- Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointToConsider);
- Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointToConsider);
- Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
- Distance windwardDistanceOfUpwindLeg = leewardPos.getDistance(windwardMarkPos);
- assertTrue(distanceOfReachingLeg.getMeters() > 0);
- getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenHungerFinishedUpwind, whenHungerFinishedReaching));
- getTrackedRace().updateMarkPassings(schomaeker, createMarkPassings(schomaeker, start, whenSchomaekerFinishedUpwind, whenSchomaekerFinishedReaching));
- getTrackedRace().recordFix(
- hunger,
- new GPSFixMovingImpl(offsetMarkPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- getTrackedRace().recordFix(
- schomaeker,
- new GPSFixMovingImpl(offsetMarkPos.translateGreatCircle(
- offsetMarkPos.getBearingGreatCircle(leewardPos), offsetMarkPos.getDistance(leewardPos)
- .scale(0.5)), timePointToConsider, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(180))));
- getTrackedRace().recordFix(
- plattner,
- new GPSFixMovingImpl(leewardPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(0))));
- assertEquals(0.,
- getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
- .getDistance(offsetMarkPos).getMeters(), 0.00001);
- assertEquals(0.,
- getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
- .getDistance(leewardPos).getMeters(), 0.00001);
- Distance schomaekersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(schomaeker, timePointToConsider, WindPositionMode.LEG_MIDDLE);
- Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE);
- assertEquals(0., schomaekersDistanceToLeader.getMeters(), 0.00001);
- // distance to leading Schomaeker expected to be the entire upwind distance plus the offset distance plus half the downwind
- assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters()*1.5, plattnersDistanceToLeader.getMeters(), 0.001);
- }
-
- @Test
- public void testWindwardDistanceOnReachingLegProjectsOntoLegDirection() throws NoWindException {
- final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
- final MillisecondsTimePoint timePointToConsider = new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis()+10000);
-
- Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointToConsider);
- Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointToConsider);
- Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
- assertTrue(distanceOfReachingLeg.getMeters() > 0);
- getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
- getTrackedRace().updateMarkPassings(plattner, createMarkPassings(plattner, start, whenBothFinishedUpwind));
- Bearing reachingLegBearing = windwardMarkPos.getBearingGreatCircle(offsetMarkPos);
- // Hunger turns left after the windward mark
- getTrackedRace().recordFix(
- hunger,
- new GPSFixMovingImpl(windwardMarkPos.translateGreatCircle(new DegreeBearingImpl(reachingLegBearing.getDegrees()-45),
- distanceOfReachingLeg.scale(1./Math.sqrt(2.))), timePointToConsider, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- // Plattner turns right after the windward mark; both travel the same distance projected along the leg
- getTrackedRace().recordFix(
- plattner,
- new GPSFixMovingImpl(windwardMarkPos.translateGreatCircle(new DegreeBearingImpl(reachingLegBearing.getDegrees()+45),
- distanceOfReachingLeg.scale(1./Math.sqrt(2.))), timePointToConsider, new KnotSpeedWithBearingImpl(12,
- new DegreeBearingImpl(270))));
- // with 90deg separating them, traveling 1/sqrt(2) the distance of the leg should put them the distance of the leg apart geometrically
- assertEquals(
- distanceOfReachingLeg.getMeters(),
- getTrackedRace()
- .getTrack(hunger)
- .getEstimatedPosition(timePointToConsider, /* extrapolate */false)
- .getDistance(
- getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */
- false)).getMeters(), 0.00001);
- // however, projected onto the leg their distance should be 0
- Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE);
- assertEquals(0., plattnersDistanceToLeader.getMeters(), 0.00001);
- }
-}
+package com.sap.sailing.domain.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.sap.sailing.domain.base.Competitor;
+import com.sap.sailing.domain.base.ControlPoint;
+import com.sap.sailing.domain.base.Course;
+import com.sap.sailing.domain.base.DomainFactory;
+import com.sap.sailing.domain.base.Mark;
+import com.sap.sailing.domain.base.RaceDefinition;
+import com.sap.sailing.domain.base.Regatta;
+import com.sap.sailing.domain.base.Sideline;
+import com.sap.sailing.domain.base.Waypoint;
+import com.sap.sailing.domain.base.impl.BoatClassImpl;
+import com.sap.sailing.domain.base.impl.CompetitorImpl;
+import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl;
+import com.sap.sailing.domain.base.impl.CourseImpl;
+import com.sap.sailing.domain.base.impl.MarkImpl;
+import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
+import com.sap.sailing.domain.base.impl.RegattaImpl;
+import com.sap.sailing.domain.base.impl.WaypointImpl;
+import com.sap.sailing.domain.common.Bearing;
+import com.sap.sailing.domain.common.Distance;
+import com.sap.sailing.domain.common.LegType;
+import com.sap.sailing.domain.common.NoWindException;
+import com.sap.sailing.domain.common.Position;
+import com.sap.sailing.domain.common.ScoringSchemeType;
+import com.sap.sailing.domain.common.WindSourceType;
+import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
+import com.sap.sailing.domain.common.impl.DegreePosition;
+import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
+import com.sap.sailing.domain.common.impl.WindSourceImpl;
+import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
+import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
+import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
+import com.sap.sailing.domain.tracking.MarkPassing;
+import com.sap.sailing.domain.tracking.TrackedLeg;
+import com.sap.sailing.domain.tracking.TrackedRegatta;
+import com.sap.sailing.domain.tracking.WindPositionMode;
+import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
+import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
+import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
+import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
+import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
+import com.sap.sailing.domain.tracking.impl.WindImpl;
+import com.sap.sse.common.TimePoint;
+import com.sap.sse.common.impl.MillisecondsTimePoint;
+
+public class ReachingLegTest extends TrackBasedTest {
+ private List competitors;
+ private CompetitorImpl plattner;
+ private CompetitorImpl hunger;
+ private MillisecondsTimePoint start;
+ private Competitor schomaeker;
+
+ /**
+ * Creates the race and two competitors ({@link #plattner} and {@link #hunger}) and sets the start line passing for both of them
+ * to {@link #start}.
+ */
+ @Before
+ public void setUp() {
+ competitors = new ArrayList();
+ hunger = createCompetitor("Wolfgang Hunger");
+ competitors.add(hunger);
+ plattner = createCompetitor("Dr. Hasso Plattner");
+ competitors.add(plattner);
+ schomaeker = createCompetitor("Meike Schom�ker");
+ competitors.add(schomaeker);
+ start = new MillisecondsTimePoint(new GregorianCalendar(2011, 05, 23).getTime());
+ setTrackedRace(createTrackedRace("Kieler Woche", "505 Race 2", "505", competitors, start));
+ List hungersMarkPassings = createMarkPassings(hunger, start);
+ getTrackedRace().updateMarkPassings(hunger, hungersMarkPassings);
+ List plattnersMarkPassings = createMarkPassings(plattner, start);
+ getTrackedRace().updateMarkPassings(plattner, plattnersMarkPassings);
+ }
+
+ protected DynamicTrackedRaceImpl createTrackedRace(String regattaName, String raceName, String boatClassName,
+ Iterable competitors, TimePoint timePointForFixes) {
+ BoatClassImpl boatClass = new BoatClassImpl(boatClassName, /* typicallyStartsUpwind */ true);
+ Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
+ RegattaImpl.getDefaultName(regattaName, boatClass.getName()), boatClass, /*startDate*/ null, /*endDate*/ null, /* trackedRegattaRegistry */ null,
+ DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), "123", null);
+ TrackedRegatta trackedRegatta = new DynamicTrackedRegattaImpl(regatta);
+ List waypoints = new ArrayList();
+ // create a two-lap upwind/downwind course:
+ MarkImpl left = new MarkImpl("Left lee gate buoy");
+ MarkImpl right = new MarkImpl("Right lee gate buoy");
+ ControlPoint leeGate = new ControlPointWithTwoMarksImpl(left, right, "Lee Gate");
+ Mark windwardMark = new MarkImpl("Windward mark");
+ Mark offsetMark = new MarkImpl("Offset mark");
+ waypoints.add(new WaypointImpl(leeGate));
+ waypoints.add(new WaypointImpl(windwardMark));
+ waypoints.add(new WaypointImpl(offsetMark));
+ waypoints.add(new WaypointImpl(leeGate));
+ Course course = new CourseImpl(raceName, waypoints);
+ RaceDefinition race = new RaceDefinitionImpl(raceName, course, boatClass, competitors);
+ DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections. emptyList(), EmptyWindStore.INSTANCE,
+ EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0,
+ /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
+ /* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false);
+ // in this simplified artificial course, the top mark is exactly north of the right leeward gate, the offset
+ // mark is slightly west of the top mark; wind from the north makes the leg from top to offset a reaching leg
+ Position leftPosition = new DegreePosition(0, -0.00001);
+ Position rightPosition = new DegreePosition(0, 0.00001);
+ Position topPosition = new DegreePosition(1, 0);
+ Position offsetPosition = new DegreePosition(1, -0.0001);
+ TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix time
+ trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(leftPosition, new MillisecondsTimePoint(0)));
+ trackedRace.getOrCreateTrack(right).addGPSFix(new GPSFixImpl(rightPosition, new MillisecondsTimePoint(0)));
+ trackedRace.getOrCreateTrack(windwardMark).addGPSFix(new GPSFixImpl(topPosition, new MillisecondsTimePoint(0)));
+ trackedRace.getOrCreateTrack(offsetMark).addGPSFix(new GPSFixImpl(offsetPosition, new MillisecondsTimePoint(0)));
+ trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(leftPosition, afterTheRace));
+ trackedRace.getOrCreateTrack(right).addGPSFix(new GPSFixImpl(rightPosition, afterTheRace));
+ trackedRace.getOrCreateTrack(windwardMark).addGPSFix(new GPSFixImpl(topPosition, afterTheRace));
+ trackedRace.getOrCreateTrack(offsetMark).addGPSFix(new GPSFixImpl(offsetPosition, afterTheRace));
+ trackedRace.recordWind(new WindImpl(topPosition, timePointForFixes, new KnotSpeedWithBearingImpl(
+ /* speedInKnots */14.7, new DegreeBearingImpl(180))), new WindSourceImpl(WindSourceType.WEB));
+ return trackedRace;
+ }
+
+ @Test
+ public void testSecondLegIsReaching() throws NoWindException {
+ Iterator legIter = getTrackedRace().getTrackedLegs().iterator();
+ assertEquals(LegType.UPWIND, legIter.next().getLegType(start));
+ assertEquals(LegType.REACHING, legIter.next().getLegType(start));
+ assertEquals(LegType.DOWNWIND, legIter.next().getLegType(start));
+ }
+
+ @Test
+ public void testHungerInReachingPlattnerInUpwind() {
+ // give Hunger a mark passing for the windward mark, putting him into the reaching leg
+ final MillisecondsTimePoint whenHungerFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
+ getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenHungerFinishedUpwind));
+ assertEquals(
+ getTrackedRace().getRace().getCourse().getLegs().get(1),
+ getTrackedRace().getTrackedLeg(hunger,
+ new MillisecondsTimePoint(whenHungerFinishedUpwind.asMillis() + 10000)).getLeg());
+ assertEquals(
+ getTrackedRace().getRace().getCourse().getLegs().get(0),
+ getTrackedRace().getTrackedLeg(plattner,
+ new MillisecondsTimePoint(whenHungerFinishedUpwind.asMillis() + 10000)).getLeg());
+ }
+
+ @Test
+ public void testHungerAndPlattnerInReaching() {
+ // give Hunger and Plattner a mark passing for the windward mark, putting both of them into the reaching leg
+ final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
+ getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
+ getTrackedRace().updateMarkPassings(plattner, createMarkPassings(plattner, start, whenBothFinishedUpwind));
+ assertEquals(
+ getTrackedRace().getRace().getCourse().getLegs().get(1),
+ getTrackedRace().getTrackedLeg(hunger,
+ new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis() + 10000)).getLeg());
+ assertEquals(
+ getTrackedRace().getRace().getCourse().getLegs().get(1),
+ getTrackedRace().getTrackedLeg(plattner,
+ new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis() + 10000)).getLeg());
+ }
+
+ @Test
+ public void testDistanceWithHungerAndPlattnerInReaching() throws NoWindException {
+ // give Hunger and Plattner a mark passing for the windward mark, putting both of them into the reaching leg
+ final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
+ final MillisecondsTimePoint timePointInReaching = new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis()+10000);
+ Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointInReaching);
+ Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointInReaching);
+ Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
+ assertTrue(distanceOfReachingLeg.getMeters() > 0);
+ getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
+ getTrackedRace().updateMarkPassings(plattner, createMarkPassings(plattner, start, whenBothFinishedUpwind));
+ getTrackedRace().recordFix(
+ hunger,
+ new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ getTrackedRace().recordFix(
+ plattner,
+ new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ assertEquals(0.,
+ getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
+ .getDistance(offsetMarkPos).getMeters(), 0.00001);
+ assertEquals(0.,
+ getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
+ .getDistance(windwardMarkPos).getMeters(), 0.00001);
+ Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE);
+ Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE);
+ assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001);
+ assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001);
+ }
+
+ @Test
+ public void testDistanceWithHungerInReachingAndPlattnerInUpwind() throws NoWindException {
+ // give Hunger and Plattner a mark passing for the windward mark, putting both of them into the reaching leg
+ final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
+ final MillisecondsTimePoint timePointInReaching = new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis()+10000);
+ Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointInReaching);
+ Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointInReaching);
+ Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
+ assertTrue(distanceOfReachingLeg.getMeters() > 0);
+ getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
+ getTrackedRace().recordFix(
+ hunger,
+ new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ getTrackedRace().recordFix(
+ plattner,
+ new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ assertEquals(0.,
+ getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
+ .getDistance(offsetMarkPos).getMeters(), 0.00001);
+ assertEquals(0.,
+ getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
+ .getDistance(windwardMarkPos).getMeters(), 0.00001);
+ Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE);
+ Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE);
+ assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001);
+ assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001);
+ }
+
+ @Test
+ public void testDistanceWithHungerInDownwindAndPlattnerInReaching() throws NoWindException {
+ // give Hunger and Plattner a mark passing for the windward mark, putting both of them into the reaching leg
+ final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
+ final MillisecondsTimePoint timePointInReaching = new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis()+10000);
+ Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointInReaching);
+ Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointInReaching);
+ Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
+ assertTrue(distanceOfReachingLeg.getMeters() > 0);
+ getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
+ getTrackedRace().recordFix(
+ hunger,
+ new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ getTrackedRace().recordFix(
+ plattner,
+ new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ assertEquals(0.,
+ getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
+ .getDistance(offsetMarkPos).getMeters(), 0.00001);
+ assertEquals(0.,
+ getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
+ .getDistance(windwardMarkPos).getMeters(), 0.00001);
+ Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointInReaching, WindPositionMode.LEG_MIDDLE);
+ Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointInReaching, WindPositionMode.LEG_MIDDLE);
+ assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001);
+ assertEquals(distanceOfReachingLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001);
+ }
+
+ @Test
+ public void testDistanceWithHungerInDownwindAndPlattnerInUpwindWithReachingInBetween() throws NoWindException {
+ // give Hunger a mark passing for the windward mark, consume Plattner is stuck at the starting line, putting
+ // the empty reaching leg between the two; see if the reaching leg's non-windward distance is counted, and if
+ // Plattner's distance is accumulated correctly
+ final MillisecondsTimePoint whenHungerFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
+ final MillisecondsTimePoint whenHungerFinishedReaching = new MillisecondsTimePoint(whenHungerFinishedUpwind.asMillis()+10000);
+ final MillisecondsTimePoint timePointToConsider = new MillisecondsTimePoint(whenHungerFinishedReaching.asMillis()+10000);
+ Position leewardPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getFrom(), timePointToConsider);
+ Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointToConsider);
+ Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointToConsider);
+ Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
+ Distance windwardDistanceOfUpwindLeg = leewardPos.getDistance(windwardMarkPos);
+ assertTrue(distanceOfReachingLeg.getMeters() > 0);
+ getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenHungerFinishedUpwind, whenHungerFinishedReaching));
+ getTrackedRace().recordFix(
+ hunger,
+ new GPSFixMovingImpl(offsetMarkPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ getTrackedRace().recordFix(
+ plattner,
+ new GPSFixMovingImpl(leewardPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(0))));
+ assertEquals(0.,
+ getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
+ .getDistance(offsetMarkPos).getMeters(), 0.00001);
+ assertEquals(0.,
+ getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
+ .getDistance(leewardPos).getMeters(), 0.00001);
+ Distance hungersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(hunger, timePointToConsider, WindPositionMode.LEG_MIDDLE);
+ Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE);
+ assertEquals(0., hungersDistanceToLeader.getMeters(), 0.00001);
+ assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters(), plattnersDistanceToLeader.getMeters(), 0.001);
+ }
+
+ @Test
+ public void testWindwardDistanceToOverallLeaderWithHungerFirstAtWindwardMarkButSecondAfterReachingLeg() throws NoWindException {
+ // Hunger finished first upwind before Schomaeker; Schomaeker finished reaching before Hunger, leading now;
+ // Schoemaeker made it half through the downwind while Hunger got stuck at the offset mark
+ final MillisecondsTimePoint whenHungerFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
+ final MillisecondsTimePoint whenSchomaekerFinishedUpwind = new MillisecondsTimePoint(whenHungerFinishedUpwind.asMillis()+1000);
+ final MillisecondsTimePoint whenSchomaekerFinishedReaching = new MillisecondsTimePoint(whenSchomaekerFinishedUpwind.asMillis()+10000);
+ final MillisecondsTimePoint whenHungerFinishedReaching = new MillisecondsTimePoint(whenSchomaekerFinishedReaching.asMillis()+1000);
+ final MillisecondsTimePoint timePointToConsider = new MillisecondsTimePoint(whenHungerFinishedReaching.asMillis()+10000);
+
+ Position leewardPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getFrom(), timePointToConsider);
+ Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointToConsider);
+ Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointToConsider);
+ Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
+ Distance windwardDistanceOfUpwindLeg = leewardPos.getDistance(windwardMarkPos);
+ assertTrue(distanceOfReachingLeg.getMeters() > 0);
+ getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenHungerFinishedUpwind, whenHungerFinishedReaching));
+ getTrackedRace().updateMarkPassings(schomaeker, createMarkPassings(schomaeker, start, whenSchomaekerFinishedUpwind, whenSchomaekerFinishedReaching));
+ getTrackedRace().recordFix(
+ hunger,
+ new GPSFixMovingImpl(offsetMarkPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ getTrackedRace().recordFix(
+ schomaeker,
+ new GPSFixMovingImpl(offsetMarkPos.translateGreatCircle(
+ offsetMarkPos.getBearingGreatCircle(leewardPos), offsetMarkPos.getDistance(leewardPos)
+ .scale(0.5)), timePointToConsider, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(180))));
+ getTrackedRace().recordFix(
+ plattner,
+ new GPSFixMovingImpl(leewardPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(0))));
+ assertEquals(0.,
+ getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
+ .getDistance(offsetMarkPos).getMeters(), 0.00001);
+ assertEquals(0.,
+ getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
+ .getDistance(leewardPos).getMeters(), 0.00001);
+ Distance schomaekersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(schomaeker, timePointToConsider, WindPositionMode.LEG_MIDDLE);
+ Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE);
+ assertEquals(0., schomaekersDistanceToLeader.getMeters(), 0.00001);
+ // distance to leading Schomaeker expected to be the entire upwind distance plus the offset distance plus half the downwind
+ assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters()*1.5, plattnersDistanceToLeader.getMeters(), 0.001);
+ }
+
+ @Test
+ public void testWindwardDistanceOnReachingLegProjectsOntoLegDirection() throws NoWindException {
+ final MillisecondsTimePoint whenBothFinishedUpwind = new MillisecondsTimePoint(start.asMillis()+600000);
+ final MillisecondsTimePoint timePointToConsider = new MillisecondsTimePoint(whenBothFinishedUpwind.asMillis()+10000);
+
+ Position windwardMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(0).getTo(), timePointToConsider);
+ Position offsetMarkPos = getTrackedRace().getApproximatePosition(getTrackedRace().getRace().getCourse().getLegs().get(1).getTo(), timePointToConsider);
+ Distance distanceOfReachingLeg = windwardMarkPos.getDistance(offsetMarkPos);
+ assertTrue(distanceOfReachingLeg.getMeters() > 0);
+ getTrackedRace().updateMarkPassings(hunger, createMarkPassings(hunger, start, whenBothFinishedUpwind));
+ getTrackedRace().updateMarkPassings(plattner, createMarkPassings(plattner, start, whenBothFinishedUpwind));
+ Bearing reachingLegBearing = windwardMarkPos.getBearingGreatCircle(offsetMarkPos);
+ // Hunger turns left after the windward mark
+ getTrackedRace().recordFix(
+ hunger,
+ new GPSFixMovingImpl(windwardMarkPos.translateGreatCircle(new DegreeBearingImpl(reachingLegBearing.getDegrees()-45),
+ distanceOfReachingLeg.scale(1./Math.sqrt(2.))), timePointToConsider, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ // Plattner turns right after the windward mark; both travel the same distance projected along the leg
+ getTrackedRace().recordFix(
+ plattner,
+ new GPSFixMovingImpl(windwardMarkPos.translateGreatCircle(new DegreeBearingImpl(reachingLegBearing.getDegrees()+45),
+ distanceOfReachingLeg.scale(1./Math.sqrt(2.))), timePointToConsider, new KnotSpeedWithBearingImpl(12,
+ new DegreeBearingImpl(270))));
+ // with 90deg separating them, traveling 1/sqrt(2) the distance of the leg should put them the distance of the leg apart geometrically
+ assertEquals(
+ distanceOfReachingLeg.getMeters(),
+ getTrackedRace()
+ .getTrack(hunger)
+ .getEstimatedPosition(timePointToConsider, /* extrapolate */false)
+ .getDistance(
+ getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */
+ false)).getMeters(), 0.00001);
+ // however, projected onto the leg their distance should be 0
+ Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToOverallLeader(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE);
+ assertEquals(0., plattnersDistanceToLeader.getMeters(), 0.00001);
+ }
+}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveMarkPassingDataTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveMarkPassingDataTest.java
index fa78cfaab45..c1bc2f1b499 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveMarkPassingDataTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveMarkPassingDataTest.java
@@ -107,7 +107,7 @@ public class ReceiveMarkPassingDataTest extends AbstractTracTracLiveTest {
}
}, /* trackedRegattaRegistry */null,
/* courseDesignUpdateURI */null, /* tracTracUsername */null, null, /* tracTracPassword */
- getEventSubscriber(), getRaceSubscriber(), ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH,
+ getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH,
ReceiverType.RAWPOSITIONS)) {
receivers.add(r);
}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java
index d2ffc899fb4..5846d508b3c 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java
@@ -84,7 +84,7 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
}
},
/* trackedRegattaRegistry */null, getTracTracRace(), null, /* courseDesignUpdateURI */
- /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber())) {
+ /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)) {
receiver.subscribe();
getRaceSubscriber().start();
}
@@ -96,7 +96,7 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) {
}
}, /* trackedRegattaRegistry */null, getTracTracRace(), null, /* courseDesignUpdateURI */
- /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber()));
+ /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false));
}
@Test
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java
index f69815b0ef7..334e27bbba3 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java
@@ -86,7 +86,7 @@ public class StarbordSideOfStartLineRecognitionTest {
private static final long serialVersionUID = -8007932232555073829L;
public MockedTrackedRaceImpl() {
- super(null, null, Collections. emptyList(), null, null, 0, 0, 0, 0);
+ super(null, null, Collections. emptyList(), null, null, 0, 0, 0, 0, false);
}
@Override
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java
index faeaca23b4e..ac029889f68 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java
@@ -117,7 +117,7 @@ public abstract class TrackBasedTest {
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections. emptyList(), EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0,
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
- /* delay for wind estimation cache invalidation */ 0);
+ /* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false);
// in this simplified artificial course, the top mark is exactly north of the right leeward gate
DegreePosition topPosition = new DegreePosition(54.48, 10.24);
TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix time
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java
index fc42239e6bc..de22a3fa28b 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java
@@ -65,7 +65,8 @@ public class UnicodeCharactersInCompetitorNamesTest {
+ TracTracConnectionConstants.PORT_STORED), new URI(
"http://tracms.traclive.dk/update_course"),
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l,
- /* simulateWithStartTimeNow */false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
+ /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
+ false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, "tracTest", "tracTest", "", "",
new DummyTrackedRegattaRegistry());
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java
index 60aacd5527f..2611d968806 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java
@@ -46,7 +46,7 @@ public class UpdateMarkPassingTest {
/* trackedRegatta */new DynamicTrackedRegattaImpl(new RegattaImpl("test", null, null, null, new HashSet(), false, null,
"test", null)), race, Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,
/* delayToLiveInMillis */1000, /* millisecondsOverWhichToAverageWind */30000,
- /* millisecondsOverWhichToAverageSpeed */30000);
+ /* millisecondsOverWhichToAverageSpeed */30000, /*useMarkPassingCalculator*/ false);
TimePoint now = MillisecondsTimePoint.now();
TimePoint later = now.plus(1000);
trackedRace.updateMarkPassings(competitor, Arrays.asList(new MarkPassing[] { new MarkPassingImpl(now, waypoint, competitor) }));
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java
index 64368e6e02e..9b6782bf4b7 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java
@@ -1,355 +1,355 @@
-package com.sap.sailing.domain.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.junit.Test;
-
-import com.sap.sailing.domain.base.BoatClass;
-import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.base.ControlPoint;
-import com.sap.sailing.domain.base.DomainFactory;
-import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.base.Sideline;
-import com.sap.sailing.domain.base.Waypoint;
-import com.sap.sailing.domain.base.impl.BoatClassImpl;
-import com.sap.sailing.domain.base.impl.BoatImpl;
-import com.sap.sailing.domain.base.impl.CompetitorImpl;
-import com.sap.sailing.domain.base.impl.CourseImpl;
-import com.sap.sailing.domain.base.impl.NationalityImpl;
-import com.sap.sailing.domain.base.impl.PersonImpl;
-import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
-import com.sap.sailing.domain.base.impl.RegattaImpl;
-import com.sap.sailing.domain.base.impl.TeamImpl;
-import com.sap.sailing.domain.common.Bearing;
-import com.sap.sailing.domain.common.Position;
-import com.sap.sailing.domain.common.ScoringSchemeType;
-import com.sap.sailing.domain.common.confidence.Weigher;
-import com.sap.sailing.domain.common.confidence.impl.PositionAndTimePointWeigher;
-import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
-import com.sap.sailing.domain.common.impl.DegreePosition;
-import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
-import com.sap.sailing.domain.common.impl.MeterDistance;
-import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager;
-import com.sap.sailing.domain.confidence.ConfidenceFactory;
-import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
-import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
-import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
-import com.sap.sailing.domain.tracking.DynamicTrackedRace;
-import com.sap.sailing.domain.tracking.MarkPassing;
-import com.sap.sailing.domain.tracking.Wind;
-import com.sap.sailing.domain.tracking.WindTrack;
-import com.sap.sailing.domain.tracking.WindWithConfidence;
-import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
-import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
-import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
-import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
-import com.sap.sailing.domain.tracking.impl.WindImpl;
-import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
-import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
-import com.sap.sse.common.Color;
-import com.sap.sse.common.TimePoint;
-import com.sap.sse.common.Util;
-import com.sap.sse.common.Util.Pair;
-import com.sap.sse.common.impl.MillisecondsTimePoint;
-
-public class WindTest {
- private static final int AVERAGING_INTERVAL_MILLIS = 30000 /* 30s averaging interval */;
-
- /**
- * Tests that averaging also works across the 0deg mark
- */
- @Test
- public void testAveragingWind() throws InterruptedException {
- WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
- TimePoint t1 = MillisecondsTimePoint.now();
- TimePoint t2 = new MillisecondsTimePoint(t1.asMillis()+10);
- TimePoint middle = new MillisecondsTimePoint((t1.asMillis()+t2.asMillis())/2);
- DegreePosition pos = new DegreePosition(0, 0);
- Wind wind1 = new WindImpl(pos, t1, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(355)));
- Wind wind2 = new WindImpl(pos, t2, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(5)));
- track.add(wind1);
- track.add(wind2);
- Wind average = track.getAveragedWind(pos, middle);
- assertEquals(0., average.getBearing().getDifferenceTo(new DegreeBearingImpl(0)).getDegrees(), 0.0001);
- }
-
- @Test
- public void testMultipleWindFixesWithSameTimestampInSameWindTrack() {
- WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
- TimePoint now = MillisecondsTimePoint.now();
- DegreePosition pos1 = new DegreePosition(0, 0);
- DegreePosition pos2 = new DegreePosition(1, 1);
- Wind wind1 = new WindImpl(pos1, now, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(0)));
- Wind wind2 = new WindImpl(pos2, now, new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
- track.add(wind1);
- track.add(wind2);
- track.lockForRead();
- try {
- assertEquals(2, Util.size(track.getFixes()));
- Set expectedWind = new HashSet();
- expectedWind.add(wind1);
- expectedWind.add(wind2);
- Set actualWind = new HashSet();
- for (Wind wind : track.getFixes()) {
- actualWind.add(wind);
- }
- assertEquals(expectedWind, actualWind);
- } finally {
- track.unlockAfterRead();
- }
- }
-
- @Test
- public void testEmptyTrackYieldsNullAsWindEstimate() {
- WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
- assertNull(track.getAveragedWind(new DegreePosition(0, 0), MillisecondsTimePoint.now()));
- }
-
- /**
- * If the wind track has areas with no data, and wind information is requested for such an interval,
- * it is essential to still average over the {@link #AVERAGING_INTERVAL_MILLIS} interval, even if the
- * interval is further away than {@link #AVERAGING_INTERVAL_MILLIS}.
- */
- @Test
- public void testAveragingOfSparseWindTrack() {
- WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
- DegreePosition pos = new DegreePosition(0, 0);
- Wind wind1 = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
- Wind wind2 = new WindImpl(pos, new MillisecondsTimePoint(1000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
- Wind wind3 = new WindImpl(pos, new MillisecondsTimePoint(2000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
- Wind wind4 = new WindImpl(pos, new MillisecondsTimePoint(10000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
- Wind wind5 = new WindImpl(pos, new MillisecondsTimePoint(30000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
- Wind wind6 = new WindImpl(pos, new MillisecondsTimePoint(40000), new KnotSpeedWithBearingImpl(130, new DegreeBearingImpl(0)));
- Wind wind7 = new WindImpl(pos, new MillisecondsTimePoint(50000), new KnotSpeedWithBearingImpl(170, new DegreeBearingImpl(0)));
- track.add(wind1);
- track.add(wind2);
- track.add(wind3);
- track.add(wind4);
- track.add(wind5);
- track.add(wind6);
- track.add(wind7);
-
- // interval does bearely reach 20's burst because 0 has 0 length and 1000..30000 has 29000 length
- assertEquals(20, track.getAveragedWind(pos, new MillisecondsTimePoint(1)).getKnots(), 0.00000001);
- // interval uses the two fixes to the left (0, 1000)=1000 and three to the right (2000, 10000, 30000)=28000
- assertEquals(20, track.getAveragedWind(pos, new MillisecondsTimePoint(1001)).getKnots(), 0.00000001);
- // in the middle of the "hole", fetches (0, 1000, 2000, 10000)=10000 and (30000, 40000)=10000, so 20000ms worth of wind
- final double averageFor20000 = track.getAveragedWind(pos, new MillisecondsTimePoint(20000)).getKnots();
- // value is hard to predict exactly because time difference-based confidences rate fixes closer to 20000ms higher than those further away
- assertEquals(35, averageFor20000, 5);
- // right of the middle of the "hole", fetches (0, 1000, 2000, 10000)=10000 and (30000, 40000, 50000)=20000
- final double averageFor20500 = track.getAveragedWind(pos, new MillisecondsTimePoint(20500)).getKnots();
- assertEquals(37, averageFor20500, 5);
- assertTrue(averageFor20500 > averageFor20000);
- }
-
- @Test
- public void testSingleElementWindTrack() {
- WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
- DegreePosition pos = new DegreePosition(0, 0);
- Wind wind = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)));
- track.add(wind);
- Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(0));
- assertEquals(10, estimate.getKnots(), 0.000000001);
- assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001);
- }
-
- @Test
- public void testSingleElementExtrapolation() {
- WindTrack track = new WindTrackImpl(30000 /* 30s averaging interval */, /* useSpeed */ true, "TestWindTrack");
- DegreePosition pos = new DegreePosition(0, 0);
- Wind wind = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)));
- track.add(wind);
- // we only have one measurement; this should be extrapolated because it's our best guess
- Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(1000));
- assertEquals(10, estimate.getKnots(), 0.000000001);
- assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001);
- }
-
- @Test
- public void testSingleElementExtrapolationBeyondThreshold() {
- WindTrack track = new WindTrackImpl(30000 /* 30s averaging interval */, /* useSpeed */ true, "TestWindTrack");
- DegreePosition pos = new DegreePosition(0, 0);
- Wind wind = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)));
- track.add(wind);
- // we only have one measurement; this should be extrapolated because it's our best guess even if
- // the last measurement was longer ago than our smoothening interval
- Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(AVERAGING_INTERVAL_MILLIS+1000));
- assertEquals(10, estimate.getKnots(), 0.000000001);
- assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001);
- }
-
- @Test
- public void testTwoElementWindTrackSameBearing() {
- WindTrack track = new WindTrackImpl(30000 /* 30s averaging interval */, /* useSpeed */ true, "TestWindTrack");
- DegreePosition pos = new DegreePosition(0, 0);
- Wind wind1 = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(100)));
- track.add(wind1);
- Wind wind2 = new WindImpl(pos, new MillisecondsTimePoint(1000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(100)));
- track.add(wind2);
- Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(500));
- assertEquals(15, estimate.getKnots(), 0.000000001);
- assertEquals(100, estimate.getBearing().getDegrees(), 0.00000001);
- }
-
- @Test
- public void testTwoElementWindTrackDifferentBearing() {
- WindTrack track = new WindTrackImpl(30000 /* 30s averaging interval */, /* useSpeed */ true, "TestWindTrack");
- DegreePosition pos = new DegreePosition(0, 0);
- Wind wind1 = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(110)));
- track.add(wind1);
- Wind wind2 = new WindImpl(pos, new MillisecondsTimePoint(1000), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(100)));
- track.add(wind2);
- Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(2000));
- assertEquals(10, estimate.getKnots(), 0.000000001);
- assertEquals(105, estimate.getBearing().getDegrees(), 0.6); // some tolerance needed because of time-based confidence
- }
-
- @Test
- public void testUsingNewerThanRequestedIfCloserThanOlder() throws ParseException {
- /*
- Imagine the following wind measurements:
-
- 2009-07-11T13:45:00.000+0200@null: 10.0kn from 278.0� avg(30000ms): 2009-07-11T13:45:00.000+0200@null: 10.0kn from 278.0°
- 2009-07-11T13:45:05.000+0200@null: 10.0kn from 265.0� avg(30000ms): 2009-07-11T13:45:05.000+0200@null: 10.0kn from 265.0°
- 2009-07-12T17:31:40.000+0200@null: 10.0kn from 260.0� avg(30000ms): 2009-07-12T17:31:40.000+0200@null: 10.0kn from 260.0°
-
- Now assume a query for 2009-07-12T17:31:38 which is closest to the newest entry but (much) more than
- the averaging interval after the previous entry (2009-07-11T13:45:05.000). This test ensures that
- the WindTrack uses the newer entry even though it's after the time point requested because it's
- much closer, and the previous entry would be out of the averaging interval anyway.
- */
- SimpleDateFormat df = new SimpleDateFormat("yyyy-DD-mm'T'hh:mm:ss");
- Wind wind1 = new WindImpl(null, new MillisecondsTimePoint(df.parse("2009-07-11T13:45:00").getTime()),
- new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(98)));
- Wind wind2 = new WindImpl(null, new MillisecondsTimePoint(df.parse("2009-07-11T13:45:05").getTime()),
- new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(85)));
- Wind wind3 = new WindImpl(null, new MillisecondsTimePoint(df.parse("2009-07-11T17:31:40").getTime()),
- new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(80)));
- WindTrack track = new WindTrackImpl(/* millisecondsOverWhichToAverage */ 30000, /* useSpeed */ true, "TestWindTrack");
- track.add(wind1);
- track.add(wind2);
- track.add(wind3);
- TimePoint timePoint = new MillisecondsTimePoint(df.parse("2009-07-11T17:31:38").getTime());
- Wind result = track.getAveragedWind(null, timePoint);
- // expectation: take two from left (because they are closer than AVERAGING_INTERVAL_MILLIS apart), one from right side:
- assertEquals((wind1.getKnots() + wind2.getKnots() + wind3.getKnots()) / 3, result.getKnots(), 0.000000001);
- assertEquals(80., result.getBearing().getDegrees(), 5);
- }
-
- @Test
- public void testWindwardDistanceForReachingLeg() {
- // TODO construct a tiny course with one upwind, one reaching and one downwind leg, a race with two competitors;
- // TODO create a tracked race with corresponding WEB wind source; put leader in downwind, trailer in upwind and
- // TODO test that windward distance includes the full reaching leg's length
- }
-
- /**
- * See bug 943. Wind estimation should return null instead of causing exceptions in case there
- * is no wind data to bootstrap the estimator with.
- */
- @Test
- public void testWindEstimationReturnsNullIfNoUpwindStartAndNoOtherWindDataAvailable() {
- DomainFactory domainFactory = DomainFactory.INSTANCE;
- Mark startFinishLeft = domainFactory.getOrCreateMark("Start/Finish left");
- Mark startFinishRight = domainFactory.getOrCreateMark("Start/Finish right");
- ControlPoint startFinish = domainFactory.createControlPointWithTwoMarks(startFinishLeft, startFinishRight, "Start/Finish");
- ControlPoint top = domainFactory.getOrCreateMark("Top");
- Waypoint w1 = domainFactory.createWaypoint(startFinish, /*passingInstruction*/ null);
- Waypoint w2 = domainFactory.createWaypoint(top, /*passingInstruction*/ null);
- Waypoint w3 = domainFactory.createWaypoint(startFinish, /*passingInstruction*/ null);
- Competitor competitor = new CompetitorImpl(123, "Test Competitor", Color.RED, null, new TeamImpl("STG", Collections.singleton(
- new PersonImpl("Test Competitor", new NationalityImpl("GER"),
- /* dateOfBirth */null, "This is famous " + "Test Competitor")), new PersonImpl("Rigo van Maas",
- new NationalityImpl("NED"),
- /* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl("Test Competitor" + "'s boat",
- new BoatClassImpl("505", /* typicallyStartsUpwind */true), null));
- final BoatClass boatClass = domainFactory.getOrCreateBoatClass("ESS40");
- DynamicTrackedRace trackedRace = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(
- new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
- RegattaImpl.getDefaultName("Test Regatta", boatClass.getName()), boatClass, /*startDate*/ null, /*endDate*/ null,
- /* trackedRegattaRegistry */ null, domainFactory.createScoringScheme(ScoringSchemeType.LOW_POINT), "123", null)),
- new RaceDefinitionImpl("Test Race",
- new CourseImpl("Test Course", Arrays.asList(new Waypoint[] { w1, w2, w3 })),
- boatClass, Collections.singleton(competitor)), Collections. emptyList(),
- EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 1000,
- /* millisecondsOverWhichToAverageWind */ 30000,
- /* millisecondsOverWhichToAverageSpeed */ 30000);
- TimePoint start = MillisecondsTimePoint.now();
- TimePoint topMarkRounding = start.plus(30000);
- TimePoint finish = topMarkRounding.plus(30000);
- trackedRace.updateMarkPassings(competitor, Arrays.asList(new MarkPassing[] {
- new MarkPassingImpl(start, w1, competitor),
- new MarkPassingImpl(topMarkRounding, w2, competitor),
- new MarkPassingImpl(finish, w3, competitor)
- }));
- assertFalse(boatClass.typicallyStartsUpwind());
- assertNull(trackedRace.getEstimatedWindDirection(MillisecondsTimePoint.now()));
- }
-
- @Test
- public void testWindAveragingBasedOnPosition() {
- Weigher> timeWeigherThatPretendsToAlsoWeighPositions = new PositionAndTimePointWeigher(
- /* halfConfidenceAfterMilliseconds */10000l, new MeterDistance(1000));
- ConfidenceBasedWindAverager> averager = ConfidenceFactory.INSTANCE
- .createWindAverager(timeWeigherThatPretendsToAlsoWeighPositions);
- TimePoint now = MillisecondsTimePoint.now();
- final DegreePosition p1 = new DegreePosition(0, 0);
- WindWithConfidence> w1 = new WindWithConfidenceImpl<>(
- new WindImpl(p1, now, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(90))),
- /* confidence */ 1.0, new Pair(p1, now), /* useSpeed */ true);
- final Position p2 = p1.translateGreatCircle(new DegreeBearingImpl(0), new MeterDistance(1000));
- WindWithConfidence> w2 = new WindWithConfidenceImpl<>(
- new WindImpl(p2, now, new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0))),
- /* confidence */ 1.0, new Pair(p2, now), /* useSpeed */ true);
- List>> fixes = new ArrayList<>();
- fixes.add(w1);
- fixes.add(w2);
- WindWithConfidence> averageAtP1 = averager.getAverage(fixes, new Pair(p1, now));
- WindWithConfidence> averageAtP2 = averager.getAverage(fixes, new Pair(p2, now));
- // first careful assertion: at p1 where wind is from the west (to the east), wind should be further from the
- // west (further to the east) than at p2 where wind is from the south (to the north).
- final Bearing averageAtP1Bearing = averageAtP1.getObject().getBearing();
- assertTrue(Math.abs(averageAtP1Bearing.getDifferenceTo(w1.getObject().getBearing()).getDegrees()) <
- Math.abs(averageAtP1Bearing.getDifferenceTo(w2.getObject().getBearing()).getDegrees()));
- // ...and vice versa
- final Bearing averageAtP2Bearing = averageAtP2.getObject().getBearing();
- assertTrue(Math.abs(averageAtP2Bearing.getDifferenceTo(w2.getObject().getBearing()).getDegrees()) <
- Math.abs(averageAtP2Bearing.getDifferenceTo(w1.getObject().getBearing()).getDegrees()));
- // expect the arithmetic average at the point which is in the middle between the two positions
- Position middleBetweenP1AndP2 = p1.translateGreatCircle(p1.getBearingGreatCircle(p2), p1.getDistance(p2).scale(.5));
- WindWithConfidence> averageAtMiddleBetweenP1AndP2 = averager.getAverage(fixes,
- new Pair(middleBetweenP1AndP2, now));
- assertEquals(15, averageAtMiddleBetweenP1AndP2.getObject().getKnots(), 0.00001);
- assertEquals(45, averageAtMiddleBetweenP1AndP2.getObject().getBearing().getDegrees(), 0.00001);
-
- // now try again with distance 2km and demand the difference between the position-dependent readings to be greater
- final Position p3 = p1.translateGreatCircle(new DegreeBearingImpl(0), new MeterDistance(2000));
- WindWithConfidence> w3 = new WindWithConfidenceImpl<>(
- new WindImpl(p3, now, new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0))),
- /* confidence */ 1.0, new Pair(p3, now), /* useSpeed */ true);
- List>> fixesFurtherApart = new ArrayList<>();
- fixesFurtherApart.add(w1);
- fixesFurtherApart.add(w3);
- WindWithConfidence> averageFurtherApartAtP1 = averager.getAverage(fixesFurtherApart, new Pair(p1, now));
- WindWithConfidence> averageAtP3 = averager.getAverage(fixesFurtherApart, new Pair(p3, now));
- assertTrue(averageFurtherApartAtP1.getObject().getKnots() < averageAtP1.getObject().getKnots());
- assertTrue(averageAtP3.getObject().getKnots() > averageAtP2.getObject().getKnots());
- assertTrue(Math.abs(averageFurtherApartAtP1.getObject().getBearing().getDifferenceTo(w1.getObject().getBearing()).getDegrees())
- < Math.abs(averageAtP1.getObject().getBearing().getDifferenceTo(w1.getObject().getBearing()).getDegrees()));
- assertTrue(Math.abs(averageAtP3.getObject().getBearing().getDifferenceTo(w3.getObject().getBearing()).getDegrees())
- < Math.abs(averageAtP2.getObject().getBearing().getDifferenceTo(w3.getObject().getBearing()).getDegrees()));
- }
-}
+package com.sap.sailing.domain.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.sap.sailing.domain.base.BoatClass;
+import com.sap.sailing.domain.base.Competitor;
+import com.sap.sailing.domain.base.ControlPoint;
+import com.sap.sailing.domain.base.DomainFactory;
+import com.sap.sailing.domain.base.Mark;
+import com.sap.sailing.domain.base.Sideline;
+import com.sap.sailing.domain.base.Waypoint;
+import com.sap.sailing.domain.base.impl.BoatClassImpl;
+import com.sap.sailing.domain.base.impl.BoatImpl;
+import com.sap.sailing.domain.base.impl.CompetitorImpl;
+import com.sap.sailing.domain.base.impl.CourseImpl;
+import com.sap.sailing.domain.base.impl.NationalityImpl;
+import com.sap.sailing.domain.base.impl.PersonImpl;
+import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
+import com.sap.sailing.domain.base.impl.RegattaImpl;
+import com.sap.sailing.domain.base.impl.TeamImpl;
+import com.sap.sailing.domain.common.Bearing;
+import com.sap.sailing.domain.common.Position;
+import com.sap.sailing.domain.common.ScoringSchemeType;
+import com.sap.sailing.domain.common.confidence.Weigher;
+import com.sap.sailing.domain.common.confidence.impl.PositionAndTimePointWeigher;
+import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
+import com.sap.sailing.domain.common.impl.DegreePosition;
+import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
+import com.sap.sailing.domain.common.impl.MeterDistance;
+import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager;
+import com.sap.sailing.domain.confidence.ConfidenceFactory;
+import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
+import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
+import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
+import com.sap.sailing.domain.tracking.MarkPassing;
+import com.sap.sailing.domain.tracking.Wind;
+import com.sap.sailing.domain.tracking.WindTrack;
+import com.sap.sailing.domain.tracking.WindWithConfidence;
+import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
+import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
+import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
+import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
+import com.sap.sailing.domain.tracking.impl.WindImpl;
+import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
+import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
+import com.sap.sse.common.Color;
+import com.sap.sse.common.TimePoint;
+import com.sap.sse.common.Util;
+import com.sap.sse.common.Util.Pair;
+import com.sap.sse.common.impl.MillisecondsTimePoint;
+
+public class WindTest {
+ private static final int AVERAGING_INTERVAL_MILLIS = 30000 /* 30s averaging interval */;
+
+ /**
+ * Tests that averaging also works across the 0deg mark
+ */
+ @Test
+ public void testAveragingWind() throws InterruptedException {
+ WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
+ TimePoint t1 = MillisecondsTimePoint.now();
+ TimePoint t2 = new MillisecondsTimePoint(t1.asMillis()+10);
+ TimePoint middle = new MillisecondsTimePoint((t1.asMillis()+t2.asMillis())/2);
+ DegreePosition pos = new DegreePosition(0, 0);
+ Wind wind1 = new WindImpl(pos, t1, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(355)));
+ Wind wind2 = new WindImpl(pos, t2, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(5)));
+ track.add(wind1);
+ track.add(wind2);
+ Wind average = track.getAveragedWind(pos, middle);
+ assertEquals(0., average.getBearing().getDifferenceTo(new DegreeBearingImpl(0)).getDegrees(), 0.0001);
+ }
+
+ @Test
+ public void testMultipleWindFixesWithSameTimestampInSameWindTrack() {
+ WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
+ TimePoint now = MillisecondsTimePoint.now();
+ DegreePosition pos1 = new DegreePosition(0, 0);
+ DegreePosition pos2 = new DegreePosition(1, 1);
+ Wind wind1 = new WindImpl(pos1, now, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(0)));
+ Wind wind2 = new WindImpl(pos2, now, new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
+ track.add(wind1);
+ track.add(wind2);
+ track.lockForRead();
+ try {
+ assertEquals(2, Util.size(track.getFixes()));
+ Set expectedWind = new HashSet();
+ expectedWind.add(wind1);
+ expectedWind.add(wind2);
+ Set actualWind = new HashSet();
+ for (Wind wind : track.getFixes()) {
+ actualWind.add(wind);
+ }
+ assertEquals(expectedWind, actualWind);
+ } finally {
+ track.unlockAfterRead();
+ }
+ }
+
+ @Test
+ public void testEmptyTrackYieldsNullAsWindEstimate() {
+ WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
+ assertNull(track.getAveragedWind(new DegreePosition(0, 0), MillisecondsTimePoint.now()));
+ }
+
+ /**
+ * If the wind track has areas with no data, and wind information is requested for such an interval,
+ * it is essential to still average over the {@link #AVERAGING_INTERVAL_MILLIS} interval, even if the
+ * interval is further away than {@link #AVERAGING_INTERVAL_MILLIS}.
+ */
+ @Test
+ public void testAveragingOfSparseWindTrack() {
+ WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
+ DegreePosition pos = new DegreePosition(0, 0);
+ Wind wind1 = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
+ Wind wind2 = new WindImpl(pos, new MillisecondsTimePoint(1000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
+ Wind wind3 = new WindImpl(pos, new MillisecondsTimePoint(2000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
+ Wind wind4 = new WindImpl(pos, new MillisecondsTimePoint(10000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
+ Wind wind5 = new WindImpl(pos, new MillisecondsTimePoint(30000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0)));
+ Wind wind6 = new WindImpl(pos, new MillisecondsTimePoint(40000), new KnotSpeedWithBearingImpl(130, new DegreeBearingImpl(0)));
+ Wind wind7 = new WindImpl(pos, new MillisecondsTimePoint(50000), new KnotSpeedWithBearingImpl(170, new DegreeBearingImpl(0)));
+ track.add(wind1);
+ track.add(wind2);
+ track.add(wind3);
+ track.add(wind4);
+ track.add(wind5);
+ track.add(wind6);
+ track.add(wind7);
+
+ // interval does bearely reach 20's burst because 0 has 0 length and 1000..30000 has 29000 length
+ assertEquals(20, track.getAveragedWind(pos, new MillisecondsTimePoint(1)).getKnots(), 0.00000001);
+ // interval uses the two fixes to the left (0, 1000)=1000 and three to the right (2000, 10000, 30000)=28000
+ assertEquals(20, track.getAveragedWind(pos, new MillisecondsTimePoint(1001)).getKnots(), 0.00000001);
+ // in the middle of the "hole", fetches (0, 1000, 2000, 10000)=10000 and (30000, 40000)=10000, so 20000ms worth of wind
+ final double averageFor20000 = track.getAveragedWind(pos, new MillisecondsTimePoint(20000)).getKnots();
+ // value is hard to predict exactly because time difference-based confidences rate fixes closer to 20000ms higher than those further away
+ assertEquals(35, averageFor20000, 5);
+ // right of the middle of the "hole", fetches (0, 1000, 2000, 10000)=10000 and (30000, 40000, 50000)=20000
+ final double averageFor20500 = track.getAveragedWind(pos, new MillisecondsTimePoint(20500)).getKnots();
+ assertEquals(37, averageFor20500, 5);
+ assertTrue(averageFor20500 > averageFor20000);
+ }
+
+ @Test
+ public void testSingleElementWindTrack() {
+ WindTrack track = new WindTrackImpl(AVERAGING_INTERVAL_MILLIS, /* useSpeed */ true, "TestWindTrack");
+ DegreePosition pos = new DegreePosition(0, 0);
+ Wind wind = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)));
+ track.add(wind);
+ Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(0));
+ assertEquals(10, estimate.getKnots(), 0.000000001);
+ assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001);
+ }
+
+ @Test
+ public void testSingleElementExtrapolation() {
+ WindTrack track = new WindTrackImpl(30000 /* 30s averaging interval */, /* useSpeed */ true, "TestWindTrack");
+ DegreePosition pos = new DegreePosition(0, 0);
+ Wind wind = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)));
+ track.add(wind);
+ // we only have one measurement; this should be extrapolated because it's our best guess
+ Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(1000));
+ assertEquals(10, estimate.getKnots(), 0.000000001);
+ assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001);
+ }
+
+ @Test
+ public void testSingleElementExtrapolationBeyondThreshold() {
+ WindTrack track = new WindTrackImpl(30000 /* 30s averaging interval */, /* useSpeed */ true, "TestWindTrack");
+ DegreePosition pos = new DegreePosition(0, 0);
+ Wind wind = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)));
+ track.add(wind);
+ // we only have one measurement; this should be extrapolated because it's our best guess even if
+ // the last measurement was longer ago than our smoothening interval
+ Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(AVERAGING_INTERVAL_MILLIS+1000));
+ assertEquals(10, estimate.getKnots(), 0.000000001);
+ assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001);
+ }
+
+ @Test
+ public void testTwoElementWindTrackSameBearing() {
+ WindTrack track = new WindTrackImpl(30000 /* 30s averaging interval */, /* useSpeed */ true, "TestWindTrack");
+ DegreePosition pos = new DegreePosition(0, 0);
+ Wind wind1 = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(100)));
+ track.add(wind1);
+ Wind wind2 = new WindImpl(pos, new MillisecondsTimePoint(1000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(100)));
+ track.add(wind2);
+ Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(500));
+ assertEquals(15, estimate.getKnots(), 0.000000001);
+ assertEquals(100, estimate.getBearing().getDegrees(), 0.00000001);
+ }
+
+ @Test
+ public void testTwoElementWindTrackDifferentBearing() {
+ WindTrack track = new WindTrackImpl(30000 /* 30s averaging interval */, /* useSpeed */ true, "TestWindTrack");
+ DegreePosition pos = new DegreePosition(0, 0);
+ Wind wind1 = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(110)));
+ track.add(wind1);
+ Wind wind2 = new WindImpl(pos, new MillisecondsTimePoint(1000), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(100)));
+ track.add(wind2);
+ Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(2000));
+ assertEquals(10, estimate.getKnots(), 0.000000001);
+ assertEquals(105, estimate.getBearing().getDegrees(), 0.6); // some tolerance needed because of time-based confidence
+ }
+
+ @Test
+ public void testUsingNewerThanRequestedIfCloserThanOlder() throws ParseException {
+ /*
+ Imagine the following wind measurements:
+
+ 2009-07-11T13:45:00.000+0200@null: 10.0kn from 278.0� avg(30000ms): 2009-07-11T13:45:00.000+0200@null: 10.0kn from 278.0°
+ 2009-07-11T13:45:05.000+0200@null: 10.0kn from 265.0� avg(30000ms): 2009-07-11T13:45:05.000+0200@null: 10.0kn from 265.0°
+ 2009-07-12T17:31:40.000+0200@null: 10.0kn from 260.0� avg(30000ms): 2009-07-12T17:31:40.000+0200@null: 10.0kn from 260.0°
+
+ Now assume a query for 2009-07-12T17:31:38 which is closest to the newest entry but (much) more than
+ the averaging interval after the previous entry (2009-07-11T13:45:05.000). This test ensures that
+ the WindTrack uses the newer entry even though it's after the time point requested because it's
+ much closer, and the previous entry would be out of the averaging interval anyway.
+ */
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-DD-mm'T'hh:mm:ss");
+ Wind wind1 = new WindImpl(null, new MillisecondsTimePoint(df.parse("2009-07-11T13:45:00").getTime()),
+ new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(98)));
+ Wind wind2 = new WindImpl(null, new MillisecondsTimePoint(df.parse("2009-07-11T13:45:05").getTime()),
+ new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(85)));
+ Wind wind3 = new WindImpl(null, new MillisecondsTimePoint(df.parse("2009-07-11T17:31:40").getTime()),
+ new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(80)));
+ WindTrack track = new WindTrackImpl(/* millisecondsOverWhichToAverage */ 30000, /* useSpeed */ true, "TestWindTrack");
+ track.add(wind1);
+ track.add(wind2);
+ track.add(wind3);
+ TimePoint timePoint = new MillisecondsTimePoint(df.parse("2009-07-11T17:31:38").getTime());
+ Wind result = track.getAveragedWind(null, timePoint);
+ // expectation: take two from left (because they are closer than AVERAGING_INTERVAL_MILLIS apart), one from right side:
+ assertEquals((wind1.getKnots() + wind2.getKnots() + wind3.getKnots()) / 3, result.getKnots(), 0.000000001);
+ assertEquals(80., result.getBearing().getDegrees(), 5);
+ }
+
+ @Test
+ public void testWindwardDistanceForReachingLeg() {
+ // TODO construct a tiny course with one upwind, one reaching and one downwind leg, a race with two competitors;
+ // TODO create a tracked race with corresponding WEB wind source; put leader in downwind, trailer in upwind and
+ // TODO test that windward distance includes the full reaching leg's length
+ }
+
+ /**
+ * See bug 943. Wind estimation should return null instead of causing exceptions in case there
+ * is no wind data to bootstrap the estimator with.
+ */
+ @Test
+ public void testWindEstimationReturnsNullIfNoUpwindStartAndNoOtherWindDataAvailable() {
+ DomainFactory domainFactory = DomainFactory.INSTANCE;
+ Mark startFinishLeft = domainFactory.getOrCreateMark("Start/Finish left");
+ Mark startFinishRight = domainFactory.getOrCreateMark("Start/Finish right");
+ ControlPoint startFinish = domainFactory.createControlPointWithTwoMarks(startFinishLeft, startFinishRight, "Start/Finish");
+ ControlPoint top = domainFactory.getOrCreateMark("Top");
+ Waypoint w1 = domainFactory.createWaypoint(startFinish, /*passingInstruction*/ null);
+ Waypoint w2 = domainFactory.createWaypoint(top, /*passingInstruction*/ null);
+ Waypoint w3 = domainFactory.createWaypoint(startFinish, /*passingInstruction*/ null);
+ Competitor competitor = new CompetitorImpl(123, "Test Competitor", Color.RED, null, new TeamImpl("STG", Collections.singleton(
+ new PersonImpl("Test Competitor", new NationalityImpl("GER"),
+ /* dateOfBirth */null, "This is famous " + "Test Competitor")), new PersonImpl("Rigo van Maas",
+ new NationalityImpl("NED"),
+ /* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl("Test Competitor" + "'s boat",
+ new BoatClassImpl("505", /* typicallyStartsUpwind */true), null));
+ final BoatClass boatClass = domainFactory.getOrCreateBoatClass("ESS40");
+ DynamicTrackedRace trackedRace = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(
+ new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
+ RegattaImpl.getDefaultName("Test Regatta", boatClass.getName()), boatClass, /*startDate*/ null, /*endDate*/ null,
+ /* trackedRegattaRegistry */ null, domainFactory.createScoringScheme(ScoringSchemeType.LOW_POINT), "123", null)),
+ new RaceDefinitionImpl("Test Race",
+ new CourseImpl("Test Course", Arrays.asList(new Waypoint[] { w1, w2, w3 })),
+ boatClass, Collections.singleton(competitor)), Collections. emptyList(),
+ EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 1000,
+ /* millisecondsOverWhichToAverageWind */ 30000,
+ /* millisecondsOverWhichToAverageSpeed */ 30000, /*useMarkPassingCalculator*/ false);
+ TimePoint start = MillisecondsTimePoint.now();
+ TimePoint topMarkRounding = start.plus(30000);
+ TimePoint finish = topMarkRounding.plus(30000);
+ trackedRace.updateMarkPassings(competitor, Arrays.asList(new MarkPassing[] {
+ new MarkPassingImpl(start, w1, competitor),
+ new MarkPassingImpl(topMarkRounding, w2, competitor),
+ new MarkPassingImpl(finish, w3, competitor)
+ }));
+ assertFalse(boatClass.typicallyStartsUpwind());
+ assertNull(trackedRace.getEstimatedWindDirection(MillisecondsTimePoint.now()));
+ }
+
+ @Test
+ public void testWindAveragingBasedOnPosition() {
+ Weigher> timeWeigherThatPretendsToAlsoWeighPositions = new PositionAndTimePointWeigher(
+ /* halfConfidenceAfterMilliseconds */10000l, new MeterDistance(1000));
+ ConfidenceBasedWindAverager> averager = ConfidenceFactory.INSTANCE
+ .createWindAverager(timeWeigherThatPretendsToAlsoWeighPositions);
+ TimePoint now = MillisecondsTimePoint.now();
+ final DegreePosition p1 = new DegreePosition(0, 0);
+ WindWithConfidence> w1 = new WindWithConfidenceImpl<>(
+ new WindImpl(p1, now, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(90))),
+ /* confidence */ 1.0, new Pair(p1, now), /* useSpeed */ true);
+ final Position p2 = p1.translateGreatCircle(new DegreeBearingImpl(0), new MeterDistance(1000));
+ WindWithConfidence> w2 = new WindWithConfidenceImpl<>(
+ new WindImpl(p2, now, new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0))),
+ /* confidence */ 1.0, new Pair(p2, now), /* useSpeed */ true);
+ List>> fixes = new ArrayList<>();
+ fixes.add(w1);
+ fixes.add(w2);
+ WindWithConfidence> averageAtP1 = averager.getAverage(fixes, new Pair(p1, now));
+ WindWithConfidence> averageAtP2 = averager.getAverage(fixes, new Pair(p2, now));
+ // first careful assertion: at p1 where wind is from the west (to the east), wind should be further from the
+ // west (further to the east) than at p2 where wind is from the south (to the north).
+ final Bearing averageAtP1Bearing = averageAtP1.getObject().getBearing();
+ assertTrue(Math.abs(averageAtP1Bearing.getDifferenceTo(w1.getObject().getBearing()).getDegrees()) <
+ Math.abs(averageAtP1Bearing.getDifferenceTo(w2.getObject().getBearing()).getDegrees()));
+ // ...and vice versa
+ final Bearing averageAtP2Bearing = averageAtP2.getObject().getBearing();
+ assertTrue(Math.abs(averageAtP2Bearing.getDifferenceTo(w2.getObject().getBearing()).getDegrees()) <
+ Math.abs(averageAtP2Bearing.getDifferenceTo(w1.getObject().getBearing()).getDegrees()));
+ // expect the arithmetic average at the point which is in the middle between the two positions
+ Position middleBetweenP1AndP2 = p1.translateGreatCircle(p1.getBearingGreatCircle(p2), p1.getDistance(p2).scale(.5));
+ WindWithConfidence> averageAtMiddleBetweenP1AndP2 = averager.getAverage(fixes,
+ new Pair(middleBetweenP1AndP2, now));
+ assertEquals(15, averageAtMiddleBetweenP1AndP2.getObject().getKnots(), 0.00001);
+ assertEquals(45, averageAtMiddleBetweenP1AndP2.getObject().getBearing().getDegrees(), 0.00001);
+
+ // now try again with distance 2km and demand the difference between the position-dependent readings to be greater
+ final Position p3 = p1.translateGreatCircle(new DegreeBearingImpl(0), new MeterDistance(2000));
+ WindWithConfidence> w3 = new WindWithConfidenceImpl<>(
+ new WindImpl(p3, now, new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(0))),
+ /* confidence */ 1.0, new Pair(p3, now), /* useSpeed */ true);
+ List>> fixesFurtherApart = new ArrayList<>();
+ fixesFurtherApart.add(w1);
+ fixesFurtherApart.add(w3);
+ WindWithConfidence> averageFurtherApartAtP1 = averager.getAverage(fixesFurtherApart, new Pair(p1, now));
+ WindWithConfidence> averageAtP3 = averager.getAverage(fixesFurtherApart, new Pair(p3, now));
+ assertTrue(averageFurtherApartAtP1.getObject().getKnots() < averageAtP1.getObject().getKnots());
+ assertTrue(averageAtP3.getObject().getKnots() > averageAtP2.getObject().getKnots());
+ assertTrue(Math.abs(averageFurtherApartAtP1.getObject().getBearing().getDifferenceTo(w1.getObject().getBearing()).getDegrees())
+ < Math.abs(averageAtP1.getObject().getBearing().getDifferenceTo(w1.getObject().getBearing()).getDegrees()));
+ assertTrue(Math.abs(averageAtP3.getObject().getBearing().getDifferenceTo(w3.getObject().getBearing()).getDegrees())
+ < Math.abs(averageAtP2.getObject().getBearing().getDifferenceTo(w3.getObject().getBearing()).getDegrees()));
+ }
+}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMarkPassingTest.java
index 28ee679f364..08d53b1e61c 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMarkPassingTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMarkPassingTest.java
@@ -11,10 +11,9 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
-import java.util.LinkedHashMap;
+import java.util.HashMap;
import java.util.List;
-
-import junit.framework.Assert;
+import java.util.Map;
import org.junit.AfterClass;
@@ -28,6 +27,8 @@ import com.sap.sailing.domain.markpassingcalculation.Candidate;
import com.sap.sailing.domain.markpassingcalculation.CandidateChooser;
import com.sap.sailing.domain.markpassingcalculation.CandidateFinder;
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateChooserImpl;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateFinderImpl;
import com.sap.sailing.domain.test.OnlineTracTracBasedTest;
import com.sap.sailing.domain.test.measurements.Measurement;
import com.sap.sailing.domain.test.measurements.MeasurementCase;
@@ -45,8 +46,8 @@ import com.tractrac.subscription.lib.api.SubscriberInitializationException;
public abstract class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
- private LinkedHashMap> givenPasses = new LinkedHashMap<>();
- private ArrayList waypoints = new ArrayList<>();
+ private Map> givenPasses = new HashMap<>();
+ private List waypoints = new ArrayList<>();
private static String className;
private static String simpleName;
private static double totalPasses = 0;
@@ -59,23 +60,24 @@ public abstract class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
super();
className = getClass().getName();
simpleName = getClass().getSimpleName();
-
}
private void setUp(String raceNumber) throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
super.setUp();
- URI storedUri = new URI("file:///" + new File("resources/" + getFileName() + raceNumber + ".mtb").getCanonicalPath().replace('\\', '/'));
+ URI storedUri = new URI("file:///"
+ + new File("resources/" + getFileName() + raceNumber + ".mtb").getCanonicalPath().replace('\\', '/'));
super.setUp(new URL("file:///" + new File("resources/" + getFileName() + raceNumber + ".txt").getCanonicalPath()),
- /* liveUri */null, /* storedUri */storedUri,
- new ReceiverType[] { ReceiverType.MARKPASSINGS, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, ReceiverType.RAWPOSITIONS });
- getTrackedRace().recordWind(new WindImpl(/* position */null, MillisecondsTimePoint.now(), new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(65))),
+ /* liveUri */null, /* storedUri */storedUri, new ReceiverType[] { ReceiverType.MARKPASSINGS, ReceiverType.RACECOURSE,
+ ReceiverType.MARKPOSITIONS, ReceiverType.RAWPOSITIONS });
+ getTrackedRace().recordWind(
+ new WindImpl(/* position */null, MillisecondsTimePoint.now(), new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(65))),
new WindSourceImpl(WindSourceType.WEB));
for (Waypoint w : getRace().getCourse().getWaypoints()) {
waypoints.add(w);
}
for (Competitor c : getRace().getCompetitors()) {
- LinkedHashMap givenMarkPasses = new LinkedHashMap();
+ Map givenMarkPasses = new HashMap();
for (Waypoint wp : waypoints) {
MarkPassing markPassing = getTrackedRace().getMarkPassing(c, wp);
givenMarkPasses.put(wp, markPassing);
@@ -89,17 +91,23 @@ public abstract class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
protected void testRace(String raceNumber) throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
setUp(raceNumber);
testWholeRace();
- testMiddleOfRace(2);
testMiddleOfRace(0);
+ testMiddleOfRace(2);
}
private void testWholeRace() {
- LinkedHashMap> computedPasses = new LinkedHashMap<>();
+ Map> computedPasses = new HashMap<>();
// Get calculatedMarkPasses
long time = System.currentTimeMillis();
- final MarkPassingCalculator markPassCreator = new MarkPassingCalculator(getTrackedRace(), true);
+ new MarkPassingCalculator(getTrackedRace(), false);
time = System.currentTimeMillis() - time;
- computedPasses = markPassCreator.getAllPasses();
+
+ for (Competitor c : getRace().getCompetitors()) {
+ computedPasses.put(c, new HashMap());
+ for (Waypoint w : waypoints) {
+ computedPasses.get(c).put(w, getTrackedRace().getMarkPassing(c, w));
+ }
+ }
// Compare computed and calculated MarkPassings
final int tolerance = 10000;
@@ -113,7 +121,9 @@ public abstract class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
boolean printRight = false;
boolean printWrong = true;
- boolean printResult = false;
+ boolean printResult = true;
+
+ System.out.println(getTrackedRace().getStartOfRace());
for (Competitor c : getRace().getCompetitors()) {
numberOfCompetitors++;
@@ -145,7 +155,8 @@ public abstract class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
System.out.println("Both null" + "\n");
}
} else {
- long timeDelta = givenPasses.get(c).get(w).getTimePoint().asMillis() - computedPasses.get(c).get(w).getTimePoint().asMillis();
+ long timeDelta = givenPasses.get(c).get(w).getTimePoint().asMillis()
+ - computedPasses.get(c).get(w).getTimePoint().asMillis();
if ((Math.abs(timeDelta) < tolerance)) {
correctPasses++;
if (printRight) {
@@ -190,58 +201,58 @@ public abstract class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
incorrect += incorrectPasses;
skipped += wronglyNotComputed;
extra += wronglyComputed;
- assertTrue("Expected accuracy to be at least 0.8 but was "+accuracy, accuracy >= 0.8);
+ assertTrue("Expected accuracy to be at least 0.8 but was " + accuracy, accuracy >= 0.8);
}
- private void testMiddleOfRace(int waypoint) {
- CandidateFinder finder = new CandidateFinder(getTrackedRace());
- CandidateChooser chooser = new CandidateChooser(getTrackedRace());
+ private void testMiddleOfRace(int zeroBasedIndexOfLastWaypointToBePassed) {
+ CandidateFinder finder = new CandidateFinderImpl(getTrackedRace());
+ CandidateChooser chooser = new CandidateChooserImpl(getTrackedRace());
int mistakes = 0;
- Waypoint start = waypoints.get(waypoint);
- Waypoint second = waypoints.get(waypoint + 1);
+ Waypoint lastWaypointToBePassed = waypoints.get(zeroBasedIndexOfLastWaypointToBePassed);
+ Waypoint wayPointAfterwards = waypoints.get(zeroBasedIndexOfLastWaypointToBePassed + 1);
for (Competitor c : getRace().getCompetitors()) {
- TimePoint startTime;
- TimePoint secondPass;
- if (givenPasses.get(c).get(start) != null && givenPasses.get(c).get(second) != null) {
- startTime = givenPasses.get(c).get(start).getTimePoint();
- secondPass = givenPasses.get(c).get(second).getTimePoint();
- TimePoint delta = new MillisecondsTimePoint(startTime.plus(secondPass.asMillis()).asMillis() / 2);
- List fixes = new ArrayList();
- try {
- getTrackedRace().getTrack(c).lockForRead();
- for (GPSFixMoving fix : getTrackedRace().getTrack(c).getFixes()) {
- if (fix.getTimePoint().before(delta)) {
- fixes.add(fix);
+ MarkPassing markPassingAfter = givenPasses.get(c).get(wayPointAfterwards);
+ if (markPassingAfter != null) {
+ if (givenPasses.get(c).get(lastWaypointToBePassed) != null && givenPasses.get(c).get(wayPointAfterwards) != null) {
+ TimePoint beforeNextPassing = markPassingAfter.getTimePoint().minus(20000);
+ List fixes = new ArrayList();
+ try {
+ getTrackedRace().getTrack(c).lockForRead();
+ for (GPSFixMoving fix : getTrackedRace().getTrack(c).getFixes()) {
+ if (fix.getTimePoint().before(beforeNextPassing)) {
+ fixes.add(fix);
+ }
+ }
+ } finally {
+ getTrackedRace().getTrack(c).unlockAfterRead();
+ }
+ Util.Pair, Iterable> f = finder.getCandidateDeltas(c, fixes);
+ chooser.calculateMarkPassDeltas(c, f.getA(), f.getB());
+ boolean gotPassed = true;
+ boolean gotOther = false;
+ System.out.println(c);
+ for (Waypoint w : getRace().getCourse().getWaypoints()) {
+ MarkPassing old = givenPasses.get(c).get(w);
+ MarkPassing newm = getTrackedRace().getMarkPassing(c, w);
+ System.out.println(newm);
+ if (waypoints.indexOf(w) <= zeroBasedIndexOfLastWaypointToBePassed) {
+ if ((old == null) != (newm == null)) {
+ gotPassed = false;
+ }
+ } else {
+ if (w != wayPointAfterwards && newm != null) {
+ gotOther = true;
+ }
}
}
- } finally {
- getTrackedRace().getTrack(c).unlockAfterRead();
- }
- Util.Pair, Iterable> f = finder.getCandidateDeltas(c, fixes);
- chooser.calculateMarkPassDeltas(c, f);
- boolean gotPassed = true;
- boolean gotOther = false;
- // System.out.println(c);
- for (Waypoint w : getRace().getCourse().getWaypoints()) {
- MarkPassing old = givenPasses.get(c).get(w);
- MarkPassing newm = getTrackedRace().getMarkPassing(c, w);
- // System.out.println(newm);
- if (waypoints.indexOf(w) <= waypoint) {
- if ((old == null) != (newm == null)) {
- gotPassed = false;
- }
- } else {
- if (newm != null) {
- gotOther = true;
- }
+ if (!gotPassed || gotOther) {
+ mistakes++;
}
}
- if (!gotPassed || gotOther) {
- mistakes++;
- }
}
}
- Assert.assertTrue(mistakes == 0);
+ assertEquals(0, mistakes);
+
}
@AfterClass
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java
index 30ce75475d8..b41aa583c8a 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java
@@ -1,95 +1,79 @@
-package com.sap.sailing.domain.test.markpassing;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-import java.util.UUID;
-
-import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.base.ControlPointWithTwoMarks;
-import com.sap.sailing.domain.base.Course;
-import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.base.RaceDefinition;
-import com.sap.sailing.domain.base.Regatta;
-import com.sap.sailing.domain.base.Sideline;
-import com.sap.sailing.domain.base.Waypoint;
-import com.sap.sailing.domain.base.impl.BoatClassImpl;
-import com.sap.sailing.domain.base.impl.CompetitorImpl;
-import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl;
-import com.sap.sailing.domain.base.impl.CourseAreaImpl;
-import com.sap.sailing.domain.base.impl.CourseImpl;
-import com.sap.sailing.domain.base.impl.FleetImpl;
-import com.sap.sailing.domain.base.impl.MarkImpl;
-import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
-import com.sap.sailing.domain.base.impl.RegattaImpl;
-import com.sap.sailing.domain.base.impl.SeriesImpl;
-import com.sap.sailing.domain.base.impl.WaypointImpl;
-import com.sap.sailing.domain.common.PassingInstruction;
-import com.sap.sailing.domain.common.Position;
-import com.sap.sailing.domain.common.SpeedWithBearing;
-import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
-import com.sap.sailing.domain.common.impl.DegreePosition;
-import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
-import com.sap.sailing.domain.leaderboard.impl.HighPoint;
-import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
-import com.sap.sailing.domain.tracking.DynamicTrackedRace;
-import com.sap.sailing.domain.tracking.GPSFixMoving;
-import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
-import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
-import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
-import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
-import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
-import com.sap.sse.common.TimePoint;
-import com.sap.sse.common.Util;
-import com.sap.sse.common.impl.MillisecondsTimePoint;
-
-public class AbstractMockedRaceMarkPassingTest {
- protected Competitor bob = new CompetitorImpl("Bob", "Bob", null, null, null, null);
- protected Competitor joe = new CompetitorImpl("Joe", "Joe", null, null, null, null);
- protected Competitor mike = new CompetitorImpl("Mike", "Mike", null, null, null, null);
-
- protected Mark m = new MarkImpl("black");
- protected Mark m2 = new MarkImpl("white 1");
- protected Mark m3 = new MarkImpl("white 2");
-
- protected List waypoints = new ArrayList<>();
- protected DynamicTrackedRace trackedRace;
- protected long time;
- protected Random rnd = new Random();
-
- public AbstractMockedRaceMarkPassingTest() {
- ControlPointWithTwoMarks cp = new ControlPointWithTwoMarksImpl(m2, m3, "cp");
- Waypoint w1 = new WaypointImpl(cp, PassingInstruction.Line);
- Waypoint w2 = new WaypointImpl(m, PassingInstruction.Port);
- Waypoint w3 = new WaypointImpl(cp, PassingInstruction.Line);
- final BoatClassImpl boatClass = new BoatClassImpl("boat", true);
- Regatta r = new RegattaImpl(RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
- /*startDate*/ null, /*endDate*/ null, Arrays.asList(new SeriesImpl("Series", true, Arrays.asList(new FleetImpl("fleet")),
- new ArrayList(), null)), true, new HighPoint(), "ID", new CourseAreaImpl("area", new UUID(5, 5)));
- Course course = new CourseImpl("course", Arrays.asList(w1, w2, w3));
- RaceDefinition race = new RaceDefinitionImpl("Performance Race", course, boatClass, Arrays.asList(bob));
- trackedRace = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(r), race, new ArrayList(), new EmptyWindStore(), EmptyGPSFixStore.INSTANCE, 0, 10000, 10000);
- trackedRace.setStartTimeReceived(new MillisecondsTimePoint(System.currentTimeMillis() - 120000));
- List tps = Arrays.asList(new MillisecondsTimePoint(System.currentTimeMillis()), new MillisecondsTimePoint(System.currentTimeMillis() - 30000),
- new MillisecondsTimePoint(System.currentTimeMillis() + 30000));
- List> pos = Arrays.asList(new Util.Pair(m, new DegreePosition(0, 0)), new Util.Pair(m2, new DegreePosition(-0.001, -0.00005)),
- new Util.Pair(m3, new DegreePosition(-0.001, 0.00005)));
- for (Util.Pair pair : pos) {
- for (TimePoint t : tps) {
- trackedRace.recordFix(pair.getA(), new GPSFixImpl(pair.getB(), t));
- }
- }
- for (Waypoint w : trackedRace.getRace().getCourse().getWaypoints()) {
- waypoints.add(w);
- }
- }
-
- protected GPSFixMoving rndFix() {
- DegreePosition position = new DegreePosition(37.8878 + rnd.nextDouble() * 0.0019, -122.268 - rnd.nextDouble() * 0.012);
- TimePoint p = new MillisecondsTimePoint((long) (System.currentTimeMillis() - 300000 + (Math.random() * (7800000))));
- SpeedWithBearing speed = new KnotSpeedWithBearingImpl(rnd.nextInt(11), new DegreeBearingImpl(rnd.nextInt(360)));
-
- return new GPSFixMovingImpl(position, p, speed);
- }
-}
+package com.sap.sailing.domain.test.markpassing;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import com.sap.sailing.domain.base.Competitor;
+import com.sap.sailing.domain.base.ControlPointWithTwoMarks;
+import com.sap.sailing.domain.base.Course;
+import com.sap.sailing.domain.base.Mark;
+import com.sap.sailing.domain.base.RaceDefinition;
+import com.sap.sailing.domain.base.Regatta;
+import com.sap.sailing.domain.base.Sideline;
+import com.sap.sailing.domain.base.Waypoint;
+import com.sap.sailing.domain.base.impl.BoatClassImpl;
+import com.sap.sailing.domain.base.impl.CompetitorImpl;
+import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl;
+import com.sap.sailing.domain.base.impl.CourseAreaImpl;
+import com.sap.sailing.domain.base.impl.CourseImpl;
+import com.sap.sailing.domain.base.impl.FleetImpl;
+import com.sap.sailing.domain.base.impl.MarkImpl;
+import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
+import com.sap.sailing.domain.base.impl.RegattaImpl;
+import com.sap.sailing.domain.base.impl.SeriesImpl;
+import com.sap.sailing.domain.base.impl.WaypointImpl;
+import com.sap.sailing.domain.common.PassingInstruction;
+import com.sap.sailing.domain.common.Position;
+import com.sap.sailing.domain.common.impl.DegreePosition;
+import com.sap.sailing.domain.leaderboard.impl.HighPoint;
+import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
+import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
+import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
+import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
+import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
+import com.sap.sse.common.TimePoint;
+import com.sap.sse.common.Util;
+import com.sap.sse.common.impl.MillisecondsTimePoint;
+
+public class AbstractMockedRaceMarkPassingTest {
+ protected Competitor ron = new CompetitorImpl("Ron", "Ron", null, null, null, null);
+ protected Competitor tom = new CompetitorImpl("Tom", "Tom", null, null, null, null);
+ protected Competitor ben = new CompetitorImpl("Ben", "Ben", null, null, null, null);
+
+ protected Mark m = new MarkImpl("Mark");
+ protected Mark gate1 = new MarkImpl("Gate1");
+ protected Mark gate2 = new MarkImpl("Gate2");
+ protected Mark reaching = new MarkImpl("Reaching");
+
+ protected List waypoints = new ArrayList<>();
+
+ protected DynamicTrackedRace race;
+
+ public AbstractMockedRaceMarkPassingTest() {
+ ControlPointWithTwoMarks cp = new ControlPointWithTwoMarksImpl(gate1, gate2, "cp");
+
+ Waypoint w1 = new WaypointImpl(cp, PassingInstruction.Line);
+ Waypoint w2 = new WaypointImpl(m, PassingInstruction.Port);
+ Waypoint w3 = new WaypointImpl(cp, PassingInstruction.Gate);
+ Waypoint w4 = new WaypointImpl(m, PassingInstruction.Starboard);
+ Waypoint w5 = new WaypointImpl(cp, PassingInstruction.Line);
+ waypoints = Arrays.asList(w1, w2, w3, w4, w5);
+ final BoatClassImpl boatClass = new BoatClassImpl("boat", true);
+ Regatta r = new RegattaImpl(RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
+ /*startDate*/ null, /*endDate*/ null, Arrays.asList(new SeriesImpl("Series", true, Arrays.asList(new FleetImpl("fleet")),
+ new ArrayList(), null)), true, new HighPoint(), "ID", new CourseAreaImpl("area", new UUID(5, 5)));
+ Course course = new CourseImpl("course", waypoints);
+ RaceDefinition raceDef = new RaceDefinitionImpl("Performance Race", course, boatClass, Arrays.asList(ron, tom, ben));
+ race = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(r), raceDef, new ArrayList(), new EmptyWindStore(), EmptyGPSFixStore.INSTANCE, 0, 10000, 10000, /*useMarkPassingCalculator*/ false);
+ race.setStartTimeReceived(new MillisecondsTimePoint(10000));
+ TimePoint t = new MillisecondsTimePoint(30000);
+ List> pos = Arrays.asList(new Util.Pair(m, new DegreePosition(0, 0)),
+ new Util.Pair(gate1, new DegreePosition(-0.001, -0.00005)), new Util.Pair(gate2, new DegreePosition(-0.001, 0.00005)), new Util.Pair(reaching, new DegreePosition(-0.0005, -0.0005)));
+ for (Util.Pair pair : pos) {
+ race.recordFix(pair.getA(), new GPSFixImpl(pair.getB(), t));
+ }
+ }
+}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/CandidateFinderTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/CandidateFinderTest.java
deleted file mode 100755
index 4074acf5ef2..00000000000
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/CandidateFinderTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.sap.sailing.domain.test.markpassing;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-
-import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
-import com.sap.sailing.domain.common.impl.DegreePosition;
-import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
-import com.sap.sailing.domain.markpassingcalculation.CandidateFinder;
-import com.sap.sailing.domain.tracking.GPSFix;
-import com.sap.sailing.domain.tracking.GPSFixMoving;
-import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
-import com.sap.sse.common.Util;
-import com.sap.sse.common.impl.MillisecondsTimePoint;
-
-public class CandidateFinderTest extends AbstractMockedRaceMarkPassingTest {
-
- @Test
- public void test() {
- GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(0.000003,0.000049),
- new MillisecondsTimePoint(System.currentTimeMillis() - 2000), new KnotSpeedWithBearingImpl(5,
- new DegreeBearingImpl(330)));
- GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0.000062,0.000029),
- new MillisecondsTimePoint(System.currentTimeMillis()), new KnotSpeedWithBearingImpl(5,
- new DegreeBearingImpl(270)));
- GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0.000026,-0.000024),
- new MillisecondsTimePoint(System.currentTimeMillis() + 2000), new KnotSpeedWithBearingImpl(5,
- new DegreeBearingImpl(225)));
- GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(-0.000056,-0.000049),
- new MillisecondsTimePoint(System.currentTimeMillis() + 4000), new KnotSpeedWithBearingImpl(5,
- new DegreeBearingImpl(190)));
- trackedRace.recordFix(bob, fix1);
- trackedRace.recordFix(bob, fix2);
- CandidateFinder finder = new CandidateFinder(trackedRace);
- List fixes = new ArrayList();
- fixes.add(fix1);
- fixes.add(fix2);
- assertEquals(0, Util.size(finder.getCandidateDeltas(bob, fixes).getA()));
-
- trackedRace.recordFix(bob, fix3);
- fixes.clear();
- fixes.add(fix3);
- assertEquals(1, Util.size(finder.getCandidateDeltas(bob, fixes).getA())); // CTE candidate
-
- trackedRace.recordFix(bob, fix4);
- fixes.clear();
- fixes.add(fix4);
- assertEquals(1, Util.size(finder.getCandidateDeltas(bob, fixes).getA())); // Distance Candidate
- }
-}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/FlorianopolisMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/FlorianopolisMarkPassingTest.java
index fecd9da93f9..6703e5326ee 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/FlorianopolisMarkPassingTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/FlorianopolisMarkPassingTest.java
@@ -17,70 +17,107 @@ public class FlorianopolisMarkPassingTest extends AbstractMarkPassingTest {
}
@Test
- public void testRace1() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
+ public void testRace3() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
testRace("3");
}
@Test
- public void testRace4() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
+ public void testRace4() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
testRace("4");
}
- /*
- * Test ignored on master branch to quicken the hudson build.
- *
- * @Test public void testRace1() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("1"); }
- *
- * @Test public void testRace2() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("2"); }
- *
- * @Test public void testRace5() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("5"); }
- *
- * @Test public void testRace6() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("6"); }
- *
- * @Test public void testRace7() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("7"); }
- *
- * @Test public void testRace8() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("8"); }
- *
- * @Test public void testRace10() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("10"); }
- *
- * @Test public void testRace11() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("11"); }
- *
- * @Test public void testRace12() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("12"); }
- *
- * @Test public void testRace13() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("13"); }
- *
- * @Test public void testRace14() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("14"); }
- *
- * @Test public void testRace16() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("16"); }
- *
- * @Test public void testRace17() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("17"); }
- *
- * @Test public void testRace19() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("19"); }
- *
- * @Test public void testRace22() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("22"); }
- *
- * @Test public void testRace24() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("24"); }
- */
+ @Test
+ public void testRace1() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("1");
+ }
+
+ @Test
+ public void testRace2() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("2");
+ }
+
+ @Test
+ public void testRace5() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("5");
+ }
+
+ @Test
+ public void testRace6() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("6");
+ }
+
+ @Test
+ public void testRace7() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("7");
+ }
+
+ @Test
+ public void testRace8() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("8");
+ }
+
+ @Test
+ public void testRace10() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("10");
+ }
+
+ @Test
+ public void testRace11() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("11");
+ }
+
+ @Test
+ public void testRace12() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("12");
+ }
+
+ @Test
+ public void testRace13() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("13");
+ }
+
+ @Test
+ public void testRace17() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("17");
+ }
+
+ @Test
+ public void testRace19() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("19");
+ }
+
+ @Test
+ public void testRace22() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("22");
+ }
+
+ @Test
+ public void testRace24() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("24");
+ }
/*
* Alinghi acting wierd
*
+ * @Test public void testRace14() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ * SubscriberInitializationException, CreateModelException { testRace("14"); }
+ *
* @Test public void testRace23() throws IOException, InterruptedException, URISyntaxException { testRace(23); }
*/
@@ -90,6 +127,13 @@ public class FlorianopolisMarkPassingTest extends AbstractMarkPassingTest {
* @Test public void testRace18() throws IOException, InterruptedException, URISyntaxException { testRace("18"); }
*/
+ /*
+ * Fails in Hudson...
+ *
+ * @Test public void testRace16() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ * SubscriberInitializationException, CreateModelException { testRace("16"); }
+ */
+
/*
* All mark data seems to be missing
*
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/KW470MarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/KW470MarkPassingTest.java
index 0642f5afb04..b0b1f4af49a 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/KW470MarkPassingTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/KW470MarkPassingTest.java
@@ -17,19 +17,22 @@ public class KW470MarkPassingTest extends AbstractMarkPassingTest {
}
@Test
- public void testRace4() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
+ public void testRace4() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
testRace("4");
}
- /*
- * Ignored on master branch
- *
- * @Test public void testRace5() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("5"); }
- *
- * @Test public void testRace6() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("6"); }
- */
+ @Test
+ public void testRace5() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("5");
+ }
+
+ @Test
+ public void testRace6() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("6");
+ }
@Override
protected String getFileName() {
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/Kiel2011505MarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/Kiel2011505MarkPassingTest.java
index 3d3d22ce26c..3cc40b64aa6 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/Kiel2011505MarkPassingTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/Kiel2011505MarkPassingTest.java
@@ -16,6 +16,8 @@ public class Kiel2011505MarkPassingTest extends AbstractMarkPassingTest {
super();
}
+ // The Start-Times are set very wrong on these races
+
@Ignore
public void testRace2() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
testRace("2");
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/Kiel2013505Test.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/Kiel2013505Test.java
index 65efcb3ebbc..9844a4266f7 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/Kiel2013505Test.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/Kiel2013505Test.java
@@ -5,7 +5,7 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.text.ParseException;
-import org.junit.Ignore;
+import org.junit.Test;
import com.tractrac.model.lib.api.event.CreateModelException;
import com.tractrac.subscription.lib.api.SubscriberInitializationException;
@@ -16,12 +16,13 @@ public class Kiel2013505Test extends AbstractMarkPassingTest {
super();
}
- @Ignore
+ //Takes longer than 2 minutes, so the rule in AbstractTracTracLiveTest needs to be deactivated first.
+
+ @Test
public void testRace5() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
testRace("5");
}
-
@Override
protected String getFileName() {
return "event_20130626_KielerWoch-505_race_";
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingCalculatorPerformanceTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingCalculatorPerformanceTest.java
index 0d3e0ac9bbe..3ac56b61333 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingCalculatorPerformanceTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingCalculatorPerformanceTest.java
@@ -13,14 +13,22 @@ import junit.framework.Assert;
import org.junit.AfterClass;
import org.junit.Test;
+import com.sap.sailing.domain.common.SpeedWithBearing;
+import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
+import com.sap.sailing.domain.common.impl.DegreePosition;
+import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.markpassingcalculation.Candidate;
-import com.sap.sailing.domain.markpassingcalculation.CandidateChooser;
import com.sap.sailing.domain.markpassingcalculation.CandidateFinder;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateChooserImpl;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateFinderImpl;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateImpl;
import com.sap.sailing.domain.test.measurements.Measurement;
import com.sap.sailing.domain.test.measurements.MeasurementCase;
import com.sap.sailing.domain.test.measurements.MeasurementXMLFile;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
+import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
+import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -47,49 +55,57 @@ public class MarkPassingCalculatorPerformanceTest extends AbstractMockedRaceMark
@Test
public void testFinder() {
- CandidateFinder f = new CandidateFinder(trackedRace);
+ CandidateFinder f = new CandidateFinderImpl(race);
List fixesAdded = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
GPSFixMoving fix = rndFix();
- trackedRace.recordFix(bob, fix);
+ race.recordFix(ron, fix);
fixesAdded.add(fix);
}
time = System.currentTimeMillis();
- f.getCandidateDeltas(bob, fixesAdded);
+ f.getCandidateDeltas(ron, fixesAdded);
time = System.currentTimeMillis() - time;
result.put("FinderPerformance", time);
System.out.println(time);
- Assert.assertTrue(time < 3000);
+ Assert.assertTrue(time < 5000);
}
@Test
public void testChooser() {
- long time = timeToAddCandidatesToChooser(100, 1, 25);
+ long time = timeToAddCandidatesToChooser(500, 1, 25);
System.out.println(time);
result.put("ChooserPerformance", time);
- assertTrue(time < 2000);
+ assertTrue(time < 5000);
}
private long timeToAddCandidatesToChooser(int numberOfTimesAdding, int numberToAddEachTime, int numberOfRepititions) {
long totalTime = 0;
for (int i = 0; i < numberOfRepititions; i++) {
- CandidateChooser c = new CandidateChooser(trackedRace);
+ CandidateChooserImpl c = new CandidateChooserImpl(race);
for (int j = 0; j < numberOfTimesAdding; j++) {
List newCandidates = new ArrayList<>();
for (int k = 0; k < numberToAddEachTime; k++) {
newCandidates.add(randomCan());
}
time = System.currentTimeMillis();
- c.calculateMarkPassDeltas(bob, new Util.Pair, Iterable>(newCandidates, new ArrayList()));
+ c.calculateMarkPassDeltas(ron, newCandidates, new ArrayList());
totalTime += System.currentTimeMillis() - time;
}
}
return totalTime / numberOfRepititions;
}
- private Candidate randomCan() {
+ private CandidateImpl randomCan() {
int id = rnd.nextInt(3);
- return new Candidate(id + 1, new MillisecondsTimePoint((long) (rnd.nextDouble() * 200000)),
- 0.5 + 0.5 * rnd.nextDouble(), Util.get(trackedRace.getRace().getCourse().getWaypoints(), id), true, true, null);
+ return new CandidateImpl(id + 1, new MillisecondsTimePoint((long) (rnd.nextDouble() * 200000)),
+ 0.5 + 0.5 * rnd.nextDouble(), Util.get(race.getRace().getCourse().getWaypoints(), id));
+ }
+
+ private GPSFixMoving rndFix() {
+ DegreePosition position = new DegreePosition(0.001 - rnd.nextDouble() * 0.001,
+ 0.0002 - rnd.nextDouble() * 0.0004);
+ TimePoint p = new MillisecondsTimePoint((long) (rnd.nextDouble() * 200000));
+ SpeedWithBearing speed = new KnotSpeedWithBearingImpl(rnd.nextInt(11), new DegreeBearingImpl(rnd.nextInt(360)));
+ return new GPSFixMovingImpl(position, p, speed);
}
}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingWhiteBoxTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingWhiteBoxTest.java
new file mode 100755
index 00000000000..b9a7bf7df93
--- /dev/null
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/MarkPassingWhiteBoxTest.java
@@ -0,0 +1,305 @@
+package com.sap.sailing.domain.test.markpassing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NavigableSet;
+
+import org.junit.Test;
+
+import com.sap.sailing.domain.base.Course;
+import com.sap.sailing.domain.base.Waypoint;
+import com.sap.sailing.domain.base.impl.WaypointImpl;
+import com.sap.sailing.domain.common.PassingInstruction;
+import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
+import com.sap.sailing.domain.common.impl.DegreePosition;
+import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
+import com.sap.sailing.domain.markpassingcalculation.Candidate;
+import com.sap.sailing.domain.markpassingcalculation.CandidateChooser;
+import com.sap.sailing.domain.markpassingcalculation.CandidateFinder;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateChooserImpl;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateFinderImpl;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateImpl;
+import com.sap.sailing.domain.tracking.GPSFix;
+import com.sap.sailing.domain.tracking.GPSFixMoving;
+import com.sap.sailing.domain.tracking.MarkPassing;
+import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
+import com.sap.sse.common.Util;
+import com.sap.sse.common.impl.MillisecondsTimePoint;
+
+/**
+ * Tests tricky situation that can fail easily. Created with help of http://itouchmap.com/latlong.html
+ *
+ */
+public class MarkPassingWhiteBoxTest extends AbstractMockedRaceMarkPassingTest {
+
+ @Test
+ public void testNormalPassingAndSuppressingPassings() {
+ // Normal Passing of Single mark
+ GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(0.000003, 0.000049), new MillisecondsTimePoint(
+ 40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)));
+ GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0.000062, 0.000029), new MillisecondsTimePoint(
+ 44000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(270)));
+ GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0.000026, -0.000024), new MillisecondsTimePoint(
+ 47000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(225)));
+ GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(-0.000056, -0.000049), new MillisecondsTimePoint(
+ 50000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(190)));
+ race.recordFix(ron, fix1);
+ race.recordFix(ron, fix2);
+ CandidateFinder finder = new CandidateFinderImpl(race);
+ CandidateChooser chooser = new CandidateChooserImpl(race);
+ List fixes = new ArrayList();
+ fixes.add(fix1);
+ fixes.add(fix2);
+ Util.Pair, Iterable> candidateDeltas = finder.getCandidateDeltas(ron, fixes);
+ assertEquals(0, Util.size(candidateDeltas.getA()));
+ chooser.calculateMarkPassDeltas(ron, candidateDeltas.getA(), candidateDeltas.getB());
+
+ race.recordFix(ron, fix3);
+ fixes.clear();
+ fixes.add(fix3);
+ candidateDeltas = finder.getCandidateDeltas(ron, fixes);
+ assertEquals(2, Util.size(candidateDeltas.getA())); // CTE candidate
+ chooser.calculateMarkPassDeltas(ron, candidateDeltas.getA(), candidateDeltas.getB());
+
+
+ race.recordFix(ron, fix4);
+ fixes.clear();
+ fixes.add(fix4);
+ candidateDeltas = finder.getCandidateDeltas(ron, fixes);
+ assertEquals(2, Util.size(candidateDeltas.getA())); // Distance Candidate
+ chooser.calculateMarkPassDeltas(ron, candidateDeltas.getA(), candidateDeltas.getB());
+
+ NavigableSet markPassings = race.getMarkPassings(ron);
+ assertEquals(1, markPassings.size());
+ chooser.suppressMarkPassings(ron, 1);
+ NavigableSet markPassingsAfterSupressing = race.getMarkPassings(ron);
+ assertEquals(0, markPassingsAfterSupressing.size());
+
+ }
+
+ @Test
+ public void testDistance() {
+ // 3 fixes all on one side of crossing Bearing, therefore no XTE-Candidate
+ GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.000155, 0.000103), new MillisecondsTimePoint(
+ 60000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)));
+ GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0.000038, 0.000021), new MillisecondsTimePoint(
+ 65000), new KnotSpeedWithBearingImpl(4, new DegreeBearingImpl(280)));
+ GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(-0.000268, 0.000135), new MillisecondsTimePoint(
+ 80000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(170)));
+ CandidateFinderImpl finder = new CandidateFinderImpl(race);
+
+ race.recordFix(tom, fix1);
+ race.recordFix(tom, fix3);
+ List fixes = new ArrayList<>();
+ fixes.add(fix1);
+ fixes.add(fix3);
+ Util.Pair, Iterable> cans = finder.getCandidateDeltas(tom, fixes);
+ assertEquals(Util.size(cans.getA()), 0);
+ assertEquals(Util.size(cans.getB()), 0);
+
+ fixes.clear();
+ race.recordFix(tom, fix2);
+ fixes.add(fix2);
+ cans = finder.getCandidateDeltas(tom, fixes);
+ assertEquals(Util.size(cans.getA()), 2); // 2 Distance candidates (mark is rounded twice in course)
+ Double probability = cans.getA().iterator().next().getProbability();
+ assertTrue(probability > 0.5 && probability < 0.8); // Close but distance candidate
+ assertEquals(Util.size(cans.getB()), 0);
+ }
+
+ @Test
+ public void testPastGate() {
+ // Competitor sails closely past one mark of gate and rounds the other mark further away
+ GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.000967, -0.000124), new MillisecondsTimePoint(
+ 100000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(100)));
+ GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.000989, -0.000001), new MillisecondsTimePoint(
+ 110000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(160)));
+ GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(-0.001079, 0.000045), new MillisecondsTimePoint(
+ 115000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)));
+ GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(-0.000982, 0.000143), new MillisecondsTimePoint(
+ 125000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)));
+ CandidateFinderImpl finder = new CandidateFinderImpl(race);
+ race.recordFix(tom, fix1);
+ race.recordFix(tom, fix2);
+ List fixes = new ArrayList<>();
+ fixes.addAll(Arrays.asList(fix1, fix2));
+ Util.Pair, Iterable> cans = finder.getCandidateDeltas(tom, fixes);
+ Double inFront = cans.getA().iterator().next().getProbability();
+ assertTrue(Util.size(cans.getA()) == 1);
+ // Passing of one mark, close but wrong side and direction
+ assertEquals(Util.size(cans.getB()), 0);
+
+ race.recordFix(tom, fix3);
+ fixes.clear();
+ fixes.add(fix3);
+ cans = finder.getCandidateDeltas(tom, fixes);
+ assertEquals(5, Util.size(cans.getA()));
+ assertEquals(Util.size(cans.getB()), 0);
+
+ race.recordFix(tom, fix4);
+ fixes.clear();
+ fixes.add(fix4);
+ cans = finder.getCandidateDeltas(tom, fixes);
+ assertEquals(Util.size(cans.getB()), 0);
+ for (Candidate c : cans.getA()) {
+ if (c.getOneBasedIndexOfWaypoint() == 3) {
+ assertTrue(c.getProbability() > inFront);
+ // Passing of correct mark with greater distance
+ }
+ }
+ }
+
+ @Test
+ public void testGateAfterLine() {
+ // The problem of passing a gate right after the start line is crossed, solved by the distance estimation
+ GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.001051, -0.000008), new MillisecondsTimePoint(
+ 10000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(5)));
+ GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.000942, 0.000022), new MillisecondsTimePoint(
+ 14000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(15)));
+ race.recordFix(tom, fix1);
+ race.recordFix(tom, fix2);
+ Candidate c1 = new CandidateImpl(1, new MillisecondsTimePoint(11000), 0.99, waypoints.get(0));
+ Candidate c3 = new CandidateImpl(3, new MillisecondsTimePoint(13000), 0.99, waypoints.get(2));
+ // Good candidate but bad time
+ CandidateChooser chooser = new CandidateChooserImpl(race);
+ chooser.calculateMarkPassDeltas(tom, Arrays.asList(c1, c3), new ArrayList());
+ NavigableSet markPassings = race.getMarkPassings(tom);
+ assertEquals(markPassings.size(), 1);
+ assertEquals(markPassings.first().getWaypoint(), waypoints.get(0));
+ }
+
+ @Test
+ public void testVerySlowCompetitor() {
+ // TODO
+ }
+
+ @Test
+ public void testSailingInFrontAndAroundMark() {
+ CandidateFinder finder = new CandidateFinderImpl(race);
+ GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.000037, -0.000126), new MillisecondsTimePoint(
+ 40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(80)));
+ GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.000022, 0.000001), new MillisecondsTimePoint(
+ 43000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)));
+ GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0.000018, 0.000038), new MillisecondsTimePoint(
+ 46000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)));
+ GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(0.000084, -0.000004), new MillisecondsTimePoint(
+ 49000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(260)));
+ GPSFixMoving fix5 = new GPSFixMovingImpl(new DegreePosition(0.000054, -0.000153), new MillisecondsTimePoint(
+ 52000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(200)));
+ race.recordFix(ben, fix1);
+ race.recordFix(ben, fix2);
+ race.recordFix(ben, fix3);
+ List fixes = new ArrayList<>();
+ fixes.addAll(Arrays.asList(fix1, fix2, fix3));
+ Util.Pair, Iterable> cans = finder.getCandidateDeltas(ben, fixes);
+ Candidate inFront = Util.get(cans.getA(), 0);
+ race.recordFix(ben, fix4);
+ race.recordFix(ben, fix5);
+ fixes.clear();
+ fixes.addAll(Arrays.asList(fix4, fix5));
+ cans = finder.getCandidateDeltas(ben, fixes);
+ Candidate behind = Util.get(cans.getA(), 0);
+ assertTrue(behind.getProbability() > inFront.getProbability());
+ }
+
+ public void fixAndUnfixMarkPassing() {
+ GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.001027, -0.000001), new MillisecondsTimePoint(
+ 11000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(340)));
+ GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.000396, -0.000602), new MillisecondsTimePoint(
+ 35000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(315)));
+ GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0.000164, -0.000012), new MillisecondsTimePoint(
+ 60000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)));
+ GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(-0.000402, 0.00043), new MillisecondsTimePoint(
+ 85000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(135)));
+ GPSFixMoving fix5 = new GPSFixMovingImpl(new DegreePosition(-0.001027, -0.000001), new MillisecondsTimePoint(
+ 115000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)));
+
+ race.recordFix(tom, fix1);
+ race.recordFix(tom, fix2);
+ race.recordFix(tom, fix3);
+ race.recordFix(tom, fix4);
+ race.recordFix(tom, fix5);
+
+ CandidateChooser chooser = new CandidateChooserImpl(race);
+ Iterable waypoints = race.getRace().getCourse().getWaypoints();
+ Candidate c0 = new CandidateImpl(1, new MillisecondsTimePoint(12000), 1, Util.get(waypoints, 0));
+ Waypoint waypointToSet = Util.get(waypoints, 1);
+ Candidate c1 = new CandidateImpl(2, new MillisecondsTimePoint(60000), 1, waypointToSet);
+ Candidate c2 = new CandidateImpl(3, new MillisecondsTimePoint(110000), 1, Util.get(waypoints, 2));
+
+ chooser.calculateMarkPassDeltas(tom, Arrays.asList(c0, c1, c2), new ArrayList());
+
+ NavigableSet markPassingsBeforeFixing = race.getMarkPassings(tom);
+ MarkPassing markPassingBeforeAdding = Util.get(markPassingsBeforeFixing, 1);
+ assertTrue(markPassingBeforeAdding.getTimePoint().asMillis() == 60000);
+
+ chooser.setFixedPassing(tom, 1, new MillisecondsTimePoint(58000));
+
+ NavigableSet markPassingsAfterFixing = race.getMarkPassings(tom);
+ MarkPassing markPassingAfterAdding = Util.get(markPassingsAfterFixing, 1);
+ assertTrue(markPassingAfterAdding.getTimePoint().asMillis() == 58000);
+
+ chooser.setFixedPassing(tom, 1, new MillisecondsTimePoint(59000));
+
+ NavigableSet markPassingsAfterSecondFixing = race.getMarkPassings(tom);
+ MarkPassing markPassingAfterSecondAdding = Util.get(markPassingsAfterSecondFixing, 1);
+ assertTrue(markPassingAfterSecondAdding.getTimePoint().asMillis() == 59000);
+
+ chooser.removeFixedPassing(tom, 1);
+
+ NavigableSet markPassingsAfterRemoving = race.getMarkPassings(tom);
+ MarkPassing markPassingAfterRemoving = Util.get(markPassingsAfterRemoving, 1);
+ assertTrue(markPassingAfterRemoving.getTimePoint().asMillis() == 60000);
+ }
+
+ @Test
+ public void testAddingAndRemovingWaypointToFinder() {
+ GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.00045, -0.00052), new MillisecondsTimePoint(
+ 40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(200)));
+ GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.0006, -0.00052),
+ new MillisecondsTimePoint(44000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(160)));
+
+ race.recordFix(ron, fix1);
+ race.recordFix(ron, fix2);
+
+ CandidateFinder finder = new CandidateFinderImpl(race);
+ Waypoint newWaypoint = new WaypointImpl(reaching, PassingInstruction.Port);
+ Course course = race.getRace().getCourse();
+
+ // Before adding
+ Util.Pair, Iterable> allCandidatesBefore = finder.getAllCandidates(ron);
+ assertEquals(Util.size(allCandidatesBefore.getB()), 0);
+ assertEquals(Util.size(allCandidatesBefore.getA()), 0);
+
+ // The process of adding
+ course.addWaypoint(4, newWaypoint);
+ Util.Pair, List> addedCans = finder.updateWaypoints(Arrays.asList(newWaypoint), new ArrayList(), 4).get(ron);
+ assertEquals(Util.size(addedCans.getA()), 1);
+ for (Candidate c : addedCans.getA()) {
+ assertEquals(c.getWaypoint(), newWaypoint);
+ }
+
+ // Before removing
+ Util.Pair, Iterable> allCandidatesInBetween = finder.getAllCandidates(ron);
+ assertEquals(Util.size(allCandidatesInBetween.getA()), 1);
+ assertEquals(Util.size(allCandidatesInBetween.getB()), 0);
+
+ // The Process of removing
+ course.removeWaypoint(4);
+ Util.Pair, List> removedCans = finder.updateWaypoints(new ArrayList(), Arrays.asList(newWaypoint), 4).get(ron);
+ assertEquals(Util.size(removedCans.getB()), 1);
+ for (Candidate c : removedCans.getB()) {
+ assertEquals(c.getWaypoint(), newWaypoint);
+ }
+
+ // After removing
+ Util.Pair, Iterable> allCansAfterRemoving = finder.getAllCandidates(ron);
+ assertEquals(Util.size(allCansAfterRemoving.getB()), 0);
+ assertEquals(Util.size(allCansAfterRemoving.getA()), 0);
+ }
+
+}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/OBMR2012VRMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/OBMR2012VRMarkPassingTest.java
index ef7938fed48..487bfd22c3c 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/OBMR2012VRMarkPassingTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/OBMR2012VRMarkPassingTest.java
@@ -17,45 +17,70 @@ public class OBMR2012VRMarkPassingTest extends AbstractMarkPassingTest {
}
@Test
- public void testRaceFr11() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
+ public void testRaceFr11() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
testRace("Fr_Fleet_1_1");
}
@Test
- public void testRaceFr12() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
+ public void testRaceFr12() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
testRace("Fr_Fleet_1_2");
}
- /*
- * Ignored on master branch.
- *
- * @Test public void testRaceFr13() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Fr_Fleet_1_3"); }
- *
- * @Test public void testRaceFr21() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Fr_Fleet_2_1"); }
- *
- * @Test public void testRaceFr22() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Fr_Fleet_2_2"); }
- *
- * @Test public void testRaceFr23() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Fr_Fleet_2_3"); }
- *
- * @Test public void testRaceSaVm11() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Sa-Vm_Fleet_1_1"); }
- *
- * @Test public void testRaceSaVm12() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Sa-Vm_Fleet_1_2"); }
- *
- * @Test public void testRaceSaVm13() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Sa-Vm_Fleet_1_3"); }
- *
- * @Test public void testRaceSaVm21() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Sa-Vm_Fleet_2_1"); }
- *
- * @Test public void testRaceSaVm22() throws IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
- * testRace("Sa-Vm_Fleet_2_2"); }
- */
+ @Test
+ public void testRaceFr13() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Fr_Fleet_1_3");
+ }
+
+ @Test
+ public void testRaceFr21() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Fr_Fleet_2_1");
+ }
+
+ @Test
+ public void testRaceFr22() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Fr_Fleet_2_2");
+ }
+
+ @Test
+ public void testRaceFr23() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Fr_Fleet_2_3");
+ }
+
+ @Test
+ public void testRaceSaVm11() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Sa-Vm_Fleet_1_1");
+ }
+
+ @Test
+ public void testRaceSaVm12() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Sa-Vm_Fleet_1_2");
+ }
+
+ @Test
+ public void testRaceSaVm13() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Sa-Vm_Fleet_1_3");
+ }
+
+ @Test
+ public void testRaceSaVm21() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Sa-Vm_Fleet_2_1");
+ }
+
+ @Test
+ public void testRaceSaVm22() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("Sa-Vm_Fleet_2_2");
+ }
@Override
protected String getExpectedEventName() {
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/StarIDM2013MarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/StarIDM2013MarkPassingTest.java
new file mode 100755
index 00000000000..600111324cb
--- /dev/null
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/StarIDM2013MarkPassingTest.java
@@ -0,0 +1,41 @@
+package com.sap.sailing.domain.test.markpassing;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+
+import org.junit.Test;
+
+import com.tractrac.model.lib.api.event.CreateModelException;
+import com.tractrac.subscription.lib.api.SubscriberInitializationException;
+
+public class StarIDM2013MarkPassingTest extends AbstractMarkPassingTest {
+
+ public StarIDM2013MarkPassingTest() throws MalformedURLException, URISyntaxException {
+ super();
+ }
+
+ @Test
+ public void testRace5() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("5");
+ }
+
+ @Test
+ public void testRace6() throws IOException, InterruptedException, URISyntaxException, ParseException,
+ SubscriberInitializationException, CreateModelException {
+ testRace("6");
+ }
+
+ @Override
+ protected String getFileName() {
+ return "event_20130424_IDMStarboo-Race_";
+ }
+
+ @Override
+ protected String getExpectedEventName() {
+ return "IDM Starboot 2013";
+ }
+
+}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
index f9188fa2a8e..b9dd404787c 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
@@ -25,7 +25,6 @@ import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
-import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
@@ -484,7 +483,7 @@ public class MockedTrackedRace implements DynamicTrackedRace {
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines,
WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
- DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
+ DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingcalculator) {
return null;
}
};
@@ -822,21 +821,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
return null;
}
- @Override
public GPSFixStore getGPSFixStore() {
return null;
}
- @Override
- public Bearing getCrossingBearing(Waypoint w, TimePoint t) {
- return null;
- }
-
- @Override
- public Util.Pair getPortAndStarboardMarks(TimePoint t, Waypoint w) {
- return null;
- }
-
@Override
public Distance getAverageSignedCrossTrackError(Competitor competitor, TimePoint timePoint,
boolean waitForLatestAnalysis) throws NoWindException {
@@ -872,6 +860,12 @@ public class MockedTrackedRace implements DynamicTrackedRace {
return null;
}
+ @Override
+ public boolean isUsingMarkPassingCalculator() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
@Override
public void attachRegattaLog(RegattaLog regattaLog) {
}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java
index aa9653d3ae4..87741525f7b 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java
@@ -592,4 +592,10 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
return null;
}
+ @Override
+ public boolean isUsingMarkPassingCalculator() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
}
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java
index e8632586471..39788f49d40 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java
@@ -136,7 +136,7 @@ public interface DomainFactory {
*/
TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
- boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
+ boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry)
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, SubscriberInitializationException;
@@ -147,7 +147,7 @@ public interface DomainFactory {
*/
RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
- boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
+ boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry)
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
@@ -173,7 +173,8 @@ public interface DomainFactory {
Iterable getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, long delayToLiveInMillis,
Simulator simulator, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry,
IRace tractracRace, URI courseDesignUpdateURI,
- String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber);
+ String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber,
+ IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm);
/**
* Creates a {@link RaceDefinition} from a TracTrac {@link Race} and a domain {@link Course} definition. The
@@ -197,7 +198,7 @@ public interface DomainFactory {
String raceName, Iterable competitors, BoatClass boatClass,
Course course, Iterable sidelines, WindStore windStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
- URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword);
+ URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings);
/**
* The record may be for a single mark or a gate. If for a gate, the
@@ -216,7 +217,7 @@ public interface DomainFactory {
Iterable getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, IRace tractracRace, WindStore windStore,
long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry,
URI courseDesignUpdateURI, String tracTracUsername,
- String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, ReceiverType... types);
+ String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean ignoreTracTracMarkPassings, ReceiverType... types);
JSONService parseJSONURLWithRaceRecords(URL jsonURL, boolean loadClientParams) throws IOException, ParseException, org.json.simple.parser.ParseException, URISyntaxException;
@@ -252,7 +253,7 @@ public interface DomainFactory {
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI, URI storedURI,
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
- boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
+ boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility);
/**
* Removes all knowledge about tractracRace which includes removing it from the race cache, from the
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java
index 77240764b88..72fcb93662e 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java
@@ -70,7 +70,7 @@ public interface TracTracAdapter {
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,
+ long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm,
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility)
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/Activator.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/Activator.java
index fecda2340b6..f5e866cd48d 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/Activator.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/Activator.java
@@ -13,8 +13,6 @@ public class Activator implements BundleActivator {
private final TracTracAdapterFactory tracTracAdapterFactory;
- private static boolean useTracTracMarkPassings = true;
-
public Activator() {
// there is exactly one instance of the racingEventService in the whole server
tracTracAdapterFactory = new TracTracAdapterFactoryImpl();
@@ -24,18 +22,8 @@ public class Activator implements BundleActivator {
// register the racing service in the OSGi registry
context.registerService(TracTracAdapterFactory.class.getName(), tracTracAdapterFactory, null);
logger.log(Level.INFO, "Started "+context.getBundle().getSymbolicName());
- useTracTracMarkPassings = context.getProperty("tractrac.usemarkpassings") == null ? true : context.getProperty(
- "tractrac.usemarkpassings").equals("false") ? false : true;
}
public void stop(BundleContext context) throws Exception {
}
-
- public boolean isUseTracTracMarkPassings() {
- return useTracTracMarkPassings;
- }
-
- public static Activator getInstance() {
- return new Activator();
- }
}
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java
index 650902ae32a..6375116d53e 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java
@@ -47,7 +47,6 @@ import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
-import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
@@ -402,7 +401,7 @@ public class DomainFactoryImpl implements DomainFactory {
WindStore windStore, long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
TrackedRegattaRegistry trackedRegattaRegistry, URI courseDesignUpdateURI,
String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber,
- IRaceSubscriber raceSubscriber, ReceiverType... types) {
+ IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm, ReceiverType... types) {
IEvent tractracEvent = tractracRace.getEvent();
Collection result = new ArrayList();
for (ReceiverType type : types) {
@@ -411,7 +410,7 @@ public class DomainFactoryImpl implements DomainFactory {
result.add(new RaceCourseReceiver(this, trackedRegatta, tractracEvent, tractracRace,
windStore, raceDefinitionSetToUpdate,
delayToLiveInMillis, WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, simulator,
- courseDesignUpdateURI, tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber));
+ courseDesignUpdateURI, tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm));
break;
case MARKPOSITIONS:
result.add(new MarkPositionReceiver(
@@ -422,7 +421,7 @@ public class DomainFactoryImpl implements DomainFactory {
trackedRegatta, tractracEvent, this, simulator, eventSubscriber, raceSubscriber));
break;
case MARKPASSINGS:
- if (Activator.getInstance().isUseTracTracMarkPassings()) {
+ if (!useInternalMarkPassingAlgorithm) {
result.add(new MarkPassingReceiver(trackedRegatta, tractracEvent, simulator, this, eventSubscriber, raceSubscriber));
}
break;
@@ -440,9 +439,10 @@ public class DomainFactoryImpl implements DomainFactory {
long delayToLiveInMillis, Simulator simulator, WindStore windStore,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, IRace tractracRace,
URI courseDesignUpdateURI, String tracTracUsername,
- String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber) {
+ String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm) {
return getUpdateReceivers(trackedRegatta, tractracRace, windStore, delayToLiveInMillis, simulator,
- raceDefinitionSetToUpdate, trackedRegattaRegistry, courseDesignUpdateURI, tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber,
+ raceDefinitionSetToUpdate, trackedRegattaRegistry, courseDesignUpdateURI, tracTracUsername,
+ tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm,
ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS,
ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS);
}
@@ -505,7 +505,7 @@ public class DomainFactoryImpl implements DomainFactory {
String raceName, Iterable competitors, BoatClass boatClass, Course course,
Iterable sidelines, WindStore windStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
- URI tracTracUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword) {
+ URI tracTracUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings) {
synchronized (raceCache) {
RaceDefinition raceDefinition = raceCache.get(raceId);
if (raceDefinition == null) {
@@ -520,7 +520,7 @@ public class DomainFactoryImpl implements DomainFactory {
if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) {
trackedRegatta.getRegatta().addRace(raceDefinition);
trackedRace = createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore, EmptyGPSFixStore.INSTANCE,
- delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate);
+ delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, ignoreTracTracMarkPassings);
logger.info("Added race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta());
addTracTracUpdateHandlers(tracTracUpdateURI, tracTracEventUuid, tracTracUsername, tracTracPassword,
raceDefinition, trackedRace);
@@ -534,9 +534,6 @@ public class DomainFactoryImpl implements DomainFactory {
} else {
logger.info("Found existing tracked race for race "+raceName+" with ID "+raceId);
}
- if (!Activator.getInstance().isUseTracTracMarkPassings()) {
- new MarkPassingCalculator(trackedRace, true);
- }
return trackedRace;
}
}
@@ -559,11 +556,11 @@ public class DomainFactoryImpl implements DomainFactory {
}
private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore,
- long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
+ long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator) {
return trackedRegatta.createTrackedRace(race, sidelines,
windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
- raceDefinitionSetToUpdate);
+ raceDefinitionSetToUpdate, useMarkPassingCalculator);
}
@Override
@@ -638,26 +635,26 @@ 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, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
+ boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry)
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
SubscriberInitializationException {
return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking,
- endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, regattaLogStore, windStore,
+ endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry);
}
@Override
public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI,
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
- boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
+ boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry)
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
SubscriberInitializationException {
return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, courseDesignUpdateURI,
- startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore,
+ startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
raceVisibility, trackedRegattaRegistry);
}
@@ -675,11 +672,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, RaceLogStore raceLogStore,
+ long delayToLiveInMillis, boolean simulateWithStartTimeNow, 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, raceLogStore,
+ startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
regattaLogStore, this, tracTracUsername, tracTracPassword, raceStatus, raceVisibility);
}
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/MetadataParserImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/MetadataParserImpl.java
index 41f3ffabc97..6972bbe22c6 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/MetadataParserImpl.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/MetadataParserImpl.java
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.common.MarkType;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.tractracadapter.MetadataParser;
import com.sap.sailing.domain.tractracadapter.TracTracControlPoint;
+import com.sap.sse.common.Util;
import com.sap.sse.common.impl.NamedImpl;
/**
@@ -82,10 +83,11 @@ public class MetadataParserImpl implements MetadataParser {
* Parses the route metadata for additional course information
* The 'passing side' for each course waypoint is encoded like this...
*
- * Seq.1=GATE
- * Seq.2=PORT
- * Seq.3=GATE
- * Seq.4=STARBOARD
+ * Seq.0=LINE
+ * Seq.1=PORT
+ * Seq.2=GATE
+ * Seq.3=STARBOARD
+ * Seq.4=LINE
*
*/
@Override
@@ -93,16 +95,15 @@ public class MetadataParserImpl implements MetadataParser {
Map result = new HashMap();
if (routeMetadataString != null) {
Map routeMetadata = parseMetadata(routeMetadataString);
- int i = 1;
- for (TracTracControlPoint controlPoint : controlPoints) {
+ int start = routeMetadata.containsKey("Seq." + 0) ? 0 : 1;
+ for (int i = start; i < start + Util.size(controlPoints); i++) {
String seqValue = routeMetadata.get("Seq." + i);
- if (!controlPoint.getHasTwoPoints() && seqValue != null) {
+ if (seqValue != null) {
final PassingInstruction passingInstructions = PassingInstruction.valueOfIgnoringCase(seqValue);
if (passingInstructions != null) {
- result.put(i, passingInstructions);
+ result.put(i - start, passingInstructions);
}
}
- i++;
}
}
return result;
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java
index 2cfd1880a1c..114ce6d2508 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java
@@ -16,7 +16,6 @@ import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.common.PassingInstruction;
-import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
@@ -60,12 +59,13 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue courseWaypointPassingInstructions = getDomainFactory().getMetadataParser().parsePassingInstructionData(routeMetadataString, routeControlPoints);
List> ttControlPoints = new ArrayList<>();
- int i = 1;
+ int i = 0;
for (IControl cp : event.getA().getControls()) {
PassingInstruction passingInstructions = courseWaypointPassingInstructions.containsKey(i) ? courseWaypointPassingInstructions.get(i) : null;
ttControlPoints.add(new com.sap.sse.common.Util.Pair(ttControlPointsForAllOriginalEventControlPoints.get(cp), passingInstructions));
@@ -154,7 +155,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue();
for (Receiver receiver : domainFactory.getUpdateReceivers(getTrackedRegatta(), delayToLiveInMillis,
simulator, windStore, this, trackedRegattaRegistry, tractracRace, tracTracUpdateURI,
- tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber)) {
+ tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm)) {
receivers.add(receiver);
}
addListenersForStoredDataAndStartController(receivers);
diff --git a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
old mode 100644
new mode 100755
index a9856674f3d..abcdb4207e4
--- a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
@@ -14,6 +14,7 @@ Export-Package: com.sap.sailing.domain.base,
com.sap.sailing.domain.leaderboard.impl,
com.sap.sailing.domain.leaderboard.meta,
com.sap.sailing.domain.markpassingcalculation,
+ com.sap.sailing.domain.markpassingcalculation.impl,
com.sap.sailing.domain.markpassingcalculation.splining,
com.sap.sailing.domain.masterdataimport,
com.sap.sailing.domain.racelog,
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java
index aa862ad14cc..35b896f7133 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java
@@ -33,6 +33,7 @@ import difflib.Patch;
import difflib.PatchFailedException;
public class CourseImpl extends NamedImpl implements Course {
+
private static final long serialVersionUID = -4280487649617132403L;
private static final Logger logger = Logger.getLogger(CourseImpl.class.getName());
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java
index 906c2e17780..61fc4571ddb 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.base.impl;
import java.io.Serializable;
+import com.sap.sailing.domain.abstractlog.race.FixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
@@ -18,6 +19,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
+import com.sap.sailing.domain.abstractlog.race.SuppressedMarkPassingsEvent;
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
@@ -152,6 +154,16 @@ public class RaceColumnRaceLogReplicator implements RaceLogEventVisitor, Seriali
notifyOnAdd(event);
}
+ @Override
+ public void visit(FixedMarkPassingEvent event) {
+ notifyOnAdd(event);
+ }
+
+ @Override
+ public void visit(SuppressedMarkPassingsEvent event) {
+ notifyOnAdd(event);
+ }
+
@Override
public void visit(RaceLogAdditionalScoringInformationEvent additionalScoringInformation) {
notifyOnAdd(additionalScoringInformation);
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/AbstractCandidateChooser.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/AbstractCandidateChooser.java
deleted file mode 100755
index f936d476f83..00000000000
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/AbstractCandidateChooser.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.sap.sailing.domain.markpassingcalculation;
-
-import java.util.LinkedHashMap;
-
-import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.base.Waypoint;
-import com.sap.sailing.domain.tracking.MarkPassing;
-import com.sap.sse.common.Util;
-
-/**
- * Takes the {@link Candidate}s from an {@link AbstractCandidateFinder} and calculates any new {@link MarkPassing}s. The
- * race should then be notified about these new MarkPassings.
- *
- * @author Nicolas Klose
- *
- */
-
-public interface AbstractCandidateChooser {
-
- public void calculateMarkPassDeltas(Competitor c, Util.Pair, Iterable> candidateDeltas);
-
- public LinkedHashMap> getAllPasses();
-}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/AbstractCandidateFinder.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/AbstractCandidateFinder.java
deleted file mode 100755
index 6db9daf73bc..00000000000
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/AbstractCandidateFinder.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.sap.sailing.domain.markpassingcalculation;
-
-import java.util.LinkedHashMap;
-import java.util.List;
-
-import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.tracking.GPSFix;
-import com.sap.sse.common.Util;
-
-/**
- * A CandidateFinder converts the incoming GPSFixes of competitors and marks into {@link Candidate}s for each
- * competitor. {@link #calculateFixesAffectedByNewMarkFixes(Mark, List)} determines the fixes that may have changed
- * their status as {@link Candidate} after new fixes for a mark arrive. This determines those fixes that may have
- * changed their status as a {@link Candidate}. {@link #getCandidateDeltas(Competitor, Iterable)} then returns the
- * actual changes to the list of Candidates as a Pair of Lists, one of the new Candidates and one of the Candidates that
- * should be removed.
- *
- * @author Nicolas Klose
- *
- */
-
-public interface AbstractCandidateFinder {
-
- LinkedHashMap> calculateFixesAffectedByNewMarkFixes(Mark mark, Iterable gps);
-
- /**
- * Before calling this method, there have to be fixes that may have changed their status as a Candidate. This is
- * done by the the method {@link #calculateFixesAffectedByNewMarkFixes(Mark, Iterable)}
- *
- * @param c
- * @return
- */
- Util.Pair, Iterable> getCandidateDeltas(Competitor c, Iterable fixes);
-
- /**
- * When initializing the calculator, the whole race until now is evaluated. For that purpose all of the Candidates
- * are needed instead of just the deltas.
- *
- * @param c
- * the competitor whose {@link Candidate}s should be returned
- * @return all of the Candidates for the specified competitor
- */
- Util.Pair, Iterable> getAllCandidates(Competitor c);
-}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/Candidate.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/Candidate.java
index 8e6dd45374e..71b4aca1767 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/Candidate.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/Candidate.java
@@ -2,61 +2,32 @@ package com.sap.sailing.domain.markpassingcalculation;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sse.common.TimePoint;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateChooserImpl;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateImpl;
/**
- * A possible passing of a {@link Waypoint}. It contains the {@link Waypoint} that it might be passing, a
+ * Represent the possible {@link MarkPassing} of a {@link Waypoint}. It contains the {@link Waypoint} it might be passing, a
* {@link TimePoint}, the probability that this candidate is a passing (e.g. based on the distance to the
* {@link Waypoint}) and the one-based(!) ID of this Waypoint. The ID is one based because the standard implementation
- * of {@link AbstractCandidateChooser} (see {@link CandidateChooser}) uses a proxy Candidates at the end and the
- * beginning of the race, the one at the beginning receives the ID 0. Candidates are created in an
- * {@link AbstractCandidateFinder}, which determines where a passing could be and assigns them
+ * of {@link CandidateChooser} (see {@link CandidateChooserImpl}) uses a proxy Candidates at the end and the beginning
+ * of the race, the one at the beginning recieves the ID 0.
*
* @author Nicolas Klose
*
*/
-public class Candidate implements Comparable {
- private Waypoint waypoint;
- private TimePoint timePoint;
- private double distanceProbability;
- private Integer id;
- private boolean rightSide;
- private boolean rightDirection;
- private String type;
+public interface Candidate extends Comparable {
- public Candidate(int id, TimePoint timePoint, double distanceProbability, Waypoint w, boolean rightSide, boolean rightDirection, String type) {
- this.waypoint = w;
- this.timePoint = timePoint;
- this.distanceProbability = distanceProbability;
- this.id = id;
- this.rightSide = rightSide;
- this.rightDirection=rightDirection;
- this.type = type;
- }
+ Waypoint getWaypoint();
- public int getID() {
- return id;
- }
+ int getOneBasedIndexOfWaypoint();
- public TimePoint getTimePoint() {
- return timePoint;
- }
+ TimePoint getTimePoint();
- public Double getProbability() {
- double factor= (rightSide&&rightDirection)?1:(rightSide||rightDirection)?0.7:0.4;
- double cost = distanceProbability * factor;
- return cost;
- }
+ /**
+ * @return the probability that this actually is a passing.
+ */
+ Double getProbability();
- public Waypoint getWaypoint() {
- return waypoint;
- }
-
- public String toString() {
- return type + "-Candidate for " + id + " with cost " + getProbability() + "and Timepoint " + timePoint;
- }
-
- @Override
- public int compareTo(Candidate arg0) {
- return id != arg0.getID() ? id.compareTo(arg0.getID()) : timePoint != arg0.getTimePoint() ? timePoint.compareTo(arg0.getTimePoint()) : getProbability().compareTo(arg0.getProbability());
- }
+ int compareTo(Candidate arg0);
+
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/CandidateChooser.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/CandidateChooser.java
index 97318ab4b97..d2d1e2f809a 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/CandidateChooser.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/CandidateChooser.java
@@ -1,234 +1,30 @@
package com.sap.sailing.domain.markpassingcalculation;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
-import com.sap.sailing.domain.common.Distance;
-import com.sap.sailing.domain.common.LegType;
-import com.sap.sailing.domain.common.NoWindException;
-import com.sap.sailing.domain.common.impl.MeterDistance;
+import com.sap.sailing.domain.markpassingcalculation.impl.CandidateImpl;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.MarkPassing;
-import com.sap.sailing.domain.tracking.TrackedLeg;
-import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
import com.sap.sse.common.TimePoint;
-import com.sap.sse.common.Util;
-/**
- * The standard implementation of {@link AbstractCandidateChooser}. A graph is created, with each {@link Candidate} as a
- * vertices between two proxy Candidates, start and end. The probability of an {@link Edge} is
- * equal to the probability of the two Candidates plus and estimation of the distance traveled between the them. A
- * shortest path-algorithm is then used to find the most likely sequence of {@link MarkPassing}s.
- *
- * @author Nicolas Klose
- *
- */
-public class CandidateChooser implements AbstractCandidateChooser {
+public interface CandidateChooser {
+ /**
+ * Calculates any new {@link MarkPassing}s and notifies the {@link DynamicTrackedRace}.
+ *
+ * @param candidateDeltas
+ * new {@link CandidateImpl}s and those that should be removed.
+ */
- private static final Logger logger = Logger.getLogger(CandidateChooser.class.getName());
+ public void calculateMarkPassDeltas(Competitor c, Iterable newCans, Iterable oldCans);
- private LinkedHashMap> currentMarkPasses = new LinkedHashMap<>();
- private LinkedHashMap> allEdges = new LinkedHashMap<>();
- private LinkedHashMap> candidates = new LinkedHashMap<>();
- private TimePoint raceStartTime;
- private Candidate start;
- private Candidate end;
- private final DynamicTrackedRace race;
- private final double penaltyForSkipping = 1 - Edge.getPenaltyForSkipping();
- private static double strictness = 900; // Lower = stricter; 900
+ void removeWaypoints(Iterable ways);
- public CandidateChooser(DynamicTrackedRace race) {
- logger.setLevel(Level.INFO);
- this.race = race;
- raceStartTime = race.getStartOfRace()!=null?race.getStartOfRace().minus(2000):null;
- start = new Candidate(/*Index*/0, raceStartTime, /*Probability*/1, /*Waypoint*/null, /*right Side*/true, /*right Direction*/true, "Proxy");
- end = new Candidate(race.getRace().getCourse().getIndexOfWaypoint(race.getRace().getCourse().getLastWaypoint()) + 2, /*TimePoint*/null,
- /*Probability*/1, /*Waypoint*/null, /*right Side*/true, /*right Direction*/true, "Proxy");
- candidates = new LinkedHashMap<>();
- for (Competitor c : race.getRace().getCompetitors()) {
- candidates.put(c, new TreeSet