mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-23 04:23:54 +00:00
Merge branch 'master' into bug2570_2
This commit is contained in:
commit
95f295d79a
20 files changed
+612
-36
No files matched your search
+86
@@ -0,0 +1,86 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries;
|
||||
import com.sap.sse.datamining.impl.data.ClusterWithSingleBoundary;
|
||||
import com.sap.sse.datamining.impl.data.ComparableClusterBoundary;
|
||||
import com.sap.sse.datamining.impl.data.ComparisonStrategy;
|
||||
|
||||
// TODO Move to sse bundle, after 49er analysis
|
||||
public class TestLinearDoubleClusterGroup {
|
||||
|
||||
private LinearDoubleClusterGroup hardPercentageClusterGroup;
|
||||
private LinearDoubleClusterGroup softLinearClusterGroup;
|
||||
|
||||
@Before
|
||||
public void initialize() {
|
||||
hardPercentageClusterGroup = new LinearDoubleClusterGroup(0.0, 1.0, 0.1, true);
|
||||
softLinearClusterGroup = new LinearDoubleClusterGroup(0, 100, 10, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetClusterForValueOutOfBounds() {
|
||||
Cluster<Double> cluster = hardPercentageClusterGroup.getClusterFor(-0.01);
|
||||
assertThat(cluster, nullValue());
|
||||
|
||||
cluster = hardPercentageClusterGroup.getClusterFor(1.01);
|
||||
assertThat(cluster, nullValue());
|
||||
|
||||
cluster = softLinearClusterGroup.getClusterFor(-0.1);
|
||||
Cluster<Double> expectedCluster = createCluster(softLinearClusterGroup.getStepSize(), ComparisonStrategy.LOWER_THAN);
|
||||
assertThat(cluster, is(expectedCluster));
|
||||
|
||||
cluster = softLinearClusterGroup.getClusterFor(100.1);
|
||||
expectedCluster = createCluster(softLinearClusterGroup.getUpperGroupBound() - softLinearClusterGroup.getStepSize(), ComparisonStrategy.GREATER_EQUALS_THAN);
|
||||
assertThat(cluster, is(expectedCluster));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetClusterForBoundaryValues() {
|
||||
Cluster<Double> cluster = hardPercentageClusterGroup.getClusterFor(0.0);
|
||||
Cluster<Double> expectedCluster = createCluster(hardPercentageClusterGroup.getLowerGroupBound(), ComparisonStrategy.GREATER_EQUALS_THAN,
|
||||
hardPercentageClusterGroup.getLowerGroupBound() + hardPercentageClusterGroup.getStepSize(), ComparisonStrategy.LOWER_THAN);
|
||||
assertThat(cluster, is(expectedCluster));
|
||||
|
||||
cluster = hardPercentageClusterGroup.getClusterFor(1.0);
|
||||
expectedCluster = createCluster(hardPercentageClusterGroup.getUpperGroupBound() - hardPercentageClusterGroup.getStepSize(), ComparisonStrategy.GREATER_EQUALS_THAN,
|
||||
hardPercentageClusterGroup.getUpperGroupBound(), ComparisonStrategy.LOWER_EQUALS_THAN);
|
||||
assertThat(cluster, is(expectedCluster));
|
||||
|
||||
cluster = softLinearClusterGroup.getClusterFor(0.0);
|
||||
expectedCluster = createCluster(softLinearClusterGroup.getStepSize(), ComparisonStrategy.LOWER_THAN);
|
||||
assertThat(cluster, is(expectedCluster));
|
||||
|
||||
cluster = softLinearClusterGroup.getClusterFor(100.0);
|
||||
expectedCluster = createCluster(softLinearClusterGroup.getUpperGroupBound() - softLinearClusterGroup.getStepSize(), ComparisonStrategy.GREATER_EQUALS_THAN);
|
||||
assertThat(cluster, is(expectedCluster));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetClusterFor() {
|
||||
LinearDoubleClusterGroup clusterGroup = softLinearClusterGroup;
|
||||
double value = (clusterGroup.getUpperGroupBound() + clusterGroup.getStepSize()) / 2;
|
||||
Cluster<Double> cluster = clusterGroup.getClusterFor(value);
|
||||
Cluster<Double> expectedCluster = createCluster(clusterGroup.getUpperGroupBound() / 2, ComparisonStrategy.GREATER_EQUALS_THAN,
|
||||
(clusterGroup.getUpperGroupBound() / 2) + clusterGroup.getStepSize(), ComparisonStrategy.LOWER_THAN);
|
||||
assertThat(cluster, is(expectedCluster));
|
||||
}
|
||||
|
||||
private Cluster<Double> createCluster(double lowerBoundValue, ComparisonStrategy lowerComparisonStrategy, double upperBoundValue, ComparisonStrategy upperComparisonStrategy) {
|
||||
ComparableClusterBoundary<Double> lowerBound = new ComparableClusterBoundary<>(lowerBoundValue, lowerComparisonStrategy);
|
||||
ComparableClusterBoundary<Double> upperBound = new ComparableClusterBoundary<>(upperBoundValue, upperComparisonStrategy);
|
||||
return new ClusterWithLowerAndUpperBoundaries<>(lowerBound, upperBound);
|
||||
}
|
||||
|
||||
private Cluster<Double> createCluster(double boundValue, ComparisonStrategy comparisonStrategy) {
|
||||
return new ClusterWithSingleBoundary<>(new ComparableClusterBoundary<>(boundValue, comparisonStrategy));
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
|
||||
public class TestPercentageClusterFormatter {
|
||||
|
||||
private ClusterGroup<Double> percentageClusterGroup;
|
||||
private PercentageClusterFormatter formatter;
|
||||
|
||||
@Before
|
||||
public void initialize() {
|
||||
percentageClusterGroup = new LinearDoubleClusterGroup(0.0, 1.0, 0.1, true);
|
||||
formatter = new PercentageClusterFormatter();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormat() {
|
||||
Cluster<Double> cluster = percentageClusterGroup.getClusterFor(0.05);
|
||||
String formattedCluster = formatter.format(cluster);
|
||||
assertThat(formattedCluster, is("[0% - 10%["));
|
||||
}
|
||||
|
||||
}
|
||||
+6
-1
@@ -47,6 +47,8 @@ Bft10=Storm
|
||||
Bft11=Violent storm
|
||||
Bft12=Hurricane
|
||||
RelativeScore=Relative Score (0 best; 1 worst)
|
||||
RelativeScoreInPercent=Relative Score in %
|
||||
RelativeScoreInRaceInPercent=Relative Score in Race in %
|
||||
AbsoluteRank=Absolute Rank
|
||||
WindSpeedInBeaufort=Wind Speed in Bft
|
||||
DistanceAtStart=Distance to Start at Start
|
||||
@@ -76,4 +78,7 @@ PassingSide=Passing Side
|
||||
TackAtStart=Tack at Start
|
||||
SpeedTenSecondsAfterStart=Speed 10s After Start
|
||||
RankThirtySecondsAfterStart=Rank 30s After Start
|
||||
StartAdvantage=Start Advantage
|
||||
WindwardDistanceToAdvantageousEndOfLine=Windward Distance to Advantageous End of Line
|
||||
RankAfterHalfOfTheFirstLeg=Rank after the half of the first leg
|
||||
AdvantageousEndOfLine=Advantageous End of Line
|
||||
TimeSpentInSeconds=Time Spent in Seconds
|
||||
+6
-1
@@ -47,6 +47,8 @@ Bft10=schwerer Sturm
|
||||
Bft11=orkanartiger Sturm
|
||||
Bft12=Orkan
|
||||
RelativeScore=Relative Wertung (0 am besten; 1 am schlechtesten)
|
||||
RelativeScoreInPercent=Relative Wertung in %
|
||||
RelativeScoreInRaceInPercent=Relative Wertung im Rennen in %
|
||||
AbsoluteRank=Absolute Platzierung
|
||||
WindSpeedInBeaufort=Windgeschwindigkeit in Bft.
|
||||
DistanceAtStart=Distanz zur Startlinie zum Startzeitpunkt
|
||||
@@ -76,4 +78,7 @@ PassingSide=Passierende Seite
|
||||
TackAtStart=Startbug
|
||||
SpeedTenSecondsAfterStart=Geschwindigkeit 10s nach dem Startzeitpunkt
|
||||
RankThirtySecondsAfterStart=Absolute Platzierung 30s nach dem Startzeitpunkt
|
||||
StartAdvantage=Startvorteil
|
||||
WindwardDistanceToAdvantageousEndOfLine=Windwärtige Distanz zum Bevorteilten Ende der Startlinie
|
||||
RankAfterHalfOfTheFirstLeg=Platzierung nach der Hälfte des ersten Schenkels
|
||||
AdvantageousEndOfLine=Bevorteiltes Ende der Startlinie
|
||||
TimeSpentInSeconds=Benötigte Zeit in Sekunden
|
||||
@@ -23,11 +23,9 @@ import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMa
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMedianAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMinAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceSumAggregationProcessor;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sse.datamining.DataSourceProvider;
|
||||
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
|
||||
import com.sap.sse.datamining.components.DataRetrieverChainDefinition;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.datamining.impl.AbstractDataMiningActivatorWithPredefinedQueries;
|
||||
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
|
||||
@@ -126,9 +124,9 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries
|
||||
dataSourceProviders = new HashSet<>();
|
||||
dataSourceProviders.add(new RacingEventServiceProvider(context));
|
||||
}
|
||||
|
||||
public static ClusterGroup<Speed> getWindStrengthInBeaufortClusterGroup() {
|
||||
return clusterGroups.getWindStrengthInBeaufortCluster();
|
||||
|
||||
public static SailingClusterGroups getClusterGroups() {
|
||||
return clusterGroups;
|
||||
}
|
||||
|
||||
public static Activator getDefault() {
|
||||
|
||||
+21
-4
@@ -3,6 +3,9 @@ package com.sap.sailing.datamining;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.datamining.data.ClusterFormatter;
|
||||
import com.sap.sailing.datamining.impl.data.LinearDoubleClusterGroup;
|
||||
import com.sap.sailing.datamining.impl.data.PercentageClusterFormatter;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
@@ -17,7 +20,10 @@ import com.sap.sse.datamining.impl.data.LocalizedCluster;
|
||||
|
||||
public class SailingClusterGroups {
|
||||
|
||||
private final ClusterGroup<Speed> windStrengthInBeaufortCluster;
|
||||
private final ClusterGroup<Speed> windStrengthInBeaufortClusterGroup;
|
||||
|
||||
private final ClusterGroup<Double> percentageClusterGroup;
|
||||
private final ClusterFormatter<Double> percentageClusterFormatter;
|
||||
|
||||
public SailingClusterGroups() {
|
||||
Collection<Cluster<Speed>> clusters = new ArrayList<>();
|
||||
@@ -98,11 +104,22 @@ public class SailingClusterGroups {
|
||||
lowerBound = new ComparableClusterBoundary<Speed>(lowerBoundWindSpeed, ComparisonStrategy.GREATER_EQUALS_THAN);
|
||||
clusters.add(new LocalizedCluster<Speed>("Bft12", new ClusterWithSingleBoundary<Speed>(lowerBound)));
|
||||
|
||||
windStrengthInBeaufortCluster = new FixClusterGroup<Speed>(clusters);
|
||||
windStrengthInBeaufortClusterGroup = new FixClusterGroup<Speed>(clusters);
|
||||
|
||||
percentageClusterGroup = new LinearDoubleClusterGroup(0.0, 1.0, 0.1, true);
|
||||
percentageClusterFormatter = new PercentageClusterFormatter();
|
||||
}
|
||||
|
||||
public ClusterGroup<Speed> getWindStrengthInBeaufortCluster() {
|
||||
return windStrengthInBeaufortCluster;
|
||||
public ClusterGroup<Speed> getWindStrengthInBeaufortClusterGroup() {
|
||||
return windStrengthInBeaufortClusterGroup;
|
||||
}
|
||||
|
||||
public ClusterGroup<Double> getPercentageClusterGroup() {
|
||||
return percentageClusterGroup;
|
||||
}
|
||||
|
||||
public ClusterFormatter<Double> getPercentageClusterFormatter() {
|
||||
return percentageClusterFormatter;
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.sap.sailing.datamining.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
|
||||
// TODO Move to sse bundle, after 49er analysis
|
||||
public interface ClusterFormatter<T extends Serializable> {
|
||||
|
||||
String format(Cluster<T> cluster);
|
||||
|
||||
}
|
||||
+23
-13
@@ -8,6 +8,7 @@ import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sse.datamining.annotations.Connector;
|
||||
import com.sap.sse.datamining.annotations.Dimension;
|
||||
import com.sap.sse.datamining.annotations.Statistic;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
|
||||
|
||||
public interface HasRaceOfCompetitorContext {
|
||||
|
||||
@@ -23,43 +24,52 @@ public interface HasRaceOfCompetitorContext {
|
||||
@Dimension(messageKey="TackAtStart", ordinal=12)
|
||||
public Tack getTackAtStart() throws NoWindException;
|
||||
|
||||
@Dimension(messageKey="DistanceToStarboardSideAtStart", ordinal=13)
|
||||
public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart();
|
||||
|
||||
@Dimension(messageKey="RelativeScoreInPercent", ordinal=14)
|
||||
public ClusterDTO getPercentageClusterForRelativeScore();
|
||||
|
||||
@Statistic(messageKey="DistanceAtStart", resultDecimals=2, ordinal=0)
|
||||
public Distance getDistanceToStartLineAtStart();
|
||||
|
||||
@Statistic(messageKey="DistanceToStarboardSideAtStart", resultDecimals=2, ordinal=1)
|
||||
public Double getNormalizedDistanceToStarboardSideAtStart();
|
||||
|
||||
// @Statistic(messageKey="StartAdvantage", resultDecimals=2, ordinal=2)
|
||||
// public Double getNormalizedDistanceToFavoredEndAtStart();
|
||||
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLine", resultDecimals=2, ordinal=2)
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStart();
|
||||
|
||||
@Connector(messageKey="SpeedWhenStarting", ordinal=2)
|
||||
@Connector(messageKey="SpeedWhenStarting", ordinal=3)
|
||||
public Speed getSpeedWhenStarting();
|
||||
|
||||
@Connector(messageKey="SpeedTenSecondsBeforeStart", ordinal=3)
|
||||
@Connector(messageKey="SpeedTenSecondsBeforeStart", ordinal=4)
|
||||
public Speed getSpeedTenSecondsBeforeStart();
|
||||
|
||||
@Connector(messageKey="SpeedTenSecondsAfterStart", ordinal=4)
|
||||
@Connector(messageKey="SpeedTenSecondsAfterStart", ordinal=5)
|
||||
public Speed getSpeedTenSecondsAfterStart();
|
||||
|
||||
@Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=5)
|
||||
public Double getAbsoluteRankThirtySecondsAfterStart();
|
||||
@Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=6)
|
||||
public Double getRankThirtySecondsAfterStart();
|
||||
|
||||
@Statistic(messageKey="RankAtFirstMark", resultDecimals=2, ordinal=6)
|
||||
@Statistic(messageKey="RankAfterHalfOfTheFirstLeg", resultDecimals=2, ordinal=7)
|
||||
public Double getRankAfterHalfOfTheFirstLeg();
|
||||
|
||||
@Statistic(messageKey="RankAtFirstMark", resultDecimals=2, ordinal=8)
|
||||
public Double getRankAtFirstMark();
|
||||
|
||||
@Statistic(messageKey="RankGainsOrLossesBetweenFirstMarkAndFinish", resultDecimals=2, ordinal=7)
|
||||
@Statistic(messageKey="RankGainsOrLossesBetweenFirstMarkAndFinish", resultDecimals=2, ordinal=9)
|
||||
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish();
|
||||
|
||||
@Statistic(messageKey="NumberOfManeuvers", resultDecimals=0, ordinal=8)
|
||||
@Statistic(messageKey="NumberOfManeuvers", resultDecimals=0, ordinal=10)
|
||||
public int getNumberOfManeuvers();
|
||||
|
||||
@Statistic(messageKey="NumberOfTacks", resultDecimals=2, ordinal=9)
|
||||
@Statistic(messageKey="NumberOfTacks", resultDecimals=2, ordinal=11)
|
||||
public int getNumberOfTacks();
|
||||
|
||||
@Statistic(messageKey="NumberOfJibes", resultDecimals=2, ordinal=10)
|
||||
@Statistic(messageKey="NumberOfJibes", resultDecimals=2, ordinal=12)
|
||||
public int getNumberOfJibes();
|
||||
|
||||
@Statistic(messageKey="NumberOfPenaltyCircles", resultDecimals=2, ordinal=11)
|
||||
@Statistic(messageKey="NumberOfPenaltyCircles", resultDecimals=2, ordinal=13)
|
||||
public int getNumberOfPenaltyCircles();
|
||||
|
||||
}
|
||||
+7
@@ -6,6 +6,7 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sse.datamining.annotations.Connector;
|
||||
import com.sap.sse.datamining.annotations.Dimension;
|
||||
import com.sap.sse.datamining.annotations.Statistic;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
|
||||
|
||||
public interface HasTrackedLegOfCompetitorContext {
|
||||
|
||||
@@ -16,6 +17,9 @@ public interface HasTrackedLegOfCompetitorContext {
|
||||
|
||||
@Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible
|
||||
public String getCompetitorSearchTag();
|
||||
|
||||
@Dimension(messageKey="RelativeScoreInRaceInPercent", ordinal=12)
|
||||
public ClusterDTO getPercentageClusterForRelativeScoreInRace();
|
||||
|
||||
@Connector(messageKey="Competitor")
|
||||
public Competitor getCompetitor();
|
||||
@@ -31,5 +35,8 @@ public interface HasTrackedLegOfCompetitorContext {
|
||||
|
||||
@Statistic(messageKey="AbsoluteRank", resultDecimals=2, ordinal=3)
|
||||
public Double getAbsoluteRank();
|
||||
|
||||
@Statistic(messageKey="TimeSpentInSeconds", resultDecimals=0, ordinal=4)
|
||||
public Long getTimeTakenInSeconds();
|
||||
|
||||
}
|
||||
+11
-1
@@ -1,10 +1,12 @@
|
||||
package com.sap.sailing.datamining.data;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.NauticalSide;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.datamining.annotations.Connector;
|
||||
import com.sap.sse.datamining.annotations.Dimension;
|
||||
@@ -35,7 +37,10 @@ public interface HasTrackedRaceContext {
|
||||
@Dimension(messageKey="Year", ordinal=2)
|
||||
public Integer getYear();
|
||||
|
||||
@Dimension(messageKey="IsTracked", ordinal=6)
|
||||
@Dimension(messageKey="AdvantageousEndOfLine", ordinal=6)
|
||||
public NauticalSide getAdvantageousEndOfLine();
|
||||
|
||||
@Dimension(messageKey="IsTracked", ordinal=7)
|
||||
public Boolean isTracked();
|
||||
|
||||
@Statistic(messageKey="NumberOfCompetitorFixes", resultDecimals=0, ordinal=0)
|
||||
@@ -44,4 +49,9 @@ public interface HasTrackedRaceContext {
|
||||
@Statistic(messageKey="NumberOfMarkFixes", resultDecimals=0, ordinal=1)
|
||||
public int getNumberOfMarkFixes();
|
||||
|
||||
// Convenience methods for race dependent calculation to avoid code duplication
|
||||
public Double getRelativeScoreForCompetitor(Competitor competitor);
|
||||
|
||||
public Double getRankAtFinishForCompetitor(Competitor competitor);
|
||||
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.datamining.data.ClusterFormatter;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.data.ClusterBoundary;
|
||||
import com.sap.sse.datamining.impl.data.AbstractCluster;
|
||||
import com.sap.sse.datamining.impl.data.AbstractClusterBoundary;
|
||||
import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries;
|
||||
import com.sap.sse.datamining.impl.data.ClusterWithSingleBoundary;
|
||||
import com.sap.sse.datamining.impl.data.ComparisonStrategy;
|
||||
import com.sap.sse.datamining.impl.data.LocalizedCluster;
|
||||
|
||||
//TODO Clean and move to sse bundle after 49er analysis
|
||||
public abstract class AbstractClusterFormatter<T extends Serializable> implements ClusterFormatter<T> {
|
||||
|
||||
private static final char INFINITE = '\u221e';
|
||||
|
||||
private final ClusterBoundariesAccessor boundariesAccessor = new ClusterBoundariesAccessor();
|
||||
private final BoundaryValueAccessor valueAccessor = new BoundaryValueAccessor();
|
||||
|
||||
@Override
|
||||
public String format(Cluster<T> cluster) {
|
||||
if (cluster instanceof LocalizedCluster) {
|
||||
// TODO recursive call format(localizedCluster.getInnerCluster()) after 49er analysis
|
||||
}
|
||||
if (cluster instanceof ClusterWithSingleBoundary) {
|
||||
return formatClusterWithSingleBoundary((ClusterWithSingleBoundary<T>) cluster);
|
||||
}
|
||||
if (cluster instanceof ClusterWithLowerAndUpperBoundaries) {
|
||||
return formatClusterWithLowerAndUpperBoundaries((ClusterWithLowerAndUpperBoundaries<T>) cluster);
|
||||
}
|
||||
throw new IllegalArgumentException("Can't format clusters of type " + cluster.getClass().getName());
|
||||
}
|
||||
|
||||
protected String formatClusterWithSingleBoundary(ClusterWithSingleBoundary<T> cluster) {
|
||||
List<ClusterBoundary<T>> boundaries = boundariesAccessor.getBoundaries(cluster);
|
||||
if (boundaries == null) {
|
||||
return "<Unformattable>";
|
||||
}
|
||||
|
||||
ClusterBoundary<T> boundary = boundaries.get(0);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (boundary.getStrategy() == ComparisonStrategy.LOWER_EQUALS_THAN ||
|
||||
boundary.getStrategy() == ComparisonStrategy.LOWER_THAN) {
|
||||
builder.append("-" + INFINITE + " - ");
|
||||
}
|
||||
builder.append(formatBoundary(boundary));
|
||||
if (boundary.getStrategy() == ComparisonStrategy.GREATER_EQUALS_THAN ||
|
||||
boundary.getStrategy() == ComparisonStrategy.GREATER_THAN) {
|
||||
builder.append(" - " + INFINITE);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected String formatClusterWithLowerAndUpperBoundaries(ClusterWithLowerAndUpperBoundaries<T> cluster) {
|
||||
List<ClusterBoundary<T>> boundaries = boundariesAccessor.getBoundaries(cluster);
|
||||
if (boundaries == null) {
|
||||
return "<Unformattable>";
|
||||
}
|
||||
|
||||
return String.format("%s - %s", formatBoundary(boundaries.get(0)), formatBoundary(boundaries.get(1)));
|
||||
}
|
||||
|
||||
protected String formatBoundary(ClusterBoundary<T> boundary) {
|
||||
String value = formatValue(valueAccessor.getValue((AbstractClusterBoundary<T>) boundary));
|
||||
if (value == null) {
|
||||
return "<Unformattable>";
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
ComparisonStrategy strategy = boundary.getStrategy();
|
||||
if (strategy == ComparisonStrategy.GREATER_EQUALS_THAN || strategy == ComparisonStrategy.GREATER_THAN) {
|
||||
builder.append(strategy.getSignifier());
|
||||
}
|
||||
builder.append(value);
|
||||
if (strategy == ComparisonStrategy.LOWER_EQUALS_THAN || strategy == ComparisonStrategy.LOWER_THAN) {
|
||||
builder.append(strategy.getSignifier());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected abstract String formatValue(T value);
|
||||
|
||||
//FIXME Please delete me
|
||||
private class ClusterBoundariesAccessor {
|
||||
|
||||
private static final String boundariesFieldName = "boundaries";
|
||||
|
||||
public List<ClusterBoundary<T>> getBoundaries(AbstractCluster<T> cluster) {
|
||||
List<ClusterBoundary<T>> boundaries = null;
|
||||
Field boundariesField = null;
|
||||
try {
|
||||
boundariesField = AbstractCluster.class.getDeclaredField(boundariesFieldName);
|
||||
boundariesField.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<ClusterBoundary<T>> reflectedBoundaries = (Collection<ClusterBoundary<T>>) boundariesField.get(cluster);
|
||||
boundaries = new ArrayList<>();
|
||||
for (ClusterBoundary<T> boundary : reflectedBoundaries) {
|
||||
boundaries.add(boundary);
|
||||
}
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
} finally {
|
||||
if (boundariesField != null) {
|
||||
boundariesField.setAccessible(false);
|
||||
}
|
||||
}
|
||||
return boundaries;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//FIXME Please delete me
|
||||
private class BoundaryValueAccessor {
|
||||
|
||||
private static final String valueFieldName = "boundaryValue";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T getValue(AbstractClusterBoundary<T> boundary) {
|
||||
T value = null;
|
||||
Field valueField = null;
|
||||
try {
|
||||
valueField = AbstractClusterBoundary.class.getDeclaredField(valueFieldName);
|
||||
valueField.setAccessible(true);
|
||||
value = (T) valueField.get(boundary);
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
} finally {
|
||||
if (valueField != null) {
|
||||
valueField.setAccessible(false);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -36,7 +36,7 @@ public class GPSFixWithContext implements HasGPSFixContext {
|
||||
@Override
|
||||
public ClusterDTO getWindStrengthAsBeaufortCluster(Locale locale, ResourceBundleStringMessages stringMessages) {
|
||||
Wind wind = getWind();
|
||||
Cluster<?> cluster = Activator.getWindStrengthInBeaufortClusterGroup().getClusterFor(wind);
|
||||
Cluster<?> cluster = Activator.getClusterGroups().getWindStrengthInBeaufortClusterGroup().getClusterFor(wind);
|
||||
return new ClusterDTO(cluster.asLocalizedString(locale, stringMessages));
|
||||
}
|
||||
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries;
|
||||
import com.sap.sse.datamining.impl.data.ClusterWithSingleBoundary;
|
||||
import com.sap.sse.datamining.impl.data.ComparableClusterBoundary;
|
||||
import com.sap.sse.datamining.impl.data.ComparisonStrategy;
|
||||
|
||||
// TODO: Improve and move to com.sap.sse.datamining
|
||||
public class LinearDoubleClusterGroup implements ClusterGroup<Double> {
|
||||
private static final long serialVersionUID = 1559316450183865115L;
|
||||
|
||||
private final double lowerBound;
|
||||
private final double upperBound;
|
||||
private final double stepSize;
|
||||
private final boolean hardBounds;
|
||||
|
||||
private final transient Map<Integer, Cluster<Double>> clusterCache;
|
||||
private final int lastClusterIndex;
|
||||
|
||||
public LinearDoubleClusterGroup(double lowerBound, double upperBound, double stepSize, boolean hardBounds) {
|
||||
this.lowerBound = lowerBound;
|
||||
this.upperBound = upperBound;
|
||||
this.stepSize = stepSize;
|
||||
this.hardBounds = hardBounds;
|
||||
|
||||
clusterCache = new HashMap<>();
|
||||
lastClusterIndex = calculateLastClusterIndex(this.upperBound, this.stepSize);
|
||||
}
|
||||
|
||||
private static int calculateLastClusterIndex(double upperBound, double stepSize) {
|
||||
double doubleIndex = upperBound / stepSize;
|
||||
int index = (int) doubleIndex;
|
||||
double fractionalPart = doubleIndex - index;
|
||||
if (fractionalPart <= 0.0001) {
|
||||
index--;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cluster<Double> getClusterFor(Double valueObject) {
|
||||
double value = valueObject.doubleValue();
|
||||
if (value < lowerBound) {
|
||||
return hardBounds ? null : getCluster(0);
|
||||
}
|
||||
if (value > upperBound) {
|
||||
return hardBounds ? null : getCluster(lastClusterIndex);
|
||||
}
|
||||
|
||||
if (Math.abs(upperBound - value) < 0.0001) {
|
||||
return getCluster(lastClusterIndex);
|
||||
}
|
||||
return getCluster((int) (value / stepSize));
|
||||
}
|
||||
|
||||
private Cluster<Double> getCluster(int index) {
|
||||
if (!clusterCache.containsKey(index)) {
|
||||
clusterCache.put(index, createCluster(index));
|
||||
}
|
||||
return clusterCache.get(index);
|
||||
}
|
||||
|
||||
private Cluster<Double> createCluster(int index) {
|
||||
if (index == 0 && !hardBounds) {
|
||||
return new ClusterWithSingleBoundary<>(createUpperBound(index, ComparisonStrategy.LOWER_THAN));
|
||||
}
|
||||
if (index == lastClusterIndex && !hardBounds) {
|
||||
return new ClusterWithSingleBoundary<>(createLowerBound(index, ComparisonStrategy.GREATER_EQUALS_THAN));
|
||||
}
|
||||
|
||||
ComparisonStrategy upperComparisonStrategy = index == lastClusterIndex ? ComparisonStrategy.LOWER_EQUALS_THAN : ComparisonStrategy.LOWER_THAN;
|
||||
return new ClusterWithLowerAndUpperBoundaries<>(createLowerBound(index, ComparisonStrategy.GREATER_EQUALS_THAN),
|
||||
createUpperBound(index, upperComparisonStrategy));
|
||||
}
|
||||
|
||||
private ComparableClusterBoundary<Double> createLowerBound(int index, ComparisonStrategy comparisonStrategy) {
|
||||
return new ComparableClusterBoundary<Double>(this.lowerBound + stepSize * index, comparisonStrategy);
|
||||
}
|
||||
|
||||
private ComparableClusterBoundary<Double> createUpperBound(int index, ComparisonStrategy comparisonStrategy) {
|
||||
return new ComparableClusterBoundary<Double>(this.lowerBound + stepSize * (index + 1.0), comparisonStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Double> getClusterElementsType() {
|
||||
return Double.class;
|
||||
}
|
||||
|
||||
public double getLowerGroupBound() {
|
||||
return lowerBound;
|
||||
}
|
||||
|
||||
public double getUpperGroupBound() {
|
||||
return upperBound;
|
||||
}
|
||||
|
||||
public double getStepSize() {
|
||||
return stepSize;
|
||||
}
|
||||
|
||||
public boolean isHardBounds() {
|
||||
return hardBounds;
|
||||
}
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
public class PercentageClusterFormatter extends AbstractClusterFormatter<Double> {
|
||||
|
||||
@Override
|
||||
protected String formatValue(Double value) {
|
||||
return (int) (value * 100) + "%";
|
||||
}
|
||||
|
||||
}
|
||||
+81
-7
@@ -2,20 +2,32 @@ package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.sap.sailing.datamining.Activator;
|
||||
import com.sap.sailing.datamining.SailingClusterGroups;
|
||||
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.LineDetails;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindPositionMode;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
|
||||
|
||||
public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
|
||||
@@ -52,6 +64,18 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
return startOfRace == null ? null : getTrackedRace().getTack(getCompetitor(), startOfRace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart() {
|
||||
Double normalizedDistance = getNormalizedDistanceToStarboardSideAtStart();
|
||||
if (normalizedDistance == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SailingClusterGroups clusterGroups = Activator.getClusterGroups();
|
||||
Cluster<Double> cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(normalizedDistance);
|
||||
return new ClusterDTO(clusterGroups.getPercentageClusterFormatter().format(cluster));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getDistanceToStartLineAtStart() {
|
||||
return getTrackedRace().getDistanceToStartLine(getCompetitor(), 0);
|
||||
@@ -71,6 +95,46 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
return distance / length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStart() {
|
||||
TrackedRace trackedRace = getTrackedRace();
|
||||
TimePoint startOfRace = trackedRace.getStartOfRace();
|
||||
LineDetails startLine = trackedRace.getStartLine(startOfRace);
|
||||
Mark advantageousMark = null;
|
||||
switch (startLine.getAdvantageousSideWhileApproachingLine()) {
|
||||
case PORT:
|
||||
advantageousMark = startLine.getPortMarkWhileApproachingLine();
|
||||
break;
|
||||
case STARBOARD:
|
||||
advantageousMark = startLine.getStarboardMarkWhileApproachingLine();
|
||||
break;
|
||||
}
|
||||
if (advantageousMark == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GPSFixTrack<Mark, GPSFix> advantageousMarkTrack = trackedRace.getOrCreateTrack(advantageousMark);
|
||||
Position advantageousMarkPosition = advantageousMarkTrack.getEstimatedPosition(startOfRace, false);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> competitorTrack = trackedRace.getTrack(getCompetitor());
|
||||
Position competitorPosition = competitorTrack.getEstimatedPosition(startOfRace, false);
|
||||
|
||||
TrackedLeg trackedLeg = trackedRace.getTrackedLeg(trackedRace.getRace().getCourse().getFirstLeg());
|
||||
Distance distance = trackedLeg.getWindwardDistance(competitorPosition, advantageousMarkPosition, startOfRace, WindPositionMode.LEG_MIDDLE);
|
||||
return distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterDTO getPercentageClusterForRelativeScore() {
|
||||
Double relativeScore = getTrackedRaceContext().getRelativeScoreForCompetitor(getCompetitor());
|
||||
if (relativeScore == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SailingClusterGroups clusterGroups = Activator.getClusterGroups();
|
||||
Cluster<Double> cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(relativeScore);
|
||||
return new ClusterDTO(clusterGroups.getPercentageClusterFormatter().format(cluster));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getSpeedWhenStarting() {
|
||||
return getTrackedRace().getSpeedWhenCrossingStartLine(getCompetitor());
|
||||
@@ -91,7 +155,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getAbsoluteRankThirtySecondsAfterStart() {
|
||||
public Double getRankThirtySecondsAfterStart() {
|
||||
TimePoint startOfRace = getTrackedRace().getStartOfRace();
|
||||
if (startOfRace == null) {
|
||||
return null;
|
||||
@@ -101,6 +165,21 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
return rank == 0 ? null : Double.valueOf(rank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRankAfterHalfOfTheFirstLeg() {
|
||||
Course course = getTrackedRace().getRace().getCourse();
|
||||
TrackedLegOfCompetitor trackedLeg = getTrackedRace().getTrackedLeg(getCompetitor(), course.getFirstLeg());
|
||||
TimePoint startTime = trackedLeg.getStartTime();
|
||||
TimePoint finishTime = trackedLeg.getFinishTime();
|
||||
if (startTime == null || finishTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long halfOffset = (finishTime.asMillis() - startTime.asMillis()) / 2;
|
||||
int rank = getTrackedRace().getRank(getCompetitor(), startTime.plus(halfOffset));
|
||||
return rank == 0 ? null : Double.valueOf(rank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRankAtFirstMark() {
|
||||
Course course = getTrackedRace().getRace().getCourse();
|
||||
@@ -113,15 +192,10 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
@Override
|
||||
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish() {
|
||||
Double rankAtFirstMark = getRankAtFirstMark();
|
||||
Double rankAtFinish = getRankAtFinish();
|
||||
Double rankAtFinish = getTrackedRaceContext().getRankAtFinishForCompetitor(getCompetitor());
|
||||
return rankAtFirstMark != null && rankAtFinish != null ? rankAtFirstMark - rankAtFinish : null;
|
||||
}
|
||||
|
||||
private Double getRankAtFinish() {
|
||||
int rank = getTrackedRace().getRank(getCompetitor(), getTrackedRace().getEndOfTracking());
|
||||
return rank == 0 ? null : Double.valueOf(rank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfManeuvers() {
|
||||
return getNumberOfTacks() + getNumberOfJibes();
|
||||
|
||||
+27
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import com.sap.sailing.datamining.Activator;
|
||||
import com.sap.sailing.datamining.SailingClusterGroups;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
@@ -9,6 +11,8 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
|
||||
|
||||
public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompetitorContext {
|
||||
|
||||
@@ -48,6 +52,18 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
|
||||
return getCompetitor().getSearchTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterDTO getPercentageClusterForRelativeScoreInRace() {
|
||||
Double relativeScore = getTrackedLegContext().getTrackedRaceContext().getRelativeScoreForCompetitor(getCompetitor());
|
||||
if (relativeScore == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SailingClusterGroups clusterGroups = Activator.getClusterGroups();
|
||||
Cluster<Double> cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(relativeScore);
|
||||
return new ClusterDTO(clusterGroups.getPercentageClusterFormatter().format(cluster));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getDistanceTraveled() {
|
||||
TimePoint timePoint = getTrackedLegContext().getTrackedRaceContext().getTrackedRace().getEndOfTracking();
|
||||
@@ -94,4 +110,15 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
|
||||
return rankAtFinish;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTimeTakenInSeconds() {
|
||||
TimePoint startTime = getTrackedLegOfCompetitor().getStartTime();
|
||||
TimePoint finishTime = getTrackedLegOfCompetitor().getFinishTime();
|
||||
if (startTime == null || finishTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (finishTime.asMillis() - startTime.asMillis()) / 1000;
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -11,9 +11,11 @@ import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.NauticalSide;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.LineDetails;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -90,6 +92,12 @@ public class TrackedRaceWithContext implements HasTrackedRaceContext {
|
||||
calendar.setTime(time.asDate());
|
||||
return calendar.get(Calendar.YEAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NauticalSide getAdvantageousEndOfLine() {
|
||||
LineDetails startLine = getTrackedRace().getStartLine(getTrackedRace().getStartOfRace());
|
||||
return startLine.getAdvantageousSideWhileApproachingLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isTracked() {
|
||||
@@ -125,5 +133,20 @@ public class TrackedRaceWithContext implements HasTrackedRaceContext {
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
// Convenience methods for race dependent calculation to avoid code duplication
|
||||
public Double getRelativeScoreForCompetitor(Competitor competitor) {
|
||||
Double rankAtFinish = getRankAtFinishForCompetitor(competitor);
|
||||
if (rankAtFinish == null) {
|
||||
return null;
|
||||
}
|
||||
return rankAtFinish / Util.size(getTrackedRace().getRace().getCompetitors());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRankAtFinishForCompetitor(Competitor competitor) {
|
||||
int rank = getTrackedRace().getRank(competitor, getTrackedRace().getEndOfTracking());
|
||||
return rank == 0 ? null : Double.valueOf(rank);
|
||||
}
|
||||
|
||||
}
|
||||
+9
-2
@@ -35,6 +35,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.polars.PolarsChangedListener;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.PolarDataOperation;
|
||||
import com.sap.sailing.polars.mining.BearingClusterGroup;
|
||||
@@ -236,8 +237,14 @@ public class PolarDataServiceImpl implements PolarDataService,
|
||||
@Override
|
||||
public void insertExistingFixes(TrackedRace trackedRace) {
|
||||
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
||||
for (GPSFixMoving fix : trackedRace.getTrack(competitor).getFixes()) {
|
||||
competitorPositionChanged(fix, competitor, trackedRace);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
try {
|
||||
for (GPSFixMoving fix : track.getFixes()) {
|
||||
competitorPositionChanged(fix, competitor, trackedRace);
|
||||
}
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -3484,6 +3484,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
trackedRace.setPolarDataService(service);
|
||||
service.insertExistingFixes(trackedRace);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.log(Level.SEVERE, "Error reconstructing the polars for tracked races", e);
|
||||
} finally {
|
||||
trackedRegatta.unlockTrackedRacesAfterRead();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class NaturalComparator implements Comparator<String> {
|
||||
|
||||
// Compare all-digit blocks as numbers - all-char blocks as strings
|
||||
if (Character.isDigit(aBlock.charAt(0)) && Character.isDigit(bBlock.charAt(0))) {
|
||||
result = Integer.valueOf(aBlock).compareTo(Integer.valueOf(bBlock));
|
||||
result = Long.valueOf(aBlock).compareTo(Long.valueOf(bBlock));
|
||||
} else {
|
||||
result = aBlock.compareTo(bBlock);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user