Merge branch 'main' into translation

This commit is contained in:
Axel Uhl
2024-11-14 17:58:42 +01:00
38 changed files with 318 additions and 139 deletions
@@ -7,6 +7,9 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.sap.sailing.geocoding,
com.sap.sailing.server.interfaces,
com.sap.sailing.server.preferences,
com.sap.sse.replication,
com.sap.sse.security,
org.osgi.framework;version="1.7.0"
Export-Package: com.sap.sailing.datamining,
com.sap.sailing.datamining.data,
@@ -119,7 +119,7 @@ TackAtStart=Tack at Start
SpeedTenSecondsAfterStart=Speed 10s After Start
RankThirtySecondsAfterStart=Rank 30s After Start
WindwardDistanceToAdvantageousEndOfLineAtStartOfRace=Windward Distance to Advantageous End of Line at Start of Race
WindwardDistanceToAdvantageousEndOfLineAtStartOfCompetitor=Windward Distance to Starboard Side of Line at Start of Competitor
WindwardDistanceToAdvantageousEndOfLineAtStartOfCompetitor=Windward Distance to Advantageous Side of Line at Start of Competitor
RankAfterHalfOfTheFirstLeg=Rank after the half of the first leg
AdvantageousEndOfLine=Advantageous End of Line
AdvantageOfStarboardSideOfStartLine=Advantage of starboard side of start line
@@ -133,6 +133,7 @@ WindSourceType=Wind Source Type
AbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor=Absolute Windward Distance to Starboardside of Line at Start of Competitor
WindSourceName=Wind Source Name
RelativeDistanceToAdvantageousEndOfLineAtStartOfRace=Relative Distance to Advantageous End of Line at Start of Race
RelativeDistanceToAdvantageousEndOfLineAtStartOfCompetitor=Relative Distance to Advantageous End of Line at Start of Competitor
windFrom=True Wind Direction (TWD)
windSpeedKnots=True Wind Speed (kts)
speedInKnots=Speed (kts)
@@ -284,4 +285,5 @@ RatioDurationLongVsShortTack=Ratio duration long tack / short tack
Discarded=Discarded
DurationFromRaceStartToFirstTack=Duration from race start to first tack
TypeOfFirstLeg=Type of first leg
TenthInLeg=Which tenth of the leg (1-10)
TenthInLeg=Which tenth of the leg (1-10)
SailorProfile=Sailor Profile
@@ -143,6 +143,7 @@ pitch=Neigung
heel=Krängung
WindwardDistanceToAdvantageousEndOfLineAtStartOfRaceVsRelativeDistanceToAdvantageousEndOfLine=Windwärtige Distanz zum Bevorteilten Ende der Startlinie zum Start des Rennens (X) vs. Relative Distanz zum Bevorteilten Ende der Startlinie zum Start des Rennens (Y)
RelativeDistanceToAdvantageousEndOfLineAtStartOfRace=Relative Distanz zum Bevorteilten Ende der Startlinie zum Start des Rennens
RelativeDistanceToAdvantageousEndOfLineAtStartOfCompetitor=Relative Distanz zum Bevorteilten Ende der Startlinie zum Startzeitpunkt des Teilnehmers
rideHeight=Foiling-Höhe
rideHeightPort=Foiling-Höhe Backbord-Rumpf
rideHeightStarboard=Foiling-Höhe Steuerbord-Rumpf
@@ -258,8 +259,8 @@ XTERelativeSigned=Relative Querabweichung, mit Vorzeichen (-1 = 1/2 Schenkellän
XTERelativeUnsigned=Relative Querabweichung, ohne Vorzeichen (0 = Mitte, 1 = ganz aussen)
XTEToWindAxisUnsigned=Querabweichung zur Windachse, ohne Vorzeichen
XTEToWindAxisSigned=Querabweichung zur Windachse, vorzeichenbehaftet (- = links, + = rechts)
XTEToWindAxisRelativeUnsigned=Relative Querabweichung zur Windachse, mit Vorzeichen (-1 = 1/2 Schenkellänge links, 0 = Mitte, +1 = 1/2 Schenkellänge rechts)
XTEToWindAxisRelativeSigned=Relative Querabweichung zur Windachse, ohne Vorzeichen (0 = Mitte, 1 = ganz aussen)
XTEToWindAxisRelativeUnsigned=Relative Querabweichung zur Windachse, ohne Vorzeichen (0 = Mitte, 1 = ganz aussen)
XTEToWindAxisRelativeSigned=Relative Querabweichung zur Windachse, mit Vorzeichen (-1 = 1/2 Schenkellänge links, 0 = Mitte, +1 = 1/2 Schenkellänge rechts)
Day=Tag
CompetitorDay=Teilnehmer-Tag
CompetitorDaySailingDomainRetrieverChain=Teilnehmer-Tag für Wettfahrt
@@ -282,4 +283,5 @@ RatioDurationLongVsShortTack=Verhältnis gesegelte Dauer auf Streck- zu Holebug
Discarded=Gestrichen
DurationFromRaceStartToFirstTack=Dauer vom Start der Wettfahrt bis zur ersten Wende
TypeOfFirstLeg=Art des ersten Bahnschenkels
TenthInLeg=Zehntel des Bahnschenkels (1-10)
TenthInLeg=Zehntel des Bahnschenkels (1-10)
SailorProfile=Seglerprofil
@@ -1,7 +1,6 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
@@ -19,86 +18,87 @@ import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
* @author Axel Uhl (d043530)
*
*/
public interface AbstractHasTrackedLegSliceOfCompetitorContext extends HasWindOnTrackedLeg {
public interface AbstractHasTrackedLegSliceOfCompetitorContext extends HasWindOnTrackedLeg, HasSomethingOfCompetitorContext {
@Connector(scanForStatistics=false)
public HasTrackedLegContext getTrackedLegContext();
HasTrackedLegContext getTrackedLegContext();
public TrackedLegOfCompetitor getTrackedLegOfCompetitor();
TrackedLegOfCompetitor getTrackedLegOfCompetitor();
default HasTrackedRaceContext getTrackedRaceContext() {
return getTrackedLegContext().getTrackedRaceContext();
}
@Dimension(messageKey="RelativeScoreInRaceInPercent", ordinal=12)
public ClusterDTO getPercentageClusterForRelativeScoreInRace();
ClusterDTO getPercentageClusterForRelativeScoreInRace();
@Connector(messageKey="Boat")
public Boat getBoat();
@Connector(messageKey="Competitor")
public Competitor getCompetitor();
Boat getBoat();
@Statistic(messageKey="DistanceTraveled", resultDecimals=2, ordinal=0)
public Distance getDistanceTraveled();
Distance getDistanceTraveled();
@Statistic(messageKey="SpeedAverage", resultDecimals=2, ordinal=0)
public Double getSpeedAverageInKnots();
Double getSpeedAverageInKnots();
@Statistic(messageKey="RankGainsOrLosses", resultDecimals=2, ordinal=1)
public Integer getRankGainsOrLosses();
Integer getRankGainsOrLosses();
@Statistic(messageKey="RelativeScore", resultDecimals=2, ordinal=2)
public Double getRelativeRank();
Double getRelativeRank();
@Statistic(messageKey="AbsoluteRank", resultDecimals=0, ordinal=3)
public Integer getRankAtSliceFinish();
Integer getRankAtSliceFinish();
@Statistic(messageKey="AbsoluteRankAfterFirstQuarter", resultDecimals=0, ordinal=4)
public Integer getRankAfterFirstQuarter();
Integer getRankAfterFirstQuarter();
@Statistic(messageKey="AbsoluteRankAfterSecondQuarter", resultDecimals=0, ordinal=5)
public Integer getRankAfterSecondQuarter();
Integer getRankAfterSecondQuarter();
@Statistic(messageKey="AbsoluteRankAfterThirdQuarter", resultDecimals=0, ordinal=6)
public Integer getRankAfterThirdQuarter();
Integer getRankAfterThirdQuarter();
@Statistic(messageKey="AbsoluteRankAverageAcrossFirstThreeQuarters", resultDecimals=2, ordinal=7)
public Double getRankAverageAcrossFirstThreeQuarters();
Double getRankAverageAcrossFirstThreeQuarters();
@Statistic(messageKey="AbsoluteRankRhumbLineBasedAfterFirstQuarter", resultDecimals=0, ordinal=8)
public Integer getRankRhumbLineBasedAfterFirstQuarter();
Integer getRankRhumbLineBasedAfterFirstQuarter();
@Statistic(messageKey="AbsoluteRankRhumbLineBasedAfterSecondQuarter", resultDecimals=0, ordinal=9)
public Integer getRankRhumbLineBasedAfterSecondQuarter();
Integer getRankRhumbLineBasedAfterSecondQuarter();
@Statistic(messageKey="AbsoluteRankRhumbLineBasedAfterThirdQuarter", resultDecimals=0, ordinal=10)
public Integer getRankRhumbLineBasedAfterThirdQuarter();
Integer getRankRhumbLineBasedAfterThirdQuarter();
@Statistic(messageKey="AbsoluteRankRhumbLineBasedAverageAcrossFirstThreeQuarters", resultDecimals=2, ordinal=11)
public Double getRankRhumbLineBasedAverageAcrossFirstThreeQuarters();
Double getRankRhumbLineBasedAverageAcrossFirstThreeQuarters();
@Statistic(messageKey="AbsoluteRankPredictionErrorAfterFirstQuarter", resultDecimals=2, ordinal=12)
public Double getRankPredictionErrorAfterFirstQuarter();
Double getRankPredictionErrorAfterFirstQuarter();
@Statistic(messageKey="AbsoluteRankPredictionErrorAfterSecondQuarter", resultDecimals=2, ordinal=13)
public Double getRankPredictionErrorAfterSecondQuarter();
Double getRankPredictionErrorAfterSecondQuarter();
@Statistic(messageKey="AbsoluteRankPredictionErrorAfterThirdQuarter", resultDecimals=2, ordinal=14)
public Double getRankPredictionErrorAfterThirdQuarter();
Double getRankPredictionErrorAfterThirdQuarter();
@Statistic(messageKey="AbsoluteRankPredictionErrorAcrossFirstThreeQuarters", resultDecimals=2, ordinal=15)
public Double getRankPredictionErrorAcrossFirstThreeQuarters();
Double getRankPredictionErrorAcrossFirstThreeQuarters();
@Statistic(messageKey="AbsoluteRankPredictionErrorRhumbLineBasedAfterFirstQuarter", resultDecimals=2, ordinal=16)
public Double getRankPredictionErrorRhumbLineBasedAfterFirstQuarter();
Double getRankPredictionErrorRhumbLineBasedAfterFirstQuarter();
@Statistic(messageKey="AbsoluteRankPredictionErrorRhumbLineBasedAfterSecondQuarter", resultDecimals=2, ordinal=17)
public Double getRankPredictionErrorRhumbLineBasedAfterSecondQuarter();
Double getRankPredictionErrorRhumbLineBasedAfterSecondQuarter();
@Statistic(messageKey="AbsoluteRankPredictionErrorRhumbLineBasedAfterThirdQuarter", resultDecimals=2, ordinal=18)
public Double getRankPredictionErrorRhumbLineBasedAfterThirdQuarter();
Double getRankPredictionErrorRhumbLineBasedAfterThirdQuarter();
@Statistic(messageKey="AbsoluteRankPredictionErrorRhumbLineBasedAcrossFirstThreeQuarters", resultDecimals=2, ordinal=19)
public Double getRankPredictionErrorRhumbLineBasedAcrossFirstThreeQuarters();
Double getRankPredictionErrorRhumbLineBasedAcrossFirstThreeQuarters();
@Statistic(messageKey="TimeSpentInSeconds", resultDecimals=0, ordinal=4)
public Long getTimeTakenInSeconds();
Long getTimeTakenInSeconds();
@Statistic(messageKey="timeSpentFoiling", resultDecimals=1)
Duration getTimeSpentFoiling();
@@ -107,20 +107,20 @@ public interface AbstractHasTrackedLegSliceOfCompetitorContext extends HasWindOn
Distance getDistanceSpentFoiling();
@Statistic(messageKey="NumberOfManeuvers", resultDecimals=0)
public Integer getNumberOfManeuvers();
Integer getNumberOfManeuvers();
@Statistic(messageKey="NumberOfJibes", resultDecimals=0)
public Integer getNumberOfJibes();
Integer getNumberOfJibes();
@Statistic(messageKey="NumberOfTacks", resultDecimals=0)
public Integer getNumberOfTacks();
Integer getNumberOfTacks();
@Statistic(messageKey="VMG", resultDecimals=2)
public Speed getVelocityMadeGood();
Speed getVelocityMadeGood();
@Statistic(messageKey="RatioDurationLongVsShortTack", resultDecimals=2)
public double getRatioDurationLongVsShortTack();
double getRatioDurationLongVsShortTack();
@Statistic(messageKey="RatioDistanceLongVsShortTack", resultDecimals=2)
public double getRatioDistanceLongVsShortTack();
double getRatioDistanceLongVsShortTack();
}
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.security.SecurityService;
public interface HasLeaderboardGroupContext {
@Connector(messageKey="LeaderboardGroup", ordinal=0)
@@ -12,4 +13,8 @@ public interface HasLeaderboardGroupContext {
PolarDataService getPolarDataService();
DomainFactory getBaseDomainFactory();
SecurityService getSecurityService();
SailorProfiles getSailorProfiles();
}
@@ -1,7 +1,6 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Tack;
@@ -14,15 +13,11 @@ 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 {
public interface HasRaceOfCompetitorContext extends HasSomethingOfCompetitorContext {
@Override
@Connector(scanForStatistics=false)
HasTrackedRaceContext getTrackedRaceContext();
@Connector(messageKey="Competitor")
@Statistic(messageKey="Competitor")
Competitor getCompetitor();
@Dimension(messageKey="TackAtStart", ordinal=12)
Tack getTackAtStart() throws NoWindException;
@@ -140,6 +135,9 @@ public interface HasRaceOfCompetitorContext {
@Statistic(messageKey="RelativeDistanceToAdvantageousEndOfLineAtStartOfRace", resultDecimals=2)
Double getRelativeDistanceToAdvantageousEndOfLineAtStartOfRace();
@Statistic(messageKey="RelativeDistanceToAdvantageousEndOfLineAtStartOfCompetitor", resultDecimals=2)
Double getRelativeDistanceToAdvantageousEndOfLineAtStartOfCompetitor();
@Statistic(messageKey="RaceDuration")
Duration getDuration();
@@ -1,32 +1,28 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.MaxPointsReason;
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 HasRaceResultOfCompetitorContext {
public interface HasRaceResultOfCompetitorContext extends HasSomethingOfCompetitorContext {
@Connector(scanForStatistics=false)
public HasLeaderboardContext getLeaderboardContext();
HasLeaderboardContext getLeaderboardContext();
@Override
@Connector(scanForStatistics=false)
public HasTrackedRaceContext getTrackedRaceContext();
HasTrackedRaceContext getTrackedRaceContext();
@Connector(messageKey="Competitor", ordinal=2)
public Competitor getCompetitor();
@Connector(messageKey="Boat")
public Boat getBoat();
Boat getBoat();
@Dimension(messageKey="Regatta", ordinal=4)
String getRegattaName();
@Dimension(messageKey="RelativeScoreInPercent", ordinal=6)
public ClusterDTO getPercentageClusterForRelativeScore();
ClusterDTO getPercentageClusterForRelativeScore();
@Dimension(messageKey="WindSpeedInBeaufort", ordinal=7)
int getAverageWindSpeedInRoundedBeaufort();
@@ -35,20 +31,20 @@ public interface HasRaceResultOfCompetitorContext {
* 0 means the competitor won the race, 1 means the competitor ranked last
*/
@Statistic(messageKey="RelativeScore", ordinal=1, resultDecimals=2)
public Double getRelativeRank();
Double getRelativeRank();
@Statistic(messageKey="AbsoluteRank", ordinal=2, resultDecimals=2)
public Double getAbsoluteRank();
Double getAbsoluteRank();
@Dimension(messageKey="IRM")
public MaxPointsReason getMaxPointsReason();
MaxPointsReason getMaxPointsReason();
@Dimension(messageKey="Discarded")
boolean isDiscarded();
@Statistic(messageKey="NumberOfPodiumFinish", ordinal=3)
public Boolean isPodiumFinish();
Boolean isPodiumFinish();
@Statistic(messageKey="NumberOfWins", ordinal=4)
public Boolean isWin();
Boolean isWin();
}
@@ -0,0 +1,16 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sse.datamining.annotations.Connector;
public interface HasSomethingOfCompetitorContext {
HasTrackedRaceContext getTrackedRaceContext();
@Connector(messageKey="Competitor", ordinal=2)
Competitor getCompetitor();
@Connector(messageKey="SailorProfile")
default SailorProfile getSailorProfile() {
return getTrackedRaceContext().getLeaderboardContext().getLeaderboardGroupContext().getSailorProfiles().getProfileForCompetitor(getCompetitor());
}
}
@@ -0,0 +1,51 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.server.preferences.SailorProfilePreference;
import com.sap.sailing.server.preferences.SailorProfilePreferences;
import com.sap.sse.common.NamedWithUUID;
import com.sap.sse.common.Util;
/**
* A sailor profile currently mainly consists of a set of competitors that it consolidates into a single profile. It can
* be used particularly in a data mining context when there are multiple distinct records that from a user's point of
* view represent the same sailor/competitor. With this, a user can define a {@link SailorProfile} like an "equivalence
* class" that allows the user to, e.g., filter or group data mining results based on a competitor's "equivalence
* class."
* <p>
*
* A typical example would be a single-handed class, say "ILCA 6," where the same person has been participating in
* several events, but each time captured with a different technical competitor ID, maybe even competing under different
* sail numbers. Yet, during analysis, it may make sense to group the results for all of these entities under one sailor
* profile.
* <p>
*
* Technically, the sailor profiles are managed as user preferences in the user store. A preference converter can turn
* the underlying JSON string into an {@link SailorProfilePreferences} object which contains
* {@link SailorProfilePreference}. These, in turn, can be converted to instances of a type implementing this interface.
* <p>
*
* Comparability is defined such that no two profiles with different {@link #getId() IDs} will ever compare equal.
* Beyond this, {@link SailorProfile}s with a greater number of {@link #getCompetitors() competitors} than another will
* be considered "greater." In case of an equal number of competitors, the sailor profile {@link #getName() name} will
* be used for lexicographic ordering. In case of equal names, sorting will work by the stringified version of the
* {@link #getId() UUID}.
*
* @author Axel Uhl (d043530)
*
*/
public interface SailorProfile extends NamedWithUUID, Comparable<SailorProfile> {
Iterable<Competitor> getCompetitors();
@Override
default int compareTo(SailorProfile o) {
int result = Integer.compare(Util.size(getCompetitors()), Util.size(o.getCompetitors()));
if (result == 0) {
result = getName().compareTo(o.getName());
if (result == 0) {
result = getId().compareTo(o.getId());
}
}
return result;
}
}
@@ -0,0 +1,21 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.base.Competitor;
/**
* A "data mining" view on the current user's sailor profiles as defined in the user preferences. When an instance is
* constructed, it collects all of the user's sailor profiles and builds a map from the {@link Competitor} objects to
* the {@link SailorProfile} objects that refer to that {@link Competitor}.
* <p>
*
* When more than one of the user's {@link SailorProfile}s comprise the same {@link Competitor}, a stable algorithm
* for determining a single preferred {@link SailorProfile} for the {@link Competitor} will be used in the
* {@link #getProfileForCompetitor(Competitor)}, finding the "greatest" (as defined by the {@link Comparable} property
* of the {@link SailorProfile} interface) profile for the {@link Competitor}.
*
* @author Axel Uhl (d043530)
*
*/
public interface SailorProfiles {
SailorProfile getProfileForCompetitor(Competitor competitor);
}
@@ -30,9 +30,8 @@ public class LeaderboardGroupRetrievalProcessor extends AbstractRetrievalProcess
if (isAborted()) {
break;
}
data.add(new LeaderboardGroupWithContext(leaderboardGroup, polarDataService, element.getBaseDomainFactory()));
data.add(new LeaderboardGroupWithContext(leaderboardGroup, polarDataService, element.getBaseDomainFactory(), element.getSecurityService()));
}
return data;
}
}
@@ -1,19 +1,34 @@
package com.sap.sailing.datamining.impl.data;
import java.util.ArrayList;
import java.util.List;
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.datamining.data.SailorProfile;
import com.sap.sailing.datamining.data.SailorProfiles;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.server.preferences.SailorProfilePreference;
import com.sap.sailing.server.preferences.SailorProfilePreferences;
import com.sap.sse.security.SecurityService;
public class LeaderboardGroupWithContext implements HasLeaderboardGroupContext {
private final LeaderboardGroup leaderboardGroup;
private final PolarDataService polarDataService;
private final DomainFactory baseDomainFactory;
private final SecurityService securityService;
/**
* Access has to be synchronized; it is constructed lazily by the {@link #getSailorProfiles()} method.
*/
private SailorProfiles sailorProfiles;
public LeaderboardGroupWithContext(LeaderboardGroup leaderboardGroup, PolarDataService polarDataService, DomainFactory baseDomainFactory) {
public LeaderboardGroupWithContext(LeaderboardGroup leaderboardGroup, PolarDataService polarDataService, DomainFactory baseDomainFactory, SecurityService securityService) {
this.leaderboardGroup = leaderboardGroup;
this.polarDataService = polarDataService;
this.baseDomainFactory = baseDomainFactory;
this.securityService = securityService;
}
@Override
@@ -30,4 +45,25 @@ public class LeaderboardGroupWithContext implements HasLeaderboardGroupContext {
public DomainFactory getBaseDomainFactory() {
return baseDomainFactory;
}
@Override
public SecurityService getSecurityService() {
return securityService;
}
@Override
public synchronized SailorProfiles getSailorProfiles() {
if (sailorProfiles == null) {
final SailorProfilePreferences sailorProfilePreferences = getSecurityService().getPreferenceObject(getSecurityService().getCurrentUser().getName(), SailorProfilePreferences.PREF_NAME);
if (sailorProfilePreferences != null) {
final List<SailorProfile> theSailorProfiles = new ArrayList<>();
for (final SailorProfilePreference sailorProfilePreference : sailorProfilePreferences.getSailorProfiles()) {
final SailorProfile sailorProfile = new SailorProfileImpl(sailorProfilePreference.getUuid(), sailorProfilePreference.getName(), sailorProfilePreference.getCompetitors());
theSailorProfiles.add(sailorProfile);
}
sailorProfiles = new SailorProfilesImpl(theSailorProfiles);
}
}
return sailorProfiles;
}
}
@@ -360,9 +360,18 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
@Override
public Double getRelativeDistanceToAdvantageousEndOfLineAtStartOfRace() {
TrackedRace trackedRace = getTrackedRace();
TimePoint startOfRace = trackedRace.getStartOfRace();
LineDetails startLine = trackedRace.getStartLine(startOfRace);
final TimePoint startOfRace = getTrackedRace().getStartOfRace();
return getRelativeDistanceToAdvantageousEndOfLine(startOfRace);
}
@Override
public Double getRelativeDistanceToAdvantageousEndOfLineAtStartOfCompetitor() {
final TimePoint competitorStartTimePoint = getTrackedRace().getTrackedLeg(getCompetitor(), getTrackedRace().getRace().getCourse().getFirstLeg()).getStartTime();
return getRelativeDistanceToAdvantageousEndOfLine(competitorStartTimePoint);
}
private Double getRelativeDistanceToAdvantageousEndOfLine(final TimePoint timePoint) {
final LineDetails startLine = getTrackedRace().getStartLine(timePoint);
Mark advantageousMark = null;
switch (startLine.getAdvantageousSideWhileApproachingLine()) {
case PORT:
@@ -375,14 +384,14 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
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);
Double distance = competitorPosition.getDistance(advantageousMarkPosition).getMeters();
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = getTrackedRace().getTrackedLeg(competitor, trackedRace.getRace().getCourse().getFirstLeg());
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
Double length = trackedRace.getStartLine(competitorStartTime).getLength().getMeters();
final GPSFixTrack<Mark, GPSFix> advantageousMarkTrack = getTrackedRace().getOrCreateTrack(advantageousMark);
final Position advantageousMarkPosition = advantageousMarkTrack.getEstimatedPosition(timePoint, false);
final GPSFixTrack<Competitor, GPSFixMoving> competitorTrack = getTrackedRace().getTrack(getCompetitor());
final Position competitorPosition = competitorTrack.getEstimatedPosition(timePoint, false);
final Double distance = competitorPosition.getDistance(advantageousMarkPosition).getMeters();
final TrackedLegOfCompetitor firstTrackedLegOfCompetitor = getTrackedRace().getTrackedLeg(competitor, getTrackedRace().getRace().getCourse().getFirstLeg());
final TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
final Double length = getTrackedRace().getStartLine(competitorStartTime).getLength().getMeters();
return distance / length;
}
@@ -0,0 +1,29 @@
package com.sap.sailing.datamining.impl.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import com.sap.sailing.datamining.data.SailorProfile;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.NamedWithUUIDImpl;
public class SailorProfileImpl extends NamedWithUUIDImpl implements SailorProfile {
private static final long serialVersionUID = 5851705759679719738L;
private final List<Competitor> competitors;
public SailorProfileImpl(UUID id, String name, Iterable<Competitor> competitors) {
super(name, id);
final List<Competitor> myCompetitors = new ArrayList<>();
Util.addAll(competitors, myCompetitors);
this.competitors = myCompetitors;
}
@Override
public Iterable<Competitor> getCompetitors() {
return Collections.unmodifiableList(competitors);
}
}
@@ -0,0 +1,35 @@
package com.sap.sailing.datamining.impl.data;
import java.util.HashMap;
import java.util.Map;
import com.sap.sailing.datamining.data.SailorProfile;
import com.sap.sailing.datamining.data.SailorProfiles;
import com.sap.sailing.domain.base.Competitor;
public class SailorProfilesImpl implements SailorProfiles {
final Map<Competitor, SailorProfile> profilesForCompetitor;
/**
* Constructs the mapping from {@link Competitor} to {@link SailorProfile} based on the
* {@link SailorProfile#compareTo(SailorProfile) ordering} of the {@link SailorProfile}s. For each competitor,
* {@link #getProfileForCompetitor(Competitor)} will return the "greatest" profile found that
* {@link SailorProfile#getCompetitors() contains} that competitor.
*/
public SailorProfilesImpl(final Iterable<SailorProfile> sailorProfiles) {
this.profilesForCompetitor = new HashMap<>();
for (final SailorProfile sailorProfile : sailorProfiles) {
for (final Competitor competitor : sailorProfile.getCompetitors()) {
final SailorProfile existingSailorProfileForCompetitor = profilesForCompetitor.get(competitor);
if (existingSailorProfileForCompetitor == null || existingSailorProfileForCompetitor.compareTo(sailorProfile) < 0) {
profilesForCompetitor.put(competitor, sailorProfile);
}
}
}
}
@Override
public SailorProfile getProfileForCompetitor(Competitor competitor) {
return profilesForCompetitor.get(competitor);
}
}