mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-09 12:31:00 +00:00
Merge remote-tracking branch 'server/bug4521'
Change-Id: Ib9945f9d3ebb72b2647c486a9fd043ef00fa7ac8
This commit is contained in:
commit
2ce37bdca8
22 files changed
+820
-21
No files matched your search
+12
-2
@@ -1,8 +1,10 @@
|
||||
Speed=Speed
|
||||
SpeedAverage=Average Speed
|
||||
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
|
||||
@@ -32,6 +34,7 @@ RaceResultSailingDomainRetrieverChain=Race Results
|
||||
RaceOfCompetitorSailingDomainRetrieverChain=Races of Competitors
|
||||
ManeuverSailingDomainRetrieverChain=Maneuver
|
||||
LeaderboardGroup=Leaderboard Group
|
||||
LineLengthAtStart=Length of Startline at Start of Race
|
||||
Leaderboard=Leaderboard
|
||||
Leg=Leg
|
||||
MarkPassing=Mark Passing
|
||||
@@ -69,7 +72,8 @@ NumberOfTacks=Number of Tacks
|
||||
NumberOfJibes=Number of Jibes
|
||||
NumberOfPenaltyCircles=Number of Penalty Circles
|
||||
RankGainsOrLosses=Rank Gains or Losses
|
||||
DistanceToStarboardSideAtStart=Distance to Starboard Side (% of Length)
|
||||
DistanceToStarboardSideAtStartOfCompetitor=Relative Distance to Starboard Side at Start of Competitor
|
||||
DistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark=Relative Distance to Starboard Side at Start of Competitor (X) vs. Rank at First Mark (Y)
|
||||
NumberOfPodiumFinish=Number of Podium Finishes
|
||||
NumberOfWins=Number of Wins
|
||||
RankGainsOrLossesBetweenFirstMarkAndFinish=Rank Gains or Losses (1st Mark -> Finish)
|
||||
@@ -78,6 +82,7 @@ NumberOfCompetitorFixes=Number of Competitor Fixes
|
||||
NumberOfMarkFixes=Number of Mark Fixes
|
||||
ManeuverType=Maneuver Type
|
||||
Tack=Tack
|
||||
WindSpeedVsManeuverLoss=Wind Speed in Knots (X) vs. Maneuver Loss in Meters (Y)
|
||||
SpeedBefore=Speed Before Maneuver
|
||||
SpeedAfter=Speed After Maneuver
|
||||
DirectionChange=Direction Change in Degrees
|
||||
@@ -90,19 +95,24 @@ PassingSide=Passing Side
|
||||
TackAtStart=Tack at Start
|
||||
SpeedTenSecondsAfterStart=Speed 10s After Start
|
||||
RankThirtySecondsAfterStart=Rank 30s After Start
|
||||
WindwardDistanceToAdvantageousEndOfLine=Windward Distance to Advantageous End of Line
|
||||
WindwardDistanceToAdvantageousEndOfLineAtStartOfRace=Windward Distance to Advantageous End of Line at Start of Race
|
||||
WindwardDistanceToAdvantageousEndOfLineAtStartOfCompetitor=Windward Distance to Starboard Side of Line at Start of Competitor
|
||||
RankAfterHalfOfTheFirstLeg=Rank after the half of the first leg
|
||||
AdvantageousEndOfLine=Advantageous End of Line
|
||||
TimeSpentInSeconds=Time Spent in Seconds
|
||||
MedalRace=Medal Race
|
||||
WindwardDistanceToAdvantageousEndOfLineAtStartOfRaceVsRelativeDistanceToAdvantageousEndOfLine=Windward Distance to Advantageous End of Line at Start of Race (X) vs. Relative Distance to Advantageous End of Line at Start of Race (Y)
|
||||
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
|
||||
windFrom=True Wind Direction (TWD)
|
||||
windSpeedKnots=True Wind Speed (kts)
|
||||
speedInKnots=Speed (kts)
|
||||
bearing=Direction (°T)
|
||||
WindTrack=Wind Track
|
||||
timeSpentFoiling=Time spent foiling
|
||||
DistanceToStarboardSideAtStartOfCompetitorVsFinalRank=Relative Distance to Starboard Side at Start of Competitor (X) vs. Final Rank (Y)
|
||||
yaw=Yaw
|
||||
pitch=Pitch
|
||||
heel=Heel
|
||||
|
||||
+12
-2
@@ -36,6 +36,7 @@ MarkPassing=Tonnenrundung
|
||||
LegOfCompetitor=Schenkel eines Teilnehmers
|
||||
GpsFix=GPS-Fix
|
||||
BravoFix=Bravo-Fix
|
||||
LineLengthAtStart=Länge der Startlinie zum Startzeitpunkt
|
||||
BravoFixTrack=Bravo-Messreihe
|
||||
WindFix=Windmessung
|
||||
Maneuver=Manöver
|
||||
@@ -69,8 +70,10 @@ NumberOfTacks=Anzahl der Wenden
|
||||
NumberOfJibes=Anzahl der Halsen
|
||||
NumberOfPenaltyCircles=Anzahl der Straf-Kreise
|
||||
RankGainsOrLosses=Positions-Verluste oder -Gewinne
|
||||
DistanceToStarboardSideAtStart=Distanz zur Steuerbordseite (% der Länge)
|
||||
DistanceToStarboardSideAtStartOfCompetitor=Relative Distanz zur Steuerbordseite beim Start des Teilnehmers
|
||||
DistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark=Relative Distanz zur Steuerbordseite beim Start des Teilnehmers (X) vs. Position beim ersten Wegpunkt (Y)
|
||||
NumberOfPodiumFinish=Azahl der Podium-Siege
|
||||
DistanceToStarboardSideAtStartOfCompetitorVsFinalRank=Relative Distanz zur Steuerbordseite zum Start des Teilnehmers (X) vs. finale Platzierung (Y)
|
||||
NumberOfWins=Anzahl der Siege
|
||||
RankGainsOrLossesBetweenFirstMarkAndFinish=Positions-Verluste oder -Gewinne (1ter Wegpunkt -> Ziel)
|
||||
IsTracked=Ist getracked
|
||||
@@ -90,11 +93,14 @@ PassingSide=Passierende Seite
|
||||
TackAtStart=Startbug
|
||||
SpeedTenSecondsAfterStart=Geschwindigkeit 10s nach dem Startzeitpunkt
|
||||
RankThirtySecondsAfterStart=Absolute Platzierung 30s nach dem Startzeitpunkt
|
||||
WindwardDistanceToAdvantageousEndOfLine=Windwärtige Distanz zum Bevorteilten Ende der Startlinie
|
||||
WindwardDistanceToAdvantageousEndOfLineAtStartOfRace=Windwärtige Distanz zum Bevorteilten Ende der Startlinie zum Start des Rennens
|
||||
WindwardDistanceToAdvantageousEndOfLineAtStartOfCompetitor=Windwärtige Distanz zum Bevorteilten Ende der Startlinie zum Start des Teilnehmers
|
||||
AbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor=Absolute Windwärtige Distanz zur Steuerbordseite beim Start des Teilnehmers
|
||||
RankAfterHalfOfTheFirstLeg=Platzierung nach der Hälfte des ersten Schenkels
|
||||
AdvantageousEndOfLine=Bevorteiltes Ende der Startlinie
|
||||
TimeSpentInSeconds=Benötigte Zeit in Sekunden
|
||||
MedalRace=Medaillenrennen
|
||||
WindSpeedVsManeuverLoss=Windgeschwindigkeit in Knoten (X) vs. Manöververlust in Meter (Y)
|
||||
WindSourceType=Art der Windmessung
|
||||
WindSourceName=Name der Windmessreihe
|
||||
windFrom=Wind aus Richtung (TWD)
|
||||
@@ -106,6 +112,8 @@ timeSpentFoiling=Zeit auf Foils
|
||||
yaw=Gierung
|
||||
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
|
||||
rideHeight=Foiling-Höhe
|
||||
rideHeightPort=Foiling-Höhe Backbord-Rumpf
|
||||
rideHeightStarboard=Foiling-Höhe Steuerbord-Rumpf
|
||||
@@ -127,6 +135,8 @@ 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
|
||||
ManeuverEnteringAbsTWA=Absolutes TWA vor Manöver
|
||||
|
||||
+4
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
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;
|
||||
@@ -26,6 +27,9 @@ public interface HasManeuverContext extends HasManeuver, HasTrackedLegOfCompetit
|
||||
|
||||
@Statistic(messageKey = "ManeuverLoss", resultDecimals = 0, ordinal = 4)
|
||||
Distance getManeuverLoss();
|
||||
|
||||
@Statistic(messageKey = "WindSpeedVsManeuverLoss", resultDecimals = 2, ordinal = 4)
|
||||
Pair<Double, Double> getWindSpeedVsManeuverLoss();
|
||||
|
||||
@Statistic(messageKey = "AbsTWAAtManeuverClimax", ordinal = 7)
|
||||
Double getAbsTWAAtManeuverClimax();
|
||||
|
||||
+28
-7
@@ -5,6 +5,7 @@ import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.annotations.Connector;
|
||||
import com.sap.sse.datamining.annotations.Dimension;
|
||||
import com.sap.sse.datamining.annotations.Statistic;
|
||||
@@ -22,7 +23,7 @@ public interface HasRaceOfCompetitorContext {
|
||||
@Dimension(messageKey="TackAtStart", ordinal=12)
|
||||
public Tack getTackAtStart() throws NoWindException;
|
||||
|
||||
@Dimension(messageKey="DistanceToStarboardSideAtStart", ordinal=13)
|
||||
@Dimension(messageKey="DistanceToStarboardSideAtStartOfCompetitor", ordinal=13)
|
||||
public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart();
|
||||
|
||||
@Dimension(messageKey="RelativeScoreInPercent", ordinal=14)
|
||||
@@ -31,11 +32,17 @@ public interface HasRaceOfCompetitorContext {
|
||||
@Statistic(messageKey="DistanceAtStart", resultDecimals=2, ordinal=0)
|
||||
public Distance getDistanceToStartLineAtStart();
|
||||
|
||||
@Statistic(messageKey="DistanceToStarboardSideAtStart", resultDecimals=2, ordinal=1)
|
||||
public Double getNormalizedDistanceToStarboardSideAtStart();
|
||||
@Statistic(messageKey="DistanceToStarboardSideAtStartOfCompetitor", resultDecimals=2, ordinal=1)
|
||||
public Double getNormalizedDistanceToStarboardSideAtStartOfCompetitor();
|
||||
|
||||
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLine", resultDecimals=2, ordinal=2)
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStart();
|
||||
@Statistic(messageKey="DistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark", resultDecimals=2, ordinal=1)
|
||||
public Pair<Double, Double> getNormalizedDistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark();
|
||||
|
||||
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLineAtStartOfRace", resultDecimals=2, ordinal=2)
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStartofRace();
|
||||
|
||||
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLineAtStartOfCompetitor", resultDecimals=2, ordinal=2)
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStartofCompetitor();
|
||||
|
||||
@Connector(messageKey="SpeedWhenStarting", ordinal=3)
|
||||
public Speed getSpeedWhenStarting();
|
||||
@@ -44,10 +51,10 @@ public interface HasRaceOfCompetitorContext {
|
||||
public Speed getSpeedTenSecondsBeforeStart();
|
||||
|
||||
@Connector(messageKey="SpeedTenSecondsAfterStart", ordinal=5)
|
||||
public Speed getSpeedTenSecondsAfterStart();
|
||||
public Speed getSpeedTenSecondsAfterStartOfRace();
|
||||
|
||||
@Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=6)
|
||||
public Double getRankThirtySecondsAfterStart();
|
||||
public Double getRankThirtySecondsAfterStartOfRace();
|
||||
|
||||
@Statistic(messageKey="RankAfterHalfOfTheFirstLeg", resultDecimals=2, ordinal=7)
|
||||
public Double getRankAfterHalfOfTheFirstLeg();
|
||||
@@ -73,4 +80,18 @@ public interface HasRaceOfCompetitorContext {
|
||||
@Statistic(messageKey="DistanceTraveled", resultDecimals=1)
|
||||
public Distance getDistanceTraveled();
|
||||
|
||||
@Statistic(messageKey="LineLengthAtStart", resultDecimals=1)
|
||||
public Distance getLineLengthAtStart();
|
||||
|
||||
@Statistic(messageKey="AbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor", resultDecimals=2)
|
||||
Distance getAbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor();
|
||||
|
||||
@Statistic(messageKey="DistanceToStarboardSideAtStartOfCompetitorVsFinalRank", resultDecimals=2)
|
||||
Pair<Double, Double> getRelativeDistanceToStarboardSideAtStartOfCompetitorVsFinalRank();
|
||||
|
||||
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLineAtStartOfRaceVsRelativeDistanceToAdvantageousEndOfLine", resultDecimals=2)
|
||||
Pair<Double, Double> getWindwardDistanceToAdvantageousEndOfLineAtStartOfRaceVsRelativeDistanceToAdvantageousEndOfLineAtStartOfRace();
|
||||
|
||||
@Statistic(messageKey="RelativeDistanceToAdvantageousEndOfLineAtStartOfRace", resultDecimals=2)
|
||||
Double getRelativeDistanceToAdvantageousEndOfLineAtStartOfRace();
|
||||
}
|
||||
+7
@@ -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.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;
|
||||
@@ -24,6 +25,12 @@ public interface HasTrackedLegOfCompetitorContext extends HasWindOnTrackedLeg {
|
||||
@Statistic(messageKey="DistanceTraveled", resultDecimals=0, ordinal=0)
|
||||
public Distance getDistanceTraveled();
|
||||
|
||||
@Statistic(messageKey="SpeedAverage", resultDecimals=0, 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();
|
||||
|
||||
|
||||
+7
@@ -14,6 +14,7 @@ import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -64,6 +65,7 @@ public class ManeuverWithContext implements HasManeuverContext {
|
||||
public ManeuverType getTypeOfNextManeuver() {
|
||||
return nextManeuver != null ? nextManeuver.getType() : ManeuverType.UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Double getManeuverEnteringSpeed() {
|
||||
@@ -142,6 +144,11 @@ public class ManeuverWithContext implements HasManeuverContext {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Pair<Double, Double> getWindSpeedVsManeuverLoss(){
|
||||
Wind wind = getTrackedLegOfCompetitorContext().getTrackedRace().getWind(maneuver.getPosition(), getTimePointBeforeForAnalysis());
|
||||
return new Pair<>(wind.getKnots(), getManeuverLoss().getMeters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getEnteringManeuverSpeedMinusExitingSpeed() {
|
||||
|
||||
+104
-9
@@ -27,6 +27,7 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindPositionMode;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.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;
|
||||
@@ -63,7 +64,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
|
||||
@Override
|
||||
public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart() {
|
||||
Double normalizedDistance = getNormalizedDistanceToStarboardSideAtStart();
|
||||
Double normalizedDistance = getNormalizedDistanceToStarboardSideAtStartOfCompetitor();
|
||||
if (normalizedDistance == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -79,7 +80,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getNormalizedDistanceToStarboardSideAtStart() {
|
||||
public Double getNormalizedDistanceToStarboardSideAtStartOfCompetitor() {
|
||||
TrackedRace trackedRace = getTrackedRace();
|
||||
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, trackedRace.getRace().getCourse().getFirstLeg());
|
||||
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
|
||||
@@ -93,10 +94,16 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStart() {
|
||||
public Pair<Double, Double> getNormalizedDistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark(){
|
||||
return new Pair<Double, Double> (getNormalizedDistanceToStarboardSideAtStartOfCompetitor(), getRankAtFirstMark());
|
||||
}
|
||||
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStartOf(TimePoint timepoint) {
|
||||
if(timepoint == null) {
|
||||
return null;
|
||||
}
|
||||
TrackedRace trackedRace = getTrackedRace();
|
||||
TimePoint startOfRace = trackedRace.getStartOfRace();
|
||||
LineDetails startLine = trackedRace.getStartLine(startOfRace);
|
||||
LineDetails startLine = trackedRace.getStartLine(timepoint);
|
||||
Mark advantageousMark = null;
|
||||
switch (startLine.getAdvantageousSideWhileApproachingLine()) {
|
||||
case PORT:
|
||||
@@ -111,12 +118,49 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
}
|
||||
|
||||
GPSFixTrack<Mark, GPSFix> advantageousMarkTrack = trackedRace.getOrCreateTrack(advantageousMark);
|
||||
Position advantageousMarkPosition = advantageousMarkTrack.getEstimatedPosition(startOfRace, false);
|
||||
Position advantageousMarkPosition = advantageousMarkTrack.getEstimatedPosition(timepoint, false);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> competitorTrack = trackedRace.getTrack(getCompetitor());
|
||||
Position competitorPosition = competitorTrack.getEstimatedPosition(timepoint, false);
|
||||
|
||||
TrackedLeg trackedLeg = trackedRace.getTrackedLeg(trackedRace.getRace().getCourse().getFirstLeg());
|
||||
Distance distance = trackedLeg.getWindwardDistance(competitorPosition, advantageousMarkPosition, timepoint, WindPositionMode.LEG_MIDDLE);
|
||||
return distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStartofRace() {
|
||||
return getWindwardDistanceToAdvantageousLineEndAtStartOf(getTrackedRace().getStartOfRace());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWindwardDistanceToAdvantageousLineEndAtStartofCompetitor() {
|
||||
return getWindwardDistanceToAdvantageousLineEndAtStartOf(getTrackedRace().getTrackedLeg(getCompetitor(), getTrackedRace().getRace().getCourse().getFirstLeg()).getStartTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getAbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor() {
|
||||
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = getTrackedRace().getTrackedLeg(competitor, getTrackedRace().getRace().getCourse().getFirstLeg());
|
||||
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
|
||||
if(competitorStartTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TrackedRace trackedRace = getTrackedRace();
|
||||
TimePoint startOfRace = trackedRace.getStartOfRace();
|
||||
LineDetails startLine = trackedRace.getStartLine(startOfRace);
|
||||
Mark starboardMark = startLine.getStarboardMarkWhileApproachingLine();
|
||||
if (starboardMark == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GPSFixTrack<Mark, GPSFix> starboardMarkTrack = trackedRace.getOrCreateTrack(starboardMark);
|
||||
Position starboardMarkPosition = starboardMarkTrack.getEstimatedPosition(startOfRace, false);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> competitorTrack = trackedRace.getTrack(getCompetitor());
|
||||
Position competitorPosition = competitorTrack.getEstimatedPosition(startOfRace, false);
|
||||
|
||||
TrackedLeg trackedLeg = trackedRace.getTrackedLeg(trackedRace.getRace().getCourse().getFirstLeg());
|
||||
Distance distance = trackedLeg.getWindwardDistance(competitorPosition, advantageousMarkPosition, startOfRace, WindPositionMode.LEG_MIDDLE);
|
||||
Distance distance = trackedLeg.getAbsoluteWindwardDistance(competitorPosition, starboardMarkPosition, startOfRace, WindPositionMode.LEG_MIDDLE);
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
@@ -143,7 +187,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getSpeedTenSecondsAfterStart() {
|
||||
public Speed getSpeedTenSecondsAfterStartOfRace() {
|
||||
TimePoint startOfRace = getTrackedRace().getStartOfRace();
|
||||
if (startOfRace == null) {
|
||||
return null;
|
||||
@@ -152,7 +196,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRankThirtySecondsAfterStart() {
|
||||
public Double getRankThirtySecondsAfterStartOfRace() {
|
||||
TimePoint startOfRace = getTrackedRace().getStartOfRace();
|
||||
if (startOfRace == null) {
|
||||
return null;
|
||||
@@ -244,4 +288,55 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
|
||||
return getTrackedRace().getDistanceTraveledIncludingGateStart(getCompetitor(), MillisecondsTimePoint.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getLineLengthAtStart() {
|
||||
TrackedLegOfCompetitor firstTrackedLegOfCompetitor = getTrackedRace().getTrackedLeg(competitor, getTrackedRace().getRace().getCourse().getFirstLeg());
|
||||
TimePoint competitorStartTime = firstTrackedLegOfCompetitor.getStartTime();
|
||||
if (competitorStartTime == null) {
|
||||
return null;
|
||||
}
|
||||
return getTrackedRace().getStartLine(competitorStartTime).getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Double, Double> getRelativeDistanceToStarboardSideAtStartOfCompetitorVsFinalRank(){
|
||||
return new Pair<>(getNormalizedDistanceToStarboardSideAtStartOfCompetitor(), getTrackedRaceContext().getRankAtFinishForCompetitor(getCompetitor()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Double, Double> getWindwardDistanceToAdvantageousEndOfLineAtStartOfRaceVsRelativeDistanceToAdvantageousEndOfLineAtStartOfRace(){
|
||||
return new Pair<>(getWindwardDistanceToAdvantageousLineEndAtStartofRace().getMeters(), getRelativeDistanceToAdvantageousEndOfLineAtStartOfRace());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRelativeDistanceToAdvantageousEndOfLineAtStartOfRace() {
|
||||
TrackedRace trackedRace = getTrackedRace();
|
||||
TimePoint startOfRace = trackedRace.getStartOfRace();
|
||||
LineDetails startLine = trackedRace.getStartLine(startOfRace);
|
||||
Mark advantageousMark = null;
|
||||
switch (startLine.getAdvantageousSideWhileApproachingLine()) {
|
||||
case PORT:
|
||||
advantageousMark = startLine.getPortMarkWhileApproachingLine();
|
||||
break;
|
||||
case STARBOARD:
|
||||
advantageousMark = startLine.getStarboardMarkWhileApproachingLine();
|
||||
break;
|
||||
}
|
||||
if (advantageousMark == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GPSFixTrack<Mark, GPSFix> advantageousMarkTrack = trackedRace.getOrCreateTrack(advantageousMark);
|
||||
Position advantageousMarkPosition = advantageousMarkTrack.getEstimatedPosition(startOfRace, false);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> competitorTrack = trackedRace.getTrack(getCompetitor());
|
||||
Position competitorPosition = competitorTrack.getEstimatedPosition(startOfRace, false);
|
||||
|
||||
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();
|
||||
return distance / length;
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.sap.sailing.datamining.Activator;
|
||||
@@ -7,17 +8,21 @@ import com.sap.sailing.datamining.SailingClusterGroups;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
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;
|
||||
@@ -111,6 +116,28 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
|
||||
return getTrackedLegOfCompetitor().getDistanceTraveled(timePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getSpeedAverage() {
|
||||
if (getTrackedRace() == null) {
|
||||
return null;
|
||||
} else {
|
||||
final List<Leg> legs = getTrackedRace().getRace().getCourse().getLegs();
|
||||
if (legs.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
final Leg lastLeg = legs.get(legs.size() - 1);
|
||||
TimePoint finished = getTrackedRace().getTrackedLeg(getCompetitor(), lastLeg).getFinishTime();
|
||||
return getTrackedRace().getAverageSpeedOverGround(getCompetitor(), finished).getKnots();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Double, Double> getSpeedAverageVsDistanceTraveled(){
|
||||
return new Pair<Double, Double>(getSpeedAverage(), getDistanceTraveled().getMeters());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Double getRankGainsOrLosses() {
|
||||
Double rankAtStart = getRankAtStart();
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sse.datamining.shared.impl;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.shared.impl.PairWithStatsImpl;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class PairWithStatsImpl_CustomFieldSerializer extends CustomFieldSerializer<PairWithStatsImpl> {
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PairWithStatsImpl instantiateInstance(SerializationStreamReader streamReader) throws SerializationException {
|
||||
return instantiate(streamReader);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static PairWithStatsImpl instantiate(SerializationStreamReader streamReader) throws SerializationException {
|
||||
final Pair average = (Pair) streamReader.readObject();
|
||||
final Pair min = (Pair) streamReader.readObject();
|
||||
final Pair max = (Pair) streamReader.readObject();
|
||||
final Pair median = (Pair) streamReader.readObject();
|
||||
final Pair standardDeviation = (Pair) streamReader.readObject();
|
||||
final HashSet individualPairs = (HashSet) streamReader.readObject();
|
||||
final String resultType = streamReader.readString();
|
||||
final long count = streamReader.readLong();
|
||||
return new PairWithStatsImpl<Object>(average, min, max, median, standardDeviation, individualPairs, count, resultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(SerializationStreamReader streamReader, PairWithStatsImpl instance)
|
||||
throws SerializationException {
|
||||
deserialize(streamReader, instance);
|
||||
}
|
||||
|
||||
public static void deserialize(SerializationStreamReader streamReader, PairWithStatsImpl instance) {
|
||||
// handled by instantiate
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(SerializationStreamWriter streamWriter, PairWithStatsImpl instance)
|
||||
throws SerializationException {
|
||||
serialize(streamWriter, instance);
|
||||
}
|
||||
|
||||
public static void serialize(SerializationStreamWriter streamWriter, PairWithStatsImpl instance)
|
||||
throws SerializationException {
|
||||
streamWriter.writeObject(instance.getAverage());
|
||||
streamWriter.writeObject(instance.getMin());
|
||||
streamWriter.writeObject(instance.getMax());
|
||||
streamWriter.writeObject(instance.getMedian());
|
||||
streamWriter.writeObject(instance.getStandardDeviation());
|
||||
streamWriter.writeObject(instance.getIndividualPairs());
|
||||
streamWriter.writeString(instance.getResultType());
|
||||
streamWriter.writeLong(instance.getCount());
|
||||
}
|
||||
}
|
||||
+1
@@ -1533,6 +1533,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String tabbedResultsPresenter();
|
||||
String polarResultsPresenter();
|
||||
String maneuverSpeedDetailsResultsPresenter();
|
||||
String numberPairResultsPresenter();
|
||||
String dataMiningRetrieval();
|
||||
String actionWatch();
|
||||
String actionAnalyze();
|
||||
|
||||
+1
@@ -9,6 +9,7 @@ trackedBefore=History of tracked events
|
||||
general=General
|
||||
listRaces=List Races
|
||||
listRegattas=List Regattas
|
||||
numberPairResultsPresenter=Scatterplot
|
||||
wind=Wind
|
||||
maneuverType=Maneuver
|
||||
windPanelLabel=This is the Wind Panel which so far is completely empty.
|
||||
|
||||
+1
@@ -1489,6 +1489,7 @@ resultsChart=Ergebnis-Diagramm
|
||||
tabbedResultsPresenter=Tab Ergebnis-Darsteller
|
||||
polarResultsPresenter=Polar Ergebnis-Darsteller
|
||||
maneuverSpeedDetailsResultsPresenter=Manöver Geschwindigkeitsdetails Ergebnis-Darsteller
|
||||
numberPairResultsPresenter=Scatterplot
|
||||
dataMiningRetrieval=Datenbeschaffung
|
||||
actionWatch=Verfolgen
|
||||
actionAnalyze=Analysieren
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package com.sap.sailing.gwt.ui.datamining.presentation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.Chart;
|
||||
import org.moxieapps.gwt.highcharts.client.ChartTitle;
|
||||
import org.moxieapps.gwt.highcharts.client.Color;
|
||||
import org.moxieapps.gwt.highcharts.client.Credits;
|
||||
import org.moxieapps.gwt.highcharts.client.Exporting;
|
||||
import org.moxieapps.gwt.highcharts.client.Point;
|
||||
import org.moxieapps.gwt.highcharts.client.Series;
|
||||
import org.moxieapps.gwt.highcharts.client.ToolTip;
|
||||
import org.moxieapps.gwt.highcharts.client.ToolTipData;
|
||||
import org.moxieapps.gwt.highcharts.client.ToolTipFormatter;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.SeriesPlotOptions;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker.Symbol;
|
||||
|
||||
import com.google.gwt.user.client.ui.SimpleLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.settings.Settings;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.data.PairWithStats;
|
||||
import com.sap.sse.datamining.shared.impl.CompoundGroupKey;
|
||||
import com.sap.sse.datamining.shared.impl.GenericGroupKey;
|
||||
import com.sap.sse.datamining.shared.impl.dto.QueryResultDTO;
|
||||
import com.sap.sse.gwt.client.shared.components.Component;
|
||||
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
|
||||
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
|
||||
|
||||
public class NumberPairResultsPresenter extends AbstractResultsPresenter<Settings> {
|
||||
private QueryResultDTO<?> result;
|
||||
private final SimpleLayoutPanel chartPanel;
|
||||
private final Chart chart;
|
||||
private final Map<GroupKey, Series> seriesMappedByGroupKey;
|
||||
private final GroupKey simpleResultSeriesKey;
|
||||
|
||||
public NumberPairResultsPresenter(Component<?> parent, ComponentContext<?> context, StringMessages stringMessages) {
|
||||
super(parent, context, stringMessages);
|
||||
seriesMappedByGroupKey = new HashMap<>();
|
||||
chartPanel = new SimpleLayoutPanel() {
|
||||
@Override
|
||||
public void onResize() {
|
||||
chart.setSizeToMatchContainer();
|
||||
chart.redraw();
|
||||
}
|
||||
};
|
||||
simpleResultSeriesKey = new GenericGroupKey<>(stringMessages.results());
|
||||
chart = createChart();
|
||||
chartPanel.setWidget(chart);
|
||||
}
|
||||
|
||||
private Chart createChart() {
|
||||
Chart chart = new Chart()
|
||||
.setType(Series.Type.SCATTER)
|
||||
.setMarginLeft(100)
|
||||
.setMarginRight(45)
|
||||
.setWidth100()
|
||||
.setHeight100()
|
||||
.setBorderColor(new Color("#F0AB00"))
|
||||
.setPlotBorderWidth(0)
|
||||
.setCredits(new Credits().setEnabled(false))
|
||||
.setChartTitle(new ChartTitle().setText(getStringMessages().dataMiningResult()));
|
||||
chart.setExporting(new Exporting().setEnabled(false));
|
||||
chart.getXAxis().setAllowDecimals(false);
|
||||
chart.getYAxis().setAxisTitleText("");
|
||||
|
||||
chart.setToolTip(new ToolTip().setFormatter(new ToolTipFormatter() {
|
||||
|
||||
@Override
|
||||
public String format(ToolTipData toolTipData) {
|
||||
return "<b>"+toolTipData.getPointName()+"</b><br>X: "+toolTipData.getPoint().getX()+"<br>Y: "+toolTipData.getYAsString();
|
||||
}
|
||||
}));
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getPresentationWidget() {
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void internalShowResults(QueryResultDTO<?> res) {
|
||||
result = res;
|
||||
createAndAddSeriesToChart();
|
||||
|
||||
for (Entry<GroupKey, ?> resultEntry : result.getResults().entrySet()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
PairWithStats<Number> value = (PairWithStats<Number>) resultEntry.getValue();
|
||||
|
||||
if(value.getIndividualPairs() != null) {
|
||||
for(Pair<Number, Number> pair : value.getIndividualPairs()) {
|
||||
createAndAddPoint(resultEntry.getKey(), pair.getA(), pair.getB());
|
||||
}
|
||||
}
|
||||
else {
|
||||
createAndAddPoint(resultEntry.getKey(), value.getAverage().getA(), value.getAverage().getB());
|
||||
}
|
||||
|
||||
}
|
||||
chart.getXAxis().setAxisTitleText(result.getResultSignifier());
|
||||
}
|
||||
|
||||
private void createAndAddPoint(GroupKey key, Number x, Number y) {
|
||||
Point point = new Point(x, y);
|
||||
point.setName(key.asString());
|
||||
seriesMappedByGroupKey.get(groupKeyToSeriesKey(key)).addPoint(point, false, false, false);
|
||||
}
|
||||
|
||||
private void createAndAddSeriesToChart() {
|
||||
for (GroupKey groupKey : result.getResults().keySet()) {
|
||||
GroupKey seriesKey = groupKeyToSeriesKey(groupKey);
|
||||
if (!seriesMappedByGroupKey.containsKey(seriesKey)) {
|
||||
seriesMappedByGroupKey.put(seriesKey, chart.createSeries().setPlotOptions(new SeriesPlotOptions().setMarker(new Marker().setSymbol(Symbol.CIRCLE))).setName(seriesKey.asString()));
|
||||
chart.addSeries(seriesMappedByGroupKey.get(seriesKey), false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GroupKey groupKeyToSeriesKey(GroupKey groupKey) {
|
||||
return new CompoundGroupKey(groupKey.getKeys());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getLocalizedShortName() {
|
||||
return getStringMessages().numberPairResultsPresenter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<Settings> getSettingsDialogComponent(Settings settings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSettings(Settings newSettings) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings getSettings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "NumberPairResultsPresenter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDependentCssClassName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+9
-1
@@ -88,7 +88,15 @@ public class TabbedResultsPresenter extends AbstractComponent<Settings> implemen
|
||||
addTabAndFocus(new ManeuverSpeedDetailsResultsPresenter(TabbedResultsPresenter.this,
|
||||
getComponentContext(), stringMessages));
|
||||
removeTab(oldHeader);
|
||||
} else {
|
||||
}
|
||||
else if (result.getResultType()
|
||||
.equals("com.sap.sse.datamining.shared.data.PairWithStats")) {
|
||||
CloseableTabHeader oldHeader = getSelectedHeader();
|
||||
addTabAndFocus(new NumberPairResultsPresenter(TabbedResultsPresenter.this,
|
||||
getComponentContext(), stringMessages));
|
||||
removeTab(oldHeader);
|
||||
}
|
||||
else {
|
||||
if (!(getSelectedPresenter() instanceof MultiResultsPresenter)) {
|
||||
CloseableTabHeader oldHeader = getSelectedHeader();
|
||||
addTabAndFocus(new MultiResultsPresenter(this, getComponentContext(), drillDownCallback, stringMessages));
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
Previously it was only possible to import a new event structure.</li>
|
||||
<li>The Expedition log file import now prefers "GPS Time" for time stamping over "Utc" and over other date / time formats, making it
|
||||
more consistent with the Expedition live connector which uses column 146 for time stamping which is GPS Time.</li>
|
||||
<li>Two dimensional metrics can now be displayed by using a scatter plot presenter within the data mining tool.
|
||||
Select a metric that returns a pair of numbers and choose "Average" or "Identity" as an aggregator.</li>
|
||||
<li>Replication was made more robust for fixes that are delivered and applied asynchronously. If a race was removed
|
||||
while still in tracking mode, fix-related operations may have been queued already on the replica when the
|
||||
tracked race is removed. The pending GPS fix operations then would have clogged the executor threads until
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.sap.sse.datamining.shared.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public interface PairWithStats<T> extends Serializable {
|
||||
Pair<T, T> getAverage();
|
||||
Pair<T, T> getMin();
|
||||
Pair<T, T> getMax();
|
||||
Pair<T, T> getMedian();
|
||||
Pair<T, T> getStandardDeviation();
|
||||
HashSet<Pair<T,T>> getIndividualPairs();
|
||||
long getCount();
|
||||
|
||||
/**
|
||||
* @return the fully-qualified type name of the {@code T} type argument; may be used by
|
||||
* the results presenter to choose an applicable data provider.
|
||||
*/
|
||||
String getResultType();
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package com.sap.sse.datamining.shared.impl;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.shared.data.PairWithStats;
|
||||
|
||||
public class PairWithStatsImpl<T> implements PairWithStats<T> {
|
||||
private static final long serialVersionUID = -2643300186690471524L;
|
||||
private final Pair<T, T> average;
|
||||
private final Pair<T, T> min;
|
||||
private final Pair<T, T> max;
|
||||
private final Pair<T, T> median;
|
||||
private final Pair<T, T> standardDeviation;
|
||||
private final HashSet<Pair<T,T>> individualPairs;
|
||||
private final long count;
|
||||
private final String resultType;
|
||||
|
||||
public PairWithStatsImpl(Pair<T, T> average, Pair<T, T> min, Pair<T, T> max, Pair<T, T> median, Pair<T, T> standardDeviation, HashSet<Pair<T,T>> individualPairs, long count, String resultType) {
|
||||
super();
|
||||
this.average = average;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.median = median;
|
||||
this.standardDeviation = standardDeviation;
|
||||
this.individualPairs = individualPairs;
|
||||
this.count = count;
|
||||
this.resultType = resultType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<T, T> getAverage() {
|
||||
return average;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<T, T> getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<T, T> getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<T, T> getMedian() {
|
||||
return median;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<T, T> getStandardDeviation() {
|
||||
return standardDeviation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultType() {
|
||||
return resultType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Pair<T, T>> getIndividualPairs() {
|
||||
return individualPairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PairWithStatsImpl [average=" + average + ", min=" + min + ", max=" + max + ", median=" + median
|
||||
+ ", standardDeviation=" + standardDeviation + ", individualPairs=" + individualPairs + ", count=" + count + ", resultType=" + resultType + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((average == null) ? 0 : average.hashCode());
|
||||
result = prime * result + (int) (count ^ (count >>> 32));
|
||||
result = prime * result + ((max == null) ? 0 : max.hashCode());
|
||||
result = prime * result + ((median == null) ? 0 : median.hashCode());
|
||||
result = prime * result + ((min == null) ? 0 : min.hashCode());
|
||||
result = prime * result + ((resultType == null) ? 0 : resultType.hashCode());
|
||||
result = prime * result + ((standardDeviation == null) ? 0 : standardDeviation.hashCode());
|
||||
result = prime * result + ((individualPairs == null) ? 0 : individualPairs.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
PairWithStatsImpl<?> other = (PairWithStatsImpl<?>) obj;
|
||||
if (average == null) {
|
||||
if (other.average != null)
|
||||
return false;
|
||||
} else if (!average.equals(other.average))
|
||||
return false;
|
||||
if (count != other.count)
|
||||
return false;
|
||||
if (max == null) {
|
||||
if (other.max != null)
|
||||
return false;
|
||||
} else if (!max.equals(other.max))
|
||||
return false;
|
||||
if (median == null) {
|
||||
if (other.median != null)
|
||||
return false;
|
||||
} else if (!median.equals(other.median))
|
||||
return false;
|
||||
if (min == null) {
|
||||
if (other.min != null)
|
||||
return false;
|
||||
} else if (!min.equals(other.min))
|
||||
return false;
|
||||
if (resultType == null) {
|
||||
if (other.resultType != null)
|
||||
return false;
|
||||
} else if (!resultType.equals(other.resultType))
|
||||
return false;
|
||||
if (standardDeviation == null) {
|
||||
if (other.standardDeviation != null)
|
||||
return false;
|
||||
} else if (!standardDeviation.equals(other.standardDeviation))
|
||||
return false;
|
||||
if (individualPairs == null) {
|
||||
if (other.individualPairs != null)
|
||||
return false;
|
||||
} else if (!individualPairs.equals(other.individualPairs))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
Average=Average
|
||||
PairAverage=Average
|
||||
Median=Median
|
||||
PairCollecting=Identity
|
||||
Sum=Sum
|
||||
Maximum=Maximum
|
||||
Minimum=Minimum
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
Average=Durchschnitt
|
||||
PairAverage=Durchschnitt
|
||||
PairCollecting=Identität
|
||||
Median=Median
|
||||
Sum=Summe
|
||||
Maximum=Maximum
|
||||
|
||||
+4
@@ -28,11 +28,13 @@ import com.sap.sse.datamining.components.management.FunctionRegistry;
|
||||
import com.sap.sse.datamining.components.management.QueryDefinitionDTORegistry;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedDataCountAggregationProcessor;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedDataCountDistinctAggregationProcessor;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedNumberPairCollectingProcessor;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedNumberDataAverageAggregationProcessor;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedNumberDataMaxAggregationProcessor;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedNumberDataMedianAggregationProcessor;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedNumberDataMinAggregationProcessor;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedNumberDataSumAggregationProcessor;
|
||||
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedNumberPairAverageAggregationProcessor;
|
||||
import com.sap.sse.datamining.impl.components.management.AggregationProcessorDefinitionManager;
|
||||
import com.sap.sse.datamining.impl.components.management.DataRetrieverChainDefinitionManager;
|
||||
import com.sap.sse.datamining.impl.components.management.DataSourceProviderManager;
|
||||
@@ -86,6 +88,8 @@ public class DataMiningFrameworkActivator implements BundleActivator {
|
||||
defaultAggregationProcessors.add(ParallelGroupedDataCountDistinctAggregationProcessor.getDefinition());
|
||||
defaultAggregationProcessors.add(ParallelGroupedDataCountAggregationProcessor.getDefinition());
|
||||
defaultAggregationProcessors.add(ParallelGroupedNumberDataAverageAggregationProcessor.getDefinition());
|
||||
defaultAggregationProcessors.add(ParallelGroupedNumberPairAverageAggregationProcessor.getDefinition());
|
||||
defaultAggregationProcessors.add(ParallelGroupedNumberPairCollectingProcessor.getDefinition());
|
||||
defaultAggregationProcessors.add(ParallelGroupedNumberDataMaxAggregationProcessor.getDefinition());
|
||||
defaultAggregationProcessors.add(ParallelGroupedNumberDataMedianAggregationProcessor.getDefinition());
|
||||
defaultAggregationProcessors.add(ParallelGroupedNumberDataMinAggregationProcessor.getDefinition());
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.sap.sse.datamining.impl.components.aggregators;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
import com.sap.sse.datamining.impl.components.SimpleAggregationProcessorDefinition;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.data.PairWithStats;
|
||||
import com.sap.sse.datamining.shared.impl.PairWithStatsImpl;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ParallelGroupedNumberPairAverageAggregationProcessor
|
||||
extends AbstractParallelGroupedDataStoringAggregationProcessor<Pair, PairWithStats<Number>> {
|
||||
private static final Class<?> _c = PairWithStats.class;
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final Class<PairWithStats<Number>> _cc = (Class<PairWithStats<Number>>) _c;
|
||||
|
||||
private static final AggregationProcessorDefinition<Pair, PairWithStats<Number>> DEFINITION =
|
||||
new SimpleAggregationProcessorDefinition<>(Pair.class,
|
||||
_cc, "PairAverage", ParallelGroupedNumberPairAverageAggregationProcessor.class);
|
||||
|
||||
public static AggregationProcessorDefinition<Pair, PairWithStats<Number>> getDefinition() {
|
||||
return DEFINITION;
|
||||
}
|
||||
|
||||
private final Map<GroupKey, Pair<Number, Number>> sumPerKey;
|
||||
private final Map<GroupKey, Pair<Number, Number>> minPerKey;
|
||||
private final Map<GroupKey, Pair<Number, Number>> maxPerKey;
|
||||
private final Map<GroupKey, AtomicLong> elementAmountPerKey;
|
||||
|
||||
public ParallelGroupedNumberPairAverageAggregationProcessor(ExecutorService executor,
|
||||
Collection<Processor<Map<GroupKey, PairWithStats<Number>>, ?>> resultReceivers) {
|
||||
super(executor, resultReceivers, "PairAverage");
|
||||
elementAmountPerKey = new HashMap<>();
|
||||
sumPerKey = new HashMap<>();
|
||||
minPerKey = new HashMap<>();
|
||||
maxPerKey = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void storeElement(GroupedDataEntry<Pair> element) {
|
||||
if (element.getDataEntry() != null) {
|
||||
incrementElementAmount(element);
|
||||
// concurrency is not an issue here; needsSynchronization() returns true
|
||||
Pair<Number, Number> aggregate = sumPerKey.get(element.getKey());
|
||||
Number a = ((Number) element.getDataEntry().getA());
|
||||
Number b = ((Number) element.getDataEntry().getB());
|
||||
|
||||
final Double doubleValueA = a == null ? null : a.doubleValue();
|
||||
final Double doubleValueB = b == null ? null : b.doubleValue();
|
||||
|
||||
if (doubleValueA != null && doubleValueB != null) {
|
||||
if(aggregate == null) {
|
||||
aggregate = new Pair<>(doubleValueA, doubleValueB);
|
||||
sumPerKey.put(element.getKey(), aggregate);
|
||||
}
|
||||
else {
|
||||
sumPerKey.put(element.getKey(), new Pair<>(doubleValueA + aggregate.getA().doubleValue(),doubleValueB + aggregate.getB().doubleValue()));
|
||||
}
|
||||
if (!minPerKey.containsKey(element.getKey()) || doubleValueA < minPerKey.get(element.getKey()).getA().doubleValue() && doubleValueB < minPerKey.get(element.getKey()).getB().doubleValue()) {
|
||||
minPerKey.put(element.getKey(), new Pair<>(doubleValueA, doubleValueB));
|
||||
}
|
||||
if (!maxPerKey.containsKey(element.getKey()) || doubleValueA > maxPerKey.get(element.getKey()).getA().doubleValue() && doubleValueB > maxPerKey.get(element.getKey()).getB().doubleValue()) {
|
||||
maxPerKey.put(element.getKey(), new Pair<>(doubleValueA, doubleValueB));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void incrementElementAmount(GroupedDataEntry<Pair> element) {
|
||||
GroupKey key = element.getKey();
|
||||
// concurrency is not an issue here; needsSynchronization() returns true
|
||||
AtomicLong currentAmount = elementAmountPerKey.get(key);
|
||||
if (currentAmount == null) {
|
||||
elementAmountPerKey.put(key, new AtomicLong(1));
|
||||
} else {
|
||||
currentAmount.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<GroupKey, PairWithStats<Number>> aggregateResult() {
|
||||
Map<GroupKey, PairWithStats<Number>> result = new HashMap<>();
|
||||
for (Entry<GroupKey, Pair<Number, Number>> sumAggregationEntry : sumPerKey.entrySet()) {
|
||||
GroupKey key = sumAggregationEntry.getKey();
|
||||
result.put(key, new PairWithStatsImpl<Number>(new Pair<>(sumAggregationEntry.getValue().getA() != null ? sumAggregationEntry.getValue().getA().doubleValue() / elementAmountPerKey.get(key).get() : null, sumAggregationEntry.getValue().getB() != null ? sumAggregationEntry.getValue().getB().doubleValue() / elementAmountPerKey.get(key).get() : null) ,
|
||||
minPerKey.get(key), maxPerKey.get(key),
|
||||
/* median */ null,
|
||||
/* standardDeviation */ null,
|
||||
/* individualPairs */ null,
|
||||
/* count */ elementAmountPerKey.get(key).get(),
|
||||
Pair.class.getName()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package com.sap.sse.datamining.impl.components.aggregators;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
import com.sap.sse.datamining.impl.components.SimpleAggregationProcessorDefinition;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.data.PairWithStats;
|
||||
import com.sap.sse.datamining.shared.impl.PairWithStatsImpl;
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ParallelGroupedNumberPairCollectingProcessor
|
||||
extends AbstractParallelGroupedDataStoringAggregationProcessor<Pair, PairWithStats<Number>> {
|
||||
|
||||
private static final Class<?> _c = PairWithStats.class;
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final Class<PairWithStats<Number>> _cc = (Class<PairWithStats<Number>>) _c;
|
||||
|
||||
private static final AggregationProcessorDefinition<Pair, PairWithStats<Number>> DEFINITION =
|
||||
new SimpleAggregationProcessorDefinition<>(Pair.class,
|
||||
_cc, "PairCollecting", ParallelGroupedNumberPairCollectingProcessor.class);
|
||||
|
||||
public static AggregationProcessorDefinition<Pair, PairWithStats<Number>> getDefinition() {
|
||||
return DEFINITION;
|
||||
}
|
||||
|
||||
private final Map<GroupKey, HashSet<Pair<Number, Number>>> individualPairs;
|
||||
private final Map<GroupKey, AtomicLong> elementAmountPerKey;
|
||||
|
||||
public ParallelGroupedNumberPairCollectingProcessor(ExecutorService executor,
|
||||
Collection<Processor<Map<GroupKey, PairWithStats<Number>>, ?>> resultReceivers) {
|
||||
super(executor, resultReceivers, "PairCollecting");
|
||||
individualPairs = new HashMap<>();
|
||||
elementAmountPerKey = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void storeElement(GroupedDataEntry<Pair> element) {
|
||||
if (element.getDataEntry() != null) {
|
||||
incrementElementAmount(element);
|
||||
HashSet<Pair<Number, Number>> aggregate = individualPairs.get(element.getKey());
|
||||
Number a = ((Number) element.getDataEntry().getA());
|
||||
Number b = ((Number) element.getDataEntry().getB());
|
||||
|
||||
final Double doubleValueA = a == null ? null : a.doubleValue();
|
||||
final Double doubleValueB = b == null ? null : b.doubleValue();
|
||||
|
||||
if (doubleValueA != null && doubleValueB != null) {
|
||||
if(aggregate == null) {
|
||||
aggregate = new HashSet<>();
|
||||
aggregate.add(new Pair<>(doubleValueA, doubleValueB));
|
||||
individualPairs.put(element.getKey(), aggregate);
|
||||
}
|
||||
else {
|
||||
individualPairs.get(element.getKey()).add(new Pair<>(doubleValueA, doubleValueB));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void incrementElementAmount(GroupedDataEntry<Pair> element) {
|
||||
GroupKey key = element.getKey();
|
||||
// concurrency is not an issue here; needsSynchronization() returns true
|
||||
AtomicLong currentAmount = elementAmountPerKey.get(key);
|
||||
if (currentAmount == null) {
|
||||
elementAmountPerKey.put(key, new AtomicLong(1));
|
||||
} else {
|
||||
currentAmount.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<GroupKey, PairWithStats<Number>> aggregateResult() {
|
||||
Map<GroupKey, PairWithStats<Number>> result = new HashMap<>();
|
||||
for (Entry<GroupKey, HashSet<Pair<Number, Number>>> sumAggregationEntry : individualPairs.entrySet()) {
|
||||
GroupKey key = sumAggregationEntry.getKey();
|
||||
result.put(key, new PairWithStatsImpl<Number>(null,
|
||||
/* min */ null,
|
||||
/* max */ null,
|
||||
/* median */ null,
|
||||
/* standardDeviation */ null,
|
||||
/* individualPairs */ individualPairs.get(key),
|
||||
/* count */ elementAmountPerKey.get(key).get(),
|
||||
Pair.class.getName()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user