mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-24 14:38:45 +00:00
bug5396: added COG column; drive-by fix: show course middle line (Rhumb line) also pre-start
This commit is contained in:
@@ -372,6 +372,7 @@ public enum DetailType implements Serializable {
|
||||
allowed.add(RACE_IMPLIED_WIND);
|
||||
allowed.add(RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD);
|
||||
allowed.add(RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
|
||||
allowed.add(RACE_CURRENT_COURSE_OVER_GROUND_IN_TRUE_DEGREES);
|
||||
allowed.add(RACE_CURRENT_DISTANCE_FOILED_IN_METERS);
|
||||
allowed.add(RACE_CURRENT_DURATION_FOILED_IN_SECONDS);
|
||||
allowed.add(RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS);
|
||||
|
||||
+11
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sse.common.Bearing;
|
||||
@@ -141,6 +142,8 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
* farthest ahead for all subsequent legs.
|
||||
*/
|
||||
public Duration calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead;
|
||||
|
||||
public SpeedWithBearing currentSpeedAndCourseOverGround;
|
||||
|
||||
/**
|
||||
* If <code>null</code>, no leg details are known yet, the race is not being tracked or the details
|
||||
@@ -618,6 +621,8 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
result = prime * result + ((calculatedTime == null) ? 0 : calculatedTime.hashCode());
|
||||
result = prime * result + ((calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) ? 0
|
||||
: calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.hashCode());
|
||||
result = prime * result + ((currentSpeedAndCourseOverGround == null) ? 0
|
||||
: currentSpeedAndCourseOverGround.hashCode());
|
||||
result = prime * result + (discarded ? 1231 : 1237);
|
||||
result = prime * result + ((distanceToStarboardSideOfStartLineInMeters == null) ? 0
|
||||
: distanceToStarboardSideOfStartLineInMeters.hashCode());
|
||||
@@ -703,6 +708,12 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
} else if (!calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead
|
||||
.equals(other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead))
|
||||
return false;
|
||||
if (currentSpeedAndCourseOverGround == null) {
|
||||
if (other.currentSpeedAndCourseOverGround != null)
|
||||
return false;
|
||||
} else if (!currentSpeedAndCourseOverGround
|
||||
.equals(other.currentSpeedAndCourseOverGround))
|
||||
return false;
|
||||
if (discarded != other.discarded)
|
||||
return false;
|
||||
if (distanceToStarboardSideOfStartLineInMeters == null) {
|
||||
|
||||
+1
@@ -689,6 +689,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
|
||||
Date timePointOfLastPositionFixAtOrBeforeQueryTimePoint = getTimePointOfLastFixAtOrBefore(competitor, trackedRace, timePoint);
|
||||
if (track != null) {
|
||||
entryDTO.averageSamplingInterval = track.getAverageIntervalBetweenRawFixes();
|
||||
entryDTO.currentSpeedAndCourseOverGround = track.getEstimatedSpeed(timePoint);
|
||||
}
|
||||
if (timePointOfLastPositionFixAtOrBeforeQueryTimePoint != null) {
|
||||
long timeDifferenceInMs = timePoint.asMillis() - timePointOfLastPositionFixAtOrBeforeQueryTimePoint.getTime();
|
||||
|
||||
+4
@@ -14,6 +14,10 @@
|
||||
of tracks and course broke. This has been fixed now.</li>
|
||||
<li>For better visibility especially with satellite view enabled, rhumb line display now uses a bright
|
||||
green color.</li>
|
||||
<li>Added an optional COG (Course over Ground) column to the leaderboard which shows all competitors'
|
||||
COG in true degrees.</li>
|
||||
<li>The rhumb line ("course middle line") for the first leg is now already displayed prior to the
|
||||
start time point.</li>
|
||||
</ul>
|
||||
<h5 class="articleSubheadline">September 2020</h5>
|
||||
<ul class="bulletList">
|
||||
|
||||
+5
-4
@@ -170,7 +170,7 @@ import com.sap.sse.gwt.shared.DebugConstants;
|
||||
public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> implements TimeListener, CompetitorSelectionChangeListener,
|
||||
RaceTimesInfoProviderListener, TailFactory, ColorMapperChangedListener, RequiresDataInitialization, RequiresResize, QuickFlagDataValuesProvider {
|
||||
/* Line colors */
|
||||
static private final RGBColor COURSE_MIDDLE_LINE_COLOR = new RGBColor("#0eed1d");
|
||||
static private final RGBColor COURSE_MIDDLE_LINE_COLOR = new RGBColor("#0eed1d"); // selected by Larry Rosenfeld...
|
||||
static final Color ADVANTAGE_LINE_COLOR = new RGBColor("#ff9900"); // orange
|
||||
static final Color START_LINE_COLOR = Color.WHITE;
|
||||
static final Color FINISH_LINE_COLOR = Color.BLACK;
|
||||
@@ -1994,8 +1994,9 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
|
||||
boolean showCourseMiddleLine = keysAlreadyHandled.containsKey(key) && keysAlreadyHandled.get(key).getA() ||
|
||||
settings.getHelpLinesSettings().isVisible(HelpLineTypes.COURSEGEOMETRY) ||
|
||||
(settings.getHelpLinesSettings().isVisible(HelpLineTypes.COURSEMIDDLELINE)
|
||||
&& courseDTO.currentLegNumber > 0
|
||||
&& courseDTO.currentLegNumber-1 == zeroBasedIndexOfStartWaypoint);
|
||||
// show the line for the current leg or for the first leg if we are still before the start
|
||||
&& (courseDTO.currentLegNumber-1 == zeroBasedIndexOfStartWaypoint) ||
|
||||
courseDTO.currentLegNumber == 0 && zeroBasedIndexOfStartWaypoint == 0);
|
||||
keysAlreadyHandled.put(key, new Pair<>(showCourseMiddleLine, zeroBasedIndexOfStartWaypoint));
|
||||
}
|
||||
Set<Set<ControlPointDTO>> keysToConsider = new HashSet<>(keysAlreadyHandled.keySet());
|
||||
@@ -2069,7 +2070,7 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
|
||||
}
|
||||
};
|
||||
return showOrRemoveOrUpdateLine(lineToShowOrRemoveOrUpdate, showLine, position1DTO, position2DTO,
|
||||
lineInfoProvider, COURSE_MIDDLE_LINE_COLOR.getAsHtml() /* selected by Larry Rosenfeld... */, STANDARD_LINE_STROKEWEIGHT, STANDARD_LINE_OPACITY);
|
||||
lineInfoProvider, COURSE_MIDDLE_LINE_COLOR.getAsHtml(), STANDARD_LINE_STROKEWEIGHT, STANDARD_LINE_OPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+42
-12
@@ -1203,6 +1203,10 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
|
||||
new FormattedDoubleLeaderboardRowDTODetailTypeColumn(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS,
|
||||
new RaceCurrentSpeedOverGroundInKnots(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE,
|
||||
LeaderboardPanel.this));
|
||||
result.put(DetailType.RACE_CURRENT_COURSE_OVER_GROUND_IN_TRUE_DEGREES,
|
||||
new FormattedDoubleLeaderboardRowDTODetailTypeColumn(DetailType.RACE_CURRENT_COURSE_OVER_GROUND_IN_TRUE_DEGREES,
|
||||
new RaceCurrentCourseOverGroundInTrueDegrees(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE,
|
||||
LeaderboardPanel.this));
|
||||
result.put(DetailType.BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS,
|
||||
new RideHeightColumn(DetailType.BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS,
|
||||
new RaceCurrentRideHeightInMeters(), LEG_COLUMN_HEADER_STYLE, LEG_COLUMN_STYLE,
|
||||
@@ -1580,6 +1584,44 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the average absolute (distance always counted as positive, no matter whether left or right)
|
||||
* cross-track error for the race
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*/
|
||||
private class RaceCurrentSpeedOverGroundInKnots implements DataExtractor<Double, LeaderboardRowDTO> {
|
||||
@Override
|
||||
public Double get(LeaderboardRowDTO row) {
|
||||
Double result = null;
|
||||
LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName());
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.currentSpeedAndCourseOverGround == null ? null :
|
||||
fieldsForRace.currentSpeedAndCourseOverGround.getKnots();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the average absolute (distance always counted as positive, no matter whether left or right)
|
||||
* cross-track error for the race
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*/
|
||||
private class RaceCurrentCourseOverGroundInTrueDegrees implements DataExtractor<Double, LeaderboardRowDTO> {
|
||||
@Override
|
||||
public Double get(LeaderboardRowDTO row) {
|
||||
Double result = null;
|
||||
LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName());
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.currentSpeedAndCourseOverGround == null ? null :
|
||||
fieldsForRace.currentSpeedAndCourseOverGround.getBearing().getDegrees();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the average absolute (distance always counted as positive, no matter whether left or right)
|
||||
* cross-track error for the race
|
||||
@@ -1912,18 +1954,6 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
|
||||
}
|
||||
}
|
||||
|
||||
private class RaceCurrentSpeedOverGroundInKnots extends AbstractLastLegDetailField<Double> {
|
||||
@Override
|
||||
protected Double getBeforeLastLegFinished(LegEntryDTO currentLegDetail) {
|
||||
return currentLegDetail.currentSpeedOverGroundInKnots;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Double getAfterLastLegFinished(LeaderboardRowDTO row) {
|
||||
return new RaceAverageSpeedInKnots().get(row);
|
||||
}
|
||||
}
|
||||
|
||||
private class RaceCurrentRideHeightInMeters extends AbstractLastLegDetailField<Double> {
|
||||
@Override
|
||||
protected Double getBeforeLastLegFinished(LegEntryDTO currentLegDetail) {
|
||||
|
||||
+5
@@ -14,6 +14,11 @@ public class CoursePositionsDTO implements IsSerializable {
|
||||
public Set<MarkDTO> marks;
|
||||
|
||||
public int totalLegsCount;
|
||||
|
||||
/**
|
||||
* The leg number is 0 before the start, the number of the current leg during the race
|
||||
* and the number of the last leg at the end of the race even if the race has finished.
|
||||
*/
|
||||
public int currentLegNumber;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ public enum DetailCheckboxInfo {
|
||||
REGATTA_RANK(DetailType.REGATTA_RANK, "Regatta Rank"), TOTAL_DISTANCE(DetailType.OVERALL_TOTAL_DISTANCE_TRAVELED , "Total distance"), TOTAL_AVERAGE_SPEED_OVER_GROUND(DetailType.OVERALL_TOTAL_AVERAGE_SPEED_OVER_GROUND, "∅ SOG"), TOTAL_TIME(DetailType.OVERALL_TOTAL_TIME_SAILED_IN_SECONDS, "Total time"), MAXIMUM_SPEED_OVER_GROUND(DetailType.OVERALL_MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS, "Max SOG"), TIME_ON_TIME_FACTOR(DetailType.OVERALL_TIME_ON_TIME_FACTOR, "ToT Factor"), TIME_ON_DISTANCE_ALLOWANCE(DetailType.OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE, "ToD Allowance"),
|
||||
|
||||
// Race details
|
||||
RACE_GAP_TO_LEADER(DetailType.RACE_GAP_TO_LEADER_IN_SECONDS, "Gap to leader"), RACE_AVERAGE_SPEED_OVER_GROUND(DetailType.RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS, "∅ Speed"), RACE_DISTANCE(DetailType.RACE_DISTANCE_TRAVELED, "Distance"), RACE_DISTANCE_INCLUDING_GATE_START(DetailType.RACE_DISTANCE_TRAVELED_INCLUDING_GATE_START, "Distance (w/ Gate Start)"), RACE_TIME(DetailType.RACE_TIME_TRAVELED, "Time"), RACE_CURRENT_SPEED_OVER_GROUND(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, "SOG"), RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD(DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS, "Gap"), NUMBER_OF_MANEUVERS(DetailType.NUMBER_OF_MANEUVERS, "Maneuvers"), DISPLAY_LEGS(DetailType.RACE_DISPLAY_LEGS, "Legs"), CURRENT_LEG(DetailType.RACE_CURRENT_LEG, "On Leg"), RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR(DetailType.RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS, "∅ XTE"), RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR(DetailType.RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS, "∅ XTE +/-"), RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL(DetailType.RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL, "GPS Lag"),
|
||||
RACE_GAP_TO_LEADER(DetailType.RACE_GAP_TO_LEADER_IN_SECONDS, "Gap to leader"), RACE_AVERAGE_SPEED_OVER_GROUND(DetailType.RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS, "∅ Speed"), RACE_DISTANCE(DetailType.RACE_DISTANCE_TRAVELED, "Distance"), RACE_DISTANCE_INCLUDING_GATE_START(DetailType.RACE_DISTANCE_TRAVELED_INCLUDING_GATE_START, "Distance (w/ Gate Start)"), RACE_TIME(DetailType.RACE_TIME_TRAVELED, "Time"), RACE_CURRENT_SPEED_OVER_GROUND(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, "SOG"), RACE_CURRENT_COURSE_OVER_GROUND(DetailType.RACE_CURRENT_COURSE_OVER_GROUND_IN_TRUE_DEGREES, "COG"), RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD(DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS, "Gap"), NUMBER_OF_MANEUVERS(DetailType.NUMBER_OF_MANEUVERS, "Maneuvers"), DISPLAY_LEGS(DetailType.RACE_DISPLAY_LEGS, "Legs"), CURRENT_LEG(DetailType.RACE_CURRENT_LEG, "On Leg"), RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR(DetailType.RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS, "∅ XTE"), RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR(DetailType.RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS, "∅ XTE +/-"), RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL(DetailType.RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL, "GPS Lag"),
|
||||
|
||||
// Race Start Analysis
|
||||
RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_START(DetailType.RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START, "Distance to line 5s before start"), RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START(DetailType.RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START, "SOG 5s before start"), DISTANCE_TO_START_AT_RACE_START(DetailType.DISTANCE_TO_START_AT_RACE_START, "Distance to line at Start"), TIME_BETWEEN_RACE_START_AND_COMPETITOR_START(DetailType.TIME_BETWEEN_RACE_START_AND_COMPETITOR_START, "Start delay"), SPEED_OVER_GROUND_AT_RACE_START(DetailType.SPEED_OVER_GROUND_AT_RACE_START, "SOG at Start"), SPEED_OVER_GROUND_WHEN_STARTING(DetailType.SPEED_OVER_GROUND_WHEN_PASSING_START, "SOG when Starting"), DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_STARTING(DetailType.DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS, "Dist. Stb-Side of Line when Starting"), START_TACK(DetailType.START_TACK, "Start Tack"),
|
||||
|
||||
Reference in New Issue
Block a user