Introduced WindWithConfidence; use Scalable* classes instead of Pair/Triple as scalable values in interfaces;

I extracted some of the Scalable... classes into public standalone classes so I could use them in
ScalableWind. This made it obvious that these classes can easily be used instead of the more
cumbersome Pair<Double, Double> or Triple<Double, Double, Double> types for the scalable value type
argument. Subsequently this required adjustments to a few tests.
This commit is contained in:
Axel Uhl committed 2012-03-01 10:59:48 +01:00
1 parent 04531d217f
commit f24deeb2e3
19 files changed
+239 -146

No files matched your search

@@ -14,6 +14,7 @@ import org.junit.Test;
import com.sap.sailing.domain.base.PositionWithConfidence;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.PositionWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.ScalablePosition;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.TimePoint;
@@ -21,7 +22,6 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.RadianBearingImpl;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.confidence.ConfidenceBasedAverager;
import com.sap.sailing.domain.confidence.ConfidenceFactory;
import com.sap.sailing.domain.confidence.HasConfidence;
@@ -59,7 +59,7 @@ public class ConfidenceTest {
}
@Override
public Bearing divide(double divisor, double confidence) {
public Bearing divide(double divisor) {
double angle;
if (cos == 0) {
angle = sin >= 0 ? Math.PI / 2 : -Math.PI / 2;
@@ -185,9 +185,9 @@ public class ConfidenceTest {
public void testAveragingTwoPositions() {
PositionWithConfidence<TimePoint> p1 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(0, 45), 0.9, null);
PositionWithConfidence<TimePoint> p2 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(0, -45), 0.9, null);
ConfidenceBasedAverager<Triple<Double, Double, Double>, Position, TimePoint> averager = ConfidenceFactory.INSTANCE.createAverager(null);
ConfidenceBasedAverager<ScalablePosition, Position, TimePoint> averager = ConfidenceFactory.INSTANCE.createAverager(null);
List<PositionWithConfidence<TimePoint>> list = Arrays.asList(p1, p2);
HasConfidence<Triple<Double, Double, Double>, Position, TimePoint> average = averager.getAverage(list, null);
HasConfidence<ScalablePosition, Position, TimePoint> average = averager.getAverage(list, null);
assertEquals(0, average.getObject().getLatDeg(), 0.1);
assertEquals(0, average.getObject().getLngDeg(), 0.1);
}
@@ -206,8 +206,8 @@ public class ConfidenceTest {
private void assertScaleAndDownscalePosition(DegreePosition position, double scale) {
PositionWithConfidence<TimePoint> p1 = new PositionWithConfidenceImpl<TimePoint>(position, 0.9, null);
ScalableValue<Triple<Double, Double, Double>, Position> scaledPosition = p1.getScalableValue().multiply(scale);
Position downscaledPosition = scaledPosition.divide(scale, 1);
ScalableValue<ScalablePosition, Position> scaledPosition = p1.getScalableValue().multiply(scale);
Position downscaledPosition = scaledPosition.divide(scale);
assertEquals(position.getLatDeg(), downscaledPosition.getLatDeg(), 0.000001);
assertEquals(position.getLngDeg(), downscaledPosition.getLngDeg(), 0.000001);
}
@@ -216,9 +216,9 @@ public class ConfidenceTest {
public void testAveragingTwoPositionsToNorthPole() {
PositionWithConfidence<TimePoint> p1 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(45, 90), 0.9, null);
PositionWithConfidence<TimePoint> p2 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(45, -90), 0.9, null);
ConfidenceBasedAverager<Triple<Double, Double, Double>, Position, TimePoint> averager = ConfidenceFactory.INSTANCE.createAverager(null);
ConfidenceBasedAverager<ScalablePosition, Position, TimePoint> averager = ConfidenceFactory.INSTANCE.createAverager(null);
List<PositionWithConfidence<TimePoint>> list = Arrays.asList(p1, p2);
HasConfidence<Triple<Double, Double, Double>, Position, TimePoint> average = averager.getAverage(list, null);
HasConfidence<ScalablePosition, Position, TimePoint> average = averager.getAverage(list, null);
assertEquals(90, average.getObject().getLatDeg(), 0.1);
assertEquals(0, average.getObject().getLngDeg(), 0.1);
}
@@ -228,9 +228,9 @@ public class ConfidenceTest {
PositionWithConfidence<TimePoint> p1 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(49, 8), 0.9, null);
PositionWithConfidence<TimePoint> p2 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(49, 9), 0.9, null);
PositionWithConfidence<TimePoint> p3 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(50, 8.5), 0.9, null);
ConfidenceBasedAverager<Triple<Double, Double, Double>, Position, TimePoint> averager = ConfidenceFactory.INSTANCE.createAverager(null);
ConfidenceBasedAverager<ScalablePosition, Position, TimePoint> averager = ConfidenceFactory.INSTANCE.createAverager(null);
List<PositionWithConfidence<TimePoint>> list = Arrays.asList(p1, p2, p3);
HasConfidence<Triple<Double, Double, Double>, Position, TimePoint> average = averager.getAverage(list, null);
HasConfidence<ScalablePosition, Position, TimePoint> average = averager.getAverage(list, null);
assertTrue(average.getObject().getLatDeg() > 49);
assertTrue(average.getObject().getLatDeg() < 50);
assertEquals(8.5, average.getObject().getLngDeg(), 0.000000001);
@@ -327,10 +327,10 @@ public class ConfidenceTest {
0.9, new MillisecondsTimePoint(2000)); // confidence 2/4 when viewed for time point 1000
PositionWithConfidence<TimePoint> p2 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(0, -45),
0.9, new MillisecondsTimePoint(1000)); // confidence 4/4 when viewed for time point 1000
ConfidenceBasedAverager<Triple<Double, Double, Double>, Position, TimePoint> averager = ConfidenceFactory.INSTANCE
ConfidenceBasedAverager<ScalablePosition, Position, TimePoint> averager = ConfidenceFactory.INSTANCE
.createAverager(ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(1000));
List<PositionWithConfidence<TimePoint>> list = Arrays.asList(p1, p2);
HasConfidence<Triple<Double, Double, Double>, Position, TimePoint> average = averager.getAverage(list, new MillisecondsTimePoint(1000));
HasConfidence<ScalablePosition, Position, TimePoint> average = averager.getAverage(list, new MillisecondsTimePoint(1000));
assertEquals(0, average.getObject().getLatDeg(), 0.1);
// note that the weight varies rather with atan(x) than with x
assertEquals(Math.atan2(-1, 3)/Math.PI*180., average.getObject().getLngDeg(), 0.0001);
@@ -342,10 +342,10 @@ public class ConfidenceTest {
0.9, new MillisecondsTimePoint(1000)); // confidence 4/4 when viewed for time point 1000
PositionWithConfidence<TimePoint> p2 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(45, -90),
0.9, new MillisecondsTimePoint(2000)); // confidence 2/4 when viewed for time point 1000
ConfidenceBasedAverager<Triple<Double, Double, Double>, Position, TimePoint> averager = ConfidenceFactory.INSTANCE
ConfidenceBasedAverager<ScalablePosition, Position, TimePoint> averager = ConfidenceFactory.INSTANCE
.createAverager(ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(1000));
List<PositionWithConfidence<TimePoint>> list = Arrays.asList(p1, p2);
HasConfidence<Triple<Double, Double, Double>, Position, TimePoint> average = averager.getAverage(list, new MillisecondsTimePoint(1000));
HasConfidence<ScalablePosition, Position, TimePoint> average = averager.getAverage(list, new MillisecondsTimePoint(1000));
assertEquals(Math.atan2(3, 1)/Math.PI*180., average.getObject().getLatDeg(), 0.1);
assertEquals(90, average.getObject().getLngDeg(), 0.1);
}
@@ -358,11 +358,11 @@ public class ConfidenceTest {
0.9, new MillisecondsTimePoint(2000)); // confidence 2/4 when viewed for time point 1000
PositionWithConfidence<TimePoint> p3 = new PositionWithConfidenceImpl<TimePoint>(new DegreePosition(50, 8.5),
0.9, new MillisecondsTimePoint(3000)); // confidence 1/4 when viewed for time point 1000
ConfidenceBasedAverager<Triple<Double, Double, Double>, Position, TimePoint> averager = ConfidenceFactory.INSTANCE
ConfidenceBasedAverager<ScalablePosition, Position, TimePoint> averager = ConfidenceFactory.INSTANCE
.createAverager(ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(1000));
List<PositionWithConfidence<TimePoint>> list = Arrays.asList(p1, p2, p3);
// asking for time 1000, we're expecting to be closer to (49, 8) than to the other fixes
HasConfidence<Triple<Double, Double, Double>, Position, TimePoint> average = averager.getAverage(list, new MillisecondsTimePoint(1000));
HasConfidence<ScalablePosition, Position, TimePoint> average = averager.getAverage(list, new MillisecondsTimePoint(1000));
assertTrue(average.getObject().getLatDeg() > 49);
assertTrue(average.getObject().getLatDeg() < 49.15);
assertEquals((8.0*4/4 + 9.0*2/4 + 8.5*1/4)/(7./4.), average.getObject().getLngDeg(), 0.01);
@@ -16,6 +16,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.BearingWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.PositionWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.ScalablePosition;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
@@ -23,7 +24,6 @@ import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.confidence.ConfidenceBasedAverager;
import com.sap.sailing.domain.confidence.ConfidenceFactory;
import com.sap.sailing.domain.confidence.HasConfidence;
@@ -50,8 +50,8 @@ public class WindEstimationOnStoredTracksTest extends StoredTrackBasedTestWithTr
@Test
public void testZeroConfidenceLeadsToNullPositionAverage() {
ConfidenceBasedAverager<Triple<Double, Double, Double>, Position, Void> averager = ConfidenceFactory.INSTANCE.createAverager(null);
HasConfidence<Triple<Double, Double, Double>, Position, Void> average = averager.getAverage(
ConfidenceBasedAverager<ScalablePosition, Position, Void> averager = ConfidenceFactory.INSTANCE.createAverager(null);
HasConfidence<ScalablePosition, Position, Void> average = averager.getAverage(
Collections.singleton(new PositionWithConfidenceImpl<Void>(new DegreePosition(123, 12), /* confidence */
0.0, null)), null);
assertNull(average.getObject());
@@ -1,7 +1,7 @@
package com.sap.sailing.domain.base;
import com.sap.sailing.domain.base.impl.ScalablePosition;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.confidence.HasConfidenceAndIsScalable;
/**
@@ -11,5 +11,5 @@ import com.sap.sailing.domain.confidence.HasConfidenceAndIsScalable;
* @author Axel Uhl (d043530)
*
*/
public interface PositionWithConfidence<RelativeTo> extends HasConfidenceAndIsScalable<Triple<Double, Double, Double>, Position, RelativeTo> {
public interface PositionWithConfidence<RelativeTo> extends HasConfidenceAndIsScalable<ScalablePosition, Position, RelativeTo> {
}
@@ -50,7 +50,7 @@ implements BearingWithConfidence<RelativeTo>, IsScalable<Pair<Double, Double>, B
* is returned in such cases.
*/
@Override
public Bearing divide(double divisor, double confidence) {
public Bearing divide(double divisor) {
Bearing result;
if (sin == 0 && cos == 0) {
result = null;
@@ -2,71 +2,16 @@ package com.sap.sailing.domain.base.impl;
import com.sap.sailing.domain.base.PositionWithConfidence;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.impl.RadianPosition;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.confidence.IsScalable;
import com.sap.sailing.domain.confidence.ScalableValue;
public class PositionWithConfidenceImpl<RelativeTo> extends HasConfidenceImpl<Triple<Double, Double, Double>, Position, RelativeTo> implements
PositionWithConfidence<RelativeTo>, IsScalable<Triple<Double, Double, Double>, Position> {
public class PositionWithConfidenceImpl<RelativeTo> extends HasConfidenceImpl<ScalablePosition, Position, RelativeTo> implements
PositionWithConfidence<RelativeTo>, IsScalable<ScalablePosition, Position> {
public PositionWithConfidenceImpl(Position position, double confidence, RelativeTo relativeTo) {
super(position, confidence, relativeTo);
}
@Override
public ScalableValue<Triple<Double, Double, Double>, Position> getScalableValue() {
public ScalablePosition getScalableValue() {
return new ScalablePosition(getObject());
}
private static class ScalablePosition implements ScalableValue<Triple<Double, Double, Double>, Position> {
private final double x, y, z;
public ScalablePosition(Position position) {
this(Math.cos(position.getLatRad()) * Math.cos(position.getLngRad()),
Math.cos(position.getLatRad()) * Math.sin(position.getLngRad()),
Math.sin(position.getLatRad()));
}
public ScalablePosition(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public ScalableValue<Triple<Double, Double, Double>, Position> multiply(double factor) {
return new ScalablePosition(factor*x, factor*y, factor*z);
}
@Override
public ScalableValue<Triple<Double, Double, Double>, Position> add(
ScalableValue<Triple<Double, Double, Double>, Position> t) {
return new ScalablePosition(x+t.getValue().getA(), y+t.getValue().getB(), z+t.getValue().getC());
}
/**
* If combined confidence is 0.0 (all coordinate components are 0.0), <code>null</code> is returned because no
* position can reasonably be constructed out of nowhere.
*/
@Override
public Position divide(double divisor, double confidence) {
Position result;
if (x == 0 && y == 0 && z == 0) {
result = null;
} else {
// don't need to scale down; atan2 is agnostic regarding scaling factors
double hyp = Math.sqrt(x * x + y * y);
double latRad = Math.atan2(z, hyp);
double lngRad = Math.atan2(y, x);
result = new RadianPosition(latRad, lngRad);
}
return result;
}
@Override
public Triple<Double, Double, Double> getValue() {
return new Triple<Double, Double, Double>(x, y, z);
}
}
}
@@ -0,0 +1,56 @@
package com.sap.sailing.domain.base.impl;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.impl.RadianPosition;
import com.sap.sailing.domain.confidence.ScalableValue;
public class ScalablePosition implements ScalableValue<ScalablePosition, Position> {
private final double x, y, z;
public ScalablePosition(Position position) {
this(Math.cos(position.getLatRad()) * Math.cos(position.getLngRad()),
Math.cos(position.getLatRad()) * Math.sin(position.getLngRad()),
Math.sin(position.getLatRad()));
}
public ScalablePosition(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public ScalablePosition multiply(double factor) {
return new ScalablePosition(factor*x, factor*y, factor*z);
}
@Override
public ScalablePosition add(ScalableValue<ScalablePosition, Position> t) {
return new ScalablePosition(x+t.getValue().x, y+t.getValue().y, z+t.getValue().z);
}
/**
* If combined confidence is 0.0 (all coordinate components are 0.0), <code>null</code> is returned because no
* position can reasonably be constructed out of nowhere.
*/
@Override
public Position divide(double divisor) {
Position result;
if (x == 0 && y == 0 && z == 0) {
result = null;
} else {
// don't need to scale down; atan2 is agnostic regarding scaling factors
double hyp = Math.sqrt(x * x + y * y);
double latRad = Math.atan2(z, hyp);
double lngRad = Math.atan2(y, x);
result = new RadianPosition(latRad, lngRad);
}
return result;
}
@Override
public ScalablePosition getValue() {
return this;
}
}
@@ -0,0 +1,56 @@
package com.sap.sailing.domain.base.impl;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.impl.RadianBearingImpl;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.confidence.ScalableValue;
public class ScalableSpeedWithBearing implements ScalableValue<Triple<Speed, Double, Double>, SpeedWithBearing> {
private final Speed speed;
private final double sin;
private final double cos;
public ScalableSpeedWithBearing(SpeedWithBearing speedWithBearing) {
this(new KnotSpeedImpl(speedWithBearing.getKnots()), Math.sin(speedWithBearing.getBearing()
.getRadians()), Math.cos(speedWithBearing.getBearing().getRadians()));
}
public ScalableSpeedWithBearing(Speed speed, double sin, double cos) {
this.speed = speed;
this.sin = sin;
this.cos = cos;
}
@Override
public ScalableSpeedWithBearing multiply(double factor) {
Speed newSpeed = new KnotSpeedImpl(factor*speed.getKnots());
return new ScalableSpeedWithBearing(newSpeed, factor*sin, factor*cos);
}
@Override
public ScalableSpeedWithBearing add(ScalableValue<Triple<Speed, Double, Double>, SpeedWithBearing> t) {
Speed newSpeed = new KnotSpeedImpl(speed.getKnots() + t.getValue().getA().getKnots());
return new ScalableSpeedWithBearing(newSpeed, sin+t.getValue().getB(), cos+t.getValue().getC());
}
@Override
public SpeedWithBearing divide(double divisor) {
Speed newSpeed = new KnotSpeedImpl(speed.getKnots() / divisor);
double angle;
if (cos == 0) {
angle = sin >= 0 ? Math.PI / 2 : -Math.PI / 2;
} else {
angle = Math.atan2(sin, cos);
}
Bearing bearing = new RadianBearingImpl(angle < 0 ? angle + 2 * Math.PI : angle);
return new KnotSpeedWithBearingImpl(newSpeed.getKnots(), bearing);
}
@Override
public Triple<Speed, Double, Double> getValue() {
return new Triple<Speed, Double, Double>(speed, sin, cos);
}
}
@@ -2,9 +2,7 @@ package com.sap.sailing.domain.base.impl;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.impl.RadianBearingImpl;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.confidence.IsScalable;
import com.sap.sailing.domain.confidence.ScalableValue;
@@ -25,54 +23,4 @@ public class SpeedWithBearingWithConfidenceImpl<RelativeTo> extends
public ScalableValue<Triple<Speed, Double, Double>, SpeedWithBearing> getScalableValue() {
return new ScalableSpeedWithBearing(getObject());
}
private static class ScalableSpeedWithBearing implements ScalableValue<Triple<Speed, Double, Double>, SpeedWithBearing> {
private final Speed speed;
private final double sin;
private final double cos;
public ScalableSpeedWithBearing(SpeedWithBearing speedWithBearing) {
this(new KnotSpeedImpl(speedWithBearing.getKnots()), Math.sin(speedWithBearing.getBearing()
.getRadians()), Math.cos(speedWithBearing.getBearing().getRadians()));
}
public ScalableSpeedWithBearing(Speed speed, double sin, double cos) {
this.speed = speed;
this.sin = sin;
this.cos = cos;
}
@Override
public ScalableValue<Triple<Speed, Double, Double>, SpeedWithBearing> multiply(
double factor) {
Speed newSpeed = new KnotSpeedImpl(factor*speed.getKnots());
return new ScalableSpeedWithBearing(newSpeed, factor*sin, factor*cos);
}
@Override
public ScalableValue<Triple<Speed, Double, Double>, SpeedWithBearing> add(
ScalableValue<Triple<Speed, Double, Double>, SpeedWithBearing> t) {
Speed newSpeed = new KnotSpeedImpl(speed.getKnots() + t.getValue().getA().getKnots());
return new ScalableSpeedWithBearing(newSpeed, sin+t.getValue().getB(), cos+t.getValue().getC());
}
@Override
public SpeedWithBearing divide(double divisor, double confidence) {
Speed newSpeed = new KnotSpeedImpl(speed.getKnots() / divisor);
double angle;
if (cos == 0) {
angle = sin >= 0 ? Math.PI / 2 : -Math.PI / 2;
} else {
angle = Math.atan2(sin, cos);
}
Bearing bearing = new RadianBearingImpl(angle < 0 ? angle + 2 * Math.PI : angle);
return new KnotSpeedWithBearingImpl(newSpeed.getKnots(), bearing);
}
@Override
public Triple<Speed, Double, Double> getValue() {
return new Triple<Speed, Double, Double>(speed, sin, cos);
}
}
}
@@ -36,7 +36,7 @@ public class SpeedWithConfidenceImpl<RelativeTo> extends HasConfidenceImpl<Doubl
}
@Override
public Speed divide(double divisor, double confidence) {
public Speed divide(double divisor) {
return new KnotSpeedImpl(knots / divisor);
}
@@ -27,7 +27,7 @@ import com.sap.sailing.domain.tracking.GPSFixTrack;
* {@link ScalableValue} which is then used for computing a weighed sum. The values' weight is their
* {@link #getConfidence() confidence}. The sum (which is still a {@link ScalableValue} because
* {@link ScalableValue#add(ScalableValue)} returns again a {@link ScalableValue}) is then
* {@link ScalableValue#divide(double, double) divided} by the sum of the confidences. This "division" is expected to
* {@link ScalableValue#divide(double) divided} by the sum of the confidences. This "division" is expected to
* produce an object of type <code>AveragesTo</code>. Usually, <code>AveragesTo</code> would be the same as the class
* implementing this interface.
*
@@ -5,7 +5,7 @@ public interface ScalableValue<ValueType, AveragesTo> {
ScalableValue<ValueType, AveragesTo> add(ScalableValue<ValueType, AveragesTo> t);
AveragesTo divide(double divisor, double confidence);
AveragesTo divide(double divisor);
ValueType getValue();
}
@@ -63,7 +63,7 @@ public class ConfidenceBasedAveragerImpl<ValueType, BaseType, RelativeTo> implem
}
// TODO consider greater variance to reduce the confidence
double newConfidence = confidenceSum / Util.size(values);
BaseType result = numerator.divide(confidenceSum, newConfidence);
BaseType result = numerator.divide(confidenceSum);
return new HasConfidenceImpl<ValueType, BaseType, RelativeTo>(result, newConfidence, at);
}
}
@@ -21,7 +21,7 @@ public class ScalableDouble implements AbstractScalarValue<Double> {
}
@Override
public Double divide(double divisor, double confidence) {
public Double divide(double divisor) {
return getValue()/divisor;
}
@@ -0,0 +1,18 @@
package com.sap.sailing.domain.tracking;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.confidence.HasConfidenceAndIsScalable;
import com.sap.sailing.domain.tracking.impl.ScalableWind;
/**
* In order to scale a wind value, a specific type is used: {@link ScalableWind}.
*
* @author Axel Uhl (d043530)
*
* @param <RelativeTo>
* Typical candidates are {@link TimePoint}, {@link Position} or a combination thereof, such as
* <code>Pair&lt;TimePoint, Position&gt;</code>
*/
public interface WindWithConfidence<RelativeTo> extends HasConfidenceAndIsScalable<ScalableWind, Wind, RelativeTo> {
}
@@ -161,7 +161,7 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
private Position getEstimatedPosition(TimePoint timePoint, boolean extrapolate, FixType lastFixAtOrBefore,
FixType firstFixAtOrAfter) {
// TODO bug #169: compute a confidence value for the position returned based on time difference between fix(es) and timePoint; consider using Taylor approximation of more fixes around timePoint to predict and weigh position
// TODO bug #346: compute a confidence value for the position returned based on time difference between fix(es) and timePoint; consider using Taylor approximation of more fixes around timePoint to predict and weigh position
if (lastFixAtOrBefore != null && lastFixAtOrBefore == firstFixAtOrAfter) {
return lastFixAtOrBefore.getPosition(); // exact match; how unlikely is that?
} else {
@@ -356,9 +356,9 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
Iterator<GPSFix> fixIter = relevantFixes.iterator();
GPSFix last = fixIter.next();
while (fixIter.hasNext()) {
// TODO bug #169: consider time difference between next.getTimepoint() and at to compute a confidence
// TODO bug #346: consider time difference between next.getTimepoint() and at to compute a confidence
GPSFix next = fixIter.next();
// TODO bug #169: use SpeedWithConfidence to aggregate confidence-tagged speed values
// TODO bug #345: use SpeedWithConfidence to aggregate confidence-tagged speed values
MillisecondsTimePoint relativeTo = new MillisecondsTimePoint((last.getTimePoint().asMillis() + next.getTimePoint().asMillis())/2);
Speed speed = last.getPosition().getDistance(next.getPosition())
.inTime(next.getTimePoint().asMillis() - last.getTimePoint().asMillis());
@@ -0,0 +1,51 @@
package com.sap.sailing.domain.tracking.impl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.ScalablePosition;
import com.sap.sailing.domain.base.impl.ScalableSpeedWithBearing;
import com.sap.sailing.domain.confidence.ScalableValue;
import com.sap.sailing.domain.tracking.Wind;
public class ScalableWind implements ScalableValue<ScalableWind, Wind> {
private final ScalablePosition scalablePosition;
private final double scaledTimePointSumInMilliseconds;
private final ScalableSpeedWithBearing scalableSpeedWithBearing;
public ScalableWind(Wind wind) {
this.scalablePosition = new ScalablePosition(wind.getPosition());
this.scaledTimePointSumInMilliseconds = wind.getTimePoint().asMillis();
this.scalableSpeedWithBearing = new ScalableSpeedWithBearing(wind);
}
private ScalableWind(ScalablePosition scalablePosition, double scaledTimePointSumInMilliseconds,
ScalableSpeedWithBearing scalableSpeedWithBearing) {
super();
this.scalablePosition = scalablePosition;
this.scaledTimePointSumInMilliseconds = scaledTimePointSumInMilliseconds;
this.scalableSpeedWithBearing = scalableSpeedWithBearing;
}
@Override
public ScalableWind multiply(double factor) {
return new ScalableWind(scalablePosition.multiply(factor), factor*scaledTimePointSumInMilliseconds, scalableSpeedWithBearing.multiply(factor));
}
@Override
public ScalableWind add(ScalableValue<ScalableWind, Wind> t) {
return new ScalableWind(scalablePosition.add(t.getValue().scalablePosition),
scaledTimePointSumInMilliseconds+t.getValue().scaledTimePointSumInMilliseconds,
scalableSpeedWithBearing.add(t.getValue().scalableSpeedWithBearing));
}
@Override
public Wind divide(double divisor) {
return new WindImpl(scalablePosition.divide(divisor), new MillisecondsTimePoint(
(long) (scaledTimePointSumInMilliseconds / divisor)), scalableSpeedWithBearing.divide(divisor));
}
@Override
public ScalableWind getValue() {
return this;
}
}
@@ -700,7 +700,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
getMillisecondsOverWhichToAverageSpeed());
Map<LegType, BearingWithConfidenceCluster<TimePoint>> bearings = clusterBearingsForWindEstimation(timePoint,
dummyMarkPassingForNow, weigher);
position, dummyMarkPassingForNow, weigher);
// use the minimum confidence of the four "quadrants" as the result's confidence
BearingWithConfidenceImpl<TimePoint> reversedUpwindAverage = null;
int upwindNumberOfRelevantBoats = 0;
@@ -742,8 +742,9 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
new KnotSpeedWithBearingImpl(/* speedInKnots */ numberOfBoatsRelevantForEstimate, resultBearing.getObject()));
}
// TODO confidences need to be computed not only based on timePoint but also on position: boats far away don't contribute as confidently as boats close by
private Map<LegType, BearingWithConfidenceCluster<TimePoint>> clusterBearingsForWindEstimation(TimePoint timePoint,
DummyMarkPassingWithTimePointOnly dummyMarkPassingForNow, Weigher<TimePoint> weigher) {
Position position, DummyMarkPassingWithTimePointOnly dummyMarkPassingForNow, Weigher<TimePoint> weigher) {
Weigher<TimePoint> weigherForMarkPassingProximity = new LinearTimeDifferenceWeigher(getMillisecondsOverWhichToAverageSpeed()*5);
Map<LegType, BearingWithConfidenceCluster<TimePoint>> bearings = new HashMap<LegType, BearingWithConfidenceCluster<TimePoint>>();
for (LegType legType : LegType.values()) {
@@ -135,7 +135,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
Iterator<Wind> beforeIter = beforeSet.descendingIterator();
Iterator<Wind> afterIter = afterSet.iterator();
double knotSum = 0;
// TODO bug #169: also measure speed with confidence; return confidence
// TODO bug #345: also measure speed with confidence; return confidence
Weigher<TimePoint> weigher = ConfidenceFactory.INSTANCE.createLinearTimeDifferenceWeigher(millisecondsOverWhichToAverage/10);
BearingWithConfidenceCluster<TimePoint> bearingCluster = new BearingWithConfidenceCluster<TimePoint>(weigher);
int count = 0;
@@ -161,7 +161,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
beforeIntervalEnd = beforeWind.getTimePoint();
}
knotSum += beforeWind.getKnots();
// TODO bug #169: replace confidence with passed-through confidence of beforeWind fix's confidence
// TODO bug #346: replace confidence with passed-through confidence of beforeWind fix's confidence
bearingCluster.add(new BearingWithConfidenceImpl<TimePoint>(beforeWind.getBearing(), /* confidence */ 0.9, beforeWind.getTimePoint()));
count++;
if (beforeIter.hasNext()) {
@@ -176,7 +176,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
afterIntervalStart = afterWind.getTimePoint();
}
knotSum += afterWind.getKnots();
// TODO bug #169: replace confidence with passed-through confidence of beforeWind fix's confidence
// TODO bug #346: replace confidence with passed-through confidence of beforeWind fix's confidence
bearingCluster.add(new BearingWithConfidenceImpl<TimePoint>(afterWind.getBearing(), /* confidence */ 0.9, afterWind.getTimePoint()));
count++;
if (afterIter.hasNext()) {
@@ -191,7 +191,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
if (count == 0) {
return null;
} else {
// TODO bug #169: pass on confidence
// TODO bug #346: pass on confidence
BearingWithConfidence<TimePoint> average = bearingCluster.getAverage(at);
SpeedWithBearing avgWindSpeed = new KnotSpeedWithBearingImpl(knotSum / count, average == null ? null : average.getObject());
return new WindImpl(p, at, avgWindSpeed);
@@ -0,0 +1,18 @@
package com.sap.sailing.domain.tracking.impl;
import com.sap.sailing.domain.base.impl.HasConfidenceImpl;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.WindWithConfidence;
public class WindWithConfidenceImpl<RelativeTo> extends HasConfidenceImpl<ScalableWind, Wind, RelativeTo> implements WindWithConfidence<RelativeTo> {
public WindWithConfidenceImpl(Wind object, double confidence, RelativeTo relativeTo) {
super(object, confidence, relativeTo);
}
@Override
public ScalableWind getScalableValue() {
return new ScalableWind(getObject());
}
}