mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-24 21:13:50 +00:00
Merge branch 'master' into bug3881
Conflicts: java/com.sap.sailing.www/release_notes_admin.html
This commit is contained in:
commit
5428f541a2
162 files changed
+2674
-1241
No files matched your search
+1
-1
@@ -161,7 +161,7 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
|
||||
final RaceMapSettings raceMapSettings = new RaceMapSettings(raceMapZoomSettings, getHelpLineSettings(),
|
||||
defaultRaceMapSettings.getTransparentHoverlines(), defaultRaceMapSettings.getHoverlineStrokeWeight(),
|
||||
startAnalysisDTO.tailLenghtInMilliseconds, defaultRaceMapSettings.isWindUp(),
|
||||
defaultRaceMapSettings.getBuoyZoneRadiusInMeters(), defaultRaceMapSettings.isShowOnlySelectedCompetitors(),
|
||||
defaultRaceMapSettings.getBuoyZoneRadius(), defaultRaceMapSettings.isShowOnlySelectedCompetitors(),
|
||||
defaultRaceMapSettings.isShowSelectedCompetitorsInfo(), defaultRaceMapSettings.isShowWindStreamletColors(),
|
||||
defaultRaceMapSettings.isShowWindStreamletOverlay(), defaultRaceMapSettings.isShowSimulationOverlay(),
|
||||
defaultRaceMapSettings.isShowMapControls(), defaultRaceMapSettings.getManeuverTypesToShow(),
|
||||
|
||||
+6
@@ -2,6 +2,9 @@ package com.sap.sailing.datamining.shared;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.NauticalSide;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.impl.CentralAngleDistance;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
|
||||
@@ -16,6 +19,9 @@ public final class SailingDataMiningSerializationDummy implements SerializationD
|
||||
private CentralAngleDistance centralAngleDistance;
|
||||
private MeterDistance meterDistance;
|
||||
private NauticalMileDistance nauticalMileDistance;
|
||||
private ManeuverType maneuverType;
|
||||
private Tack tack;
|
||||
private NauticalSide nauticalSide;
|
||||
|
||||
private SailingDataMiningSerializationDummy() { }
|
||||
|
||||
|
||||
+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%["));
|
||||
}
|
||||
|
||||
}
|
||||
+24
-5
@@ -24,12 +24,14 @@ GPSFixSailingDomainRetrieverChain=GPS-Fixes
|
||||
MarkPassingSailingDomainRetrieverChain=Mark Passings
|
||||
RaceResultSailingDomainRetrieverChain=Race Results
|
||||
RaceOfCompetitorSailingDomainRetrieverChain=Races of Competitors
|
||||
ManeuverSailingDomainRetrieverChain=Maneuver
|
||||
LeaderboardGroup=Leaderboard Group
|
||||
Leaderboard=Leaderboard
|
||||
Leg=Leg
|
||||
MarkPassing=Mark Passing
|
||||
LegOfCompetitor=Leg of competitor
|
||||
GpsFix=GPS-Fix
|
||||
Maneuver=Maneuver
|
||||
WindStrengthInBeaufort=Wind Strength in Beaufort
|
||||
Bft0=Calm
|
||||
Bft1=Light air
|
||||
@@ -45,11 +47,13 @@ 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
|
||||
SpeedWhenStarting=Speed when starting
|
||||
SpeedTenSecondsBeforeStart=Speed 10s before start
|
||||
WindSpeedInBeaufort=Wind Speed in Bft
|
||||
DistanceAtStart=Distance to Start at Start
|
||||
SpeedWhenStarting=Speed at Start
|
||||
SpeedTenSecondsBeforeStart=Speed 10s Before Start
|
||||
RankAtFirstMark=Rank at First Mark
|
||||
NumberOfManeuvers=Number of Maneuvers
|
||||
NumberOfTacks=Number of Tacks
|
||||
@@ -62,4 +66,19 @@ NumberOfWins=Number of Wins
|
||||
RankGainsOrLossesBetweenFirstMarkAndFinish=Rank Gains or Losses (1st Mark -> Finish)
|
||||
IsTracked=Is Tracked
|
||||
NumberOfCompetitorFixes=Number of Competitor Fixes
|
||||
NumberOfMarkFixes=Number of Mark Fixes
|
||||
NumberOfMarkFixes=Number of Mark Fixes
|
||||
ManeuverType=Maneuver Type
|
||||
Tack=Tack
|
||||
SpeedBefore=Speed Before Maneuver
|
||||
SpeedAfter=Speed After Maneuver
|
||||
DirectionChange=Direction Change in Degrees
|
||||
ManeuverLoss=Maneuver Loss
|
||||
Waypoint=Waypoint
|
||||
PassingSide=Passing Side
|
||||
TackAtStart=Tack at Start
|
||||
SpeedTenSecondsAfterStart=Speed 10s After Start
|
||||
RankThirtySecondsAfterStart=Rank 30s After Start
|
||||
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
|
||||
+20
-1
@@ -22,12 +22,14 @@ GPSFixSailingDomainRetrieverChain=GPS-Fixes
|
||||
MarkPassingSailingDomainRetrieverChain=Tonnenrundungen
|
||||
RaceResultSailingDomainRetrieverChain=Rennergebnisse
|
||||
RaceOfCompetitorSailingDomainRetrieverChain=Rennen eines Teilnehmers
|
||||
ManeuverSailingDomainRetrieverChain=Manöver
|
||||
LeaderboardGroup=Ranglisten Gruppe
|
||||
Leaderboard=Rangliste
|
||||
Leg=Schenkel
|
||||
MarkPassing=Tonnenrundung
|
||||
LegOfCompetitor=Schenkel eines Teilnehmers
|
||||
GpsFix=GPS-Fix
|
||||
Maneuver=Manöver
|
||||
Speed=Geschwindigkeit
|
||||
SpeedTenSecondsBefore=Geschwindigkeit 10s vorher
|
||||
WindStrengthInBeaufort=Windstärke in Beaufort
|
||||
@@ -45,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
|
||||
@@ -62,4 +66,19 @@ NumberOfWins=Anzahl der Siege
|
||||
RankGainsOrLossesBetweenFirstMarkAndFinish=Positions-Verluste oder -Gewinne (1ter Wegpunkt -> Ziel)
|
||||
IsTracked=Ist getracked
|
||||
NumberOfCompetitorFixes=Anzahl der Teilnehmer-Fixes
|
||||
NumberOfMarkFixes=Anzahl der Tonnen-Fixes
|
||||
NumberOfMarkFixes=Anzahl der Tonnen-Fixes
|
||||
ManeuverType=Art des Manövers
|
||||
Tack=Bug
|
||||
SpeedBefore=Geschwindigkeit bevor dem Manöver
|
||||
SpeedAfter=Geschwindigkeit nach dem Manöver
|
||||
DirectionChange=Richtungsänderung in Grad
|
||||
ManeuverLoss=Manöververlust
|
||||
Waypoint=Wegpunkt
|
||||
PassingSide=Passierende Seite
|
||||
TackAtStart=Startbug
|
||||
SpeedTenSecondsAfterStart=Geschwindigkeit 10s nach dem Startzeitpunkt
|
||||
RankThirtySecondsAfterStart=Absolute Platzierung 30s nach dem Startzeitpunkt
|
||||
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
|
||||
@@ -10,6 +10,7 @@ import org.osgi.framework.BundleContext;
|
||||
import com.sap.sailing.datamining.data.HasGPSFixContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
|
||||
import com.sap.sailing.datamining.data.HasManeuverContext;
|
||||
import com.sap.sailing.datamining.data.HasMarkPassingContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
|
||||
@@ -22,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;
|
||||
@@ -82,6 +81,7 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries
|
||||
internalClasses.add(HasTrackedLegContext.class);
|
||||
internalClasses.add(HasTrackedLegOfCompetitorContext.class);
|
||||
internalClasses.add(HasGPSFixContext.class);
|
||||
internalClasses.add(HasManeuverContext.class);
|
||||
internalClasses.add(HasMarkPassingContext.class);
|
||||
internalClasses.add(HasRaceOfCompetitorContext.class);
|
||||
internalClasses.add(HasLeaderboardGroupContext.class);
|
||||
@@ -124,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;
|
||||
}
|
||||
|
||||
}
|
||||
+13
-5
@@ -5,6 +5,7 @@ import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasGPSFixContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasManeuverContext;
|
||||
import com.sap.sailing.datamining.data.HasMarkPassingContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
|
||||
@@ -15,6 +16,7 @@ import com.sap.sailing.datamining.impl.components.CompetitorOfRaceInLeaderboardR
|
||||
import com.sap.sailing.datamining.impl.components.GPSFixRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.ManeuverRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.MarkPassingRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorRetrievalProcessor;
|
||||
@@ -48,11 +50,6 @@ public class SailingDataRetrievalChainDefinitions {
|
||||
trackedRaceRetrieverChainDefinition.endWith(LeaderboardRetrievalProcessor.class, TrackedRaceRetrievalProcessor.class,
|
||||
HasTrackedRaceContext.class, "Race");
|
||||
dataRetrieverChainDefinitions.add(trackedRaceRetrieverChainDefinition);
|
||||
|
||||
final DataRetrieverChainDefinition<RacingEventService, HasMarkPassingContext> markPassingRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
|
||||
trackedRaceRetrieverChainDefinition, HasMarkPassingContext.class, "MarkPassingSailingDomainRetrieverChain");
|
||||
markPassingRetrieverChainDefinition.endWith(TrackedRaceRetrievalProcessor.class, MarkPassingRetrievalProcessor.class, HasMarkPassingContext.class, "MarkPassing");
|
||||
dataRetrieverChainDefinitions.add(markPassingRetrieverChainDefinition);
|
||||
|
||||
final DataRetrieverChainDefinition<RacingEventService, HasRaceOfCompetitorContext> raceOfCompetitorRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
|
||||
trackedRaceRetrieverChainDefinition, HasRaceOfCompetitorContext.class, "RaceOfCompetitorSailingDomainRetrieverChain");
|
||||
@@ -71,6 +68,17 @@ public class SailingDataRetrievalChainDefinitions {
|
||||
gpsFixRetrieverChainDefinition.endWith(TrackedLegOfCompetitorRetrievalProcessor.class, GPSFixRetrievalProcessor.class,
|
||||
HasGPSFixContext.class, "GpsFix");
|
||||
dataRetrieverChainDefinitions.add(gpsFixRetrieverChainDefinition);
|
||||
|
||||
final DataRetrieverChainDefinition<RacingEventService, HasManeuverContext> maneuverRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
|
||||
legOfCompetitorRetrieverChainDefinition, HasManeuverContext.class, "ManeuverSailingDomainRetrieverChain");
|
||||
maneuverRetrieverChainDefinition.endWith(TrackedLegOfCompetitorRetrievalProcessor.class, ManeuverRetrievalProcessor.class,
|
||||
HasManeuverContext.class, "Maneuver");
|
||||
dataRetrieverChainDefinitions.add(maneuverRetrieverChainDefinition);
|
||||
|
||||
final DataRetrieverChainDefinition<RacingEventService, HasMarkPassingContext> markPassingRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
|
||||
legOfCompetitorRetrieverChainDefinition, HasMarkPassingContext.class, "MarkPassingSailingDomainRetrieverChain");
|
||||
markPassingRetrieverChainDefinition.endWith(TrackedLegOfCompetitorRetrievalProcessor.class, MarkPassingRetrievalProcessor.class, HasMarkPassingContext.class, "MarkPassing");
|
||||
dataRetrieverChainDefinitions.add(markPassingRetrieverChainDefinition);
|
||||
}
|
||||
|
||||
public Iterable<DataRetrieverChainDefinition<?, ?>> get() {
|
||||
|
||||
+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);
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.sap.sailing.datamining.data;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sse.datamining.annotations.Connector;
|
||||
import com.sap.sse.datamining.annotations.Dimension;
|
||||
import com.sap.sse.datamining.annotations.Statistic;
|
||||
|
||||
public interface HasManeuverContext {
|
||||
|
||||
@Connector(scanForStatistics=false)
|
||||
HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext();
|
||||
|
||||
Maneuver getManeuver();
|
||||
|
||||
//TODO Clean-Up:
|
||||
// Move Dimensions and Statistics to Maneuver and connect to it
|
||||
@Dimension(messageKey="ManeuverType", ordinal=12)
|
||||
ManeuverType getManeuverType();
|
||||
|
||||
@Dimension(messageKey="Tack", ordinal=13)
|
||||
Tack getTack();
|
||||
|
||||
@Connector(messageKey="SpeedBefore", ordinal=0)
|
||||
SpeedWithBearing getSpeedBefore();
|
||||
@Connector(messageKey="SpeedAfter", ordinal=1)
|
||||
SpeedWithBearing getSpeedAfter();
|
||||
|
||||
@Statistic(messageKey="DirectionChange", resultDecimals=2, ordinal=2)
|
||||
Double getDirectionChangeInDegrees();
|
||||
|
||||
@Statistic(messageKey="ManeuverLoss", resultDecimals=0, ordinal=3)
|
||||
Distance getManeuverLoss();
|
||||
|
||||
}
|
||||
+32
-19
@@ -1,32 +1,45 @@
|
||||
package com.sap.sailing.datamining.data;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.NauticalSide;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.tracking.MarkPassingManeuver;
|
||||
import com.sap.sse.datamining.annotations.Connector;
|
||||
import com.sap.sse.datamining.annotations.Dimension;
|
||||
import com.sap.sse.datamining.annotations.Statistic;
|
||||
|
||||
public interface HasMarkPassingContext {
|
||||
|
||||
@Connector
|
||||
HasTrackedRaceContext getTrackedRaceContext();
|
||||
@Connector(scanForStatistics=false)
|
||||
HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext();
|
||||
|
||||
MarkPassingManeuver getManeuver();
|
||||
|
||||
//TODO Clean-Up:
|
||||
// Move Dimensions and Statistics to Maneuver/MarkPassingManeuver and connect to it
|
||||
// Find a way to implement HasManeuverContext and HasMarkPassingManeuver with a base class
|
||||
@Dimension(messageKey="Tack", ordinal=12)
|
||||
Tack getTack();
|
||||
|
||||
@Connector(messageKey="Waypoint", ordinal=13)
|
||||
Waypoint getWaypoint();
|
||||
|
||||
@Dimension(messageKey="PassingSide", ordinal=13)
|
||||
NauticalSide getPassingSide();
|
||||
|
||||
@Connector
|
||||
MarkPassing getMarkPassing();
|
||||
@Connector(messageKey="SpeedBefore", ordinal=0)
|
||||
SpeedWithBearing getSpeedBefore();
|
||||
@Connector(messageKey="SpeedAfter", ordinal=1)
|
||||
SpeedWithBearing getSpeedAfter();
|
||||
|
||||
@Connector(messageKey="Competitor")
|
||||
Competitor getCompetitor();
|
||||
@Statistic(messageKey="DirectionChange", resultDecimals=2, ordinal=2)
|
||||
Double getDirectionChangeInDegrees();
|
||||
|
||||
@Connector(messageKey="Speed", ordinal=1)
|
||||
Speed getSpeed();
|
||||
@Statistic(messageKey="RelativeScore", ordinal=3, resultDecimals=2)
|
||||
Double getRelativeRank();
|
||||
|
||||
@Connector(messageKey="SpeedTenSecondsBefore", ordinal=2)
|
||||
Speed getSpeedTenSecondsBefore();
|
||||
@Statistic(messageKey="AbsoluteRank", ordinal=4, resultDecimals=2)
|
||||
Double getAbsoluteRank();
|
||||
|
||||
@Dimension(messageKey="LegType", ordinal=6)
|
||||
String getPreviousLegTypeSignifier() throws NoWindException;
|
||||
|
||||
@Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible
|
||||
public String getCompetitorSearchTag();
|
||||
}
|
||||
+39
-15
@@ -2,10 +2,13 @@ package com.sap.sailing.datamining.data;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
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 {
|
||||
|
||||
@@ -18,34 +21,55 @@ public interface HasRaceOfCompetitorContext {
|
||||
@Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible
|
||||
public String getCompetitorSearchTag();
|
||||
|
||||
@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();
|
||||
|
||||
@Connector(messageKey="SpeedWhenStarting", ordinal=2)
|
||||
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLine", resultDecimals=2, ordinal=2)
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStart();
|
||||
|
||||
@Connector(messageKey="SpeedWhenStarting", ordinal=3)
|
||||
public Speed getSpeedWhenStarting();
|
||||
|
||||
@Connector(messageKey="SpeedTenSecondsBeforeStart", ordinal=3)
|
||||
@Connector(messageKey="SpeedTenSecondsBeforeStart", ordinal=4)
|
||||
public Speed getSpeedTenSecondsBeforeStart();
|
||||
|
||||
@Statistic(messageKey="RankAtFirstMark", resultDecimals=2, ordinal=4)
|
||||
public Double getRankAtFirstMark();
|
||||
@Connector(messageKey="SpeedTenSecondsAfterStart", ordinal=5)
|
||||
public Speed getSpeedTenSecondsAfterStart();
|
||||
|
||||
@Statistic(messageKey="NumberOfManeuvers", resultDecimals=0, ordinal=5)
|
||||
public int getNumberOfManeuvers();
|
||||
|
||||
@Statistic(messageKey="NumberOfTacks", resultDecimals=2, ordinal=6)
|
||||
public int getNumberOfTacks();
|
||||
|
||||
@Statistic(messageKey="NumberOfJibes", resultDecimals=2, ordinal=7)
|
||||
public int getNumberOfJibes();
|
||||
|
||||
@Statistic(messageKey="NumberOfPenaltyCircles", resultDecimals=2, ordinal=8)
|
||||
public int getNumberOfPenaltyCircles();
|
||||
@Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=6)
|
||||
public Double getRankThirtySecondsAfterStart();
|
||||
|
||||
@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=9)
|
||||
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish();
|
||||
|
||||
@Statistic(messageKey="NumberOfManeuvers", resultDecimals=0, ordinal=10)
|
||||
public int getNumberOfManeuvers();
|
||||
|
||||
@Statistic(messageKey="NumberOfTacks", resultDecimals=2, ordinal=11)
|
||||
public int getNumberOfTacks();
|
||||
|
||||
@Statistic(messageKey="NumberOfJibes", resultDecimals=2, ordinal=12)
|
||||
public int getNumberOfJibes();
|
||||
|
||||
@Statistic(messageKey="NumberOfPenaltyCircles", resultDecimals=2, ordinal=13)
|
||||
public int getNumberOfPenaltyCircles();
|
||||
|
||||
}
|
||||
+8
-8
@@ -12,24 +12,24 @@ public interface HasRaceResultOfCompetitorContext {
|
||||
|
||||
@Connector(messageKey="Competitor")
|
||||
public Competitor getCompetitor();
|
||||
|
||||
@Dimension(messageKey="Regatta")
|
||||
String getRegattaName();
|
||||
|
||||
@Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible
|
||||
public String getCompetitorSearchTag();
|
||||
|
||||
@Dimension(messageKey="WindSpeedInBeaufort")
|
||||
int getAverageWindSpeedInRoundedBeaufort();
|
||||
|
||||
/**
|
||||
* 0 means the competitor won the race, 1 means the competitor ranked last
|
||||
*/
|
||||
@Statistic(messageKey="RelativeScore", ordinal=1, resultDecimals=2)
|
||||
public double getRelativeRank();
|
||||
public Double getRelativeRank();
|
||||
|
||||
@Statistic(messageKey="AbsoluteRank", ordinal=2, resultDecimals=2)
|
||||
public double getAbsoluteRank();
|
||||
|
||||
@Dimension(messageKey="WindSpeedInBeaufort")
|
||||
int getAverageWindSpeedInRoundedBeaufort();
|
||||
|
||||
@Dimension(messageKey="Regatta")
|
||||
String getRegattaName();
|
||||
public Double getAbsoluteRank();
|
||||
|
||||
@Statistic(messageKey="NumberOfPodiumFinish", ordinal=3)
|
||||
public Boolean isPodiumFinish();
|
||||
|
||||
+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);
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.sap.sailing.datamining.impl.components;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasManeuverContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.impl.data.ManeuverWithContext;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
|
||||
|
||||
public class ManeuverRetrievalProcessor extends AbstractRetrievalProcessor<HasTrackedLegOfCompetitorContext, HasManeuverContext> {
|
||||
|
||||
public ManeuverRetrievalProcessor(ExecutorService executor, Collection<Processor<HasManeuverContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(HasTrackedLegOfCompetitorContext.class, HasManeuverContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<HasManeuverContext> retrieveData(HasTrackedLegOfCompetitorContext element) {
|
||||
Collection<HasManeuverContext> maneuversWithContext = new ArrayList<>();
|
||||
TimePoint finishTime = element.getTrackedLegOfCompetitor().getFinishTime();
|
||||
if (finishTime != null) {
|
||||
try {
|
||||
List<Maneuver> maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false);
|
||||
for (Maneuver maneuver : maneuvers) {
|
||||
maneuversWithContext.add(new ManeuverWithContext(element, maneuver));
|
||||
}
|
||||
} catch (NoWindException e) {
|
||||
throw new IllegalStateException("No wind retrieving the maneuvers", e);
|
||||
}
|
||||
}
|
||||
return maneuversWithContext;
|
||||
}
|
||||
|
||||
}
|
||||
+23
-24
@@ -1,46 +1,45 @@
|
||||
package com.sap.sailing.datamining.impl.components;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasMarkPassingContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.impl.data.MarkPassingWithContext;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.MarkPassingManeuver;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
|
||||
|
||||
public class MarkPassingRetrievalProcessor extends AbstractRetrievalProcessor<HasTrackedRaceContext, HasMarkPassingContext> {
|
||||
public class MarkPassingRetrievalProcessor extends AbstractRetrievalProcessor<HasTrackedLegOfCompetitorContext, HasMarkPassingContext> {
|
||||
|
||||
public MarkPassingRetrievalProcessor(ExecutorService executor,
|
||||
Collection<Processor<HasMarkPassingContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(HasTrackedRaceContext.class, HasMarkPassingContext.class, executor, resultReceivers, retrievalLevel);
|
||||
super(HasTrackedLegOfCompetitorContext.class, HasMarkPassingContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<HasMarkPassingContext> retrieveData(HasTrackedRaceContext element) {
|
||||
TrackedRace trackedRace = element.getTrackedRace();
|
||||
Set<HasMarkPassingContext> result = new HashSet<>();
|
||||
trackedRace.getRace().getCourse().lockForRead();
|
||||
try {
|
||||
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
||||
NavigableSet<MarkPassing> markPassingsForCompetitor = trackedRace.getMarkPassings(competitor);
|
||||
trackedRace.lockForRead(markPassingsForCompetitor);
|
||||
try {
|
||||
markPassingsForCompetitor.stream().forEach(mp->result.add(new MarkPassingWithContext(element, mp)));
|
||||
} finally {
|
||||
trackedRace.unlockAfterRead(markPassingsForCompetitor);
|
||||
protected Iterable<HasMarkPassingContext> retrieveData(HasTrackedLegOfCompetitorContext element) {
|
||||
Collection<HasMarkPassingContext> maneuversWithContext = new ArrayList<>();
|
||||
TimePoint finishTime = element.getTrackedLegOfCompetitor().getFinishTime();
|
||||
if (finishTime != null) {
|
||||
try {
|
||||
List<Maneuver> maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false);
|
||||
for (Maneuver maneuver : maneuvers) {
|
||||
if (maneuver.getType() == ManeuverType.MARK_PASSING) {
|
||||
maneuversWithContext.add(new MarkPassingWithContext(element, (MarkPassingManeuver) maneuver));
|
||||
}
|
||||
}
|
||||
} catch (NoWindException e) {
|
||||
throw new IllegalStateException("No wind retrieving the mark passings", e);
|
||||
}
|
||||
} finally {
|
||||
trackedRace.getRace().getCourse().unlockAfterRead();
|
||||
}
|
||||
return result;
|
||||
return maneuversWithContext;
|
||||
}
|
||||
|
||||
}
|
||||
+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;
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasManeuverContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
|
||||
public class ManeuverWithContext implements HasManeuverContext {
|
||||
|
||||
private final HasTrackedLegOfCompetitorContext trackedLegOfCompetitor;
|
||||
private final Maneuver maneuver;
|
||||
|
||||
public ManeuverWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, Maneuver maneuver) {
|
||||
this.trackedLegOfCompetitor = trackedLegOfCompetitor;
|
||||
this.maneuver = maneuver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext() {
|
||||
return trackedLegOfCompetitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maneuver getManeuver() {
|
||||
return maneuver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManeuverType getManeuverType() {
|
||||
return getManeuver().getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tack getTack() {
|
||||
return getManeuver().getNewTack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedBefore() {
|
||||
return getManeuver().getSpeedWithBearingBefore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedAfter() {
|
||||
return getManeuver().getSpeedWithBearingAfter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getDirectionChangeInDegrees() {
|
||||
return getManeuver().getDirectionChangeInDegrees();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getManeuverLoss() {
|
||||
return getManeuver().getManeuverLoss();
|
||||
}
|
||||
|
||||
}
|
||||
+62
-54
@@ -1,79 +1,87 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasMarkPassingContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.common.NauticalSide;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.tracking.MarkPassingManeuver;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class MarkPassingWithContext implements HasMarkPassingContext {
|
||||
private final HasTrackedRaceContext trackedRaceContext;
|
||||
private final MarkPassing markPassing;
|
||||
|
||||
public MarkPassingWithContext(HasTrackedRaceContext trackedRaceContext, MarkPassing markPassing) {
|
||||
super();
|
||||
this.trackedRaceContext = trackedRaceContext;
|
||||
this.markPassing = markPassing;
|
||||
private final HasTrackedLegOfCompetitorContext trackedLegOfCompetitor;
|
||||
private final MarkPassingManeuver maneuver;
|
||||
|
||||
private Double absoluteRank;
|
||||
private boolean rankHasBeenInitialized;
|
||||
|
||||
public MarkPassingWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, MarkPassingManeuver maneuver) {
|
||||
this.trackedLegOfCompetitor = trackedLegOfCompetitor;
|
||||
this.maneuver = maneuver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HasTrackedRaceContext getTrackedRaceContext() {
|
||||
return trackedRaceContext;
|
||||
public HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext() {
|
||||
return trackedLegOfCompetitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkPassing getMarkPassing() {
|
||||
return markPassing;
|
||||
public MarkPassingManeuver getManeuver() {
|
||||
return maneuver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Competitor getCompetitor() {
|
||||
return markPassing.getCompetitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCompetitorSearchTag() {
|
||||
return getCompetitor().getSearchTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getSpeed() {
|
||||
return getTrackedRace().getTrack(getCompetitor()).getEstimatedSpeed(getMarkPassing().getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getSpeedTenSecondsBefore() {
|
||||
return getTrackedRace().getTrack(getCompetitor()).getEstimatedSpeed(getMarkPassing().getTimePoint().minus(10000 /* ms */));
|
||||
}
|
||||
|
||||
private TrackedRace getTrackedRace() {
|
||||
return trackedRaceContext.getTrackedRace();
|
||||
public Tack getTack() {
|
||||
return getManeuver().getNewTack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreviousLegTypeSignifier() throws NoWindException {
|
||||
final String result;
|
||||
TrackedLeg previousLeg = getPreviousLeg();
|
||||
if (previousLeg == null) {
|
||||
result = "Start";
|
||||
} else {
|
||||
result = previousLeg.getLegType(getMarkPassing().getTimePoint()).toString();
|
||||
}
|
||||
return result;
|
||||
public Waypoint getWaypoint() {
|
||||
return getManeuver().getWaypointPassed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NauticalSide getPassingSide() {
|
||||
return getManeuver().getSide();
|
||||
}
|
||||
|
||||
private TrackedLeg getPreviousLeg() {
|
||||
final TrackedLeg result;
|
||||
Waypoint waypoint = markPassing.getWaypoint();
|
||||
if (waypoint == getTrackedRace().getRace().getCourse().getFirstWaypoint()) {
|
||||
result = null;
|
||||
} else {
|
||||
result = getTrackedRace().getTrackedLegFinishingAt(waypoint);
|
||||
}
|
||||
return result;
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedBefore() {
|
||||
return getManeuver().getSpeedWithBearingBefore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedAfter() {
|
||||
return getManeuver().getSpeedWithBearingAfter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getDirectionChangeInDegrees() {
|
||||
return getManeuver().getDirectionChangeInDegrees();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRelativeRank() {
|
||||
Leaderboard leaderboard = getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext().getLeaderboardContext().getLeaderboard();
|
||||
double competitorCount = Util.size(leaderboard.getCompetitors());
|
||||
return getAbsoluteRank() == null ? null : getAbsoluteRank() / competitorCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getAbsoluteRank() {
|
||||
if (!rankHasBeenInitialized) {
|
||||
TrackedRace trackedRace = getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
|
||||
Competitor competitor = getTrackedLegOfCompetitorContext().getCompetitor();
|
||||
int rank = trackedRace.getRank(competitor, getManeuver().getTimePoint());
|
||||
absoluteRank = rank == 0 ? null : Double.valueOf(rank);
|
||||
rankHasBeenInitialized = true;
|
||||
}
|
||||
return absoluteRank;
|
||||
}
|
||||
|
||||
}
|
||||
+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) + "%";
|
||||
}
|
||||
|
||||
}
|
||||
+130
-22
@@ -2,18 +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 {
|
||||
|
||||
@@ -44,11 +58,83 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
return getCompetitor().getSearchTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tack getTackAtStart() throws NoWindException {
|
||||
TimePoint startOfRace = getTrackedRace().getStartOfRace();
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getNormalizedDistanceToStarboardSideAtStart() {
|
||||
TrackedRace trackedRace = getTrackedRace();
|
||||
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, trackedRace.getRace().getCourse().getFirstLeg());
|
||||
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
|
||||
if (competitorStartTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Double distance = trackedRace.getDistanceFromStarboardSideOfStartLine(getCompetitor(), competitorStartTime).getMeters();
|
||||
Double length = trackedRace.getStartLine(competitorStartTime).getLength().getMeters();
|
||||
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());
|
||||
@@ -59,14 +145,57 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
return getTrackedRace().getSpeed(getCompetitor(), TimeUnit.SECONDS.toMillis(10));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getSpeedTenSecondsAfterStart() {
|
||||
TimePoint startOfRace = getTrackedRace().getStartOfRace();
|
||||
if (startOfRace == null) {
|
||||
return null;
|
||||
}
|
||||
return getTrackedRace().getTrack(getCompetitor()).getEstimatedSpeed(startOfRace.plus(TimeUnit.SECONDS.toMillis(10)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRankThirtySecondsAfterStart() {
|
||||
TimePoint startOfRace = getTrackedRace().getStartOfRace();
|
||||
if (startOfRace == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int rank = getTrackedRace().getRank(getCompetitor(), startOfRace.plus(TimeUnit.SECONDS.toMillis(30)));
|
||||
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();
|
||||
Waypoint firstMark = course.getFirstLeg().getTo();
|
||||
Competitor competitor = getCompetitor();
|
||||
return Double.valueOf(getTrackedRace().getRank(competitor, getTrackedRace().getMarkPassing(competitor, firstMark).getTimePoint()));
|
||||
int rank = getTrackedRace().getRank(competitor, getTrackedRace().getMarkPassing(competitor, firstMark).getTimePoint());
|
||||
return rank == 0 ? null : Double.valueOf(rank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish() {
|
||||
Double rankAtFirstMark = getRankAtFirstMark();
|
||||
Double rankAtFinish = getTrackedRaceContext().getRankAtFinishForCompetitor(getCompetitor());
|
||||
return rankAtFirstMark != null && rankAtFinish != null ? rankAtFirstMark - rankAtFinish : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfManeuvers() {
|
||||
return getNumberOfTacks() + getNumberOfJibes();
|
||||
@@ -97,26 +226,5 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish() {
|
||||
Double rankAtFirstMark = getRankAtFirstMark();
|
||||
Double rankAtFinish = getRankAtFinish();
|
||||
return rankAtFirstMark - rankAtFinish;
|
||||
}
|
||||
|
||||
private Double getRankAtFinish() {
|
||||
return Double.valueOf(getTrackedRace().getRank(getCompetitor(), getTrackedRace().getEndOfTracking()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getNormalizedDistanceToStarboardSideAtStart() {
|
||||
TrackedRace trackedRace = getTrackedRace();
|
||||
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, trackedRace.getRace().getCourse().getFirstLeg());
|
||||
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
|
||||
Double distance = trackedRace.getDistanceFromStarboardSideOfStartLine(getCompetitor(), competitorStartTime).getMeters();
|
||||
Double length = trackedRace.getStartLine(competitorStartTime).getLength().getMeters();
|
||||
return distance / length;
|
||||
}
|
||||
|
||||
}
|
||||
+23
-24
@@ -62,29 +62,15 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCompetitorSearchTag() {
|
||||
return getCompetitor().getSearchTag();
|
||||
public String getRegattaName() {
|
||||
Leaderboard leaderboard = getLeaderboard();;
|
||||
final String result = leaderboard.getName();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getRelativeRank() {
|
||||
Leaderboard leaderboard = getLeaderboard();
|
||||
final TimePoint now = MillisecondsTimePoint.now();
|
||||
double competitorCount = Util.size(leaderboard.getCompetitors());
|
||||
double points = leaderboard.getTotalPoints(competitor, raceColumn, now);
|
||||
double relativeLowPoints = leaderboard.getScoringScheme().isHigherBetter() ?
|
||||
competitorCount - points : points;
|
||||
final double result = relativeLowPoints / competitorCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAbsoluteRank() {
|
||||
try {
|
||||
return getLeaderboard().getTotalRankOfCompetitor(competitor, MillisecondsTimePoint.now());
|
||||
} catch (NoWindException e) {
|
||||
throw new IllegalStateException("No wind calculating the absoulte rank", e);
|
||||
}
|
||||
public String getCompetitorSearchTag() {
|
||||
return getCompetitor().getSearchTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,10 +157,23 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRegattaName() {
|
||||
Leaderboard leaderboard = getLeaderboard();;
|
||||
final String result = leaderboard.getName();
|
||||
return result;
|
||||
public Double getRelativeRank() {
|
||||
Leaderboard leaderboard = getLeaderboard();
|
||||
final TimePoint now = MillisecondsTimePoint.now();
|
||||
double competitorCount = Util.size(leaderboard.getCompetitors());
|
||||
Double points = leaderboard.getTotalPoints(competitor, raceColumn, now);
|
||||
if (points != null) {
|
||||
double relativeLowPoints = leaderboard.getScoringScheme().isHigherBetter() ? competitorCount - points
|
||||
: points;
|
||||
final double result = relativeLowPoints / competitorCount;
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getAbsoluteRank() {
|
||||
return getLeaderboard().getTotalPoints(competitor, raceColumn, MillisecondsTimePoint.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+42
-6
@@ -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 {
|
||||
|
||||
@@ -18,7 +22,9 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
|
||||
private final Competitor competitor;
|
||||
|
||||
private Double rankAtStart;
|
||||
private boolean isRankAtStartInitialized;
|
||||
private Double rankAtFinish;
|
||||
private boolean isRankAtFinishInitialized;
|
||||
|
||||
public TrackedLegOfCompetitorWithContext(HasTrackedLegContext trackedLegContext, TrackedLegOfCompetitor trackedLegOfCompetitor) {
|
||||
this.trackedLegContext = trackedLegContext;
|
||||
@@ -46,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();
|
||||
@@ -54,13 +72,17 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
|
||||
|
||||
@Override
|
||||
public Double getRankGainsOrLosses() {
|
||||
return getRankAtStart() - getRankAtFinish();
|
||||
Double rankAtStart = getRankAtStart();
|
||||
Double rankAtFinish = getRankAtFinish();
|
||||
return rankAtStart != null && rankAtFinish != null ? rankAtStart - rankAtFinish : null;
|
||||
}
|
||||
|
||||
private Double getRankAtStart() {
|
||||
if (rankAtStart == null) {
|
||||
if (!isRankAtStartInitialized) {
|
||||
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
|
||||
rankAtStart = Double.valueOf(trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getStartTime()));
|
||||
int rank = trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getStartTime());
|
||||
rankAtStart = rank == 0 ? null : Double.valueOf(rank);
|
||||
isRankAtStartInitialized = true;
|
||||
}
|
||||
return rankAtStart;
|
||||
}
|
||||
@@ -69,7 +91,8 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
|
||||
public Double getRelativeRank() {
|
||||
Leaderboard leaderboard = getTrackedLegContext().getTrackedRaceContext().getLeaderboardContext().getLeaderboard();
|
||||
double competitorCount = Util.size(leaderboard.getCompetitors());
|
||||
return getRankAtFinish() / competitorCount;
|
||||
Double rankAtFinish = getRankAtFinish();
|
||||
return rankAtFinish == null ? null : rankAtFinish / competitorCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,11 +101,24 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
|
||||
}
|
||||
|
||||
private Double getRankAtFinish() {
|
||||
if (rankAtStart == null) {
|
||||
if (!isRankAtFinishInitialized) {
|
||||
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
|
||||
rankAtFinish = Double.valueOf(trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getFinishTime()));
|
||||
int rank = trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getFinishTime());
|
||||
rankAtFinish = rank == 0 ? null : Double.valueOf(rank);
|
||||
isRankAtFinishInitialized = true;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
+10
-10
@@ -113,20 +113,20 @@ public enum BoatClassMasterdata {
|
||||
|
||||
private final String displayName;
|
||||
private final String[] alternativeNames;
|
||||
private final double hullLengthInMeter;
|
||||
private final double hullBeamInMeter;
|
||||
private final double hullLengthInMeters;
|
||||
private final double hullBeamInMeters;
|
||||
private final BoatHullType hullType;
|
||||
private final boolean typicallyStartsUpwind;
|
||||
private final boolean hasAdditionalDownwindSail;
|
||||
|
||||
private static Map<String, BoatClassMasterdata> fromUnifiedDisplayAndAlternativeNamesToBoatClassMasterdata;
|
||||
|
||||
private BoatClassMasterdata(String displayName, boolean typicallyStartsUpwind, double hullLengthInMeter,
|
||||
double hullBeamInMeter, BoatHullType hullType, boolean hasAdditionalDownwindSail, String... alternativeNames) {
|
||||
private BoatClassMasterdata(String displayName, boolean typicallyStartsUpwind, double hullLengthInMeters,
|
||||
double hullBeamInMeters, BoatHullType hullType, boolean hasAdditionalDownwindSail, String... alternativeNames) {
|
||||
this.displayName = displayName;
|
||||
this.typicallyStartsUpwind = typicallyStartsUpwind;
|
||||
this.hullLengthInMeter = hullLengthInMeter;
|
||||
this.hullBeamInMeter = hullBeamInMeter;
|
||||
this.hullLengthInMeters = hullLengthInMeters;
|
||||
this.hullBeamInMeters = hullBeamInMeters;
|
||||
this.hullType = hullType;
|
||||
this.hasAdditionalDownwindSail = hasAdditionalDownwindSail;
|
||||
this.alternativeNames = alternativeNames;
|
||||
@@ -147,8 +147,8 @@ public enum BoatClassMasterdata {
|
||||
double hullBeamInMeter, BoatHullType hullType, boolean hasAdditionalDownwindSail) {
|
||||
this.displayName = displayName;
|
||||
this.typicallyStartsUpwind = typicallyStartsUpwind;
|
||||
this.hullLengthInMeter = hullLengthInMeter;
|
||||
this.hullBeamInMeter = hullBeamInMeter;
|
||||
this.hullLengthInMeters = hullLengthInMeter;
|
||||
this.hullBeamInMeters = hullBeamInMeter;
|
||||
this.hullType = hullType;
|
||||
this.hasAdditionalDownwindSail = hasAdditionalDownwindSail;
|
||||
this.alternativeNames = null;
|
||||
@@ -192,7 +192,7 @@ public enum BoatClassMasterdata {
|
||||
}
|
||||
|
||||
public Distance getHullLength() {
|
||||
return new MeterDistance(hullLengthInMeter);
|
||||
return new MeterDistance(hullLengthInMeters);
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
@@ -204,7 +204,7 @@ public enum BoatClassMasterdata {
|
||||
}
|
||||
|
||||
public Distance getHullBeam() {
|
||||
return new MeterDistance(hullBeamInMeter);
|
||||
return new MeterDistance(hullBeamInMeters);
|
||||
}
|
||||
|
||||
public BoatHullType getHullType() {
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.sap.sse.common.Duration;
|
||||
*
|
||||
*/
|
||||
public interface Distance extends Comparable<Distance>, Serializable {
|
||||
static final Distance NULL = new Distance() {
|
||||
static class NullDistance implements Distance {
|
||||
private static final long serialVersionUID = -3167560884686340893L;
|
||||
|
||||
@Override
|
||||
@@ -96,7 +96,9 @@ public interface Distance extends Comparable<Distance>, Serializable {
|
||||
public Distance abs() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static final NullDistance NULL = new NullDistance();
|
||||
|
||||
double getGeographicalMiles();
|
||||
|
||||
|
||||
@@ -17,6 +17,11 @@ public class RegattaName implements RegattaIdentifier {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getRegattaName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRegatta(RegattaFetcher regattaFetcher) {
|
||||
return regattaFetcher.getRegatta(this);
|
||||
|
||||
+9
-7
@@ -2,6 +2,8 @@ package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
|
||||
public class BoatClassDTO extends NamedDTO implements Serializable, Comparable<BoatClassDTO> {
|
||||
private static final long serialVersionUID = 1981789833769906676L;
|
||||
|
||||
@@ -11,24 +13,24 @@ public class BoatClassDTO extends NamedDTO implements Serializable, Comparable<B
|
||||
*/
|
||||
public static final String DEFAULT_NAME = "Default";
|
||||
|
||||
private double hullLengthInMeters;
|
||||
private Distance hullLength;
|
||||
private String displayName;
|
||||
|
||||
BoatClassDTO() {}
|
||||
|
||||
public BoatClassDTO(String name, String displayName, double hullLengthInMeters) {
|
||||
public BoatClassDTO(String name, String displayName, Distance hullLength) {
|
||||
super(name);
|
||||
this.hullLengthInMeters = hullLengthInMeters;
|
||||
this.hullLength = hullLength;
|
||||
}
|
||||
|
||||
public BoatClassDTO(String name, double hullLengthInMeters) {
|
||||
public BoatClassDTO(String name, Distance hullLength) {
|
||||
super(name);
|
||||
this.hullLengthInMeters = hullLengthInMeters;
|
||||
this.hullLength = hullLength;
|
||||
this.displayName = null;
|
||||
}
|
||||
|
||||
public double getHullLengthInMeters() {
|
||||
return hullLengthInMeters;
|
||||
public Distance getHullLength() {
|
||||
return hullLength;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
|
||||
+49
@@ -3,10 +3,13 @@ package com.sap.sailing.domain.common.dto;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
|
||||
/**
|
||||
* Holds a single competitor's scoring details for a single race. It may optionally contain
|
||||
@@ -78,6 +81,8 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
*/
|
||||
public Duration averageSamplingInterval;
|
||||
|
||||
public Double averageRideHeightInMeters;
|
||||
|
||||
/**
|
||||
* The time gap to the competitor leading the race; for one-design races this is the time the competitor is expected
|
||||
* to need to reach the leader's (windward) position (if in the same leg) or the difference between the time at
|
||||
@@ -132,6 +137,44 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
public boolean hasScoreCorrection() {
|
||||
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() {
|
||||
@@ -174,6 +217,7 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
result = prime * result
|
||||
+ ((speedOverGroundAtStartOfRaceInKnots == null) ? 0 : speedOverGroundAtStartOfRaceInKnots.hashCode());
|
||||
result = prime * result + ((startTack == null) ? 0 : startTack.hashCode());
|
||||
result = prime * result + ((averageRideHeightInMeters == null) ? 0 : averageRideHeightInMeters.hashCode());
|
||||
result = prime * result + ((averageSamplingInterval == null) ? 0 : averageSamplingInterval.hashCode());
|
||||
result = prime * result + ((timeSinceLastPositionFixInSeconds == null) ? 0 : timeSinceLastPositionFixInSeconds.hashCode());
|
||||
result = prime * result + ((netPoints == null) ? 0 : netPoints.hashCode());
|
||||
@@ -282,6 +326,11 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
return false;
|
||||
if (startTack != other.startTack)
|
||||
return false;
|
||||
if (averageRideHeightInMeters == null) {
|
||||
if (other.averageRideHeightInMeters != null)
|
||||
return false;
|
||||
} else if (!averageRideHeightInMeters.equals(other.averageRideHeightInMeters))
|
||||
return false;
|
||||
if (averageSamplingInterval == null) {
|
||||
if (other.averageSamplingInterval != null)
|
||||
return false;
|
||||
|
||||
+25
@@ -4,6 +4,9 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* Holds data about one competitor and all races represented by the owning {@link LeaderboardDTO leaderboard}.
|
||||
*
|
||||
@@ -117,6 +120,28 @@ public class LeaderboardRowDTO implements Serializable {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Distance getDistanceTraveledInMeters(String raceColumnName) {
|
||||
final Distance result;
|
||||
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.getDistanceTraveledInMeters();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Duration getTimeSailed(String raceColumnName) {
|
||||
final Duration result;
|
||||
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.getTimeSailedInMillis();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LeaderboardRowDTO for competitor "+competitor;
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.domain.common.tracking;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
|
||||
/**
|
||||
* Specific {@link SensorFix} for bravo devices (http://www.bravosystems.es/).
|
||||
*
|
||||
@@ -12,5 +14,5 @@ public interface BravoFix extends SensorFix {
|
||||
*
|
||||
* @return the ride height
|
||||
*/
|
||||
double getRideHeight();
|
||||
Distance getRideHeight();
|
||||
}
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.domain.common.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
@@ -32,8 +34,8 @@ public class BravoFixImpl implements BravoFix {
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getRideHeight() {
|
||||
return fix.get(BravoSensorDataMetadata.INSTANCE.rideHeightColumn);
|
||||
public Distance getRideHeight() {
|
||||
return new MeterDistance(fix.get(BravoSensorDataMetadata.INSTANCE.rideHeightColumn));
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -1144,11 +1144,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
logger.log(Level.WARNING, "Error loading racing procedure configration for regatta.", e);
|
||||
}
|
||||
}
|
||||
final Double buoyZoneRadiusInHullLengths = (Double) dbRegatta.get(FieldNames.REGATTA_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS.name());
|
||||
final Boolean useStartTimeInference = (Boolean) dbRegatta.get(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name());
|
||||
final Boolean controlTrackingFromStartAndFinishTimes = (Boolean) dbRegatta.get(FieldNames.REGATTA_CONTROL_TRACKING_FROM_START_AND_FINISH_TIMES.name());
|
||||
final RankingMetricConstructor rankingMetricConstructor = loadRankingMetricConstructor(dbRegatta);
|
||||
result = new RegattaImpl(getRaceLogStore(), getRegattaLogStore(), name, boatClass, startDate, endDate, series, /* persistent */true,
|
||||
loadScoringScheme(dbRegatta), id, courseArea, useStartTimeInference == null ? true
|
||||
loadScoringScheme(dbRegatta), id, courseArea, buoyZoneRadiusInHullLengths == null ? Regatta.DEFAULT_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS : buoyZoneRadiusInHullLengths, useStartTimeInference == null ? true
|
||||
: useStartTimeInference, controlTrackingFromStartAndFinishTimes == null ? false : controlTrackingFromStartAndFinishTimes,
|
||||
rankingMetricConstructor);
|
||||
result.setRegattaConfiguration(configuration);
|
||||
|
||||
+1
@@ -34,6 +34,7 @@ public enum FieldNames {
|
||||
REGATTA_END_DATE,
|
||||
REGATTA_SERIES,
|
||||
REGATTA_REGATTA_CONFIGURATION,
|
||||
REGATTA_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS,
|
||||
REGATTA_USE_START_TIME_INFERENCE,
|
||||
REGATTA_CONTROL_TRACKING_FROM_START_AND_FINISH_TIMES,
|
||||
SERIES_NAME,
|
||||
|
||||
+1
@@ -646,6 +646,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
DBObject configurationObject = (DBObject) JSON.parse(json.toString());
|
||||
dbRegatta.put(FieldNames.REGATTA_REGATTA_CONFIGURATION.name(), configurationObject);
|
||||
}
|
||||
dbRegatta.put(FieldNames.REGATTA_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS.name(), regatta.getBuoyZoneRadiusInHullLengths());
|
||||
dbRegatta.put(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name(), regatta.useStartTimeInference());
|
||||
dbRegatta.put(FieldNames.REGATTA_CONTROL_TRACKING_FROM_START_AND_FINISH_TIMES.name(), regatta.isControlTrackingFromStartAndFinishTimes());
|
||||
dbRegatta.put(FieldNames.REGATTA_RANKING_METRIC.name(), storeRankingMetric(regatta));
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ public class CreateAndTrackWithRaceLogTest {
|
||||
service);
|
||||
regatta = service.createRegatta(RegattaImpl.getDefaultName("regatta", "Laser"), "Laser",
|
||||
/* startDate */null, /* endDate */null, UUID.randomUUID(), Collections.<Series> singletonList(series), false,
|
||||
new HighPoint(), UUID.randomUUID(), /* useStartTimeInference */true, /* controlTrackingFromStartAndFinishTimes */ false, OneDesignRankingMetric::new);
|
||||
new HighPoint(), UUID.randomUUID(), /*buoyZoneRadiusInHullLengths*/2.0, /* useStartTimeInference */true, /* controlTrackingFromStartAndFinishTimes */ false, OneDesignRankingMetric::new);
|
||||
series.addRaceColumn(columnName, /* trackedRegattaRegistry */null);
|
||||
leaderboard = service.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "RegattaLeaderboard", new int[] {});
|
||||
adapter = RaceLogTrackingAdapterFactory.INSTANCE.getAdapter(DomainFactory.INSTANCE);
|
||||
|
||||
+8
-12
@@ -49,9 +49,11 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
@@ -95,9 +97,9 @@ public class SensorFixStoreAndLoadTest {
|
||||
private static final long FIX_TIMESTAMP2 = 120;
|
||||
private static final long FIX_TIMESTAMP3 = 210;
|
||||
private static final long AFTER_LAST_FIX = FIX_TIMESTAMP3 + 1;
|
||||
private static final double FIX_RIDE_HEIGHT = 1337.0;
|
||||
private static final double FIX_RIDE_HEIGHT2 = 1338.0;
|
||||
private static final double FIX_RIDE_HEIGHT3 = 1336.0;
|
||||
private static final Distance FIX_RIDE_HEIGHT = new MeterDistance(1337.0);
|
||||
private static final Distance FIX_RIDE_HEIGHT2 = new MeterDistance(1338.0);
|
||||
private static final Distance FIX_RIDE_HEIGHT3 = new MeterDistance(1336.0);
|
||||
private static final double FIX_TEST_VALUE = 12.0;
|
||||
protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory();
|
||||
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
|
||||
@@ -384,20 +386,14 @@ public class SensorFixStoreAndLoadTest {
|
||||
public void testBravoFixIsCorrectlyWrapped() throws InterruptedException {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
BravoFixTrack<Competitor> bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
|
||||
assertEquals(FIX_RIDE_HEIGHT,
|
||||
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP)).getRideHeight());
|
||||
|
||||
fixLoaderAndTracker.stop(true);
|
||||
}
|
||||
|
||||
@@ -482,9 +478,9 @@ public class SensorFixStoreAndLoadTest {
|
||||
}
|
||||
|
||||
private void addBravoFixes() {
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP, FIX_RIDE_HEIGHT));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP3, FIX_RIDE_HEIGHT3));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP, FIX_RIDE_HEIGHT.getMeters()));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2.getMeters()));
|
||||
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP3, FIX_RIDE_HEIGHT3.getMeters()));
|
||||
}
|
||||
|
||||
private FixLoaderAndTracker createFixLoaderAndTracker() {
|
||||
|
||||
+1
-1
@@ -250,7 +250,7 @@ public class TransientCompetitorStoreImpl implements CompetitorStore, Serializab
|
||||
c.getFlagImage() == null ? null : c.getFlagImage().toString(),
|
||||
new BoatDTO(c.getBoat().getName(), c.getBoat().getSailID(), c.getBoat().getColor()),
|
||||
new BoatClassDTO(c.getBoat().getBoatClass()
|
||||
.getName(), c.getBoat().getBoatClass().getDisplayName(), c.getBoat().getBoatClass().getHullLength().getMeters()),
|
||||
.getName(), c.getBoat().getBoatClass().getDisplayName(), c.getBoat().getBoatClass().getHullLength()),
|
||||
c.getTimeOnTimeFactor(), c.getTimeOnDistanceAllowancePerNauticalMile(), c.getSearchTag());
|
||||
weakCompetitorDTOCache.put(c, competitorDTO);
|
||||
}
|
||||
|
||||
+5
-4
@@ -35,6 +35,7 @@ import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
|
||||
import com.sap.sailing.domain.common.dto.LegEntryDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.test.StoredTrackBasedTest;
|
||||
import com.sap.sse.common.Cloner;
|
||||
import com.sap.sse.common.Color;
|
||||
@@ -234,7 +235,7 @@ public class LeaderboardDTODiffingTest {
|
||||
public void testCompetitorListChange() {
|
||||
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
|
||||
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
|
||||
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
|
||||
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", new MeterDistance(5.05)), /* timeOnTimeFactor */ null,
|
||||
/* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
newVersion.competitors.add(13, somebodyNew); // insert a competitor; this should mess up all others' indexes; check if this works
|
||||
CompetitorDTO wolfgang = getPreviousCompetitorByName("HUNGER +JESS");
|
||||
@@ -255,7 +256,7 @@ public class LeaderboardDTODiffingTest {
|
||||
newVersion.setSuppressedCompetitors(newSuppressedCompetitors);
|
||||
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
|
||||
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
|
||||
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
|
||||
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", new MeterDistance(5.05)), /* timeOnTimeFactor */ null,
|
||||
/* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
newVersion.setSuppressed(newVersion.competitors.get(13), true); // suppress an existing competitor; compaction should reduce this to a single number only
|
||||
newVersion.setSuppressed(somebodyNew, true); // check that mixed mode with existing and new competitors works as well
|
||||
@@ -278,7 +279,7 @@ public class LeaderboardDTODiffingTest {
|
||||
public void testDisplayNameChange() {
|
||||
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
|
||||
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
|
||||
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
|
||||
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", new MeterDistance(5.05)), /* timeOnTimeFactor */ null,
|
||||
/* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
newVersion.competitors.add(somebodyNew);
|
||||
newVersion.competitorDisplayNames = new HashMap<CompetitorDTO, String>(newVersion.competitorDisplayNames);
|
||||
@@ -308,7 +309,7 @@ public class LeaderboardDTODiffingTest {
|
||||
newVersion.setCompetitorsFromBestToWorst(r9, newOrdering);
|
||||
newVersion.competitors = new ArrayList<CompetitorDTO>(newVersion.competitors); // clone competitor list so it's not identical to that of previous version
|
||||
CompetitorDTO somebodyNew = new CompetitorDTOImpl("Someone New", Color.RED, "someone@nobody.de", "DE", "GER", "Germany", "912p09871203987",
|
||||
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", 5.05), /* timeOnTimeFactor */ null,
|
||||
/* imageURL */ null, /* flagImageURL */ null, new BoatDTO("LSC", "GER 1234"), new BoatClassDTO("505", new MeterDistance(5.05)), /* timeOnTimeFactor */ null,
|
||||
/* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
newVersion.competitors.add(somebodyNew);
|
||||
newOrdering.add(somebodyNew);
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
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.impl.NauticalMileDistance;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl;
|
||||
@@ -67,6 +68,12 @@ public class PositionTest {
|
||||
assertEquals(20004, Math.abs(southPole.getDistance(northPole).getKilometers()), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void radTest() {
|
||||
assertEquals(180, new MeterDistance(20005000).getCentralAngleDeg(), 0.01);
|
||||
assertEquals(Math.PI, new MeterDistance(20005000).getCentralAngleRad(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bearingTest() {
|
||||
// Note that the bearing is a bearing on a great circle!
|
||||
|
||||
+14
-3
@@ -447,6 +447,15 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getBuoyZoneRadiusInHullLengths(){
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBuoyZoneRadiusInHullLengths(Double buoyZoneRadiusInHullLengths){
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLikeIdentifier getRegattaLikeIdentifier() {
|
||||
return null;
|
||||
@@ -532,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
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1121,4 +1127,9 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
public Iterable<RaceLog> getAttachedRaceLogs() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+5
@@ -681,4 +681,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
public Iterable<RaceLog> getAttachedRaceLogs() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -82,8 +82,8 @@ public class BravoFixTrackSerializationTest {
|
||||
assertRideHeight(track, testFixData.timePoint, testFixData.rideHeight);
|
||||
}
|
||||
|
||||
private void assertRideHeight(BravoFixTrack<Competitor> track, TimePoint timePoint, double expected) {
|
||||
assertEquals(expected, track.getRideHeight(timePoint), 0.0);
|
||||
private void assertRideHeight(BravoFixTrack<Competitor> track, TimePoint timePoint, double expectedRideHeightInMeters) {
|
||||
assertEquals(expectedRideHeightInMeters, track.getRideHeight(timePoint).getMeters(), 0.0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -24,6 +24,9 @@ import com.sap.sse.common.TimePoint;
|
||||
*
|
||||
*/
|
||||
public interface Regatta extends NamedWithID, IsRegattaLike, HasRaceColumnsAndRegattaLike {
|
||||
|
||||
public static final double DEFAULT_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS = 2;
|
||||
|
||||
ScoringScheme getScoringScheme();
|
||||
|
||||
/**
|
||||
@@ -155,6 +158,14 @@ public interface Regatta extends NamedWithID, IsRegattaLike, HasRaceColumnsAndRe
|
||||
|
||||
RegattaAndRaceIdentifier getRaceIdentifier(RaceDefinition race);
|
||||
|
||||
/**
|
||||
* Define the value which would be multipled by hull length from {@link BoatClass}.
|
||||
* Next the calculated value {@link RegattaUtil} would be used to fill out radius of buoy on race map setting.
|
||||
*/
|
||||
public Double getBuoyZoneRadiusInHullLengths();
|
||||
|
||||
public void setBuoyZoneRadiusInHullLengths(Double buoyZoneRadiusInHullLengths);
|
||||
|
||||
/**
|
||||
* When there is no race committee app in place and no operator is managing the race start times for this regatta,
|
||||
* start times can optionally be inferred from the start mark passings by the {@link TrackedRace}s in this regatta.
|
||||
|
||||
@@ -115,6 +115,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
private transient RaceLogStore raceLogStore;
|
||||
private final IsRegattaLike regattaLikeHelper;
|
||||
private final RankingMetricConstructor rankingMetricConstructor;
|
||||
private Double buoyZoneRadiusInHullLengths;
|
||||
|
||||
private CourseArea defaultCourseArea;
|
||||
private RegattaConfiguration configuration;
|
||||
@@ -162,7 +163,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme, Serializable id,
|
||||
CourseArea courseArea, RankingMetricConstructor rankingMetricConstructor) {
|
||||
this(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, name, boatClass, startDate, endDate, series,
|
||||
persistent, scoringScheme, id, courseArea, /* useStartTimeInference */true, /* controlTrackingFromStartAndFinishTimes */ false,
|
||||
persistent, scoringScheme, id, courseArea, 0.0, /* useStartTimeInference */true, /* controlTrackingFromStartAndFinishTimes */ false,
|
||||
rankingMetricConstructor);
|
||||
}
|
||||
|
||||
@@ -204,7 +205,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
/* isMedal */false, /* isFleetsCanRunInParallel */ true, Collections
|
||||
.singletonList(new FleetImpl(LeaderboardNameConstants.DEFAULT_FLEET_NAME)),
|
||||
/* race column names */new ArrayList<String>(), trackedRegattaRegistry)), /* persistent */false,
|
||||
scoringScheme, id, courseArea, /* useStartTimeInference */true, controlTrackingFromStartAndFinishTimes,
|
||||
scoringScheme, id, courseArea, /*buoyZoneRadiusInHullLengths*/2.0, /* useStartTimeInference */true, controlTrackingFromStartAndFinishTimes,
|
||||
rankingMetricConstructor);
|
||||
}
|
||||
|
||||
@@ -215,7 +216,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
*/
|
||||
public <S extends Series> RegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String name,
|
||||
BoatClass boatClass, TimePoint startDate, TimePoint endDate, Iterable<S> series, boolean persistent,
|
||||
ScoringScheme scoringScheme, Serializable id, CourseArea courseArea, boolean useStartTimeInference,
|
||||
ScoringScheme scoringScheme, Serializable id, CourseArea courseArea, Double buoyZoneRadiusInHullLengths, boolean useStartTimeInference,
|
||||
boolean controlTrackingFromStartAndFinishTimes, RankingMetricConstructor rankingMetricConstructor) {
|
||||
super(name);
|
||||
this.rankingMetricConstructor = rankingMetricConstructor;
|
||||
@@ -241,6 +242,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
this.scoringScheme = scoringScheme;
|
||||
this.defaultCourseArea = courseArea;
|
||||
this.configuration = null;
|
||||
this.buoyZoneRadiusInHullLengths = buoyZoneRadiusInHullLengths;
|
||||
this.regattaLikeHelper = new BaseRegattaLikeImpl(new RegattaAsRegattaLikeIdentifier(this), regattaLogStore) {
|
||||
private static final long serialVersionUID = 8546222568682770206L;
|
||||
|
||||
@@ -572,6 +574,16 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getBuoyZoneRadiusInHullLengths() {
|
||||
return buoyZoneRadiusInHullLengths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBuoyZoneRadiusInHullLengths(Double buoyZoneRadiusInHullLengths) {
|
||||
this.buoyZoneRadiusInHullLengths = buoyZoneRadiusInHullLengths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return defaultCourseArea;
|
||||
|
||||
+6
-2
@@ -1437,6 +1437,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
} else {
|
||||
entryDTO.timeSinceLastPositionFixInSeconds = null;
|
||||
}
|
||||
final Distance averageRideHeight = trackedRace.getAverageRideHeight(competitor, timePoint);
|
||||
entryDTO.averageRideHeightInMeters = averageRideHeight == null ? null : averageRideHeight.getMeters();
|
||||
}
|
||||
if (addLegDetails && trackedRace != null) {
|
||||
try {
|
||||
@@ -1721,11 +1723,13 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
Double speedOverGroundInKnots;
|
||||
if (trackedLeg.hasFinishedLeg(timePoint)) {
|
||||
speedOverGroundInKnots = averageSpeedOverGround == null ? null : averageSpeedOverGround.getKnots();
|
||||
result.currentRideHeightInMeters = trackedLeg.getAverageRideHeight(timePoint);
|
||||
final Distance averageRideHeight = trackedLeg.getAverageRideHeight(timePoint);
|
||||
result.currentRideHeightInMeters = averageRideHeight == null ? null : averageRideHeight.getMeters();
|
||||
} else {
|
||||
final SpeedWithBearing speedOverGround = trackedLeg.getSpeedOverGround(timePoint);
|
||||
speedOverGroundInKnots = speedOverGround == null ? null : speedOverGround.getKnots();
|
||||
result.currentRideHeightInMeters = trackedLeg.getRideHeight(timePoint);
|
||||
final Distance rideHeight = trackedLeg.getRideHeight(timePoint);
|
||||
result.currentRideHeightInMeters = rideHeight == null ? null : rideHeight.getMeters();
|
||||
}
|
||||
result.currentSpeedOverGroundInKnots = speedOverGroundInKnots == null ? null : speedOverGroundInKnots;
|
||||
Distance distanceTraveled = trackedLeg.getDistanceTraveled(timePoint);
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.WithID;
|
||||
@@ -22,7 +23,7 @@ public interface BravoFixTrack<ItemType extends WithID & Serializable> extends S
|
||||
* @return the ride height for the given {@link TimePoint} or <code>null</code> if the {@link TimePoint} is not in the range
|
||||
* where we have fixes for.
|
||||
*/
|
||||
Double getRideHeight(TimePoint timePoint);
|
||||
Distance getRideHeight(TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Calculates the average ride height for the given time range.
|
||||
@@ -34,5 +35,5 @@ public interface BravoFixTrack<ItemType extends WithID & Serializable> extends S
|
||||
* @return the average ride height for the given time range or <code>null</code> if there are no fixes in the given
|
||||
* time range.
|
||||
*/
|
||||
Double getAverageRideHeight(TimePoint from, TimePoint to);
|
||||
Distance getAverageRideHeight(TimePoint from, TimePoint to);
|
||||
}
|
||||
+2
-2
@@ -97,7 +97,7 @@ public interface TrackedLegOfCompetitor extends Serializable {
|
||||
* <code>timePoint</code>. If the competitor already completed the leg at <code>timePoint</code> and the respective
|
||||
* mark passing event was already received, the average ride height for the entire leg (and no further) is computed.
|
||||
*/
|
||||
Double getAverageRideHeight(TimePoint timePoint);
|
||||
Distance getAverageRideHeight(TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* @return <code>null</code> if the competitor hasn't started this leg yet, otherwise the fix where the maximum speed was
|
||||
@@ -237,7 +237,7 @@ public interface TrackedLegOfCompetitor extends Serializable {
|
||||
* <code>timePoint</code>, returns the current ride height for this time point. If the competitor has already
|
||||
* finished the leg, the ride height at the time the competitor finished the leg is returned.
|
||||
*/
|
||||
Double getRideHeight(TimePoint at);
|
||||
Distance getRideHeight(TimePoint at);
|
||||
|
||||
/**
|
||||
* Computes the distance along the wind track to the wind-projected position of the race's overall leader. If leader
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.SensorFix;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.ranking.RankingMetric;
|
||||
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
|
||||
import com.sap.sailing.domain.tracking.impl.NonCachingMarkPositionAtTimePointCache;
|
||||
@@ -685,6 +686,8 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
|
||||
Distance getAverageSignedCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly,
|
||||
boolean waitForLatestAnalysis) throws NoWindException;
|
||||
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint);
|
||||
|
||||
WindStore getWindStore();
|
||||
|
||||
Competitor getOverallLeader(TimePoint timePoint);
|
||||
|
||||
+15
-10
@@ -1,10 +1,8 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.Spliterator;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.BravoFix;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
@@ -34,7 +32,7 @@ public class BravoFixTrackImpl<ItemType extends WithID & Serializable> extends S
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRideHeight(TimePoint timePoint) {
|
||||
public Distance getRideHeight(TimePoint timePoint) {
|
||||
BravoFix fixAfter = getFirstFixAtOrAfter(timePoint);
|
||||
if (fixAfter != null && fixAfter.getTimePoint().compareTo(timePoint) == 0) {
|
||||
// exact match of timepoint -> no interpolation necessary
|
||||
@@ -54,17 +52,24 @@ public class BravoFixTrackImpl<ItemType extends WithID & Serializable> extends S
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getAverageRideHeight(TimePoint from, TimePoint to) {
|
||||
public Distance getAverageRideHeight(TimePoint from, TimePoint to) {
|
||||
final Distance result;
|
||||
lockForRead();
|
||||
try {
|
||||
Spliterator<BravoFix> fixes = getFixes(from, true, to, true).spliterator();
|
||||
OptionalDouble average = StreamSupport.stream(fixes, false).mapToDouble(BravoFix::getRideHeight).average();
|
||||
if (average.isPresent()) {
|
||||
return average.getAsDouble();
|
||||
Distance sum = Distance.NULL;
|
||||
int count = 0;
|
||||
for (final BravoFix fix : getFixes(from, true, to, true)) {
|
||||
sum = sum.add(fix.getRideHeight());
|
||||
count++;
|
||||
}
|
||||
if (count > 0) {
|
||||
result = sum.scale(1./count);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
} finally {
|
||||
unlockAfterRead();
|
||||
}
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -174,8 +174,7 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
}
|
||||
if (timePointToUse != null) {
|
||||
Distance d = getDistanceTraveled(timePointToUse);
|
||||
long millis = timePointToUse.asMillis() - legStart.getTimePoint().asMillis();
|
||||
result = d.inTime(millis);
|
||||
result = d.inTime(legStart.getTimePoint().until(timePointToUse));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
@@ -184,7 +183,7 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getAverageRideHeight(TimePoint timePoint) {
|
||||
public Distance getAverageRideHeight(TimePoint timePoint) {
|
||||
MarkPassing legStart = getMarkPassingForLegStart();
|
||||
if (legStart != null) {
|
||||
BravoFixTrack<Competitor> track = getTrackedRace()
|
||||
@@ -677,15 +676,17 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRideHeight(TimePoint at) {
|
||||
public Distance getRideHeight(TimePoint at) {
|
||||
final Distance result;
|
||||
if (hasStartedLeg(at)) {
|
||||
TimePoint timePoint =hasFinishedLeg(at) ? getMarkPassingForLegEnd().getTimePoint() : at;
|
||||
BravoFixTrack<Competitor> track = getTrackedRace()
|
||||
.<BravoFix, BravoFixTrack<Competitor>> getSensorTrack(competitor, BravoFixTrack.TRACK_NAME);
|
||||
return track == null ? null : track.getRideHeight(timePoint);
|
||||
result = track == null ? null : track.getRideHeight(timePoint);
|
||||
} else {
|
||||
return null;
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+16
@@ -1538,6 +1538,22 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
final Distance result;
|
||||
BravoFixTrack<Competitor> track = getSensorTrack(competitor, BravoFixTrack.TRACK_NAME);
|
||||
final Leg firstLeg;
|
||||
final TrackedLegOfCompetitor firstTrackedLeg;
|
||||
if (track != null && (firstLeg = getRace().getCourse().getFirstLeg()) != null && (firstTrackedLeg = getTrackedLeg(competitor, firstLeg)).hasStartedLeg(timePoint)) {
|
||||
final TrackedLegOfCompetitor lastTrackedLeg = getTrackedLegFinishingAt(getRace().getCourse().getLastWaypoint()).getTrackedLeg(competitor);
|
||||
TimePoint endTimePoint = lastTrackedLeg.hasFinishedLeg(timePoint) ? lastTrackedLeg.getFinishTime() : timePoint;
|
||||
result = track.getAverageRideHeight(firstTrackedLeg.getStartTime(), endTimePoint);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedLegOfCompetitor getCurrentLeg(Competitor competitor, TimePoint timePoint) {
|
||||
// If the mark passing that starts a leg happened exactly at timePoint, the MarkPassingByTimeComparator won't consider
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.sap.sailing.util;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
|
||||
public class RegattaUtil {
|
||||
|
||||
public static final Distance DEFAULT_BUOY_ZONE_RADIUS = new MeterDistance(15);
|
||||
|
||||
public static Distance getCalculatedRegattaBuoyZoneRadius(Regatta regatta, BoatClass boatClass) {
|
||||
final double buoyZoneRadiusInHullLengths;
|
||||
if (regatta != null && regatta.getBuoyZoneRadiusInHullLengths() != null) {
|
||||
buoyZoneRadiusInHullLengths = regatta.getBuoyZoneRadiusInHullLengths();
|
||||
} else {
|
||||
buoyZoneRadiusInHullLengths = Regatta.DEFAULT_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS;
|
||||
}
|
||||
final Distance boatHullLength = boatClass == null ? null : boatClass.getHullLength();
|
||||
final Distance buyZoneRadius = boatHullLength == null ? DEFAULT_BUOY_ZONE_RADIUS
|
||||
: boatHullLength.scale(buoyZoneRadiusInHullLengths);
|
||||
return buyZoneRadius;
|
||||
}
|
||||
}
|
||||
+5
@@ -860,4 +860,9 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
public Iterable<RaceLog> getAttachedRaceLogs() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -41,7 +41,7 @@ public class PingMarkViaRegattaLogTest {
|
||||
Collections.singletonList(columnName), service);
|
||||
Regatta regatta = service.createRegatta(RegattaImpl.getDefaultName("regatta", "Laser"), "Laser", /*startDate*/ null, /*endDate*/ null,
|
||||
UUID.randomUUID(), Collections.<Series>singletonList(series),
|
||||
false, new HighPoint(), UUID.randomUUID(), /* useStartTimeInference */ true,
|
||||
false, new HighPoint(), UUID.randomUUID(), /*buoyZoneRadiusInHullLengths*/2.0, /* useStartTimeInference */ true,
|
||||
/* controlTrackingFromStartAndFinishTimes */ false, RankingMetricsFactory.getRankingMetricConstructor(RankingMetrics.ONE_DESIGN));
|
||||
RegattaLeaderboard leaderboard = service.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "RegattaLeaderboard", new int[] {});
|
||||
|
||||
|
||||
@@ -1,256 +1,260 @@
|
||||
/** Add css rules here for your application. */
|
||||
/*
|
||||
body #calendar:after
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
*/
|
||||
.clearafter {
|
||||
clear: both;
|
||||
font-size: 1px;
|
||||
height: 0px;
|
||||
line-height: 0px;
|
||||
margin: -1px 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cover {
|
||||
left: -1000px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: -1000px;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
background: url(images/spectatorview-bg.png) no-repeat left top #ebebeb;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
line-height: 1;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
padding: 85px 0 0 0;
|
||||
margin: 0;
|
||||
color: #3b3b3b;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #2968c0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
table td,select,button {
|
||||
line-height: 1;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.gwt-DialogBox {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.gwt-ToggleButton {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.gwt-PopupPanelGlass {
|
||||
z-index: 19;
|
||||
}
|
||||
|
||||
.contentOuterPanel {
|
||||
background: #dddcdc;
|
||||
margin: 0 12px 0 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/** Example rules used by the template application (remove for your app) */
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: #777777;
|
||||
margin: 40px 0px 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: separate;
|
||||
}
|
||||
|
||||
.LogoAndTitlePanel {
|
||||
height: 68px;
|
||||
font-family: Arial, Verdana, sans-serif;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background-image: url(images/white_gradient_header.png), url(images/header_bg_modern.png);
|
||||
background-position: center top, 0 0;
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
box-shadow: 0 0 20px #858585;
|
||||
-moz-box-shadow: 0 0 20px #858585;
|
||||
-webkit-box-shadow: 0 0 20px #858585;
|
||||
-o-box-shadow: 0 0 20px #858585;
|
||||
-ms-box-shadow: 0 0 20px #858585;
|
||||
}
|
||||
|
||||
.LogoAndTitlePanel:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.RaceBoardHeaderPanel {
|
||||
margin: 0 12px 18px 12px;
|
||||
}
|
||||
|
||||
.sapLogo {
|
||||
float: left;
|
||||
margin: 13px 0 0 12px;
|
||||
}
|
||||
|
||||
.sailingAnalyticsLabelPanel {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
.sailingAnalyticsLabel {
|
||||
float: left;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin: 15px 0 0 0;
|
||||
}
|
||||
|
||||
.leaderboardLabel {
|
||||
border-bottom: 2px solid #007dc0;
|
||||
font-weight: bold;
|
||||
padding: 0 0 6px 0;
|
||||
}
|
||||
|
||||
.refreshAndSettings {
|
||||
background: #f2f2f2;
|
||||
border-bottom: 2px solid #fff;
|
||||
border-top: 2px solid #fff;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.refreshAndSettings table td {
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
.refreshAndSettings table table td {
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
.race-name {
|
||||
margin: 2px 10px 0 0;
|
||||
line-height: 1.0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
input.magnifier {
|
||||
display: block;
|
||||
margin: 3px auto 0 auto !important;
|
||||
}
|
||||
|
||||
.footerShadowPanel {
|
||||
position: fixed;
|
||||
height: 50px;
|
||||
bottom: 0;
|
||||
background: url(images/footer_shadow.png) left bottom repeat-x;
|
||||
width: 100%;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.mainPanel {
|
||||
width: 100%;
|
||||
margin-left: 13px;
|
||||
}
|
||||
|
||||
.errorLabel {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.chart-importantMessage {
|
||||
font-family: 'Open Sans',Arial,Verdana,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
height: 70px;
|
||||
margin: 0 auto;
|
||||
padding: 49px 0 0 80px;
|
||||
width: 400px;
|
||||
color: #7c7c7c;
|
||||
background: url(images/important-message.png) left center no-repeat;
|
||||
}
|
||||
|
||||
.chart-busyMessage {
|
||||
font-family: 'Open Sans',Arial,Verdana,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
height: 70px;
|
||||
margin: 0 auto;
|
||||
padding: 49px 0 0 40px;
|
||||
width: 400px;
|
||||
color: #7c7c7c;
|
||||
background: url(images/busy_indicator_circle.gif) left center no-repeat;
|
||||
}
|
||||
|
||||
.dataMiningPanel {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.dataMiningPanel-filledElement {
|
||||
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center 0 transparent;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
font-family: 'Open Sans',Verdana,Arial,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
margin: 0 0 0 0;
|
||||
padding: 2px 7px 2px 3px;
|
||||
height: 18px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
-moz-border-radius: 5px 0 0 5px;
|
||||
-webkit-border-radius: 5px 0 0 5px;
|
||||
-o-border-radius: 5px 0 0 5px;
|
||||
-ms-border-radius: 5px 0 0 5px;
|
||||
border-radius: 5px 0 0 5px;
|
||||
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
-o-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
-ms-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.settingsAnchor {
|
||||
position: relative;
|
||||
top: 9px;
|
||||
}
|
||||
|
||||
.groupingProviderElement {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.statisticProviderElement {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.definitionProviderControls {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.definitionProviderControlsElements {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.queryDefinitionViewerContent {
|
||||
background-color: white;
|
||||
padding: 5px;
|
||||
/** Add css rules here for your application. */
|
||||
/*
|
||||
body #calendar:after
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
*/
|
||||
html {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.clearafter {
|
||||
clear: both;
|
||||
font-size: 1px;
|
||||
height: 0px;
|
||||
line-height: 0px;
|
||||
margin: -1px 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cover {
|
||||
left: -1000px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: -1000px;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
background: url(images/spectatorview-bg.png) no-repeat left top #ebebeb;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
line-height: 1;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
padding: 85px 0 0 0;
|
||||
margin: 0;
|
||||
color: #3b3b3b;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #2968c0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
table td,select,button {
|
||||
line-height: 1;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.gwt-DialogBox {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.gwt-ToggleButton {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.gwt-PopupPanelGlass {
|
||||
z-index: 19;
|
||||
}
|
||||
|
||||
.contentOuterPanel {
|
||||
background: #dddcdc;
|
||||
margin: 0 12px 0 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/** Example rules used by the template application (remove for your app) */
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: #777777;
|
||||
margin: 40px 0px 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: separate;
|
||||
}
|
||||
|
||||
.LogoAndTitlePanel {
|
||||
height: 68px;
|
||||
font-family: Arial, Verdana, sans-serif;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background-image: url(images/white_gradient_header.png), url(images/header_bg_modern.png);
|
||||
background-position: center top, 0 0;
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
box-shadow: 0 0 20px #858585;
|
||||
-moz-box-shadow: 0 0 20px #858585;
|
||||
-webkit-box-shadow: 0 0 20px #858585;
|
||||
-o-box-shadow: 0 0 20px #858585;
|
||||
-ms-box-shadow: 0 0 20px #858585;
|
||||
}
|
||||
|
||||
.LogoAndTitlePanel:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.RaceBoardHeaderPanel {
|
||||
margin: 0 12px 18px 12px;
|
||||
}
|
||||
|
||||
.sapLogo {
|
||||
float: left;
|
||||
margin: 13px 0 0 12px;
|
||||
}
|
||||
|
||||
.sailingAnalyticsLabelPanel {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
.sailingAnalyticsLabel {
|
||||
float: left;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin: 15px 0 0 0;
|
||||
}
|
||||
|
||||
.leaderboardLabel {
|
||||
border-bottom: 2px solid #007dc0;
|
||||
font-weight: bold;
|
||||
padding: 0 0 6px 0;
|
||||
}
|
||||
|
||||
.refreshAndSettings {
|
||||
background: #f2f2f2;
|
||||
border-bottom: 2px solid #fff;
|
||||
border-top: 2px solid #fff;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.refreshAndSettings table td {
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
.refreshAndSettings table table td {
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
.race-name {
|
||||
margin: 2px 10px 0 0;
|
||||
line-height: 1.0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
input.magnifier {
|
||||
display: block;
|
||||
margin: 3px auto 0 auto !important;
|
||||
}
|
||||
|
||||
.footerShadowPanel {
|
||||
position: fixed;
|
||||
height: 50px;
|
||||
bottom: 0;
|
||||
background: url(images/footer_shadow.png) left bottom repeat-x;
|
||||
width: 100%;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.mainPanel {
|
||||
width: 100%;
|
||||
margin-left: 13px;
|
||||
}
|
||||
|
||||
.errorLabel {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.chart-importantMessage {
|
||||
font-family: 'Open Sans',Arial,Verdana,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
height: 70px;
|
||||
margin: 0 auto;
|
||||
padding: 49px 0 0 80px;
|
||||
width: 400px;
|
||||
color: #7c7c7c;
|
||||
background: url(images/important-message.png) left center no-repeat;
|
||||
}
|
||||
|
||||
.chart-busyMessage {
|
||||
font-family: 'Open Sans',Arial,Verdana,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
height: 70px;
|
||||
margin: 0 auto;
|
||||
padding: 49px 0 0 40px;
|
||||
width: 400px;
|
||||
color: #7c7c7c;
|
||||
background: url(images/busy_indicator_circle.gif) left center no-repeat;
|
||||
}
|
||||
|
||||
.dataMiningPanel {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.dataMiningPanel-filledElement {
|
||||
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center 0 transparent;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
font-family: 'Open Sans',Verdana,Arial,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
margin: 0 0 0 0;
|
||||
padding: 2px 7px 2px 3px;
|
||||
height: 18px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
-moz-border-radius: 5px 0 0 5px;
|
||||
-webkit-border-radius: 5px 0 0 5px;
|
||||
-o-border-radius: 5px 0 0 5px;
|
||||
-ms-border-radius: 5px 0 0 5px;
|
||||
border-radius: 5px 0 0 5px;
|
||||
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
-o-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
-ms-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.settingsAnchor {
|
||||
position: relative;
|
||||
top: 9px;
|
||||
}
|
||||
|
||||
.groupingProviderElement {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.statisticProviderElement {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.definitionProviderControls {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.definitionProviderControlsElements {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.queryDefinitionViewerContent {
|
||||
background-color: white;
|
||||
padding: 5px;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill=
|
||||
"#FFF" d="M10,2a8,8,0,1,1-8,8,8,8,0,0,1,8-8m0-2A10,10,0,1,0,20,10,10,10,0,0,0,
|
||||
10,0h0ZM9.71,10l0.08,0L9.71,10V10m-2-3.43v7l3.07-1.74L13.86,10,10.78,8.26,7.71,
|
||||
6.52h0Z"/></svg>
|
||||
|
After Width: | Height: | Size: 252 B |
+31
-2
@@ -7,8 +7,16 @@ import com.google.gwt.event.shared.EventBus;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.AcceptsOneWidget;
|
||||
import com.sap.sailing.gwt.autoplay.client.shared.leaderboard.LeaderboardWithHeaderPerspectiveLifecycle;
|
||||
import com.sap.sailing.gwt.autoplay.client.shared.leaderboard.LeaderboardWithHeaderPerspectiveSettings;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.raceboard.RaceBoardPerspectiveLifecycle;
|
||||
import com.sap.sailing.gwt.ui.raceboard.RaceBoardPerspectiveSettings;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
import com.sap.sse.gwt.client.mvp.ErrorView;
|
||||
import com.sap.sse.gwt.client.shared.perspective.PerspectiveLifecycleWithAllSettings;
|
||||
import com.sap.sse.gwt.client.useragent.UserAgentDetails;
|
||||
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
|
||||
|
||||
@@ -26,6 +34,17 @@ public class PlayerActivity extends AbstractActivity {
|
||||
this.autoPlayController = null;
|
||||
}
|
||||
|
||||
private StrippedLeaderboardDTO getSelectedLeaderboard(EventDTO event,String leaderBoardName) {
|
||||
for (LeaderboardGroupDTO leaderboardGroup : event.getLeaderboardGroups()) {
|
||||
for (StrippedLeaderboardDTO leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
if (leaderboard.name.equals(leaderBoardName)) {
|
||||
return leaderboard;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(final AcceptsOneWidget panel, EventBus eventBus) {
|
||||
final boolean showRaceDetails = GwtHttpRequestUtils.getBooleanParameter(PARAM_SHOW_RACE_DETAILS, false);
|
||||
@@ -36,6 +55,16 @@ public class PlayerActivity extends AbstractActivity {
|
||||
clientFactory.getSailingService().getEventById(eventUUID, true, new AsyncCallback<EventDTO>() {
|
||||
@Override
|
||||
public void onSuccess(final EventDTO event) {
|
||||
|
||||
//This place fixes a specific null pointer bug3950, once the settings are redone, this should be removed, and instead be done via playerplace (see comment there)
|
||||
StrippedLeaderboardDTO leaderBoardDTO = getSelectedLeaderboard(event,playerPlace.getConfiguration().getLeaderboardName());
|
||||
LeaderboardWithHeaderPerspectiveLifecycle leaderboardPerspectiveLifecycle = new LeaderboardWithHeaderPerspectiveLifecycle(leaderBoardDTO, StringMessages.INSTANCE);
|
||||
PerspectiveLifecycleWithAllSettings<LeaderboardWithHeaderPerspectiveLifecycle, LeaderboardWithHeaderPerspectiveSettings> leaderboardPerspectiveLifecyclesAndSettings = new PerspectiveLifecycleWithAllSettings<>(leaderboardPerspectiveLifecycle, leaderboardPerspectiveLifecycle.createDefaultSettings());
|
||||
RaceBoardPerspectiveLifecycle raceboardPerspectiveLifecycle = new RaceBoardPerspectiveLifecycle(leaderBoardDTO, StringMessages.INSTANCE);
|
||||
PerspectiveLifecycleWithAllSettings<RaceBoardPerspectiveLifecycle, RaceBoardPerspectiveSettings> raceboardPerspectiveLifecyclesAndSettings = new PerspectiveLifecycleWithAllSettings<>(raceboardPerspectiveLifecycle, raceboardPerspectiveLifecycle.createDefaultSettings());
|
||||
|
||||
|
||||
|
||||
UserAgentDetails userAgent = new UserAgentDetails(Window.Navigator.getUserAgent());
|
||||
|
||||
PlayerView view = clientFactory.createPlayerView();
|
||||
@@ -44,8 +73,8 @@ public class PlayerActivity extends AbstractActivity {
|
||||
autoPlayController = new AutoPlayController(clientFactory.getSailingService(), clientFactory
|
||||
.getMediaService(), clientFactory.getUserService(), clientFactory.getErrorReporter(),
|
||||
playerPlace.getConfiguration(), userAgent, delayToLiveMillis, showRaceDetails, view,
|
||||
playerPlace.getLeaderboardPerspectiveLifecycleWithAllSettings(),
|
||||
playerPlace.getRaceboardPerspectiveLifecycleWithAllSettings());
|
||||
leaderboardPerspectiveLifecyclesAndSettings,
|
||||
raceboardPerspectiveLifecyclesAndSettings);
|
||||
autoPlayController.updatePlayMode(AutoPlayModes.Leaderboard);
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -23,6 +23,8 @@ public class PlayerPlace extends AbstractBasePlace {
|
||||
Integer timeToSwitchBeforeRaceStartInSeconds = Integer.valueOf(getParameter(AutoPlayerConfiguration.PARAM_TIME_TO_SWITCH_BEFORE_RACE_START));
|
||||
|
||||
this.playerConfiguration = new AutoPlayerConfiguration(eventUuidAsString, leaderboardName, fullscreen, timeToSwitchBeforeRaceStartInSeconds);
|
||||
|
||||
//these are currently regenerated in the PlayerActivity, based on the historydata. Once the settings are properly stored, this should be replaced.
|
||||
this.leaderboardPerspectiveLifecycleWithAllSettings = null;
|
||||
this.raceboardPerspectiveLifecycleWithAllSettings = null;
|
||||
}
|
||||
|
||||
+11
-1
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.DTO;
|
||||
|
||||
public class RegattaMetadataDTO extends RegattaReferenceDTO implements HasRegattaMetadata {
|
||||
@@ -18,6 +19,7 @@ public class RegattaMetadataDTO extends RegattaReferenceDTO implements HasRegatt
|
||||
private RegattaState state;
|
||||
private boolean flexibleLeaderboard;
|
||||
private RaceDataInfo raceDataInfo;
|
||||
private Distance buoyZoneRadius;
|
||||
|
||||
public RegattaMetadataDTO() {
|
||||
}
|
||||
@@ -122,7 +124,15 @@ public class RegattaMetadataDTO extends RegattaReferenceDTO implements HasRegatt
|
||||
public void setRaceDataInfo(RaceDataInfo raceDataInfo) {
|
||||
this.raceDataInfo = raceDataInfo;
|
||||
}
|
||||
|
||||
|
||||
public Distance getBuoyZoneRadius() {
|
||||
return buoyZoneRadius;
|
||||
}
|
||||
|
||||
public void setBuoyZoneRadius(Distance buoyZoneRadius) {
|
||||
this.buoyZoneRadius = buoyZoneRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder class for flags, which inform about GPS, wind, video or audio data availability.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ public class GetFavoritesAction implements SailingAction<FavoritesResult> {
|
||||
if (preferences != null) {
|
||||
for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) {
|
||||
String name = pref.getBoatClass().getName(), displayName = pref.getBoatClass().getDisplayName();
|
||||
selected.add(new BoatClassDTO(name, displayName, pref.getBoatClass().getHullLength().getMeters()));
|
||||
selected.add(new BoatClassDTO(name, displayName, pref.getBoatClass().getHullLength()));
|
||||
notifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces();
|
||||
notifyAboutResults |= pref.isNotifyAboutResults();
|
||||
}
|
||||
|
||||
+13
-13
@@ -1,14 +1,14 @@
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
|
||||
xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared"
|
||||
xmlns:dp="urn:import:com.sap.sailing.gwt.home.desktop.partials">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="local_res" type="com.sap.sailing.gwt.home.desktop.partials.racelist.RaceListResources" />
|
||||
<g:HTMLPanel addStyleNames="{local_res.css.raceslistlive}">
|
||||
<h3 ui:field="titleUi"></h3>
|
||||
<div style="display: none;" ui:field="infoUi"></div>
|
||||
<div style="display: none; font-weight: bold; font-style: italic;" ui:field="noContentPlaceholderUi"></div>
|
||||
<dp:racelist.AbstractRaceList ui:field="raceListUi"/>
|
||||
</g:HTMLPanel>
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
|
||||
xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared"
|
||||
xmlns:dp="urn:import:com.sap.sailing.gwt.home.desktop.partials">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="local_res" type="com.sap.sailing.gwt.home.desktop.partials.racelist.RaceListResources" />
|
||||
<g:HTMLPanel addStyleNames="{local_res.css.raceslistlive}">
|
||||
<h3 ui:field="titleUi"></h3>
|
||||
<div style="display: none;" ui:field="infoUi"></div>
|
||||
<div style="display: none; font-weight: bold; font-style: italic;" ui:field="noContentPlaceholderUi"></div>
|
||||
<dp:racelist.AbstractRaceList ui:field="raceListUi"/>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
+19
@@ -63,6 +63,7 @@
|
||||
.raceviewerlaunchpad:hover {
|
||||
cursor: pointer;
|
||||
background: #0081b8;
|
||||
text-decoration: none;
|
||||
}
|
||||
.raceviewerlaunchpadlive {
|
||||
background: #e94a1b;
|
||||
@@ -79,11 +80,29 @@
|
||||
.raceviewerlaunchpadlive .raceviewerlaunchpad_content_item_icon svg {
|
||||
fill: #e94a1b;
|
||||
}
|
||||
.raceviewerlaunchpadplanned {
|
||||
background: #999999;
|
||||
}
|
||||
.raceviewerlaunchpadplanned:hover {
|
||||
background: #8a8a8a;
|
||||
}
|
||||
.raceviewerlaunchpadplanned .raceviewerlaunchpad_content_item {
|
||||
color: #999999;
|
||||
}
|
||||
.raceviewerlaunchpadplanned .raceviewerlaunchpad_content_item:hover {
|
||||
background: #999999;
|
||||
}
|
||||
.raceviewerlaunchpadplanned .raceviewerlaunchpad_content_item_icon svg {
|
||||
fill: #999999;
|
||||
}
|
||||
.raceviewerlaunchpad_icon {
|
||||
margin-left: 0.666666666666667em;
|
||||
width: 1.666666666666667em;
|
||||
height: 1.333333333333333em;
|
||||
}
|
||||
.raceviewerlaunchpad_icon img {
|
||||
height: 100%;
|
||||
}
|
||||
.raceviewerlaunchpad_icon svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
+109
-84
@@ -1,85 +1,110 @@
|
||||
package com.sap.sailing.gwt.home.desktop.partials.raceviewerlaunchpad;
|
||||
|
||||
import com.google.gwt.cell.client.AbstractCell;
|
||||
import com.google.gwt.cell.client.ValueUpdater;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.BrowserEvents;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.NativeEvent;
|
||||
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
|
||||
import com.sap.sailing.gwt.home.communication.race.RaceMetadataDTO;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO;
|
||||
import com.sap.sailing.gwt.home.desktop.places.event.EventView;
|
||||
import com.sap.sailing.gwt.home.desktop.places.event.EventView.Presenter;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class RaceviewerLaunchPadCell<T extends RaceMetadataDTO<?>> extends AbstractCell<T> {
|
||||
|
||||
interface CellTemplates extends SafeHtmlTemplates {
|
||||
@Template("<div class=\"{0}\">{1}</div>")
|
||||
SafeHtml raceNotTracked(String styleNames, String text);
|
||||
|
||||
@Template("<div class=\"{0}\"><div>{2}</div><div class=\"{1}\"><img src=\"images/home/launch-loupe.svg\"/></div>")
|
||||
SafeHtml raceviewerLaunchPad(String styleNames, String iconStyleNames, String text);
|
||||
}
|
||||
|
||||
private static final CellTemplates TEMPLATE = GWT.create(CellTemplates.class);
|
||||
private static final StringMessages I18N = StringMessages.INSTANCE;
|
||||
|
||||
private final RaceviewerLaunchPadResources local_res = RaceviewerLaunchPadResources.INSTANCE;
|
||||
private final String notTrackedStyleNames = local_res.css().raceviewerlaunchpad_not_tracked();
|
||||
private final String analyzeStyleNames = local_res.css().raceviewerlaunchpad();
|
||||
private final String liveStyleNames = Util.join(" ", analyzeStyleNames, local_res.css().raceviewerlaunchpadlive());
|
||||
private final String iconStyleNames = local_res.css().raceviewerlaunchpad_icon();
|
||||
|
||||
private final EventView.Presenter presenter;
|
||||
private final PopupPanel panel = new PopupPanel(true, false);
|
||||
|
||||
public RaceviewerLaunchPadCell(Presenter presenter) {
|
||||
super(BrowserEvents.CLICK);
|
||||
local_res.css().ensureInjected();
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Context context, final Element parent, T data, NativeEvent event,
|
||||
ValueUpdater<T> valueUpdater) {
|
||||
if (data.hasValidTrackingData() && BrowserEvents.CLICK.equals(event.getType())
|
||||
&& parent.getFirstChildElement().isOrHasChild(Element.as(event.getEventTarget()))) {
|
||||
panel.setWidget(new RaceviewerLaunchPad(data, panel) {
|
||||
@Override
|
||||
protected String getRaceViewerURL(SimpleRaceMetadataDTO data, String mode) {
|
||||
return presenter.getRaceViewerURL(data, mode);
|
||||
}
|
||||
});
|
||||
panel.setPopupPositionAndShow(new PositionCallback() {
|
||||
@Override
|
||||
public void setPosition(int offsetWidth, int offsetHeight) {
|
||||
int alignBottom = parent.getAbsoluteTop() + parent.getOffsetHeight() - offsetHeight;
|
||||
int top = (alignBottom - Window.getScrollTop() < 0 ? parent.getAbsoluteTop() - 1 : alignBottom + 1);
|
||||
panel.setPopupPosition(parent.getAbsoluteRight() + 1 - offsetWidth, top);
|
||||
panel.getElement().scrollIntoView();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
super.onBrowserEvent(context, parent, data, event, valueUpdater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Context context, T data, SafeHtmlBuilder sb) {
|
||||
if (data.hasValidTrackingData()) {
|
||||
String styleNames = data.isFinished() ? analyzeStyleNames : liveStyleNames;
|
||||
sb.append(TEMPLATE.raceviewerLaunchPad(styleNames, iconStyleNames, I18N.raceDetailsToShow()));
|
||||
} else {
|
||||
package com.sap.sailing.gwt.home.desktop.partials.raceviewerlaunchpad;
|
||||
|
||||
import com.google.gwt.cell.client.AbstractCell;
|
||||
import com.google.gwt.cell.client.ValueUpdater;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.BrowserEvents;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.NativeEvent;
|
||||
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
|
||||
import com.sap.sailing.gwt.home.communication.race.RaceMetadataDTO;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO;
|
||||
import com.sap.sailing.gwt.home.desktop.places.event.EventView;
|
||||
import com.sap.sailing.gwt.home.desktop.places.event.EventView.Presenter;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.raceboard.RaceBoardModes;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class RaceviewerLaunchPadCell<T extends RaceMetadataDTO<?>> extends AbstractCell<T> {
|
||||
|
||||
interface CellTemplates extends SafeHtmlTemplates {
|
||||
@Template("<div class=\"{0}\">{1}</div>")
|
||||
SafeHtml raceNotTracked(String styleNames, String text);
|
||||
|
||||
@Template("<div class=\"{0}\"><div>{2}</div><div class=\"{1}\"><img src=\"images/home/launch-loupe.svg\"/></div>")
|
||||
SafeHtml raceviewerLaunchPad(String styleNames, String iconStyleNames, String text);
|
||||
|
||||
@Template("<a href=\"{4}\" target=\"_blank\" class=\"{0}\"><div>{2}</div><div class=\"{1}\"><img src=\"images/home/{3}.svg\"/></div></a> ")
|
||||
SafeHtml standaloneButton(String styleNames, String iconStyleNames, String text, String icon, String link);
|
||||
}
|
||||
|
||||
private static final CellTemplates TEMPLATE = GWT.create(CellTemplates.class);
|
||||
private static final StringMessages I18N = StringMessages.INSTANCE;
|
||||
|
||||
private final RaceviewerLaunchPadResources local_res = RaceviewerLaunchPadResources.INSTANCE;
|
||||
private final String notTrackedStyleNames = local_res.css().raceviewerlaunchpad_not_tracked();
|
||||
private final String analyzeStyleNames = local_res.css().raceviewerlaunchpad();
|
||||
private final String plannedStyleNames = Util.join(" ", analyzeStyleNames, local_res.css().raceviewerlaunchpadplanned());
|
||||
private final String liveStyleNames = Util.join(" ", analyzeStyleNames, local_res.css().raceviewerlaunchpadlive());
|
||||
private final String iconStyleNames = local_res.css().raceviewerlaunchpad_icon();
|
||||
|
||||
private final EventView.Presenter presenter;
|
||||
private final PopupPanel panel = new PopupPanel(true, false);
|
||||
|
||||
public RaceviewerLaunchPadCell(Presenter presenter) {
|
||||
super(BrowserEvents.CLICK);
|
||||
local_res.css().ensureInjected();
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Context context, final Element parent, T data, NativeEvent event,
|
||||
ValueUpdater<T> valueUpdater) {
|
||||
if (!renderAsDirectLinkButton(data)) {
|
||||
if (data.hasValidTrackingData() && BrowserEvents.CLICK.equals(event.getType())
|
||||
&& parent.getFirstChildElement().isOrHasChild(Element.as(event.getEventTarget()))) {
|
||||
panel.setWidget(createLaunchPad(parent.getFirstChildElement(), data));
|
||||
panel.setPopupPositionAndShow(new PositionCallback() {
|
||||
@Override
|
||||
public void setPosition(int offsetWidth, int offsetHeight) {
|
||||
int alignBottom = parent.getAbsoluteTop() + parent.getOffsetHeight() - offsetHeight;
|
||||
int top = (alignBottom - Window.getScrollTop() < 0 ? parent.getAbsoluteTop() - 1 : alignBottom + 1);
|
||||
panel.setPopupPosition(parent.getAbsoluteRight() + 1 - offsetWidth, top);
|
||||
panel.getElement().scrollIntoView();
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.onBrowserEvent(context, parent, data, event, valueUpdater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Context context, T data, SafeHtmlBuilder sb) {
|
||||
if (data.hasValidTrackingData()) {
|
||||
if (renderAsDirectLinkButton(data)) {
|
||||
sb.append(TEMPLATE.standaloneButton(plannedStyleNames, iconStyleNames, I18N.watchLive(),
|
||||
"launch-play", presenter.getRaceViewerURL(data, RaceBoardModes.PLAYER.name())));
|
||||
} else {
|
||||
String styleNames = data.isFinished() ? analyzeStyleNames : liveStyleNames;
|
||||
sb.append(TEMPLATE.raceviewerLaunchPad(styleNames, iconStyleNames, I18N.raceDetailsToShow()));
|
||||
}
|
||||
} else {
|
||||
sb.append(TEMPLATE.raceNotTracked(notTrackedStyleNames, I18N.eventRegattaRaceNotTracked()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link RaceviewerLaunchPad} for the given data object.
|
||||
*/
|
||||
private RaceviewerLaunchPad createLaunchPad(Element button, T data) {
|
||||
RaceviewerLaunchPad launchPad = new RaceviewerLaunchPad(data, panel) {
|
||||
@Override
|
||||
protected String getRaceViewerURL(SimpleRaceMetadataDTO data, String raceBoardMode) {
|
||||
return presenter.getRaceViewerURL(data, raceBoardMode);
|
||||
}
|
||||
};
|
||||
return launchPad;
|
||||
}
|
||||
|
||||
/** Determine whether a direct link button should be/is rendered instead of a menu popup. */
|
||||
private boolean renderAsDirectLinkButton(T data) {
|
||||
return !data.isFinished() && !data.isRunning();
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -18,6 +18,7 @@ public interface RaceviewerLaunchPadResources extends ClientBundle {
|
||||
String raceviewerlaunchpad_date();
|
||||
String raceviewerlaunchpad_cta();
|
||||
String raceviewerlaunchpadlive();
|
||||
String raceviewerlaunchpadplanned();
|
||||
String raceviewerlaunchpad_content_item();
|
||||
String raceviewerlaunchpad_content_item_icon();
|
||||
String raceviewerlaunchpad_icon();
|
||||
|
||||
+3
@@ -174,6 +174,9 @@
|
||||
.fleet_races_raceplanned:hover {
|
||||
background-color: #8a8a8a;
|
||||
}
|
||||
.fleet_races_raceplanned .fleet_races_race_name:after {
|
||||
background: url("images/home/launch-play.svg") no-repeat center center;
|
||||
}
|
||||
.fleet_races_raceuntracked .fleet_races_race_name:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
|
||||
|
||||
if(currentPresenter.getEventDTO().getType() == EventType.SERIES_EVENT) {
|
||||
final PlaceNavigation<SeriesDefaultPlace> currentEventSeriesNavigation = currentPresenter.getCurrentEventSeriesNavigation();
|
||||
Anchor seriesAnchor = new Anchor(currentPresenter.getEventDTO().getSeriesName());
|
||||
Anchor seriesAnchor = new Anchor(i18n.overallLeaderboardSelection());
|
||||
seriesAnchor.setHref(currentEventSeriesNavigation.getTargetUrl());
|
||||
seriesAnchor.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
|
||||
+8
-3
@@ -69,6 +69,7 @@
|
||||
.regattacompetition_phase_fleetfullwidth .regattacompetition_phase_fleet_race_arrow {
|
||||
display: block;
|
||||
width: 1.6666666667em;
|
||||
height: 1.4444444444em;
|
||||
}
|
||||
.regattacompetition_phase_fleet_title {
|
||||
font-size: 1.066666666666667em;
|
||||
@@ -117,9 +118,6 @@
|
||||
background-color: #999;
|
||||
font-style: italic;
|
||||
}
|
||||
.regattacompetition_phase_fleet_raceplanned .regattacompetition_phase_fleet_race_title:after {
|
||||
display: none;
|
||||
}
|
||||
.regattacompetition_phase_fleet_racelive.regattacompetition_phase_fleet_raceuntracked {
|
||||
color: #e94a1b;
|
||||
background-color: #fff;
|
||||
@@ -150,6 +148,7 @@
|
||||
}
|
||||
.regattacompetition_phase_fleet_race_arrow {
|
||||
display: none;
|
||||
background: url("images/home/launch-loupe.svg") no-repeat center center;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 1em;
|
||||
@@ -158,6 +157,12 @@
|
||||
-ms-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.regattacompetition_phase_fleet_raceplanned .regattacompetition_phase_fleet_race_title:after {
|
||||
background: url("images/home/launch-play.svg") no-repeat center center;
|
||||
}
|
||||
.regattacompetition_phase_fleet_raceplanned .regattacompetition_phase_fleet_race_arrow {
|
||||
background: url("images/home/launch-play.svg") no-repeat center center;
|
||||
}
|
||||
.regattacompetition_phase_fleet_raceuntracked .regattacompetition_phase_fleet_race_arrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,6 +10,6 @@
|
||||
<div class="{local_res.css.regattacompetition_phase_fleet_race_state}" ui:field="raceStateUi"></div>
|
||||
<div class="{local_res.css.regattacompetition_phase_fleet_race_date}" ui:field="raceDateUi"></div>
|
||||
</div>
|
||||
<img src="images/home/launch-loupe.svg" class="{local_res.css.regattacompetition_phase_fleet_race_arrow}"></img>
|
||||
<div class="{local_res.css.regattacompetition_phase_fleet_race_arrow}"></div>
|
||||
</div>
|
||||
</ui:UiBinder>
|
||||
-3
@@ -274,12 +274,9 @@ public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> ex
|
||||
}
|
||||
linkParams.put("raceName", trackedRaceName);
|
||||
linkParams.put("regattaName", regattaName);
|
||||
// TODO this must only be forwarded if there is a logged-on user
|
||||
// linkParams.put(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, "true");
|
||||
return linkParams;
|
||||
}
|
||||
|
||||
|
||||
public String getRegattaId() {
|
||||
String regattaId = place.getRegattaId();
|
||||
if(regattaId != null) {
|
||||
|
||||
+11
-1
@@ -9,11 +9,13 @@ import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.LeaderboardEntryDTO;
|
||||
@@ -33,6 +35,7 @@ import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO;
|
||||
import com.sap.sailing.gwt.home.server.EventActionUtil.RaceCallback;
|
||||
import com.sap.sailing.gwt.server.HomeServiceUtil;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.util.RegattaUtil;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -248,8 +251,15 @@ public class LeaderboardContext {
|
||||
RegattaRaceDataInfoCalculator regattaRaceDataInfoCalculator = new RegattaRaceDataInfoCalculator();
|
||||
forRaces(regattaRaceDataInfoCalculator);
|
||||
regattaDTO.setRaceDataInfo(regattaRaceDataInfoCalculator.getRaceDataInfo());
|
||||
regattaDTO.setBuoyZoneRadius(getRegattaBuoyZoneRadius());
|
||||
}
|
||||
|
||||
|
||||
private Distance getRegattaBuoyZoneRadius() {
|
||||
Regatta regatta = service.getRegattaByName(getLeaderboardName());
|
||||
BoatClass boatClass = HomeServiceUtil.getBoatClass(leaderboard);
|
||||
return RegattaUtil.getCalculatedRegattaBuoyZoneRadius(regatta, boatClass);
|
||||
}
|
||||
|
||||
private static boolean hasMultipleLeaderboardGroups(EventBase event) {
|
||||
return Util.size(event.getLeaderboardGroups()) > 1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public abstract class AbstractSuggestedMultiSelectionBoatClassDataProvider exten
|
||||
List<BoatClassMasterdata> boatClasses = Arrays.asList(BoatClassMasterdata.values());
|
||||
List<BoatClassDTO> suggestionItems = new ArrayList<>();
|
||||
for (BoatClassMasterdata bcm : filter.applyFilter(queryTokens, boatClasses)) {
|
||||
suggestionItems.add(new BoatClassDTO(bcm.getDisplayName(), bcm.getHullLength().getMeters()));
|
||||
suggestionItems.add(new BoatClassDTO(bcm.getDisplayName(), bcm.getHullLength()));
|
||||
}
|
||||
callback.setSuggestionItems(suggestionItems);
|
||||
}
|
||||
|
||||
+122
-111
@@ -1,111 +1,122 @@
|
||||
package com.sap.sailing.gwt.home.shared.partials.regattacompetition;
|
||||
|
||||
import static com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil.shortTimeFormatter;
|
||||
import static com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil.weekdayMonthAbbrDayDateFormatter;
|
||||
import static com.sap.sse.common.impl.MillisecondsTimePoint.now;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.text.client.DateTimeFormatRenderer;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.common.client.DateUtil;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO.RaceTrackingState;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO.RaceViewState;
|
||||
import com.sap.sailing.gwt.home.desktop.partials.raceviewerlaunchpad.RaceviewerLaunchPad;
|
||||
import com.sap.sailing.gwt.home.shared.partials.regattacompetition.RegattaCompetitionView.RegattaCompetitionRaceView;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public abstract class AbstractRegattaCompetitionFleetRace extends Widget implements RegattaCompetitionRaceView {
|
||||
|
||||
private static final StringMessages I18N = StringMessages.INSTANCE;
|
||||
protected final Element mainElement;
|
||||
private final SimpleRaceMetadataDTO race;
|
||||
private final RegattaCompetitionPresenter presenter;
|
||||
private final PopupPanel panel = new PopupPanel(true, false);
|
||||
|
||||
protected AbstractRegattaCompetitionFleetRace(final SimpleRaceMetadataDTO race,
|
||||
RegattaCompetitionPresenter presenter) {
|
||||
this.race = race;
|
||||
this.presenter = presenter;
|
||||
this.mainElement = getMainUiElement();
|
||||
setupRaceState(race.getTrackingState(), race.getViewState());
|
||||
getRaceNameUiElement().setInnerText(race.getRaceName());
|
||||
setupRaceStart(race.getStart());
|
||||
setElement(mainElement);
|
||||
if (race.hasValidTrackingData()) {
|
||||
sinkEvents(Event.ONCLICK);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Event event) {
|
||||
if (race.hasValidTrackingData() && event.getTypeInt() == Event.ONCLICK) {
|
||||
this.getElement().scrollIntoView();
|
||||
panel.setWidget(new RaceviewerLaunchPad(race, panel) {
|
||||
@Override
|
||||
protected String getRaceViewerURL(SimpleRaceMetadataDTO data, String mode) {
|
||||
return presenter.getRaceViewerURL(data, mode);
|
||||
}
|
||||
});
|
||||
panel.setVisible(false);
|
||||
panel.show();
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
Widget button = AbstractRegattaCompetitionFleetRace.this, panelContent = panel.getWidget();
|
||||
int alignRight = button.getAbsoluteLeft() + button.getOffsetWidth() - panelContent.getOffsetWidth();
|
||||
int left = (alignRight - Window.getScrollLeft() < 0 ? button.getAbsoluteLeft() - 1 : alignRight + 1);
|
||||
int alignBottom = button.getAbsoluteTop() + button.getOffsetHeight() - panelContent.getOffsetHeight();
|
||||
int top = (alignBottom - Window.getScrollTop() < 0 ? button.getAbsoluteTop() - 1 : alignBottom + 1);
|
||||
panel.setPopupPosition(left, top);
|
||||
panel.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setupRaceState(RaceTrackingState trackingState, RaceViewState viewState) {
|
||||
boolean isUntrackedRace = trackingState != RaceTrackingState.TRACKED_VALID_DATA;
|
||||
if (viewState == RaceViewState.RUNNING) {
|
||||
mainElement.addClassName(getRaceLiveStyleName());
|
||||
getRaceStateUiElement().setInnerText(isUntrackedRace ? I18N.live() : I18N.actionWatch());
|
||||
} else if (viewState == RaceViewState.FINISHED) {
|
||||
getRaceStateUiElement().setInnerText(isUntrackedRace ? I18N.raceIsFinished() : I18N.actionAnalyze());
|
||||
} else {
|
||||
mainElement.addClassName(getRacePlannedStyleName());
|
||||
if (viewState == RaceViewState.SCHEDULED) getRaceStateUiElement().setInnerText(I18N.raceIsPlanned());
|
||||
else getRaceStateUiElement().setInnerText(viewState.getLabel());
|
||||
}
|
||||
setStyleName(mainElement, getRaceUntrackedStyleName(), isUntrackedRace);
|
||||
}
|
||||
|
||||
private void setupRaceStart(Date startDate) {
|
||||
if (startDate != null) {
|
||||
boolean showTime = DateUtil.isSameDayOfMonth(now().asDate(), startDate);
|
||||
DateTimeFormatRenderer renderer = showTime ? shortTimeFormatter : weekdayMonthAbbrDayDateFormatter;
|
||||
getRaceDateUiElement().setInnerText(renderer.render(startDate));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Element getMainUiElement();
|
||||
|
||||
protected abstract Element getRaceNameUiElement();
|
||||
|
||||
protected abstract Element getRaceStateUiElement();
|
||||
|
||||
protected abstract Element getRaceDateUiElement();
|
||||
|
||||
protected abstract String getRaceLiveStyleName();
|
||||
|
||||
protected abstract String getRacePlannedStyleName();
|
||||
|
||||
protected abstract String getRaceUntrackedStyleName();
|
||||
|
||||
}
|
||||
package com.sap.sailing.gwt.home.shared.partials.regattacompetition;
|
||||
|
||||
import static com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil.shortTimeFormatter;
|
||||
import static com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil.weekdayMonthAbbrDayDateFormatter;
|
||||
import static com.sap.sse.common.impl.MillisecondsTimePoint.now;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.text.client.DateTimeFormatRenderer;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.common.client.DateUtil;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO.RaceTrackingState;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO.RaceViewState;
|
||||
import com.sap.sailing.gwt.home.desktop.partials.raceviewerlaunchpad.RaceviewerLaunchPad;
|
||||
import com.sap.sailing.gwt.home.shared.partials.regattacompetition.RegattaCompetitionView.RegattaCompetitionRaceView;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.raceboard.RaceBoardModes;
|
||||
|
||||
public abstract class AbstractRegattaCompetitionFleetRace extends Widget implements RegattaCompetitionRaceView {
|
||||
|
||||
private static final StringMessages I18N = StringMessages.INSTANCE;
|
||||
protected final Element mainElement;
|
||||
private final SimpleRaceMetadataDTO race;
|
||||
private final RegattaCompetitionPresenter presenter;
|
||||
private final PopupPanel panel = new PopupPanel(true, false);
|
||||
|
||||
protected AbstractRegattaCompetitionFleetRace(final SimpleRaceMetadataDTO race,
|
||||
RegattaCompetitionPresenter presenter) {
|
||||
this.race = race;
|
||||
this.presenter = presenter;
|
||||
this.mainElement = getMainUiElement();
|
||||
setupRaceState(race.getTrackingState(), race.getViewState());
|
||||
getRaceNameUiElement().setInnerText(race.getRaceName());
|
||||
setupRaceStart(race.getStart());
|
||||
setElement(mainElement);
|
||||
if (race.hasValidTrackingData()) {
|
||||
sinkEvents(Event.ONCLICK);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Event event) {
|
||||
// Only handle click events if valid tracking data is available
|
||||
if (!race.hasValidTrackingData() || event.getTypeInt() != Event.ONCLICK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If rendered as direct link button, open link in new tab directly instead of showing the menu popup
|
||||
if (!race.isFinished() && !race.isRunning()) {
|
||||
Window.open(presenter.getRaceViewerURL(race, RaceBoardModes.PLAYER.name()), "_blank", "");
|
||||
return;
|
||||
}
|
||||
|
||||
// Show menu popup relative to button by ensuring it stays with the viewport
|
||||
this.getElement().scrollIntoView();
|
||||
panel.setWidget(new RaceviewerLaunchPad(race, panel) {
|
||||
@Override
|
||||
protected String getRaceViewerURL(SimpleRaceMetadataDTO data, String mode) {
|
||||
return presenter.getRaceViewerURL(data, mode);
|
||||
}
|
||||
});
|
||||
panel.setVisible(false);
|
||||
panel.show();
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
Widget button = AbstractRegattaCompetitionFleetRace.this, panelContent = panel.getWidget();
|
||||
int alignRight = button.getAbsoluteLeft() + button.getOffsetWidth() - panelContent.getOffsetWidth();
|
||||
int left = (alignRight - Window.getScrollLeft() < 0 ? button.getAbsoluteLeft() - 1 : alignRight + 1);
|
||||
int alignBottom = button.getAbsoluteTop() + button.getOffsetHeight() - panelContent.getOffsetHeight();
|
||||
int top = (alignBottom - Window.getScrollTop() < 0 ? button.getAbsoluteTop() - 1 : alignBottom + 1);
|
||||
panel.setPopupPosition(left, top);
|
||||
panel.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupRaceState(RaceTrackingState trackingState, RaceViewState viewState) {
|
||||
boolean isUntrackedRace = trackingState != RaceTrackingState.TRACKED_VALID_DATA;
|
||||
if (viewState == RaceViewState.RUNNING) {
|
||||
mainElement.addClassName(getRaceLiveStyleName());
|
||||
getRaceStateUiElement().setInnerText(isUntrackedRace ? I18N.live() : I18N.actionWatch());
|
||||
} else if (viewState == RaceViewState.FINISHED) {
|
||||
getRaceStateUiElement().setInnerText(isUntrackedRace ? I18N.raceIsFinished() : I18N.actionAnalyze());
|
||||
} else {
|
||||
mainElement.addClassName(getRacePlannedStyleName());
|
||||
if (viewState == RaceViewState.SCHEDULED) getRaceStateUiElement().setInnerText(I18N.raceIsPlanned());
|
||||
else getRaceStateUiElement().setInnerText(viewState.getLabel());
|
||||
}
|
||||
setStyleName(mainElement, getRaceUntrackedStyleName(), isUntrackedRace);
|
||||
}
|
||||
|
||||
private void setupRaceStart(Date startDate) {
|
||||
if (startDate != null) {
|
||||
boolean showTime = DateUtil.isSameDayOfMonth(now().asDate(), startDate);
|
||||
DateTimeFormatRenderer renderer = showTime ? shortTimeFormatter : weekdayMonthAbbrDayDateFormatter;
|
||||
getRaceDateUiElement().setInnerText(renderer.render(startDate));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Element getMainUiElement();
|
||||
|
||||
protected abstract Element getRaceNameUiElement();
|
||||
|
||||
protected abstract Element getRaceStateUiElement();
|
||||
|
||||
protected abstract Element getRaceDateUiElement();
|
||||
|
||||
protected abstract String getRaceLiveStyleName();
|
||||
|
||||
protected abstract String getRacePlannedStyleName();
|
||||
|
||||
protected abstract String getRaceUntrackedStyleName();
|
||||
|
||||
}
|
||||
+1
@@ -937,6 +937,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String createRegattaLink(RegattaOverviewEntryDTO entryDTO) {
|
||||
String leaderboardLink = EntryPointLinkFactory.createLeaderboardTabLink(eventId.toString(), entryDTO.regattaName);
|
||||
return leaderboardLink;
|
||||
|
||||
+1
-1
@@ -228,7 +228,7 @@ public final class HomeServiceUtil {
|
||||
return boatClass == null ? null : boatClass.getName();
|
||||
}
|
||||
|
||||
private static BoatClass getBoatClass(Leaderboard leaderboard) {
|
||||
public static BoatClass getBoatClass(Leaderboard leaderboard) {
|
||||
if(leaderboard instanceof RegattaLeaderboard) {
|
||||
RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard;
|
||||
BoatClass boatClassFromRegatta = regattaLeaderboard.getRegatta().getBoatClass();
|
||||
|
||||
+1
-1
@@ -709,7 +709,7 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel implement
|
||||
* Looks up the regatta for the selected leaderboard by name in {@link #allRegattas}
|
||||
*/
|
||||
protected RegattaDTO getSelectedRegatta() {
|
||||
final String regattaName = getSelectedLeaderboard().regattaName;
|
||||
final String regattaName = getSelectedLeaderboard() == null ? "" : getSelectedLeaderboard().regattaName;
|
||||
return getRegattaByName(regattaName);
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -9,6 +9,7 @@ import com.google.gwt.dom.client.SelectElement;
|
||||
import com.google.gwt.event.dom.client.ChangeEvent;
|
||||
import com.google.gwt.event.dom.client.ChangeHandler;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.DoubleBox;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ListBox;
|
||||
@@ -42,7 +43,7 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
|
||||
|
||||
protected StringMessages stringMessages;
|
||||
private final RegattaDTO regatta;
|
||||
|
||||
|
||||
protected final BetterDateTimeBox startDateBox;
|
||||
protected final BetterDateTimeBox endDateBox;
|
||||
protected final ListBox scoringSchemeListBox;
|
||||
@@ -50,6 +51,7 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
|
||||
protected final ListBox sailingEventsListBox;
|
||||
protected final CheckBox useStartTimeInferenceCheckBox;
|
||||
protected final CheckBox controlTrackingFromStartAndFinishTimesCheckBox;
|
||||
protected final DoubleBox buoyZoneRadiusInHullLengthsDoubleBox;
|
||||
protected final ListEditorComposite<SeriesDTO> seriesEditor;
|
||||
private final ListBox rankingMetricListBox;
|
||||
|
||||
@@ -93,7 +95,10 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
|
||||
controlTrackingFromStartAndFinishTimesCheckBox = createCheckbox(stringMessages.controlTrackingFromStartAndFinishTimes());
|
||||
controlTrackingFromStartAndFinishTimesCheckBox.ensureDebugId("ControlTrackingFromStartAndFinishTimesCheckBox");
|
||||
controlTrackingFromStartAndFinishTimesCheckBox.setValue(regatta.controlTrackingFromStartAndFinishTimes);
|
||||
|
||||
|
||||
buoyZoneRadiusInHullLengthsDoubleBox = createDoubleBox(regatta.buoyZoneRadiusInHullLengths, 10);
|
||||
buoyZoneRadiusInHullLengthsDoubleBox.ensureDebugId("BuoyZoneRadiusInHullLengthsDoubleBox");
|
||||
|
||||
courseAreaListBox = createListBox(false);
|
||||
courseAreaListBox.ensureDebugId("CourseAreaListBox");
|
||||
courseAreaListBox.setEnabled(false);
|
||||
@@ -142,7 +147,7 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
|
||||
if (additionalWidget != null) {
|
||||
panel.add(additionalWidget);
|
||||
}
|
||||
Grid formGrid = new Grid(8, 2);
|
||||
Grid formGrid = new Grid(9, 2);
|
||||
panel.add(formGrid);
|
||||
|
||||
formGrid.setWidget(0, 0, new Label(stringMessages.timeZone() + ":"));
|
||||
@@ -161,6 +166,8 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
|
||||
formGrid.setWidget(6, 1, useStartTimeInferenceCheckBox);
|
||||
formGrid.setWidget(7, 0, new Label(stringMessages.controlTrackingFromStartAndFinishTimes() + ":"));
|
||||
formGrid.setWidget(7, 1, controlTrackingFromStartAndFinishTimesCheckBox);
|
||||
formGrid.setWidget(8, 0, new Label(stringMessages.buoyZoneRadiusInHullLengths() + ":"));
|
||||
formGrid.setWidget(8, 1, buoyZoneRadiusInHullLengthsDoubleBox);
|
||||
setupAdditionalWidgetsOnPanel(panel, formGrid);
|
||||
return panel;
|
||||
}
|
||||
@@ -285,6 +292,7 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
|
||||
result.scoringScheme = getSelectedScoringSchemeType();
|
||||
result.useStartTimeInference = useStartTimeInferenceCheckBox.getValue();
|
||||
result.controlTrackingFromStartAndFinishTimes = controlTrackingFromStartAndFinishTimesCheckBox.getValue();
|
||||
result.buoyZoneRadiusInHullLengths = buoyZoneRadiusInHullLengthsDoubleBox.getValue();
|
||||
setCourseAreaInRegatta(result);
|
||||
result.series = getSeriesEditor().getValue();
|
||||
return result;
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.SuggestBox;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
@@ -187,7 +188,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
|
||||
color = new InvalidColor(iae);
|
||||
}
|
||||
}
|
||||
BoatClassDTO boatClass = new BoatClassDTO(boatClassName.getValue(), 0);
|
||||
BoatClassDTO boatClass = new BoatClassDTO(boatClassName.getValue(), Distance.NULL);
|
||||
BoatDTO boat = new BoatDTO(name.getText(), sailId.getText());
|
||||
CompetitorDTO result = new CompetitorDTOImpl(name.getText(), color, email.getText(),
|
||||
/* twoLetterIsoCountryCode */ null,
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.AbstractLeaderboardConfigPanel.RaceColumnDTOAndFleetDTOWithNameBasedEquality;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
@@ -27,7 +28,7 @@ public class CopyCourseAndCompetitorsDialog extends DataEntryDialog<CourseAndCom
|
||||
|
||||
public CopyCourseAndCompetitorsDialog(SailingServiceAsync sailingService, ErrorReporter errorReporter, final StringMessages stringMessages,
|
||||
Collection<RaceColumnDTOAndFleetDTOWithNameBasedEquality> races,
|
||||
String leaderboardName, DialogCallback<CourseAndCompetitorCopyOperation> dialogCallback) {
|
||||
String leaderboardName, Distance buoyZoneRadius, DialogCallback<CourseAndCompetitorCopyOperation> dialogCallback) {
|
||||
super(stringMessages.selectRaces(), stringMessages.selectRaces(), stringMessages.ok(), stringMessages.cancel(),
|
||||
new Validator<CourseAndCompetitorCopyOperation>() {
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ public class CreateRegattaCallback implements DialogCallback<RegattaDTO>{
|
||||
sailingService.createRegatta(newRegatta.getName(), newRegatta.boatClass==null?null:newRegatta.boatClass.getName(),
|
||||
newRegatta.startDate, newRegatta.endDate,
|
||||
new RegattaCreationParametersDTO(seriesStructure), true,
|
||||
newRegatta.scoringScheme, newRegatta.defaultCourseAreaUuid, newRegatta.useStartTimeInference,
|
||||
newRegatta.scoringScheme, newRegatta.defaultCourseAreaUuid, newRegatta.buoyZoneRadiusInHullLengths, newRegatta.useStartTimeInference,
|
||||
newRegatta.controlTrackingFromStartAndFinishTimes,
|
||||
newRegatta.rankingMetricType, new AsyncCallback<RegattaDTO>() {
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public class DeviceConfigurationQRIdentifierDialog extends DialogBox {
|
||||
Window.alert(stringMessages.notCapableOfGeneratingACodeForIdentifier());
|
||||
} else if (!identifierBox.getValue().isEmpty() && !serverBox.getValue().isEmpty()) {
|
||||
String apkUrl = getServerUrlWithoutFinalSlash() + rcAppApkPath;
|
||||
return DeviceConfigurationQRCodeUtils.composeQRContent(URL.encodeQueryString(identifierBox.getValue()), apkUrl, accessToken);
|
||||
return DeviceConfigurationQRCodeUtils.composeQRContent(URL.encodeQueryString(identifierBox.getValue()), apkUrl, URL.encodeQueryString(accessToken));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+2
-5
@@ -37,14 +37,11 @@ public class EventCreateDialog extends EventDialog {
|
||||
endDateBox = createDateTimeBox(now);
|
||||
endDateBox.setFormat("dd/mm/yyyy hh:ii");
|
||||
endDateBox.ensureDebugId("EndDateTimeBox");
|
||||
officialWebsiteURLEntryField = createTextBox(null);
|
||||
officialWebsiteURLEntryField.setVisibleLength(50);
|
||||
baseURLEntryField = createTextBox(null);
|
||||
baseURLEntryField.setVisibleLength(50);
|
||||
sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(Collections.<String, String> emptyMap());
|
||||
isPublicCheckBox = createCheckbox("");
|
||||
isPublicCheckBox.setValue(false);
|
||||
isPublicCheckBox.ensureDebugId("IsPublicCheckBox");
|
||||
baseURLEntryField = createTextBox(null);
|
||||
baseURLEntryField.setVisibleLength(50);
|
||||
imagesListComposite.fillImages(Collections.<ImageDTO>emptyList());
|
||||
videosListComposite.fillVideos(Collections.<VideoDTO>emptyList());
|
||||
// add default course area
|
||||
|
||||
+9
-31
@@ -5,7 +5,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@@ -32,7 +31,6 @@ import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.VenueDTO;
|
||||
import com.sap.sse.gwt.client.GWTLocaleUtil;
|
||||
import com.sap.sse.gwt.client.IconResources;
|
||||
import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite;
|
||||
import com.sap.sse.gwt.client.controls.listedit.StringConstantsListEditorComposite;
|
||||
@@ -48,14 +46,13 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
|
||||
protected BetterDateTimeBox endDateBox;
|
||||
protected CheckBox isPublicCheckBox;
|
||||
protected UUID id;
|
||||
protected TextBox officialWebsiteURLEntryField;
|
||||
protected TextBox baseURLEntryField;
|
||||
protected Map<String, TextBox> sailorsInfoWebsiteURLEntryFields = new HashMap<>();
|
||||
protected CourseAreaListInlineEditorComposite courseAreaNameList;
|
||||
protected StringConstantsListEditorComposite leaderboardGroupList;
|
||||
protected Map<String, LeaderboardGroupDTO> availableLeaderboardGroupsByName;
|
||||
protected ImagesListComposite imagesListComposite;
|
||||
protected VideosListComposite videosListComposite;
|
||||
protected ExternalLinksComposite externalLinksComposite;
|
||||
|
||||
protected static class EventParameterValidator implements Validator<EventDTO> {
|
||||
|
||||
@@ -162,6 +159,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
|
||||
|
||||
imagesListComposite = new ImagesListComposite(sailingService, stringMessages);
|
||||
videosListComposite = new VideosListComposite(stringMessages);
|
||||
externalLinksComposite = new ExternalLinksComposite(stringMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,13 +174,9 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
|
||||
}
|
||||
result.setName(nameEntryField.getText());
|
||||
result.setDescription(descriptionEntryField.getText());
|
||||
result.setOfficialWebsiteURL(officialWebsiteURLEntryField.getText().trim().isEmpty() ? null : officialWebsiteURLEntryField.getText().trim());
|
||||
result.setOfficialWebsiteURL(externalLinksComposite.getOfficialWebsiteURLValue());
|
||||
result.setBaseURL(baseURLEntryField.getText().trim().isEmpty() ? null : baseURLEntryField.getText().trim());
|
||||
for (Map.Entry<String, TextBox> sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) {
|
||||
TextBox sailorsInfoWebsiteURLEntryField = sailorsInfoWebsiteUrlEntry.getValue();
|
||||
String sailorsInfoWebsiteURL = sailorsInfoWebsiteURLEntryField.getText().trim();
|
||||
result.setSailorsInfoWebsiteURL(sailorsInfoWebsiteUrlEntry.getKey(), sailorsInfoWebsiteURL.isEmpty() ? null : sailorsInfoWebsiteURLEntryField.getText().trim());
|
||||
}
|
||||
result.setSailorsInfoWebsiteURLs(externalLinksComposite.getSailorsInfoWebsiteURLs());
|
||||
result.startDate = startDateBox.getValue();
|
||||
result.endDate = endDateBox.getValue();
|
||||
result.isPublic = isPublicCheckBox.getValue();
|
||||
@@ -206,7 +200,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
|
||||
if (additionalWidget != null) {
|
||||
panel.add(additionalWidget);
|
||||
}
|
||||
Grid formGrid = new Grid(10 + GWTLocaleUtil.getLanguageCountWithDefault(), 2);
|
||||
Grid formGrid = new Grid(8, 2);
|
||||
int rowIndex = 0;
|
||||
formGrid.setWidget(rowIndex, 0, new Label(stringMessages.name() + ":"));
|
||||
formGrid.setWidget(rowIndex++, 1, nameEntryField);
|
||||
@@ -222,24 +216,18 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
|
||||
formGrid.setWidget(rowIndex++, 1, endDateBox);
|
||||
formGrid.setWidget(rowIndex, 0, new Label(stringMessages.isPublic() + ":"));
|
||||
formGrid.setWidget(rowIndex++, 1, isPublicCheckBox);
|
||||
formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":"));
|
||||
formGrid.setWidget(rowIndex++, 1, officialWebsiteURLEntryField);
|
||||
formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventBaseURL() + ":"));
|
||||
formGrid.setWidget(rowIndex++, 1, baseURLEntryField);
|
||||
for (Map.Entry<String, TextBox> sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) {
|
||||
String suffix = " ["+ (sailorsInfoWebsiteUrlEntry.getKey() == null ? stringMessages.defaultLocale() + "*" : sailorsInfoWebsiteUrlEntry.getKey()) + "]";
|
||||
formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventSailorsInfoWebsiteURL() + suffix + ":"));
|
||||
formGrid.setWidget(rowIndex, 1, sailorsInfoWebsiteUrlEntry.getValue());
|
||||
rowIndex++;
|
||||
}
|
||||
formGrid.setText(rowIndex, 1, "[*] " + stringMessages.defaultSailorsInfoLinkInfoText());
|
||||
TabLayoutPanel tabPanel = new TabLayoutPanel(30, Unit.PX);
|
||||
tabPanel.ensureDebugId("EventDialogTabs");
|
||||
tabPanel.setHeight("525px");
|
||||
tabPanel.setHeight("400px");
|
||||
panel.add(tabPanel);
|
||||
final ScrollPanel eventTab = new ScrollPanel(formGrid);
|
||||
eventTab.ensureDebugId("EventTab");
|
||||
tabPanel.add(eventTab, stringMessages.event());
|
||||
final ScrollPanel externalLinksCompositeTab = new ScrollPanel(externalLinksComposite);
|
||||
externalLinksCompositeTab.ensureDebugId("ExternalLinksCompositeTab");
|
||||
tabPanel.add(externalLinksCompositeTab, stringMessages.externalLinks());
|
||||
final ScrollPanel leaderboardGroupTab = new ScrollPanel(leaderboardGroupList);
|
||||
leaderboardGroupTab.ensureDebugId("LeaderboardGroupsTab");
|
||||
tabPanel.add(leaderboardGroupTab, stringMessages.leaderboardGroups());
|
||||
@@ -259,14 +247,4 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
|
||||
protected FocusWidget getInitialFocusWidget() {
|
||||
return nameEntryField;
|
||||
}
|
||||
|
||||
protected Map<String, TextBox> createTextBoxesForLocalesAndDefault(Map<String, String> initialValues) {
|
||||
Map<String, TextBox> result = new LinkedHashMap<>();
|
||||
for(String localeName : GWTLocaleUtil.getAvailableLocalesAndDefault()) {
|
||||
TextBox sailorsInfoWebsiteURLEntryField = createTextBox(initialValues.get(localeName));
|
||||
sailorsInfoWebsiteURLEntryField.setVisibleLength(50);
|
||||
result.put(localeName, sailorsInfoWebsiteURLEntryField);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+2
-4
@@ -27,12 +27,9 @@ public class EventEditDialog extends EventDialog {
|
||||
endDateBox.setFormat("dd/mm/yyyy hh:ii");
|
||||
isPublicCheckBox = createCheckbox("");
|
||||
isPublicCheckBox.setValue(event.isPublic);
|
||||
id = event.id;
|
||||
officialWebsiteURLEntryField = createTextBox(event.getOfficialWebsiteURL());
|
||||
officialWebsiteURLEntryField.setVisibleLength(50);
|
||||
baseURLEntryField = createTextBox(event.getBaseURL());
|
||||
baseURLEntryField.setVisibleLength(50);
|
||||
sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(event.getSailorsInfoWebsiteURLs());
|
||||
id = event.id;
|
||||
courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas()));
|
||||
List<String> leaderboardGroupNames = new ArrayList<>();
|
||||
for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) {
|
||||
@@ -41,5 +38,6 @@ public class EventEditDialog extends EventDialog {
|
||||
leaderboardGroupList.setValue(leaderboardGroupNames);
|
||||
imagesListComposite.fillImages(event.getImages());
|
||||
videosListComposite.fillVideos(event.getVideos());
|
||||
externalLinksComposite.fillExternalLinks(event);
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.i18n.client.LocaleInfo;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sse.gwt.client.GWTLocaleUtil;
|
||||
|
||||
public class ExternalLinksComposite extends Composite {
|
||||
|
||||
private Map<String, TextBox> sailorsInfoWebsiteURLEntryFields = new HashMap<>();
|
||||
private TextBox officialWebsiteURLEntryField;
|
||||
|
||||
public ExternalLinksComposite(StringMessages stringMessages) {
|
||||
VerticalPanel panel = new VerticalPanel();
|
||||
panel.setWidth("100%");
|
||||
|
||||
officialWebsiteURLEntryField = new TextBox();
|
||||
officialWebsiteURLEntryField.setVisibleLength(50);
|
||||
sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(Collections.<String, String> emptyMap());
|
||||
|
||||
int rowIndex = 0;
|
||||
Grid formGrid = new Grid(GWTLocaleUtil.getLanguageCountWithDefault() + 3, 2);
|
||||
formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":"));
|
||||
formGrid.setWidget(rowIndex++, 1, officialWebsiteURLEntryField);
|
||||
formGrid.setWidget(rowIndex++, 0, new Label(stringMessages.eventSailorsInfoWebsiteURL()));
|
||||
for (Map.Entry<String, TextBox> sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) {
|
||||
String locale = sailorsInfoWebsiteUrlEntry.getKey();
|
||||
String suffix = locale == null ? "*" : "[" + locale + "]";
|
||||
String text = locale == null ? stringMessages.urlForAllLanguages()
|
||||
: stringMessages.urlForLanguage(LocaleInfo.getLocaleNativeDisplayName(locale));
|
||||
Label urlLabel = new Label(text + " " + suffix + ":");
|
||||
urlLabel.getElement().getStyle().setMarginLeft(10, Unit.PX);
|
||||
formGrid.setWidget(rowIndex, 0, urlLabel);
|
||||
formGrid.setWidget(rowIndex, 1, sailorsInfoWebsiteUrlEntry.getValue());
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
panel.add(formGrid);
|
||||
panel.add(new Label("[*] " + stringMessages.defaultSailorsInfoLinkInfoText()));
|
||||
initWidget(panel);
|
||||
}
|
||||
|
||||
public String getOfficialWebsiteURLValue() {
|
||||
String value = officialWebsiteURLEntryField.getText().trim();
|
||||
return value.isEmpty() ? null : value;
|
||||
}
|
||||
|
||||
public Map<String, String> getSailorsInfoWebsiteURLs() {
|
||||
Map<String, String> sailorsInfoWebsiteURLsMap = new HashMap<>();
|
||||
for (Map.Entry<String, TextBox> sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) {
|
||||
TextBox sailorsInfoWebsiteURLEntryField = sailorsInfoWebsiteUrlEntry.getValue();
|
||||
String sailorsInfoWebsiteURL = sailorsInfoWebsiteURLEntryField.getText().trim();
|
||||
sailorsInfoWebsiteURLsMap.put(sailorsInfoWebsiteUrlEntry.getKey(),
|
||||
sailorsInfoWebsiteURL.isEmpty() ? null : sailorsInfoWebsiteURL);
|
||||
}
|
||||
return sailorsInfoWebsiteURLsMap;
|
||||
}
|
||||
|
||||
public void fillExternalLinks(EventDTO event) {
|
||||
Map<String, String> initialValues = event.getSailorsInfoWebsiteURLs();
|
||||
for (String localeName : GWTLocaleUtil.getAvailableLocalesAndDefault()) {
|
||||
sailorsInfoWebsiteURLEntryFields.get(localeName).setValue(initialValues.get(localeName));
|
||||
}
|
||||
officialWebsiteURLEntryField.setValue(event.getOfficialWebsiteURL());
|
||||
}
|
||||
|
||||
private Map<String, TextBox> createTextBoxesForLocalesAndDefault(Map<String, String> initialValues) {
|
||||
Map<String, TextBox> result = new LinkedHashMap<>();
|
||||
for (String localeName : GWTLocaleUtil.getAvailableLocalesAndDefault()) {
|
||||
TextBox sailorsInfoWebsiteURLEntryField = new TextBox();
|
||||
sailorsInfoWebsiteURLEntryField.setValue(initialValues.get(localeName));
|
||||
sailorsInfoWebsiteURLEntryField.setVisibleLength(50);
|
||||
result.put(localeName, sailorsInfoWebsiteURLEntryField);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+8
-4
@@ -49,7 +49,7 @@ public class RegattaDetailsComposite extends Composite {
|
||||
private final ErrorReporter errorReporter;
|
||||
private final StringMessages stringMessages;
|
||||
private final RegattaRefresher regattaRefresher;
|
||||
|
||||
|
||||
private final Label regattaId;
|
||||
private final Label regattaName;
|
||||
private final Label startDate;
|
||||
@@ -61,7 +61,8 @@ public class RegattaDetailsComposite extends Composite {
|
||||
private final Label useStartTimeInference;
|
||||
private final Label controlTrackingFromStartAndFinishTimes;
|
||||
private final Label configuration;
|
||||
|
||||
private final Label buoyZoneRadiusInHullLengths;
|
||||
|
||||
private final SelectionModel<SeriesDTO> seriesSelectionModel;
|
||||
private final CellTable<SeriesDTO> seriesTable;
|
||||
private ListDataProvider<SeriesDTO> seriesListDataProvider;
|
||||
@@ -79,7 +80,7 @@ public class RegattaDetailsComposite extends Composite {
|
||||
VerticalPanel vPanel = new VerticalPanel();
|
||||
mainPanel.add(vPanel);
|
||||
|
||||
int rows = 11;
|
||||
int rows = 12;
|
||||
Grid grid = new Grid(rows, 2);
|
||||
vPanel.add(grid);
|
||||
|
||||
@@ -92,10 +93,11 @@ public class RegattaDetailsComposite extends Composite {
|
||||
defaultCourseArea = createLabelAndValueWidget(grid, currentRow++, stringMessages.courseArea(), "CourseAreaLabel");
|
||||
useStartTimeInference = createLabelAndValueWidget(grid, currentRow++, stringMessages.useStartTimeInference(), "UseStartTimeInferenceLabel");
|
||||
controlTrackingFromStartAndFinishTimes = createLabelAndValueWidget(grid, currentRow++, stringMessages.controlTrackingFromStartAndFinishTimes(), "UseStartTimeInferenceLabel");
|
||||
buoyZoneRadiusInHullLengths = createLabelAndValueWidget(grid, currentRow++, stringMessages.buoyZoneRadiusInHullLengths(), "BuoyZoneRadiusInHullLengthsLabel");
|
||||
configuration = createLabelAndValueWidget(grid, currentRow++, stringMessages.racingProcedureConfiguration(), "RacingProcedureLabel");
|
||||
scoringSystem = createLabelAndValueWidget(grid, currentRow++, stringMessages.scoringSystem(), "ScoringSystemLabel");
|
||||
rankingMetric = createLabelAndValueWidget(grid, currentRow++, stringMessages.rankingMetric(), "RankingMetricLabel");
|
||||
|
||||
|
||||
seriesTable = createRegattaSeriesTable();
|
||||
seriesTable.ensureDebugId("SeriesCellTable");
|
||||
seriesSelectionModel = new SingleSelectionModel<SeriesDTO>();
|
||||
@@ -398,6 +400,8 @@ public class RegattaDetailsComposite extends Composite {
|
||||
defaultCourseArea.setText(regatta.defaultCourseAreaUuid == null ? "" : regatta.defaultCourseAreaName);
|
||||
useStartTimeInference.setText(regatta.useStartTimeInference ? stringMessages.yes() : stringMessages.no());
|
||||
controlTrackingFromStartAndFinishTimes.setText(regatta.controlTrackingFromStartAndFinishTimes ? stringMessages.yes() : stringMessages.no());
|
||||
buoyZoneRadiusInHullLengths.setText(String.valueOf(regatta.buoyZoneRadiusInHullLengths));
|
||||
|
||||
if (regatta.configuration != null) {
|
||||
configuration.setText(stringMessages.configured());
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -290,7 +290,7 @@ public class RegattaListComposite extends Composite implements RegattasDisplayer
|
||||
final RegattaIdentifier regattaName = new RegattaName(editedRegatta.getName());
|
||||
|
||||
sailingService.updateRegatta(regattaName, editedRegatta.startDate, editedRegatta.endDate, editedRegatta.defaultCourseAreaUuid,
|
||||
editedRegatta.configuration, editedRegatta.useStartTimeInference, editedRegatta.controlTrackingFromStartAndFinishTimes,
|
||||
editedRegatta.configuration, editedRegatta.buoyZoneRadiusInHullLengths, editedRegatta.useStartTimeInference, editedRegatta.controlTrackingFromStartAndFinishTimes,
|
||||
new MarkedAsyncCallback<Void>(new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
|
||||
+6
@@ -12,6 +12,7 @@ import com.google.gwt.user.client.ui.FocusWidget;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.TabPanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
@@ -72,6 +73,10 @@ public class RegattaWithSeriesAndFleetsCreateDialog extends RegattaWithSeriesAnd
|
||||
errorMessage = stringMessages.regattaWithThisNameAlreadyExists();
|
||||
}
|
||||
|
||||
if (regattaToValidate.buoyZoneRadiusInHullLengths == null) {
|
||||
errorMessage = stringMessages.incorrectValueForRegattaBuoyZoneRadiusInHullLengths();
|
||||
}
|
||||
|
||||
if (errorMessage == null) {
|
||||
List<SeriesDTO> seriesToValidate = regattaToValidate.series;
|
||||
int index = 0;
|
||||
@@ -109,6 +114,7 @@ public class RegattaWithSeriesAndFleetsCreateDialog extends RegattaWithSeriesAnd
|
||||
List<EventDTO> existingEvents, EventDTO correspondingEvent, StringMessages stringMessages, DialogCallback<RegattaDTO> callback) {
|
||||
super(new RegattaDTO(), Collections.<SeriesDTO>emptySet(), existingEvents, correspondingEvent, stringMessages.addRegatta(), stringMessages.ok(),
|
||||
stringMessages, new RegattaParameterValidator(stringMessages, existingRegattas), callback);
|
||||
buoyZoneRadiusInHullLengthsDoubleBox.setValue(Regatta.DEFAULT_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS);
|
||||
SeriesDTO series = new SeriesDTO();
|
||||
series.setName(Series.DEFAULT_NAME);
|
||||
series.setMedal(false);
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.SuggestBox;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.gwt.common.client.suggestion.BoatClassMasterdataSuggestOracle;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
@@ -47,7 +48,7 @@ public abstract class RegattaWithSeriesAndFleetsDialog extends AbstractRegattaWi
|
||||
protected RegattaDTO getResult() {
|
||||
RegattaDTO result = getRegattaDTO();
|
||||
result.setName(nameEntryField.getText().trim()); // trim to particularly avoid trailing blanks
|
||||
result.boatClass = new BoatClassDTO(boatClassEntryField.getText(), 0.0);
|
||||
result.boatClass = new BoatClassDTO(boatClassEntryField.getText(), Distance.NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+18
-1
@@ -25,10 +25,27 @@ public class RegattaWithSeriesAndFleetsEditDialog extends RegattaWithSeriesAndFl
|
||||
|
||||
private RegattaConfigurationDTO currentRegattaConfiguration;
|
||||
|
||||
protected static class RegattaParameterValidator implements Validator<RegattaDTO> {
|
||||
private StringMessages stringMessages;
|
||||
|
||||
public RegattaParameterValidator(StringMessages stringMessages) {
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage(RegattaDTO regattaToValidate) {
|
||||
String errorMessage = null;
|
||||
if (regattaToValidate.buoyZoneRadiusInHullLengths == null) {
|
||||
errorMessage = stringMessages.incorrectValueForRegattaBuoyZoneRadiusInHullLengths();
|
||||
}
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public RegattaWithSeriesAndFleetsEditDialog(RegattaDTO regatta, Collection<RegattaDTO> existingRegattas,
|
||||
List<EventDTO> existingEvents, EventDTO correspondingEvent, final StringMessages stringMessages, DialogCallback<RegattaDTO> callback) {
|
||||
super(regatta, regatta.series, existingEvents, correspondingEvent, stringMessages.editRegatta(), stringMessages.ok(), stringMessages,
|
||||
null, callback);
|
||||
new RegattaParameterValidator(stringMessages), callback);
|
||||
ensureDebugId("RegattaWithSeriesAndFleetsEditDialog");
|
||||
currentRegattaConfiguration = regatta.configuration;
|
||||
|
||||
|
||||
+7
-2
@@ -31,6 +31,7 @@ import com.google.gwt.view.client.ListDataProvider;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
|
||||
import com.sap.sailing.domain.common.CourseDesignerMode;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
@@ -49,6 +50,7 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.controls.FlushableCellTable;
|
||||
import com.sap.sailing.gwt.ui.client.shared.controls.SelectionCheckboxColumn;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings;
|
||||
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
@@ -336,8 +338,11 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
|
||||
List<RaceColumnDTOAndFleetDTOWithNameBasedEquality> races =
|
||||
new ArrayList<>(raceColumnTable.getDataProvider().getList());
|
||||
races.remove(raceColumnDTOAndFleetDTO);
|
||||
Distance buoyZoneRadius = getSelectedRegatta() == null
|
||||
? RaceMapSettings.DEFAULT_BUOY_ZONE_RADIUS
|
||||
: getSelectedRegatta().getCalculatedBuoyZoneRadius();
|
||||
new CopyCourseAndCompetitorsDialog(sailingService, errorReporter, stringMessages, races,
|
||||
leaderboardName, new DialogCallback<CourseAndCompetitorCopyOperation>() {
|
||||
leaderboardName, buoyZoneRadius, new DialogCallback<CourseAndCompetitorCopyOperation>() {
|
||||
@Override
|
||||
public void ok(CourseAndCompetitorCopyOperation operation) {
|
||||
operation.perform(leaderboardName, raceColumnDTOAndFleetDTO, /* onSuccessCallback */ new Runnable() {
|
||||
@@ -619,7 +624,7 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
|
||||
DeviceConfigurationDTO.RegattaConfigurationDTO configuration) {
|
||||
final RegattaIdentifier regattaIdentifier = new RegattaName(regatta.getName());
|
||||
sailingService.updateRegatta(regattaIdentifier, regatta.startDate, regatta.endDate,
|
||||
regatta.defaultCourseAreaUuid, configuration, regatta.useStartTimeInference,
|
||||
regatta.defaultCourseAreaUuid, configuration, regatta.buoyZoneRadiusInHullLengths, regatta.useStartTimeInference,
|
||||
regatta.controlTrackingFromStartAndFinishTimes,
|
||||
new MarkedAsyncCallback<Void>(new AsyncCallback<Void>() {
|
||||
@Override
|
||||
|
||||
+2
-1
@@ -35,6 +35,7 @@ import com.google.gwt.view.client.SelectionChangeEvent.Handler;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.StructureImportListComposite.RegattaStructureProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
@@ -341,7 +342,7 @@ public class StructureImportManagementPanel extends SimplePanel implements Regat
|
||||
*/
|
||||
private RegattaDTO createRegattaDefaults(RegattaDTO regatta) {
|
||||
RegattaDTO result = new RegattaDTO("Default", ScoringSchemeType.LOW_POINT);
|
||||
result.boatClass = new BoatClassDTO(BoatClassDTO.DEFAULT_NAME, /* hull length in meters */ 5);
|
||||
result.boatClass = new BoatClassDTO(BoatClassDTO.DEFAULT_NAME, /* hull length */ new MeterDistance(5));
|
||||
result.series = regatta.series;
|
||||
result.rankingMetricType = RankingMetrics.ONE_DESIGN;
|
||||
return result;
|
||||
|
||||
+2
-2
@@ -215,7 +215,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
|
||||
RegattaDTO createRegatta(String regattaName, String boatClassName, Date startDate, Date endDate,
|
||||
RegattaCreationParametersDTO seriesNamesWithFleetNamesAndFleetOrderingAndMedal, boolean persistent,
|
||||
ScoringSchemeType scoringSchemeType, UUID defaultCourseAreaId, boolean useStartTimeInference,
|
||||
ScoringSchemeType scoringSchemeType, UUID defaultCourseAreaId, Double buoyZoneRadiusInHullLengths, boolean useStartTimeInference,
|
||||
boolean controlTrackingFromStartAndFinishTimes, RankingMetrics rankingMetricType);
|
||||
|
||||
void removeRegatta(RegattaIdentifier regattaIdentifier);
|
||||
@@ -225,7 +225,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
void removeRegattas(Collection<RegattaIdentifier> regattas);
|
||||
|
||||
void updateRegatta(RegattaIdentifier regattaIdentifier, Date startDate, Date endDate, UUID defaultCourseAreaUuid,
|
||||
RegattaConfigurationDTO regattaConfiguration, boolean useStartTimeInference, boolean controlTrackingFromStartAndFinishTimes);
|
||||
RegattaConfigurationDTO regattaConfiguration, Double buoyZoneRadiusInHullLengths, boolean useStartTimeInference, boolean controlTrackingFromStartAndFinishTimes);
|
||||
|
||||
List<RaceColumnInSeriesDTO> addRaceColumnsToSeries(RegattaIdentifier regattaIdentifier, String seriesName,
|
||||
List<Pair<String, Integer>> columnNames);
|
||||
|
||||
+2
-2
@@ -441,7 +441,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
|
||||
void createRegatta(String regattaName, String boatClassName, Date startDate, Date endDate,
|
||||
RegattaCreationParametersDTO seriesNamesWithFleetNamesAndFleetOrderingAndMedal, boolean persistent,
|
||||
ScoringSchemeType scoringSchemeType, UUID defaultCourseAreaId, boolean useStartTimeInference,
|
||||
ScoringSchemeType scoringSchemeType, UUID defaultCourseAreaId, Double buoyZoneRadiusInHullLengths, boolean useStartTimeInference,
|
||||
boolean controlTrackingFromStartAndFinishTimes, RankingMetrics rankingMetricType,
|
||||
AsyncCallback<RegattaDTO> callback);
|
||||
|
||||
@@ -528,7 +528,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
void storeSwissTimingArchiveConfiguration(String swissTimingUrl, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void updateRegatta(RegattaIdentifier regattaIdentifier, Date startDate, Date endDate, UUID defaultCourseAreaUuid,
|
||||
RegattaConfigurationDTO regattaConfiguration, boolean useStartTimeInference,
|
||||
RegattaConfigurationDTO regattaConfiguration, Double buoyZoneRadiusInHullLengths, boolean useStartTimeInference,
|
||||
boolean controlTrackingFromStartAndFinishTimes, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
|
||||
+5
@@ -1738,4 +1738,9 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String lastFix();
|
||||
String filterDeviceMappings();
|
||||
String raceStartAnalysis();
|
||||
String urlForLanguage(String language);
|
||||
String urlForAllLanguages();
|
||||
String externalLinks();
|
||||
String buoyZoneRadiusInHullLengths();
|
||||
String incorrectValueForRegattaBuoyZoneRadiusInHullLengths();
|
||||
}
|
||||
+6
-2
@@ -1616,10 +1616,12 @@ raceAnalysis=Race analysis
|
||||
startAnalysis=Start analysis
|
||||
winningLanes=Winning lanes
|
||||
maximumNumberOfDiscards=Maximum number of discards
|
||||
externalLinks=External links
|
||||
urlForAllLanguages=URL for all languages
|
||||
urlForLanguage=URL for language ''{0}''
|
||||
notificationRegattaConfigurationUpdatedUsingByMarks=Active regatta configuration was set, using the "By Marks" course designer.
|
||||
warningOverrideRegattaConfigurationCourseDesignerToByMarks=Active regatta configuration already exists, but with the wrong course designer setting.\nWould you like to override course designer setting to "By Marks"?
|
||||
allRacesHaveBeenDenoted=All races have been denoted for racelog tracking.
|
||||
|
||||
chartSelectionHint=Hint: You can also use the leaderboard (on the LEADERBOARD tab) to select the competitors displayed in the chart.
|
||||
chooseALanguage=Choose a language
|
||||
solutions=Solutions
|
||||
@@ -1710,4 +1712,6 @@ strategySimulatorReadMore=Learn More
|
||||
impressum=Imprint
|
||||
lastFix=Last fix
|
||||
filterDeviceMappings=Filter device mappings
|
||||
raceStartAnalysis=Race Start Analysis
|
||||
raceStartAnalysis=Race Start Analysis
|
||||
buoyZoneRadiusInHullLengths=Buoy zone radius in hull lengths (e.g., 2 or 3)
|
||||
incorrectValueForRegattaBuoyZoneRadiusInHullLengths=Incorrect value for the buoy zone radius in hull lengths
|
||||
Loaded 100 of 162 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user