mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-02 02:13:55 +00:00
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:
1 parent
04531d217f
commit
f24deeb2e3
19 files changed
+239
-146
No files matched your search
+16
-16
@@ -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);
|
||||
|
||||
+3
-3
@@ -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());
|
||||
|
||||
+2
-2
@@ -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> {
|
||||
}
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+3
-58
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+56
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+56
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
-52
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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.
|
||||
*
|
||||
|
||||
+1
-1
@@ -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();
|
||||
}
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -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<TimePoint, Position></code>
|
||||
*/
|
||||
public interface WindWithConfidence<RelativeTo> extends HasConfidenceAndIsScalable<ScalableWind, Wind, RelativeTo> {
|
||||
}
|
||||
+3
-3
@@ -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());
|
||||
|
||||
+51
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-2
@@ -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()) {
|
||||
|
||||
+4
-4
@@ -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);
|
||||
|
||||
Executable
+18
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user