mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-04 03:13:49 +00:00
Merge branch 'bug1952'
This commit is contained in:
commit
3991cf37e2
5 files changed
+73
-17
No files matched your search
@@ -20,7 +20,10 @@ public interface Position extends Serializable {
|
||||
Distance getDistance(Position p);
|
||||
|
||||
/**
|
||||
* The bearing from this position towards <code>p</code> on a great circle
|
||||
* The bearing from this position towards <code>p</code> on a great circle.
|
||||
*
|
||||
* @return {@code null} if {@code p} is {@code null}, otherwise the bearing from {@code this} {@link Position} to
|
||||
* {@code p} along a great circle
|
||||
*/
|
||||
Bearing getBearingGreatCircle(Position p);
|
||||
|
||||
|
||||
+39
-3
@@ -3,19 +3,22 @@ package com.sap.sailing.domain.test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.NauticalSide;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
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;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.LineDetails;
|
||||
@@ -25,12 +28,14 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
public class LineAnalysisTest extends TrackBasedTest {
|
||||
private TimePoint now;
|
||||
private DynamicTrackedRace trackedRace;
|
||||
private Competitor competitor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final List<Competitor> emptyCompetitorList = Collections.emptyList();
|
||||
competitor = createCompetitor("Test");
|
||||
final Iterable<Competitor> competitorListWithOneCompetitor = Collections.singletonList(competitor);
|
||||
now = MillisecondsTimePoint.now();
|
||||
trackedRace = createTestTrackedRace("Test Regatta", "Test Race", "505", emptyCompetitorList, now, /* useMarkPassingCalculator */ false);
|
||||
trackedRace = createTestTrackedRace("Test Regatta", "Test Race", "505", competitorListWithOneCompetitor, now, /* useMarkPassingCalculator */ false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -56,6 +61,37 @@ public class LineAnalysisTest extends TrackBasedTest {
|
||||
assertEquals(advantage.getMeters(), finishLine.getAdvantage().getMeters(), 0.1);
|
||||
assertEquals(NauticalSide.PORT, finishLine.getAdvantageousSideWhileApproachingLine());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistanceToLineWithOrthogonalProjectionOnLine() {
|
||||
Mark left = getMark("Left lee gate buoy");
|
||||
Mark right = getMark("Right lee gate buoy");
|
||||
final Position leftPos = trackedRace.getOrCreateTrack(left).getEstimatedPosition(now, /* extrapolate */ false);
|
||||
final Position rightPos = trackedRace.getOrCreateTrack(right).getEstimatedPosition(now, /* extrapolate */ false);
|
||||
final Bearing lineBearingFromLeftToRight = leftPos.getBearingGreatCircle(rightPos);
|
||||
final Bearing awayFromCourseSideOrthogonalToLine = lineBearingFromLeftToRight.add(new DegreeBearingImpl(90));
|
||||
final Position lineMiddle = leftPos.translateGreatCircle(lineBearingFromLeftToRight, leftPos.getDistance(rightPos).scale(0.5));
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistanceToLineWithOrthogonalProjectionOutsideLine() {
|
||||
Mark left = getMark("Left lee gate buoy");
|
||||
Mark right = getMark("Right lee gate buoy");
|
||||
final Position leftPos = trackedRace.getOrCreateTrack(left).getEstimatedPosition(now, /* extrapolate */ false);
|
||||
final Position rightPos = trackedRace.getOrCreateTrack(right).getEstimatedPosition(now, /* extrapolate */ false);
|
||||
final Bearing lineBearingFromLeftToRight = leftPos.getBearingGreatCircle(rightPos);
|
||||
final Bearing awayFromCourseSideOrthogonalToLine = lineBearingFromLeftToRight.add(new DegreeBearingImpl(90));
|
||||
final Position outsideOfLine = rightPos.translateGreatCircle(lineBearingFromLeftToRight, new MeterDistance(30)); // 30m right of start boat
|
||||
final Distance distanceBehindLine = new MeterDistance(10);
|
||||
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);
|
||||
}
|
||||
|
||||
private Mark getMark(String name) {
|
||||
for (Mark mark : trackedRace.getMarks()) {
|
||||
|
||||
+26
-9
@@ -3455,29 +3455,46 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
if (startWaypoint == null) {
|
||||
result = null;
|
||||
} else {
|
||||
Position competitorPosition = getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolate */false);
|
||||
Position competitorPosition = getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolate */ false);
|
||||
if (competitorPosition == null) {
|
||||
result = null;
|
||||
} else {
|
||||
Iterable<Mark> marks = startWaypoint.getControlPoint().getMarks();
|
||||
Iterator<Mark> marksIterator = marks.iterator();
|
||||
Mark first = marksIterator.next();
|
||||
Position firstPosition = getOrCreateTrack(first).getEstimatedPosition(timePoint, /* extrapolate */false);
|
||||
Position firstPosition = getOrCreateTrack(first).getEstimatedPosition(timePoint, /* extrapolate */ false);
|
||||
if (firstPosition == null) {
|
||||
result = null;
|
||||
} else {
|
||||
if (marksIterator.hasNext()) {
|
||||
// it's a line / gate
|
||||
Mark second = marksIterator.next();
|
||||
Position secondPosition = getOrCreateTrack(second).getEstimatedPosition(timePoint, /* extrapolate */
|
||||
false);
|
||||
final Bearing bearingGreatCircle = firstPosition.getBearingGreatCircle(secondPosition);
|
||||
if (bearingGreatCircle == null) {
|
||||
Position secondPosition = getOrCreateTrack(second).getEstimatedPosition(timePoint, /* extrapolate */ false);
|
||||
if (secondPosition == null) {
|
||||
result = null;
|
||||
} else {
|
||||
Position competitorProjectedOntoStartLine = competitorPosition.projectToLineThrough(
|
||||
firstPosition, bearingGreatCircle);
|
||||
result = competitorPosition.getDistance(competitorProjectedOntoStartLine);
|
||||
final Bearing lineBearingGreatCircleFromFirstToSecond = firstPosition.getBearingGreatCircle(secondPosition);
|
||||
// if the competitor is outside of the line when projected orthogonally, compute the distance to
|
||||
// the nearest of the line's marks (see also bug 1952):
|
||||
final Bearing bearingFromFirstToCompetitor = firstPosition.getBearingGreatCircle(competitorPosition);
|
||||
final Bearing angleBetweenFromFirstToCompetitorAndLine = lineBearingGreatCircleFromFirstToSecond.getDifferenceTo(bearingFromFirstToCompetitor);
|
||||
if (angleBetweenFromFirstToCompetitorAndLine.getDegrees() < -90 || angleBetweenFromFirstToCompetitorAndLine.getDegrees() > 90) {
|
||||
// competitor's orthogonal projection onto the line's extension is outside of the line's ends on the side
|
||||
// of the first mark; use distance between competitor and first mark:
|
||||
result = competitorPosition.getDistance(firstPosition);
|
||||
} else {
|
||||
final Bearing bearingFromSecondToCompetitor = secondPosition.getBearingGreatCircle(competitorPosition);
|
||||
final Bearing angleBetweenFromSecondToCompetitorAndReversedLine = lineBearingGreatCircleFromFirstToSecond.reverse().getDifferenceTo(bearingFromSecondToCompetitor);
|
||||
if (angleBetweenFromSecondToCompetitorAndReversedLine.getDegrees() < -90 || angleBetweenFromSecondToCompetitorAndReversedLine.getDegrees() > 90) {
|
||||
// competitor's orthogonal projection onto the line's extension is outside of the line's ends on the side
|
||||
// of the first mark; use distance between competitor and first mark:
|
||||
result = competitorPosition.getDistance(secondPosition);
|
||||
} else {
|
||||
Position competitorProjectedOntoStartLine = competitorPosition.projectToLineThrough(
|
||||
firstPosition, lineBearingGreatCircleFromFirstToSecond);
|
||||
result = competitorPosition.getDistance(competitorProjectedOntoStartLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = competitorPosition.getDistance(firstPosition);
|
||||
|
||||
+2
-2
@@ -651,8 +651,8 @@ distanceToLineFiveSecondsBeforeStart=Distance to line 5s before start
|
||||
speedOverGroundAtRaceStart=SOG at Start
|
||||
speedOverGroundFiveSecondsBeforeStart=SOG 5s before start
|
||||
speedOverGroundWhenPassingStart=SOG when Starting
|
||||
distanceToLineAtRaceStartTooltip=Distance to start line at race start time
|
||||
distanceToLineFiveSecondsBeforeStartTooltip=Distance to start line five seconds before the start
|
||||
distanceToLineAtRaceStartTooltip=Distance to start line at race start time; distance to nearest line end in case the competitor projects beyond the line's ends
|
||||
distanceToLineFiveSecondsBeforeStartTooltip=Distance to start line five seconds before the start; distance to nearest line end in case the competitor projects beyond the line's ends
|
||||
speedOverGroundAtRaceStartTooltip=Speed over ground at race start time
|
||||
speedOverGroundFiveSecondsBeforeStartTooltip=Speed over ground five seconds before the start
|
||||
speedOverGroundWhenPassingStartTooltip=Speed over ground when the competitor passed the start
|
||||
|
||||
+2
-2
@@ -642,9 +642,9 @@ operatorEndsWith=Endet mit
|
||||
nationality=Nationalität
|
||||
numberMustBePositive=Die Zahl muß größer als Null sein.
|
||||
distanceToLineAtRaceStart=Abstand zur Linie bei Start
|
||||
distanceToLineAtRaceStartTooltip=Abstand zur Linie zur Startzeit des Rennens
|
||||
distanceToLineAtRaceStartTooltip=Abstand zur Linie zur Startzeit des Rennens; Abstand zum näheren Ende der Linie falls Projektion des Teilnehmers außerhalb der Linie liegt
|
||||
distanceToLineFiveSecondsBeforeStart=Abstand zur Linie 5s vor Start
|
||||
distanceToLineFiveSecondsBeforeStartTooltip=Abstand zur Linie fünf Sekunden vor dem Start
|
||||
distanceToLineFiveSecondsBeforeStartTooltip=Abstand zur Linie fünf Sekunden vor dem Start; Abstand zum näheren Ende der Linie falls Projektion des Teilnehmers außerhalb der Linie liegt
|
||||
speedOverGroundAtRaceStart=FüG bei Rennstart
|
||||
speedOverGroundAtRaceStartTooltip=Fahrt über Grund zur Startzeit des Rennens
|
||||
speedOverGroundFiveSecondsBeforeStart=FüG 5s vor Start
|
||||
|
||||
Reference in new issue
Block a user