Merge remote-tracking branch 'origin/bug3964'

This commit is contained in:
Axel Uhl committed 2016-10-23 01:38:21 +02:00
commit 5b67f0b9b9
20 files changed
+210 -92

No files matched your search

@@ -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;
@@ -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;
@@ -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();
}
@@ -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));
}
}
@@ -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() {
@@ -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;
}
}
@@ -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;
}
}
@@ -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")
@@ -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);
}
@@ -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);
@@ -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;
}
}
@@ -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
@@ -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
@@ -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;
}
}
@@ -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;
}
}
}
@@ -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:
@@ -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 {
@@ -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;
}
}