From 6cff2f2aa38d12eef2cfe20a5cfe1c28f8fb7136 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sun, 1 Mar 2020 12:19:36 +0100 Subject: [PATCH] offer implied wind also in charts and LeaderboardsResourceV2 --- .../sap/sailing/domain/common/DetailType.java | 1 + .../orc/ORCPerformanceCurveRankingMetric.java | 23 +++++++++++++ ...rmanceCurveByImpliedWindRankingMetric.java | 4 ++- .../META-INF/MANIFEST.MF | 3 +- .../gwt/ui/server/SailingServiceImpl.java | 32 ++++++++++++++++++- .../jaxrs/api/LeaderboardsResourceV2.java | 7 ++++ 6 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCPerformanceCurveRankingMetric.java diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java index 532e6b819ec..50f4af8a662 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java @@ -263,6 +263,7 @@ public enum DetailType implements Serializable { availableDetailsTypes.add(DetailType.LEG_GAP_TO_LEADER_IN_SECONDS); availableDetailsTypes.add(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS); availableDetailsTypes.add(DetailType.RACE_RANK); + availableDetailsTypes.add(DetailType.RACE_IMPLIED_WIND); availableDetailsTypes.add(DetailType.REGATTA_RANK); availableDetailsTypes.add(DetailType.CHART_DISTANCE_TO_START_LINE); availableDetailsTypes.add(DetailType.CHART_BEAT_ANGLE); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCPerformanceCurveRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCPerformanceCurveRankingMetric.java new file mode 100644 index 00000000000..798dfca8bd2 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCPerformanceCurveRankingMetric.java @@ -0,0 +1,23 @@ +package com.sap.sailing.domain.orc; + +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.MaxIterationsExceededException; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.ranking.RankingMetric; +import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingAndORCPerformanceCurveCache; +import com.sap.sse.common.Speed; +import com.sap.sse.common.TimePoint; + +/** + * Marker interface for all ORC Performance Curve Scoring (PCS) ranking + * metrics ({@link RankingMetric}). + * + * @author Axel Uhl (D043530) + * + */ +public interface ORCPerformanceCurveRankingMetric { + Speed getImpliedWind(Competitor competitor, TimePoint timePoint, + WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) + throws FunctionEvaluationException, MaxIterationsExceededException; +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveByImpliedWindRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveByImpliedWindRankingMetric.java index 696df23a59f..17ec95f091a 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveByImpliedWindRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCPerformanceCurveByImpliedWindRankingMetric.java @@ -76,7 +76,8 @@ import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.common.impl.MillisecondsDurationImpl; -public class ORCPerformanceCurveByImpliedWindRankingMetric extends AbstractRankingMetric { +public class ORCPerformanceCurveByImpliedWindRankingMetric extends AbstractRankingMetric +implements com.sap.sailing.domain.orc.ORCPerformanceCurveRankingMetric { private static final long serialVersionUID = -7814822523533929816L; private static final Logger logger = Logger.getLogger(ORCPerformanceCurveByImpliedWindRankingMetric.class.getName()); @@ -492,6 +493,7 @@ public class ORCPerformanceCurveByImpliedWindRankingMetric extends AbstractRanki return performanceCurveForPartialCourse; } + @Override public Speed getImpliedWind(Competitor competitor, TimePoint timePoint, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) throws FunctionEvaluationException, MaxIterationsExceededException { final Speed result; final ORCPerformanceCurve performanceCurveForPartialCourse = cache.getPerformanceCurveForPartialCourse(timePoint, getTrackedRace(), competitor, getPerformanceCurveSupplier(cache)); diff --git a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF index 76a2b51c84c..dcf12e25167 100644 --- a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF @@ -61,7 +61,8 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sse.datamining.ui, org.mongodb.mongo-java-driver;bundle-version="3.6.4", com.sap.sailing.server.gateway.serialization.shared.android, - com.sap.sailing.shared.server + com.sap.sailing.shared.server, + org.apache.commons.math;bundle-version="2.1.0" Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator Bundle-ActivationPolicy: lazy Import-Package: javax.servlet;version="3.1.0", diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 4475ea8f6b4..ff0efd21c50 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -65,6 +65,8 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.MaxIterationsExceededException; import org.apache.http.client.ClientProtocolException; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.AuthorizationException; @@ -364,6 +366,7 @@ import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuse import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater; import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; import com.sap.sailing.domain.leaderboard.meta.MetaLeaderboardColumn; +import com.sap.sailing.domain.orc.ORCPerformanceCurveRankingMetric; import com.sap.sailing.domain.orc.ORCPublicCertificateDatabase; import com.sap.sailing.domain.orc.ORCPublicCertificateDatabase.CertificateHandle; import com.sap.sailing.domain.persistence.DomainObjectFactory; @@ -382,6 +385,7 @@ import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory; import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl; import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl; +import com.sap.sailing.domain.ranking.RankingMetric; import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.regattalike.HasRegattaLike; import com.sap.sailing.domain.regattalike.IsRegattaLike; @@ -3524,7 +3528,8 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet } private Double getCompetitorRaceDataEntry(DetailType dataType, TrackedRace trackedRace, Competitor competitor, - TimePoint timePoint, String leaderboardGroupName, String leaderboardName, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) throws NoWindException { + TimePoint timePoint, String leaderboardGroupName, String leaderboardName, + WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) throws NoWindException { Double result = null; Course course = trackedRace.getRace().getCourse(); course.lockForRead(); // make sure the tracked leg survives this call even if a course update is pending @@ -3596,6 +3601,20 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet result = (distanceToLeader == null) ? null : distanceToLeader.getMeters(); } break; + case RACE_IMPLIED_WIND: + final RankingMetric rankingMetric = trackedRace.getRankingMetric(); + if (rankingMetric instanceof ORCPerformanceCurveRankingMetric) { + final ORCPerformanceCurveRankingMetric orcPcsRankingMetric = + (ORCPerformanceCurveRankingMetric) rankingMetric; + try { + final Speed impliedWind = orcPcsRankingMetric.getImpliedWind(competitor, timePoint, cache); + result = impliedWind.getKnots(); + } catch (MaxIterationsExceededException | FunctionEvaluationException e) { + logger.log(Level.WARNING, "Problem computing implied wind", e); + result = null; + } + } + break; case RACE_RANK: if (trackedLeg != null) { result = (double) trackedLeg.getRank(timePoint, cache); @@ -8329,6 +8348,17 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet availableDetailsTypes.addAll(DetailType.getRaceExtendedBravoDetailTypes()); availableDetailsTypes.addAll(DetailType.getRaceExpeditionDetailTypes()); } + final RankingMetrics rankingMetricType = trackedRace.getRankingMetric().getType(); + switch (rankingMetricType) { + case ONE_DESIGN: + case TIME_ON_TIME_AND_DISTANCE: + break; + case ORC_PERFORMANCE_CURVE: + case ORC_PERFORMANCE_CURVE_BY_IMPLIED_WIND: + case ORC_PERFORMANCE_CURVE_LEADER_FOR_BASELINE: + availableDetailsTypes.addAll(DetailType.getAllOrcPerformanceCurveDetailTypes()); + break; + } } if (leaderboardGroupName != null) { final LeaderboardGroupDTO group = getLeaderboardGroupByName(leaderboardGroupName, false); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResourceV2.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResourceV2.java index 3ca2d629be4..fd52179d2f6 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResourceV2.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResourceV2.java @@ -305,6 +305,7 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource { DetailType.RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS, DetailType.RACE_DISTANCE_TRAVELED, DetailType.RACE_TIME_TRAVELED, + DetailType.RACE_IMPLIED_WIND, DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, DetailType.RACE_CURRENT_COURSE_OVER_GROUND_IN_TRUE_DEGREES, DetailType.RACE_CURRENT_POSITION_LAT_DEG, @@ -362,6 +363,12 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource { value = timeTraveled.asSeconds(); } break; + case RACE_IMPLIED_WIND: + name = "impliedWind-kts"; + if (entry.impliedWind != null) { + value = entry.impliedWind.getKnots(); + } + break; case RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS: name = "currentSpeedOverGround-kts"; if (currentLegEntry != null && currentLegEntry.currentSpeedOverGroundInKnots != null) {