attempt to implement solution to bug 156/1055 by integrating maneuver loss across maneuver fixes, projected onto mean maneuver course

This commit is contained in:
Axel Uhl
2012-11-23 21:39:42 +01:00
parent 6e2b9efb67
commit e93716220d
8 changed files with 79 additions and 27 deletions
@@ -12,7 +12,7 @@ public interface Position extends Serializable {
double getLngDeg();
/**
* Central angle between this position and the other position
* Central angle between this position and the other position, in radians
*/
double getCentralAngleRad(Position p);
@@ -58,5 +58,5 @@ public interface Speed extends Comparable<Speed>, Serializable {
* amount then so will the resulting distance.
*/
Distance travel(TimePoint from, TimePoint to);
}
@@ -23,4 +23,14 @@ public interface SpeedWithBearing extends Speed {
CourseChange getCourseChangeRequiredToReach(SpeedWithBearing targetSpeedWithBearing);
SpeedWithBearing applyCourseChange(CourseChange courseChange);
/**
* Projects this speed onto <code>bearing</code>. The speed will keep its sign, regardless of whether the <code>bearing</code> points in
* the opposite direction or not. The resulting speed can never be greater than this speed. If this speed's bearing is orthogonal to
* <code>bearing</code>, a zero speed will result.
*
* @param position the position at which to perform the projection; the angle between the bearings depends on the position
*/
Speed projectTo(Position position, Bearing bearing);
}
@@ -4,7 +4,9 @@ import com.sap.sailing.domain.base.CourseChange;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.common.AbstractSpeedImpl;
import com.sap.sailing.domain.common.Bearing;
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.TimePoint;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
@@ -18,7 +20,7 @@ public abstract class AbstractSpeedWithAbstractBearingImpl extends AbstractSpeed
@Override
public String toString() {
return super.toString()+" to "+getBearing().getDegrees()+"°";
return super.toString()+" to "+getBearing().getDegrees()+"�";
}
@Override
@@ -64,4 +66,19 @@ public abstract class AbstractSpeedWithAbstractBearingImpl extends AbstractSpeed
double newSpeedInKnots = from.getKnots()+courseChange.getSpeedChangeInKnots();
return new KnotSpeedWithBearingImpl(newSpeedInKnots, newBearing);
}
private final static TimePoint start = new MillisecondsTimePoint(0);
private final static TimePoint end = start.plus(60000);
public static Speed projectTo(SpeedWithBearing speedWithBearing, Position position, Bearing projectTo) {
Position traveledOneMinute = speedWithBearing.travelTo(position, start, end);
Position traveledToProjected = traveledOneMinute.projectToLineThrough(position, projectTo);
Distance projectedDistance = position.getDistance(traveledToProjected);
return projectedDistance.inTime(end.asMillis() - start.asMillis());
}
@Override
public Speed projectTo(Position position, Bearing projectTo) {
return projectTo(this, position, projectTo);
}
}
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.CourseChange;
import com.sap.sailing.domain.base.SpeedWithBearing;
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.TimePoint;
import com.sap.sailing.domain.common.impl.KilometersPerHourSpeedImpl;
@@ -38,7 +39,7 @@ public class KilometersPerHourSpeedWithBearingImpl extends KilometersPerHourSpee
@Override
public String toString() {
return super.toString()+" to "+getBearing().getDegrees()+"°";
return super.toString()+" to "+getBearing().getDegrees()+"�";
}
@Override
@@ -51,4 +52,9 @@ public class KilometersPerHourSpeedWithBearingImpl extends KilometersPerHourSpee
return super.equals(object) && object instanceof SpeedWithBearing
&& getBearing().equals(((SpeedWithBearing) object).getBearing());
}
@Override
public Speed projectTo(Position position, Bearing projectTo) {
return AbstractSpeedWithAbstractBearingImpl.projectTo(this, position, projectTo);
}
}
@@ -2,11 +2,13 @@ package com.sap.sailing.domain.tracking.impl;
import com.sap.sailing.domain.base.CourseChange;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.impl.AbstractSpeedWithAbstractBearingImpl;
import com.sap.sailing.domain.base.impl.AbstractSpeedWithBearingImpl;
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.Position;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.tracking.GPSFixMoving;
@@ -54,7 +56,7 @@ public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFix
@Override
public String toString() {
return super.toString()+" to "+getBearing().getDegrees()+"°";
return super.toString()+" to "+getBearing().getDegrees()+"�";
}
@Override
public int hashCode() {
@@ -66,6 +68,11 @@ public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFix
return super.equals(object) && object instanceof SpeedWithBearing
&& getBearing().equals(((SpeedWithBearing) object).getBearing());
}
@Override
public Speed projectTo(Position position, Bearing projectTo) {
return AbstractSpeedWithAbstractBearingImpl.projectTo(this, position, projectTo);
}
}
private class CompactBearing extends AbstractBearing {
@@ -7,6 +7,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.impl.KnotSpeedImpl;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
@@ -585,30 +586,37 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
assert timePointAfterManeuver != null;
Distance result;
long millisecondsOverWhichToAverageSpeed = getTrackedRace().getMillisecondsOverWhichToAverageSpeed();
TimePoint extrapolationBase = timePointBeforeManeuver.minus(millisecondsOverWhichToAverageSpeed/2);
TimePoint extrapolationBase = timePointBeforeManeuver.minus(millisecondsOverWhichToAverageSpeed);
final GPSFixTrack<Competitor, GPSFixMoving> track = getTrackedRace().getTrack(getCompetitor());
Position estimatedPositionAtBase = track.getEstimatedPosition(extrapolationBase, /* extrapolate */ false);
if (estimatedPositionAtBase != null) {
SpeedWithBearing estimatedSpeedAtBase = track.getEstimatedSpeed(extrapolationBase);
if (estimatedSpeedAtBase != null) {
TimePoint extrapolationTarget = timePointAfterManeuver.plus(millisecondsOverWhichToAverageSpeed / 2);
Position extrapolatedPositionWithoutManeuver = estimatedSpeedAtBase.travelTo(estimatedPositionAtBase,
extrapolationBase, extrapolationTarget);
Position estimatedActualPositionAfterManeuver = track.getEstimatedPosition(extrapolationTarget, /* extrapolate */ false);
Bearing bearingAfterManeuver = track.getEstimatedSpeed(extrapolationTarget).getBearing();
if (estimatedActualPositionAfterManeuver != null) {
// find the mean course between inbound and outbound course and project actual and extrapolated positions onto it:
Bearing middle = estimatedSpeedAtBase.getBearing().middle(bearingAfterManeuver);
result = extrapolatedPositionWithoutManeuver.alongTrackDistance(estimatedActualPositionAfterManeuver, middle);
/* TODO remove if fix for bug 1055 works well
result = getWindwardDistance(estimatedActualPositionAfterManeuver, extrapolatedPositionWithoutManeuver,
new MillisecondsTimePoint((timePointBeforeManeuver.asMillis() + timePointAfterManeuver.asMillis())/2));
*/
} else {
result = null;
SpeedWithBearing speedBeforeManeuver = track.getEstimatedSpeed(extrapolationBase);
if (speedBeforeManeuver != null) {
TimePoint extrapolationTarget = timePointAfterManeuver.plus(millisecondsOverWhichToAverageSpeed);
SpeedWithBearing speedAfterManeuver = track.getEstimatedSpeed(extrapolationTarget);
// find the mean course between inbound and outbound course and project actual and extrapolated
// positions onto it:
Bearing middle = speedBeforeManeuver.getBearing().middle(speedAfterManeuver.getBearing());
Position positionAtBase = track.getEstimatedPosition(extrapolationBase, /* extrapolate */false);
Speed projectedSpeedBeforeManeuver = speedBeforeManeuver.projectTo(positionAtBase, middle);
double projectedSpeedBeforeManeuverInKnots = projectedSpeedBeforeManeuver.getKnots();
Speed projectedSpeedAfterManeuver = speedAfterManeuver.projectTo(positionAtBase, middle);
double projectedSpeedAfterManeuverInKnots = projectedSpeedAfterManeuver.getKnots();
track.lockForRead();
try {
Iterator<GPSFixMoving> fixIter = track.getFixesIterator(timePointBeforeManeuver, /* inclusive */true);
GPSFixMoving fix;
TimePoint previousTimePoint = timePointBeforeManeuver;
result = Distance.NULL;
while (fixIter.hasNext() && !(fix = fixIter.next()).getTimePoint().after(timePointAfterManeuver)) {
Speed projectedSpeedAtFix = fix.getSpeed().projectTo(fix.getPosition(), middle);
final double estimatedSpeedWithoutManeuver = projectedSpeedBeforeManeuverInKnots +
(fix.getTimePoint().asMillis()-timePointBeforeManeuver.asMillis()) /
(timePointAfterManeuver.asMillis()-timePointBeforeManeuver.asMillis()) *
(projectedSpeedAfterManeuverInKnots - projectedSpeedBeforeManeuverInKnots);
Speed speedDifference = new KnotSpeedImpl(estimatedSpeedWithoutManeuver - projectedSpeedAtFix.getKnots());
result = result.add(speedDifference.travel(previousTimePoint, fix.getTimePoint()));
}
} else {
result = null;
} finally {
track.unlockAfterRead();
}
} else {
result = null;
@@ -365,6 +365,10 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
public CourseChange getCourseChangeRequiredToReach(SpeedWithBearing targetSpeedWithBearing) {
return null;
}
@Override
public Speed projectTo(Position position, Bearing bearing) {
return null;
}
}
@Override