From 3c9801e7b042ff2fdf73d14b95ff6bc4f43617d0 Mon Sep 17 00:00:00 2001 From: Vladislav Chumak Date: Fri, 30 Mar 2018 04:17:56 +0200 Subject: [PATCH] Improved data mining of complete maneuver curves with estimation data --- .../Sailing_StringMessages.properties | 5 +- .../Sailing_StringMessages_de.properties | 4 +- .../SailingDataRetrievalChainDefinitions.java | 10 +- ...aneuverCurveWithEstimationDataContext.java | 57 ++++++- ...eWithEstimationDataRetrievalProcessor.java | 151 ++++++++++++++++++ .../ManeuverBoundariesRetrievalProcessor.java | 51 ------ ...verCurveWithEstimationDataWithContext.java | 147 +++++++++++++++-- ...mpleteManeuverCurveWithEstimationData.java | 20 +-- .../HasDetailedManeuverLoss.java | 5 - ...tableCourseAndSpeedWithEstimationData.java | 5 +- .../ManeuverMainCurveWithEstimationData.java | 10 +- .../impl/ManeuverDetectorImpl.java | 10 +- 12 files changed, 373 insertions(+), 102 deletions(-) create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompleteManeuverCurveWithEstimationDataRetrievalProcessor.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverBoundariesRetrievalProcessor.java diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties index 47927040a03..51bf157b984 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -177,8 +177,6 @@ RatioBetweenDistanceSailedWithAndWithoutManeuver=Ratio between distance sailed w RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver=Ratio between distance sailed toward middle angle projection with and without maneuver DurationLostByManeuver=Duration lost by maneuver DurationLostByManeuverTowardMiddleAngleProjection=duration lost by maneuver toward middle angle projection -CurveWithUnstableCourseAndSpeed=Curve with unstable course and speed -MainCurve=Main curve JibingCount=Jibing count TackingCount=Tacking count AbsTwaAtMaxTurningRate=Abs. TWA at max. turning rate @@ -187,4 +185,5 @@ AbsTwaAtHighestSpeed=Abs. TWA at highest speed PercentageOfMainCurveProgressUntilLowestSpeed=Percentage of main curve progress until lowest speed PercentageOfMainCurveProgressUntilHighestSpeed=Percentage of main curve progress until highest speed PercentageOfMainCurveProgressUntilMaxTurningRate=Percentage of main curve progress until max. turning rate speed -ManeuverTypeForCompleteManeuverCurve=Maneuver type for complete maneuver curve \ No newline at end of file +AbsTwaAtManeuverMiddle=Abs. TWA at maneuver middle +GpsSamplingRate=GPS sampling rate \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties index 4a32dc5f439..d95d72c25cd 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties @@ -187,4 +187,6 @@ AbsTwaAtHighestSpeed=Abs. TWA bei höchster Geschwindigkeit PercentageOfMainCurveProgressUntilLowestSpeed=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von geringster Geschwindigkeit PercentageOfMainCurveProgressUntilHighestSpeed=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von höchster Geschwindigkeit PercentageOfMainCurveProgressUntilMaxTurningRate=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von max. Drehrate -ManeuverTypeForCompleteManeuverCurve=Manövertyp für komplette Manöverkurve \ No newline at end of file +ManeuverTypeForCompleteManeuverCurve=Manövertyp für komplette Manöverkurve +AbsTwaAtManeuverMiddle=Abs. TWA während Manövermitte +GpsSamplingRate=GPS-Samplingrate \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java index f483732c7a2..df083c132e0 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java @@ -28,7 +28,7 @@ import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProce import com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor; import com.sap.sailing.datamining.impl.components.ManeuverRetrievalProcessor; import com.sap.sailing.datamining.impl.components.ManeuverSpeedDetailsRetrievalProcessor; -import com.sap.sailing.datamining.impl.components.ManeuverBoundariesRetrievalProcessor; +import com.sap.sailing.datamining.impl.components.CompleteManeuverCurveWithEstimationDataRetrievalProcessor; import com.sap.sailing.datamining.impl.components.MarkPassingRetrievalProcessor; import com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProcessor; import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorRetrievalProcessor; @@ -128,13 +128,13 @@ public class SailingDataRetrievalChainDefinitions { "ManeuverSpeedDetails"); dataRetrieverChainDefinitions.add(speedDetailsDataRetrieverChainDefinition); - DataRetrieverChainDefinition maneuverBoundariesRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>( + DataRetrieverChainDefinition completeManeuverCurveWithEstimationDataRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>( raceOfCompetitorRetrieverChainDefinition, HasCompleteManeuverCurveWithEstimationDataContext.class, "CompleteManeuverCurveWithEstimationDataRetrieverChain"); - maneuverBoundariesRetrieverChainDefinition.endWith(RaceOfCompetitorRetrievalProcessor.class, - ManeuverBoundariesRetrievalProcessor.class, HasCompleteManeuverCurveWithEstimationDataContext.class, + completeManeuverCurveWithEstimationDataRetrieverChainDefinition.endWith(RaceOfCompetitorRetrievalProcessor.class, + CompleteManeuverCurveWithEstimationDataRetrievalProcessor.class, HasCompleteManeuverCurveWithEstimationDataContext.class, ManeuverSettings.class, ManeuverSettingsImpl.createDefault(), "CompleteManeuverCurveWithEstimationData"); - dataRetrieverChainDefinitions.add(maneuverBoundariesRetrieverChainDefinition); + dataRetrieverChainDefinitions.add(completeManeuverCurveWithEstimationDataRetrieverChainDefinition); final DataRetrieverChainDefinition markPassingRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>( legOfCompetitorRetrieverChainDefinition, HasMarkPassingContext.class, "MarkPassingSailingDomainRetrieverChain"); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasCompleteManeuverCurveWithEstimationDataContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasCompleteManeuverCurveWithEstimationDataContext.java index d7807e8e076..36458df383d 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasCompleteManeuverCurveWithEstimationDataContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasCompleteManeuverCurveWithEstimationDataContext.java @@ -1,6 +1,7 @@ package com.sap.sailing.datamining.data; -import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.ManeuverType; +import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData; import com.sap.sse.datamining.annotations.Connector; import com.sap.sse.datamining.annotations.Dimension; @@ -20,6 +21,9 @@ public interface HasCompleteManeuverCurveWithEstimationDataContext { @Connector CompleteManeuverCurveWithEstimationData getCompleteManeuverCurveWithEstimationData(); + @Dimension(messageKey = "ToSide") + NauticalSide getToSide(); + @Statistic(messageKey = "ManeuverStartSpeedDeviationRatioFromAvg", ordinal = 1, resultDecimals = 4) Double getManeuverStartSpeedDeviationRatioFromAvgStatistic(); @@ -51,12 +55,57 @@ public interface HasCompleteManeuverCurveWithEstimationDataContext { ClusterDTO getTackingCount(); @Statistic(messageKey = "AbsTwaAtMaxTurningRate") - Bearing getAbsTwaAtMaxTurningRate(); + double getAbsTwaAtMaxTurningRate(); @Statistic(messageKey = "AbsTwaAtLowestSpeed") - Bearing getAbsTwaAtLowestSpeed(); + double getAbsTwaAtLowestSpeed(); @Statistic(messageKey = "AbsTwaAtHighestSpeed") - Bearing getAbsTwaAtHighestSpeed(); + double getAbsTwaAtHighestSpeed(); + + @Statistic(messageKey = "AbsTwaAtManeuverMiddle") + double getAbsTwaAtManeuverMiddle(); + + @Statistic(messageKey = "GpsSamplingRate") + double getGpsSamplingRate(); + + @Statistic(messageKey = "ManeuverEnteringAbsTWA") + Double getEnteringAbsTWA(); + + @Statistic(messageKey = "ManeuverExitingAbsTWA") + Double getExitingAbsTWA(); + + @Dimension(messageKey = "TypeOfPreviousManeuver") + ManeuverType getTypeOfPreviousManeuver(); + + @Dimension(messageKey = "TypeOfNextManeuver") + ManeuverType getTypeOfNextManeuver(); + + @Statistic(messageKey = "AbsoluteDirectionChange", resultDecimals = 2) + Double getAbsoluteDirectionChangeInDegrees(); + + @Statistic(messageKey = "RatioBetweenDistanceSailedWithAndWithoutManeuver", resultDecimals = 4) + double getRatioBetweenDistanceSailedWithAndWithoutManeuver(); + + @Statistic(messageKey = "DurationLostByManeuver", resultDecimals = 4) + double getDurationLostByManeuver(); + + @Statistic(messageKey = "DurationLostByManeuverTowardMiddleAngleProjection", resultDecimals = 4) + double getDurationLostByManeuverTowardMiddleAngleProjection(); + + @Statistic(messageKey = "RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver", resultDecimals = 4) + double getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver(); + + @Statistic(messageKey = "RelativeBearingToNextMarkBeforeManeuver", resultDecimals = 1) + Double getRelativeBearingToNextMarkBeforeManeuver(); + + @Statistic(messageKey = "RelativeBearingToNextMarkAfterManeuver", resultDecimals = 1) + Double getRelativeBearingToNextMarkAfterManeuver(); + + @Statistic(messageKey = "ManeuverEnteringSpeedInKnots", resultDecimals = 2) + Double getManeuverEnteringSpeed(); + + @Statistic(messageKey = "ManeuverExitingSpeedInKnots", resultDecimals = 2) + Double getManeuverExitingSpeed(); } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompleteManeuverCurveWithEstimationDataRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompleteManeuverCurveWithEstimationDataRetrievalProcessor.java new file mode 100644 index 00000000000..f11191a86e7 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompleteManeuverCurveWithEstimationDataRetrievalProcessor.java @@ -0,0 +1,151 @@ +package com.sap.sailing.datamining.impl.components; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutorService; + +import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext; +import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext; +import com.sap.sailing.datamining.impl.data.CompleteManeuverCurveWithEstimationDataWithContext; +import com.sap.sailing.datamining.shared.ManeuverSettings; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData; +import com.sap.sailing.domain.maneuverdetection.ManeuverDetector; +import com.sap.sailing.domain.maneuverdetection.impl.ManeuverDetectorImpl; +import com.sap.sailing.domain.tracking.CompleteManeuverCurve; +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.Duration; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor; + +/** + * + * @author Vladislav Chumak (D069712) + * + */ +public class CompleteManeuverCurveWithEstimationDataRetrievalProcessor extends + AbstractRetrievalProcessor { + + private final ManeuverSettings settings; + + public CompleteManeuverCurveWithEstimationDataRetrievalProcessor(ExecutorService executor, + Collection> resultReceivers, + ManeuverSettings settings, int retrievalLevel) { + super(HasRaceOfCompetitorContext.class, HasCompleteManeuverCurveWithEstimationDataContext.class, executor, + resultReceivers, retrievalLevel); + this.settings = settings; + } + + @Override + protected Iterable retrieveData( + HasRaceOfCompetitorContext element) { + List result = new ArrayList<>(); + TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace(); + Competitor competitor = element.getCompetitor(); + ManeuverDetector maneuverDetector = new ManeuverDetectorImpl(trackedRace, competitor); + Iterable maneuvers = trackedRace.getManeuvers(competitor, false); + Iterable maneuverCurves = maneuverDetector.getCompleteManeuverCurves(maneuvers); + Iterable maneuversWithEstimationData = maneuverDetector + .getCompleteManeuverCurvesWithEstimationData(maneuverCurves); + + CompleteManeuverCurveWithEstimationData previousManeuver = null; + CompleteManeuverCurveWithEstimationData currentManeuver = null; + for (CompleteManeuverCurveWithEstimationData nextManeuver : maneuversWithEstimationData) { + if (currentManeuver != null) { + CompleteManeuverCurveWithEstimationDataWithContext maneuverWithContext = new CompleteManeuverCurveWithEstimationDataWithContext( + element, currentManeuver, settings, previousManeuver, nextManeuver); + if (currentManeuver.getWind() != null + && isManeuverCompliantWithSettings(previousManeuver, maneuverWithContext, nextManeuver)) { + result.add(maneuverWithContext); + } + } + previousManeuver = currentManeuver; + currentManeuver = nextManeuver; + } + if (currentManeuver != null) { + CompleteManeuverCurveWithEstimationDataWithContext maneuverWithContext = new CompleteManeuverCurveWithEstimationDataWithContext( + element, currentManeuver, settings, previousManeuver, null); + if (currentManeuver.getWind() != null + && isManeuverCompliantWithSettings(previousManeuver, maneuverWithContext, null)) { + result.add(maneuverWithContext); + } + } + return result; + } + + private boolean isManeuverCompliantWithSettings(CompleteManeuverCurveWithEstimationData previousManeuver, + CompleteManeuverCurveWithEstimationDataWithContext currentManeuverWithContext, + CompleteManeuverCurveWithEstimationData nextManeuver) { + boolean mainCurveAnalysis = settings.isMainCurveAnalysis(); + // Compute only numbers which are really required for filtering + Duration maneuverDuration = settings.getMinManeuverDuration() != null + || settings.getMaxManeuverDuration() != null + ? currentManeuverWithContext.getTimePointBeforeForAnalysis() + .until(currentManeuverWithContext.getTimePointAfterForAnalysis()) + : null; + double maneuverEnteringSpeed = settings.getMinManeuverEnteringSpeedInKnots() != null + || settings.getMaxManeuverEnteringSpeedInKnots() != null + ? currentManeuverWithContext.getManeuverEnteringSpeed() : 0; + double maneuverExitingSpeed = settings.getMinManeuverExitingSpeedInKnots() != null + || settings.getMaxManeuverExitingSpeedInKnots() != null + ? currentManeuverWithContext.getManeuverExitingSpeed() : 0; + double maneuverEnteringAbsTWA = settings.getMinManeuverEnteringAbsTWA() != null + ? currentManeuverWithContext.getEnteringAbsTWA() : 0; + double maneuverExitingAbsTWA = settings.getMinManeuverExitingAbsTWA() != null + ? currentManeuverWithContext.getExitingAbsTWA() : 0; + + Duration durationToPreviousManeuver = previousManeuver != null + ? getManeuverBoundariesForAnalysis(previousManeuver, mainCurveAnalysis).getTimePointAfter() + .until(currentManeuverWithContext.getTimePointBeforeForAnalysis()) + : null; + Duration durationToNextManeuver = nextManeuver != null + ? currentManeuverWithContext.getTimePointAfterForAnalysis().until( + getManeuverBoundariesForAnalysis(nextManeuver, mainCurveAnalysis).getTimePointBefore()) + : null; + if (!(settings.getMinManeuverDuration() != null + && maneuverDuration.compareTo(settings.getMinManeuverDuration()) < 0 + || settings.getMaxManeuverDuration() != null + && maneuverDuration.compareTo(settings.getMaxManeuverDuration()) > 0 + || settings.getMinManeuverEnteringSpeedInKnots() != null + && maneuverEnteringSpeed < settings.getMinManeuverEnteringSpeedInKnots() + || settings.getMaxManeuverEnteringSpeedInKnots() != null + && maneuverEnteringSpeed > settings.getMaxManeuverEnteringSpeedInKnots() + || settings.getMinManeuverExitingSpeedInKnots() != null + && maneuverExitingSpeed < settings.getMinManeuverExitingSpeedInKnots() + || settings.getMaxManeuverExitingSpeedInKnots() != null + && maneuverExitingSpeed > settings.getMaxManeuverExitingSpeedInKnots() + || settings.getMinManeuverEnteringAbsTWA() != null + && maneuverEnteringAbsTWA < settings.getMinManeuverEnteringAbsTWA() + || settings.getMaxManeuverEnteringAbsTWA() != null + && maneuverEnteringAbsTWA > settings.getMaxManeuverEnteringAbsTWA() + || settings.getMinManeuverExitingAbsTWA() != null + && maneuverExitingAbsTWA < settings.getMinManeuverExitingAbsTWA() + || settings.getMaxManeuverExitingAbsTWA() != null + && maneuverExitingAbsTWA > settings.getMaxManeuverExitingAbsTWA() + || settings.getMinAbsCourseChangeInDegrees() != null && currentManeuverWithContext + .getAbsoluteDirectionChangeInDegrees() < settings.getMinAbsCourseChangeInDegrees() + || settings.getMaxAbsCourseChangeInDegrees() != null && currentManeuverWithContext + .getAbsoluteDirectionChangeInDegrees() > settings.getMaxAbsCourseChangeInDegrees() + || settings.getMinDurationFromPrecedingManeuver() != null && (previousManeuver == null + || durationToPreviousManeuver.compareTo(settings.getMinDurationFromPrecedingManeuver()) < 0) + || settings.getMaxDurationFromPrecedingManeuver() != null && (previousManeuver == null + || durationToPreviousManeuver.compareTo(settings.getMaxDurationFromPrecedingManeuver()) > 0) + || settings.getMinDurationToFollowingManeuver() != null && (nextManeuver == null + || durationToNextManeuver.compareTo(settings.getMinDurationToFollowingManeuver()) < 0) + || settings.getMaxDurationToFollowingManeuver() != null && (nextManeuver == null + || durationToNextManeuver.compareTo(settings.getMaxDurationToFollowingManeuver()) > 0))) { + return true; + } else { + return false; + } + } + + private ManeuverCurveBoundaries getManeuverBoundariesForAnalysis(CompleteManeuverCurveWithEstimationData maneuver, + boolean mainCurveAnalysis) { + return mainCurveAnalysis ? maneuver.getMainCurve() : maneuver.getCurveWithUnstableCourseAndSpeed(); + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverBoundariesRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverBoundariesRetrievalProcessor.java deleted file mode 100644 index 0ba2a1541c9..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverBoundariesRetrievalProcessor.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.sap.sailing.datamining.impl.components; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.ExecutorService; - -import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext; -import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext; -import com.sap.sailing.datamining.impl.data.CompleteManeuverCurveWithEstimationDataWithContext; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData; -import com.sap.sailing.domain.maneuverdetection.ManeuverDetector; -import com.sap.sailing.domain.maneuverdetection.impl.ManeuverDetectorImpl; -import com.sap.sailing.domain.tracking.CompleteManeuverCurve; -import com.sap.sailing.domain.tracking.Maneuver; -import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sse.datamining.components.Processor; -import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor; - -/** - * - * @author Vladislav Chumak (D069712) - * - */ -public class ManeuverBoundariesRetrievalProcessor - extends AbstractRetrievalProcessor { - - public ManeuverBoundariesRetrievalProcessor(ExecutorService executor, - Collection> resultReceivers, int retrievalLevel) { - super(HasRaceOfCompetitorContext.class, HasCompleteManeuverCurveWithEstimationDataContext.class, executor, resultReceivers, - retrievalLevel); - } - - @Override - protected Iterable retrieveData(HasRaceOfCompetitorContext element) { - List result = new ArrayList<>(); - TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace(); - Competitor competitor = element.getCompetitor(); - ManeuverDetector maneuverDetector = new ManeuverDetectorImpl(trackedRace, competitor); - Iterable maneuvers = trackedRace.getManeuvers(competitor, false); - Iterable maneuverCurves = maneuverDetector.getCompleteManeuverCurves(maneuvers); - Iterable maneuversWithEstimationData = maneuverDetector - .getCompleteManeuverCurvesWithEstimationData(maneuverCurves); - for (CompleteManeuverCurveWithEstimationData maneuverWithEstimationData : maneuversWithEstimationData) { - result.add(new CompleteManeuverCurveWithEstimationDataWithContext(element, maneuverWithEstimationData)); - } - return result; - } - -} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/CompleteManeuverCurveWithEstimationDataWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/CompleteManeuverCurveWithEstimationDataWithContext.java index bd0c7d47c90..6ef707e2b14 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/CompleteManeuverCurveWithEstimationDataWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/CompleteManeuverCurveWithEstimationDataWithContext.java @@ -2,11 +2,17 @@ package com.sap.sailing.datamining.impl.data; import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext; import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext; +import com.sap.sailing.datamining.shared.ManeuverSettings; import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.ManeuverType; +import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData; +import com.sap.sailing.domain.maneuverdetection.HasDetailedManeuverLoss; +import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries; import com.sap.sse.common.Duration; +import com.sap.sse.common.TimePoint; import com.sap.sse.datamining.shared.impl.dto.ClusterDTO; /** @@ -18,12 +24,20 @@ public class CompleteManeuverCurveWithEstimationDataWithContext implements HasCompleteManeuverCurveWithEstimationDataContext { private final CompleteManeuverCurveWithEstimationData maneuverWithEstimationData; - private HasRaceOfCompetitorContext raceOfCompetitorContext; + private final HasRaceOfCompetitorContext raceOfCompetitorContext; + private final ManeuverSettings maneuverSettings; + private final CompleteManeuverCurveWithEstimationData previousManeuverCurve; + private final CompleteManeuverCurveWithEstimationData nextManeuverCurve; public CompleteManeuverCurveWithEstimationDataWithContext(HasRaceOfCompetitorContext raceOfCompetitorContext, - CompleteManeuverCurveWithEstimationData maneuverWithEstimationData) { + CompleteManeuverCurveWithEstimationData maneuverWithEstimationData, ManeuverSettings maneuverSettings, + CompleteManeuverCurveWithEstimationData previousManeuverCurve, + CompleteManeuverCurveWithEstimationData nextManeuverCurve) { this.raceOfCompetitorContext = raceOfCompetitorContext; this.maneuverWithEstimationData = maneuverWithEstimationData; + this.maneuverSettings = maneuverSettings; + this.previousManeuverCurve = previousManeuverCurve; + this.nextManeuverCurve = nextManeuverCurve; } @Override @@ -33,8 +47,8 @@ public class CompleteManeuverCurveWithEstimationDataWithContext @Override public Double getManeuverStartSpeedDeviationRatioFromAvgStatistic() { - SpeedWithBearing speedWithBearingBeforeManeuver = maneuverWithEstimationData - .getCurveWithUnstableCourseAndSpeed().getSpeedWithBearingBefore(); + SpeedWithBearing speedWithBearingBeforeManeuver = getManeuverCurveBoundariesForAnalysis() + .getSpeedWithBearingBefore(); SpeedWithBearing averageSpeedWithBearingBeforeManeuver = maneuverWithEstimationData .getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingBefore(); if (speedWithBearingBeforeManeuver != null && averageSpeedWithBearingBeforeManeuver != null) { @@ -49,8 +63,8 @@ public class CompleteManeuverCurveWithEstimationDataWithContext @Override public Double getManeuverStartCogDeviationFromAvgInDegreesStatistic() { - SpeedWithBearing speedWithBearingBeforeManeuver = maneuverWithEstimationData - .getCurveWithUnstableCourseAndSpeed().getSpeedWithBearingBefore(); + SpeedWithBearing speedWithBearingBeforeManeuver = getManeuverCurveBoundariesForAnalysis() + .getSpeedWithBearingBefore(); SpeedWithBearing averageSpeedWithBearingBeforeManeuver = maneuverWithEstimationData .getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingBefore(); if (speedWithBearingBeforeManeuver != null && averageSpeedWithBearingBeforeManeuver != null) { @@ -62,7 +76,7 @@ public class CompleteManeuverCurveWithEstimationDataWithContext @Override public Double getManeuverEndSpeedDeviationRatioFromAvgStatistic() { - SpeedWithBearing speedWithBearingAfterManeuver = maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed() + SpeedWithBearing speedWithBearingAfterManeuver = getManeuverCurveBoundariesForAnalysis() .getSpeedWithBearingAfter(); SpeedWithBearing averageSpeedWithBearingAfterManeuver = maneuverWithEstimationData .getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingAfter(); @@ -140,23 +154,132 @@ public class CompleteManeuverCurveWithEstimationDataWithContext } @Override - public Bearing getAbsTwaAtMaxTurningRate() { + public double getAbsTwaAtMaxTurningRate() { return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getCourseAtMaxTurningRate()); } @Override - public Bearing getAbsTwaAtLowestSpeed() { + public double getAbsTwaAtLowestSpeed() { return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getLowestSpeed().getBearing()); } @Override - public Bearing getAbsTwaAtHighestSpeed() { + public double getAbsTwaAtHighestSpeed() { return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getHighestSpeed().getBearing()); } - private Bearing getAbsTwaFromCourse(Bearing course) { + private double getAbsTwaFromCourse(Bearing course) { double twa = maneuverWithEstimationData.getWind().getFrom().getDifferenceTo(course).getDegrees(); - return new DegreeBearingImpl(twa); + return Math.abs(twa); + } + + @Override + public NauticalSide getToSide() { + return maneuverWithEstimationData.getMainCurve().getDirectionChangeInDegrees() < 0 ? NauticalSide.PORT + : NauticalSide.STARBOARD; + } + + private ManeuverCurveBoundaries getManeuverCurveBoundariesForAnalysis() { + return maneuverSettings.isMainCurveAnalysis() ? maneuverWithEstimationData.getMainCurve() + : maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed(); + } + + @Override + public Double getEnteringAbsTWA() { + return getAbsTwaFromCourse(getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingBefore().getBearing()); + } + + @Override + public Double getExitingAbsTWA() { + return getAbsTwaFromCourse(getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingAfter().getBearing()); + } + + @Override + public ManeuverType getTypeOfPreviousManeuver() { + return previousManeuverCurve == null ? ManeuverType.UNKNOWN + : previousManeuverCurve.getManeuverTypeForCompleteManeuverCurve(); + } + + @Override + public ManeuverType getTypeOfNextManeuver() { + return nextManeuverCurve == null ? ManeuverType.UNKNOWN + : nextManeuverCurve.getManeuverTypeForCompleteManeuverCurve(); + } + + @Override + public Double getAbsoluteDirectionChangeInDegrees() { + return Math.abs(getManeuverCurveBoundariesForAnalysis().getDirectionChangeInDegrees()); + } + + @Override + public double getRatioBetweenDistanceSailedWithAndWithoutManeuver() { + return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis()) + .getRatioBetweenDistanceSailedWithAndWithoutManeuver(); + } + + @Override + public double getDurationLostByManeuver() { + return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis()).getDurationLostByManeuver() + .asSeconds(); + } + + @Override + public double getDurationLostByManeuverTowardMiddleAngleProjection() { + return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis()) + .getDurationLostByManeuverTowardMiddleAngleProjection().asSeconds(); + } + + @Override + public double getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver() { + return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis()) + .getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver(); + } + + @Override + public Double getRelativeBearingToNextMarkBeforeManeuver() { + return maneuverWithEstimationData.getRelativeBearingToNextMarkBeforeManeuver() == null ? null + : maneuverWithEstimationData.getRelativeBearingToNextMarkBeforeManeuver().getDegrees(); + } + + @Override + public Double getRelativeBearingToNextMarkAfterManeuver() { + return maneuverWithEstimationData.getRelativeBearingToNextMarkAfterManeuver() == null ? null + : maneuverWithEstimationData.getRelativeBearingToNextMarkAfterManeuver().getDegrees(); + } + + public TimePoint getTimePointBeforeForAnalysis() { + return getManeuverCurveBoundariesForAnalysis().getTimePointBefore(); + } + + public TimePoint getTimePointAfterForAnalysis() { + return getManeuverCurveBoundariesForAnalysis().getTimePointAfter(); + } + + @Override + public Double getManeuverEnteringSpeed() { + return getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingBefore().getKnots(); + } + + @Override + public Double getManeuverExitingSpeed() { + return getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingAfter().getKnots(); + } + + @Override + public double getAbsTwaAtManeuverMiddle() { + ManeuverCurveBoundaries boundariesForAnalysis = getManeuverCurveBoundariesForAnalysis(); + Bearing middleCourse = boundariesForAnalysis.getSpeedWithBearingBefore().getBearing() + .add(new DegreeBearingImpl(boundariesForAnalysis.getDirectionChangeInDegrees() / 2)); + return getAbsTwaFromCourse(middleCourse); + } + + @Override + public double getGpsSamplingRate() { + return maneuverSettings.isMainCurveAnalysis() + ? maneuverWithEstimationData.getMainCurve().getGpsFixesCount() + / maneuverWithEstimationData.getMainCurve().getDuration().asSeconds() + : maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed().getGpsFixesCount() + / maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed().getDuration().asSeconds(); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/CompleteManeuverCurveWithEstimationData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/CompleteManeuverCurveWithEstimationData.java index 20d4a464cec..0cc722ebbad 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/CompleteManeuverCurveWithEstimationData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/CompleteManeuverCurveWithEstimationData.java @@ -6,7 +6,6 @@ import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.tracking.CompleteManeuverCurve; import com.sap.sse.datamining.annotations.Connector; import com.sap.sse.datamining.annotations.Dimension; -import com.sap.sse.datamining.annotations.Statistic; /** * Contains information of a complete maneuver curve which is regarded as relevant for maneuver classification @@ -17,19 +16,19 @@ import com.sap.sse.datamining.annotations.Statistic; * */ public interface CompleteManeuverCurveWithEstimationData { - - @Dimension(messageKey = "ManeuverTypeForCompleteManeuverCurve") + + @Dimension(messageKey = "ManeuverType") default ManeuverType getManeuverTypeForCompleteManeuverCurve() { - if(getJibingCount() > 0 && getTackingCount() > 0) { + if (getJibingCount() > 0 && getTackingCount() > 0) { return ManeuverType.PENALTY_CIRCLE; } - if(getTackingCount() > 0) { + if (getTackingCount() > 0) { return ManeuverType.TACK; } - if(getJibingCount() > 0) { + if (getJibingCount() > 0) { return ManeuverType.JIBE; } - if(getWind() == null) { + if (getWind() == null) { return ManeuverType.UNKNOWN; } return isManeuverStartsByRunningAwayFromTheWind() ? ManeuverType.BEAR_AWAY : ManeuverType.HEAD_UP; @@ -39,14 +38,13 @@ public interface CompleteManeuverCurveWithEstimationData { * Gets the information of the main curve of maneuver including its boundaries, course change, and other data * relevant for maneuver classification. */ - @Connector(messageKey="MainCurve") + @Connector ManeuverMainCurveWithEstimationData getMainCurve(); /** * Gets the information of the curve with unstable course and speed of maneuver including its boundaries, course * change, and other data relevant for maneuver classification. */ - @Connector(messageKey="CurveWithUnstableCourseAndSpeed") ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData getCurveWithUnstableCourseAndSpeed(); /** @@ -82,7 +80,6 @@ public interface CompleteManeuverCurveWithEstimationData { * calculated by absolute bearing of next mark from the boat's position minus the boat's course. As the maneuver * boundaries, the boundaries of the curve with unstable course and speed are used. */ - @Statistic(messageKey="RelativeBearingToNextMarkBeforeManeuver", resultDecimals=1) Bearing getRelativeBearingToNextMarkBeforeManeuver(); /** @@ -90,9 +87,8 @@ public interface CompleteManeuverCurveWithEstimationData { * calculated by absolute bearing of next mark from the boat's position minus the boat's course. As the maneuver * boundaries, the boundaries of the curve with unstable course and speed are used. */ - @Statistic(messageKey="RelativeBearingToNextMarkAfterManeuver", resultDecimals=1) Bearing getRelativeBearingToNextMarkAfterManeuver(); - + /** * Gets whether a mark was crossed within the maneuver curve. */ diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/HasDetailedManeuverLoss.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/HasDetailedManeuverLoss.java index 4ec1a542f23..1a6e59bdb7d 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/HasDetailedManeuverLoss.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/HasDetailedManeuverLoss.java @@ -5,7 +5,6 @@ import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sse.common.Duration; import com.sap.sse.common.impl.MillisecondsDurationImpl; -import com.sap.sse.datamining.annotations.Statistic; public interface HasDetailedManeuverLoss { @@ -44,7 +43,6 @@ public interface HasDetailedManeuverLoss { * Gets the ratio between {@link #getDistanceSailedWithinManeuver()} and * {@link #getDistanceSailedIfNotManeuvering()}. */ - @Statistic(messageKey = "RatioBetweenDistanceSailedWithAndWithoutManeuver", resultDecimals=4) default double getRatioBetweenDistanceSailedWithAndWithoutManeuver() { return getDistanceSailedWithinManeuver().getMeters() / getDistanceSailedIfNotManeuvering().getMeters(); } @@ -70,7 +68,6 @@ public interface HasDetailedManeuverLoss { /** * Gets the duration lost by maneuver. */ - @Statistic(messageKey = "DurationLostByManeuver", resultDecimals=4) default Duration getDurationLostByManeuver() { return new MillisecondsDurationImpl( (long) (getDistanceLost().getMeters() / getSpeedWithBearingBefore().getMetersPerSecond() * 1000)); @@ -79,7 +76,6 @@ public interface HasDetailedManeuverLoss { /** * Gets the duration lost by maneuver toward middle angle projection. */ - @Statistic(messageKey = "DurationLostByManeuverTowardMiddleAngleProjection", resultDecimals=4) default Duration getDurationLostByManeuverTowardMiddleAngleProjection() { return new MillisecondsDurationImpl((long) (getDistanceLostTowardMiddleAngleProjection().getMeters() / getSpeedWithBearingBefore().getMetersPerSecond() * 1000)); @@ -89,7 +85,6 @@ public interface HasDetailedManeuverLoss { * Gets the ratio between {@link #getDistanceSailedWithinManeuverTowardMiddleAngleProjection()} and * {@link #getDistanceSailedTowardMiddleAngleProjectionIfNotManeuvering()} */ - @Statistic(messageKey = "RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver", resultDecimals=4) default double getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver() { return getDistanceSailedWithinManeuverTowardMiddleAngleProjection().getMeters() / getDistanceSailedTowardMiddleAngleProjectionIfNotManeuvering().getMeters(); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData.java index 2050b9efcf9..b7e6cf3028c 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData.java @@ -11,7 +11,8 @@ import com.sap.sse.common.Duration; * @author Vladislav Chumak (D069712) * */ -public interface ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData extends ManeuverCurveBoundaries, HasDetailedManeuverLoss { +public interface ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData + extends ManeuverCurveBoundaries, HasDetailedManeuverLoss { /** * Gets the average speed and course measured from the end of the previous maneuver until the start of this @@ -46,7 +47,7 @@ public interface ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData exten * distance of at least one second, the result will be {@null}. */ Duration getDurationFromManeuverEndToNextManeuverStart(); - + /** * Gets the number of GPS-fixes contained within the maneuver curve. */ diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/ManeuverMainCurveWithEstimationData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/ManeuverMainCurveWithEstimationData.java index dd17307f14b..d65b57a8a8a 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/ManeuverMainCurveWithEstimationData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/ManeuverMainCurveWithEstimationData.java @@ -25,7 +25,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda * Gets the time point at which the lowest speed was recorded within the main curve. */ TimePoint getLowestSpeedTimePoint(); - + @Statistic(messageKey = "PercentageOfMainCurveProgressUntilLowestSpeed", resultDecimals = 4) default double getPercentageOfMainCurveProgressUntilLowestSpeed() { return getTimePointBefore().until(getLowestSpeedTimePoint()).asSeconds() / getDuration().asSeconds(); @@ -40,7 +40,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda * Gets the time point at which the highest speed was recorded within the main curve. */ TimePoint getHighestSpeedTimePoint(); - + @Statistic(messageKey = "PercentageOfMainCurveProgressUntilHighestSpeed", resultDecimals = 4) default double getPercentageOfMainCurveProgressUntilHighestSpeed() { return getTimePointBefore().until(getHighestSpeedTimePoint()).asSeconds() / getDuration().asSeconds(); @@ -50,7 +50,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda * Gets the time point at which the maximal turning rate was recorded within the main curve. */ TimePoint getTimePointOfMaxTurningRate(); - + @Statistic(messageKey = "PercentageOfMainCurveProgressUntilMaxTurningRate", resultDecimals = 4) default double getPercentageOfMainCurveProgressUntilMaxTurningRate() { return getTimePointBefore().until(getTimePointOfMaxTurningRate()).asSeconds() / getDuration().asSeconds(); @@ -61,7 +61,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda */ @Statistic(messageKey = "MaxTurningRateInDegreesPerSecond", resultDecimals = 4) double getMaxTurningRateInDegreesPerSecond(); - + /** * Gets the average turning rate recorded within the maneuver main curve. It is calculated by absolute course change * within main curve divided by maneuver main curve duration. @@ -73,7 +73,7 @@ public interface ManeuverMainCurveWithEstimationData extends ManeuverCurveBounda * Gets the course at which the maximal turning rate was measured within the main curve. */ Bearing getCourseAtMaxTurningRate(); - + /** * Gets the number of GPS-fixes contained within the maneuver main curve. */ diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java index 6c512930dad..c41f43a504e 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java @@ -253,10 +253,11 @@ public class ManeuverDetectorImpl implements ManeuverDetector { private CompleteManeuverCurveWithEstimationData calculateCompleteManeuverCurveWithEstimationData( CompleteManeuverCurve maneuverCurve, CompleteManeuverCurve previousManeuverCurve, CompleteManeuverCurve nextManeuverCurve) { - Bearing courseAtMaxTurningRate = track.getEstimatedSpeed(maneuverCurve.getMainCurveBoundaries().getTimePoint()) - .getBearing(); + Bearing courseAtMaxTurningRate = null; SpeedWithBearingStep stepWithLowestSpeed = null; SpeedWithBearingStep stepWithHighestSpeed = null; + SpeedWithBearingStep stepWithMaxTurningRate = null; + SpeedWithBearingStep previousStep = null; for (SpeedWithBearingStep step : maneuverCurve.getMainCurveBoundaries().getSpeedWithBearingSteps()) { if (stepWithLowestSpeed == null || stepWithLowestSpeed.getSpeedWithBearing().compareTo(step.getSpeedWithBearing()) > 0) { @@ -266,6 +267,11 @@ public class ManeuverDetectorImpl implements ManeuverDetector { || stepWithHighestSpeed.getSpeedWithBearing().compareTo(step.getSpeedWithBearing()) < 0) { stepWithHighestSpeed = step; } + if(previousStep != null && (stepWithMaxTurningRate == null || stepWithMaxTurningRate.getAngularVelocityInDegreesPerSecond() < step.getAngularVelocityInDegreesPerSecond())) { + stepWithMaxTurningRate = step; + courseAtMaxTurningRate = previousStep.getSpeedWithBearing().getBearing().add(new DegreeBearingImpl(step.getCourseChangeInDegrees() / 2)); + } + previousStep = step; } int gpsFixCountWithinMainCurve = 0; int gpsFixCountWithinWholeCurve = 0;