Merge remote-tracking branch 'server/master'

Change-Id: Iff405dc3c7cc85c8d53b37683e4ac8b4dfff5b0f
This commit is contained in:
Axel Uhl committed 2018-10-17 09:49:32 +02:00
commit f32c74113a
16 files changed
+318 -91

No files matched your search

@@ -4,7 +4,6 @@ SpeedTenSecondsBefore=Speed 10s before
DistanceTraveled=Distance Traveled
Name=Name
LegType=Leg Type
SpeedAverageVsDistanceTraveled=Average Speed in Knots (X) Vs. Distance Traveled in Meters (Y)
SailID=Sail Number
Year=Year
LegNumber=Leg Number
@@ -200,4 +199,17 @@ PercentageOfMainCurveProgressUntilHighestSpeed=Percentage of main curve progress
PercentageOfMainCurveProgressUntilMaxTurningRate=Percentage of main curve progress until max. turning rate speed
AbsTwaAtManeuverMiddle=Abs. TWA at maneuver middle
GpsSamplingRate=GPS sampling rate
RaceDuration=Race duration
RaceDuration=Race duration
DistanceToAdvantageousSideAtStartOfRaceVsRankAtFirstMark=Relative distance to the advantageous end of line at the start of race (X) vs. Position at top mark (Y)
DistanceToAdvantageousSideAtStartOfRaceVsFinalRank=Relative distance to the advantageous end of line at the start of race (X) vs. Final position (Y)
AverageRaceWindSpeed=Average wind speed for race
VMG5SecondsBeforeStartOfRace=VMG 5 seconds before start of race
VMGAtStartOfRace=VMG at start of race
FinalRank=Final rank
VMG5SecondsAfterStartOfRace=VMG 5 seconds after start of race
RankSixtySecondsAfterStart=Rank 60 seconds after start of race
RankNinetySecondsAfterStart=Rank 90 seconds after start of race
DistanceToStarboardSideAtStartOfRace=Relative distance to starboard side at start of race
BiasAtStartOfRace=Bias of start line at start of race in meters (negative: PORT, positive: STARBORD)
Bias30SecondsAfterRaceStart=Bias of start line 30 seconds after race start in meters (negative: PORT, positive: STARBORD)
RankAtFirstMarkVsFinalRank=Rank at first mark (X) vs. Final rank (Y)
@@ -136,7 +136,6 @@ AverageAbsoluteTrueWindAngle=Durchschnittlicher absoluter Winkel zum wahren Wind
AbsoluteTrueWindAngle=Absoluter Winkel zum wahren Wind (TWA)
TrueWindAngle=Winkel zum wahren Wind (TWA)
Wind=Wind
SpeedAverageVsDistanceTraveled=Durschnittliche Geschwindigkeit in Knoten (X) Vs. zurückgelegte Distanz in Meter (Y)
SpeedAverage=Durchschnittliche Geschwindigkeit
VMG=Luv-/Leegeschwindigkeit (VMG)
MaxTurningRateInDegreesPerSecond=Max. Drehrate in deg/s
@@ -203,4 +202,17 @@ PercentageOfMainCurveProgressUntilMaxTurningRate=Prozentualer Fortschritt der Ha
ManeuverTypeForCompleteManeuverCurve=Manövertyp für komplette Manöverkurve
AbsTwaAtManeuverMiddle=Abs. TWA während Manövermitte
GpsSamplingRate=GPS-Samplingrate
RaceDuration=Renndauer
RaceDuration=Renndauer
DistanceToStarboardSideAtStartOfRace=Relative Distanz zur Steuerbordseite der Startlinie zum Start des Rennens
VMG5SecondsBeforeStartOfRace=VMG 5 Sekunden vor Start des Rennens
VMGAtStartOfRace=VMG zum Start des Rennens
VMG5SecondsAfterStartOfRace=VMG 5 Sekunden nach Start des Rennens
RankNinetySecondsAfterStart=Rank 90 Sekunden nach Start des Rennens
RankSixtySecondsAfterStart=Rank 60 Sekunden nach Start des Rennens
FinalRank=Finaler Rang
Bias30SecondsAfterRaceStart=Bias der Startlinie 30 Sekunden nach Start des Rennens in Meter (negativ: BACKBORD, positiv: STEUERBORD)
RankAtFirstMarkVsFinalRank=Rang bei erster Marke (X) vs. Finaler Rang (Y)
DistanceToAdvantageousSideAtStartOfRaceVsRankAtFirstMark=Relative Distanz zum bevorteilten Ende der Start beim Start des Rennens (X) vs. Position beim ersten Wegpunkt (Y)
DistanceToAdvantageousSideAtStartOfRaceVsFinalRank=Relative Distanz zum bevorteilten Ende der Start beim Start des Rennens (X) vs. Finale Platzierung (Y)
AverageRaceWindSpeed=Durchschnittliche Windgeschwindigkeit für Wettfahrt
BiasAtStartOfRace=Bias der Startlinie zum Start des Rennens in Meter (negativ: BACKBORD, positiv: STEUERBORD)
@@ -5,8 +5,8 @@ import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Tack;
import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Speed;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
@@ -24,6 +24,9 @@ public interface HasRaceOfCompetitorContext {
@Dimension(messageKey="TackAtStart", ordinal=12)
Tack getTackAtStart() throws NoWindException;
@Dimension(messageKey="SailID")
public String getSailID();
@Dimension(messageKey="DistanceToStarboardSideAtStartOfCompetitor", ordinal=13)
ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart();
@@ -37,14 +40,14 @@ public interface HasRaceOfCompetitorContext {
Double getNormalizedDistanceToStarboardSideAtStartOfCompetitor();
@Statistic(messageKey="DistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark", resultDecimals=2, ordinal=1)
Pair<Double, Double> getNormalizedDistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark();
Pair<Double, Integer> getNormalizedDistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark();
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLineAtStartOfRace", resultDecimals=2, ordinal=2)
Distance getWindwardDistanceToAdvantageousLineEndAtStartofRace();
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLineAtStartOfCompetitor", resultDecimals=2, ordinal=2)
Distance getWindwardDistanceToAdvantageousLineEndAtStartofCompetitor();
@Connector(messageKey="SpeedWhenStarting", ordinal=3)
Speed getSpeedWhenStarting();
@@ -55,20 +58,20 @@ public interface HasRaceOfCompetitorContext {
Speed getSpeedTenSecondsAfterStartOfRace();
@Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=6)
Double getRankThirtySecondsAfterStartOfRace();
Integer getRankThirtySecondsAfterStartOfRace();
@Statistic(messageKey="RankAfterHalfOfTheFirstLeg", resultDecimals=2, ordinal=7)
Double getRankAfterHalfOfTheFirstLeg();
@Statistic(messageKey="RankAtFirstMark", resultDecimals=2, ordinal=8)
Double getRankAtFirstMark();
Integer getRankAtFirstMark();
@Statistic(messageKey="RankGainsOrLossesBetweenFirstMarkAndFinish", resultDecimals=2, ordinal=9)
Double getRankGainsOrLossesBetweenFirstMarkAndFinish();
Integer getRankGainsOrLossesBetweenFirstMarkAndFinish();
@Statistic(messageKey="NumberOfManeuvers", resultDecimals=0, ordinal=10)
int getNumberOfManeuvers();
@Statistic(messageKey="NumberOfTacks", resultDecimals=0, ordinal=11)
int getNumberOfTacks();
@@ -88,7 +91,7 @@ public interface HasRaceOfCompetitorContext {
Distance getAbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor();
@Statistic(messageKey="DistanceToStarboardSideAtStartOfCompetitorVsFinalRank", resultDecimals=2)
Pair<Double, Double> getRelativeDistanceToStarboardSideAtStartOfCompetitorVsFinalRank();
Pair<Double, Integer> getRelativeDistanceToStarboardSideAtStartOfCompetitorVsFinalRank();
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLineAtStartOfRaceVsRelativeDistanceToAdvantageousEndOfLine", resultDecimals=2)
Pair<Double, Double> getWindwardDistanceToAdvantageousEndOfLineAtStartOfRaceVsRelativeDistanceToAdvantageousEndOfLineAtStartOfRace();
@@ -99,4 +102,42 @@ public interface HasRaceOfCompetitorContext {
@Statistic(messageKey="RaceDuration")
Duration getDuration();
@Statistic(messageKey="DistanceToStarboardSideAtStartOfRace", resultDecimals=2)
public Double getRelativeDistanceToStarboardSideAtStartOfRace();
@Statistic(messageKey="VMG5SecondsBeforeStartOfRace", resultDecimals=2)
public Speed getVMG5SecondsBeforeStartOfRace();
@Statistic(messageKey="VMGAtStartOfRace", resultDecimals=2)
public Speed getVMGAtStartOfRace();
@Statistic(messageKey="VMG5SecondsAfterStartOfRace", resultDecimals=2)
public Speed getVMG5SecondsAfterStartOfRace();
@Statistic(messageKey="DistanceToAdvantageousSideAtStartOfRaceVsRankAtFirstMark", resultDecimals=2)
public Pair<Double, Integer> getRelativeDistanceToAdvantageousSideAtStartOfRaceVsRankAtFirstMark();
@Statistic(messageKey="RankAtFirstMarkVsFinalRank", resultDecimals=2)
public Pair<Integer, Integer> getRankAtFirstMarkVsFinalRank();
@Statistic(messageKey="RankSixtySecondsAfterStart", resultDecimals=2)
public Integer getRankSixtySecondsAfterStartOfRace();
@Statistic(messageKey="RankNinetySecondsAfterStart", resultDecimals=2)
public Integer getRankNinetySecondsAfterStartOfRace();
@Statistic(messageKey="FinalRank", resultDecimals=2, ordinal=8)
public Integer getFinalRank();
@Statistic(messageKey="DistanceToAdvantageousSideAtStartOfRaceVsFinalRank", resultDecimals=2)
Pair<Double, Integer> getRelativeDistanceToAdvantageousSideAtStartOfRaceVsFinalRank();
@Statistic(messageKey="AverageRaceWindSpeed")
Speed getAverageRaceWindSpeed();
@Statistic(messageKey="BiasAtStartOfRace", resultDecimals=2)
Double getBiasAtStartOfRace();
@Statistic(messageKey="Bias30SecondsAfterRaceStart", resultDecimals=2)
Double getBias30SecondsAfterRaceStart();
}
@@ -4,7 +4,6 @@ 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;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
@@ -18,27 +17,27 @@ public interface HasTrackedLegOfCompetitorContext extends HasWindOnTrackedLeg {
@Dimension(messageKey="RelativeScoreInRaceInPercent", ordinal=12)
public ClusterDTO getPercentageClusterForRelativeScoreInRace();
@Dimension(messageKey="SailID")
public String getSailID();
@Connector(messageKey="Competitor")
public Competitor getCompetitor();
@Statistic(messageKey="DistanceTraveled", resultDecimals=0, ordinal=0)
@Statistic(messageKey="DistanceTraveled", resultDecimals=2, ordinal=0)
public Distance getDistanceTraveled();
@Statistic(messageKey="SpeedAverage", resultDecimals=0, ordinal=0)
@Statistic(messageKey="SpeedAverage", resultDecimals=2, ordinal=0)
public Double getSpeedAverage();
@Statistic(messageKey="SpeedAverageVsDistanceTraveled", resultDecimals=0, ordinal=0)
public Pair<Double, Double> getSpeedAverageVsDistanceTraveled();
@Statistic(messageKey="RankGainsOrLosses", resultDecimals=2, ordinal=1)
public Double getRankGainsOrLosses();
public Integer getRankGainsOrLosses();
@Statistic(messageKey="RelativeScore", resultDecimals=2, ordinal=2)
public Double getRelativeRank();
@Statistic(messageKey="AbsoluteRank", resultDecimals=2, ordinal=3)
public Double getAbsoluteRank();
public Integer getRankAtFinish();
@Statistic(messageKey="TimeSpentInSeconds", resultDecimals=0, ordinal=4)
public Long getTimeTakenInSeconds();
@@ -48,4 +47,13 @@ public interface HasTrackedLegOfCompetitorContext extends HasWindOnTrackedLeg {
@Statistic(messageKey="FoilingDistance", resultDecimals=1)
Distance getDistanceSpentFoiling();
@Statistic(messageKey="NumberOfManeuvers", resultDecimals=0)
public Integer getNumberOfManeuvers();
@Statistic(messageKey="NumberOfJibes", resultDecimals=0)
public Integer getNumberOfJibes();
@Statistic(messageKey="NumberOfTacks", resultDecimals=0)
public Integer getNumberOfTacks();
}
@@ -62,6 +62,6 @@ public interface HasTrackedRaceContext {
// Convenience methods for race dependent calculation to avoid code duplication
public Double getRelativeScoreForCompetitor(Competitor competitor);
public Double getRankAtFinishForCompetitor(Competitor competitor);
public Integer getRankAtFinishForCompetitor(Competitor competitor);
}
@@ -10,6 +10,7 @@ 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.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Mark;
@@ -69,6 +70,12 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
return startOfRace == null ? null : getTrackedRace().getTack(getCompetitor(), startOfRace);
}
@Override
public String getSailID() {
Boat boatOfCompetitor = getTrackedRace().getBoatOfCompetitor(getCompetitor());
return boatOfCompetitor != null ? boatOfCompetitor.getSailID() : null;
}
@Override
public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart() {
Double normalizedDistance = getNormalizedDistanceToStarboardSideAtStartOfCompetitor();
@@ -101,8 +108,8 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
}
@Override
public Pair<Double, Double> getNormalizedDistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark(){
return new Pair<Double, Double> (getNormalizedDistanceToStarboardSideAtStartOfCompetitor(), getRankAtFirstMark());
public Pair<Double, Integer> getNormalizedDistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark(){
return new Pair<>(getNormalizedDistanceToStarboardSideAtStartOfCompetitor(), getRankAtFirstMark());
}
public Distance getWindwardDistanceToAdvantageousLineEndAtStartOf(TimePoint timepoint) {
@@ -146,7 +153,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
@Override
public Distance getAbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor() {
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = getTrackedRace().getTrackedLeg(competitor, getTrackedRace().getRace().getCourse().getFirstLeg());
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = getFirstLegOfCompetitor();
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
if(competitorStartTime == null) {
return null;
@@ -199,20 +206,9 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
if (startOfRace == null) {
return null;
}
return getTrackedRace().getTrack(getCompetitor()).getEstimatedSpeed(startOfRace.plus(TimeUnit.SECONDS.toMillis(10)));
return getTrackOfCompetitor().getEstimatedSpeed(startOfRace.plus(TimeUnit.SECONDS.toMillis(10)));
}
@Override
public Double getRankThirtySecondsAfterStartOfRace() {
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();
@@ -229,19 +225,19 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
}
@Override
public Double getRankAtFirstMark() {
public Integer getRankAtFirstMark() {
Course course = getTrackedRace().getRace().getCourse();
Waypoint firstMark = course.getFirstLeg().getTo();
Competitor competitor = getCompetitor();
final MarkPassing markPassing = getTrackedRace().getMarkPassing(competitor, firstMark);
int rank = markPassing == null ? 0 : getTrackedRace().getRank(competitor, markPassing.getTimePoint());
return rank == 0 ? null : Double.valueOf(rank);
return rank == 0 ? null : rank;
}
@Override
public Double getRankGainsOrLossesBetweenFirstMarkAndFinish() {
Double rankAtFirstMark = getRankAtFirstMark();
Double rankAtFinish = getTrackedRaceContext().getRankAtFinishForCompetitor(getCompetitor());
public Integer getRankGainsOrLossesBetweenFirstMarkAndFinish() {
Integer rankAtFirstMark = getRankAtFirstMark();
Integer rankAtFinish = getTrackedRaceContext().getRankAtFinishForCompetitor(getCompetitor());
return rankAtFirstMark != null && rankAtFinish != null ? rankAtFirstMark - rankAtFinish : null;
}
@@ -310,7 +306,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
@Override
public Distance getLineLengthAtStart() {
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = getTrackedRace().getTrackedLeg(competitor, getTrackedRace().getRace().getCourse().getFirstLeg());
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = getFirstLegOfCompetitor();
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
if (competitorStartTime == null) {
return null;
@@ -319,7 +315,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
}
@Override
public Pair<Double, Double> getRelativeDistanceToStarboardSideAtStartOfCompetitorVsFinalRank(){
public Pair<Double, Integer> getRelativeDistanceToStarboardSideAtStartOfCompetitorVsFinalRank(){
return new Pair<>(getNormalizedDistanceToStarboardSideAtStartOfCompetitor(), getTrackedRaceContext().getRankAtFinishForCompetitor(getCompetitor()));
}
@@ -372,5 +368,129 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
}
return duration;
}
@Override
public Double getRelativeDistanceToStarboardSideAtStartOfRace() {
TrackedRace trackedRace = getTrackedRace();
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, trackedRace.getRace().getCourse().getFirstLeg());
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
if (competitorStartTime == null) {
return null;
}
return getNormalizeDistanceToStarboardSideAtTimePoint(getStartOfRace());
}
@Override
public Speed getVMG5SecondsBeforeStartOfRace() {
return getTrackedRace().getVelocityMadeGood(getCompetitor(), getStartOfRace().minus(TimeUnit.SECONDS.toMillis(5)));
}
@Override
public Speed getVMGAtStartOfRace() {
return getTrackedRace().getVelocityMadeGood(getCompetitor(), getStartOfRace());
}
@Override
public Speed getVMG5SecondsAfterStartOfRace() {
return getTrackedRace().getVelocityMadeGood(getCompetitor(), getStartOfRace().plus(TimeUnit.SECONDS.toMillis(5)));
}
@Override
public Pair<Double, Integer> getRelativeDistanceToAdvantageousSideAtStartOfRaceVsRankAtFirstMark() {
return new Pair<>(getRelativeDistanceToAdvantageousEndOfLineAtStartOfRace(), getRankAtFirstMark());
}
@Override
public Pair<Integer, Integer> getRankAtFirstMarkVsFinalRank() {
return new Pair<>(getRankAtFirstMark(), getFinalRank());
}
@Override
public Integer getRankThirtySecondsAfterStartOfRace() {
return getRankAt(getStartOfRace().plus(TimeUnit.SECONDS.toMillis(30)));
}
@Override
public Integer getRankSixtySecondsAfterStartOfRace() {
return getRankAt(getStartOfRace().plus(TimeUnit.SECONDS.toMillis(60)));
}
@Override
public Integer getRankNinetySecondsAfterStartOfRace() {
return getRankAt(getStartOfRace().plus(TimeUnit.SECONDS.toMillis(90)));
}
@Override
public Integer getFinalRank() {
if(getEndOfRace() == null) {
return null;
}
return getRankAt(getEndOfRace());
}
@Override
public Pair<Double, Integer> getRelativeDistanceToAdvantageousSideAtStartOfRaceVsFinalRank() {
return new Pair<>(getRelativeDistanceToAdvantageousEndOfLineAtStartOfRace(), getFinalRank());
}
@Override
public Speed getAverageRaceWindSpeed() {
return getTrackedRace().getAverageWindSpeedWithConfidence(5000).getObject();
}
@Override
public Double getBiasAtStartOfRace() {
return getBiasAtTimePoint(getStartOfRace());
}
@Override
public Double getBias30SecondsAfterRaceStart() {
return getBiasAtTimePoint(getStartOfRace().plus(TimeUnit.SECONDS.toMillis(30)));
}
private GPSFixTrack<Competitor, GPSFixMoving> getTrackOfCompetitor() {
return getTrackedRace().getTrack(getCompetitor());
}
private TrackedLegOfCompetitor getFirstLegOfCompetitor() {
return getTrackedRace().getTrackedLeg(competitor, getTrackedRace().getRace().getCourse().getFirstLeg());
}
private TimePoint getStartOfRace() {
return getTrackedRace().getStartOfRace();
}
private TimePoint getEndOfRace() {
return getTrackedRace().getEndOfRace();
}
private Double getNormalizeDistanceToStarboardSideAtTimePoint(TimePoint timepoint) {
Double distance = getTrackedRace().getDistanceFromStarboardSideOfStartLine(getCompetitor(), timepoint).getMeters();
Double length = getTrackedRace().getStartLine(timepoint).getLength().getMeters();
return distance / length;
}
private Integer getRankAt(TimePoint timePoint) {
TimePoint startOfRace = getStartOfRace();
if (startOfRace == null) {
return null;
}
Integer rank = getTrackedRace().getRank(getCompetitor(), timePoint);
return rank == 0 ? null : rank;
}
public Double getBiasAtTimePoint(TimePoint timePoint) {
LineDetails startLine = getTrackedRace().getStartLine(timePoint);
switch (startLine.getAdvantageousSideWhileApproachingLine()) {
case PORT:
return startLine.getAdvantage().getMeters() * -1;
case STARBOARD:
return startLine.getAdvantage().getMeters();
}
return null;
}
}
@@ -7,12 +7,15 @@ 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.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.tracking.BravoFixTrack;
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;
@@ -20,7 +23,6 @@ import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
@@ -33,9 +35,9 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
private final TrackedLegOfCompetitor trackedLegOfCompetitor;
private final Competitor competitor;
private Double rankAtStart;
private Integer rankAtStart;
private boolean isRankAtStartInitialized;
private Double rankAtFinish;
private Integer rankAtFinish;
private boolean isRankAtFinishInitialized;
private Wind wind;
@@ -60,6 +62,12 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
return competitor;
}
@Override
public String getSailID() {
Boat boatOfCompetitor = getTrackedRace().getBoatOfCompetitor(getCompetitor());
return boatOfCompetitor != null ? boatOfCompetitor.getSailID() : null;
}
@Override
public ClusterDTO getPercentageClusterForRelativeScoreInRace() {
Double relativeScore = getTrackedLegContext().getTrackedRaceContext().getRelativeScoreForCompetitor(getCompetitor());
@@ -130,24 +138,18 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
}
}
@Override
public Pair<Double, Double> getSpeedAverageVsDistanceTraveled(){
return new Pair<Double, Double>(getSpeedAverage(), getDistanceTraveled().getMeters());
}
@Override
public Double getRankGainsOrLosses() {
Double rankAtStart = getRankAtStart();
Double rankAtFinish = getRankAtFinish();
public Integer getRankGainsOrLosses() {
Integer rankAtStart = getRankAtStart();
Integer rankAtFinish = getRankAtFinish();
return rankAtStart != null && rankAtFinish != null ? rankAtStart - rankAtFinish : null;
}
private Double getRankAtStart() {
private Integer getRankAtStart() {
if (!isRankAtStartInitialized) {
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
int rank = trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getStartTime());
rankAtStart = rank == 0 ? null : Double.valueOf(rank);
rankAtStart = rank == 0 ? null : rank;
isRankAtStartInitialized = true;
}
return rankAtStart;
@@ -157,20 +159,15 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
public Double getRelativeRank() {
Leaderboard leaderboard = getTrackedLegContext().getTrackedRaceContext().getLeaderboardContext().getLeaderboard();
double competitorCount = Util.size(leaderboard.getCompetitors());
Double rankAtFinish = getRankAtFinish();
Integer rankAtFinish = getRankAtFinish();
return rankAtFinish == null ? null : rankAtFinish / competitorCount;
}
@Override
public Double getAbsoluteRank() {
return getRankAtFinish();
}
private Double getRankAtFinish() {
public Integer getRankAtFinish() {
if (!isRankAtFinishInitialized) {
TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace();
int rank = trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getFinishTime());
rankAtFinish = rank == 0 ? null : Double.valueOf(rank);
rankAtFinish = rank == 0 ? null : rank;
isRankAtFinishInitialized = true;
}
return rankAtFinish;
@@ -241,4 +238,36 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
return this;
}
@Override
public Integer getNumberOfManeuvers() {
return getNumberOfJibes() + getNumberOfTacks();
}
@Override
public Integer getNumberOfJibes() {
return getSomethingForLegTrackingInterval((start, end) -> {
return getNumberOf(ManeuverType.JIBE, start, end);
});
}
@Override
public Integer getNumberOfTacks() {
return getSomethingForLegTrackingInterval((start, end) -> {
return getNumberOf(ManeuverType.TACK, start, end);
});
}
private int getNumberOf(ManeuverType maneuverType, TimePoint start, TimePoint end) {
TrackedRace trackedRace = getTrackedRace();
int number = 0;
if (trackedRace != null)
for (Maneuver maneuver : trackedRace.getManeuvers(getCompetitor(), start, end, false)) {
if (maneuver.getType() == maneuverType) {
number++;
}
}
return number;
}
}
@@ -187,9 +187,9 @@ public class TrackedRaceWithContext implements HasTrackedRaceContext {
}
@Override
public Double getRankAtFinishForCompetitor(Competitor competitor) {
public Integer getRankAtFinishForCompetitor(Competitor competitor) {
int rank = getTrackedRace().getRank(competitor, getTrackedRace().getEndOfTracking());
return rank == 0 ? null : Double.valueOf(rank);
return rank == 0 ? null : rank;
}
}
@@ -34,7 +34,7 @@ public class RPDMessageParsingTest {
private void assertRPDMessageCanBeParsed(final String rpdMessage)
throws InterruptedException, ParseException, IOException {
final SailMasterMessage message = new SailMasterMessageImpl(rpdMessage);
final SailMasterConnectorImpl connector = new SailMasterConnectorImpl(/* host */ "8.8.8.8", /* port */ 443, /* raceId */ null, /* raceName */ null, /* raceDescription */ null, /* boatClass */ null);
final SailMasterConnectorImpl connector = new SailMasterConnectorImpl(/* host */ "8.8.8.8", /* port */ 443, /* raceId */ null, /* raceName */ null, /* raceDescription */ null, /* boatClass */ null, /* SwissTimingRaceTracker */ null);
final boolean[] receivedPositionData = new boolean[1];
final SailMasterListener listener = new SailMasterAdapter() {
@Override
@@ -64,9 +64,9 @@ public class SailMasterConnectivityTest {
Race race4702 = new RaceImpl("W4702", "R2", "470 Women Race 2");
Race race4711 = new RaceImpl("4711", "R2", "A wonderful test race");
Race race4712 = new RaceImpl("4712", "R2", "Not such a wonderful race");
connector4702 = SwissTimingFactory.INSTANCE.getOrCreateSailMasterConnector("localhost", port, race4702.getRaceID(), race4702.getRaceName(), race4702.getDescription(), null /* boat class */);
connector4711 = SwissTimingFactory.INSTANCE.getOrCreateSailMasterConnector("localhost", port, race4711.getRaceID(), race4702.getRaceName(), race4711.getDescription(), null /* boat class */);
connector4712 = SwissTimingFactory.INSTANCE.getOrCreateSailMasterConnector("localhost", port, race4712.getRaceID(), race4702.getRaceName(), race4712.getDescription(), null /* boat class */);
connector4702 = SwissTimingFactory.INSTANCE.getOrCreateSailMasterConnector("localhost", port, race4702.getRaceID(), race4702.getRaceName(), race4702.getDescription(), null /* boat class */, /* SwissTimingRaceTracker */ null);
connector4711 = SwissTimingFactory.INSTANCE.getOrCreateSailMasterConnector("localhost", port, race4711.getRaceID(), race4702.getRaceName(), race4711.getDescription(), null /* boat class */, /* SwissTimingRaceTracker */ null);
connector4712 = SwissTimingFactory.INSTANCE.getOrCreateSailMasterConnector("localhost", port, race4712.getRaceID(), race4702.getRaceName(), race4712.getDescription(), null /* boat class */, /* SwissTimingRaceTracker */ null);
Thread.sleep(1000); // wait until all connectors are really connected to the SailMasterDummy
}
@@ -41,7 +41,7 @@ public class SwissTimingSailMasterLiveTest implements SailMasterListener {
@Before
public void connect() throws InterruptedException, ParseException {
connector = SwissTimingFactory.INSTANCE.getOrCreateSailMasterConnector("gps.sportresult.com", 40300, "W4702", "R2", "Women 470 Race 2", null /* boat class*/);
connector = SwissTimingFactory.INSTANCE.getOrCreateSailMasterConnector("gps.sportresult.com", 40300, "W4702", "R2", "Women 470 Race 2", null /* boat class*/, /* SwissTimingRaceTracker */ null);
}
@After
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingFactoryImpl;
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingRaceTrackerImpl;
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
@@ -42,11 +43,12 @@ public interface SwissTimingFactory {
* {@link MessageType#isRaceSpecific() Race-specific messages} for other races are ignored and not forwarded to any
* listener.
*/
SailMasterConnector getOrCreateSailMasterConnector(String hostname, int port, String raceId, String raceName, String raceDescription, BoatClass boatClass)
SailMasterConnector getOrCreateSailMasterConnector(String hostname, int port, String raceId, String raceName,
String raceDescription, BoatClass boatClass, SwissTimingRaceTrackerImpl swissTimingRaceTracker)
throws InterruptedException, ParseException;
SailMasterConnector getOrCreateSailMasterLiveSimulatorConnector(String host, int port, String raceId, String raceName,
String raceDescription, BoatClass boatClass) throws InterruptedException, ParseException;
String raceDescription, BoatClass boatClass, SwissTimingRaceTrackerImpl swissTimingRaceTracker) throws InterruptedException, ParseException;
SailMasterTransceiver createSailMasterTransceiver();
@@ -131,7 +131,7 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
private Long numberOfStoredMessages;
public SailMasterConnectorImpl(String host, int port, String raceId, String raceName, String raceDescription, BoatClass boatClass) throws InterruptedException, ParseException {
public SailMasterConnectorImpl(String host, int port, String raceId, String raceName, String raceDescription, BoatClass boatClass, SwissTimingRaceTrackerImpl swissTimingRaceTracker) throws InterruptedException, ParseException {
super();
maxSequenceNumber = -1l;
this.raceId = raceId; // from this time on, the connector interprets messages for raceID
@@ -143,6 +143,7 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
this.port = port;
this.listeners = new HashSet<SailMasterListener>();
this.unprocessedMessagesByType = new HashMap<MessageType, BlockingQueue<SailMasterMessage>>();
this.addSailMasterListener(swissTimingRaceTracker);
receiverThread = new Thread(this, "SwissTiming SailMaster Receiver");
receiverThread.start();
}
@@ -13,9 +13,9 @@ public class SailMasterLiveSimulatorConnectorImpl extends SailMasterConnectorImp
private long messageDeliveryIntervalInMs = Long.valueOf(System.getProperty("simulateLiveMode.delayInMillis", "250"));
public SailMasterLiveSimulatorConnectorImpl(String host, int port, String raceId, String raceName, String raceDescription, BoatClass boatClass)
public SailMasterLiveSimulatorConnectorImpl(String host, int port, String raceId, String raceName, String raceDescription, BoatClass boatClass, SwissTimingRaceTrackerImpl swissTimingRaceTracker)
throws InterruptedException, ParseException {
super(host, port, raceId, raceName, raceDescription, boatClass);
super(host, port, raceId, raceName, raceDescription, boatClass, swissTimingRaceTracker);
bufferedMessageList = Collections.synchronizedList(new ArrayList<SailMasterMessage>());
Thread messageDeliveryThread = new Thread("SailMasterLiveSimulatorConnector") {
public void run() {
@@ -44,9 +44,9 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
@Override
public SailMasterConnector getOrCreateSailMasterConnector(String host, int port, String raceId, String raceName,
String raceDescription, BoatClass boatClass) throws InterruptedException, ParseException {
String raceDescription, BoatClass boatClass, SwissTimingRaceTrackerImpl swissTimingRaceTracker) throws InterruptedException, ParseException {
if (Boolean.valueOf(System.getProperty("simulateLiveMode", "false"))) {
return getOrCreateSailMasterLiveSimulatorConnector(host, port, raceId, raceName, raceDescription, boatClass);
return getOrCreateSailMasterLiveSimulatorConnector(host, port, raceId, raceName, raceDescription, boatClass, swissTimingRaceTracker);
} else {
Util.Triple<String, Integer, String> key = new Util.Triple<String, Integer, String>(host, port, raceId);
SailMasterConnector result = connectors.get(key);
@@ -56,7 +56,7 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
} else {
logger.info("Creating a new connector for "+key+" because the old one was stopped");
}
result = new SailMasterConnectorImpl(host, port, raceId, raceName, raceDescription, boatClass);
result = new SailMasterConnectorImpl(host, port, raceId, raceName, raceDescription, boatClass, swissTimingRaceTracker);
connectors.put(key, result);
// TODO how do connectors get stopped, terminated and removed from the connectors map again?
} else {
@@ -68,15 +68,15 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
@Override
public SailMasterConnector getOrCreateSailMasterLiveSimulatorConnector(String host, int port, String raceId, String raceName,
String raceDescription, BoatClass boatClass) throws InterruptedException, ParseException {
String raceDescription, BoatClass boatClass, SwissTimingRaceTrackerImpl swissTimingRaceTracker) throws InterruptedException, ParseException {
Util.Triple<String, Integer, String> key = new Util.Triple<>(host, port, raceId);
SailMasterConnector result = connectors.get(key);
if (result == null) {
result = new SailMasterLiveSimulatorConnectorImpl(host, port, raceId, raceName, raceDescription, boatClass);
result = new SailMasterLiveSimulatorConnectorImpl(host, port, raceId, raceName, raceDescription, boatClass, swissTimingRaceTracker);
connectors.put(key, result);
// TODO how do connectors get stopped, terminated and removed from the connectors map again?
} else if (result.isStopped()) {
result = new SailMasterLiveSimulatorConnectorImpl(host, port, raceId, raceName, raceDescription, boatClass);
result = new SailMasterLiveSimulatorConnectorImpl(host, port, raceId, raceName, raceDescription, boatClass, swissTimingRaceTracker);
connectors.put(key, result);
}
return result;
@@ -151,9 +151,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
// found; in this case, create a default regatta based on the TracTrac event data
this.regatta = effectiveRegatta == null ? domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore,
connectivityParams.getRaceID(), connectivityParams.getBoatClass(), trackedRegattaRegistry) : effectiveRegatta;
this.connector = factory.getOrCreateSailMasterConnector(connectivityParams.getHostname(), connectivityParams.getPort(),
connectivityParams.getRaceID(), connectivityParams.getRaceName(), connectivityParams.getRaceDescription(), connectivityParams.getBoatClass());
this.domainFactory = domainFactory;
this.domainFactory = domainFactory;
this.raceID = connectivityParams.getRaceID();
// start out with an empty course, so we don't depend on receiving the CCG message before the timeout
this.course = new CourseImpl(this.raceID, /* start with empty marks list */ Collections.emptyList());
@@ -164,7 +162,6 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
this.boatClass = connectivityParams.getBoatClass();
this.windStore = windStore;
this.id = createID(connectivityParams.getRaceID(), connectivityParams.getHostname(), connectivityParams.getPort());
connector.addSailMasterListener(this);
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(this.regatta);
this.delayToLiveInMillis = connectivityParams.getDelayToLiveInMillis();
this.competitorsByBoatId = new HashMap<String, Competitor>();
@@ -175,6 +172,10 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
if (connectivityParams.getStartList() != null) {
createRaceDefinition(course);
}
// Ensure this is called last, otherwise the connector starts running without having a complete racetracker
this.connector = factory.getOrCreateSailMasterConnector(connectivityParams.getHostname(),
connectivityParams.getPort(), connectivityParams.getRaceID(), connectivityParams.getRaceName(),
connectivityParams.getRaceDescription(), connectivityParams.getBoatClass(), this);
}
@Override
@@ -505,12 +506,13 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
* {@link #trackedRace} with data received from the trackers.
*/
private boolean isTrackedRaceStillReachable() {
return trackedRace != null && Util.contains(getRegatta().getAllRaces(), trackedRace.getRace()) &&
getTrackedRegatta().getExistingTrackedRace(trackedRace.getRace()) == trackedRace;
return trackedRace != null && Util.contains(getRegatta().getAllRaces(), trackedRace.getRace())
&& getTrackedRegatta().getExistingTrackedRace(trackedRace.getRace()) == trackedRace;
}
@Override
public void receivedCourseConfiguration(String raceID, Course course) throws URISyntaxException {
Course oldCourse = this.course;
if (trackedRace == null) {
if (oldCourse == null && startList != null) {