mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-27 16:06:39 +00:00
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:
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
+18
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -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 {
|
||||
|
||||
+30
-22
@@ -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;
|
||||
|
||||
+4
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user