Merge branch 'master' into bug3938

This commit is contained in:
Kai Boernert committed 2016-10-18 11:20:24 +02:00
commit 34386899e7
20 files changed
+508 -138

No files matched your search

@@ -2,6 +2,8 @@ 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.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 +18,8 @@ public final class SailingDataMiningSerializationDummy implements SerializationD
private CentralAngleDistance centralAngleDistance;
private MeterDistance meterDistance;
private NauticalMileDistance nauticalMileDistance;
private ManeuverType maneuverType;
private Tack tack;
private SailingDataMiningSerializationDummy() { }
@@ -16,6 +16,7 @@ Race=Race
Competitor=Competitor
Boat=Boat
Team=Team
CompetitorSearchTag=Competitor Search Tag
LeaderboardSailingDomainRetrieverChain=Leaderboards
RaceSailingDomainRetrieverChain=Races
LegSailingDomainRetrieverChain=Legs
@@ -23,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
@@ -43,7 +46,8 @@ Bft9=Strong gale
Bft10=Storm
Bft11=Violent storm
Bft12=Hurricane
RelativeScoreInRace=Relative score in race (0 best; 1 worst)
RelativeScore=Relative Score (0 best; 1 worst)
AbsoluteRank=Absolute Rank
WindSpeedInBeaufort=Wind speed in Bft
DistanceAtStart=Distance to start at start
SpeedWhenStarting=Speed when starting
@@ -60,4 +64,11 @@ 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
@@ -3,6 +3,7 @@ DistanceTraveled=zur
Boat=Boot
Team=Team
Name=Name
CompetitorSearchTag=Teilnehmer Such-Tag
Nationality=Nationalitäts
Acronym=Abkürzung
SailID=Segelnummer
@@ -21,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
@@ -43,7 +46,8 @@ Bft9=Sturm
Bft10=schwerer Sturm
Bft11=orkanartiger Sturm
Bft12=Orkan
RelativeScoreInRace=Relative Wertung im Rennen (0 am besten; 1 am schlechtesten)
RelativeScore=Relative Wertung (0 am besten; 1 am schlechtesten)
AbsoluteRank=Absolute Platzierung
WindSpeedInBeaufort=Windgeschwindigkeit in Bft.
DistanceAtStart=Distanz zur Startlinie zum Startzeitpunkt
SpeedWhenStarting=Geschwindigkeit beim Überqueren der Startlinie
@@ -60,4 +64,11 @@ 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=Seite
SpeedBefore=Geschwindigkeit bevor dem Manöver
SpeedAfter=Geschwindigkeit nach dem Manöver
DirectionChange=Richtungsänderung in Grad
ManeuverLoss=Manöververlust
Waypoint=Wegpunkt
@@ -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;
@@ -82,6 +83,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);
@@ -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() {
@@ -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();
}
@@ -1,29 +1,41 @@
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.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();
@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;
}
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.Speed;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
public interface HasRaceOfCompetitorContext {
@@ -14,6 +15,9 @@ public interface HasRaceOfCompetitorContext {
@Connector(messageKey="Competitor")
public Competitor getCompetitor();
@Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible
public String getCompetitorSearchTag();
@Statistic(messageKey="DistanceAtStart", resultDecimals=2, ordinal=0)
public Distance getDistanceToStartLineAtStart();
@@ -12,22 +12,28 @@ public interface HasRaceResultOfCompetitorContext {
@Connector(messageKey="Competitor")
public Competitor getCompetitor();
/**
* 0 means the competitor won the race, 1 means the competitor ranked last
*/
@Statistic(messageKey="RelativeScoreInRace", ordinal=1, resultDecimals=2)
public double getRelativeRank();
@Dimension(messageKey="WindSpeedInBeaufort")
int getAverageWindSpeedInRoundedBeaufort();
@Dimension(messageKey="Regatta")
String getRegattaName();
@Statistic(messageKey="NumberOfPodiumFinish", ordinal=2)
@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();
@Statistic(messageKey="AbsoluteRank", ordinal=2, resultDecimals=2)
public Double getAbsoluteRank();
@Statistic(messageKey="NumberOfPodiumFinish", ordinal=3)
public Boolean isPodiumFinish();
@Statistic(messageKey="NumberOfWins", ordinal=3)
@Statistic(messageKey="NumberOfWins", ordinal=4)
public Boolean isWin();
}
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Distance;
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;
public interface HasTrackedLegOfCompetitorContext {
@@ -12,6 +13,9 @@ public interface HasTrackedLegOfCompetitorContext {
public HasTrackedLegContext getTrackedLegContext();
public TrackedLegOfCompetitor getTrackedLegOfCompetitor();
@Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible
public String getCompetitorSearchTag();
@Connector(messageKey="Competitor")
public Competitor getCompetitor();
@@ -21,5 +25,11 @@ public interface HasTrackedLegOfCompetitorContext {
@Statistic(messageKey="RankGainsOrLosses", resultDecimals=2, ordinal=1)
public Double getRankGainsOrLosses();
@Statistic(messageKey="RelativeScore", resultDecimals=2, ordinal=2)
public Double getRelativeRank();
@Statistic(messageKey="AbsoluteRank", resultDecimals=2, ordinal=3)
public Double getAbsoluteRank();
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -1,74 +1,81 @@
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.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 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();
}
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;
}
}
@@ -38,6 +38,11 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
public Competitor getCompetitor() {
return competitor;
}
@Override
public String getCompetitorSearchTag() {
return getCompetitor().getSearchTag();
}
@Override
public Distance getDistanceToStartLineAtStart() {
@@ -59,7 +64,8 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
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
@@ -97,11 +103,12 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish() {
Double rankAtFirstMark = getRankAtFirstMark();
Double rankAtFinish = getRankAtFinish();
return rankAtFirstMark - rankAtFinish;
return rankAtFirstMark != null && rankAtFinish != null ? rankAtFirstMark - rankAtFinish : null;
}
private Double getRankAtFinish() {
return Double.valueOf(getTrackedRace().getRank(getCompetitor(), getTrackedRace().getEndOfTracking()));
int rank = getTrackedRace().getRank(getCompetitor(), getTrackedRace().getEndOfTracking());
return rank == 0 ? null : Double.valueOf(rank);
}
@Override
@@ -62,17 +62,17 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti
}
@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;
public String getRegattaName() {
Leaderboard leaderboard = getLeaderboard();;
final String result = leaderboard.getName();
return result;
}
@Override
public String getCompetitorSearchTag() {
return getCompetitor().getSearchTag();
}
@Override
public int getAverageWindSpeedInRoundedBeaufort() {
Speed exactResult = getAverageWindSpeed();
@@ -157,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
@@ -4,9 +4,11 @@ import com.sap.sailing.datamining.data.HasTrackedLegContext;
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.leaderboard.Leaderboard;
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;
public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompetitorContext {
@@ -15,6 +17,11 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
private final TrackedLegOfCompetitor trackedLegOfCompetitor;
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;
this.trackedLegOfCompetitor = trackedLegOfCompetitor;
@@ -35,6 +42,11 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
public Competitor getCompetitor() {
return competitor;
}
@Override
public String getCompetitorSearchTag() {
return getCompetitor().getSearchTag();
}
@Override
public Distance getDistanceTraveled() {
@@ -44,10 +56,42 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
@Override
public Double getRankGainsOrLosses() {
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
Double rankAtStart = Double.valueOf(trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getStartTime()));
Double rankAtFinish = Double.valueOf(trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getFinishTime()));
return rankAtStart - rankAtFinish;
Double rankAtStart = getRankAtStart();
Double rankAtFinish = getRankAtFinish();
return rankAtStart != null && rankAtFinish != null ? rankAtStart - rankAtFinish : null;
}
private Double getRankAtStart() {
if (!isRankAtStartInitialized) {
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
int rank = trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getStartTime());
rankAtStart = rank == 0 ? null : Double.valueOf(rank);
isRankAtStartInitialized = true;
}
return rankAtStart;
}
@Override
public Double getRelativeRank() {
Leaderboard leaderboard = getTrackedLegContext().getTrackedRaceContext().getLeaderboardContext().getLeaderboard();
double competitorCount = Util.size(leaderboard.getCompetitors());
Double rankAtFinish = getRankAtFinish();
return rankAtFinish == null ? null : rankAtFinish / competitorCount;
}
@Override
public Double getAbsoluteRank() {
return getRankAtFinish();
}
private Double getRankAtFinish() {
if (!isRankAtFinishInitialized) {
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
int rank = trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getFinishTime());
rankAtFinish = rank == 0 ? null : Double.valueOf(rank);
isRankAtFinishInitialized = true;
}
return rankAtFinish;
}
}
@@ -10,14 +10,14 @@ Require-Bundle: org.eclipse.osgi;bundle-version="3.10.1",
com.sap.sse.datamining;bundle-version="1.0.0",
com.sap.sse.datamining.annotations;bundle-version="1.0.0",
com.sap.sse.datamining.shared;bundle-version="1.0.0",
com.sap.sailing.datamining,
com.sap.sailing.server;bundle-version="1.0.0",
com.sap.sse.common;bundle-version="1.0.0",
com.sap.sailing.domain;bundle-version="1.0.0",
com.sap.sailing.domain.shared.android,
com.sap.sailing.domain.common;bundle-version="1.0.0",
com.sap.sailing.polars.datamining.shared,
org.apache.commons.math
org.apache.commons.math,
com.sap.sailing.datamining
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Export-Package: com.sap.sailing.polars.datamining.data,
@@ -1,6 +1,7 @@
package com.sap.sailing.server.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
@@ -8,6 +9,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import org.junit.Test;
@@ -96,16 +98,99 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest
final List<Competitor> rankedCompetitorsBeforeApplying = leaderboard.getCompetitorsFromBestToWorst(later);
assertEquals(competitors, rankedCompetitorsBeforeApplying); // no effects of preliminary results list yet
f1RaceState.setFinishPositioningConfirmed(now);
final Function<Competitor, Double> expectedPoints = (c)->scores.get(c)==null?(mprs.get(c) == null || mprs.get(c) == MaxPointsReason.NONE ? competitors.indexOf(c)+1 : competitors.size()+1):scores.get(c);
for (final Competitor c : competitors) {
assertEquals(scores.get(c)==null?competitors.indexOf(c)+1:scores.get(c), leaderboard.getTotalPoints(c, f1Column, now), 0.00000001);
assertEquals(expectedPoints.apply(c), leaderboard.getTotalPoints(c, f1Column, now), 0.00000001);
}
final List<Competitor> expectedNewOrder = new ArrayList<>(competitors);
expectedNewOrder.sort((c1, c2)->
new Double(scores.get(c1)==null?competitors.indexOf(c1)+1:scores.get(c1)).compareTo(
new Double(scores.get(c2)==null?competitors.indexOf(c2)+1:scores.get(c2))));
expectedNewOrder.sort((c1, c2)->new Double(expectedPoints.apply(c1)).compareTo(new Double(expectedPoints.apply(c1))));
final List<Competitor> rankedCompetitorsAfterApplying = leaderboard.getCompetitorsFromBestToWorst(later);
assertEquals(expectedNewOrder, rankedCompetitorsAfterApplying);
double lastScore = 0;
for (final Competitor c : rankedCompetitorsAfterApplying) {
assertEquals(expectedPoints.apply(c), leaderboard.getTotalPoints(c, f1Column, later));
assertTrue(leaderboard.getTotalPoints(c, f1Column, later) >= lastScore);
lastScore = leaderboard.getTotalPoints(c, f1Column, later);
}
}
/**
* See also bug 3955: when for a competitor no score is explicitly provided but a {@link MaxPointsReason} has been set, don't
* correct the score in the leaderboard's score correction but only set the {@link MaxPointsReason}. This will let the scoring
* scheme select the score, as it used to be before the fix for bug 3794, commit 830e64842a39fb137446887c5177f7de34bd5b5a.
*/
@Test
public void testScoresFromRaceLogOnlyAppliedIfExplicitOrNoMaxPointsReason() throws NoWindException {
final RacingEventService service = new RacingEventServiceImpl();
final List<Competitor> competitors = new ArrayList<>();
for (int i=0; i<8; i++) {
final String competitorName = "C"+i;
competitors.add(service.getBaseDomainFactory().getCompetitorStore().getOrCreateCompetitor(UUID.randomUUID(),
competitorName, /* displayColor */ Color.RED, /* email */ null, /* flagImageURI */ null,
new TeamImpl("STG", Collections.singleton(
new PersonImpl(competitorName, new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous "+competitorName)),
new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null),
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null));
}
final Regatta regatta = createRegatta(/* qualifying */0, new String[] { "Default" }, /* final */1,
new String[] { "Default" },
/* medal */false, /* medal */ 0, "testOneStartedRaceWithDifferentScores",
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT));
TimePoint now = MillisecondsTimePoint.now();
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
TrackedRace f1 = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors);
RaceColumn f1Column = series.get(1).getRaceColumnByName("F1");
f1Column.setTrackedRace(f1Column.getFleets().iterator().next(), f1);
final Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]);
service.addLeaderboard(leaderboard); // should add a RaceLogScoringReplicator as listener to the leaderboard
service.addRegattaWithoutReplication(regatta);
int oneBasedRank = 1;
final CompetitorResults results = new CompetitorResultsImpl();
setResultForCompetitor(competitors.get(0), oneBasedRank++, results, MaxPointsReason.DNF, /* explicit score */ null);
setResultForCompetitor(competitors.get(1), oneBasedRank++, results, MaxPointsReason.OCS, /* explicit score */ null);
setResultForCompetitor(competitors.get(2), oneBasedRank++, results, MaxPointsReason.DNF, /* explicit score */ 0.1);
setResultForCompetitor(competitors.get(3), oneBasedRank++, results, MaxPointsReason.OCS, /* explicit score */ 0.2);
setResultForCompetitor(competitors.get(4), oneBasedRank++, results, /* maxPointsReason */ null, /* explicit score */ null);
setResultForCompetitor(competitors.get(5), oneBasedRank++, results, /* maxPointsReason */ null, /* explicit score */ 2.4);
setResultForCompetitor(competitors.get(6), oneBasedRank++, results, MaxPointsReason.NONE, /* explicit score */ null);
setResultForCompetitor(competitors.get(7), oneBasedRank++, results, MaxPointsReason.NONE, /* explicit score */ 3.3);
final RaceLog f1RaceLog = f1Column.getRaceLog(f1Column.getFleets().iterator().next());
final LogEventAuthorImpl author = new LogEventAuthorImpl("Axel", 0);
final RaceState f1RaceState = new RaceStateImpl(service, f1RaceLog, author,
new RacingProcedureFactoryImpl(author, new EmptyRegattaConfiguration()));
f1RaceState.setFinishPositioningListChanged(now, results);
final List<Competitor> rankedCompetitorsBeforeApplying = leaderboard.getCompetitorsFromBestToWorst(later);
assertEquals(competitors, rankedCompetitorsBeforeApplying); // no effects of preliminary results list yet
f1RaceState.setFinishPositioningConfirmed(now);
assertScoreCorrections(leaderboard, f1Column, competitors.get(0), MaxPointsReason.DNF, 0, /* score is corrected */ false, later);
assertScoreCorrections(leaderboard, f1Column, competitors.get(1), MaxPointsReason.OCS, 0, /* score is corrected */ false, later);
assertScoreCorrections(leaderboard, f1Column, competitors.get(2), MaxPointsReason.DNF, 0.1, /* score is corrected */ true, later);
assertScoreCorrections(leaderboard, f1Column, competitors.get(3), MaxPointsReason.OCS, 0.2, /* score is corrected */ true, later);
assertScoreCorrections(leaderboard, f1Column, competitors.get(4), MaxPointsReason.NONE, 6, /* score is corrected */ true, later); // score corrected based on rank because no MaxPointsReason set
assertScoreCorrections(leaderboard, f1Column, competitors.get(5), MaxPointsReason.NONE, 2.4, /* score is corrected */ true, later); // score corrected based on explicit score
assertScoreCorrections(leaderboard, f1Column, competitors.get(6), MaxPointsReason.NONE, 4, /* score is corrected */ true, later); // score corrected based on rank because MaxPointsReason.NONE set
assertScoreCorrections(leaderboard, f1Column, competitors.get(7), MaxPointsReason.NONE, 3.3, /* score is corrected */ true, later); // score corrected based on explicit score
}
private void assertScoreCorrections(Leaderboard leaderboard, RaceColumn raceColumn, Competitor competitor,
MaxPointsReason expectedMaxPointsReason, double expectedScore, boolean expectedIsScoreCorrected,
TimePoint timePoint) {
assertEquals(expectedIsScoreCorrected, leaderboard.getScoreCorrection().getExplicitScoreCorrection(competitor, raceColumn) != null);
assertEquals(expectedMaxPointsReason, leaderboard.getScoreCorrection().getMaxPointsReason(competitor, raceColumn, timePoint));
assertEquals(expectedScore, leaderboard.getTotalPoints(competitor, raceColumn, timePoint), 0.000001);
}
private void setResultForCompetitor(final Competitor competitor, int oneBasedRank,
final CompetitorResults results, MaxPointsReason maxPointsReason, Double explicitScore) {
results.add(new CompetitorResultImpl(competitor.getId(), competitor.getName(), oneBasedRank++, maxPointsReason, explicitScore, /* finishingTime */ null, /* comment */ null));
}
}
@@ -143,9 +143,17 @@ public class RaceLogScoringReplicator implements RaceColumnListener {
if (positioningList != null) {
for (CompetitorResult positionedCompetitor : positioningList) {
Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getCompetitorId());
int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positionedCompetitor);
correctScoreInLeaderboard(leaderboard, raceColumn, timePoint, numberOfCompetitorsInRace,
competitor, rankByRaceCommittee, positionedCompetitor.getScore());
// The score is updated when explicitly provided or when no penalty was set;
// in turn, this means that when a penalty is set and no score is explicitly provided,
// it is up to the scoring scheme to infer a penalty score for the MaxPointsReason.
// See also bug 3955.
if (positionedCompetitor.getScore() != null
|| positionedCompetitor.getMaxPointsReason() == null
|| positionedCompetitor.getMaxPointsReason().equals(MaxPointsReason.NONE)) {
int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positionedCompetitor);
correctScoreInLeaderboard(leaderboard, raceColumn, timePoint, numberOfCompetitorsInRace, competitor,
rankByRaceCommittee, positionedCompetitor.getScore());
}
setMaxPointsReasonInLeaderboardIfNecessary(leaderboard, raceColumn, timePoint, positionedCompetitor.getMaxPointsReason(), competitor);
}
// Since the metadata update is used by the Sailing suite to determine the final state of a race, it has to