mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-25 05:23:51 +00:00
Merge branch 'master' into bug3985
This commit is contained in:
commit
e92116be9d
244 files changed
+3042
-893
No files matched your search
@@ -2,4 +2,4 @@ eclipse.preferences.version=1
|
||||
encoding//src/com/sap/sailing/domain/common/AbstractBearing.java=UTF-8
|
||||
encoding//src/com/sap/sailing/domain/common/confidence/impl/ConfidenceBasedAveragerImpl.java=utf-8
|
||||
encoding//src/com/sap/sailing/domain/common/impl/AbstractSpeedWithAbstractBearingImpl.java=UTF-8
|
||||
encoding//src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java=UTF-8
|
||||
encoding//src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java=UTF-8
|
||||
+1
-1
@@ -4,6 +4,6 @@ public enum ScoringSchemeType {
|
||||
// make sure to also add new ones to ScoringSchemeTypeFormatter
|
||||
LOW_POINT, HIGH_POINT, HIGH_POINT_ESS_OVERALL,HIGH_POINT_ESS_OVERALL_12, HIGH_POINT_LAST_BREAKS_TIE, HIGH_POINT_FIRST_GETS_TEN,
|
||||
HIGH_POINT_FIRST_GETS_ONE, LOW_POINT_WINNER_GETS_ZERO, HIGH_POINT_WINNER_GETS_SIX, HIGH_POINT_WINNER_GETS_FIVE, HIGH_POINT_WINNER_GETS_EIGHT,
|
||||
HIGH_POINT_WINNER_GETS_EIGHT_AND_INTERPOLATION, HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT, LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07,
|
||||
HIGH_POINT_WINNER_GETS_EIGHT_AND_INTERPOLATION, HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017, LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07,
|
||||
LOW_POINT_LEAGUE_OVERALL, HIGH_POINT_MATCH_RACING, LOW_POINT_TIE_BREAK_BASED_ON_LAST_SERIES_ONLY
|
||||
}
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class WindImpl extends KnotSpeedWithBearingImpl implements Wind {
|
||||
}
|
||||
|
||||
public static int hashCode(double latDeg, double lngDeg, long timePointAsMillis) {
|
||||
return (31 * (int) (timePointAsMillis & Integer.MAX_VALUE)) ^ (int) (latDeg*lngDeg);
|
||||
return (31 * (int) (timePointAsMillis & Integer.MAX_VALUE)) ^ (int) (Math.round(latDeg)*Math.round(lngDeg));
|
||||
}
|
||||
/**
|
||||
* Wind hash is determined based on time point and position only to speed this up a little.
|
||||
|
||||
+5
-4
@@ -14,10 +14,11 @@ public enum BravoSensorDataMetadata {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
private static final String RIDE_HEIGHT_PORT_HULL = "RideHeightPortHull";
|
||||
private static final String RIDE_HEIGHT_STBD_HULL = "RideHeightStbdHull";
|
||||
private static final String HEEL = "Heel";
|
||||
private static final String PITCH = "ImuSensor_Pitch";
|
||||
public static final String RIDE_HEIGHT = "RideHeight";
|
||||
public static final String RIDE_HEIGHT_PORT_HULL = "RideHeightPortHull";
|
||||
public static final String RIDE_HEIGHT_STBD_HULL = "RideHeightStbdHull";
|
||||
public static final String HEEL = "Heel";
|
||||
public static final String PITCH = "ImuSensor_Pitch";
|
||||
|
||||
private final int HEADER_COLUMN_OFFSET = 3;
|
||||
|
||||
|
||||
+8
-81
@@ -1,11 +1,6 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractPosition;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.AbstractTimePoint;
|
||||
@@ -21,9 +16,9 @@ import com.sap.sse.common.impl.AbstractTimePoint;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
||||
private static final long serialVersionUID = 8167588584536992501L;
|
||||
|
||||
public abstract class AbstractCompactGPSFixImpl extends AbstractGPSFixImpl {
|
||||
private static final long serialVersionUID = 3943572107870245437L;
|
||||
|
||||
/**
|
||||
* Bit mask for {@link #whatIsCached}, telling whether validity is currently cached
|
||||
*/
|
||||
@@ -39,9 +34,7 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
||||
* <code>{@link #whatIsCached}&{@link #IS_VALIDITY_CACHED} != 0</code>
|
||||
*/
|
||||
private static final byte VALIDITY = 1<<2;
|
||||
|
||||
private final double latDeg;
|
||||
private final double lngDeg;
|
||||
|
||||
private final long timePointAsMillis;
|
||||
|
||||
/**
|
||||
@@ -52,32 +45,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
||||
*/
|
||||
private byte whatIsCached = 0;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed's
|
||||
* true "bearing" (true course over ground) in degrees.
|
||||
*/
|
||||
private double cachedEstimatedSpeedBearingInDegrees;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed
|
||||
* in knots.
|
||||
*/
|
||||
private double cachedEstimatedSpeedInKnots;
|
||||
|
||||
public class CompactPosition extends AbstractPosition {
|
||||
private static final long serialVersionUID = 5621506820766614178L;
|
||||
|
||||
@Override
|
||||
public double getLatDeg() {
|
||||
return latDeg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLngDeg() {
|
||||
return lngDeg;
|
||||
}
|
||||
}
|
||||
|
||||
private class CompactTimePoint extends AbstractTimePoint implements TimePoint {
|
||||
private static final long serialVersionUID = -2470922642359937437L;
|
||||
|
||||
@@ -87,37 +54,12 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private class CompactEstimatedSpeedBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = 8549231429037883121L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return cachedEstimatedSpeedBearingInDegrees;
|
||||
}
|
||||
}
|
||||
|
||||
private class CompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl {
|
||||
private static final long serialVersionUID = -5871855443391817248L;
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
return new CompactEstimatedSpeedBearing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return cachedEstimatedSpeedInKnots;
|
||||
}
|
||||
}
|
||||
|
||||
public CompactGPSFixImpl(Position position, TimePoint timePoint) {
|
||||
latDeg = position.getLatDeg();
|
||||
lngDeg = position.getLngDeg();
|
||||
public AbstractCompactGPSFixImpl(TimePoint timePoint) {
|
||||
timePointAsMillis = timePoint==null?-1:timePoint.asMillis();
|
||||
}
|
||||
|
||||
public CompactGPSFixImpl(GPSFix gpsFix) {
|
||||
this(gpsFix.getPosition(), gpsFix.getTimePoint());
|
||||
|
||||
public AbstractCompactGPSFixImpl(GPSFix gpsFix) {
|
||||
this(gpsFix.getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,11 +67,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
||||
return getTimePoint() + ": " + getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return new CompactPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePoint() {
|
||||
return new CompactTimePoint();
|
||||
@@ -166,12 +103,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
||||
return (whatIsCached & IS_ESTIMATED_SPEED_CACHED) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getCachedEstimatedSpeed() {
|
||||
assert isEstimatedSpeedCached();
|
||||
return new CompactEstimatedSpeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateEstimatedSpeedCache() {
|
||||
whatIsCached &= ~IS_ESTIMATED_SPEED_CACHED;
|
||||
@@ -179,10 +110,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
||||
|
||||
@Override
|
||||
public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) {
|
||||
cachedEstimatedSpeedBearingInDegrees = estimatedSpeed.getBearing().getDegrees();
|
||||
cachedEstimatedSpeedInKnots = estimatedSpeed.getKnots();
|
||||
whatIsCached |= IS_ESTIMATED_SPEED_CACHED;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+9
-40
@@ -1,6 +1,5 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractSpeedImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.CourseChange;
|
||||
@@ -21,23 +20,14 @@ import com.sap.sse.common.TimePoint;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFixMoving {
|
||||
private static final long serialVersionUID = 761582024504236533L;
|
||||
private final double knotSpeed;
|
||||
private final double degBearing;
|
||||
|
||||
private class CompactSpeedWithBearing extends AbstractSpeedImpl implements SpeedWithBearing {
|
||||
public abstract class AbstractCompactGPSFixMovingImpl extends AbstractCompactGPSFixImpl implements GPSFixMoving {
|
||||
private static final long serialVersionUID = 3977983319207618335L;
|
||||
|
||||
protected abstract class AbstractCompactSpeedWithBearing extends AbstractSpeedImpl implements SpeedWithBearing {
|
||||
private static final long serialVersionUID = 1802065090733146728L;
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return knotSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
return new CompactBearing();
|
||||
}
|
||||
public abstract double getKnots();
|
||||
|
||||
@Override
|
||||
public Position travelTo(Position pos, TimePoint from, TimePoint to) {
|
||||
@@ -81,33 +71,12 @@ public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFix
|
||||
}
|
||||
}
|
||||
|
||||
private class CompactBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = -6474909210513108635L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return degBearing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getRadians() {
|
||||
return degBearing / 180. * Math.PI;
|
||||
}
|
||||
public AbstractCompactGPSFixMovingImpl(TimePoint timePoint) {
|
||||
super(timePoint);
|
||||
}
|
||||
|
||||
public CompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) {
|
||||
super(position, timePoint);
|
||||
knotSpeed = speed.getKnots();
|
||||
degBearing = speed.getBearing().getDegrees();
|
||||
}
|
||||
|
||||
public CompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) {
|
||||
this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeed() {
|
||||
return new CompactSpeedWithBearing();
|
||||
public AbstractCompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) throws CompactionNotPossibleException {
|
||||
this(gpsFixMoving.getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.AbstractTimePoint;
|
||||
|
||||
public abstract class AbstractCompactWindImpl extends AbstractSpeedWithAbstractBearingImpl implements Wind {
|
||||
private static final long serialVersionUID = -5059956032663387929L;
|
||||
|
||||
/**
|
||||
* bit mask for {@link #flags}, telling the bit encoding whether the position is {@code null}.
|
||||
*/
|
||||
private static final byte POSITION_IS_NULL = 1<<0;
|
||||
|
||||
/**
|
||||
* bit mask for {@link #flags}, telling the bit encoding whether the bearing is {@code null}.
|
||||
*/
|
||||
private static final byte BEARING_IS_NULL = 1<<1;
|
||||
|
||||
/**
|
||||
* bit mask for {@link #flags}, telling the bit encoding whether the time point is {@code null}.
|
||||
*/
|
||||
private static final byte TIME_POINT_IS_NULL = 1<<2;
|
||||
|
||||
/**
|
||||
* See the bit mask values such as {@link #POSITION_IS_NULL}, {@link #BEARING_IS_NULL} and {@link #TIME_POINT_IS_NULL}.
|
||||
*/
|
||||
private final byte flags;
|
||||
|
||||
private final long timePointAsMillis;
|
||||
|
||||
private class CompactTimePoint extends AbstractTimePoint implements TimePoint {
|
||||
private static final long serialVersionUID = -2470922642359937437L;
|
||||
|
||||
@Override
|
||||
public long asMillis() {
|
||||
return timePointAsMillis;
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractCompactWindImpl(Wind wind) {
|
||||
final boolean bearingIsNull;
|
||||
final boolean positionIsNull;
|
||||
final boolean timePointIsNull;
|
||||
bearingIsNull = wind.getBearing() == null;
|
||||
positionIsNull = wind.getPosition() == null;
|
||||
if (wind.getTimePoint() == null) {
|
||||
timePointIsNull = true;
|
||||
this.timePointAsMillis = 0;
|
||||
} else {
|
||||
timePointIsNull = false;
|
||||
this.timePointAsMillis = wind.getTimePoint().asMillis();
|
||||
}
|
||||
flags = (byte) ((byte) (bearingIsNull ? BEARING_IS_NULL : (byte) 0) | (positionIsNull ? POSITION_IS_NULL : (byte) 0) | (timePointIsNull ? TIME_POINT_IS_NULL : (byte) 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
if ((flags & POSITION_IS_NULL) != 0) {
|
||||
return null;
|
||||
} else {
|
||||
return getCompactPosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Position getCompactPosition();
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePoint() {
|
||||
if ((flags & TIME_POINT_IS_NULL) != 0) {
|
||||
return null;
|
||||
} else {
|
||||
return new CompactTimePoint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
if ((flags & BEARING_IS_NULL) != 0) {
|
||||
return null;
|
||||
} else {
|
||||
return getCompactBearing();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Bearing getCompactBearing();
|
||||
|
||||
/**
|
||||
* Make abstract to force implementing subclasses to implement this method.
|
||||
*/
|
||||
@Override
|
||||
public abstract double getKnots();
|
||||
|
||||
@Override
|
||||
public Bearing getFrom() {
|
||||
if (getBearing() == null) {
|
||||
return null;
|
||||
} else {
|
||||
return getBearing().reverse();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return WindImpl.hashCode(getPosition().getLatDeg(), getPosition().getLngDeg(), (flags&TIME_POINT_IS_NULL) != 0?0:timePointAsMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (!(obj instanceof Wind))
|
||||
return false;
|
||||
Wind other = (Wind) obj;
|
||||
return Util.equalsWithNull(getPosition(), other.getPosition()) && Util.equalsWithNull(getTimePoint(), other.getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ""+getTimePoint()+"@"+getPosition()+": "+getKnots()+"kn from "+getFrom();
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
|
||||
/**
|
||||
* A utility class that "compact" fix implementations such as {@link VeryCompactGPSFixImpl} etc. can use
|
||||
* to obtain representations of latitudes, longitudes, knot speeds and degree bearings marshalled in
|
||||
* types that sacrifice very little accuracy from a real-world perspective, yet use a data type for
|
||||
* encoding that requires fewer bytes than a {@code double} value.<p>
|
||||
*
|
||||
* Latitude and longitude values are represented using a signed {@code int} value, scaling their range (-90°..+90° and
|
||||
* -180°..+180°, respectively over the full {@code int} range. This gives a resolution of 4.6mm for latitudes,
|
||||
* and at the equator of 9.3mm for longitudes.<p>
|
||||
*
|
||||
* Bearings / courses over ground are represented as a signed {@code short} value, mapping the range of -360°..+360° to the
|
||||
* value range of the {@code short} datatype. This results in a resolution of 0.01°.<p>
|
||||
*
|
||||
* Speed values are represented in knots in their compact form; lossy compaction uses a signed {@code short} value for
|
||||
* the knot speeds, assuming a range of -500kts..+500kts, spreading this range over the value range of the {@code short}
|
||||
* datatype. This results in a resolution of 0.015kts.<p>
|
||||
*
|
||||
* If an attempt is made to obtain a compact form of a knot speed or bearing where the value if out of the range described above,
|
||||
* a {@link CompactionNotPossibleException} will be thrown. Callers should then transparently resort to the precise
|
||||
* compaction counterparts for the respective type.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompactPositionHelper {
|
||||
private static final double LAT_SCALE = 90. / (double) (1 << 31); // int
|
||||
private static final double LNG_SCALE = 180. / (double) (1 << 31); // int
|
||||
|
||||
private static final double KNOT_SPEED_SCALE = 500. /* knots; what that we track would ever be faster? */ / (double) (1<<15); // short
|
||||
private static final double DEGREE_BEARING_SCALE = 360. / (double) (1<<15); // short
|
||||
|
||||
// Positions
|
||||
public static double getLatDeg(int latDegScaled) {
|
||||
return LAT_SCALE * latDegScaled;
|
||||
}
|
||||
|
||||
public static double getLngDeg(int lngDegScaled) {
|
||||
return LNG_SCALE * lngDegScaled;
|
||||
}
|
||||
|
||||
public static int getLngDegScaled(Position position) {
|
||||
return (int) (position.getLngDeg() / LNG_SCALE);
|
||||
}
|
||||
|
||||
public static int getLatDegScaled(Position position) {
|
||||
return (int) (position.getLatDeg() / LAT_SCALE);
|
||||
}
|
||||
|
||||
// Speeds / Bearings
|
||||
public static double getKnotSpeed(short knotSpeedScaled) {
|
||||
return KNOT_SPEED_SCALE * knotSpeedScaled;
|
||||
}
|
||||
|
||||
public static double getDegreeBearing(short degreeBearingScaled) {
|
||||
return DEGREE_BEARING_SCALE * degreeBearingScaled;
|
||||
}
|
||||
|
||||
public static short getKnotSpeedScaled(Speed speed) throws CompactionNotPossibleException {
|
||||
final double knotSpeedScaled = speed.getKnots() / KNOT_SPEED_SCALE;
|
||||
if (knotSpeedScaled > Short.MAX_VALUE || knotSpeedScaled < Short.MIN_VALUE) {
|
||||
throw new CompactionNotPossibleException("Speed "+speed+" cannot be compacted; "+speed.getKnots()+" does not fit into a signed short value");
|
||||
}
|
||||
return (short) knotSpeedScaled;
|
||||
}
|
||||
|
||||
public static short getDegreeBearingScaled(Bearing bearing) {
|
||||
return (short) (bearing.getDegrees() / DEGREE_BEARING_SCALE);
|
||||
}
|
||||
}
|
||||
-161
@@ -1,161 +0,0 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractPosition;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.AbstractTimePoint;
|
||||
|
||||
public class CompactWindImpl extends AbstractSpeedWithAbstractBearingImpl implements Wind {
|
||||
private static final long serialVersionUID = -5059956032663387929L;
|
||||
private final double latDeg;
|
||||
private final double lngDeg;
|
||||
private final boolean positionIsNull;
|
||||
private final boolean bearingIsNull;
|
||||
private final boolean timePointIsNull;
|
||||
private final double speedInKnots;
|
||||
private final double degBearing;
|
||||
private final long timePointAsMillis;
|
||||
|
||||
public class CompactPosition extends AbstractPosition {
|
||||
private static final long serialVersionUID = 5621506820766614178L;
|
||||
|
||||
@Override
|
||||
public double getLatDeg() {
|
||||
return latDeg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLngDeg() {
|
||||
return lngDeg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this==o || o instanceof Position && getLatDeg() == ((Position) o).getLatDeg() && getLngDeg() == ((Position) o).getLngDeg();
|
||||
}
|
||||
}
|
||||
|
||||
private class CompactBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = -6474909210513108635L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return degBearing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getRadians() {
|
||||
return degBearing / 180. * Math.PI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
return this==object || object instanceof Bearing && getDegrees() == ((Bearing) object).getDegrees();
|
||||
}
|
||||
}
|
||||
|
||||
private class CompactTimePoint extends AbstractTimePoint implements TimePoint {
|
||||
private static final long serialVersionUID = -2470922642359937437L;
|
||||
|
||||
@Override
|
||||
public long asMillis() {
|
||||
return timePointAsMillis;
|
||||
}
|
||||
}
|
||||
|
||||
public CompactWindImpl(Wind wind) {
|
||||
if (wind.getBearing() == null) {
|
||||
bearingIsNull = true;
|
||||
degBearing = 0;
|
||||
} else {
|
||||
this.degBearing = wind.getBearing().getDegrees();
|
||||
bearingIsNull = false;
|
||||
}
|
||||
if (wind.getPosition() == null) {
|
||||
positionIsNull = true;
|
||||
this.latDeg = 0;
|
||||
this.lngDeg = 0;
|
||||
} else {
|
||||
this.latDeg = wind.getPosition().getLatDeg();
|
||||
this.lngDeg = wind.getPosition().getLngDeg();
|
||||
positionIsNull = false;
|
||||
}
|
||||
this.speedInKnots = wind.getKnots();
|
||||
if (wind.getTimePoint() == null) {
|
||||
timePointIsNull = true;
|
||||
this.timePointAsMillis = 0;
|
||||
} else {
|
||||
timePointIsNull = false;
|
||||
this.timePointAsMillis = wind.getTimePoint().asMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
if (positionIsNull) {
|
||||
return null;
|
||||
} else {
|
||||
return new CompactPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePoint() {
|
||||
if (timePointIsNull) {
|
||||
return null;
|
||||
} else {
|
||||
return new CompactTimePoint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
if (bearingIsNull) {
|
||||
return null;
|
||||
} else {
|
||||
return new CompactBearing();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return speedInKnots;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getFrom() {
|
||||
if (getBearing() == null) {
|
||||
return null;
|
||||
} else {
|
||||
return getBearing().reverse();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return WindImpl.hashCode(latDeg, lngDeg, timePointIsNull?0:timePointAsMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (!(obj instanceof Wind))
|
||||
return false;
|
||||
Wind other = (Wind) obj;
|
||||
return Util.equalsWithNull(getPosition(), other.getPosition()) && Util.equalsWithNull(getTimePoint(), other.getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ""+getTimePoint()+"@"+getPosition()+": "+getKnots()+"kn from "+getFrom();
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
/**
|
||||
* Throws when an attempt is made to turn a fix of some sort into a more compact form, probably
|
||||
* slightly reducing accuracy and/or reducing value ranges, such as for the speeds possible, where
|
||||
* the fix presented cannot be turned into its compact form without exceeding a range. This would
|
||||
* lead to an overflow or wrap-around and cannot be tolerated. Clients need to handle this exception
|
||||
* by skipping compaction and using the original fix instead.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompactionNotPossibleException extends Exception {
|
||||
private static final long serialVersionUID = -723044264487667717L;
|
||||
|
||||
public CompactionNotPossibleException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CompactionNotPossibleException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
public CompactionNotPossibleException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public CompactionNotPossibleException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CompactionNotPossibleException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractPosition;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* A compact representation of a GPS fix which collects all primitive-typed attributes in one object to avoid
|
||||
* memory overhead otherwise created by using too many individual fine-grained objects.<p>
|
||||
*
|
||||
* Objects of this type are assumed to be contained in at most one {@link DynamicGPSFixTrackImpl}. It is
|
||||
* therefore permissible to cache information about validity to speed up the otherwise expensive
|
||||
* {@link DynamicGPSFixTrackImpl#isValid(PartialNavigableSetView, GPSFix)} computation.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class PreciseCompactGPSFixImpl extends AbstractCompactGPSFixImpl {
|
||||
private static final long serialVersionUID = 8167588584536992501L;
|
||||
|
||||
private final double latDeg;
|
||||
private final double lngDeg;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed's
|
||||
* true "bearing" (true course over ground) in degrees.
|
||||
*/
|
||||
private double cachedEstimatedSpeedBearingInDegrees;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed
|
||||
* in knots.
|
||||
*/
|
||||
private double cachedEstimatedSpeedInKnots;
|
||||
|
||||
public class PreciseCompactPosition extends AbstractPosition {
|
||||
private static final long serialVersionUID = 5621506820766614178L;
|
||||
|
||||
@Override
|
||||
public double getLatDeg() {
|
||||
return latDeg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLngDeg() {
|
||||
return lngDeg;
|
||||
}
|
||||
}
|
||||
|
||||
private class PreciseCompactEstimatedSpeedBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = 8549231429037883121L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return cachedEstimatedSpeedBearingInDegrees;
|
||||
}
|
||||
}
|
||||
|
||||
private class PreciseCompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl {
|
||||
private static final long serialVersionUID = -5871855443391817248L;
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
return new PreciseCompactEstimatedSpeedBearing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return cachedEstimatedSpeedInKnots;
|
||||
}
|
||||
}
|
||||
|
||||
public PreciseCompactGPSFixImpl(Position position, TimePoint timePoint) {
|
||||
super(timePoint);
|
||||
latDeg = position.getLatDeg();
|
||||
lngDeg = position.getLngDeg();
|
||||
}
|
||||
|
||||
public PreciseCompactGPSFixImpl(GPSFix gpsFix) {
|
||||
this(gpsFix.getPosition(), gpsFix.getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return new PreciseCompactPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getCachedEstimatedSpeed() {
|
||||
assert isEstimatedSpeedCached();
|
||||
return new PreciseCompactEstimatedSpeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) {
|
||||
cachedEstimatedSpeedBearingInDegrees = estimatedSpeed.getBearing().getDegrees();
|
||||
cachedEstimatedSpeedInKnots = estimatedSpeed.getKnots();
|
||||
super.cacheEstimatedSpeed(estimatedSpeed);
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractPosition;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* A memory-conserving representation of a {@link GPSFixMoving} object that produces the fine-grained
|
||||
* objects for {@link Position}, {@link SpeedWithBearing}, {@link Bearing} and {@link TimePoint} dynamically
|
||||
* as thin wrappers around this object which holds all elementary attributes required. This saves several
|
||||
* object references and object headers.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class PreciseCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl {
|
||||
private static final long serialVersionUID = 761582024504236533L;
|
||||
private final double latDeg;
|
||||
private final double lngDeg;
|
||||
private final double knotSpeed;
|
||||
private final double degBearing;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed's
|
||||
* true "bearing" (true course over ground) in degrees.
|
||||
*/
|
||||
private double cachedEstimatedSpeedBearingInDegrees;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed
|
||||
* in knots.
|
||||
*/
|
||||
private double cachedEstimatedSpeedInKnots;
|
||||
|
||||
|
||||
private class PreciseCompactSpeedWithBearing extends AbstractCompactSpeedWithBearing implements SpeedWithBearing {
|
||||
private static final long serialVersionUID = 1802065090733146728L;
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return knotSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
return new PreciseCompactBearing();
|
||||
}
|
||||
}
|
||||
|
||||
private class PreciseCompactBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = -6474909210513108635L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return degBearing;
|
||||
}
|
||||
}
|
||||
|
||||
public class PreciseCompactPosition extends AbstractPosition {
|
||||
private static final long serialVersionUID = 5621506820766614178L;
|
||||
|
||||
@Override
|
||||
public double getLatDeg() {
|
||||
return latDeg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLngDeg() {
|
||||
return lngDeg;
|
||||
}
|
||||
}
|
||||
|
||||
private class PreciseCompactEstimatedSpeedBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = 8549231429037883121L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return cachedEstimatedSpeedBearingInDegrees;
|
||||
}
|
||||
}
|
||||
|
||||
private class PreciseCompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl {
|
||||
private static final long serialVersionUID = -5871855443391817248L;
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
return new PreciseCompactEstimatedSpeedBearing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return cachedEstimatedSpeedInKnots;
|
||||
}
|
||||
}
|
||||
|
||||
public PreciseCompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) {
|
||||
super(timePoint);
|
||||
latDeg = position.getLatDeg();
|
||||
lngDeg = position.getLngDeg();
|
||||
knotSpeed = speed.getKnots();
|
||||
degBearing = speed.getBearing().getDegrees();
|
||||
}
|
||||
|
||||
public PreciseCompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) {
|
||||
this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeed() {
|
||||
return new PreciseCompactSpeedWithBearing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return new PreciseCompactPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getCachedEstimatedSpeed() {
|
||||
assert isEstimatedSpeedCached();
|
||||
return new PreciseCompactEstimatedSpeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) {
|
||||
cachedEstimatedSpeedBearingInDegrees = estimatedSpeed.getBearing().getDegrees();
|
||||
cachedEstimatedSpeedInKnots = estimatedSpeed.getKnots();
|
||||
super.cacheEstimatedSpeed(estimatedSpeed);
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractPosition;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
|
||||
/**
|
||||
* Keeps the precise values of lat/lng and speed/course.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class PreciseCompactWindImpl extends AbstractCompactWindImpl {
|
||||
private static final long serialVersionUID = -5059956032663387929L;
|
||||
private final double latDeg;
|
||||
private final double lngDeg;
|
||||
private final double speedInKnots;
|
||||
private final double degBearing;
|
||||
|
||||
public class CompactPosition extends AbstractPosition {
|
||||
private static final long serialVersionUID = 5621506820766614178L;
|
||||
|
||||
@Override
|
||||
public double getLatDeg() {
|
||||
return latDeg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLngDeg() {
|
||||
return lngDeg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this==o || o instanceof Position && getLatDeg() == ((Position) o).getLatDeg() && getLngDeg() == ((Position) o).getLngDeg();
|
||||
}
|
||||
}
|
||||
|
||||
private class CompactBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = -6474909210513108635L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return degBearing;
|
||||
}
|
||||
}
|
||||
|
||||
public PreciseCompactWindImpl(Wind wind) {
|
||||
super(wind);
|
||||
if (wind.getBearing() == null) {
|
||||
degBearing = 0;
|
||||
} else {
|
||||
this.degBearing = wind.getBearing().getDegrees();
|
||||
}
|
||||
if (wind.getPosition() == null) {
|
||||
this.latDeg = 0;
|
||||
this.lngDeg = 0;
|
||||
} else {
|
||||
this.latDeg = wind.getPosition().getLatDeg();
|
||||
this.lngDeg = wind.getPosition().getLngDeg();
|
||||
}
|
||||
this.speedInKnots = wind.getKnots();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return speedInKnots;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Position getCompactPosition() {
|
||||
return new CompactPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bearing getCompactBearing() {
|
||||
return new CompactBearing();
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractPosition;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* A compact representation of a GPS fix which collects all primitive-typed attributes in one object to avoid
|
||||
* memory overhead otherwise created by using too many individual fine-grained objects.<p>
|
||||
*
|
||||
* Objects of this type are assumed to be contained in at most one {@link DynamicGPSFixTrackImpl}. It is
|
||||
* therefore permissible to cache information about validity to speed up the otherwise expensive
|
||||
* {@link DynamicGPSFixTrackImpl#isValid(PartialNavigableSetView, GPSFix)} computation.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class VeryCompactGPSFixImpl extends AbstractCompactGPSFixImpl {
|
||||
private static final long serialVersionUID = 3943572107870245437L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(VeryCompactGPSFixImpl.class.getName());
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final int latDegScaled;
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final int lngDegScaled;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed's
|
||||
* true "bearing" (true course over ground) in degrees, scaled into a short value using {@link CompactPositionHelper}.
|
||||
*/
|
||||
private short cachedEstimatedSpeedBearingInDegreesScaled;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed
|
||||
* in knots, scaled into a short value using {@link CompactPositionHelper}.
|
||||
*/
|
||||
private short cachedEstimatedSpeedInKnotsScaled;
|
||||
|
||||
public class CompactPosition extends AbstractPosition {
|
||||
private static final long serialVersionUID = 5621506820766614178L;
|
||||
|
||||
@Override
|
||||
public double getLatDeg() {
|
||||
return CompactPositionHelper.getLatDeg(latDegScaled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLngDeg() {
|
||||
return CompactPositionHelper.getLngDeg(lngDegScaled);
|
||||
}
|
||||
}
|
||||
|
||||
private class VeryCompactEstimatedSpeedBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = 8549231429037883121L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return CompactPositionHelper.getDegreeBearing(cachedEstimatedSpeedBearingInDegreesScaled);
|
||||
}
|
||||
}
|
||||
|
||||
private class VeryCompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl {
|
||||
private static final long serialVersionUID = -5871855443391817248L;
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
return new VeryCompactEstimatedSpeedBearing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return CompactPositionHelper.getKnotSpeed(cachedEstimatedSpeedInKnotsScaled);
|
||||
}
|
||||
}
|
||||
|
||||
public VeryCompactGPSFixImpl(Position position, TimePoint timePoint) {
|
||||
super(timePoint);
|
||||
latDegScaled = CompactPositionHelper.getLatDegScaled(position);
|
||||
lngDegScaled = CompactPositionHelper.getLngDegScaled(position);
|
||||
}
|
||||
|
||||
public VeryCompactGPSFixImpl(GPSFix gpsFix) {
|
||||
this(gpsFix.getPosition(), gpsFix.getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return new CompactPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getCachedEstimatedSpeed() {
|
||||
assert isEstimatedSpeedCached();
|
||||
return new VeryCompactEstimatedSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Under rare circumstances, caching the speed may fail for the compact representation of a GPS fix.
|
||||
* This can happen if the speed estimated exceeds the range that can be represented in this compact
|
||||
* form which is less than in the original form where the speed amount is represented as a {@code double}
|
||||
* value. In this case, a warning message is logged with level {@link Level#FINER}, and the speed remains
|
||||
* uncached.
|
||||
*/
|
||||
@Override
|
||||
public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) {
|
||||
try {
|
||||
cachedEstimatedSpeedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(estimatedSpeed);
|
||||
cachedEstimatedSpeedBearingInDegreesScaled = CompactPositionHelper.getDegreeBearingScaled(estimatedSpeed.getBearing());
|
||||
super.cacheEstimatedSpeed(estimatedSpeed);
|
||||
} catch (CompactionNotPossibleException e) {
|
||||
logger.log(Level.FINER, "Cannot cache estimated speed "+estimatedSpeed+" in compact fix:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractPosition;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* A memory-conserving representation of a {@link GPSFixMoving} object that produces the fine-grained
|
||||
* objects for {@link Position}, {@link SpeedWithBearing}, {@link Bearing} and {@link TimePoint} dynamically
|
||||
* as thin wrappers around this object which holds all elementary attributes required. This saves several
|
||||
* object references and object headers.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class VeryCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl {
|
||||
private static final long serialVersionUID = 3977983319207618335L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(VeryCompactGPSFixMovingImpl.class.getName());
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final int latDegScaled;
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final int lngDegScaled;
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final short speedInKnotsScaled;
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final short degreeBearingScaled;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed's
|
||||
* true "bearing" (true course over ground) in degrees, scaled into a short value using {@link CompactPositionHelper}.
|
||||
*/
|
||||
private short cachedEstimatedSpeedBearingInDegreesScaled;
|
||||
|
||||
/**
|
||||
* When <code>{@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed
|
||||
* in knots, scaled into a short value using {@link CompactPositionHelper}.
|
||||
*/
|
||||
private short cachedEstimatedSpeedInKnotsScaled;
|
||||
|
||||
public class VeryCompactPosition extends AbstractPosition {
|
||||
private static final long serialVersionUID = 5621506820766614178L;
|
||||
|
||||
@Override
|
||||
public double getLatDeg() {
|
||||
return CompactPositionHelper.getLatDeg(latDegScaled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLngDeg() {
|
||||
return CompactPositionHelper.getLngDeg(lngDegScaled);
|
||||
}
|
||||
}
|
||||
|
||||
private class VeryCompactSpeedWithBearing extends AbstractCompactSpeedWithBearing {
|
||||
private static final long serialVersionUID = 1802065090733146728L;
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return CompactPositionHelper.getKnotSpeed(speedInKnotsScaled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
return new VeryCompactBearing();
|
||||
}
|
||||
}
|
||||
|
||||
private class VeryCompactBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = 8167886382067060570L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return CompactPositionHelper.getDegreeBearing(degreeBearingScaled);
|
||||
}
|
||||
}
|
||||
|
||||
private class VeryCompactEstimatedSpeedBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = 8549231429037883121L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return CompactPositionHelper.getDegreeBearing(cachedEstimatedSpeedBearingInDegreesScaled);
|
||||
}
|
||||
}
|
||||
|
||||
private class VeryCompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl {
|
||||
private static final long serialVersionUID = -5871855443391817248L;
|
||||
|
||||
@Override
|
||||
public Bearing getBearing() {
|
||||
return new VeryCompactEstimatedSpeedBearing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return CompactPositionHelper.getKnotSpeed(cachedEstimatedSpeedInKnotsScaled);
|
||||
}
|
||||
}
|
||||
|
||||
public VeryCompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) throws CompactionNotPossibleException {
|
||||
super(timePoint);
|
||||
latDegScaled = CompactPositionHelper.getLatDegScaled(position);
|
||||
lngDegScaled = CompactPositionHelper.getLngDegScaled(position);
|
||||
if (speed == null) {
|
||||
speedInKnotsScaled = 0;
|
||||
degreeBearingScaled = 0;
|
||||
} else {
|
||||
speedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(speed);
|
||||
degreeBearingScaled = CompactPositionHelper.getDegreeBearingScaled(speed.getBearing());
|
||||
}
|
||||
}
|
||||
|
||||
public VeryCompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) throws CompactionNotPossibleException {
|
||||
this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeed() {
|
||||
return new VeryCompactSpeedWithBearing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return new VeryCompactPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getCachedEstimatedSpeed() {
|
||||
assert isEstimatedSpeedCached();
|
||||
return new VeryCompactEstimatedSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Under rare circumstances, caching the speed may fail for the compact representation of a GPS fix.
|
||||
* This can happen if the speed estimated exceeds the range that can be represented in this compact
|
||||
* form which is less than in the original form where the speed amount is represented as a {@code double}
|
||||
* value. In this case, a warning message is logged with level {@link Level#FINER}, and the speed remains
|
||||
* uncached.
|
||||
*/
|
||||
@Override
|
||||
public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) {
|
||||
try {
|
||||
cachedEstimatedSpeedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(estimatedSpeed);
|
||||
cachedEstimatedSpeedBearingInDegreesScaled = CompactPositionHelper.getDegreeBearingScaled(estimatedSpeed.getBearing());
|
||||
super.cacheEstimatedSpeed(estimatedSpeed);
|
||||
} catch (CompactionNotPossibleException e) {
|
||||
logger.log(Level.FINER, "Cannot cache estimated speed "+estimatedSpeed+" in compact fix:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractBearing;
|
||||
import com.sap.sailing.domain.common.AbstractPosition;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
|
||||
/**
|
||||
* Uses scaled, rounded internal representations of the values for lat/lng and speed/course. See
|
||||
* {@link CompactPositionHelper} for the details of how value ranges and accuracies are affected.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class VeryCompactWindImpl extends AbstractCompactWindImpl {
|
||||
private static final long serialVersionUID = -5059956032663387929L;
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final int latDegScaled;
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final int lngDegScaled;
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final short speedInKnotsScaled;
|
||||
|
||||
/**
|
||||
* See {@link CompactPositionHelper}
|
||||
*/
|
||||
private final short degreeBearingScaled;
|
||||
|
||||
public class VeryCompactPosition extends AbstractPosition {
|
||||
private static final long serialVersionUID = 5621506820766614178L;
|
||||
|
||||
@Override
|
||||
public double getLatDeg() {
|
||||
return CompactPositionHelper.getLatDeg(latDegScaled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLngDeg() {
|
||||
return CompactPositionHelper.getLngDeg(lngDegScaled);
|
||||
}
|
||||
}
|
||||
|
||||
private class VeryCompactBearing extends AbstractBearing {
|
||||
private static final long serialVersionUID = -6474909210513108635L;
|
||||
|
||||
@Override
|
||||
public double getDegrees() {
|
||||
return CompactPositionHelper.getDegreeBearing(degreeBearingScaled);
|
||||
}
|
||||
}
|
||||
|
||||
public VeryCompactWindImpl(Wind wind) throws CompactionNotPossibleException {
|
||||
super(wind);
|
||||
if (wind.getBearing() == null) {
|
||||
degreeBearingScaled = 0;
|
||||
} else {
|
||||
this.degreeBearingScaled = CompactPositionHelper.getDegreeBearingScaled(wind.getBearing());
|
||||
}
|
||||
if (wind.getPosition() == null) {
|
||||
this.latDegScaled = 0;
|
||||
this.lngDegScaled = 0;
|
||||
} else {
|
||||
this.latDegScaled = CompactPositionHelper.getLatDegScaled(wind.getPosition());
|
||||
this.lngDegScaled = CompactPositionHelper.getLngDegScaled(wind.getPosition());
|
||||
}
|
||||
this.speedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(wind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getKnots() {
|
||||
return CompactPositionHelper.getKnotSpeed(speedInKnotsScaled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Position getCompactPosition() {
|
||||
return new VeryCompactPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bearing getCompactBearing() {
|
||||
return new VeryCompactBearing();
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -566,8 +566,7 @@ public class SensorFixStoreAndLoadTest {
|
||||
public static final String TRACK_NAME = "TestFixTrack";
|
||||
|
||||
public TestFixTrackImpl(ItemType trackedItem, String trackName) {
|
||||
super(trackedItem, trackName, TestFixImpl.COLUMNS,
|
||||
TRACK_NAME + " for " + trackedItem);
|
||||
super(trackedItem, trackName, TRACK_NAME + " for " + trackedItem);
|
||||
}
|
||||
|
||||
public Double getTextValue(TimePoint timePoint) {
|
||||
|
||||
+4
-4
@@ -4,8 +4,8 @@ import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.DoubleVectorFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
@@ -26,9 +26,9 @@ public class MockGPSFixMongoServiceFinder extends AbstractTypeBasedServiceFinder
|
||||
@Override
|
||||
public FixMongoHandler<?> findService(String fixType) {
|
||||
if (fixType.equals(GPSFixMovingImpl.class.getName()) ||
|
||||
fixType.equals(CompactGPSFixMovingImpl.class.getName())) return movingHandler;
|
||||
fixType.equals(VeryCompactGPSFixMovingImpl.class.getName())) return movingHandler;
|
||||
if (fixType.equals(GPSFixImpl.class.getName()) ||
|
||||
fixType.equals(CompactGPSFixImpl.class.getName())) return handler;
|
||||
fixType.equals(VeryCompactGPSFixImpl.class.getName())) return handler;
|
||||
if (fixType.equals(DoubleVectorFixImpl.class.getName())) return doubleVectorFixHandler;
|
||||
return null;
|
||||
}
|
||||
|
||||
-4
@@ -35,14 +35,10 @@ public interface SwissTimingReplayService {
|
||||
* @param link
|
||||
* the URL without the implicit "http://" prefix, as obtained, e.g., from
|
||||
* {@link SwissTimingReplayRace#getLink()}.
|
||||
* @param raceName TODO
|
||||
* @param raceID
|
||||
* the SwissTiming ID for the race
|
||||
* @param trackerManager TODO
|
||||
* @param useInternalMarkPassingAlgorithm
|
||||
* use our own instead of the SwissTiming-provided mark rounding / split times
|
||||
* @param raceLogStore TODO
|
||||
* @param regattaLogStore TODO
|
||||
* @param boatClassNameName
|
||||
* only required if {@code regattaToAddTo} is {@code null}; used for the retrieval/creation of a default
|
||||
* regatta
|
||||
|
||||
+26
-19
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracControlPoint;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.ControlPointAdapter;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.tractrac.model.lib.api.ModelLocator;
|
||||
import com.tractrac.model.lib.api.event.CreateModelException;
|
||||
@@ -36,6 +37,7 @@ import com.tractrac.subscription.lib.api.IRaceSubscriber;
|
||||
import com.tractrac.subscription.lib.api.ISubscriberFactory;
|
||||
import com.tractrac.subscription.lib.api.SubscriberInitializationException;
|
||||
import com.tractrac.subscription.lib.api.SubscriptionLocator;
|
||||
import com.tractrac.util.lib.api.exceptions.TimeOutException;
|
||||
|
||||
/**
|
||||
* Subclassing tests have to call {@link #addListenersForStoredDataAndStartController(Iterable)} to kick off
|
||||
@@ -65,6 +67,7 @@ public abstract class AbstractTracTracLiveTest extends StoredTrackBasedTest {
|
||||
* Default set-up for an STG training session in Weymouth, 2011
|
||||
* @throws SubscriberInitializationException
|
||||
* @throws CreateModelException
|
||||
* @throws TimeOutException
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws MalformedURLException, IOException, InterruptedException, URISyntaxException, SubscriberInitializationException, ParseException, CreateModelException {
|
||||
@@ -95,26 +98,30 @@ public abstract class AbstractTracTracLiveTest extends StoredTrackBasedTest {
|
||||
|
||||
protected void setUp(URL paramUrl, URI liveUri, URI storedUri) throws FileNotFoundException, MalformedURLException, URISyntaxException, SubscriberInitializationException, CreateModelException {
|
||||
// Read event data from configuration file
|
||||
final IRace race = ModelLocator.getEventFactory().createRace(new URI(paramUrl.toString()));
|
||||
this.race = race;
|
||||
ISubscriberFactory subscriberFactory = SubscriptionLocator.getSusbcriberFactory();
|
||||
if (storedUri == null) {
|
||||
eventSubscriber = subscriberFactory.createEventSubscriber(race.getEvent());
|
||||
raceSubscriber = subscriberFactory.createRaceSubscriber(race);
|
||||
} else {
|
||||
eventSubscriber = subscriberFactory.createEventSubscriber(race.getEvent(), liveUri, storedUri);
|
||||
raceSubscriber = subscriberFactory.createRaceSubscriber(race, liveUri, storedUri);
|
||||
}
|
||||
assertNotNull(race);
|
||||
// Initialize data controller using live and stored data sources
|
||||
if (storedUri != null && storedUri.toString().startsWith("file:")) {
|
||||
try {
|
||||
URI oldStoredUri = storedUri;
|
||||
storedUri = new URI(storedUri.toString().replaceFirst("file:/([^/])", "file:////$1"));
|
||||
logger.info("Replaced storedUri "+oldStoredUri+" by "+storedUri);
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
final IRace race = ModelLocator.getEventFactory().createRace(new URI(paramUrl.toString()), (int) /* timeout in milliseconds */ Duration.ONE_MINUTE.asMillis());
|
||||
this.race = race;
|
||||
ISubscriberFactory subscriberFactory = SubscriptionLocator.getSusbcriberFactory();
|
||||
if (storedUri == null) {
|
||||
eventSubscriber = subscriberFactory.createEventSubscriber(race.getEvent());
|
||||
raceSubscriber = subscriberFactory.createRaceSubscriber(race);
|
||||
} else {
|
||||
eventSubscriber = subscriberFactory.createEventSubscriber(race.getEvent(), liveUri, storedUri);
|
||||
raceSubscriber = subscriberFactory.createRaceSubscriber(race, liveUri, storedUri);
|
||||
}
|
||||
assertNotNull(race);
|
||||
// Initialize data controller using live and stored data sources
|
||||
if (storedUri != null && storedUri.toString().startsWith("file:")) {
|
||||
try {
|
||||
URI oldStoredUri = storedUri;
|
||||
storedUri = new URI(storedUri.toString().replaceFirst("file:/([^/])", "file:////$1"));
|
||||
logger.info("Replaced storedUri "+oldStoredUri+" by "+storedUri);
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (TimeOutException te) {
|
||||
throw new RuntimeException(te);
|
||||
}
|
||||
// test cases need to start the thread calling addListenersForStoredDataAndStartController
|
||||
// after adding their listeners
|
||||
|
||||
+1
-1
@@ -57,6 +57,6 @@ public class DistanceCacheInvalidationAfterLoadingFinishedTest extends TrackBase
|
||||
final Distance distance = speed.travel(Duration.ONE_SECOND);
|
||||
trackedRace.recordFix(competitor, new GPSFixMovingImpl(startPos.translateGreatCircle(bearing, distance), now.plus(Duration.ONE_SECOND), speed));
|
||||
trackedRace.onStatusChanged(tdl, new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, /* progress */ 1.0));
|
||||
assertEquals(distance.getMeters(), trackedRace.getDistanceTraveled(competitor, now.plus(Duration.ONE_SECOND.times(2))).getMeters(), 0.000001); // ask 1s after the second fix
|
||||
assertEquals(distance.getMeters(), trackedRace.getDistanceTraveled(competitor, now.plus(Duration.ONE_SECOND.times(2))).getMeters(), 0.01); // ask 1s after the second fix
|
||||
}
|
||||
}
|
||||
+40
@@ -61,6 +61,7 @@ import com.sap.sailing.domain.leaderboard.impl.HighPoint;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOverall;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10LastBreaksTie;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10Or8AndLastBreaksTie;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets12Or8AndLastBreaksTie2017;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
|
||||
@@ -1454,6 +1455,44 @@ public class LeaderboardScoringAndRankingTest extends LeaderboardScoringAndRanki
|
||||
assertEquals(new Double(1), leaderboardHighPointESSOverall.getNetPoints(competitors[14], later));
|
||||
assertEquals(new Double(1), leaderboardHighPointESSOverall.getNetPoints(competitors[15], later));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testESS2017WithCompetitorsBeingDSQScoringTwoLessThanLastCompetingCompetitor() throws NoWindException {
|
||||
Competitor[] competitors = createCompetitors(8).toArray(new Competitor[0]);
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
|
||||
FlexibleLeaderboard leaderboardHighPoint12LastBreaksTie2017 = new FlexibleLeaderboardImpl("Test ESS Highpoint",
|
||||
new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new HighPointFirstGets12Or8AndLastBreaksTie2017(), null);
|
||||
RaceColumn raceColumn = leaderboardHighPoint12LastBreaksTie2017
|
||||
.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(competitors)), "R1", /* medalRace */
|
||||
false);
|
||||
// test basic scores with best getting 12 and worst getting 5 in a 12 point scheme
|
||||
assertTrue(leaderboardHighPoint12LastBreaksTie2017.getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false).compare(
|
||||
leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later),
|
||||
leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[3], later)) < 0); // c0 better than c3
|
||||
assertEquals(8, leaderboardHighPoint12LastBreaksTie2017.getCompetitorsFromBestToWorst(later).size());
|
||||
assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later));
|
||||
assertEquals(new Double(5), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[7], later));
|
||||
// now let's assume that the first competitor is DSQ so it gets 4 points
|
||||
leaderboardHighPoint12LastBreaksTie2017.getScoreCorrection().setMaxPointsReason(competitors[0], raceColumn, MaxPointsReason.DSQ);
|
||||
assertEquals(8, leaderboardHighPoint12LastBreaksTie2017.getCompetitorsFromBestToWorst(later).size());
|
||||
assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[1], later));
|
||||
assertEquals(new Double(4), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later));
|
||||
assertEquals(new Double(6), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[7], later));
|
||||
leaderboardHighPoint12LastBreaksTie2017.getScoreCorrection().setMaxPointsReason(competitors[0], raceColumn, MaxPointsReason.NONE);
|
||||
assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later));
|
||||
assertEquals(new Double(5), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[7], later));
|
||||
leaderboardHighPoint12LastBreaksTie2017.getScoreCorrection().setMaxPointsReason(competitors[0], raceColumn, MaxPointsReason.DNS);
|
||||
assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[1], later));
|
||||
assertEquals(new Double(5), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later));
|
||||
assertEquals(new Double(6), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[7], later));
|
||||
// two competitors not started leading to tie
|
||||
leaderboardHighPoint12LastBreaksTie2017.getScoreCorrection().setMaxPointsReason(competitors[1], raceColumn, MaxPointsReason.DNS);
|
||||
assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[2], later));
|
||||
assertEquals(new Double(6), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[1], later));
|
||||
assertEquals(new Double(6), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverallLeaderboardWithESSHighPointScoring() throws NoWindException {
|
||||
@@ -1538,6 +1577,7 @@ public class LeaderboardScoringAndRankingTest extends LeaderboardScoringAndRanki
|
||||
assertEquals(c[0], rankedCompetitors.get(0));
|
||||
assertEquals(c[2], rankedCompetitors.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighPointScoringEightWithInterpolationWhenFleetNotComplete() throws NoWindException {
|
||||
int competitorsCount = 21;
|
||||
|
||||
+2
-2
@@ -74,7 +74,7 @@ public class LineAnalysisTest extends TrackBasedTest {
|
||||
final Distance distanceBehindLine = new MeterDistance(10);
|
||||
final Position behindMiddleOfLine = lineMiddle.translateGreatCircle(awayFromCourseSideOrthogonalToLine, distanceBehindLine);
|
||||
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(behindMiddleOfLine, now, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45))));
|
||||
assertEquals(distanceBehindLine.getMeters(), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.000001);
|
||||
assertEquals(distanceBehindLine.getMeters(), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,7 +90,7 @@ public class LineAnalysisTest extends TrackBasedTest {
|
||||
final Position behindOutsideOfLine = outsideOfLine.translateGreatCircle(awayFromCourseSideOrthogonalToLine, distanceBehindLine);
|
||||
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(behindOutsideOfLine, now, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45))));
|
||||
// the distance is that of the hypotenuse formed by the two cathesuses of 10m and 30m length, respectively:
|
||||
assertEquals(Math.sqrt(10.*10.+30.*30.), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.001);
|
||||
assertEquals(Math.sqrt(10.*10.+30.*30.), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.01);
|
||||
}
|
||||
|
||||
private Mark getMark(String name) {
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ public class MultipleClassesInRegattaTest {
|
||||
/* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
|
||||
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, domainFactory,
|
||||
tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
|
||||
/* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ true, /* preferReplayIfAvailable */ false);
|
||||
/* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ true, /* preferReplayIfAvailable */ false, /* timeoutInMillis */ -1);
|
||||
}
|
||||
|
||||
@After
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
|
||||
/**
|
||||
* Contains equality assertions for "compact" fixes, allowing for deltas to be specified, assuming
|
||||
* that the "compact" version of a fix may vary slightly from its original.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class PositionAssert {
|
||||
public static void assertPositionEquals(Position p1, Position p2, double degreeDelta) {
|
||||
assertEquals(p1.getLatDeg(), p2.getLatDeg(), degreeDelta);
|
||||
assertEquals(p1.getLngDeg(), p2.getLngDeg(), degreeDelta);
|
||||
}
|
||||
|
||||
public static void assertGPSFixEquals(GPSFixMoving f1, GPSFixMoving f2, double positionDegreeDelta, double bearingDegreeDelta, double knotDelta) {
|
||||
assertGPSFixEquals((GPSFix) f1, (GPSFix) f2, positionDegreeDelta);
|
||||
assertSpeedEquals(f1.getSpeed(), f2.getSpeed(), bearingDegreeDelta, knotDelta);
|
||||
}
|
||||
|
||||
public static void assertBearingEquals(Bearing b1, Bearing b2, double bearingDegreeDelta) {
|
||||
assertEquals(b1.getDegrees(), b2.getDegrees(), bearingDegreeDelta);
|
||||
}
|
||||
|
||||
public static void assertGPSFixEquals(GPSFix f1, GPSFix f2, double positionDegreeDelta) {
|
||||
assertPositionEquals(f1.getPosition(), f2.getPosition(), positionDegreeDelta);
|
||||
assertEquals(f1.getTimePoint(), f2.getTimePoint());
|
||||
}
|
||||
|
||||
public static void assertWindEquals(Wind w1, Wind w2, double posDegDelta, double bearingDegreeDelta, double knotSpeedDelta) {
|
||||
assertEquals(w1.getTimePoint(), w2.getTimePoint());
|
||||
assertPositionEquals(w1.getPosition(), w2.getPosition(), posDegDelta);
|
||||
assertBearingEquals(w1.getBearing(), w2.getBearing(), bearingDegreeDelta);
|
||||
assertSpeedEquals(w1, w2, bearingDegreeDelta, knotSpeedDelta);
|
||||
}
|
||||
|
||||
public static void assertSpeedEquals(Speed s1, Speed s2, double knotSpeedDelta) {
|
||||
assertEquals(s1.getKnots(), s2.getKnots(), knotSpeedDelta);
|
||||
}
|
||||
|
||||
public static void assertSpeedEquals(SpeedWithBearing s1, SpeedWithBearing s2, double bearingDegreeDelta, double knotSpeedDelta) {
|
||||
assertBearingEquals(s1.getBearing(), s2.getBearing(), bearingDegreeDelta);
|
||||
assertSpeedEquals((Speed) s1, (Speed) s2, knotSpeedDelta);
|
||||
}
|
||||
|
||||
public static void assertWindEquals(Set<Wind> expectedWinds, Set<Wind> actualWinds, double posDegDelta,
|
||||
double bearingDegreeDelta, double knotSpeedDelta) {
|
||||
for (final Wind expectedWind : expectedWinds) {
|
||||
boolean found = false;
|
||||
for (final Wind actualWind : actualWinds) {
|
||||
try {
|
||||
assertWindEquals(expectedWind, actualWind, posDegDelta, bearingDegreeDelta, knotSpeedDelta);
|
||||
found = true;
|
||||
break;
|
||||
} catch (AssertionError e) {
|
||||
// not equals
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
fail("Expected to find "+expectedWind+" in "+actualWinds+" but didn't");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,11 @@ 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.common.impl.NauticalMileDistance;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class PositionTest {
|
||||
@@ -32,20 +35,40 @@ public class PositionTest {
|
||||
@Test
|
||||
public void testEqualityBetweenCompactAndVerbosePosition() {
|
||||
Position p1 = new DegreePosition(49.2, 008.3);
|
||||
CompactGPSFixImpl compactFix = new CompactGPSFixImpl(p1, MillisecondsTimePoint.now());
|
||||
VeryCompactGPSFixImpl compactFix = new VeryCompactGPSFixImpl(p1, MillisecondsTimePoint.now());
|
||||
assertNotSame(p1, compactFix.getPosition());
|
||||
assertEquals(p1, compactFix.getPosition());
|
||||
PositionAssert.assertPositionEquals(p1, compactFix.getPosition(), 0.000001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualityBetweenCompactAndVerboseSpeedWithBearing() {
|
||||
public void testCompactFixRange() {
|
||||
final TimePoint now = MillisecondsTimePoint.now();
|
||||
assertCompactFixHasEqualLatLng(now, 0., 0.);
|
||||
assertCompactFixHasEqualLatLng(now, 90., 0.);
|
||||
assertCompactFixHasEqualLatLng(now, -90., 0.);
|
||||
assertCompactFixHasEqualLatLng(now, 0., 180.);
|
||||
assertCompactFixHasEqualLatLng(now, 0., -180.);
|
||||
assertCompactFixHasEqualLatLng(now, 45., 45.);
|
||||
assertCompactFixHasEqualLatLng(now, 0., -45.);
|
||||
assertCompactFixHasEqualLatLng(now, -45., 45.);
|
||||
assertCompactFixHasEqualLatLng(now, 0., 45.);
|
||||
}
|
||||
|
||||
private void assertCompactFixHasEqualLatLng(final TimePoint now, final double latDeg, final double lngDeg) {
|
||||
GPSFix fix = new VeryCompactGPSFixImpl(new DegreePosition(latDeg, lngDeg), now);
|
||||
assertEquals(latDeg, fix.getPosition().getLatDeg(), 0.0000001);
|
||||
assertEquals(lngDeg, fix.getPosition().getLngDeg(), 0.0000001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualityBetweenCompactAndVerboseSpeedWithBearing() throws CompactionNotPossibleException {
|
||||
Position p1 = new DegreePosition(49.2, 008.3);
|
||||
SpeedWithBearing swb = new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123));
|
||||
CompactGPSFixMovingImpl compactFix = new CompactGPSFixMovingImpl(p1, MillisecondsTimePoint.now(), swb);
|
||||
VeryCompactGPSFixMovingImpl compactFix = new VeryCompactGPSFixMovingImpl(p1, MillisecondsTimePoint.now(), swb);
|
||||
assertNotSame(p1, compactFix.getPosition());
|
||||
assertEquals(p1, compactFix.getPosition());
|
||||
PositionAssert.assertPositionEquals(p1, compactFix.getPosition(), 0.000001);
|
||||
assertNotSame(swb, compactFix.getSpeed());
|
||||
assertEquals(swb, compactFix.getSpeed());
|
||||
PositionAssert.assertSpeedEquals(swb, compactFix.getSpeed(), /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+3
-3
@@ -338,7 +338,7 @@ public class ReachingLegTest extends TrackBasedTest {
|
||||
Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(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);
|
||||
assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters()*1.5, plattnersDistanceToLeader.getMeters(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -373,9 +373,9 @@ public class ReachingLegTest extends TrackBasedTest {
|
||||
.getEstimatedPosition(timePointToConsider, /* extrapolate */false)
|
||||
.getDistance(
|
||||
getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */
|
||||
false)).getMeters(), 0.00001);
|
||||
false)).getMeters(), 0.01);
|
||||
// however, projected onto the leg their distance should be 0
|
||||
Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE);
|
||||
assertEquals(0., plattnersDistanceToLeader.getMeters(), 0.00001);
|
||||
assertEquals(0., plattnersDistanceToLeader.getMeters(), 0.01);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -141,7 +141,7 @@ public class StarbordSideOfStartLineRecognitionTest {
|
||||
MockedTrackedRaceImpl trackedRace = createTrackedRaceWithMarkPositions(startPortPosition, startStarboardPosition, windwardPosition);
|
||||
Position p = trackedRace.getOrCreateTrack(trackedRace.getStartLine(now).getStarboardMarkWhileApproachingLine()).
|
||||
getEstimatedPosition(now, /* extrapolate */ false);
|
||||
assertEquals(startStarboardPosition, p);
|
||||
PositionAssert.assertPositionEquals(startStarboardPosition, p, 0.0000001);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -43,7 +43,8 @@ import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.MeterPerSecondSpeedWithDegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
@@ -63,6 +64,7 @@ import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class TrackTest {
|
||||
private static final int MILLIS_BETWEEN_FIXES = 3000000;
|
||||
private DynamicGPSFixTrack<Boat, GPSFixMoving> track;
|
||||
private GPSFixMovingImpl gpsFix1;
|
||||
private GPSFixMovingImpl gpsFix2;
|
||||
@@ -75,7 +77,7 @@ public class TrackTest {
|
||||
track = new DynamicGPSFixMovingTrackImpl<Boat>(new BoatImpl("MyFirstBoat", new BoatClassImpl("505", /* typicallyStartsUpwind */
|
||||
true), null), /* millisecondsOverWhichToAverage */5000, /* no smoothening */null);
|
||||
TimePoint now1 = MillisecondsTimePoint.now();
|
||||
TimePoint now2 = addMillisToTimepoint(now1, 3);
|
||||
TimePoint now2 = addMillisToTimepoint(now1, MILLIS_BETWEEN_FIXES);
|
||||
DegreePosition position1 = new DegreePosition(1, 2);
|
||||
DegreePosition position2 = new DegreePosition(1, 3);
|
||||
gpsFix1 = new GPSFixMovingImpl(
|
||||
@@ -84,19 +86,19 @@ public class TrackTest {
|
||||
new DegreeBearingImpl(90)));
|
||||
gpsFix2 = new GPSFixMovingImpl(position2, now2, new KnotSpeedWithBearingImpl(position1.getDistance(position2)
|
||||
.inTime(now2.asMillis() - gpsFix1.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(90)));
|
||||
TimePoint now3 = addMillisToTimepoint(now2, 3);
|
||||
TimePoint now3 = addMillisToTimepoint(now2, MILLIS_BETWEEN_FIXES);
|
||||
Position position3 = new DegreePosition(1, 4);
|
||||
gpsFix3 = new GPSFixMovingImpl(
|
||||
position3, now3, new KnotSpeedWithBearingImpl(position2.getDistance(position3)
|
||||
.inTime(now3.asMillis() - gpsFix2.getTimePoint().asMillis()).getKnots(),
|
||||
new DegreeBearingImpl(0)));
|
||||
TimePoint now4 = addMillisToTimepoint(now3, 3);
|
||||
TimePoint now4 = addMillisToTimepoint(now3, MILLIS_BETWEEN_FIXES);
|
||||
Position position4 = new DegreePosition(3, 4);
|
||||
gpsFix4 = new GPSFixMovingImpl(
|
||||
position4, now4, new KnotSpeedWithBearingImpl(position3.getDistance(position4)
|
||||
.inTime(now4.asMillis() - gpsFix3.getTimePoint().asMillis()).getKnots(),
|
||||
new DegreeBearingImpl(0)));
|
||||
TimePoint now5 = addMillisToTimepoint(now4, 3);
|
||||
TimePoint now5 = addMillisToTimepoint(now4, MILLIS_BETWEEN_FIXES);
|
||||
Position position5 = new DegreePosition(5, 4);
|
||||
gpsFix5 = new GPSFixMovingImpl(position5, now5, new KnotSpeedWithBearingImpl(position4.getDistance(position5)
|
||||
.inTime(now5.asMillis() - gpsFix4.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(0)));
|
||||
@@ -106,6 +108,7 @@ public class TrackTest {
|
||||
track.addGPSFix(gpsFix4);
|
||||
track.addGPSFix(gpsFix5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for a incorrect method of estimating Positions
|
||||
*/
|
||||
@@ -128,7 +131,6 @@ public class TrackTest {
|
||||
assertEquals(45, track.getEstimatedPosition(t1.plus(15), true).getLatDeg(), 0.00000001);
|
||||
assertEquals(60, track.getEstimatedPosition(t1.plus(20), true).getLatDeg(), 0.00000001);
|
||||
assertEquals(90, track.getEstimatedPosition(t1.plus(30), true).getLatDeg(), 0.00000001);
|
||||
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
@@ -221,7 +223,7 @@ public class TrackTest {
|
||||
now = nextNow;
|
||||
}
|
||||
assertEquals(speed.travel(start, now.minus(NUMBER_OF_FIXES_AT_SAME_POSITION * 1000)).getMeters(),
|
||||
track.getDistanceTraveled(start, now).getMeters(), 0.00000001);
|
||||
track.getDistanceTraveled(start, now).getMeters(), 0.01);
|
||||
}
|
||||
|
||||
private void addFixesWithSamePositionButProgressingTime(DynamicGPSFixTrack<Object, GPSFixMoving> track,
|
||||
@@ -320,7 +322,7 @@ public class TrackTest {
|
||||
cacheBarrier.await(20, TimeUnit.SECONDS);
|
||||
cacheDone.await(20, TimeUnit.SECONDS);
|
||||
testDone.await();
|
||||
assertEquals(2., maxSpeed[0], 0.001);
|
||||
assertEquals(2., maxSpeed[0], 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -366,12 +368,12 @@ public class TrackTest {
|
||||
1, new DegreeBearingImpl(123)));
|
||||
track.addGPSFix(fix3);
|
||||
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(7200000)).
|
||||
getB().getKnots(), 0.001); // produces a cache entry that ends
|
||||
getB().getKnots(), 0.01); // produces a cache entry that ends
|
||||
GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(10800000), new KnotSpeedWithBearingImpl(
|
||||
1, new DegreeBearingImpl(123)));
|
||||
track.addGPSFix(fix4);
|
||||
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)).
|
||||
getB().getKnots(), 0.001);
|
||||
getB().getKnots(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -383,7 +385,7 @@ public class TrackTest {
|
||||
2, new DegreeBearingImpl(123)));
|
||||
track.addGPSFix(fast);
|
||||
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)).
|
||||
getB().getKnots(), 0.001);
|
||||
getB().getKnots(), 0.01);
|
||||
track.addGPSFix(slow);
|
||||
track.lockForRead();
|
||||
try {
|
||||
@@ -392,7 +394,7 @@ public class TrackTest {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
assertEquals(1., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)).
|
||||
getB().getKnots(), 0.001);
|
||||
getB().getKnots(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -405,7 +407,7 @@ public class TrackTest {
|
||||
2, new DegreeBearingImpl(123)));
|
||||
track.addGPSFix(fix2);
|
||||
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(7200000)).
|
||||
getB().getKnots(), 0.001); // produces a cache entry that ends
|
||||
getB().getKnots(), 0.01); // produces a cache entry that ends
|
||||
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(7200000), new KnotSpeedWithBearingImpl(
|
||||
1, new DegreeBearingImpl(123)));
|
||||
track.addGPSFix(fix3);
|
||||
@@ -413,7 +415,7 @@ public class TrackTest {
|
||||
1, new DegreeBearingImpl(123)));
|
||||
track.addGPSFix(fix4);
|
||||
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)).
|
||||
getB().getKnots(), 0.001);
|
||||
getB().getKnots(), 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -462,7 +464,7 @@ public class TrackTest {
|
||||
track.addGPSFix(f2);
|
||||
track.addGPSFix(f3);
|
||||
SpeedWithBearing average = track.getEstimatedSpeed(t2);
|
||||
assertEquals(0, average.getBearing().getDegrees(), 0.00001);
|
||||
PositionAssert.assertBearingEquals(new DegreeBearingImpl(0), average.getBearing(), 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -477,7 +479,7 @@ public class TrackTest {
|
||||
track.addGPSFix(f1);
|
||||
track.addGPSFix(f2);
|
||||
track.addGPSFix(f3);
|
||||
assertEquals(f2, track.getFirstFixAtOrAfter(f2.getTimePoint())); // expect the fix to still be valid, but only its provided speed shall be ignored
|
||||
PositionAssert.assertGPSFixEquals(f2, track.getFirstFixAtOrAfter(f2.getTimePoint()), /* pos deg delta */ 0.00001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01); // expect the fix to still be valid, but only its provided speed shall be ignored
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -492,7 +494,7 @@ public class TrackTest {
|
||||
track.addGPSFix(f1);
|
||||
track.addGPSFix(f2);
|
||||
track.addGPSFix(f3);
|
||||
assertEquals(f3, track.getFirstFixAtOrAfter(f2.getTimePoint())); // expect the f2 fix to be invalid
|
||||
PositionAssert.assertGPSFixEquals(f3, track.getFirstFixAtOrAfter(f2.getTimePoint()), /* pos deg delta */ 0.00001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01); // expect the fix to still be valid, but only its provided speed shall be ignored
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -508,7 +510,7 @@ public class TrackTest {
|
||||
track.addGPSFix(f2);
|
||||
track.addGPSFix(f3);
|
||||
// expect the f2 fix to be invalid because provided speed is too different
|
||||
assertEquals(0, f3.getPosition().getDistance(track.getFirstFixAtOrAfter(f2.getTimePoint()).getPosition()).getMeters(), 0.001);
|
||||
assertEquals(0, f3.getPosition().getDistance(track.getFirstFixAtOrAfter(f2.getTimePoint()).getPosition()).getMeters(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -523,9 +525,9 @@ public class TrackTest {
|
||||
track.addGPSFix(f1);
|
||||
track.addGPSFix(f2);
|
||||
track.addGPSFix(f3);
|
||||
assertEquals(f2, track.getFirstFixAtOrAfter(f2.getTimePoint())); // expect the fix to still be valid, but only its provided speed shall be ignored
|
||||
PositionAssert.assertGPSFixEquals(f2, track.getFirstFixAtOrAfter(f2.getTimePoint()), /* pos deg delta */ 0.00001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01); // expect the fix to still be valid, but only its provided speed shall be ignored
|
||||
SpeedWithBearing average = track.getEstimatedSpeed(t2);
|
||||
assertEquals(1, average.getKnots(), 0.001);
|
||||
assertEquals(1, average.getKnots(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -541,7 +543,7 @@ public class TrackTest {
|
||||
track.addGPSFix(f2);
|
||||
track.addGPSFix(f3);
|
||||
SpeedWithBearing average = track.getRawEstimatedSpeed(t2);
|
||||
assertEquals(0, average.getBearing().getDegrees(), 0.00001);
|
||||
PositionAssert.assertBearingEquals(new DegreeBearingImpl(0), average.getBearing(), /* deg delta */ 0.1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -560,14 +562,14 @@ public class TrackTest {
|
||||
Iterator<GPSFixMoving> subsetIter = subset.iterator();
|
||||
// start iteration
|
||||
GPSFixMoving firstOfSubset = subsetIter.next();
|
||||
assertEquals(gpsFix2, firstOfSubset);
|
||||
PositionAssert.assertGPSFixEquals(gpsFix2, firstOfSubset, /* pos deg delta */ 0.00001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01);
|
||||
// now add a fix:
|
||||
TimePoint now6 = addMillisToTimepoint(gpsFix5.getTimePoint(), 3);
|
||||
track.addGPSFix(new GPSFixMovingImpl(
|
||||
new DegreePosition(6, 5), now6, new KnotSpeedWithBearingImpl(2, new DegreeBearingImpl(0))));
|
||||
try {
|
||||
GPSFixMoving secondOfSubset = subsetIter.next();
|
||||
assertEquals(gpsFix3, secondOfSubset);
|
||||
PositionAssert.assertGPSFixEquals(gpsFix3, secondOfSubset, /* pos deg delta */ 0.000001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01);
|
||||
fail("adding a fix interferes with iteration over subSet of track's fixes");
|
||||
} catch (ConcurrentModificationException e) {
|
||||
// this is what we expected
|
||||
@@ -675,7 +677,7 @@ public class TrackTest {
|
||||
TimePoint afterTimePoint = new MillisecondsTimePoint(millis + (millis-lastMillis));
|
||||
Position extrapolatedPosition = track.getEstimatedPosition(afterTimePoint, true);
|
||||
assertEquals(0.5, fix.getPosition().getDistance(extrapolatedPosition).getMeters()
|
||||
/ lastFix.getPosition().getDistance(extrapolatedPosition).getMeters(), 0.00001);
|
||||
/ lastFix.getPosition().getDistance(extrapolatedPosition).getMeters(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -792,7 +794,7 @@ public class TrackTest {
|
||||
bearing = new DegreeBearingImpl(bearing.getDegrees() + 1);
|
||||
}
|
||||
invalidationCalls.clear();
|
||||
assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.01);
|
||||
assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.02);
|
||||
final com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> fullIntervalCacheEntry = distanceCache.getEarliestFromAndDistanceAtOrAfterFrom(now, start);
|
||||
assertNotNull(fullIntervalCacheEntry); // no more entry for "to"-value start in cache
|
||||
assertEquals(start, fullIntervalCacheEntry.getA());
|
||||
@@ -808,7 +810,7 @@ public class TrackTest {
|
||||
invalidationCalls.clear();
|
||||
final TimePoint timePointOfLastOriginalFix = track.getLastRawFix().getTimePoint();
|
||||
assertEquals(speed.getMetersPerSecond() * (steps - 1),
|
||||
track.getDistanceTraveled(now, timePointOfLastOriginalFix).getMeters(), 0.01);
|
||||
track.getDistanceTraveled(now, timePointOfLastOriginalFix).getMeters(), 0.02);
|
||||
final com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> newFullIntervalCacheEntry = distanceCache
|
||||
.getEarliestFromAndDistanceAtOrAfterFrom(now, timePointOfLastOriginalFix);
|
||||
assertNotNull(newFullIntervalCacheEntry); // no more entry for "to"-value start in cache
|
||||
@@ -861,7 +863,7 @@ public class TrackTest {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
GPSFix polishedLastFix2 = track.getLastFixBefore(new MillisecondsTimePoint(Long.MAX_VALUE)); // get the last smoothened fix...
|
||||
assertEquals(fix, polishedLastFix2);
|
||||
PositionAssert.assertGPSFixEquals(fix, polishedLastFix2, /* pos deg delta */ 0.000001);
|
||||
assertEquals(speed.getMetersPerSecond()*steps, track.getDistanceTraveled(now, start).getMeters(), 0.01);
|
||||
}
|
||||
|
||||
@@ -1003,7 +1005,7 @@ public class TrackTest {
|
||||
final TimePoint stripTo = start.minus(2*timeBetweenFixesInMillis);
|
||||
assertEquals(speed.getMetersPerSecond()*(steps-3),
|
||||
track.getDistanceTraveled(stripFrom, stripTo).getMeters(), 0.01);
|
||||
assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.01);
|
||||
assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.02);
|
||||
assertTrue(invalidationCalls.isEmpty());
|
||||
// expect a cache entry exactly for the strip's boundaries
|
||||
com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> stripCacheEntry = distanceCache.getEarliestFromAndDistanceAtOrAfterFrom(stripFrom, stripTo);
|
||||
@@ -1054,8 +1056,7 @@ public class TrackTest {
|
||||
assertEquals(gpsFix2.getPosition().getLatDeg(), estimatedPosNew.getLatDeg(), 0.5);
|
||||
assertEquals(gpsFix2.getPosition().getLngDeg(), estimatedPosNew.getLngDeg(), 0.5);
|
||||
SpeedWithBearing estimatedSpeedNew = track.getEstimatedSpeed(normalFixesTime);
|
||||
assertEquals(estimatedSpeed.getKnots(), estimatedSpeedNew.getKnots(), 0.001);
|
||||
assertEquals(estimatedSpeed.getBearing().getDegrees(), estimatedSpeedNew.getBearing().getDegrees(), 0.001);
|
||||
PositionAssert.assertSpeedEquals(estimatedSpeed, estimatedSpeedNew, /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1262,21 +1263,21 @@ public class TrackTest {
|
||||
|
||||
@Test
|
||||
public void testFrequency() {
|
||||
assertEquals(3, track.getAverageIntervalBetweenFixes().asMillis());
|
||||
assertEquals(3, track.getAverageIntervalBetweenRawFixes().asMillis());
|
||||
assertEquals(MILLIS_BETWEEN_FIXES, track.getAverageIntervalBetweenFixes().asMillis());
|
||||
assertEquals(MILLIS_BETWEEN_FIXES, track.getAverageIntervalBetweenRawFixes().asMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEstimatedSpeedCaching() {
|
||||
public void testEstimatedSpeedCaching() throws CompactionNotPossibleException {
|
||||
GPSFixMoving originalFix = new GPSFixMovingImpl(new DegreePosition(12, 34), MillisecondsTimePoint.now(),
|
||||
new KnotSpeedWithBearingImpl(9, new DegreeBearingImpl(123)));
|
||||
GPSFixMoving fix = new CompactGPSFixMovingImpl(originalFix);
|
||||
GPSFixMoving fix = new VeryCompactGPSFixMovingImpl(originalFix);
|
||||
assertFalse(fix.isEstimatedSpeedCached());
|
||||
final KnotSpeedWithBearingImpl estimatedSpeed = new KnotSpeedWithBearingImpl(9.1, new DegreeBearingImpl(124));
|
||||
fix.cacheEstimatedSpeed(estimatedSpeed);
|
||||
assertTrue(fix.isEstimatedSpeedCached());
|
||||
SpeedWithBearing cachedEstimatedSpeed = fix.getCachedEstimatedSpeed();
|
||||
assertEquals(estimatedSpeed, cachedEstimatedSpeed);
|
||||
PositionAssert.assertSpeedEquals(estimatedSpeed, cachedEstimatedSpeed, /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1);
|
||||
fix.invalidateEstimatedSpeedCache();
|
||||
assertFalse(fix.isEstimatedSpeedCached());
|
||||
}
|
||||
@@ -1287,8 +1288,9 @@ public class TrackTest {
|
||||
assertFalse(compactFix3.isEstimatedSpeedCached());
|
||||
SpeedWithBearing fix3EstimatedSpeed = track.getEstimatedSpeed(gpsFix3.getTimePoint());
|
||||
assertTrue(compactFix3.isEstimatedSpeedCached());
|
||||
assertEquals(fix3EstimatedSpeed, compactFix3.getCachedEstimatedSpeed());
|
||||
assertEquals(fix3EstimatedSpeed, track.getEstimatedSpeed(gpsFix3.getTimePoint())); // fetch again from the cache
|
||||
PositionAssert.assertSpeedEquals(fix3EstimatedSpeed, compactFix3.getCachedEstimatedSpeed(), /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1);
|
||||
PositionAssert.assertSpeedEquals(fix3EstimatedSpeed, track.getEstimatedSpeed(gpsFix3.getTimePoint()),
|
||||
/* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); // fetch again from the cache
|
||||
// assuming that all test fixes are within a few milliseconds and the averaging interval is much larger than that,
|
||||
// adding a single fix in the middle should invalidate the cache
|
||||
track.add(new GPSFixMovingImpl(gpsFix3.getPosition(), gpsFix3.getTimePoint().plus(1), gpsFix3.getSpeed()));
|
||||
|
||||
+3
-1
@@ -68,7 +68,9 @@ public class UnicodeCharactersInCompetitorNamesTest {
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l,
|
||||
/* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
|
||||
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, domainFactory,
|
||||
"tracTest", "tracTest", "", "", /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ true, /* preferReplayIfAvailable */ false), RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
"tracTest", "tracTest", "", "", /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ true,
|
||||
/* preferReplayIfAvailable */ false, /* timeoutInMillis */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS),
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
|
||||
Iterable<Competitor> competitors = fourtyninerYellow_2.getRaceHandle().getRace().getCompetitors();
|
||||
for (Competitor competitor : competitors) {
|
||||
|
||||
+10
-10
@@ -186,9 +186,9 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
|
||||
};
|
||||
Wind estimatedWindDirection = track.getAveragedWind(/* position */ null, checkTime);
|
||||
assertNotNull(estimatedWindDirection);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1);
|
||||
assertFalse(cachedFixes.isEmpty());
|
||||
assertEquals(185., cachedFixes.values().iterator().next().getObject().getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., cachedFixes.values().iterator().next().getObject().getBearing().getDegrees(), 0.1);
|
||||
// now invert leg's type by moving the top mark along the wind from the leeward gate:
|
||||
Iterator<Waypoint> waypointsIter = getTrackedRace().getRace().getCourse().getWaypoints().iterator();
|
||||
Waypoint leewardMark = waypointsIter.next();
|
||||
@@ -202,7 +202,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
|
||||
assertEquals(LegType.DOWNWIND, firstLeg.getLegType(fixTime));
|
||||
Wind estimatedWindDirectionDownwind = track.getAveragedWind(/* position */ null, checkTime);
|
||||
assertNotNull(estimatedWindDirectionDownwind);
|
||||
assertEquals(185., estimatedWindDirectionDownwind.getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., estimatedWindDirectionDownwind.getBearing().getDegrees(), 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -229,15 +229,15 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
|
||||
};
|
||||
Wind estimatedWindDirection = track.getAveragedWind(/* position */ null, checkTime);
|
||||
assertNotNull(estimatedWindDirection);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1);
|
||||
assertFalse(cachedFixes.isEmpty());
|
||||
assertEquals(185., cachedFixes.values().iterator().next().getObject().getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., cachedFixes.values().iterator().next().getObject().getBearing().getDegrees(), 0.1);
|
||||
// now clear set of cached fixes, ask again and ensure nothing is cached again:
|
||||
cachedFixes.clear();
|
||||
Wind estimatedWindDirectionCached = track.getAveragedWind(/* position */ null, checkTime);
|
||||
assertTrue(cachedFixes.isEmpty());
|
||||
assertNotNull(estimatedWindDirectionCached);
|
||||
assertEquals(185., estimatedWindDirectionCached.getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., estimatedWindDirectionCached.getBearing().getDegrees(), 0.1);
|
||||
// now add a GPS fix and make sure the cache is invalidated by adding it inside the averaging interval
|
||||
now = new MillisecondsTimePoint(checkTime.asMillis() + track.getMillisecondsOverWhichToAverageWind()/2);
|
||||
setBearingForCompetitor(competitors.get(0), now, 330);
|
||||
@@ -257,7 +257,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
|
||||
setBearingForCompetitor(competitors.get(0), now, 320);
|
||||
setBearingForCompetitor(competitors.get(1), now, 50);
|
||||
Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(now);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -268,7 +268,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
|
||||
setBearingForCompetitor(competitors.get(1), now, 50);
|
||||
setBearingForCompetitor(competitors.get(2), new MillisecondsTimePoint(0), 100); // this shouldn't disturb the estimation because it's too old
|
||||
Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(now);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -280,7 +280,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
|
||||
setBearingForCompetitor(competitors.get(1), now, 50);
|
||||
setBearingForCompetitor(competitors.get(2), markPassingTimePoint, 100); // this shouldn't disturb the estimation because it's too old
|
||||
Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(now);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -318,7 +318,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
|
||||
setBearingForCompetitor(competitors.get(2), now, 135);
|
||||
setBearingForCompetitor(competitors.get(3), now, 220); // on the same tack, should give no read-out
|
||||
Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(now);
|
||||
assertEquals(177.5, estimatedWindDirection.getBearing().getDegrees(), 0.00000001);
|
||||
assertEquals(177.5, estimatedWindDirection.getBearing().getDegrees(), 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -43,10 +43,12 @@ 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.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactWindImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager;
|
||||
import com.sap.sailing.domain.confidence.ConfidenceFactory;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
@@ -86,7 +88,7 @@ public class WindTest {
|
||||
track.add(wind1);
|
||||
track.add(wind2);
|
||||
Wind average = track.getAveragedWind(pos, middle);
|
||||
assertEquals(0., average.getBearing().getDifferenceTo(new DegreeBearingImpl(0)).getDegrees(), 0.0001);
|
||||
PositionAssert.assertBearingEquals(new DegreeBearingImpl(0), average.getBearing().getDifferenceTo(new DegreeBearingImpl(0)), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -109,14 +111,14 @@ public class WindTest {
|
||||
for (Wind wind : track.getFixes()) {
|
||||
actualWind.add(wind);
|
||||
}
|
||||
assertEquals(expectedWind, actualWind);
|
||||
PositionAssert.assertWindEquals(expectedWind, actualWind, /* pos deg delta */ 0.000001, /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1);
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindEquality() {
|
||||
public void testWindEquality() throws CompactionNotPossibleException {
|
||||
Position p1 = new DegreePosition(1, 2);
|
||||
Position p2 = new DegreePosition(4, 5);
|
||||
TimePoint t1 = MillisecondsTimePoint.now();
|
||||
@@ -124,8 +126,8 @@ public class WindTest {
|
||||
SpeedWithBearing s1 = new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(3));
|
||||
SpeedWithBearing s2 = new KnotSpeedWithBearingImpl(22, new DegreeBearingImpl(123));
|
||||
Wind w1 = new WindImpl(p1, t1, s1);
|
||||
Wind w2 = new CompactWindImpl(w1);
|
||||
assertEquals(w1, w2);
|
||||
Wind w2 = new VeryCompactWindImpl(w1);
|
||||
PositionAssert.assertWindEquals(w1, w2, /* pos deg delta */ 0.000001, /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1);
|
||||
assertEquals(w1.hashCode(), w2.hashCode());
|
||||
Wind w3 = new WindImpl(p2, t2, s2);
|
||||
assertFalse(w1.equals(w3));
|
||||
@@ -163,9 +165,9 @@ public class WindTest {
|
||||
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);
|
||||
PositionAssert.assertSpeedEquals(new KnotSpeedImpl(20), track.getAveragedWind(pos, new MillisecondsTimePoint(1)), 0.02);
|
||||
// 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);
|
||||
PositionAssert.assertSpeedEquals(new KnotSpeedImpl(20), track.getAveragedWind(pos, new MillisecondsTimePoint(1001)), 0.02);
|
||||
// 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
|
||||
@@ -183,8 +185,7 @@ public class WindTest {
|
||||
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);
|
||||
PositionAssert.assertSpeedEquals(new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)), estimate, /* deg bearing delta */ 0.1, /* knot speed delta */ 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -195,8 +196,8 @@ public class WindTest {
|
||||
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);
|
||||
PositionAssert.assertSpeedEquals(new KnotSpeedImpl(10), estimate, 0.01);
|
||||
PositionAssert.assertBearingEquals(new DegreeBearingImpl(123), estimate.getBearing(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -208,8 +209,7 @@ public class WindTest {
|
||||
// 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);
|
||||
PositionAssert.assertSpeedEquals(new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)), estimate, /* deg bearing delta */ 0.1, /* knot speed delta */ 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -221,8 +221,7 @@ public class WindTest {
|
||||
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);
|
||||
PositionAssert.assertSpeedEquals(new KnotSpeedWithBearingImpl(15, new DegreeBearingImpl(100)), estimate, /* deg bearing delta */ 0.1, /* knot speed delta */ 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -234,8 +233,7 @@ public class WindTest {
|
||||
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
|
||||
PositionAssert.assertSpeedEquals(new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(105)), estimate, /* deg bearing delta, some tolerance needed because of time-based confidence */ 0.6, /* knot speed delta */ 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -266,7 +264,7 @@ public class WindTest {
|
||||
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((wind1.getKnots() + wind2.getKnots() + wind3.getKnots()) / 3, result.getKnots(), 0.01);
|
||||
assertEquals(80., result.getBearing().getDegrees(), 5);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.tractrac.model.lib.api.ModelLocator;
|
||||
import com.tractrac.model.lib.api.data.IControlPassing;
|
||||
import com.tractrac.model.lib.api.data.IControlPassings;
|
||||
@@ -66,7 +67,7 @@ public class JorgesTracTracParallelLoadingTest {
|
||||
threads.add(new Thread(()->{
|
||||
try {
|
||||
// Download the parameters file and load the race
|
||||
IRace race = ModelLocator.getEventFactory().createRace(new URI(paramsURIs.get(index)));
|
||||
IRace race = ModelLocator.getEventFactory().createRace(new URI(paramsURIs.get(index)), (int) /* timeout in milliseconds */ Duration.ONE_MINUTE.asMillis());
|
||||
|
||||
// Create the subscriptions
|
||||
SubscriptionLogger subscriptionLogger = new SubscriptionLogger(race);
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.test.PositionAssert;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
@@ -22,7 +21,7 @@ public abstract class PositionInterpolationAndExtrapolationTest<FixType extends
|
||||
}
|
||||
|
||||
protected void assertPos(Position p, boolean extrapolate) {
|
||||
assertEquals(p, getTrack().getEstimatedPosition(now, extrapolate));
|
||||
PositionAssert.assertPositionEquals(p, getTrack().getEstimatedPosition(now, extrapolate), /* deg delta */ 0.0005);
|
||||
}
|
||||
|
||||
protected GPSFixTrack<Object, FixType> getTrack() {
|
||||
|
||||
+3
-1
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.impl.AbstractRaceTrackingConnectivityParametersHandler;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
@@ -88,7 +89,8 @@ public class TracTracConnectivityParamsHandler extends AbstractRaceTrackingConne
|
||||
map.get(TRAC_TRAC_PASSWORD)==null?null:map.get(TRAC_TRAC_PASSWORD).toString(),
|
||||
map.get(RACE_STATUS)==null?null:map.get(RACE_STATUS).toString(),
|
||||
map.get(RACE_VISIBILITY)==null?null:map.get(RACE_VISIBILITY).toString(), isTrackWind(map),
|
||||
isCorrectWindDirectionByMagneticDeclination(map), /* preferReplayIfAvailable */ true);
|
||||
isCorrectWindDirectionByMagneticDeclination(map), /* preferReplayIfAvailable */ true,
|
||||
/* default timeout for obtaining IRace object from params URL */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-1
@@ -256,12 +256,13 @@ public interface DomainFactory {
|
||||
* {@code File}) then if this parameter is {@code true} the race will be loaded from the replay file
|
||||
* instead of the {@code storedURI}/{@code liveURI} specified. This is particularly useful for restoring
|
||||
* races if since the last connection the race was migrated to a replay file format.
|
||||
* @param timeoutInMillis TODO
|
||||
*/
|
||||
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI, URI storedURI,
|
||||
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination,
|
||||
boolean preferReplayIfAvailable) throws Exception;
|
||||
boolean preferReplayIfAvailable, int timeoutInMillis) throws Exception;
|
||||
/**
|
||||
* Removes all knowledge about <code>tractracRace</code> which includes removing it from the race cache, from the
|
||||
* {@link com.sap.sailing.domain.base.Regatta} and, if a {@link TrackedRace} for the corresponding
|
||||
|
||||
+2
-3
@@ -48,13 +48,12 @@ public interface TracTracAdapter {
|
||||
* @param timeoutInMilliseconds
|
||||
* if the race definition is not received for the race within this time, the race tracker for that race
|
||||
* is stopped; use -1 to wait forever
|
||||
* @param trackWind TODO
|
||||
* @param correctWindDirectionByMagneticDeclination TODO
|
||||
*/
|
||||
RaceHandle addTracTracRace(TrackerManager trackerManager, URL paramURL, URI liveURI, URI storedURI,
|
||||
URI courseDesignUpdateURI, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
long timeoutInMilliseconds, String tracTracUsername, String tracTracPassword, String raceStatus,
|
||||
String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, int timeoutInMillis)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
/**
|
||||
* Same as {@link #addTracTracRace(URL, URI, URI, WindStore, long)}, only that start and end of tracking are
|
||||
|
||||
+33
-8
@@ -12,12 +12,12 @@ import java.util.logging.Logger;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.LoadingQueueDoneCallBack;
|
||||
import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
import com.tractrac.model.lib.api.event.IEvent;
|
||||
@@ -35,7 +35,15 @@ import com.tractrac.subscription.lib.api.IRaceSubscriber;
|
||||
*/
|
||||
public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Receiver {
|
||||
private static Logger logger = Logger.getLogger(AbstractReceiverWithQueue.class.getName());
|
||||
|
||||
|
||||
/**
|
||||
* The timeout after which to re-try looking for the race definition to have appeared in
|
||||
* {@link #getTrackedRace(IRace)} in case an infinite timeout (-1) was specified. During this
|
||||
* short break, {@link #getTrackedRace(IRace)} will check for {@link #hasBeenStoppedPreemptively()}
|
||||
* and will stop trying to look for the race if this received was stopped preemptively.
|
||||
*/
|
||||
private static final long RETRY_TIMEOUT_IN_MILLIS = Duration.ONE_MINUTE.asMillis();
|
||||
|
||||
private final LinkedBlockingDeque<Util.Triple<A, B, C>> queue;
|
||||
private final DomainFactory domainFactory;
|
||||
private final IEvent tractracEvent;
|
||||
@@ -53,6 +61,14 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
|
||||
*/
|
||||
private boolean receivedEventDuringTimeout;
|
||||
|
||||
/**
|
||||
* Set by {@link #stopPreemptively()}. Invocations of {@link #handleEvent(Triple)} waiting for something
|
||||
* should wait repeatedly with some timeout, such as, say, one minute, and keep re-trying until what they
|
||||
* are waiting for has appeared, or this flag has been set in which case they can abort and assume they
|
||||
* received a stop event.
|
||||
*/
|
||||
private boolean stoppedPreemptively;
|
||||
|
||||
public AbstractReceiverWithQueue(DomainFactory domainFactory, IEvent tractracEvent,
|
||||
DynamicTrackedRegatta trackedRegatta, Simulator simulator, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber,
|
||||
long timeoutInMilliseconds) {
|
||||
@@ -97,6 +113,11 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
|
||||
// mark the end and hence terminate the thread by adding a null/null/null event to the queue
|
||||
queue.clear();
|
||||
stopAfterProcessingQueuedEvents();
|
||||
stoppedPreemptively = true;
|
||||
}
|
||||
|
||||
protected boolean hasBeenStoppedPreemptively() {
|
||||
return stoppedPreemptively;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -195,15 +216,19 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
|
||||
/**
|
||||
* Tries to find a {@link TrackedRace} for <code>race</code> in the {@link com.sap.sailing.domain.base.Regatta}
|
||||
* corresponding to {@link #tractracEvent}, as keyed by the {@link #domainFactory}. Waits for
|
||||
* {@link RaceTracker#TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS} milliseconds for the
|
||||
* {@link RaceDefinition} to show up. If it doesn't, <code>null</code> is returned. If the {@link RaceDefinition}
|
||||
* for <code>race</code> is not found in the {@link com.sap.sailing.domain.base.Regatta}, <code>null</code> is
|
||||
* returned. If the {@link TrackedRace} for <code>race</code> isn't found in the {@link TrackedRegatta},
|
||||
* <code>null</code> is returned, too.
|
||||
* {@link #timeoutInMilliseconds} milliseconds for the {@link RaceDefinition} to show up, or infinitely if
|
||||
* {@link #timeoutInMilliseconds} is -1, except this receiver is {@link #hasBeenStoppedPreemptively() stopped
|
||||
* preemptively}. If the race doesn't show up under these boundary conditions, <code>null</code> is returned. If the
|
||||
* {@link RaceDefinition} for <code>race</code> is not found in the {@link com.sap.sailing.domain.base.Regatta},
|
||||
* <code>null</code> is returned. If the {@link TrackedRace} for <code>race</code> isn't found in the
|
||||
* {@link TrackedRegatta}, <code>null</code> is returned, too.
|
||||
*/
|
||||
protected DynamicTrackedRace getTrackedRace(IRace race) {
|
||||
DynamicTrackedRace result = null;
|
||||
RaceDefinition raceDefinition = getDomainFactory().getAndWaitForRaceDefinition(race.getId(), timeoutInMilliseconds);
|
||||
final long effectiveTimeoutInMilliseconds = timeoutInMilliseconds == -1 ? RETRY_TIMEOUT_IN_MILLIS : timeoutInMilliseconds;
|
||||
RaceDefinition raceDefinition;
|
||||
while ((raceDefinition = getDomainFactory().getAndWaitForRaceDefinition(race.getId(), effectiveTimeoutInMilliseconds)) == null &&
|
||||
timeoutInMilliseconds == -1 && !hasBeenStoppedPreemptively());
|
||||
if (raceDefinition != null) {
|
||||
com.sap.sailing.domain.base.Regatta domainRegatta = trackedRegatta.getRegatta();
|
||||
if (domainRegatta.getRaceByName(raceDefinition.getName()) != null) {
|
||||
|
||||
+11
-4
@@ -537,9 +537,16 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
raceCache.put(raceId, raceDefinition);
|
||||
raceCache.notifyAll();
|
||||
} else {
|
||||
logger.warning("Not adding race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta()
|
||||
final String reasonForNotAddingRaceToRegatta = "Not adding race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta()
|
||||
+ " because boat class " + raceDefinition.getBoatClass()
|
||||
+ " doesn't match regatta's boat class " + trackedRegatta.getRegatta().getBoatClass());
|
||||
+ " doesn't match regatta's boat class " + trackedRegatta.getRegatta().getBoatClass();
|
||||
logger.warning(reasonForNotAddingRaceToRegatta);
|
||||
try {
|
||||
raceDefinitionSetToUpdate.raceNotLoaded(reasonForNotAddingRaceToRegatta);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.INFO, "Something else went wrong while trying to notify the RaceDefinition set that the race "+
|
||||
raceDefinition+" could not be added to the the regatta "+trackedRegatta.getRegatta(), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.info("Found existing tracked race for race "+raceName+" with ID "+raceId);
|
||||
@@ -688,11 +695,11 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
|
||||
long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, String tracTracUsername, String tracTracPassword, String raceStatus,
|
||||
String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, boolean preferReplayIfAvailable) throws Exception {
|
||||
String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, boolean preferReplayIfAvailable, int timeoutInMillis) throws Exception {
|
||||
return new RaceTrackingConnectivityParametersImpl(paramURL, liveURI, storedURI, courseDesignUpdateURI,
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore,
|
||||
regattaLogStore, this, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination,
|
||||
preferReplayIfAvailable);
|
||||
preferReplayIfAvailable, timeoutInMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
-2
@@ -5,6 +5,7 @@ import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
@@ -54,17 +55,24 @@ public class RaceTrackingConnectivityParametersImpl extends AbstractRaceTracking
|
||||
* {@code File}) then if this parameter is {@code true} the race will be loaded from the replay file
|
||||
* instead of the {@code storedURI}/{@code liveURI} specified. This is particularly useful for restoring
|
||||
* races if since the last connection the race was migrated to a replay file format.
|
||||
* @param timeoutInMillis
|
||||
* -1 means no timeout; otherwise, this is the timeout for waiting for the {@link IRace} to be obtained
|
||||
* from the {@code paramURL} document. A {@link TimeoutException} will result if the timeout applied.
|
||||
*/
|
||||
public RaceTrackingConnectivityParametersImpl(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, DomainFactory domainFactory,
|
||||
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility,
|
||||
boolean trackWind, boolean correctWindDirectionByMagneticDeclination, boolean preferReplayIfAvailable)
|
||||
boolean trackWind, boolean correctWindDirectionByMagneticDeclination, boolean preferReplayIfAvailable, int timeoutInMillis)
|
||||
throws Exception {
|
||||
super(trackWind, correctWindDirectionByMagneticDeclination);
|
||||
this.paramURL = paramURL;
|
||||
this.tractracRace = ModelLocator.getEventFactory().createRace(new URI(paramURL.toString()));
|
||||
if (timeoutInMillis == -1) {
|
||||
this.tractracRace = ModelLocator.getEventFactory().createRace(new URI(paramURL.toString()));
|
||||
} else {
|
||||
this.tractracRace = ModelLocator.getEventFactory().createRace(new URI(paramURL.toString()), timeoutInMillis);
|
||||
}
|
||||
if (preferReplayIfAvailable && isReplayRace(tractracRace) &&
|
||||
(!Util.equalsWithNull(liveURI, tractracRace.getLiveURI()) || !Util.equalsWithNull(storedURI, tractracRace.getStoredURI()))) {
|
||||
logger.info("Replay format available and preferred for race " + tractracRace.getName()
|
||||
|
||||
+4
-3
@@ -49,7 +49,7 @@ public class TracTracAdapterImpl implements TracTracAdapter {
|
||||
public RaceHandle addTracTracRace(TrackerManager trackerManager, URL paramURL, URI liveURI, URI storedURI,
|
||||
URI courseDesignUpdateURI, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
long timeoutInMilliseconds, String tracTracUsername, String tracTracPassword, String raceStatus,
|
||||
String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws Exception {
|
||||
String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, int timeoutInMillis) throws Exception {
|
||||
return trackerManager.addRace(
|
||||
/* regattaToAddTo */null,
|
||||
getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
|
||||
@@ -57,7 +57,7 @@ public class TracTracAdapterImpl implements TracTracAdapter {
|
||||
/* startOfTracking */null,
|
||||
/* endOfTracking */null, delayToLiveInMillis, /* offsetToStartTimeOfSimulatedRace */null, /* ignoreTracTracMarkPassings */ false,
|
||||
raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination,
|
||||
/* preferReplayIfAvailable */ false),
|
||||
/* preferReplayIfAvailable */ false, timeoutInMillis),
|
||||
timeoutInMilliseconds);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,8 @@ public class TracTracAdapterImpl implements TracTracAdapter {
|
||||
getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
|
||||
courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
|
||||
offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword,
|
||||
raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination, /* preferReplayIfAvailable */ false), timeoutInMilliseconds);
|
||||
raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination, /* preferReplayIfAvailable */ false,
|
||||
(int) timeoutInMilliseconds), timeoutInMilliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
@@ -647,6 +647,16 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
notifyRaceCreationListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* When this tracker is informed that the race cannot be loaded, e.g., because its boat class does
|
||||
* not match the regatta's boat class, the tracker will {@link #stop} preemptively.
|
||||
*/
|
||||
@Override
|
||||
public void raceNotLoaded(String reason) throws MalformedURLException, IOException, InterruptedException {
|
||||
logger.severe("Race for tracker "+this+" with ID "+getID()+" did not load: "+reason+". Stopping tracker.");
|
||||
stop(/* preemptive */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gotLiveDataEvent(ILiveDataEvent liveDataEvent) {
|
||||
logger.info("Status change in tracker "+getID()+" for race(s) "+getRace()+": "+liveDataEvent);
|
||||
|
||||
+3
@@ -43,6 +43,7 @@ import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOver
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10LastBreaksTie;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10Or8AndLastBreaksTie;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets12Or8AndLastBreaksTie;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets12Or8AndLastBreaksTie2017;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets1LastBreaksTie;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointLastBreaksTie;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointWinnerGetsEight;
|
||||
@@ -124,6 +125,8 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
|
||||
return new HighPointFirstGets10Or8AndLastBreaksTie();
|
||||
case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT:
|
||||
return new HighPointFirstGets12Or8AndLastBreaksTie();
|
||||
case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017:
|
||||
return new HighPointFirstGets12Or8AndLastBreaksTie2017();
|
||||
case LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07:
|
||||
return new LowPointWithEliminationsAndRoundsWinnerGets07();
|
||||
case LOW_POINT_LEAGUE_OVERALL:
|
||||
|
||||
+3
@@ -1,6 +1,8 @@
|
||||
package com.sap.sailing.domain.leaderboard;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.impl.AbstractSimpleLeaderboardImpl;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* Computing the competitors can be a bit expensive, particularly if the fleet is large and there may be suppressed
|
||||
@@ -23,4 +25,5 @@ import com.sap.sailing.domain.leaderboard.impl.AbstractSimpleLeaderboardImpl;
|
||||
*/
|
||||
public interface NumberOfCompetitorsInLeaderboardFetcher {
|
||||
int getNumberOfCompetitorsInLeaderboard();
|
||||
int getNumberOfCompetitorsWithoutMaxPointReason(RaceColumn column, TimePoint timePoint);
|
||||
}
|
||||
+4
-1
@@ -66,9 +66,12 @@ public interface ScoringScheme extends Serializable {
|
||||
* otherwise, this parameter tells the number of competitors in the same race as <code>competitor</code>,
|
||||
* not in the entire <code>raceColumn</code> (those may be more in case of split fleets). The scoring scheme
|
||||
* may use this number, if available, to infer a penalty score.
|
||||
* @param timePoint
|
||||
* an optional timePoint that may help the scheme to determine the penalty related to a certain point in time only.
|
||||
*/
|
||||
Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason,
|
||||
Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher);
|
||||
Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher,
|
||||
TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* @param competitor1Scores scores of the first competitor, in the order of race columns in the leaderboard
|
||||
|
||||
+13
@@ -252,6 +252,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
*/
|
||||
public class NumberOfCompetitorsFetcherImpl implements NumberOfCompetitorsInLeaderboardFetcher {
|
||||
private int numberOfCompetitors = -1;
|
||||
private int numberOfCompetitorsWithoutMaxPointReason = -1;
|
||||
|
||||
@Override
|
||||
public int getNumberOfCompetitorsInLeaderboard() {
|
||||
@@ -260,6 +261,18 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
}
|
||||
return numberOfCompetitors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfCompetitorsWithoutMaxPointReason(RaceColumn column, TimePoint timePoint) {
|
||||
if (numberOfCompetitorsWithoutMaxPointReason == -1) {
|
||||
numberOfCompetitorsWithoutMaxPointReason = 0;
|
||||
for (Competitor competitor : getCompetitors()) {
|
||||
MaxPointsReason maxPointReason = getScoreCorrection().getMaxPointsReason(competitor, column, timePoint);
|
||||
numberOfCompetitorsWithoutMaxPointReason += maxPointReason == MaxPointsReason.NONE ? 1 : 0;
|
||||
}
|
||||
}
|
||||
return numberOfCompetitorsWithoutMaxPointReason;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ public class HighPoint extends AbstractScoringSchemeImpl {
|
||||
|
||||
@Override
|
||||
public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason, Integer numberOfCompetitorsInRace,
|
||||
NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) {
|
||||
NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* {@link HighPointFirstGetsFixedScore} scheme that in most cases applies
|
||||
* 12 points for the winner. Iff for one race column a {@link RaceLogAdditionalScoringInformationEvent}
|
||||
* is found then 8 points are applied for the winner.
|
||||
*
|
||||
* From Phil, Race Director, on 12.09.2014: "If there is a tie in the regatta score between two or more boats at any time, the tie
|
||||
* shall be broken in favour of the boat that has won the most races. If a tie still remains, it shall be broken in
|
||||
* favour of the boat that had the better place at the last race sailed."
|
||||
*
|
||||
* 13.1.2 A Boat that did not start, did not finish, or retired shall receive 1 point less than the last boat to complete the race.
|
||||
* 13.1.3 A Boat that is disqualified from a race, including OCS, shall receive 2 points less than the last boat to complete the race.
|
||||
*
|
||||
* @author Simon Marcel Pamies
|
||||
*/
|
||||
public class HighPointFirstGets12Or8AndLastBreaksTie2017 extends AbstractHighPointFirstGetsFixedOr8AndLastBreaksTie {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public HighPointFirstGets12Or8AndLastBreaksTie2017() {
|
||||
super(12.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringSchemeType getType() {
|
||||
return ScoringSchemeType.HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason,
|
||||
Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) {
|
||||
Double result;
|
||||
/**
|
||||
* 1. Get all competitors without a max point reason.
|
||||
* 2. This list of competitors is assumed to be all competitors having successfully taken part in the race.
|
||||
* 3. The score of the last competitor will be 12-size(competitorList)
|
||||
*
|
||||
* XXX How about two competitors not finishing a race? They will get the same score. NOR does not state
|
||||
* anything on how to handle such a situation except that it implicates that this will lead to a tie. No
|
||||
* update from OC Sport on that question so far (Mar 2017).
|
||||
*/
|
||||
int competitorCountWithoutMaxPointReason = numberOfCompetitorsInLeaderboardFetcher.getNumberOfCompetitorsWithoutMaxPointReason(raceColumn, timePoint);
|
||||
if (maxPointsReason == MaxPointsReason.DNS || maxPointsReason == MaxPointsReason.DNF || maxPointsReason == MaxPointsReason.RET) {
|
||||
result = (12 - competitorCountWithoutMaxPointReason) * 1.0;
|
||||
} else if (maxPointsReason == MaxPointsReason.DSQ || maxPointsReason == MaxPointsReason.OCS) {
|
||||
result = (12 - competitorCountWithoutMaxPointReason - 1) * 1.0;
|
||||
} else {
|
||||
result = 0.0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@ public class HighPointFirstGets1LastBreaksTie extends HighPointFirstGetsFixedSco
|
||||
|
||||
@Override
|
||||
public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason, Integer numberOfCompetitorsInRace,
|
||||
NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) {
|
||||
NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) {
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ public class LowPoint extends AbstractScoringSchemeImpl {
|
||||
|
||||
@Override
|
||||
public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason,
|
||||
Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) {
|
||||
Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) {
|
||||
Double result;
|
||||
if (numberOfCompetitorsInRace == null || raceColumn.hasSplitFleetContiguousScoring()) {
|
||||
result = (double) (numberOfCompetitorsInLeaderboardFetcher.getNumberOfCompetitorsInLeaderboard()+1);
|
||||
|
||||
+2
-2
@@ -330,7 +330,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotatedMaxPointsReason getAnnotatedMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
protected AnnotatedMaxPointsReason getAnnotatedMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
MaxPointsReason maxPointsReason = maxPointsReasons.get(raceColumn.getKey(competitor));
|
||||
boolean maxPointsReasonExistsButIsNotApplicableForTimePoint;
|
||||
if (maxPointsReason == null) {
|
||||
@@ -390,7 +390,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
if (correctedNonMaxedScore == null) {
|
||||
result = scoringScheme.getPenaltyScore(raceColumn, competitor, maxPointsReason.getMaxPointsReason(),
|
||||
getNumberOfCompetitorsInRace(raceColumn, competitor, numberOfCompetitorsInLeaderboardFetcher),
|
||||
numberOfCompetitorsInLeaderboardFetcher);
|
||||
numberOfCompetitorsInLeaderboardFetcher, timePoint);
|
||||
} else {
|
||||
result = correctedNonMaxedScore;
|
||||
}
|
||||
|
||||
+7
@@ -18,4 +18,11 @@ import com.sap.sailing.domain.base.RaceDefinition;
|
||||
@FunctionalInterface
|
||||
public interface DynamicRaceDefinitionSet {
|
||||
void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace);
|
||||
|
||||
/**
|
||||
* Called when the race has not or can not be loaded. A {@code reason} may be provided or may be left {@code null}.
|
||||
* This default implementation does nothing. Implementing classes may choose, e.g., to stop all further efforts
|
||||
* trying to track the race.
|
||||
*/
|
||||
default void raceNotLoaded(String reason) throws Exception {}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
|
||||
/**
|
||||
* Centerpiece of a tracking adapter. A tracker is responsible for receiving tracking data for one or more
|
||||
* {@link RaceDefinition races} that are {@link Regatta#getAllRaces() part of} a common {@link #getRegatta() Event}. Some
|
||||
* Centerpiece of a tracking adapter. A tracker is responsible for receiving tracking data for one
|
||||
* {@link RaceDefinition race} that is {@link Regatta#getAllRaces() part of} a common {@link #getRegatta() Event}. Some
|
||||
* tracker architectures may not be able to deliver all data for the {@link RaceDefinition} when created or started.
|
||||
* Therefore, {@link #getRace()} may return <code>null</code> if the race information hasn't been received by the
|
||||
* tracker yet. Through the {@link RaceHandle} returned by {@link #getRaceHandle()} it is also possible to perform a
|
||||
@@ -43,7 +43,7 @@ public interface RaceTracker {
|
||||
static long TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS = 60000;
|
||||
|
||||
/**
|
||||
* Stops tracking the races.
|
||||
* Stops tracking the race.
|
||||
*
|
||||
* @param preemptive
|
||||
* if <code>false</code>, the tracker will continue to process data already received but will stop
|
||||
@@ -55,7 +55,7 @@ public interface RaceTracker {
|
||||
com.sap.sailing.domain.base.Regatta getRegatta();
|
||||
|
||||
/**
|
||||
* Returns the races being tracked by this tracker, in a "volatile" way, meaning that if another thread belonging to
|
||||
* Returns the race being tracked by this tracker, in a "volatile" way, meaning that if another thread belonging to
|
||||
* this tracker has established the {@link RaceDefinition} for this tracker, other threads will immediately see this
|
||||
* object. Non-blocking call that returns <code>null</code> if the {@link RaceDefinition} hasn't been created yet,
|
||||
* e.g., because the course definition hasn't been received yet or the listener for receiving course information
|
||||
|
||||
+7
-1
@@ -25,7 +25,13 @@ public interface RaceTrackingConnectivityParameters {
|
||||
* {@link Regatta} is provided, this will first look up a regatta for the race from
|
||||
* {@link TrackedRegattaRegistry#getRememberedRegattaForRace(java.io.Serializable)} and if not found will look up or
|
||||
* create a default regatta based on race data such as an event name and the boat class.
|
||||
* @param timeoutInMilliseconds TODO
|
||||
*
|
||||
* @param timeoutInMilliseconds
|
||||
* gives the tracker a possibility to abort tracking the race after so many milliseconds of
|
||||
* unsuccessfully waiting for the connection to be established. Support is optional for
|
||||
* implementations, and there is no exact specification what must have happened before
|
||||
* this timeout in order for tracking to continue. So, consider this as a "hint" to the
|
||||
* tracker.
|
||||
*/
|
||||
RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
|
||||
RaceLogResolver raceLogResolver, long timeoutInMilliseconds) throws Exception;
|
||||
|
||||
@@ -16,13 +16,6 @@ import com.sap.sse.common.WithID;
|
||||
public interface SensorFixTrack<ItemType extends WithID & Serializable, FixT extends SensorFix>
|
||||
extends MappedTrack<ItemType, FixT> {
|
||||
|
||||
/**
|
||||
* Value names to be used when reading values from {@link SensorFix}es by calling {@link SensorFix#get(String)}.
|
||||
*
|
||||
* @return the value names that fixes contained in this track support
|
||||
*/
|
||||
Iterable<String> getValueNames();
|
||||
|
||||
void addListener(SensorFixTrackListener<ItemType, FixT> listener);
|
||||
|
||||
void removeListener(SensorFixTrackListener<ItemType, FixT> listener);
|
||||
|
||||
+1
-3
@@ -3,7 +3,6 @@ package com.sap.sailing.domain.tracking.impl;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicBravoFixTrack;
|
||||
@@ -28,8 +27,7 @@ public class BravoFixTrackImpl<ItemType extends WithID & Serializable> extends S
|
||||
* the name of the track by which it can be obtained from the {@link TrackedRace}.
|
||||
*/
|
||||
public BravoFixTrackImpl(ItemType trackedItem, String trackName) {
|
||||
super(trackedItem, trackName, BravoSensorDataMetadata.INSTANCE.getFileColumns(),
|
||||
BravoFixTrack.TRACK_NAME + " for " + trackedItem);
|
||||
super(trackedItem, trackName, BravoFixTrack.TRACK_NAME + " for " + trackedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+54
-5
@@ -3,6 +3,8 @@ package com.sap.sailing.domain.tracking.impl;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
@@ -13,6 +15,7 @@ import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidenceCluster;
|
||||
import com.sap.sailing.domain.common.confidence.ConfidenceBasedAverager;
|
||||
@@ -22,23 +25,62 @@ import com.sap.sailing.domain.common.confidence.Weigher;
|
||||
import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactPositionHelper;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public class DynamicGPSFixMovingTrackImpl<ItemType> extends GPSFixTrackImpl<ItemType, GPSFixMoving> implements DynamicGPSFixTrack<ItemType, GPSFixMoving> {
|
||||
private static final Logger logger = Logger.getLogger(DynamicGPSFixMovingTrackImpl.class.getName());
|
||||
|
||||
private static final long serialVersionUID = 9111448573301259784L;
|
||||
private static final double MAX_SPEED_FACTOR_COMPARED_TO_MEASURED_SPEED_FOR_FILTERING = 2;
|
||||
|
||||
/**
|
||||
* Uses lossy compaction of fixes. See {@link CompactPositionHelper}. Use {@link #DynamicGPSFixMovingTrackImpl(Object, long, boolean)}
|
||||
* to configure lossless compaction.
|
||||
*/
|
||||
public DynamicGPSFixMovingTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage) {
|
||||
super(trackedItem, millisecondsOverWhichToAverage);
|
||||
this(trackedItem, millisecondsOverWhichToAverage, /* losslessCompaction */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxSpeedForSmoothening pass <code>null</code> if you don't want speed-based smoothening
|
||||
* Uses lossy compaction. Use {@link #DynamicGPSFixMovingTrackImpl(Object, long, Speed, boolean)} to configure
|
||||
* lossless compaction.
|
||||
*
|
||||
* @param maxSpeedForSmoothening
|
||||
* pass <code>null</code> if you don't want speed-based smoothening
|
||||
*/
|
||||
public DynamicGPSFixMovingTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, Speed maxSpeedForSmoothening) {
|
||||
super(trackedItem, millisecondsOverWhichToAverage, maxSpeedForSmoothening);
|
||||
this(trackedItem, millisecondsOverWhichToAverage, maxSpeedForSmoothening, /* losslessCompaction */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxSpeedForSmoothening
|
||||
* pass <code>null</code> if you don't want speed-based smoothening
|
||||
* @param losslessCompaction
|
||||
* If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely equal to
|
||||
* their original, without rounding or range limitations different from those of the original
|
||||
* {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that, however, has
|
||||
* stricter limits on ranges and precisions. See {@link CompactPositionHelper} for details on lossy
|
||||
* compaction.
|
||||
*/
|
||||
public DynamicGPSFixMovingTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, Speed maxSpeedForSmoothening, boolean losslessCompaction) {
|
||||
super(trackedItem, millisecondsOverWhichToAverage, maxSpeedForSmoothening, losslessCompaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param losslessCompaction
|
||||
* If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely equal to
|
||||
* their original, without rounding or range limitations different from those of the original
|
||||
* {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that, however, has
|
||||
* stricter limits on ranges and precisions. See {@link CompactPositionHelper} for details on lossy
|
||||
* compaction.
|
||||
*/
|
||||
public DynamicGPSFixMovingTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, boolean losslessCompaction) {
|
||||
super(trackedItem, millisecondsOverWhichToAverage, losslessCompaction);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +99,14 @@ public class DynamicGPSFixMovingTrackImpl<ItemType> extends GPSFixTrackImpl<Item
|
||||
|
||||
@Override
|
||||
public boolean add(GPSFixMoving fix, boolean replace) {
|
||||
return super.add(new CompactGPSFixMovingImpl(fix), replace);
|
||||
GPSFixMoving compactFix;
|
||||
try {
|
||||
compactFix = isLosslessCompaction() ? new PreciseCompactGPSFixMovingImpl(fix) : new VeryCompactGPSFixMovingImpl(fix);
|
||||
} catch (CompactionNotPossibleException e) {
|
||||
logger.log(Level.FINE, "Couldn't compact fix "+fix+". Using losslessly-compacted fix instead.", e);
|
||||
compactFix = new PreciseCompactGPSFixMovingImpl(fix);
|
||||
}
|
||||
return super.add(compactFix, replace);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-3
@@ -1,14 +1,23 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactPositionHelper;
|
||||
import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
|
||||
public class DynamicGPSFixTrackImpl<ItemType> extends GPSFixTrackImpl<ItemType, GPSFix> implements DynamicGPSFixTrack<ItemType, GPSFix> {
|
||||
private static final long serialVersionUID = 4035953954507697564L;
|
||||
|
||||
/**
|
||||
* By default uses lossy compaction. See {@link CompactPositionHelper}.
|
||||
*/
|
||||
public DynamicGPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage) {
|
||||
super(trackedItem, millisecondsOverWhichToAverage);
|
||||
this(trackedItem, millisecondsOverWhichToAverage, /* losslessCompaction */ false);
|
||||
}
|
||||
|
||||
public DynamicGPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, boolean losslessCompaction) {
|
||||
super(trackedItem, millisecondsOverWhichToAverage, losslessCompaction);
|
||||
}
|
||||
|
||||
public void addGPSFix(GPSFix gpsFix) {
|
||||
@@ -22,7 +31,8 @@ public class DynamicGPSFixTrackImpl<ItemType> extends GPSFixTrackImpl<ItemType,
|
||||
|
||||
@Override
|
||||
public boolean add(GPSFix fix, boolean replace) {
|
||||
return super.add(new CompactGPSFixImpl(fix), replace);
|
||||
return super.add(
|
||||
isLosslessCompaction() ? new PreciseCompactGPSFixImpl(fix) : new VeryCompactGPSFixImpl(fix), replace);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+29
-5
@@ -22,6 +22,7 @@ import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidenceCluster;
|
||||
import com.sap.sailing.domain.common.confidence.ConfidenceBasedAverager;
|
||||
@@ -34,6 +35,7 @@ import com.sap.sailing.domain.common.impl.NauticalMileDistance;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.WithValidityCache;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactPositionHelper;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSTrackListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -45,7 +47,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
import com.sap.sse.util.impl.ArrayListNavigableSet;
|
||||
|
||||
public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends MappedTrackImpl<ItemType, FixType>
|
||||
public abstract class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends MappedTrackImpl<ItemType, FixType>
|
||||
implements GPSFixTrack<ItemType, FixType> {
|
||||
private static final Logger logger = Logger.getLogger(GPSFixTrackImpl.class.getName());
|
||||
private static final long serialVersionUID = 2115321069242514378L;
|
||||
@@ -121,8 +123,25 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends MappedTra
|
||||
private int estimatedSpeedCacheHits;
|
||||
private int estimatedSpeedCacheMisses;
|
||||
|
||||
public GPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage) {
|
||||
this(trackedItem, millisecondsOverWhichToAverage, DEFAULT_MAX_SPEED_FOR_SMOOTHING);
|
||||
/**
|
||||
* If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely
|
||||
* equal to their original, without rounding or range limitations different from those of the
|
||||
* original {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that,
|
||||
* however, has stricter limits on ranges and precisions. See {@link CompactPositionHelper} for
|
||||
* details on lossy compaction.
|
||||
*/
|
||||
private final boolean losslessCompaction;
|
||||
|
||||
/**
|
||||
* @param losslessCompaction
|
||||
* If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely equal to
|
||||
* their original, without rounding or range limitations different from those of the original
|
||||
* {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that, however, has
|
||||
* stricter limits on ranges and precisions. See {@link CompactPositionHelper} for details on lossy
|
||||
* compaction.
|
||||
*/
|
||||
protected GPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, boolean losslessCompaction) {
|
||||
this(trackedItem, millisecondsOverWhichToAverage, DEFAULT_MAX_SPEED_FOR_SMOOTHING, losslessCompaction);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +149,7 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends MappedTra
|
||||
* if <code>null</code>, any fix speed will be accepted as long as fix-provided speed (if any) and
|
||||
* inferred speed can be matched.
|
||||
*/
|
||||
public GPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, Speed maxSpeedForSmoothening) {
|
||||
protected GPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, Speed maxSpeedForSmoothening, boolean losslessCompaction) {
|
||||
super(trackedItem, /* nameForReadWriteLock */ GPSFixTrackImpl.class.getSimpleName()
|
||||
+ (trackedItem == null ? "" : (" for " + trackedItem.toString())));
|
||||
this.millisecondsOverWhichToAverage = millisecondsOverWhichToAverage;
|
||||
@@ -139,8 +158,13 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends MappedTra
|
||||
this.distanceCache = new DistanceCache(trackedItem==null?"null":trackedItem.toString());
|
||||
this.maxSpeedCache = createMaxSpeedCache();
|
||||
this.validityCachingSuspended = false;
|
||||
this.losslessCompaction = losslessCompaction;
|
||||
}
|
||||
|
||||
|
||||
protected boolean isLosslessCompaction() {
|
||||
return losslessCompaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suspendValidityCaching() {
|
||||
validityCachingSuspended = true;
|
||||
|
||||
+1
-10
@@ -21,21 +21,17 @@ public class SensorFixTrackImpl<ItemType extends WithID & Serializable, FixT ext
|
||||
|
||||
private static final long serialVersionUID = 6383421895429843002L;
|
||||
|
||||
private final Iterable<String> valueNames;
|
||||
private final String trackName;
|
||||
private final TrackListenerCollection<ItemType, FixT, SensorFixTrackListener<ItemType, FixT>> listeners;
|
||||
|
||||
/**
|
||||
* @param trackedItem the item this track is mapped to
|
||||
* @param trackName the name of the track by which it can be obtained from the {@link TrackedRace}.
|
||||
* @param valueNames the name of the values that can be obtained by fixes contained in the track
|
||||
* @param nameForReadWriteLock the name to use for the lock object that is used internally
|
||||
*/
|
||||
public SensorFixTrackImpl(ItemType trackedItem, String trackName, Iterable<String> valueNames,
|
||||
String nameForReadWriteLock) {
|
||||
public SensorFixTrackImpl(ItemType trackedItem, String trackName, String nameForReadWriteLock) {
|
||||
super(trackedItem, nameForReadWriteLock);
|
||||
this.trackName = trackName;
|
||||
this.valueNames = valueNames;
|
||||
this.listeners = new TrackListenerCollection<>();
|
||||
}
|
||||
|
||||
@@ -57,11 +53,6 @@ public class SensorFixTrackImpl<ItemType extends WithID & Serializable, FixT ext
|
||||
listeners.getListeners().forEach(notification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> getValueNames() {
|
||||
return valueNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(SensorFixTrackListener<ItemType, FixT> listener) {
|
||||
this.listeners.addListener(listener);
|
||||
|
||||
+48
-3
@@ -19,7 +19,10 @@ import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.confidence.impl.PositionAndTimePointWeigher;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactWindImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactPositionHelper;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
import com.sap.sailing.domain.common.tracking.impl.PreciseCompactWindImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl;
|
||||
import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager;
|
||||
import com.sap.sailing.domain.confidence.ConfidenceFactory;
|
||||
import com.sap.sailing.domain.tracking.WindListener;
|
||||
@@ -56,11 +59,23 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
*/
|
||||
private transient Set<WindListener> listeners;
|
||||
|
||||
/**
|
||||
* If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely
|
||||
* equal to their original, without rounding or range limitations different from those of the
|
||||
* original {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that,
|
||||
* however, has stricter limits on ranges and precisions. See {@link CompactPositionHelper} for
|
||||
* details on lossy compaction.
|
||||
*/
|
||||
private final boolean losslessCompaction;
|
||||
|
||||
public WindTrackImpl(long millisecondsOverWhichToAverage, boolean useSpeed, String nameForReadWriteLock) {
|
||||
this(millisecondsOverWhichToAverage, DEFAULT_BASE_CONFIDENCE, useSpeed, nameForReadWriteLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses lossy compaction. See {@link CompactPositionHelper}. Use {@link #WindTrackImpl(long, double, boolean, String, boolean)}
|
||||
* to select lossless compaction.
|
||||
*
|
||||
* @param baseConfidence
|
||||
* the confidence to attribute to the raw wind fixes in this track
|
||||
* @param useSpeed
|
||||
@@ -69,11 +84,29 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
* value for the speed
|
||||
*/
|
||||
public WindTrackImpl(long millisecondsOverWhichToAverage, double baseConfidence, boolean useSpeed, String nameForReadWriteLock) {
|
||||
this(millisecondsOverWhichToAverage, baseConfidence, useSpeed, nameForReadWriteLock, /* losslessCompaction */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses lossy compaction. See {@link CompactPositionHelper}.
|
||||
*
|
||||
* @param baseConfidence
|
||||
* the confidence to attribute to the raw wind fixes in this track
|
||||
* @param useSpeed
|
||||
* whether the wind speed described by the fixes in this track are usable at all; example for an unusable
|
||||
* wind speed would be that of an estimation that only estimates the wind direction and uses some default
|
||||
* value for the speed
|
||||
* @param losslessCompaction
|
||||
* whether or not to use lossless compaction; see {@link CompactPositionHelper} for details on lossy
|
||||
* compaction
|
||||
*/
|
||||
public WindTrackImpl(long millisecondsOverWhichToAverage, double baseConfidence, boolean useSpeed, String nameForReadWriteLock, boolean losslessCompaction) {
|
||||
super(new ArrayListNavigableSet<Timed>(WindComparator.INSTANCE), nameForReadWriteLock);
|
||||
this.baseConfidence = baseConfidence;
|
||||
this.millisecondsOverWhichToAverage = millisecondsOverWhichToAverage;
|
||||
listeners = new HashSet<WindListener>();
|
||||
this.useSpeed = useSpeed;
|
||||
this.losslessCompaction = losslessCompaction;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
@@ -114,12 +147,23 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
|
||||
@Override
|
||||
public boolean add(Wind wind, boolean replace) {
|
||||
final CompactWindImpl compactWind = new CompactWindImpl(wind);
|
||||
final Wind compactWind = compactify(wind);
|
||||
final boolean result = super.add(compactWind, replace);
|
||||
notifyListenersAboutReceive(compactWind);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Wind compactify(Wind wind) {
|
||||
Wind compactWind;
|
||||
try {
|
||||
compactWind = losslessCompaction ? new PreciseCompactWindImpl(wind) : new VeryCompactWindImpl(wind);
|
||||
} catch (CompactionNotPossibleException e) {
|
||||
logger.log(Level.FINE, "Couldn't compact wind fix "+wind+". Using lossless compactification instead.", e);
|
||||
compactWind = new PreciseCompactWindImpl(wind);
|
||||
}
|
||||
return compactWind;
|
||||
}
|
||||
|
||||
private void notifyListenersAboutReceive(Wind wind) {
|
||||
synchronized (listeners) {
|
||||
for (WindListener listener : listeners) {
|
||||
@@ -420,7 +464,8 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
public void remove(Wind wind) {
|
||||
lockForWrite();
|
||||
try {
|
||||
getInternalRawFixes().remove(wind);
|
||||
// map through "compactify" to account for possible rounding / accuracy differences and still achieve "equals"
|
||||
getInternalRawFixes().remove(compactify(wind));
|
||||
} finally {
|
||||
unlockAfterWrite();
|
||||
}
|
||||
|
||||
+21
-11
@@ -1,5 +1,7 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
@@ -8,46 +10,54 @@ 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.WindImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactWindImpl.CompactPosition;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl.VeryCompactPosition;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
|
||||
public final class CompactWindImpl {
|
||||
public static final class CompactPosition_CustomFieldSerializer extends CustomFieldSerializer<CompactPosition> {
|
||||
private static final Logger logger = Logger.getLogger(CompactWindImpl.class.getName());
|
||||
|
||||
public static final class CompactPosition_CustomFieldSerializer extends CustomFieldSerializer<VeryCompactPosition> {
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompactPosition instantiateInstance(SerializationStreamReader streamReader)
|
||||
public VeryCompactPosition instantiateInstance(SerializationStreamReader streamReader)
|
||||
throws SerializationException {
|
||||
return instantiate(streamReader);
|
||||
}
|
||||
|
||||
public static CompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException {
|
||||
public static VeryCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException {
|
||||
final double latDeg = streamReader.readDouble();
|
||||
final double lngDeg = streamReader.readDouble();
|
||||
return (CompactPosition) new com.sap.sailing.domain.common.tracking.impl.CompactWindImpl(new WindImpl(
|
||||
new DegreePosition(latDeg, lngDeg), /* timePoint */null, new KnotSpeedWithBearingImpl(0,
|
||||
new DegreeBearingImpl(0)))).getPosition();
|
||||
try {
|
||||
return (VeryCompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl(new WindImpl(
|
||||
new DegreePosition(latDeg, lngDeg), /* timePoint */null, new KnotSpeedWithBearingImpl(0,
|
||||
new DegreeBearingImpl(0)))).getPosition();
|
||||
} catch (CompactionNotPossibleException e) {
|
||||
logger.severe("Internal error: Cannot de-serialize compact position: "+e.getMessage()+"; throwing runtime exception");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(SerializationStreamReader streamReader, CompactPosition instance)
|
||||
public void deserializeInstance(SerializationStreamReader streamReader, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
deserialize(streamReader, instance);
|
||||
}
|
||||
|
||||
public static void deserialize(SerializationStreamReader streamReader, CompactPosition instance) {
|
||||
public static void deserialize(SerializationStreamReader streamReader, VeryCompactPosition instance) {
|
||||
// handled by instantiate
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(SerializationStreamWriter streamWriter, CompactPosition instance)
|
||||
public void serializeInstance(SerializationStreamWriter streamWriter, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
serialize(streamWriter, instance);
|
||||
}
|
||||
|
||||
public static void serialize(SerializationStreamWriter streamWriter, CompactPosition instance)
|
||||
public static void serialize(SerializationStreamWriter streamWriter, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
streamWriter.writeDouble(instance.getLatDeg());
|
||||
streamWriter.writeDouble(instance.getLngDeg());
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixImpl.PreciseCompactPosition;
|
||||
|
||||
public final class PreciseCompactGPSFixImpl {
|
||||
public static final class PreciseCompactPosition_CustomFieldSerializer extends CustomFieldSerializer<PreciseCompactPosition> {
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreciseCompactPosition instantiateInstance(SerializationStreamReader streamReader)
|
||||
throws SerializationException {
|
||||
return instantiate(streamReader);
|
||||
}
|
||||
|
||||
public static PreciseCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException {
|
||||
final double latDeg = streamReader.readDouble();
|
||||
final double lngDeg = streamReader.readDouble();
|
||||
return (PreciseCompactPosition) new com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixImpl(
|
||||
new DegreePosition(latDeg, lngDeg), /* timePoint */null).getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(SerializationStreamReader streamReader, PreciseCompactPosition instance)
|
||||
throws SerializationException {
|
||||
deserialize(streamReader, instance);
|
||||
}
|
||||
|
||||
public static void deserialize(SerializationStreamReader streamReader, PreciseCompactPosition instance) {
|
||||
// handled by instantiate
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(SerializationStreamWriter streamWriter, PreciseCompactPosition instance)
|
||||
throws SerializationException {
|
||||
serialize(streamWriter, instance);
|
||||
}
|
||||
|
||||
public static void serialize(SerializationStreamWriter streamWriter, PreciseCompactPosition instance)
|
||||
throws SerializationException {
|
||||
streamWriter.writeDouble(instance.getLatDeg());
|
||||
streamWriter.writeDouble(instance.getLngDeg());
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -5,9 +5,9 @@ import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl.CompactPosition;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl.CompactPosition;
|
||||
|
||||
public final class CompactGPSFixImpl {
|
||||
public final class VeryCompactGPSFixImpl {
|
||||
public static final class CompactPosition_CustomFieldSerializer extends CustomFieldSerializer<CompactPosition> {
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
@@ -23,7 +23,7 @@ public final class CompactGPSFixImpl {
|
||||
public static CompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException {
|
||||
final double latDeg = streamReader.readDouble();
|
||||
final double lngDeg = streamReader.readDouble();
|
||||
return (CompactPosition) new com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl(
|
||||
return (CompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl(
|
||||
new DegreePosition(latDeg, lngDeg), /* timePoint */null).getPosition();
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl.VeryCompactPosition;
|
||||
|
||||
public final class VeryCompactGPSFixMovingImpl {
|
||||
private static final Logger logger = Logger.getLogger(VeryCompactGPSFixMovingImpl.class.getName());
|
||||
|
||||
public static final class VeryCompactPosition_CustomFieldSerializer extends CustomFieldSerializer<VeryCompactPosition> {
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VeryCompactPosition instantiateInstance(SerializationStreamReader streamReader)
|
||||
throws SerializationException {
|
||||
return instantiate(streamReader);
|
||||
}
|
||||
|
||||
public static VeryCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException {
|
||||
final double latDeg = streamReader.readDouble();
|
||||
final double lngDeg = streamReader.readDouble();
|
||||
try {
|
||||
return (VeryCompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl(
|
||||
new DegreePosition(latDeg, lngDeg), /* timePoint */null, /* speed with bearing */ null).getPosition();
|
||||
} catch (CompactionNotPossibleException e) {
|
||||
logger.log(Level.SEVERE, "Internal error: an object that was a very compact position and was serialized "+
|
||||
"couldn't be de-serialized again as such an object", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(SerializationStreamReader streamReader, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
deserialize(streamReader, instance);
|
||||
}
|
||||
|
||||
public static void deserialize(SerializationStreamReader streamReader, VeryCompactPosition instance) {
|
||||
// handled by instantiate
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(SerializationStreamWriter streamWriter, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
serialize(streamWriter, instance);
|
||||
}
|
||||
|
||||
public static void serialize(SerializationStreamWriter streamWriter, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
streamWriter.writeDouble(instance.getLatDeg());
|
||||
streamWriter.writeDouble(instance.getLngDeg());
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
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.WindImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl.VeryCompactPosition;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
|
||||
public final class VeryCompactWindImpl {
|
||||
private static final Logger logger = Logger.getLogger(VeryCompactWindImpl.class.getName());
|
||||
|
||||
public static final class VeryCompactPosition_CustomFieldSerializer extends CustomFieldSerializer<VeryCompactPosition> {
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VeryCompactPosition instantiateInstance(SerializationStreamReader streamReader)
|
||||
throws SerializationException {
|
||||
return instantiate(streamReader);
|
||||
}
|
||||
|
||||
public static VeryCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException {
|
||||
final double latDeg = streamReader.readDouble();
|
||||
final double lngDeg = streamReader.readDouble();
|
||||
try {
|
||||
return (VeryCompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl(new WindImpl(
|
||||
new DegreePosition(latDeg, lngDeg), /* timePoint */null, new KnotSpeedWithBearingImpl(0,
|
||||
new DegreeBearingImpl(0)))).getPosition();
|
||||
} catch (CompactionNotPossibleException e) {
|
||||
logger.severe("Internal error: Cannot de-serialize compact position: "+e.getMessage()+"; throwing runtime exception");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(SerializationStreamReader streamReader, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
deserialize(streamReader, instance);
|
||||
}
|
||||
|
||||
public static void deserialize(SerializationStreamReader streamReader, VeryCompactPosition instance) {
|
||||
// handled by instantiate
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(SerializationStreamWriter streamWriter, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
serialize(streamWriter, instance);
|
||||
}
|
||||
|
||||
public static void serialize(SerializationStreamWriter streamWriter, VeryCompactPosition instance)
|
||||
throws SerializationException {
|
||||
streamWriter.writeDouble(instance.getLatDeg());
|
||||
streamWriter.writeDouble(instance.getLngDeg());
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -435,6 +435,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String scoringSchemeHighPointEssOverall12Description();
|
||||
String scoringSchemeHighPointFirstGetsTwelveOrEight();
|
||||
String scoringSchemeHighPointFirstGetsTwelveOrEightDescription();
|
||||
String scoringSchemeHighPointFirstGetsTwelveOrEight2017();
|
||||
String scoringSchemeHighPointFirstGetsTwelveOrEight2017Description();
|
||||
String scoringSystem();
|
||||
String createFlexibleLeaderboard();
|
||||
String createRegattaLeaderboard();
|
||||
|
||||
+2
@@ -452,6 +452,8 @@ scoringSchemeHighPointFirstGetsTenOrEight=High Point, winner gets 10 points (or
|
||||
scoringSchemeHighPointFirstGetsTenOrEightDescription=Score in points. Winner scores 10 points, 2nd - 9 points, .... A tie is broken in favour of the competitor having won most races, if tie remains then tie is broken by the rank in the last race scored.
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight=High Point, winner gets 12 points (or 8)
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored.
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017=High Point ESS 2017, winner gets 12 points (or 8)
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored.
|
||||
scoringSystem=Scoring system
|
||||
createFlexibleLeaderboard=Create flexible leaderboard
|
||||
createRegattaLeaderboard=Create regatta leaderboard
|
||||
|
||||
+2
@@ -1475,6 +1475,8 @@ confirmLosingCompetitorEditsWhenTogglingLogBasedView=Damit werden alle aktuellen
|
||||
removalOfMarkDisabledMayBeUsedInRaces=Löschung deaktiviert, Bahnmarke wird in folgenden anderen Wettfahrten benutzt: {0}
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight=High-Point System 12 Punkte
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Scores als Punkte. Der Gewinner bekommt 12 Punkte.
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017=High-Point System 12 Punkte ESS2017
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Scores als Punkte. Der Gewinner bekommt 12 Punkte.
|
||||
scoringSchemeHighPointEssOverall12=High Point System ESS Gesamtwertung (12)
|
||||
scoringSchemeHighPointEssOverall12Description=High Point System, der Gewinner eines Acts erhält 12 Punkte, der Zweite 11 und so weiter.
|
||||
pleaseCreateAtLeastOneMappingBy=Bitte erstellen Sie mindestens eine Zuordnung, indem Sie zunächst einen Track auf der linken Seite und anschließend einen Teilnehmer oder eine Tonne auf der rechten Seite auswählen
|
||||
|
||||
+2
@@ -450,6 +450,8 @@ scoringSchemeHighPointFirstGetsTenOrEight=高得点方式、1 位が 10 点 (ま
|
||||
scoringSchemeHighPointFirstGetsTenOrEightDescription=得点数によるスコアです。1 位が 10 点、2 位が 9 点などと得点します。同点となった場合は、より多くのレースで勝者となった競技者を上位とします。それでも同順位となる場合には、最終レースでの得点でのランクで順位を決定します。
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight=高得点方式、1 位が 12 点 (または 8 点)
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=得点数によるスコアです。1 位が 12 点、2 位が 11 点などと得点します。同点となった場合は、(各競技者のレース得点を高い方から比較して) 最多得点の競技者を上位とします。それでも同順位となる場合には、最終レースでの得点でのランクで順位を決定します。
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017=High Point ESS 2017, winner gets 12 points (or 8)
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored.
|
||||
scoringSystem=得点方式
|
||||
createFlexibleLeaderboard=フレキシブルリーダーボード登録
|
||||
createRegattaLeaderboard=レガッタリーダーボード登録
|
||||
|
||||
+2
@@ -450,6 +450,8 @@ scoringSchemeHighPointFirstGetsTenOrEight=Высокий балл, победи
|
||||
scoringSchemeHighPointFirstGetsTenOrEightDescription=Оценка в баллах. Победитель получает 10 баллов, 2-й — 9 баллов, .... Равенство разрешается в пользу участника, имеющего больше побед в гонках. Если равенство сохраняется, оно разрешается по рангу в последней гонке.
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight=Высокий балл, победитель получает 12 баллов (или 8)
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Оценка в баллах. Победитель получает 12 баллов, 2-й — 11 баллов, .... Равенство разрешается в пользу участника с наивысшей оценкой. Если равенство сохраняется, оно разрешается по рангу в последней гонке.
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017=High Point ESS 2017, winner gets 12 points (or 8)
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored.
|
||||
scoringSystem=Система оценок
|
||||
createFlexibleLeaderboard=Создать гибкую таблицу лидеров
|
||||
createRegattaLeaderboard=Создать таблицу лидеров регаты
|
||||
|
||||
+2
@@ -450,6 +450,8 @@ scoringSchemeHighPointFirstGetsTenOrEight=高分,获胜者得 10 分(或 8
|
||||
scoringSchemeHighPointFirstGetsTenOrEightDescription=得分。 获胜者得 10 分、第 2 名 9 分、.... 以赢得最多比赛轮次的参赛队取得胜利,如果仍有平局,则以最后一个比赛轮次的名次打破平局。
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight=高分,获胜者得 12 分(或 8 分)
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=得分。获胜者得 12 分、第 2 名 11 分、.... 得分最高的参赛队取得胜利,如果仍有平局,则以最后一个比赛轮次的名次打破平局。
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017=High Point ESS 2017, winner gets 12 points (or 8)
|
||||
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored.
|
||||
scoringSystem=记分系统
|
||||
createFlexibleLeaderboard=创建灵活的积分榜
|
||||
createRegattaLeaderboard=创建比赛积分榜
|
||||
|
||||
+4
@@ -36,6 +36,8 @@ public class ScoringSchemeTypeFormatter {
|
||||
return stringMessages.scoringSchemeHighPointFirstGetsTenOrEight();
|
||||
case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT:
|
||||
return stringMessages.scoringSchemeHighPointFirstGetsTwelveOrEight();
|
||||
case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017:
|
||||
return stringMessages.scoringSchemeHighPointFirstGetsTwelveOrEight2017();
|
||||
case LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07:
|
||||
return stringMessages.scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07();
|
||||
case LOW_POINT_LEAGUE_OVERALL:
|
||||
@@ -52,6 +54,8 @@ public class ScoringSchemeTypeFormatter {
|
||||
return stringMessages.scoringSchemeHighPointFirstGetsTenOrEightDescription();
|
||||
case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT:
|
||||
return stringMessages.scoringSchemeHighPointFirstGetsTwelveOrEightDescription();
|
||||
case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017:
|
||||
return stringMessages.scoringSchemeHighPointFirstGetsTwelveOrEight2017Description();
|
||||
case HIGH_POINT_ESS_OVERALL:
|
||||
return stringMessages.scoringSchemeHighPointEssOverallDescription();
|
||||
case HIGH_POINT_ESS_OVERALL_12:
|
||||
|
||||
+4
-3
@@ -35,6 +35,7 @@ import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.test.AbstractTracTracLiveTest;
|
||||
import com.sap.sailing.domain.test.PositionAssert;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
@@ -124,9 +125,9 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive
|
||||
result.lockForRead();
|
||||
try {
|
||||
for (Wind wind : result.getRawFixes()) {
|
||||
assertEquals(pos, wind.getPosition());
|
||||
assertEquals(10., wind.getKnots(), 0.000000000001);
|
||||
assertEquals(myBearingDeg, wind.getBearing().getDegrees(), 0.000000001);
|
||||
PositionAssert.assertPositionEquals(pos, wind.getPosition(), /* deg delta */ 0.000001);
|
||||
assertEquals(10., wind.getKnots(), 0.01);
|
||||
assertEquals(myBearingDeg, wind.getBearing().getDegrees(), 0.01);
|
||||
myBearingDeg += 1.1;
|
||||
}
|
||||
} finally {
|
||||
|
||||
+3
-1
@@ -12,6 +12,7 @@ import java.util.Set;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
|
||||
@@ -47,7 +48,8 @@ public class TracTracConnectivityParamsLoadAndStoreTest extends AbstractConnecti
|
||||
paramURL, /* live URI */ null, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking,
|
||||
delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm,
|
||||
/* raceLogStore */ null, /* regattaLogStore */ null, DomainFactory.INSTANCE, tracTracUsername, tracTracPassword,
|
||||
raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination, /* preferReplayIfAvailable */ false);
|
||||
raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination, /* preferReplayIfAvailable */ false,
|
||||
/* timeoutInMillis */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
// store
|
||||
mongoObjectFactory.addConnectivityParametersForRaceToRestore(tracTracParams);
|
||||
// load
|
||||
|
||||
@@ -20,7 +20,7 @@ public abstract class HostPage extends PageObject {
|
||||
/**
|
||||
* </p>The default timeout of 60 seconds for the initialization of the page object.</p>
|
||||
*/
|
||||
protected static final int DEFAULT_PAGE_LOAD_TIMEOUT = 60;
|
||||
protected static final int DEFAULT_PAGE_LOAD_TIMEOUT = 120;
|
||||
|
||||
public static final String getGWTCodeServer() {
|
||||
String codeServer = System.getProperty(GWT_CODE_SERVER_PARAMETER_NAME);
|
||||
|
||||
+101
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.server.gateway.jaxrs.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -9,6 +10,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
@@ -33,6 +36,7 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RegattaName;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
@@ -44,6 +48,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -868,6 +873,102 @@ public class RegattasResource extends AbstractSailingServerResource {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actual or anticipated start order for the race identified by {@coode regattaName} and {@code raceName}.
|
||||
* Those competitors for which a start mark passing is already known are sorted by those start mark passings. All other
|
||||
* boats are ordered by their geometrical distance from the start line or the windward distance from the start mark
|
||||
* if the start for some reason is defined by a single mark. See {@link #compareDistanceFromStartLine(Competitor, Competitor)}.
|
||||
*/
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
@Path("{regattaname}/races/{racename}/startorder")
|
||||
public Response getStartOrder(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName) {
|
||||
Response response;
|
||||
Regatta regatta = findRegattaByName(regattaName);
|
||||
if (regatta == null) {
|
||||
response = Response.status(Status.NOT_FOUND)
|
||||
.entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
|
||||
.build();
|
||||
} else {
|
||||
RaceDefinition race = findRaceByName(regatta, raceName);
|
||||
if (race == null) {
|
||||
response = Response.status(Status.NOT_FOUND)
|
||||
.entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "'.").type(MediaType.TEXT_PLAIN)
|
||||
.build();
|
||||
} else {
|
||||
final TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
|
||||
Course course = trackedRace.getRace().getCourse();
|
||||
final List<Competitor> competitors = new ArrayList<>();
|
||||
final Waypoint firstWaypoint = course.getFirstWaypoint();
|
||||
final TimePoint timeToUseForStart;
|
||||
if (trackedRace.getStartOfRace() != null) {
|
||||
timeToUseForStart = trackedRace.getStartOfRace();
|
||||
} else {
|
||||
timeToUseForStart = MillisecondsTimePoint.now();
|
||||
}
|
||||
if (firstWaypoint != null) {
|
||||
final List<Position> startWaypointMarkPositions =
|
||||
StreamSupport.stream(firstWaypoint.getMarks().spliterator(), /* parallel */ false).
|
||||
map(mark->trackedRace.getTrack(mark)).filter(markTrack->markTrack!=null).
|
||||
map(markTrack->markTrack.getEstimatedPosition(timeToUseForStart, /* extrapolate */ false)).
|
||||
collect(Collectors.toList());
|
||||
Util.addAll(trackedRace.getRace().getCompetitors(), competitors);
|
||||
competitors.sort((a, b)->{
|
||||
final MarkPassing aStartMarkPassing = trackedRace.getMarkPassing(a, firstWaypoint);
|
||||
final MarkPassing bStartMarkPassing = trackedRace.getMarkPassing(b, firstWaypoint);
|
||||
final int result;
|
||||
if (aStartMarkPassing == null) {
|
||||
if (bStartMarkPassing == null) {
|
||||
result = compareDistanceFromStartLine(trackedRace, startWaypointMarkPositions, timeToUseForStart, a, b);
|
||||
} else {
|
||||
result = 1; // b consider less than a because it has a start mark passing and therefore is assumed to have started before a
|
||||
}
|
||||
} else if (bStartMarkPassing == null) {
|
||||
result = -1; // a consider less than b because it has a start mark passing and therefore is assumed to have started before b
|
||||
} else {
|
||||
// both have a start mark passing; compare time points
|
||||
result = aStartMarkPassing.getTimePoint().compareTo(bStartMarkPassing.getTimePoint());
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
CompetitorJsonSerializer serializer = new CompetitorJsonSerializer();
|
||||
JSONArray result = new JSONArray();
|
||||
for (final Competitor c : competitors) {
|
||||
JSONObject jsonCompetitor = serializer.serialize(c);
|
||||
result.add(jsonCompetitor);
|
||||
}
|
||||
String json = result.toJSONString();
|
||||
return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private int compareDistanceFromStartLine(TrackedRace trackedRace, Iterable<Position> startWaypointMarkPositions,
|
||||
TimePoint timeToUseForStart, Competitor a, Competitor b) {
|
||||
final Position aPos = trackedRace.getTrack(a).getEstimatedPosition(timeToUseForStart, /* extrapolate */ true);
|
||||
final Position bPos = trackedRace.getTrack(b).getEstimatedPosition(timeToUseForStart, /* extrapolate */ true);
|
||||
final Distance aDist = aPos==null?null:getDistanceFromStartWaypoint(aPos, startWaypointMarkPositions);
|
||||
final Distance bDist = bPos==null?null:getDistanceFromStartWaypoint(bPos, startWaypointMarkPositions);
|
||||
return Comparator.<Distance>nullsLast(Comparator.naturalOrder()).compare(aDist, bDist);
|
||||
}
|
||||
|
||||
private Distance getDistanceFromStartWaypoint(Position pos, Iterable<Position> startWaypointMarkPositions) {
|
||||
final Distance result;
|
||||
if (Util.isEmpty(startWaypointMarkPositions)) {
|
||||
result = null;
|
||||
} else if (Util.size(startWaypointMarkPositions) == 1) {
|
||||
// single mark start; strange, but possible:
|
||||
result = startWaypointMarkPositions.iterator().next().getDistance(pos);
|
||||
} else {
|
||||
final Position first = Util.get(startWaypointMarkPositions, 0);
|
||||
final Position second = Util.get(startWaypointMarkPositions, 1);
|
||||
result = pos.getDistanceToLine(first, second).abs();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
@Path("{regattaname}/races")
|
||||
|
||||
+3
-3
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.server.replication.test;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
@@ -57,6 +56,7 @@ import com.sap.sailing.domain.persistence.PersistenceFactory;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.EmptySensorFixStore;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.test.PositionAssert;
|
||||
import com.sap.sailing.domain.test.TrackBasedTest;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -158,7 +158,7 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
|
||||
WindTrack masterRCWindFixes = masterTrackedRace.getOrCreateWindTrack(new WindSourceImpl(WindSourceType.RACECOMMITTEE));
|
||||
masterRCWindFixes.lockForRead();
|
||||
try {
|
||||
assertEquals(masterWindFix, masterRCWindFixes.getRawFixes().iterator().next());
|
||||
PositionAssert.assertWindEquals(masterWindFix, masterRCWindFixes.getRawFixes().iterator().next(), /* pos deg delta */ 0.0000001, /* bearing deg delta */ 0.01, /* knot speed delta */ 0.01);
|
||||
} finally {
|
||||
masterRCWindFixes.unlockAfterRead();
|
||||
}
|
||||
@@ -233,7 +233,7 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
|
||||
try {
|
||||
Iterator<Wind> replicaRCWindFixesIter = replicaRCWindFixes.getRawFixes().iterator();
|
||||
replicaRCWindFixesIter.next();
|
||||
assertEquals(replicaWindFix, replicaRCWindFixesIter.next());
|
||||
PositionAssert.assertWindEquals(replicaWindFix, replicaRCWindFixesIter.next(), /* pos deg delta */ 0.0000001, /* bearing deg delta */ 0.01, /* knot speed delta */ 0.02);
|
||||
} finally {
|
||||
replicaRCWindFixes.unlockAfterRead();
|
||||
}
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@ import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.test.AbstractTracTracLiveTest;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
@@ -72,7 +73,7 @@ public class TrackRaceBoatCompetitorMetadataReplicationTest extends AbstractServ
|
||||
startOfTracking, endOfTracking, /* delayToLiveInMillis */
|
||||
0l, /* offsetToStartTimeOfSimulatedRace */null, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, tracTracUsername, tracTracPassword, "", "", /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false,
|
||||
/* preferReplayIfAvailable */ false);
|
||||
/* preferReplayIfAvailable */ false, /* timeoutInMillis */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
private void startTracking() throws Exception, InterruptedException {
|
||||
|
||||
+2
-1
@@ -31,6 +31,7 @@ import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.test.AbstractTracTracLiveTest;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
@@ -90,7 +91,7 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
|
||||
startOfTracking, endOfTracking, /* delayToLiveInMillis */
|
||||
0l, /* offsetToStartTimeOfSimulatedRace */null, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, tracTracUsername, tracTracPassword, "", "", /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false,
|
||||
/* preferReplayIfAvailable */ false);
|
||||
/* preferReplayIfAvailable */ false, /* timeoutInMillis */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
private void startTracking() throws Exception, InterruptedException {
|
||||
|
||||
+4
-3
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.persistence.MongoWindStore;
|
||||
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
|
||||
import com.sap.sailing.domain.persistence.PersistenceFactory;
|
||||
import com.sap.sailing.domain.test.PositionAssert;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
@@ -130,7 +131,7 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
|
||||
competitorTrack.lockForRead();
|
||||
try {
|
||||
assertEquals(1, Util.size(competitorTrack.getRawFixes()));
|
||||
assertEquals(fix, competitorTrack.getRawFixes().iterator().next());
|
||||
PositionAssert.assertGPSFixEquals(fix, competitorTrack.getRawFixes().iterator().next(), /* pos deg delta */ 0.0000001, /* bearing deg delta */ 0.01, /* knot speed delta */ 0.01);
|
||||
assertNotSame(fix, competitorTrack.getRawFixes().iterator().next());
|
||||
} finally {
|
||||
competitorTrack.unlockAfterRead();
|
||||
@@ -151,7 +152,7 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
|
||||
replicaMarkTrack.lockForRead();
|
||||
try {
|
||||
assertEquals(1, Util.size(replicaMarkTrack.getRawFixes()));
|
||||
assertEquals(replicaMarkTrack.getRawFixes().iterator().next(), fix);
|
||||
PositionAssert.assertGPSFixEquals(replicaMarkTrack.getRawFixes().iterator().next(), fix, /* pos deg delta */ 0.0000001);
|
||||
assertNotSame(fix, replicaMarkTrack.getRawFixes().iterator().next());
|
||||
} finally {
|
||||
replicaMarkTrack.unlockAfterRead();
|
||||
@@ -174,7 +175,7 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
|
||||
try {
|
||||
assertEquals(1, Util.size(replicaWindTrack.getRawFixes()));
|
||||
Wind replicaWind = replicaWindTrack.getRawFixes().iterator().next();
|
||||
assertEquals(wind, replicaWind);
|
||||
PositionAssert.assertWindEquals(wind, replicaWind, /* pos deg delta */ 0.0000001, /* bearing deg delta */ 0.02, /* knot speed delta */ 0.02);
|
||||
assertNotSame(wind, replicaWind);
|
||||
} finally {
|
||||
replicaWindTrack.unlockAfterRead();
|
||||
|
||||
+3
-1
@@ -37,6 +37,8 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
|
||||
import com.sap.sailing.domain.persistence.PersistenceFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.test.PositionAssert;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
@@ -157,7 +159,7 @@ public class TrackedRaceWithGPSFixStoreContentsReplicationTest extends AbstractS
|
||||
competitorTrack.lockForRead();
|
||||
try {
|
||||
assertEquals(1, Util.size(competitorTrack.getRawFixes()));
|
||||
assertEquals(fix, competitorTrack.getRawFixes().iterator().next());
|
||||
PositionAssert.assertGPSFixEquals(fix, competitorTrack.getRawFixes().iterator().next(), /* pos deg delta */ 0.0000001, /* bearing deg delta */ 0.01, /* knot speed delta */ 0.01);
|
||||
assertNotSame(fix, competitorTrack.getRawFixes().iterator().next());
|
||||
} finally {
|
||||
competitorTrack.unlockAfterRead();
|
||||
|
||||
+5
-3
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
|
||||
@@ -73,7 +74,8 @@ public class RaceTrackerTest {
|
||||
service, paramUrl, liveUri, storedUri, courseDesignUpdateUri, EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, /* timeoutInMilliseconds */60000, tracTracUsername, tracTracPassword,
|
||||
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
|
||||
/* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
|
||||
/* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false,
|
||||
/* timeoutInMillis */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
logger.info("Calling raceHandle.getRaces()");
|
||||
RaceDefinition race = raceHandle.getRace(); // wait for RaceDefinition to be completely wired in Regatta
|
||||
logger.info("Obtained race: "+race);
|
||||
@@ -133,7 +135,7 @@ public class RaceTrackerTest {
|
||||
EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, /* timeoutInMilliseconds */60000,
|
||||
tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS,
|
||||
TracTracConnectionConstants.ONLINE_VISIBILITY, /* trackWind */ false,
|
||||
/* correctWindDirectionByMagneticDeclination */ false);
|
||||
/* correctWindDirectionByMagneticDeclination */ false, /* timeoutInMillis */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
TrackedRegatta newTrackedRegatta = myRaceHandle.getTrackedRegatta();
|
||||
assertNotSame(oldTrackedRegatta, newTrackedRegatta);
|
||||
TrackedRace newTrackedRace = getTrackedRace(newTrackedRegatta);
|
||||
@@ -162,7 +164,7 @@ public class RaceTrackerTest {
|
||||
EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, /* timeoutInMilliseconds */60000,
|
||||
tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS,
|
||||
TracTracConnectionConstants.ONLINE_VISIBILITY, /* trackWind */ false,
|
||||
/* correctWindDirectionByMagneticDeclination */ false);
|
||||
/* correctWindDirectionByMagneticDeclination */ false, /* timeoutInMillis */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
TrackedRegatta newTrackedEvent = myRaceHandle.getTrackedRegatta();
|
||||
TrackedRace newTrackedRace = getTrackedRace(newTrackedEvent);
|
||||
// expecting a new tracked race to be created when starting over with tracking
|
||||
|
||||
+26
-3
@@ -42,6 +42,7 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.test.PositionAssert;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
@@ -146,8 +147,22 @@ public class WindByRaceLogTest {
|
||||
|
||||
try {
|
||||
windTrack.lockForRead();
|
||||
assertTrue(Util.contains(windTrack.getFixes(), wind1));
|
||||
assertTrue(Util.contains(windTrack.getFixes(), wind2));
|
||||
boolean foundWind1 = false;
|
||||
boolean foundWind2 = false;
|
||||
for (Wind w : windTrack.getFixes()) {
|
||||
try {
|
||||
PositionAssert.assertWindEquals(w, wind1, /* posDegDelta */ 0.000001, /* bearingDegreeDelta */ 0.01, /* knotSpeedDelta */ 0.01);
|
||||
foundWind1 = true;
|
||||
} catch (AssertionError e) {
|
||||
}
|
||||
try {
|
||||
PositionAssert.assertWindEquals(w, wind2, /* posDegDelta */ 0.000001, /* bearingDegreeDelta */ 0.01, /* knotSpeedDelta */ 0.01);
|
||||
foundWind2 = true;
|
||||
} catch (AssertionError e) {
|
||||
}
|
||||
}
|
||||
assertTrue(foundWind1);
|
||||
assertTrue(foundWind2);
|
||||
} finally {
|
||||
windTrack.unlockAfterRead();
|
||||
}
|
||||
@@ -172,7 +187,15 @@ public class WindByRaceLogTest {
|
||||
|
||||
try {
|
||||
windTrack.lockForRead();
|
||||
assertTrue(Util.contains(windTrack.getFixes(), wind1));
|
||||
boolean foundWind1 = false;
|
||||
for (Wind w : windTrack.getFixes()) {
|
||||
try {
|
||||
PositionAssert.assertWindEquals(w, wind1, /* posDegDelta */ 0.000001, /* bearingDegreeDelta */ 0.01, /* knotSpeedDelta */ 0.01);
|
||||
foundWind1 = true;
|
||||
} catch (AssertionError e) {
|
||||
}
|
||||
}
|
||||
assertTrue(foundWind1);
|
||||
} finally {
|
||||
windTrack.unlockAfterRead();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#------------------------------------------------------------
|
||||
#-- File created 08/03/2017 at 05:38:19
|
||||
#------------------------------------------------------------
|
||||
jjlDATE jjlTIME Epoch RideHeight RideHeightPortHull RideHeightStbdHull Heel Trim ImuSensor_GyroX ImuSensor_GyroY ImuSensor_GyroZ ImuSensor_Pitch ImuSensor_Roll ImuSensor_Yaw ImuSensor_LinearAccX ImuSensor_LinearAccY ImuSensor_LinearAccZ Hb_Z Dn_Z Db_Z LKF_ride_hgh LKF_ride_hgh_Position LKF_ride_hgh_Velocity LKF_ride_hgh_Acceleration LKF_ride_hgh_PositionError LKF_ride_hgh_VelocityError LKF_ride_hgh_AccelerationError Gps_Gga_PosFixTime Gps_Gga_Lat Gps_Gga_Lon Gps_Gga_QI Gps_Gga_HDOP Gps_Gga_AntHeight Gps_Vtg_TMG Gps_Vtg_SOGKnots Gps_Rmc_MagVar Gps_EastVelocity Gps_NorthVelocity Gps_UpVelocity BravoNet_Node0x0A0_Ch0 BravoNet_Node0x0A0_Voltage BravoNet_Node0x0A0_Temperature BravoNet_Node0x0A0_Current SyncTimeDiff SyncTimeSync SyncTimeUpdateCount SyncTimePercentageToSync ES_OnTimeSync
|
||||
20170308.000000 53819.390491 1488951499390.000000 0.313796 -0.714744 -0.853481 -1.500000 3.200000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.100172 -0.314127 -0.330172 0.016091 -0.314174 -0.004288 -0.000000 0.121613 1.403056 0.062733 53819.200000 2337.887200 5815.964540 0.000000 0.000000 0.000000 0.000000 0.000000 1.300000 0.000000 0.000000 0.000000 -0.001831 24.295210 21.217340 0.015640 542266653.468207 0.000000 1.000000 0.000000 0.000000
|
||||
20170308.000000 53819.487567 1488951499481.000000 0.313992 -0.714548 -0.853286 -1.500000 3.200000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.100172 -0.314127 -0.330172 0.016090 -0.314261 -0.002298 0.000000 0.097345 0.648185 0.049813 53819.400000 2337.887200 5815.964540 0.000000 0.000000 0.000000 0.000000 0.000000 1.300000 0.000000 0.000000 0.000000 -0.002441 24.295210 21.000116 0.023460 0.000077 1.000000 1.000000 0.000000 1.000000
|
||||
20170308.000000 53819.585786 1488951499572.000000 0.314025 -0.714515 -0.853253 -1.500000 3.200000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.099696 -0.313652 -0.329696 0.019540 -0.313953 -0.000227 0.000001 0.086096 0.423595 0.043597 53819.400000 2337.887200 5815.964540 0.000000 0.000000 0.000000 0.000000 0.000000 1.300000 0.000000 0.000000 0.000000 -0.002441 24.295210 20.782894 0.046921 0.000077 1.000000 1.000000 0.000000 1.000000
|
||||
20170308.000000 53819.685771 1488951499682.000000 0.313923 -0.714617 -0.853355 -1.500000 3.200000 -0.086588 -0.214116 0.175599 -0.000000 0.000000 0.000000 -0.258920 0.519435 -0.087402 -0.099696 -0.313652 -0.329696 0.019270 -0.313730 0.000672 0.000839 0.075893 0.287746 0.038563 53819.600000 2337.887200 5815.964540 0.000000 0.000000 0.000000 0.000000 0.000000 1.300000 0.000000 0.000000 0.000000 -0.002441 24.253178 21.000116 0.046921 -0.000199 1.000000 1.000000 0.000000 1.000000
|
||||
20170308.000000 53819.782123 1488951499772.000000 0.313831 -0.714709 -0.853447 -1.500000 3.200000 0.013137 -0.213877 0.120009 -1.060399 -3.133662 0.001262 -0.108944 0.029720 0.070589 -0.099696 -0.313652 -0.329696 0.015927 -0.313576 0.001633 0.003961 0.069401 0.222243 0.035510 53819.600000 2337.887200 5815.964540 0.000000 0.000000 0.000000 0.000000 0.000000 1.300000 0.000000 0.000000 0.000000 -0.002441 24.295210 21.000116 0.046921 -0.000199 1.000000 1.000000 0.000000 1.000000
|
||||
20170308.000000 53819.880156 1488951499863.000000 0.314961 -0.768407 -0.798152 -0.321583 2.797351 0.072364 -0.168356 0.209327 -1.091322 -3.133510 0.016635 -0.068841 0.000188 0.184953 -0.099696 -0.324611 -0.329696 0.016254 -0.318301 -0.005391 0.019517 0.064999 0.178037 0.033119 53819.800000 2337.887200 5815.964540 0.000000 0.000000 0.000000 0.000000 0.000000 1.300000 0.000000 0.000000 0.000000 -0.002441 24.295210 21.000116 0.031281 -0.000724 1.000000 1.000000 0.000000 1.000000
|
||||
@@ -1,7 +1,7 @@
|
||||
#------------------------------------------------------------
|
||||
#-- File created 09/04/2016 at 23:26:40
|
||||
#------------------------------------------------------------
|
||||
jjlDATE jjlTIME Epoch RideHeight RideHeightPortHull RideHeightStbdHull Heel Trim ImuSensor_GyroX ImuSensor_GyroY ImuSensor_GyroZ ImuSensor_Pitch ImuSensor_Roll ImuSensor_Yaw ImuSensor_LinearAccX ImuSensor_LinearAccY ImuSensor_LinearAccZ Hb_Z Dn_Z Db_Z LKF_ride_hgh LKF_ride_hgh_Position LKF_ride_hgh_Velocity LKF_ride_hgh_Acceleration LKF_ride_hgh_PositionError LKF_ride_hgh_VelocityError LKF_ride_hgh_AccelerationError Gps_Gga_PosFixTime Gps_Gga_Lat Gps_Gga_Lon Gps_Gga_QI Gps_Gga_HDOP Gps_Gga_AntHeight Gps_Vtg_TMG Gps_Vtg_SOGKnots Gps_Rmc_MagVar Gps_EastVelocity Gps_NorthVelocity Gps_UpVelocity BravoNet_Node0x0A0_Ch0 BravoNet_Node0x0A0_Voltage BravoNet_Node0x0A0_Temperature BravoNet_Node0x0A0_Current
|
||||
jjlDATE jjlTIME Epoch RideHeight RideHeightPortHull RideHeightStbdHull Heel Trim ImuSensor_GyroX ImuSensor_GyroY ImuSensor_GyroZ ImuSensor_Pitch ImuSensor_Roll ImuSensor_Yaw ImuSensor_LinearAccX ImuSensor_LinearAccY ImuSensor_LinearAccZ Hb_Z Dn_Z Db_Z LKF_ride_hgh LKF_ride_hgh_Position LKF_ride_hgh_Velocity LKF_ride_hgh_Acceleration LKF_ride_hgh_PositionError LKF_ride_hgh_VelocityError LKF_ride_hgh_AccelerationError Gps_Gga_PosFixTime Gps_Gga_Lat Gps_Gga_Lon Gps_Gga_QI Gps_Gga_HDOP Gps_Gga_AntHeight Gps_Vtg_TMG Gps_Vtg_SOGKnots Gps_Rmc_MagVar Gps_EastVelocity Gps_NorthVelocity Gps_UpVelocity BravoNet_Node0x0A0_Ch0 BravoNet_Node0x0A0_Voltage BravoNet_Node0x0A0_Temperature BravoNet_Node0x0A0_Current
|
||||
20160409.000000 232640.908740 1460244399905.000000 0.757862 0.650044 0.865680 2.095203 -10.572519 0.014012 0.080612 0.075319 -10.572519 -2.095203 358.804353 -0.021935 0.017397 0.000239 -0.673131 -0.757548 -0.743131 0.013623 -0.757862 -0.004228 -0.018140 0.074238 0.272712 0.037974 212640.800000 5232.276310 1325.488310 1.000000 1.100000 80.800000 306.100000 0.370000 3.200000 -0.170000 0.130000 -0.000000 0.733032 24.043011 36.640236 0.054741
|
||||
20160409.000000 232641.008763 1460244399995.000000 0.758014 0.650158 0.865870 2.095937 -10.571562 0.032092 0.217810 -0.023014 -10.571683 -2.096830 358.798479 -0.028412 0.021632 -0.027246 -0.673131 -0.757548 -0.743131 0.019586 -0.758014 -0.005095 -0.018096 0.069231 0.211765 0.035063 212640.800000 5232.276310 1325.488310 1.000000 1.100000 80.800000 306.100000 0.370000 3.200000 -0.150000 0.110000 -0.000000 0.733032 24.000978 35.988564 0.054741
|
||||
20160409.000000 232641.105742 1460244400089.000000 0.758203 0.650319 0.866087 2.096466 -10.570188 0.073738 0.193435 0.107095 -10.570447 -2.097253 358.792882 -0.042638 0.045676 -0.010817 -0.673131 -0.757547 -0.743131 0.019374 -0.758203 -0.006152 -0.018839 0.064587 0.170564 0.032760 212641.000000 5232.276260 1325.488390 1.000000 1.100000 80.800000 306.100000 0.300000 3.200000 -0.150000 0.110000 -0.000000 0.733032 24.043011 35.988564 0.054741
|
||||
|
||||
+11
-1
@@ -48,6 +48,11 @@ public class BravoDataImportTest {
|
||||
testImport(ImportData.FILE_UNDEFINED_RACE_BRAVO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileImportNewFormat() throws FormatNotSupportedException, IOException {
|
||||
testImport(ImportData.FILE_NEW_BRAVO_FORMAT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultHeaderNoDataImport() throws FormatNotSupportedException, IOException {
|
||||
testImport(ImportData.DUMMY_DEFAULT_HEADER_NO_DATA);
|
||||
@@ -64,7 +69,6 @@ public class BravoDataImportTest {
|
||||
}
|
||||
|
||||
private void testImport(ImportData importData) throws FormatNotSupportedException, IOException {
|
||||
|
||||
bravoDataImporter.importFixes(importData.getInputStream(), (fixes, device) -> {
|
||||
for (DoubleVectorFix fix : fixes) {
|
||||
callbackCallCount++;
|
||||
@@ -85,6 +89,12 @@ public class BravoDataImportTest {
|
||||
return getClass().getResourceAsStream("/Undefined Race - BRAVO.txt");
|
||||
}
|
||||
},
|
||||
FILE_NEW_BRAVO_FORMAT(6, 1) {
|
||||
@Override
|
||||
protected InputStream getInputStream() {
|
||||
return getClass().getResourceAsStream("/FMU_out_new.txt");
|
||||
}
|
||||
},
|
||||
DUMMY_DEFAULT_HEADER_NO_DATA(0, 0) {
|
||||
@Override
|
||||
protected InputStream getInputStream() {
|
||||
|
||||
+8
-4
@@ -6,8 +6,10 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.logging.Level;
|
||||
@@ -142,10 +144,12 @@ public class BravoDataImporterImpl implements DoubleVectorFixImporter {
|
||||
String header = headerTokens[j];
|
||||
colIndicesInFile.put(header, j);
|
||||
}
|
||||
List<String> columnsInFix = metadata.getFileColumns();
|
||||
if (colIndicesInFile.size() != columnsInFix.size() || !colIndicesInFile.keySet().containsAll(columnsInFix)) {
|
||||
LOG.log(Level.SEVERE, "Missing headers");
|
||||
throw new RuntimeException("Missing headers in import files");
|
||||
List<String> requiredColumnsInFix = metadata.getTrackColumns();
|
||||
if (!colIndicesInFile.keySet().containsAll(requiredColumnsInFix)) {
|
||||
final Set<String> missingColumns = new HashSet<>(requiredColumnsInFix);
|
||||
missingColumns.removeAll(colIndicesInFile.keySet());
|
||||
LOG.log(Level.SEVERE, "Missing headers: "+missingColumns);
|
||||
throw new RuntimeException("Missing headers "+missingColumns+" in import files");
|
||||
}
|
||||
return colIndicesInFile;
|
||||
}
|
||||
|
||||
+7
-7
@@ -31,8 +31,8 @@ import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.impl.MasterDataImportObjectCreationCountImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
@@ -415,12 +415,12 @@ public class ImportMasterDataOperation extends
|
||||
DeviceIdentifier device = entry.getKey();
|
||||
final Collection<Timed> fixesToAddAsBatch = new ArrayList<>(BATCH_SIZE_FOR_IMPORTING_FIXES);
|
||||
for (Timed fixToAdd : entry.getValue()) {
|
||||
if (fixToAdd instanceof CompactGPSFixMovingImpl) {
|
||||
CompactGPSFixMovingImpl gpsFix = (CompactGPSFixMovingImpl) fixToAdd;
|
||||
if (fixToAdd instanceof VeryCompactGPSFixMovingImpl) {
|
||||
VeryCompactGPSFixMovingImpl gpsFix = (VeryCompactGPSFixMovingImpl) fixToAdd;
|
||||
fixToAdd = new GPSFixMovingImpl(gpsFix.getPosition(), fixToAdd.getTimePoint(),
|
||||
((CompactGPSFixMovingImpl) fixToAdd).getSpeed());
|
||||
} else if (fixToAdd instanceof CompactGPSFixImpl) {
|
||||
CompactGPSFixImpl gpsFix = (CompactGPSFixImpl) fixToAdd;
|
||||
((VeryCompactGPSFixMovingImpl) fixToAdd).getSpeed());
|
||||
} else if (fixToAdd instanceof VeryCompactGPSFixImpl) {
|
||||
VeryCompactGPSFixImpl gpsFix = (VeryCompactGPSFixImpl) fixToAdd;
|
||||
fixToAdd = new GPSFixImpl(gpsFix.getPosition(), fixToAdd.getTimePoint());
|
||||
}
|
||||
fixesToAddAsBatch.add(fixToAdd);
|
||||
|
||||
Regular → Executable
+18
-1
@@ -23,7 +23,24 @@
|
||||
<h2 class="releaseHeadline">Release Notes - Administration Console</h2>
|
||||
<div class="innerContent">
|
||||
|
||||
<h2 class="articleSubheadline">Febrbuary 2017</h2>
|
||||
<h2 class="articleSubheadline">March 2017</h2>
|
||||
<ul class="bulletList">
|
||||
<li>A more compact internal storage format for GPS and Wind fixes is now being used. Instead of a full
|
||||
64-bit "double" value for all components such at latitude, longitude, speed over ground or course over
|
||||
ground, "smaller" data types such as "int" and "short" are now employed. The reduction of accuracy
|
||||
that this brings about is negligible given the accuracy of the tracking systems used. For example,
|
||||
the latitude values are encoded such that while covering the full range from -90° to +90°, the
|
||||
resolution is at 4.6mm. Similarly, speeds are represented in their compact form in such a way
|
||||
that speeds up to 500kts can be represented at a resolution of 0.015kts.
|
||||
</li>
|
||||
<li>When a race cannot be loaded successfully through the TracTrac connector, e.g., because its boat
|
||||
class does not match the regatta's boat class, the tracker is now stopped, and a SEVERE log message
|
||||
is written, giving the reason for the failure to load the race. This gives administrators an opportunity
|
||||
to correct any errors in the underlying data and try again. Previously, tracking such a
|
||||
was not possible without a server re-start because the tracker continued to exist.
|
||||
</li>
|
||||
</ul>
|
||||
<h2 class="articleSubheadline">February 2017</h2>
|
||||
<ul class="bulletList">
|
||||
<li>Wind data in GRIB format can now be imported in the "Wind" sub-tab of the "Tracked Races" tab
|
||||
in the <tt>AdminConsole</tt>. When one or more races are being tracked, with a tracking time
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.sap.sailing.xmlexport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public class FoilingData {
|
||||
|
||||
private final HttpServletRequest req;
|
||||
private final HttpServletResponse res;
|
||||
private final RacingEventService service;
|
||||
private final boolean useProvidedLeaderboard;
|
||||
|
||||
public FoilingData(HttpServletRequest req, HttpServletResponse res, RacingEventService service) {
|
||||
this.req = req;
|
||||
this.res = res;
|
||||
this.service = service;
|
||||
this.useProvidedLeaderboard = false;
|
||||
}
|
||||
|
||||
public String getAttribute(String name) {
|
||||
return this.req.getParameter(name);
|
||||
}
|
||||
|
||||
public RacingEventService getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
public Leaderboard getLeaderboard() throws IOException, ServletException {
|
||||
Leaderboard leaderboard = null;
|
||||
if (!useProvidedLeaderboard) {
|
||||
final String leaderboardName = getAttribute("name");
|
||||
if (leaderboardName == null) {
|
||||
throw new ServletException("Use the name= parameter to specify the leaderboard");
|
||||
}
|
||||
leaderboard = getService().getLeaderboardByName(leaderboardName);
|
||||
if (leaderboard == null) {
|
||||
throw new ServletException("Leaderboard " + leaderboardName + " not found.");
|
||||
}
|
||||
}
|
||||
return leaderboard;
|
||||
}
|
||||
|
||||
public void perform() throws Exception {
|
||||
StringBuffer result = new StringBuffer();
|
||||
result.append("TimePoint").append(";");
|
||||
result.append("RegattaName").append(";");
|
||||
result.append("RaceName").append(";");
|
||||
result.append("LegIndexStartingAtZero").append(";");
|
||||
result.append("LegType").append(";");
|
||||
result.append("CompetitorName").append(";");
|
||||
result.append("CompetitorSailId").append(";");
|
||||
result.append("CompetitorUUID").append(";");
|
||||
result.append("SpeedOverGroundInKnots").append(";");
|
||||
result.append("RideHeightInMeter").append(";");
|
||||
result.append("RideHeightPortInMeter").append(";");
|
||||
result.append("RideHeightStarboardInMeter").append(";");
|
||||
result.append("Heel").append(";");
|
||||
result.append("Pitch").append(";");
|
||||
result.append("AveragedWindSpeedInKnots").append(";");
|
||||
result.append("WindDirectionInDegrees").append(";");
|
||||
result.append("CompetitorBearingInDegrees").append(";");
|
||||
result.append("BearingDifferenceBetweenCompetitorAndWindInDegrees").append("\n");
|
||||
Leaderboard leaderboard = getLeaderboard();
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
final List<Competitor> allCompetitors = trackedRace.getCompetitorsFromBestToWorst(/*timePoint*/trackedRace.getEndOfRace());
|
||||
for (Competitor competitor : allCompetitors) {
|
||||
DynamicSensorFixTrack<Competitor, BravoFix> sensorTrack = trackedRace.getSensorTrack(competitor, BravoFixTrack.TRACK_NAME);
|
||||
final Duration samplingInterval = Duration.ONE_SECOND;
|
||||
final TimePoint fromTimePoint = trackedRace.getStartOfRace();
|
||||
if (sensorTrack != null && fromTimePoint != null) {
|
||||
final List<WindSource> windSourcesToDeliver = new ArrayList<WindSource>();
|
||||
final WindSource windSource = new WindSourceImpl(WindSourceType.COMBINED);
|
||||
windSourcesToDeliver.add(windSource);
|
||||
final WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource);
|
||||
final TimePoint toTimePoint = trackedRace.getEndOfRace();
|
||||
TimePoint timePointToConsider = fromTimePoint;
|
||||
int attemptedNumberOfFixes = 0;
|
||||
while (toTimePoint == null ? (attemptedNumberOfFixes<5) : (timePointToConsider.compareTo(toTimePoint) < 0)) {
|
||||
BravoFix bravoFixAtTimepoint = sensorTrack.getFirstFixAtOrAfter(timePointToConsider);
|
||||
if (bravoFixAtTimepoint != null) {
|
||||
SpeedWithBearing speedOfCompetitor = trackedRace.getTrack(competitor).getEstimatedSpeed(timePointToConsider);
|
||||
double rideHeight = bravoFixAtTimepoint.get(BravoSensorDataMetadata.RIDE_HEIGHT);
|
||||
double rideHeightPort = bravoFixAtTimepoint.get(BravoSensorDataMetadata.RIDE_HEIGHT_PORT_HULL);
|
||||
double rideHeightStarboard = bravoFixAtTimepoint.get(BravoSensorDataMetadata.RIDE_HEIGHT_STBD_HULL);
|
||||
double heel = bravoFixAtTimepoint.get(BravoSensorDataMetadata.HEEL);
|
||||
double pitch = bravoFixAtTimepoint.get(BravoSensorDataMetadata.PITCH);
|
||||
WindWithConfidence<com.sap.sse.common.Util.Pair<Position, TimePoint>> windFix = windTrack.getAveragedWindWithConfidence(null, timePointToConsider);
|
||||
SpeedWithConfidence<TimePoint> windFixSpeed = new SpeedWithConfidenceImpl<TimePoint>(new KnotSpeedImpl(windFix.getObject().getKnots()), windFix.getConfidence(), timePointToConsider);
|
||||
Bearing windFixBearing = windFix.getObject().getBearing();
|
||||
TrackedLegOfCompetitor leg = trackedRace.getTrackedLeg(competitor, timePointToConsider);
|
||||
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-M-dd HH:mm:ss");
|
||||
result.append(simpleDateFormat.format(timePointToConsider.asDate())).append(";");
|
||||
result.append(trackedRace.getRaceIdentifier().getRegattaName()).append(";");
|
||||
result.append(trackedRace.getRaceIdentifier().getRaceName()).append(";");
|
||||
if (leg != null) {
|
||||
result.append(trackedRace.getRace().getCourse().getLegs().indexOf(leg.getLeg())).append(";");
|
||||
result.append(leg.getTrackedLeg().getLegType(timePointToConsider).name()).append(";");
|
||||
} else {
|
||||
result.append("-1").append(";");
|
||||
result.append("UNKNOWN").append(";");
|
||||
}
|
||||
result.append(competitor.getName()).append(";");
|
||||
result.append(competitor.getBoat().getSailID()).append(";");
|
||||
result.append(competitor.getId()).append(";");
|
||||
result.append(speedOfCompetitor != null ? speedOfCompetitor.getKnots() : "0.0").append(";");
|
||||
result.append(rideHeight).append(";");
|
||||
result.append(rideHeightPort).append(";");
|
||||
result.append(rideHeightStarboard).append(";");
|
||||
result.append(heel).append(";");
|
||||
result.append(pitch).append(";");
|
||||
result.append(windFixSpeed.getObject().getKnots()).append(";");
|
||||
result.append(windFixBearing.reverse().getDegrees()).append(";");
|
||||
result.append(speedOfCompetitor != null ? speedOfCompetitor.getBearing().getDegrees() : "0.0").append(";");
|
||||
result.append(speedOfCompetitor != null ? speedOfCompetitor.getBearing().getDifferenceTo(windFixBearing.reverse()).getDegrees() : "0.0").append("\n");
|
||||
}
|
||||
timePointToConsider = timePointToConsider.plus(samplingInterval);
|
||||
attemptedNumberOfFixes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res.setContentType("text/csv");
|
||||
res.addHeader("Content-Disposition", "attachment; filename=" + leaderboard.getName() + ".csv");
|
||||
res.getOutputStream().write(result.toString().getBytes("UTF-8"));
|
||||
res.getOutputStream().flush();
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,10 @@ public class XmlExportServlet extends SailingServerHttpServlet {
|
||||
final LeaderboardData leaderboardData = new LeaderboardData(req, res, getService());
|
||||
leaderboardData.perform();
|
||||
return;
|
||||
} else if ("foiling".equalsIgnoreCase(action)) {
|
||||
final FoilingData foilingData = new FoilingData(req, res, getService());
|
||||
foilingData.perform();
|
||||
return;
|
||||
}
|
||||
throw new ServletException("Unknown domain " + action);
|
||||
}
|
||||
|
||||
+3
-2
@@ -19,6 +19,7 @@ import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -131,7 +132,7 @@ public abstract class AbstractServerReplicationTestSetUp<ReplicableInterface ext
|
||||
ReplicableImpl master, ReplicableImpl replica) throws Exception {
|
||||
logger.info("basicSetUp for test class "+getClass().getName());
|
||||
persistenceSetUp(dropDB);
|
||||
String exchangeName = "test-sapsailinganalytics-exchange";
|
||||
String exchangeName = "test-sapsailinganalytics-exchange-"+new Random().nextInt();
|
||||
String exchangeHost = "localhost";
|
||||
if (System.getenv(Activator.ENV_VAR_NAME_REPLICATION_HOST) != null) {
|
||||
exchangeHost = System.getenv(Activator.ENV_VAR_NAME_REPLICATION_HOST);
|
||||
@@ -188,7 +189,7 @@ public abstract class AbstractServerReplicationTestSetUp<ReplicableInterface ext
|
||||
}
|
||||
if (masterDescriptor != null) {
|
||||
logger.info("before stopConnection...");
|
||||
masterDescriptor.stopConnection();
|
||||
masterDescriptor.stopConnection(/* deleteExchange */ true);
|
||||
}
|
||||
try {
|
||||
if (initialLoadTestServerThread != null) {
|
||||
|
||||
+6
-1
@@ -59,7 +59,12 @@ public interface ReplicationMasterDescriptor {
|
||||
|
||||
String getExchangeName();
|
||||
|
||||
void stopConnection();
|
||||
/**
|
||||
* @param deleteExchange
|
||||
* Only to be used by the master itself when no longer delivering messages to the exchange, or to tear
|
||||
* down after a test
|
||||
*/
|
||||
void stopConnection(boolean deleteExchange);
|
||||
|
||||
String getMessagingHostname();
|
||||
|
||||
|
||||
+5
-2
@@ -225,12 +225,15 @@ public class ReplicationMasterDescriptorImpl implements ReplicationMasterDescrip
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stopConnection() {
|
||||
public synchronized void stopConnection(boolean deleteExchange) {
|
||||
try {
|
||||
if (consumer != null) {
|
||||
// make sure to remove queue in order to avoid any exchanges filling it with messages
|
||||
consumer.getChannel().queueUnbind(queueName, exchangeName, "");
|
||||
consumer.getChannel().queueDelete(queueName);
|
||||
if (deleteExchange) {
|
||||
consumer.getChannel().exchangeDelete(exchangeName);
|
||||
}
|
||||
consumer.getChannel().getConnection().close(/* timeout in millis */ 1000);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
@@ -239,7 +242,7 @@ public class ReplicationMasterDescriptorImpl implements ReplicationMasterDescrip
|
||||
logger.log(Level.SEVERE, "Exception while closing replication channel consumer", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return 0 means use default port
|
||||
*/
|
||||
|
||||
+1
-1
@@ -400,7 +400,7 @@ public class ReplicationReceiver implements Runnable {
|
||||
}
|
||||
logger.info("Signaled Replicator thread to stop asap.");
|
||||
stopped = true;
|
||||
master.stopConnection();
|
||||
master.stopConnection(/* deleteExchange */ false);
|
||||
notifyAll(); // notify those waiting for stopped
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: TracTrac Client module
|
||||
Bundle-SymbolicName: com.tractrac.clientmodule
|
||||
Bundle-Version: 3.4.1
|
||||
Bundle-Version: 3.6.0
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-ClassPath: .,
|
||||
lib/TracAPI.jar
|
||||
|
||||
@@ -16,6 +16,65 @@ It contains also some files:
|
||||
- test.sh -> script that compiles the code in the src folder, creates the test.jar library and execute the code of the example.
|
||||
- Manifest.txt -> manifest used to create the test.jar file
|
||||
|
||||
********************************************
|
||||
************* TracAPI 3.6.0 ****************
|
||||
********************************************
|
||||
This is a final version. It change the signature of a couple of methods, breaking the
|
||||
backward compatibility. These changes are:
|
||||
|
||||
- The IEventFactory.createRace(URI) doesn't throw the TimeOutException.
|
||||
- The IEventFactory.createRace(URI, URI, URI) doesn't throw the TimeOutException.
|
||||
|
||||
This version provides a new JavaDoc version.
|
||||
|
||||
Release date: 08/03/2017
|
||||
Build number: 13498
|
||||
|
||||
1) Features
|
||||
|
||||
- Removing the TimeOutException of some methods of the IEventFactory (Requested by Axel Uhl, 08/03/2017)
|
||||
|
||||
********************************************
|
||||
************* TracAPI 3.5.0 ****************
|
||||
********************************************
|
||||
This is a final version. It fixes bugs in the implementation and it adds some new features.
|
||||
These features add methods to the API breaking the backward compatibility. These changes are:
|
||||
|
||||
- The IRaceCompetitor interface changes the return type of the getStatusTime method
|
||||
from Date to long.
|
||||
- The methods IEventFactory.createRace throw now a TimeOutException when there is a timeout
|
||||
downloading the parameters file.
|
||||
|
||||
This version provides a new JavaDoc version.
|
||||
|
||||
Release date: 07/03/2017
|
||||
Build number: 13490
|
||||
|
||||
1) Features
|
||||
|
||||
- Updating the return type of the IRaceCompetitor.getStatusTime from Date to long to
|
||||
be consistent with the API (Requested by Jorge Piera, 13/02/2017)
|
||||
- Adding the methods ISegment.getExtent(), the IRoute.getExtent() and IRace.getExtent()
|
||||
that return the extent of the object (Requested by Jorge Piera, 23/02/2017)
|
||||
- Adding an extra parameter to the IEventFactory.createRace methods to indicate
|
||||
the timeout used to download the parameters file. The IEventFactory also includes a method
|
||||
getDefaultTimeOut that returns the default timeout (Requested by Axel Uhl, 06/03/2017)
|
||||
|
||||
********************************************
|
||||
************* TracAPI 3.4.1 ****************
|
||||
********************************************
|
||||
This is a final version. Only fixes bugs in the implementation
|
||||
|
||||
Release date: 20/02/2017
|
||||
Build number: 13415
|
||||
|
||||
1) Bugs
|
||||
|
||||
- TracAPI doesn't send all data when the races are retrieved in parallel.
|
||||
It is an error in the thread that executes the callback messages that in some
|
||||
internal circumstances, doesn't execute the callback (Reported by Axel Uhl,
|
||||
13/02/2017)
|
||||
|
||||
********************************************
|
||||
************* TracAPI 3.4.0 ****************
|
||||
********************************************
|
||||
@@ -33,9 +92,9 @@ Build number: 13339
|
||||
1) Features
|
||||
|
||||
- Adding the method IRace.getDataSource that returns the datasource used by the race
|
||||
to load data (Requested by Axel Ulh, 25/01/2017)
|
||||
to load data (Requested by Axel Uhl, 25/01/2017)
|
||||
- Adding the method IRacesListener.dataSourceChanged that sends a notification
|
||||
every time that the datasource of a race changes (Requested by Axel Ulh, 25/01/2017)
|
||||
every time that the datasource of a race changes (Requested by Axel Uhl, 25/01/2017)
|
||||
|
||||
2) Bugs
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<!-- NewPage -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Generated by javadoc (1.8.0_91) on Tue Jan 17 09:51:12 UTC 2017 -->
|
||||
<!-- Generated by javadoc (1.8.0_111) on Wed Mar 08 07:35:44 UTC 2017 -->
|
||||
<title>All Classes</title>
|
||||
<meta name="date" content="2017-01-17">
|
||||
<meta name="date" content="2017-03-08">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
</head>
|
||||
@@ -14,6 +14,7 @@
|
||||
<ul>
|
||||
<li><a href="com/tractrac/model/lib/api/attachment/AbstractAttachable.html" title="class in com.tractrac.model.lib.api.attachment" target="classFrame">AbstractAttachable</a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/event/CreateModelException.html" title="class in com.tractrac.model.lib.api.event" target="classFrame">CreateModelException</a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/event/DataSource.html" title="enum in com.tractrac.model.lib.api.event" target="classFrame">DataSource</a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/event/EventType.html" title="enum in com.tractrac.model.lib.api.event" target="classFrame">EventType</a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/attachment/IAttachable.html" title="interface in com.tractrac.model.lib.api.attachment" target="classFrame"><span class="interfaceName">IAttachable</span></a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/attachment/IAttachmentKey.html" title="interface in com.tractrac.model.lib.api.attachment" target="classFrame"><span class="interfaceName">IAttachmentKey</span></a></li>
|
||||
@@ -37,6 +38,7 @@
|
||||
<li><a href="com/tractrac/model/lib/api/event/IEventFactory.html" title="interface in com.tractrac.model.lib.api.event" target="classFrame"><span class="interfaceName">IEventFactory</span></a></li>
|
||||
<li><a href="com/tractrac/subscription/lib/api/event/IEventMessageListener.html" title="interface in com.tractrac.subscription.lib.api.event" target="classFrame"><span class="interfaceName">IEventMessageListener</span></a></li>
|
||||
<li><a href="com/tractrac/subscription/lib/api/IEventSubscriber.html" title="interface in com.tractrac.subscription.lib.api" target="classFrame"><span class="interfaceName">IEventSubscriber</span></a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/spatial/IExtent.html" title="interface in com.tractrac.model.lib.api.spatial" target="classFrame"><span class="interfaceName">IExtent</span></a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/spatial/IGeoCoordinate.html" title="interface in com.tractrac.model.lib.api.spatial" target="classFrame"><span class="interfaceName">IGeoCoordinate</span></a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/IIdentifiable.html" title="interface in com.tractrac.model.lib.api" target="classFrame"><span class="interfaceName">IIdentifiable</span></a></li>
|
||||
<li><a href="com/tractrac/subscription/lib/api/event/ILiveDataEvent.html" title="interface in com.tractrac.subscription.lib.api.event" target="classFrame"><span class="interfaceName">ILiveDataEvent</span></a></li>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<!-- NewPage -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Generated by javadoc (1.8.0_91) on Tue Jan 17 09:51:12 UTC 2017 -->
|
||||
<!-- Generated by javadoc (1.8.0_111) on Wed Mar 08 07:35:44 UTC 2017 -->
|
||||
<title>All Classes</title>
|
||||
<meta name="date" content="2017-01-17">
|
||||
<meta name="date" content="2017-03-08">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
</head>
|
||||
@@ -14,6 +14,7 @@
|
||||
<ul>
|
||||
<li><a href="com/tractrac/model/lib/api/attachment/AbstractAttachable.html" title="class in com.tractrac.model.lib.api.attachment">AbstractAttachable</a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/event/CreateModelException.html" title="class in com.tractrac.model.lib.api.event">CreateModelException</a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/event/DataSource.html" title="enum in com.tractrac.model.lib.api.event">DataSource</a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/event/EventType.html" title="enum in com.tractrac.model.lib.api.event">EventType</a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/attachment/IAttachable.html" title="interface in com.tractrac.model.lib.api.attachment"><span class="interfaceName">IAttachable</span></a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/attachment/IAttachmentKey.html" title="interface in com.tractrac.model.lib.api.attachment"><span class="interfaceName">IAttachmentKey</span></a></li>
|
||||
@@ -37,6 +38,7 @@
|
||||
<li><a href="com/tractrac/model/lib/api/event/IEventFactory.html" title="interface in com.tractrac.model.lib.api.event"><span class="interfaceName">IEventFactory</span></a></li>
|
||||
<li><a href="com/tractrac/subscription/lib/api/event/IEventMessageListener.html" title="interface in com.tractrac.subscription.lib.api.event"><span class="interfaceName">IEventMessageListener</span></a></li>
|
||||
<li><a href="com/tractrac/subscription/lib/api/IEventSubscriber.html" title="interface in com.tractrac.subscription.lib.api"><span class="interfaceName">IEventSubscriber</span></a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/spatial/IExtent.html" title="interface in com.tractrac.model.lib.api.spatial"><span class="interfaceName">IExtent</span></a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/spatial/IGeoCoordinate.html" title="interface in com.tractrac.model.lib.api.spatial"><span class="interfaceName">IGeoCoordinate</span></a></li>
|
||||
<li><a href="com/tractrac/model/lib/api/IIdentifiable.html" title="interface in com.tractrac.model.lib.api"><span class="interfaceName">IIdentifiable</span></a></li>
|
||||
<li><a href="com/tractrac/subscription/lib/api/event/ILiveDataEvent.html" title="interface in com.tractrac.subscription.lib.api.event"><span class="interfaceName">ILiveDataEvent</span></a></li>
|
||||
|
||||
Loaded 100 of 244 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user