mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-22 20:13:52 +00:00
Merge remote-tracking branch 'origin/bug3964'
This commit is contained in:
commit
5b67f0b9b9
20 files changed
+210
-92
No files matched your search
+49
@@ -3,10 +3,13 @@ package com.sap.sailing.domain.common.dto;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
|
||||
/**
|
||||
* Holds a single competitor's scoring details for a single race. It may optionally contain
|
||||
@@ -78,6 +81,8 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
*/
|
||||
public Duration averageSamplingInterval;
|
||||
|
||||
public Double averageRideHeightInMeters;
|
||||
|
||||
/**
|
||||
* The time gap to the competitor leading the race; for one-design races this is the time the competitor is expected
|
||||
* to need to reach the leader's (windward) position (if in the same leg) or the difference between the time at
|
||||
@@ -133,6 +138,44 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
return totalPointsCorrected || (reasonForMaxPoints != null && reasonForMaxPoints != MaxPointsReason.NONE);
|
||||
}
|
||||
|
||||
public Duration getTimeSailedInMillis() {
|
||||
final Duration result;
|
||||
if (legDetails != null) {
|
||||
long timeInMilliseconds = 0;
|
||||
for (LegEntryDTO legDetail : legDetails) {
|
||||
if (legDetail != null) {
|
||||
if (legDetail.distanceTraveledInMeters != null && legDetail.timeInMilliseconds != null) {
|
||||
timeInMilliseconds += legDetail.timeInMilliseconds;
|
||||
} else {
|
||||
timeInMilliseconds = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = new MillisecondsDurationImpl(timeInMilliseconds);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Distance getDistanceTraveledInMeters() {
|
||||
Distance result = null;
|
||||
if (legDetails != null) {
|
||||
for (LegEntryDTO legDetail : legDetails) {
|
||||
if (legDetail != null) {
|
||||
if (legDetail.distanceTraveledInMeters != null) {
|
||||
if (result == null) {
|
||||
result = Distance.NULL;
|
||||
}
|
||||
result = result.add(new MeterDistance(legDetail.distanceTraveledInMeters));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
@@ -174,6 +217,7 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
result = prime * result
|
||||
+ ((speedOverGroundAtStartOfRaceInKnots == null) ? 0 : speedOverGroundAtStartOfRaceInKnots.hashCode());
|
||||
result = prime * result + ((startTack == null) ? 0 : startTack.hashCode());
|
||||
result = prime * result + ((averageRideHeightInMeters == null) ? 0 : averageRideHeightInMeters.hashCode());
|
||||
result = prime * result + ((averageSamplingInterval == null) ? 0 : averageSamplingInterval.hashCode());
|
||||
result = prime * result + ((timeSinceLastPositionFixInSeconds == null) ? 0 : timeSinceLastPositionFixInSeconds.hashCode());
|
||||
result = prime * result + ((netPoints == null) ? 0 : netPoints.hashCode());
|
||||
@@ -282,6 +326,11 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
return false;
|
||||
if (startTack != other.startTack)
|
||||
return false;
|
||||
if (averageRideHeightInMeters == null) {
|
||||
if (other.averageRideHeightInMeters != null)
|
||||
return false;
|
||||
} else if (!averageRideHeightInMeters.equals(other.averageRideHeightInMeters))
|
||||
return false;
|
||||
if (averageSamplingInterval == null) {
|
||||
if (other.averageSamplingInterval != null)
|
||||
return false;
|
||||
|
||||
+25
@@ -4,6 +4,9 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* Holds data about one competitor and all races represented by the owning {@link LeaderboardDTO leaderboard}.
|
||||
*
|
||||
@@ -117,6 +120,28 @@ public class LeaderboardRowDTO implements Serializable {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Distance getDistanceTraveledInMeters(String raceColumnName) {
|
||||
final Distance result;
|
||||
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.getDistanceTraveledInMeters();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Duration getTimeSailed(String raceColumnName) {
|
||||
final Duration result;
|
||||
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.getTimeSailedInMillis();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LeaderboardRowDTO for competitor "+competitor;
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.domain.common.tracking;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
|
||||
/**
|
||||
* Specific {@link SensorFix} for bravo devices (http://www.bravosystems.es/).
|
||||
*
|
||||
@@ -12,5 +14,5 @@ public interface BravoFix extends SensorFix {
|
||||
*
|
||||
* @return the ride height
|
||||
*/
|
||||
double getRideHeight();
|
||||
Distance getRideHeight();
|
||||
}
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
@@ -32,8 +34,8 @@ public class BravoFixImpl implements BravoFix {
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getRideHeight() {
|
||||
return fix.get(BravoSensorDataMetadata.INSTANCE.rideHeightColumn);
|
||||
public Distance getRideHeight() {
|
||||
return new MeterDistance(fix.get(BravoSensorDataMetadata.INSTANCE.rideHeightColumn));
|
||||
}
|
||||
|
||||
}
|
||||
+8
-12
@@ -49,9 +49,11 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
@@ -95,9 +97,9 @@ public class SensorFixStoreAndLoadTest {
|
||||
private static final long FIX_TIMESTAMP2 = 120;
|
||||
private static final long FIX_TIMESTAMP3 = 210;
|
||||
private static final long AFTER_LAST_FIX = FIX_TIMESTAMP3 + 1;
|
||||
private static final double FIX_RIDE_HEIGHT = 1337.0;
|
||||
private static final double FIX_RIDE_HEIGHT2 = 1338.0;
|
||||
private static final double FIX_RIDE_HEIGHT3 = 1336.0;
|
||||
private static final Distance FIX_RIDE_HEIGHT = new MeterDistance(1337.0);
|
||||
private static final Distance FIX_RIDE_HEIGHT2 = new MeterDistance(1338.0);
|
||||
private static final Distance FIX_RIDE_HEIGHT3 = new MeterDistance(1336.0);
|
||||
private static final double FIX_TEST_VALUE = 12.0;
|
||||
protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory();
|
||||
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
|
||||
@@ -384,20 +386,14 @@ public class SensorFixStoreAndLoadTest {
|
||||
public void testBravoFixIsCorrectlyWrapped() throws InterruptedException {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
BravoFixTrack<Competitor> bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
|
||||
assertEquals(FIX_RIDE_HEIGHT,
|
||||
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP)).getRideHeight());
|
||||
|
||||
fixLoaderAndTracker.stop(true);
|
||||
}
|
||||
|
||||
@@ -482,9 +478,9 @@ public class SensorFixStoreAndLoadTest {
|
||||
}
|
||||
|
||||
private void addBravoFixes() {
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP, FIX_RIDE_HEIGHT));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP3, FIX_RIDE_HEIGHT3));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP, FIX_RIDE_HEIGHT.getMeters()));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2.getMeters()));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP3, FIX_RIDE_HEIGHT3.getMeters()));
|
||||
}
|
||||
|
||||
private FixLoaderAndTracker createFixLoaderAndTracker() {
|
||||
|
||||
+5
-3
@@ -541,15 +541,12 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
|
||||
@Override
|
||||
public boolean isControlTrackingFromStartAndFinishTimes() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControlTrackingFromStartAndFinishTimes(
|
||||
boolean controlTrackingFromStartAndFinishTimes) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1130,4 +1127,9 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
public Iterable<RaceLog> getAttachedRaceLogs() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+5
@@ -681,4 +681,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
public Iterable<RaceLog> getAttachedRaceLogs() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -82,8 +82,8 @@ public class BravoFixTrackSerializationTest {
|
||||
assertRideHeight(track, testFixData.timePoint, testFixData.rideHeight);
|
||||
}
|
||||
|
||||
private void assertRideHeight(BravoFixTrack<Competitor> track, TimePoint timePoint, double expected) {
|
||||
assertEquals(expected, track.getRideHeight(timePoint), 0.0);
|
||||
private void assertRideHeight(BravoFixTrack<Competitor> track, TimePoint timePoint, double expectedRideHeightInMeters) {
|
||||
assertEquals(expectedRideHeightInMeters, track.getRideHeight(timePoint).getMeters(), 0.0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
+6
-2
@@ -1437,6 +1437,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
} else {
|
||||
entryDTO.timeSinceLastPositionFixInSeconds = null;
|
||||
}
|
||||
final Distance averageRideHeight = trackedRace.getAverageRideHeight(competitor, timePoint);
|
||||
entryDTO.averageRideHeightInMeters = averageRideHeight == null ? null : averageRideHeight.getMeters();
|
||||
}
|
||||
if (addLegDetails && trackedRace != null) {
|
||||
try {
|
||||
@@ -1721,11 +1723,13 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
Double speedOverGroundInKnots;
|
||||
if (trackedLeg.hasFinishedLeg(timePoint)) {
|
||||
speedOverGroundInKnots = averageSpeedOverGround == null ? null : averageSpeedOverGround.getKnots();
|
||||
result.currentRideHeightInMeters = trackedLeg.getAverageRideHeight(timePoint);
|
||||
final Distance averageRideHeight = trackedLeg.getAverageRideHeight(timePoint);
|
||||
result.currentRideHeightInMeters = averageRideHeight == null ? null : averageRideHeight.getMeters();
|
||||
} else {
|
||||
final SpeedWithBearing speedOverGround = trackedLeg.getSpeedOverGround(timePoint);
|
||||
speedOverGroundInKnots = speedOverGround == null ? null : speedOverGround.getKnots();
|
||||
result.currentRideHeightInMeters = trackedLeg.getRideHeight(timePoint);
|
||||
final Distance rideHeight = trackedLeg.getRideHeight(timePoint);
|
||||
result.currentRideHeightInMeters = rideHeight == null ? null : rideHeight.getMeters();
|
||||
}
|
||||
result.currentSpeedOverGroundInKnots = speedOverGroundInKnots == null ? null : speedOverGroundInKnots;
|
||||
Distance distanceTraveled = trackedLeg.getDistanceTraveled(timePoint);
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.WithID;
|
||||
@@ -22,7 +23,7 @@ public interface BravoFixTrack<ItemType extends WithID & Serializable> extends S
|
||||
* @return the ride height for the given {@link TimePoint} or <code>null</code> if the {@link TimePoint} is not in the range
|
||||
* where we have fixes for.
|
||||
*/
|
||||
Double getRideHeight(TimePoint timePoint);
|
||||
Distance getRideHeight(TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Calculates the average ride height for the given time range.
|
||||
@@ -34,5 +35,5 @@ public interface BravoFixTrack<ItemType extends WithID & Serializable> extends S
|
||||
* @return the average ride height for the given time range or <code>null</code> if there are no fixes in the given
|
||||
* time range.
|
||||
*/
|
||||
Double getAverageRideHeight(TimePoint from, TimePoint to);
|
||||
Distance getAverageRideHeight(TimePoint from, TimePoint to);
|
||||
}
|
||||
+2
-2
@@ -97,7 +97,7 @@ public interface TrackedLegOfCompetitor extends Serializable {
|
||||
* <code>timePoint</code>. If the competitor already completed the leg at <code>timePoint</code> and the respective
|
||||
* mark passing event was already received, the average ride height for the entire leg (and no further) is computed.
|
||||
*/
|
||||
Double getAverageRideHeight(TimePoint timePoint);
|
||||
Distance getAverageRideHeight(TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* @return <code>null</code> if the competitor hasn't started this leg yet, otherwise the fix where the maximum speed was
|
||||
@@ -237,7 +237,7 @@ public interface TrackedLegOfCompetitor extends Serializable {
|
||||
* <code>timePoint</code>, returns the current ride height for this time point. If the competitor has already
|
||||
* finished the leg, the ride height at the time the competitor finished the leg is returned.
|
||||
*/
|
||||
Double getRideHeight(TimePoint at);
|
||||
Distance getRideHeight(TimePoint at);
|
||||
|
||||
/**
|
||||
* Computes the distance along the wind track to the wind-projected position of the race's overall leader. If leader
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.SensorFix;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.ranking.RankingMetric;
|
||||
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
|
||||
import com.sap.sailing.domain.tracking.impl.NonCachingMarkPositionAtTimePointCache;
|
||||
@@ -685,6 +686,8 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
|
||||
Distance getAverageSignedCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly,
|
||||
boolean waitForLatestAnalysis) throws NoWindException;
|
||||
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint);
|
||||
|
||||
WindStore getWindStore();
|
||||
|
||||
Competitor getOverallLeader(TimePoint timePoint);
|
||||
|
||||
+15
-10
@@ -1,10 +1,8 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.Spliterator;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
@@ -34,7 +32,7 @@ public class BravoFixTrackImpl<ItemType extends WithID & Serializable> extends S
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRideHeight(TimePoint timePoint) {
|
||||
public Distance getRideHeight(TimePoint timePoint) {
|
||||
BravoFix fixAfter = getFirstFixAtOrAfter(timePoint);
|
||||
if (fixAfter != null && fixAfter.getTimePoint().compareTo(timePoint) == 0) {
|
||||
// exact match of timepoint -> no interpolation necessary
|
||||
@@ -54,17 +52,24 @@ public class BravoFixTrackImpl<ItemType extends WithID & Serializable> extends S
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getAverageRideHeight(TimePoint from, TimePoint to) {
|
||||
public Distance getAverageRideHeight(TimePoint from, TimePoint to) {
|
||||
final Distance result;
|
||||
lockForRead();
|
||||
try {
|
||||
Spliterator<BravoFix> fixes = getFixes(from, true, to, true).spliterator();
|
||||
OptionalDouble average = StreamSupport.stream(fixes, false).mapToDouble(BravoFix::getRideHeight).average();
|
||||
if (average.isPresent()) {
|
||||
return average.getAsDouble();
|
||||
Distance sum = Distance.NULL;
|
||||
int count = 0;
|
||||
for (final BravoFix fix : getFixes(from, true, to, true)) {
|
||||
sum = sum.add(fix.getRideHeight());
|
||||
count++;
|
||||
}
|
||||
if (count > 0) {
|
||||
result = sum.scale(1./count);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
} finally {
|
||||
unlockAfterRead();
|
||||
}
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -174,8 +174,7 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
}
|
||||
if (timePointToUse != null) {
|
||||
Distance d = getDistanceTraveled(timePointToUse);
|
||||
long millis = timePointToUse.asMillis() - legStart.getTimePoint().asMillis();
|
||||
result = d.inTime(millis);
|
||||
result = d.inTime(legStart.getTimePoint().until(timePointToUse));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
@@ -184,7 +183,7 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getAverageRideHeight(TimePoint timePoint) {
|
||||
public Distance getAverageRideHeight(TimePoint timePoint) {
|
||||
MarkPassing legStart = getMarkPassingForLegStart();
|
||||
if (legStart != null) {
|
||||
BravoFixTrack<Competitor> track = getTrackedRace()
|
||||
@@ -677,15 +676,17 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRideHeight(TimePoint at) {
|
||||
public Distance getRideHeight(TimePoint at) {
|
||||
final Distance result;
|
||||
if (hasStartedLeg(at)) {
|
||||
TimePoint timePoint =hasFinishedLeg(at) ? getMarkPassingForLegEnd().getTimePoint() : at;
|
||||
BravoFixTrack<Competitor> track = getTrackedRace()
|
||||
.<BravoFix, BravoFixTrack<Competitor>> getSensorTrack(competitor, BravoFixTrack.TRACK_NAME);
|
||||
return track == null ? null : track.getRideHeight(timePoint);
|
||||
result = track == null ? null : track.getRideHeight(timePoint);
|
||||
} else {
|
||||
return null;
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+16
@@ -1538,6 +1538,22 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
final Distance result;
|
||||
BravoFixTrack<Competitor> track = getSensorTrack(competitor, BravoFixTrack.TRACK_NAME);
|
||||
final Leg firstLeg;
|
||||
final TrackedLegOfCompetitor firstTrackedLeg;
|
||||
if (track != null && (firstLeg = getRace().getCourse().getFirstLeg()) != null && (firstTrackedLeg = getTrackedLeg(competitor, firstLeg)).hasStartedLeg(timePoint)) {
|
||||
final TrackedLegOfCompetitor lastTrackedLeg = getTrackedLegFinishingAt(getRace().getCourse().getLastWaypoint()).getTrackedLeg(competitor);
|
||||
TimePoint endTimePoint = lastTrackedLeg.hasFinishedLeg(timePoint) ? lastTrackedLeg.getFinishTime() : timePoint;
|
||||
result = track.getAverageRideHeight(firstTrackedLeg.getStartTime(), endTimePoint);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLegOfCompetitor getCurrentLeg(Competitor competitor, TimePoint timePoint) {
|
||||
// If the mark passing that starts a leg happened exactly at timePoint, the MarkPassingByTimeComparator won't consider
|
||||
|
||||
+5
@@ -860,4 +860,9 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
public Iterable<RaceLog> getAttachedRaceLogs() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+41
-45
@@ -58,6 +58,7 @@ import com.google.gwt.view.client.MultiSelectionModel;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.InvertibleComparator;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
@@ -97,6 +98,7 @@ import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.DetailTypeColumn.LegDetailField;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings.RaceColumnSelectionStrategies;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.filter.BinaryOperator;
|
||||
@@ -972,10 +974,10 @@ public class LeaderboardPanel extends SimplePanel implements Component<Leaderboa
|
||||
new FormattedDoubleDetailTypeColumn(DetailType.RACE_GAP_TO_LEADER_IN_SECONDS, new RaceGapToLeaderInSeconds(),
|
||||
LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this));
|
||||
result.put(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS,
|
||||
new FormattedDoubleDetailTypeColumn(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, new CurrentSpeedOverGroundInKnots(),
|
||||
new FormattedDoubleDetailTypeColumn(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, new RaceCurrentSpeedOverGroundInKnots(),
|
||||
LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this));
|
||||
result.put(DetailType.RACE_CURRENT_RIDE_HEIGHT_IN_METERS, new RideHeightColumn(DetailType.RACE_CURRENT_RIDE_HEIGHT_IN_METERS,
|
||||
new CurrentRideHeightInMeters(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this));
|
||||
new RaceCurrentRideHeightInMeters(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this));
|
||||
result.put(DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS,
|
||||
new FormattedDoubleDetailTypeColumn(DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS, new RaceDistanceToCompetitorFarthestAheadInMeters(),
|
||||
LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE, LeaderboardPanel.this));
|
||||
@@ -1098,26 +1100,13 @@ public class LeaderboardPanel extends SimplePanel implements Component<Leaderboa
|
||||
private class RaceAverageSpeedInKnots implements LegDetailField<Double> {
|
||||
@Override
|
||||
public Double get(LeaderboardRowDTO row) {
|
||||
Double result = null;
|
||||
LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName());
|
||||
if (fieldsForRace != null && fieldsForRace.legDetails != null) {
|
||||
double distanceTraveledInMeters = 0;
|
||||
long timeInMilliseconds = 0;
|
||||
for (LegEntryDTO legDetail : fieldsForRace.legDetails) {
|
||||
if (legDetail != null) {
|
||||
if (legDetail.distanceTraveledInMeters != null && legDetail.timeInMilliseconds != null) {
|
||||
distanceTraveledInMeters += legDetail.distanceTraveledInMeters;
|
||||
timeInMilliseconds += legDetail.timeInMilliseconds;
|
||||
} else {
|
||||
distanceTraveledInMeters = 0;
|
||||
timeInMilliseconds = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (timeInMilliseconds != 0) {
|
||||
result = distanceTraveledInMeters / (double) timeInMilliseconds * 1000 * 3600 / 1852;
|
||||
}
|
||||
final Distance distanceTraveledInMeters = row.getDistanceTraveledInMeters(getRaceColumnName());
|
||||
final Duration time = row.getTimeSailed(getRaceColumnName());
|
||||
final Double result;
|
||||
if (distanceTraveledInMeters != null && time != null) {
|
||||
result = distanceTraveledInMeters.inTime(time).getKnots();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1299,21 +1288,7 @@ public class LeaderboardPanel extends SimplePanel implements Component<Leaderboa
|
||||
private class RaceDistanceTraveledInMeters implements LegDetailField<Double> {
|
||||
@Override
|
||||
public Double get(LeaderboardRowDTO row) {
|
||||
Double result = null;
|
||||
LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName());
|
||||
if (fieldsForRace != null && fieldsForRace.legDetails != null) {
|
||||
for (LegEntryDTO legDetail : fieldsForRace.legDetails) {
|
||||
if (legDetail != null) {
|
||||
if (legDetail.distanceTraveledInMeters != null) {
|
||||
if (result == null) {
|
||||
result = 0.0;
|
||||
}
|
||||
result += legDetail.distanceTraveledInMeters;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return row.getDistanceTraveledInMeters(getRaceColumnName()).getMeters();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1446,27 +1421,48 @@ public class LeaderboardPanel extends SimplePanel implements Component<Leaderboa
|
||||
lastLegDetail = fieldsForRace.legDetails.get(--lastLegIndex);
|
||||
}
|
||||
if (lastLegDetail != null) {
|
||||
result = get(lastLegDetail);
|
||||
if (lastLegDetail.finished) {
|
||||
result = getAfterLastLegFinished(row);
|
||||
} else {
|
||||
result = getBeforeLastLegFinished(lastLegDetail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract T get(LegEntryDTO lastLegDetail);
|
||||
protected abstract T getBeforeLastLegFinished(LegEntryDTO currentLegDetail);
|
||||
|
||||
protected abstract T getAfterLastLegFinished(LeaderboardRowDTO row);
|
||||
}
|
||||
|
||||
private class CurrentSpeedOverGroundInKnots extends AbstractLastLegDetailField<Double> {
|
||||
private class RaceCurrentSpeedOverGroundInKnots extends AbstractLastLegDetailField<Double> {
|
||||
@Override
|
||||
protected Double get(LegEntryDTO lastLegDetail) {
|
||||
return lastLegDetail.currentSpeedOverGroundInKnots;
|
||||
protected Double getBeforeLastLegFinished(LegEntryDTO currentLegDetail) {
|
||||
return currentLegDetail.currentSpeedOverGroundInKnots;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Double getAfterLastLegFinished(LeaderboardRowDTO row) {
|
||||
return new RaceAverageSpeedInKnots().get(row);
|
||||
}
|
||||
}
|
||||
|
||||
private class CurrentRideHeightInMeters extends AbstractLastLegDetailField<Double> {
|
||||
private class RaceCurrentRideHeightInMeters extends AbstractLastLegDetailField<Double> {
|
||||
@Override
|
||||
protected Double get(LegEntryDTO lastLegDetail) {
|
||||
return lastLegDetail.currentRideHeightInMeters;
|
||||
protected Double getBeforeLastLegFinished(LegEntryDTO currentLegDetail) {
|
||||
return currentLegDetail.currentRideHeightInMeters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Double getAfterLastLegFinished(LeaderboardRowDTO row) {
|
||||
Double result = null;
|
||||
LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName());
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.averageRideHeightInMeters;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -2941,7 +2941,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
final BravoFixTrack<Competitor> bravoFixTrack = trackedRace
|
||||
.<BravoFix, BravoFixTrack<Competitor>> getSensorTrack(competitor, BravoFixTrack.TRACK_NAME);
|
||||
if (bravoFixTrack != null) {
|
||||
result = bravoFixTrack.getRideHeight(timePoint);
|
||||
final Distance rideHeight = bravoFixTrack.getRideHeight(timePoint);
|
||||
result = rideHeight == null ? null : rideHeight.getMeters();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
+4
-4
@@ -19,12 +19,12 @@ public class BravoDataImportTest {
|
||||
|
||||
private final DoubleVectorFixImporter bravoDataImporter = new BravoDataImporterImpl();
|
||||
private int callbackCallCount = 0;
|
||||
private double sumRideHeight = 0.0;
|
||||
private double sumRideHeightInMeters = 0.0;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.callbackCallCount = 0;
|
||||
this.sumRideHeight = 0.0;
|
||||
this.sumRideHeightInMeters = 0.0;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -51,12 +51,12 @@ public class BravoDataImportTest {
|
||||
bravoDataImporter.importFixes(importData.getInputStream(), (fixes, device) -> {
|
||||
for (DoubleVectorFix fix : fixes) {
|
||||
callbackCallCount++;
|
||||
sumRideHeight += new BravoFixImpl(fix).getRideHeight();
|
||||
sumRideHeightInMeters += new BravoFixImpl(fix).getRideHeight().getMeters();
|
||||
}
|
||||
}, "filename", "source");
|
||||
Assert.assertEquals(importData.expectedFixesCount, callbackCallCount);
|
||||
Assert.assertEquals(importData.expectedAverageRideHeight,
|
||||
callbackCallCount == 0 ? sumRideHeight : sumRideHeight / callbackCallCount, 0.00001);
|
||||
callbackCallCount == 0 ? sumRideHeightInMeters : sumRideHeightInMeters / callbackCallCount, 0.00001);
|
||||
}
|
||||
|
||||
private enum ImportData {
|
||||
|
||||
+5
@@ -656,4 +656,9 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
|
||||
public Iterable<RaceLog> getAttachedRaceLogs() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user