mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-21 21:25:38 +00:00
bug6064: implemented slicing of tracked legs of competitors in data mining
This commit is contained in:
+1
@@ -25,6 +25,7 @@ SearchTag=Search Tag
|
||||
LeaderboardSailingDomainRetrieverChain=Leaderboards
|
||||
RaceSailingDomainRetrieverChain=Races
|
||||
LegOfCompetitorSailingDomainRetrieverChain=Legs of Competitors
|
||||
LegOfCompetitorSliceSailingDomainRetrieverChain=Slices of Legs of Competitors
|
||||
GPSFixSailingDomainRetrieverChain=GPS Fixes
|
||||
BravoFixSailingDomainRetrieverChain=Bravo Fixes
|
||||
BravoFixTrackSailingDomainRetrieverChain=Bravo Tracks
|
||||
|
||||
+1
@@ -22,6 +22,7 @@ Race=Rennen
|
||||
LeaderboardSailingDomainRetrieverChain=Leaderboards
|
||||
RaceSailingDomainRetrieverChain=Rennen
|
||||
LegOfCompetitorSailingDomainRetrieverChain=Bahnschenkel eines Teilnehmers
|
||||
LegOfCompetitorSliceSailingDomainRetrieverChain=Segmente der Bahnschenkel eines Teilnehmers
|
||||
GPSFixSailingDomainRetrieverChain=GPS-Fixes
|
||||
BravoFixSailingDomainRetrieverChain=Bravo-Fixes
|
||||
BravoFixTrackSailingDomainRetrieverChain=Bravo Messreihen
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ public interface HasTrackedLegSliceOfCompetitorContext extends HasWindOnTrackedL
|
||||
public Distance getDistanceTraveled();
|
||||
|
||||
@Statistic(messageKey="SpeedAverage", resultDecimals=2, ordinal=0)
|
||||
public Double getSpeedAverage();
|
||||
public Double getSpeedAverageInKnots();
|
||||
|
||||
@Statistic(messageKey="RankGainsOrLosses", resultDecimals=2, ordinal=1)
|
||||
public Integer getRankGainsOrLosses();
|
||||
@@ -47,7 +47,7 @@ public interface HasTrackedLegSliceOfCompetitorContext extends HasWindOnTrackedL
|
||||
public Double getRelativeRank();
|
||||
|
||||
@Statistic(messageKey="AbsoluteRank", resultDecimals=0, ordinal=3)
|
||||
public Integer getRankAtFinish();
|
||||
public Integer getRankAtSliceFinish();
|
||||
|
||||
@Statistic(messageKey="AbsoluteRankAfterFirstQuarter", resultDecimals=0, ordinal=4)
|
||||
public Integer getRankAfterFirstQuarter();
|
||||
|
||||
+7
-3
@@ -12,9 +12,13 @@ import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
|
||||
|
||||
/**
|
||||
* Produces "slices" of a {@link HasTrackedLegOfCompetitorContext} object, splitting up the leg in multiple consecutive parts. The parts
|
||||
* are numbered. Slicing currently happens based on wind-based distance traveled in the leg, into ten slices. Future extensions, based on
|
||||
* settings, may offer more sophisticated ways of slicing. See also bug 6064.
|
||||
* Produces "slices" of a {@link HasTrackedLegOfCompetitorContext} object, splitting up the leg in multiple consecutive
|
||||
* parts. The parts are numbered. Slicing currently happens based on the time sailed in the leg, into ten equally long
|
||||
* slices. If the competitor hasn't finished the leg (yet), the duration sailed so far will be divided up into the slices.
|
||||
* This makes this fact type less useful for live situation as the slices "grow" while the competitor continues to sail
|
||||
* in the leg.<p>
|
||||
*
|
||||
* Future extensions, based on settings, may offer more sophisticated ways of slicing. See also bug 6064.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
|
||||
+52
-1
@@ -1,12 +1,17 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasTackTypeSegmentContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.shared.TackTypeSegmentsDataMiningSettings;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.common.Speed;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* Equality is based on the {@link #getTrackedLegOfCompetitor()} only.
|
||||
* Equality is based on the {@link #getTrackedLegOfCompetitor()} only. The {@link #getSliceNumber()} defaults to {@code 1} for this
|
||||
* special case of the entire leg. Start and finish times of this "slice" equal the start/finish times of the competitor in the leg.
|
||||
*/
|
||||
public class TrackedLegOfCompetitorWithContext extends TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegOfCompetitorContext {
|
||||
private static final long serialVersionUID = 5944904146286262768L;
|
||||
@@ -14,4 +19,50 @@ public class TrackedLegOfCompetitorWithContext extends TrackedLegSliceOfCompetit
|
||||
public TrackedLegOfCompetitorWithContext(HasTrackedLegContext trackedLegContext, TrackedLegOfCompetitor trackedLegOfCompetitor, TackTypeSegmentsDataMiningSettings settings) {
|
||||
super(trackedLegContext, trackedLegOfCompetitor, settings, 1);
|
||||
}
|
||||
|
||||
protected TimePoint getSliceStartTime() {
|
||||
return getTrackedLegOfCompetitor().getStartTime();
|
||||
}
|
||||
|
||||
protected TimePoint getSliceFinishTime() {
|
||||
return getEffectiveEndOfLeg(getTrackedLegOfCompetitor().getFinishTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* For the whole leg the distance traveled can be calculated more easily, without subtracting the distance traveled in the leg from
|
||||
* the beginning of the slice.
|
||||
*/
|
||||
@Override
|
||||
public Distance getDistanceTraveled() {
|
||||
return getSliceStartTime() == null ? null : getTrackedLegOfCompetitor().getDistanceTraveled(getSliceFinishTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Can use {@link TrackedLegOfCompetitor#getAverageSpeedOverGround(TimePoint)} which computes efficiently
|
||||
* from the competitor's leg start time point.
|
||||
*/
|
||||
@Override
|
||||
public Double getSpeedAverageInKnots() {
|
||||
final Double result;
|
||||
if (getTrackedRace() == null) {
|
||||
result = null;
|
||||
} else {
|
||||
if (getSliceStartTime() == null) {
|
||||
result = null;
|
||||
} else {
|
||||
final Speed averageSOG = getTrackedLegOfCompetitor().getAverageSpeedOverGround(getSliceFinishTime());
|
||||
result = averageSOG == null ? null : averageSOG.getKnots();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for full leg: only the tack type segment's {@link HasTackTypeSegmentContext#getLegNumber() leg number}
|
||||
* must match this leg's leg number.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isTackTypeSegmentIntersectingWithLegSlice(HasTackTypeSegmentContext tackTypeSegmentContext) {
|
||||
return tackTypeSegmentContext.getLegNumber() == getTrackedLegContext().getLegNumber();
|
||||
}
|
||||
}
|
||||
|
||||
+117
-71
@@ -17,7 +17,6 @@ import com.sap.sailing.datamining.impl.components.TackTypeSegmentRetrievalProces
|
||||
import com.sap.sailing.datamining.shared.TackTypeSegmentsDataMiningSettings;
|
||||
import com.sap.sailing.domain.base.Boat;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
@@ -35,27 +34,32 @@ import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Speed;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
|
||||
|
||||
/**
|
||||
* Equality is based on the {@link #getTrackedLegOfCompetitor()} only.
|
||||
* Equality is based on the {@link #getTrackedLegOfCompetitor()} and the {@link #sliceNumber} only. The current slicing implementation
|
||||
* uses the time sailed in the leg as the basis for slicing. Other slicing criteria, such as windward distance traveled, would be much
|
||||
* harder to implement because we would need to find out iteratively, between which fixes the competitor sailed, say, one tenth of the
|
||||
* windward distance in the leg.
|
||||
*/
|
||||
public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSliceOfCompetitorContext {
|
||||
private static final long serialVersionUID = 5944904146286262768L;
|
||||
|
||||
private static final long DEFAULT_NUMBER_OF_SLICES = 10;
|
||||
|
||||
private final HasTrackedLegContext trackedLegContext;
|
||||
private final TackTypeSegmentsDataMiningSettings settings;
|
||||
|
||||
private final TrackedLegOfCompetitor trackedLegOfCompetitor;
|
||||
private final Competitor competitor;
|
||||
|
||||
private Integer rankAtStart;
|
||||
private boolean isRankAtStartInitialized;
|
||||
private Integer rankAtFinish;
|
||||
private boolean isRankAtFinishInitialized;
|
||||
private Integer rankAtSliceStart;
|
||||
private boolean isRankAtSliceStartInitialized;
|
||||
private Integer rankAtSliceFinish;
|
||||
private boolean isRankAtSliceFinishInitialized;
|
||||
private Wind wind;
|
||||
private int sliceNumber;
|
||||
|
||||
@@ -131,18 +135,60 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
}
|
||||
|
||||
protected <R> R getSomethingForLegTrackingInterval(BiFunction<TimePoint, TimePoint, R> resultSupplier) {
|
||||
final TimePoint startTime = getTrackedLegOfCompetitor().getStartTime();
|
||||
final TimePoint finishTime = getTrackedLegOfCompetitor().getFinishTime();
|
||||
final TimePoint startTime = getSliceStartTime();
|
||||
final TimePoint finishTime = getSliceFinishTime();
|
||||
return getSomethingForInterval(resultSupplier, startTime, finishTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code null} if the competitor hasn't started the leg; otherwise, the start of the slice as split between
|
||||
* the competitors leg start time point and {@link #getEffectiveEndOfLeg(TimePoint)}, into {@link #DEFAULT_NUMBER_OF_SLICES}
|
||||
* parts of equal duration.
|
||||
*/
|
||||
protected TimePoint getSliceStartTime() {
|
||||
return getTimePointAtStartOfSlice(sliceNumber-1); // sliceNumber is one-based, parameter is zero-based, so this means the beginning of the slice
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code null} if the competitor hasn't started the leg; otherwise, the non-{@code null} end of the slice
|
||||
* as split between the competitors leg start time point and {@link #getEffectiveEndOfLeg(TimePoint)}, into
|
||||
* {@link #DEFAULT_NUMBER_OF_SLICES} parts of equal duration.
|
||||
*/
|
||||
protected TimePoint getSliceFinishTime() {
|
||||
return getTimePointAtStartOfSlice(sliceNumber); // sliceNumber is one-based, parameter is zero-based, so this means the end of the slice
|
||||
}
|
||||
|
||||
private TimePoint getTimePointAtStartOfSlice(int zeroBasedSliceNumber) {
|
||||
final TimePoint legStartTime = getTrackedLegOfCompetitor().getStartTime();
|
||||
final TimePoint sliceFinishTime;
|
||||
if (legStartTime == null) {
|
||||
sliceFinishTime = null;
|
||||
} else {
|
||||
final TimePoint finishTime = getTrackedLegOfCompetitor().getFinishTime();
|
||||
final TimePoint effectiveEndOfLeg = getEffectiveEndOfLeg(finishTime);
|
||||
sliceFinishTime = legStartTime.plus(legStartTime.until(effectiveEndOfLeg).divide(DEFAULT_NUMBER_OF_SLICES).times(zeroBasedSliceNumber)); // sliceNumber is one-based, so this means the end of the slice
|
||||
}
|
||||
return sliceFinishTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a non-{@code null} time point; {@code finishTime} if not {@code null}; otherwise the {@link TrackedRace#getEndOfRace() end of the race} if
|
||||
* not {@code null}; otherwise the {@link TrackedRace#getEndOfTracking() end of tracking} if not {@code null}; otherwise the current time.
|
||||
*/
|
||||
protected TimePoint getEffectiveEndOfLeg(final TimePoint finishTime) {
|
||||
return finishTime != null ? finishTime :
|
||||
getTrackedLegContext().getTrackedLeg().getTrackedRace().getEndOfRace() != null ? getTrackedLegContext().getTrackedLeg().getTrackedRace().getEndOfRace() :
|
||||
getTrackedLegContext().getTrackedLeg().getTrackedRace().getEndOfTracking() != null ? getTrackedLegContext().getTrackedLeg().getTrackedRace().getEndOfTracking() :
|
||||
TimePoint.now();
|
||||
}
|
||||
|
||||
protected <R> R getSomethingForInterval(BiFunction<TimePoint, TimePoint, R> resultSupplier,
|
||||
final TimePoint startTime, final TimePoint finishTime) {
|
||||
final R result;
|
||||
if (startTime != null) {
|
||||
final TrackedRace trackedRace = getTrackedLegContext().getTrackedLeg().getTrackedRace();
|
||||
final TimePoint effectiveEndOfInterval = finishTime != null ? finishTime :
|
||||
trackedRace.getEndOfTracking() != null ? trackedRace.getEndOfTracking() : MillisecondsTimePoint.now();
|
||||
trackedRace.getEndOfTracking() != null ? trackedRace.getEndOfTracking() : TimePoint.now();
|
||||
result = resultSupplier.apply(startTime, effectiveEndOfInterval);
|
||||
} else {
|
||||
result = null;
|
||||
@@ -168,52 +214,45 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
|
||||
@Override
|
||||
public Distance getDistanceTraveled() {
|
||||
final Distance result;
|
||||
final TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
|
||||
if (trackedRace != null) {
|
||||
final TimePoint now = TimePoint.now();
|
||||
final TimePoint endTimePoint = trackedRace.getEndOfRace() != null ? trackedRace.getEndOfRace()
|
||||
: trackedRace.getEndOfTracking() != null ? trackedRace.getEndOfTracking() : now;
|
||||
result = getTrackedLegOfCompetitor().getDistanceTraveled(endTimePoint.after(now) ? now : endTimePoint);
|
||||
} else {
|
||||
return getSomethingForLegTrackingInterval((start, end) -> {
|
||||
return start == null ? null :
|
||||
getTrackedLegOfCompetitor().getDistanceTraveled(end).add(getTrackedLegOfCompetitor().getDistanceTraveled(start).scale(-1));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getSpeedAverageInKnots() {
|
||||
final Double result;
|
||||
if (getTrackedRace() == null || getSliceStartTime() == null) {
|
||||
result = null;
|
||||
} else {
|
||||
final TrackedLegOfCompetitor trackedLegOfCompetitor = getTrackedLegOfCompetitor();
|
||||
final Distance distanceTraveledInSlice = trackedLegOfCompetitor.getDistanceTraveled(getSliceFinishTime())
|
||||
.add(trackedLegOfCompetitor.getDistanceTraveled(getSliceStartTime()).scale(-1));
|
||||
final Duration sliceDuration = getSliceStartTime().until(getSliceFinishTime());
|
||||
final Speed averageSOG = distanceTraveledInSlice.inTime(sliceDuration);
|
||||
result = averageSOG == null ? null :averageSOG.getKnots();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getSpeedAverage() {
|
||||
if (getTrackedRace() == null) {
|
||||
return null;
|
||||
} else {
|
||||
final List<Leg> legs = getTrackedRace().getRace().getCourse().getLegs();
|
||||
if (legs.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
final Leg lastLeg = legs.get(legs.size() - 1);
|
||||
TimePoint finished = getTrackedRace().getTrackedLeg(getCompetitor(), lastLeg).getFinishTime();
|
||||
return getTrackedRace().getAverageSpeedOverGround(getCompetitor(), finished).getKnots();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getRankGainsOrLosses() {
|
||||
Integer rankAtStart = getRankAtStart();
|
||||
Integer rankAtFinish = getRankAtFinish();
|
||||
return rankAtStart != null && rankAtFinish != null ? rankAtStart - rankAtFinish : null;
|
||||
Integer rankAtSliceStart = getRankAtSliceStart();
|
||||
Integer rankAtSliceFinish = getRankAtSliceFinish();
|
||||
return rankAtSliceStart != null && rankAtSliceFinish != null ? rankAtSliceStart - rankAtSliceFinish : null;
|
||||
}
|
||||
|
||||
private Integer getRankAtStart() {
|
||||
private Integer getRankAtSliceStart() {
|
||||
final Integer result;
|
||||
if (getTrackedLegContext().getTrackedRaceContext().getTrackedRace() != null) {
|
||||
if (!isRankAtStartInitialized) {
|
||||
if (!isRankAtSliceStartInitialized) {
|
||||
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
|
||||
int rank = trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getStartTime());
|
||||
rankAtStart = rank == 0 ? null : rank;
|
||||
isRankAtStartInitialized = true;
|
||||
int rank = trackedRace.getRank(getCompetitor(), getSliceStartTime());
|
||||
rankAtSliceStart = rank == 0 ? null : rank;
|
||||
isRankAtSliceStartInitialized = true;
|
||||
}
|
||||
result = rankAtStart;
|
||||
result = rankAtSliceStart;
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
@@ -223,18 +262,18 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
/**
|
||||
* If the competitor hasn't started and finished the leg, {@code null} will be returned.
|
||||
*
|
||||
* @param ratioOfLegTimeSpent
|
||||
* the ratio of the time the competitor has spent in the leg overall; 0=just starting the leg; 1=just
|
||||
* finished the leg
|
||||
* @param ratioOfLegSliceTimeSpent
|
||||
* the ratio of the time the competitor has spent in this slice of the leg; 0=just starting the leg; 1=just
|
||||
* finished the slice of the leg
|
||||
*/
|
||||
private Integer getRankAtTimePercent(double ratioOfLegTimeSpent) {
|
||||
private Integer getRankAtTimePercent(double ratioOfLegSliceTimeSpent) {
|
||||
final Integer result;
|
||||
final TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
|
||||
if (trackedRace != null) {
|
||||
final TimePoint startTime = getTrackedLegOfCompetitor().getStartTime();
|
||||
final TimePoint finishTime = getTrackedLegOfCompetitor().getFinishTime();
|
||||
final TimePoint startTime = getSliceStartTime();
|
||||
final TimePoint finishTime = getSliceFinishTime();
|
||||
if (startTime != null && finishTime != null) {
|
||||
final TimePoint timePoint = startTime.plus(startTime.until(finishTime).times(ratioOfLegTimeSpent));
|
||||
final TimePoint timePoint = startTime.plus(startTime.until(finishTime).times(ratioOfLegSliceTimeSpent));
|
||||
result = trackedRace.getRank(getCompetitor(), timePoint);
|
||||
} else {
|
||||
result = null;
|
||||
@@ -258,8 +297,8 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
final Integer result;
|
||||
final TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
|
||||
if (trackedRace != null) {
|
||||
final TimePoint startTime = getTrackedLegOfCompetitor().getStartTime();
|
||||
final TimePoint finishTime = getTrackedLegOfCompetitor().getFinishTime();
|
||||
final TimePoint startTime = getSliceStartTime();
|
||||
final TimePoint finishTime = getSliceFinishTime();
|
||||
if (startTime != null && finishTime != null) {
|
||||
final TimePoint timePoint = startTime.plus(startTime.until(finishTime).times(ratioOfLegTimeSpent));
|
||||
final WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache = new LeaderboardDTOCalculationReuseCache(timePoint) {
|
||||
@@ -295,24 +334,24 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
public Double getRelativeRank() {
|
||||
Leaderboard leaderboard = getTrackedLegContext().getTrackedRaceContext().getLeaderboardContext().getLeaderboard();
|
||||
double competitorCount = Util.size(leaderboard.getCompetitors());
|
||||
Integer rankAtFinish = getRankAtFinish();
|
||||
return rankAtFinish == null ? null : rankAtFinish / competitorCount;
|
||||
Integer rankAtSliceFinish = getRankAtSliceFinish();
|
||||
return rankAtSliceFinish == null ? null : rankAtSliceFinish / competitorCount;
|
||||
}
|
||||
|
||||
public Integer getRankAtFinish() {
|
||||
if (!isRankAtFinishInitialized) {
|
||||
public Integer getRankAtSliceFinish() {
|
||||
if (!isRankAtSliceFinishInitialized) {
|
||||
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
|
||||
int rank = trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getFinishTime());
|
||||
rankAtFinish = rank == 0 ? null : rank;
|
||||
isRankAtFinishInitialized = true;
|
||||
int rank = trackedRace.getRank(getCompetitor(), getSliceFinishTime());
|
||||
rankAtSliceFinish = rank == 0 ? null : rank;
|
||||
isRankAtSliceFinishInitialized = true;
|
||||
}
|
||||
return rankAtFinish;
|
||||
return rankAtSliceFinish;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTimeTakenInSeconds() {
|
||||
TimePoint startTime = getTrackedLegOfCompetitor().getStartTime();
|
||||
TimePoint finishTime = getTrackedLegOfCompetitor().getFinishTime();
|
||||
TimePoint startTime = getSliceStartTime();
|
||||
TimePoint finishTime = getSliceFinishTime();
|
||||
final Long result;
|
||||
if (startTime == null || finishTime == null) {
|
||||
result = null;
|
||||
@@ -336,7 +375,7 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
public Position getPosition() {
|
||||
final TrackedLeg trackedLeg = getTrackedLegContext().getTrackedLeg();
|
||||
final TrackedRace trackedRace = trackedLeg.getTrackedRace();
|
||||
final TimePoint timepoint = getTimePointBetweenLegStartAndLegFinish(trackedRace);
|
||||
final TimePoint timepoint = getTimePointBetweenLegSliceStartAndLegFinish(trackedRace);
|
||||
final Position result;
|
||||
if (timepoint == null) {
|
||||
result = null;
|
||||
@@ -346,12 +385,12 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
return result;
|
||||
}
|
||||
|
||||
private TimePoint getTimePointBetweenLegStartAndLegFinish(final TrackedRace trackedRace) {
|
||||
final TimePoint competitorLegStartTime = getTrackedLegOfCompetitor().getStartTime();
|
||||
final TimePoint competitorLegEndTime = getTrackedLegOfCompetitor().getFinishTime();
|
||||
final TimePoint startTime = competitorLegStartTime != null ? competitorLegStartTime :
|
||||
private TimePoint getTimePointBetweenLegSliceStartAndLegFinish(final TrackedRace trackedRace) {
|
||||
final TimePoint competitorLegSliceStartTime = getSliceStartTime();
|
||||
final TimePoint competitorLegSliceEndTime = getSliceFinishTime();
|
||||
final TimePoint startTime = competitorLegSliceStartTime != null ? competitorLegSliceStartTime :
|
||||
trackedRace.getStartOfRace() != null ? trackedRace.getStartOfRace() : trackedRace.getStartOfTracking();
|
||||
final TimePoint endTime = competitorLegEndTime != null ? competitorLegEndTime :
|
||||
final TimePoint endTime = competitorLegSliceEndTime != null ? competitorLegSliceEndTime :
|
||||
trackedRace.getEndOfRace() != null ? trackedRace.getEndOfRace() : trackedRace.getEndOfTracking();
|
||||
final TimePoint timepoint = endTime == null ? startTime : startTime == null ? null : startTime.plus(startTime.until(endTime).divide(2));
|
||||
return timepoint;
|
||||
@@ -366,7 +405,7 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
public TimePoint getTimePoint() {
|
||||
final TrackedLeg trackedLeg = getTrackedLegContext().getTrackedLeg();
|
||||
final TrackedRace trackedRace = trackedLeg.getTrackedRace();
|
||||
return getTimePointBetweenLegStartAndLegFinish(trackedRace);
|
||||
return getTimePointBetweenLegSliceStartAndLegFinish(trackedRace);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -460,7 +499,7 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
}
|
||||
|
||||
private Double getRankPredictionError(final Supplier<? extends Number> rankPredictor) {
|
||||
final Integer rankAtFinish = getRankAtFinish();
|
||||
final Integer rankAtFinish = getRankAtSliceFinish();
|
||||
final Double result;
|
||||
if (rankAtFinish != null) {
|
||||
final Number predictiveRank = rankPredictor.get();
|
||||
@@ -523,7 +562,7 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
|
||||
@Override
|
||||
public Speed getVelocityMadeGood() {
|
||||
final TimePoint finishTime = getTrackedLegOfCompetitor().getFinishTime();
|
||||
final TimePoint finishTime = getSliceFinishTime();
|
||||
return getTrackedLegOfCompetitor().getAverageVelocityMadeGood(finishTime == null ? TimePoint.now() : finishTime);
|
||||
}
|
||||
|
||||
@@ -552,6 +591,13 @@ public class TrackedLegSliceOfCompetitorWithContext implements HasTrackedLegSlic
|
||||
new RaceOfCompetitorWithContext(getTrackedLegContext().getTrackedRaceContext(), competitor, settings)))
|
||||
.filter(tt->tt.getLegNumber() == getTrackedLegContext().getLegNumber()).collect(resultProcessor);
|
||||
}
|
||||
|
||||
protected boolean isTackTypeSegmentIntersectingWithLegSlice(HasTackTypeSegmentContext tackTypeSegmentContext) {
|
||||
return getSliceStartTime() != null &&
|
||||
tackTypeSegmentContext.getLegNumber() == getTrackedLegContext().getLegNumber()
|
||||
&& TimeRange.create(tackTypeSegmentContext.getStartOfTackTypeSegment(), tackTypeSegmentContext.getEndOfTackTypeSegment())
|
||||
.intersects(TimeRange.create(getSliceStartTime(), getSliceFinishTime()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getRatioDistanceLongVsShortTack() {
|
||||
|
||||
Reference in New Issue
Block a user