mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-19 10:39:59 +00:00
Merge branch 'master' into bug4350
This commit is contained in:
commit
6b279c7910
1539 files changed
+9530
-5650
No files matched your search
@@ -1,4 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
entryPointModules=
|
||||
filesCopiedToWebInfLib=
|
||||
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDIwMjRtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmRhc2hib2FyZHMuZ3d0LlJpYkRhc2hib2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+
|
||||
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0UgLVhmcmFnbWVudENvdW50IDRdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDIwMjRtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmRhc2hib2FyZHMuZ3d0LlJpYkRhc2hib2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+
|
||||
@@ -28,6 +28,15 @@
|
||||
<url-pattern>/service/sailing</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<filter>
|
||||
<filter-name>LocaleInjectionFilter</filter-name>
|
||||
<filter-class>com.sap.sse.security.ui.server.LocaleInjectionFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>LocaleInjectionFilter</filter-name>
|
||||
<url-pattern>*.html</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<servlet>
|
||||
<display-name>Dashboard Dispatch Service</display-name>
|
||||
<servlet-name>dashboardDispatch</servlet-name>
|
||||
|
||||
@@ -23,12 +23,6 @@
|
||||
<version>1.0.0.GA</version>
|
||||
<classifier>sources</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.gwtbootstrap</groupId>
|
||||
<artifactId>gwt-bootstrap</artifactId>
|
||||
<version>2.3.2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- This dependency is required because the GWT Maven Plugin searches
|
||||
other GWT modules only in Maven dependencies -->
|
||||
|
||||
+2
-2
@@ -56,7 +56,7 @@ public class BravoFixTrackWithContext implements HasBravoFixTrackContext {
|
||||
end = endOfRace;
|
||||
}
|
||||
return bravoFixTrack.getDistanceSpentFoiling(
|
||||
getRaceOfCompetitorContext().getTrackedRaceContext().getTrackedRace().getTrack(getRaceOfCompetitorContext().getCompetitor()),
|
||||
startOfRace, end);
|
||||
startOfRace,
|
||||
end);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -96,7 +96,7 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
|
||||
public Distance getDistanceSpentFoiling() {
|
||||
return getSomethingForLegTrackingInterval((start, end) -> {
|
||||
BravoFixTrack<Competitor> bravoFixTrack = getTrackedLegContext().getTrackedLeg().getTrackedRace().getSensorTrack(getCompetitor(), BravoFixTrack.TRACK_NAME);
|
||||
return bravoFixTrack == null ? Distance.NULL : bravoFixTrack.getDistanceSpentFoiling(getTrackedLegContext().getTrackedLeg().getTrackedRace().getTrack(getCompetitor()), start, end);
|
||||
return bravoFixTrack == null ? Distance.NULL : bravoFixTrack.getDistanceSpentFoiling(start, end);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -8,6 +8,8 @@ import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
@@ -30,6 +32,7 @@ import com.sap.sse.common.TimePoint;
|
||||
*
|
||||
*/
|
||||
public class NOAAImporter {
|
||||
private static final Logger logger = Logger.getLogger(NOAAImporter.class.getName());
|
||||
private static final String QUERY_URL = "https://www.ngdc.noaa.gov/geomag-web/calculators/calculateDeclination";
|
||||
private static final String REGEXP_DECLINATION = "<p class=\"indent\"><b>Declination</b> = ([0-9]*)° ([0-9]*)' *([EW])";
|
||||
private static final String REGEXP_ANNUAL_CHANGE = "changing by *([0-9]*)° *([0-9]*)' ([EW])/year *</p>";
|
||||
@@ -102,7 +105,7 @@ public class NOAAImporter {
|
||||
result.notifyAll();
|
||||
}
|
||||
} catch (IOException | ParserConfigurationException | SAXException e) {
|
||||
throw new RuntimeException(e);
|
||||
logger.log(Level.FINE, "Exception while trying to load magnetic declination online", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.sap.sailing.domain.bravoadapter</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
pluginProject.extensions=false
|
||||
resolve.requirebundle=false
|
||||
@@ -0,0 +1,14 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Bravoadapter
|
||||
Bundle-SymbolicName: com.sap.sailing.domain.bravoadapter
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package: org.osgi.framework;version="1.8.0"
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.server.trackfiles,
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sse.common,
|
||||
com.sap.sailing.server.gateway
|
||||
Bundle-Activator: com.sap.sailing.domain.bravoadapter.impl.Activator
|
||||
@@ -0,0 +1,4 @@
|
||||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.domain.bravoadapter</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
java/com.sap.sailing.domain.bravoadapter/src/com/sap/sailing/domain/bravoadapter/impl/Activator.java
Executable
+17
@@ -0,0 +1,17 @@
|
||||
package com.sap.sailing.domain.bravoadapter.impl;
|
||||
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import com.sap.sailing.server.trackfiles.common.GPSFixImporterRegistration;
|
||||
|
||||
public class Activator implements BundleActivator {
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
GPSFixImporterRegistration.register(new BravoGPSFixImporter(), context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.sap.sailing.domain.bravoadapter.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoExtendedSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||
import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
|
||||
import com.sap.sailing.domain.trackimport.GPSFixImporter;
|
||||
import com.sap.sailing.server.gateway.windimport.bravo.FunnyDegreeConverter;
|
||||
import com.sap.sailing.server.trackfiles.impl.BravoExtendedDataImporterImpl;
|
||||
|
||||
public class BravoGPSFixImporter implements GPSFixImporter {
|
||||
@Override
|
||||
public void importFixes(InputStream inputStream, Callback callback, boolean inferSpeedAndBearing, final String filename)
|
||||
throws FormatNotSupportedException, IOException {
|
||||
TrackFileImportDeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(filename, getType() + "@" + new Date());
|
||||
new BravoExtendedDataImporterImpl().importFixes(inputStream,
|
||||
(Iterable<DoubleVectorFix> fixes, TrackFileImportDeviceIdentifier deviceIdentifier)->{
|
||||
for (final DoubleVectorFix fix : fixes) {
|
||||
GPSFixMoving gpsFix = new GPSFixMovingImpl(
|
||||
new DegreePosition(FunnyDegreeConverter.funnyLatLng(fix.get(BravoExtendedSensorDataMetadata.LAT.getColumnIndex())),
|
||||
FunnyDegreeConverter.funnyLatLng(fix.get(BravoExtendedSensorDataMetadata.LON.getColumnIndex()))),
|
||||
fix.getTimePoint(),
|
||||
new KnotSpeedWithBearingImpl(fix.get(BravoExtendedSensorDataMetadata.SOG.getColumnIndex()),
|
||||
new DegreeBearingImpl(fix.get(BravoExtendedSensorDataMetadata.COG.getColumnIndex()))));
|
||||
callback.addFix(gpsFix, device);
|
||||
}
|
||||
}, filename, /* sourceName */ getType(), /* downsample */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> getSupportedFileExtensions() {
|
||||
return Arrays.asList(new String[] { "csv", "log", "txt" });
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "Bravo";
|
||||
}
|
||||
}
|
||||
+1
@@ -112,6 +112,7 @@ public enum BoatClassMasterdata {
|
||||
TORNADO ("Tornado Catamaran", true, 6.10, 3.02, BoatHullType.CATAMARAN, true, "Tornado", "Tornado Cat"),
|
||||
TOM_28_MAX ("Tom 28 MAX", true, 8.48, 2.48, BoatHullType.MONOHULL, true, "Tom 28"),
|
||||
TRIAS ("Trias", true, 9.20, 2.12, BoatHullType.MONOHULL, true),
|
||||
TP52 ("TP52", true, 15.85, 4.35, BoatHullType.MONOHULL, true, "TP 52", "Transpac 52", "Transpac52"),
|
||||
VIPER_640 ("Viper 640", true, 6.43, 2.49, BoatHullType.MONOHULL, true),
|
||||
VO60 ("VO60", true, 19.5, 5.25, BoatHullType.MONOHULL, true, "Volvo Ocean 60", "VolvoOcean60", "W60", "Whitbread60", "Whitbread 60"),
|
||||
VX_ONE ("VX ONE", true, 5.79, 2.19, BoatHullType.MONOHULL, true, "VX-ONE"),
|
||||
|
||||
+19
-2
@@ -25,11 +25,26 @@ public enum DetailType implements Serializable {
|
||||
CURRENT_HEEL_IN_DEGREES(2,DESCENDING),
|
||||
CURRENT_PITCH_IN_DEGREES(2,DESCENDING),
|
||||
CURRENT_RIDE_HEIGHT_IN_METERS(2,DESCENDING),
|
||||
CURRENT_DISTANCE_FOILED_IN_METERS(0, DESCENDING),
|
||||
CURRENT_DURATION_FOILED_IN_SECONDS(0, DESCENDING),
|
||||
CURRENT_PORT_DAGGERBOARD_RAKE(2,DESCENDING),
|
||||
CURRENT_STBD_DAGGERBOARD_RAKE(2,DESCENDING),
|
||||
CURRENT_PORT_RUDDER_RAKE(2,DESCENDING),
|
||||
CURRENT_STBD_RUDDER_RAKE(2,DESCENDING),
|
||||
CURRENT_MAST_ROTATION_IN_DEGREES(2,DESCENDING),
|
||||
CURRENT_LEEWAY_IN_DEGREES(1, ASCENDING),
|
||||
CURRENT_SET(1, ASCENDING),
|
||||
CURRENT_DRIFT_IN_DEGREES(1, ASCENDING),
|
||||
CURRENT_DEPTH_IN_METERS(1, ASCENDING),
|
||||
CURRENT_RUDDER_IN_DEGREES(2, ASCENDING),
|
||||
CURRENT_TACK_ANGLE_IN_DEGREES(2, ASCENDING),
|
||||
CURRENT_DEFLECTOR_PERCENTAGE(2, ASCENDING),
|
||||
CURRENT_DEFLECTOR_IN_MILLIMETERS(2, ASCENDING),
|
||||
CURRENT_RAKE_IN_DEGREES(2, ASCENDING),
|
||||
CURRENT_TARGET_HEEL_ANGLE_IN_DEGREES(2, ASCENDING),
|
||||
CURRENT_FORESTAY_LOAD(2, ASCENDING),
|
||||
CURRENT_FORESTAY_PRESSURE(2, ASCENDING),
|
||||
CURRENT_TARGET_BOATSPEED_PERCENTAGE(2, ASCENDING),
|
||||
ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS(1, ASCENDING), VELOCITY_MADE_GOOD_IN_KNOTS(2, DESCENDING),
|
||||
GAP_TO_LEADER_IN_SECONDS(0, ASCENDING), GAP_CHANGE_SINCE_LEG_START_IN_SECONDS(0, ASCENDING),
|
||||
SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED(0, ASCENDING), WINDWARD_DISTANCE_TO_GO_IN_METERS(0, ASCENDING),
|
||||
@@ -51,8 +66,10 @@ public enum DetailType implements Serializable {
|
||||
MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS(1, DESCENDING),
|
||||
TIME_ON_TIME_FACTOR(4, DESCENDING), TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE(0, ASCENDING),
|
||||
TOTAL_DISTANCE_TRAVELED(0, ASCENDING), TOTAL_AVERAGE_SPEED_OVER_GROUND(2, DESCENDING),
|
||||
TOTAL_TIME_SAILED_IN_SECONDS(1, ASCENDING), RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS(2,
|
||||
DESCENDING), RACE_CURRENT_RIDE_HEIGHT_IN_METERS(2, DESCENDING),
|
||||
TOTAL_TIME_SAILED_IN_SECONDS(1, ASCENDING),
|
||||
TOTAL_DURATION_FOILED_IN_SECONDS(0, DESCENDING), TOTAL_DISTANCE_FOILED_IN_METERS(0, DESCENDING),
|
||||
RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_CURRENT_RIDE_HEIGHT_IN_METERS(2, DESCENDING),
|
||||
RACE_CURRENT_DISTANCE_FOILED_IN_METERS(0, DESCENDING), RACE_CURRENT_DURATION_FOILED_IN_SECONDS(0, DESCENDING),
|
||||
RACE_NET_POINTS(2, ASCENDING), REGATTA_NET_POINTS(2, ASCENDING), REGATTA_NET_POINTS_SUM(2, ASCENDING),
|
||||
RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL(1, ASCENDING), RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START(1, ASCENDING),
|
||||
RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START(2, DESCENDING),
|
||||
|
||||
+2
-3
@@ -1,9 +1,7 @@
|
||||
package com.sap.sailing.domain.racelogtracking;
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
|
||||
/**
|
||||
* Identifies any kind of tracking device. Should be implemented accordingly for different tracking
|
||||
* adapters, e.g. for smartphones, Igtimi trackers etc.<p>
|
||||
@@ -37,6 +35,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
* {@link Object#equals(Object)} and {@link Object#hashCode()} should be implemented so that multiple
|
||||
* deserializations of same device identifier (conceptually) result in objects that are be identified
|
||||
* as being equal through these two methods.
|
||||
*
|
||||
* @author Fredrik Teschke
|
||||
*
|
||||
*/
|
||||
+43
-2
@@ -138,7 +138,7 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
return totalPointsCorrected || (reasonForMaxPoints != null && reasonForMaxPoints != MaxPointsReason.NONE);
|
||||
}
|
||||
|
||||
public Duration getTimeSailedInMillis() {
|
||||
public Duration getTimeSailed() {
|
||||
final Duration result;
|
||||
if (legDetails != null) {
|
||||
long timeInMilliseconds = 0;
|
||||
@@ -159,7 +159,7 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Distance getDistanceTraveledInMeters() {
|
||||
public Distance getDistanceTraveled() {
|
||||
Distance result = null;
|
||||
if (legDetails != null) {
|
||||
for (LegEntryDTO legDetail : legDetails) {
|
||||
@@ -176,6 +176,47 @@ public class LeaderboardEntryDTO implements Serializable {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Duration getDurationFoiled() {
|
||||
final Duration result;
|
||||
if (legDetails != null) {
|
||||
Double acc = null;
|
||||
for (LegEntryDTO legDetail : legDetails) {
|
||||
if (legDetail != null) {
|
||||
if (legDetail.currentDurationFoiledInSeconds != null) {
|
||||
if (acc == null) {
|
||||
acc = 0.0;
|
||||
}
|
||||
acc += legDetail.currentDurationFoiledInSeconds;
|
||||
} else {
|
||||
acc = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = acc == null ? null : new MillisecondsDurationImpl((long) (acc*1000.));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Distance getDistanceFoiled() {
|
||||
Distance result = null;
|
||||
if (legDetails != null) {
|
||||
for (LegEntryDTO legDetail : legDetails) {
|
||||
if (legDetail != null) {
|
||||
if (legDetail.currentDistanceFoiledInMeters != null) {
|
||||
if (result == null) {
|
||||
result = Distance.NULL;
|
||||
}
|
||||
result = result.add(new MeterDistance(legDetail.currentDistanceFoiledInMeters));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getOneBasedCurrentLegNumber() {
|
||||
int result = 0;
|
||||
if (legDetails != null && !legDetails.isEmpty()) {
|
||||
|
||||
+41
-3
@@ -26,6 +26,8 @@ public class LeaderboardRowDTO implements Serializable {
|
||||
public Double totalTimeSailedUpwindInSeconds;
|
||||
public Double totalTimeSailedReachingInSeconds;
|
||||
public Double totalDistanceTraveledInMeters;
|
||||
public Double totalDurationFoiledInSeconds;
|
||||
public Double totalDistanceFoiledInMeters;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
@@ -38,6 +40,10 @@ public class LeaderboardRowDTO implements Serializable {
|
||||
+ ((maximumSpeedOverGroundInKnots == null) ? 0 : maximumSpeedOverGroundInKnots.hashCode());
|
||||
result = prime * result
|
||||
+ ((totalDistanceTraveledInMeters == null) ? 0 : totalDistanceTraveledInMeters.hashCode());
|
||||
result = prime * result
|
||||
+ ((totalDurationFoiledInSeconds == null) ? 0 : totalDurationFoiledInSeconds.hashCode());
|
||||
result = prime * result
|
||||
+ ((totalDistanceFoiledInMeters == null) ? 0 : totalDistanceFoiledInMeters.hashCode());
|
||||
result = prime * result + ((netPoints == null) ? 0 : netPoints.hashCode());
|
||||
result = prime * result
|
||||
+ ((totalTimeSailedDownwindInSeconds == null) ? 0 : totalTimeSailedDownwindInSeconds.hashCode());
|
||||
@@ -87,6 +93,16 @@ public class LeaderboardRowDTO implements Serializable {
|
||||
return false;
|
||||
} else if (!totalDistanceTraveledInMeters.equals(other.totalDistanceTraveledInMeters))
|
||||
return false;
|
||||
if (totalDurationFoiledInSeconds == null) {
|
||||
if (other.totalDurationFoiledInSeconds != null)
|
||||
return false;
|
||||
} else if (!totalDurationFoiledInSeconds.equals(other.totalDurationFoiledInSeconds))
|
||||
return false;
|
||||
if (totalDistanceFoiledInMeters == null) {
|
||||
if (other.totalDistanceFoiledInMeters != null)
|
||||
return false;
|
||||
} else if (!totalDistanceFoiledInMeters.equals(other.totalDistanceFoiledInMeters))
|
||||
return false;
|
||||
if (netPoints == null) {
|
||||
if (other.netPoints != null)
|
||||
return false;
|
||||
@@ -120,11 +136,11 @@ public class LeaderboardRowDTO implements Serializable {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Distance getDistanceTraveledInMeters(String raceColumnName) {
|
||||
public Distance getDistanceTraveled(String raceColumnName) {
|
||||
final Distance result;
|
||||
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.getDistanceTraveledInMeters();
|
||||
result = fieldsForRace.getDistanceTraveled();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
@@ -135,7 +151,29 @@ public class LeaderboardRowDTO implements Serializable {
|
||||
final Duration result;
|
||||
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.getTimeSailedInMillis();
|
||||
result = fieldsForRace.getTimeSailed();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Distance getDistanceFoiled(String raceColumnName) {
|
||||
final Distance result;
|
||||
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.getDistanceFoiled();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Duration getDurationFoiled(String raceColumnName) {
|
||||
final Duration result;
|
||||
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (fieldsForRace != null) {
|
||||
result = fieldsForRace.getDurationFoiled();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
|
||||
+14
@@ -44,6 +44,8 @@ public class LegEntryDTO implements Serializable {
|
||||
|
||||
public Double currentHeelInDegrees;
|
||||
public Double currentPitchInDegrees;
|
||||
public Double currentDistanceFoiledInMeters;
|
||||
public Double currentDurationFoiledInSeconds;
|
||||
|
||||
/**
|
||||
* If the competitor has already finished the leg at the time point for which this entry was created, contains the
|
||||
@@ -81,6 +83,8 @@ public class LegEntryDTO implements Serializable {
|
||||
result = prime * result + ((currentHeelInDegrees == null) ? 0 : currentHeelInDegrees.hashCode());
|
||||
result = prime * result + ((currentPitchInDegrees == null) ? 0 : currentPitchInDegrees.hashCode());
|
||||
result = prime * result + ((currentRideHeightInMeters == null) ? 0 : currentRideHeightInMeters.hashCode());
|
||||
result = prime * result + ((currentDurationFoiledInSeconds == null) ? 0 : currentDurationFoiledInSeconds.hashCode());
|
||||
result = prime * result + ((currentDistanceFoiledInMeters == null) ? 0 : currentDistanceFoiledInMeters.hashCode());
|
||||
result = prime * result
|
||||
+ ((currentSpeedOverGroundInKnots == null) ? 0 : currentSpeedOverGroundInKnots.hashCode());
|
||||
result = prime * result + ((distanceTraveledInMeters == null) ? 0 : distanceTraveledInMeters.hashCode());
|
||||
@@ -150,6 +154,16 @@ public class LegEntryDTO implements Serializable {
|
||||
return false;
|
||||
} else if (!currentRideHeightInMeters.equals(other.currentRideHeightInMeters))
|
||||
return false;
|
||||
if (currentDurationFoiledInSeconds == null) {
|
||||
if (other.currentDurationFoiledInSeconds != null)
|
||||
return false;
|
||||
} else if (!currentDurationFoiledInSeconds.equals(other.currentDurationFoiledInSeconds))
|
||||
return false;
|
||||
if (currentDistanceFoiledInMeters == null) {
|
||||
if (other.currentDistanceFoiledInMeters != null)
|
||||
return false;
|
||||
} else if (!currentDistanceFoiledInMeters.equals(other.currentDistanceFoiledInMeters))
|
||||
return false;
|
||||
if (currentSpeedOverGroundInKnots == null) {
|
||||
if (other.currentSpeedOverGroundInKnots != null)
|
||||
return false;
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ public class DegreeBearingImpl extends AbstractBearing implements Bearing {
|
||||
private final double bearingDeg;
|
||||
/**
|
||||
*
|
||||
* @param bearingDeg if a mount degrees over 360, then it will be mod 360 degrees
|
||||
* @param bearingDeg if amount degrees over 360, then it will be mod 360 degrees
|
||||
*/
|
||||
public DegreeBearingImpl(double bearingDeg) {
|
||||
super();
|
||||
|
||||
+5
@@ -35,12 +35,17 @@ public enum BravoExtendedSensorDataMetadata implements ColumnMetadata {
|
||||
DEPTH(null, /* expectedInLogfile */ false), //
|
||||
RUDDER(null, /* expectedInLogfile */ false), //
|
||||
FORESTAY_LOAD(null, /* expectedInLogfile */ false), //
|
||||
FORESTAY_PRESSURE(null, /* expectedInLogfile */ false), //
|
||||
TACK_ANGLE(null, /* expectedInLogfile */ false), //
|
||||
RAKE_DEG(null, /* expectedInLogfile */ false), //
|
||||
DEFLECTOR_PERCENTAGE(null, /* expectedInLogfile */ false), //
|
||||
TARGET_HEEL(null, /* expectedInLogfile */ false), //
|
||||
DEFLECTOR_MILLIMETERS(null, /* expectedInLogfile */ false), //
|
||||
TARGET_BOATSPEED_P(null, /* expectedInLogfile */ false), //
|
||||
LAT("Lat", /* expectedInLogfile */ true), //
|
||||
LON("Lon", /* expectedInLogfile */ true), //
|
||||
COG("COG", /* expectedInLogfile */ true), //
|
||||
SOG("SOG", /* expectedInLogfile */ true), //
|
||||
;
|
||||
|
||||
private final String columnName;
|
||||
|
||||
+25
-15
@@ -9,28 +9,31 @@ import java.util.Objects;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
|
||||
/**
|
||||
* Metadata that defines the column structure of BravoExtended fixes when imported as {@link com.sap.sailing.domain.common.tracking.DoubleVectorFix}.
|
||||
* Metadata that defines the column structure of BravoExtended fixes when imported as
|
||||
* {@link com.sap.sailing.domain.common.tracking.DoubleVectorFix}.
|
||||
* <p>
|
||||
*
|
||||
* The current implementation only stores a subset of the information available during the import.
|
||||
* <p>
|
||||
*
|
||||
* The first columns need to be consistent with {@link BravoSensorDataMetadata}.
|
||||
*/
|
||||
public enum ExpeditionExtendedSensorDataMetadata {
|
||||
HEEL("Heel", BravoExtendedSensorDataMetadata.HEEL), //
|
||||
TRIM("TRIM", BravoExtendedSensorDataMetadata.PITCH), //
|
||||
LEEWAY(null, BravoExtendedSensorDataMetadata.LEEWAY), //
|
||||
SET(null, BravoExtendedSensorDataMetadata.SET), //
|
||||
DRIFT(null, BravoExtendedSensorDataMetadata.DRIFT), //
|
||||
DEPTH(null, BravoExtendedSensorDataMetadata.DEPTH), //
|
||||
RUDDER(null, BravoExtendedSensorDataMetadata.RUDDER), //
|
||||
FORESTAY_LOAD(null, BravoExtendedSensorDataMetadata.FORESTAY_LOAD), //
|
||||
TRIM("Trim", BravoExtendedSensorDataMetadata.PITCH), //
|
||||
LEEWAY("Leeway", BravoExtendedSensorDataMetadata.LEEWAY, /* expected in logfile */ true), //
|
||||
SET("Set", BravoExtendedSensorDataMetadata.SET, /* expected in logfile */ true), //
|
||||
DRIFT("Drift", BravoExtendedSensorDataMetadata.DRIFT, /* expected in logfile */ true), //
|
||||
DEPTH("Depth", BravoExtendedSensorDataMetadata.DEPTH, /* expected in logfile */ true), //
|
||||
RUDDER("Rudder", BravoExtendedSensorDataMetadata.RUDDER, /* expected in logfile */ true), //
|
||||
FORESTAY_LOAD("Forestay", BravoExtendedSensorDataMetadata.FORESTAY_LOAD, /* expected in logfile */ true), //
|
||||
FORESTAY_PRESSURE("ForestayPres", BravoExtendedSensorDataMetadata.FORESTAY_PRESSURE, /* expected in logfile */ true), //
|
||||
TACK_ANGLE(null, BravoExtendedSensorDataMetadata.TACK_ANGLE), //
|
||||
RAKE_DEG(null, BravoExtendedSensorDataMetadata.RAKE_DEG), //
|
||||
DEFLECTOR_PERCENTAGE(null, BravoExtendedSensorDataMetadata.DEFLECTOR_PERCENTAGE), //
|
||||
TARGET_HEEL(null, BravoExtendedSensorDataMetadata.TARGET_HEEL), //
|
||||
DEFLECTOR_MILLIMETERS(null, BravoExtendedSensorDataMetadata.DEFLECTOR_MILLIMETERS), //
|
||||
TARGET_BOATSPEED_P(null, BravoExtendedSensorDataMetadata.TARGET_BOATSPEED_P), //
|
||||
|
||||
RAKE_DEG("RakeDeg", BravoExtendedSensorDataMetadata.RAKE_DEG, /* expected in logfile */ true), //
|
||||
DEFLECTOR_PERCENTAGE("DflectrPP", BravoExtendedSensorDataMetadata.DEFLECTOR_PERCENTAGE, /* expected in logfile */ true), //
|
||||
TARGET_HEEL("TG Heell", BravoExtendedSensorDataMetadata.TARGET_HEEL, /* expected in logfile */ true), //
|
||||
DEFLECTOR_MILLIMETERS("DflectrMM", BravoExtendedSensorDataMetadata.DEFLECTOR_MILLIMETERS, /* expected in logfile */ true), //
|
||||
TARGET_BOATSPEED_P("BspTr", BravoExtendedSensorDataMetadata.TARGET_BOATSPEED_P, /* expected in logfile */ true), //
|
||||
;
|
||||
|
||||
private String columnName;
|
||||
@@ -44,10 +47,17 @@ public enum ExpeditionExtendedSensorDataMetadata {
|
||||
* the Bravo metadata.
|
||||
*/
|
||||
private final BravoExtendedSensorDataMetadata mappedToBravoField;
|
||||
|
||||
private final boolean expectedInLogfile;
|
||||
|
||||
private ExpeditionExtendedSensorDataMetadata(String columnName, BravoExtendedSensorDataMetadata mappedToBravoField) {
|
||||
this(columnName, mappedToBravoField, mappedToBravoField.isExpectedInLogFile());
|
||||
}
|
||||
|
||||
private ExpeditionExtendedSensorDataMetadata(String columnName, BravoExtendedSensorDataMetadata mappedToBravoField, boolean expectedInLogfile) {
|
||||
this.columnName = columnName;
|
||||
this.mappedToBravoField = mappedToBravoField;
|
||||
this.expectedInLogfile = expectedInLogfile;
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
@@ -62,7 +72,7 @@ public enum ExpeditionExtendedSensorDataMetadata {
|
||||
}
|
||||
|
||||
public boolean isExpectedInLogFile() {
|
||||
return mappedToBravoField.isExpectedInLogFile();
|
||||
return expectedInLogfile;
|
||||
}
|
||||
|
||||
public static ExpeditionExtendedSensorDataMetadata byColumnName(String valueName) {
|
||||
|
||||
+3
-2
@@ -12,12 +12,13 @@ public interface BravoExtendedFix extends BravoFix {
|
||||
Double getPortRudderRake();
|
||||
Double getStbdRudderRake();
|
||||
Bearing getMastRotation();
|
||||
Double getLeeway();
|
||||
Bearing getLeeway();
|
||||
Double getSet();
|
||||
Double getDrift();
|
||||
Bearing getDrift();
|
||||
Distance getDepth();
|
||||
Bearing getRudder();
|
||||
Double getForestayLoad();
|
||||
Double getForestayPressure();
|
||||
Bearing getTackAngle();
|
||||
Bearing getRake();
|
||||
Double getDeflectorPercentage();
|
||||
|
||||
+11
-4
@@ -52,8 +52,9 @@ public class BravoExtendedFixImpl extends BravoFixImpl implements BravoExtendedF
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getLeeway() {
|
||||
return fix.get(BravoExtendedSensorDataMetadata.LEEWAY.getColumnIndex());
|
||||
public Bearing getLeeway() {
|
||||
final Double leeway = fix.get(BravoExtendedSensorDataMetadata.LEEWAY.getColumnIndex());
|
||||
return leeway == null ? null : new DegreeBearingImpl(leeway);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,8 +63,9 @@ public class BravoExtendedFixImpl extends BravoFixImpl implements BravoExtendedF
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getDrift() {
|
||||
return fix.get(BravoExtendedSensorDataMetadata.DRIFT.getColumnIndex());
|
||||
public Bearing getDrift() {
|
||||
final Double drift = fix.get(BravoExtendedSensorDataMetadata.DRIFT.getColumnIndex());
|
||||
return drift == null ? null : new DegreeBearingImpl(drift);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,6 +85,11 @@ public class BravoExtendedFixImpl extends BravoFixImpl implements BravoExtendedF
|
||||
return fix.get(BravoExtendedSensorDataMetadata.FORESTAY_LOAD.getColumnIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getForestayPressure() {
|
||||
return fix.get(BravoExtendedSensorDataMetadata.FORESTAY_PRESSURE.getColumnIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getTackAngle() {
|
||||
final Double tackAngleDeg = fix.get(BravoExtendedSensorDataMetadata.TACK_ANGLE.getColumnIndex());
|
||||
|
||||
+8
-3
@@ -27,10 +27,15 @@ public class BravoFixImpl extends SensorFixImpl implements BravoFix {
|
||||
|
||||
@Override
|
||||
public Distance getRideHeight() {
|
||||
double rideHeightPortHullasDouble = fix.get(BravoSensorDataMetadata.RIDE_HEIGHT_PORT_HULL.getColumnIndex());
|
||||
double rideHeightStarboardHullasDouble = fix
|
||||
Double rideHeightPortHullasDouble = fix.get(BravoSensorDataMetadata.RIDE_HEIGHT_PORT_HULL.getColumnIndex());
|
||||
Double rideHeightStarboardHullAsDouble = fix
|
||||
.get(BravoSensorDataMetadata.RIDE_HEIGHT_STBD_HULL.getColumnIndex());
|
||||
return new MeterDistance(Math.min(rideHeightPortHullasDouble, rideHeightStarboardHullasDouble));
|
||||
return rideHeightPortHullasDouble == null ?
|
||||
rideHeightStarboardHullAsDouble == null ? null :
|
||||
new MeterDistance(rideHeightStarboardHullAsDouble) :
|
||||
rideHeightStarboardHullAsDouble == null ?
|
||||
new MeterDistance(rideHeightPortHullasDouble) :
|
||||
new MeterDistance(Math.min(rideHeightPortHullasDouble, rideHeightStarboardHullAsDouble));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ import com.sap.sailing.server.trackfiles.impl.ExpeditionExtendedDataImporterImpl
|
||||
public class ExpeditionGPSFixImporter implements GPSFixImporter {
|
||||
private static final String LAT_COLUMN_HEADING = ExpeditionExtendedDataImporterImpl.COL_NAME_LAT;
|
||||
private static final String LON_COLUMN_HEADING = ExpeditionExtendedDataImporterImpl.COL_NAME_LON;
|
||||
private static final String COG_COLUMN_HEADING = "Ext_COG";
|
||||
private static final String SOG_COLUMN_HEADING = "Ext_SOG";
|
||||
private static final String COG_COLUMN_HEADING = "Cog";
|
||||
private static final String SOG_COLUMN_HEADING = "Sog";
|
||||
@Override
|
||||
public void importFixes(InputStream inputStream, Callback callback, boolean inferSpeedAndBearing, final String sourceName)
|
||||
throws FormatNotSupportedException, IOException {
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.sap.sailing.domain.igtimiadapter.test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Fix;
|
||||
import com.sap.sailing.domain.igtimiadapter.impl.FixFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class FixFactoryTest {
|
||||
private FixFactory fixFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
fixFactory = new FixFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownFixTypes() throws ParseException {
|
||||
final String[] messages = new String[] {
|
||||
"{\"DC-FE-AAKG\":{\"1\":{\"t\":[1510174025500],\"1\":[170.5044476],\"2\":[-45.87697]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"2\":{\"t\":[1510174025500],\"1\":[1]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"3\":{\"t\":[1510174025500],\"1\":[10]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"7\":{\"t\":[1510174025500],\"1\":[187.7]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"11\":{\"t\":[1510174025500],\"1\":[54]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"12\":{\"t\":[1510174025500],\"1\":[1.852]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"22\":{\"t\":[1510174025500],\"1\":[263.4]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"23\":{\"t\":[1510174025500],\"1\":[1.852]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"6\":{\"t\":[1510174025500],\"1\":[0]}}}",
|
||||
"{\"DC-FE-AAKG\":{\"9\":{\"t\":[1510174025500],\"1\":[0]}}}" };
|
||||
List<Fix> fixes = new ArrayList<>();
|
||||
for (final String message : messages) {
|
||||
JSONObject jsonObject = (JSONObject) new JSONParser().parse(message);
|
||||
Util.addAll(fixFactory.createFixes(jsonObject), fixes);
|
||||
}
|
||||
assertTrue(!Util.isEmpty(fixes)); // this largely asserts that no exception was thrown although there were unknown fix types (22/23)
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -54,9 +54,12 @@ public class FixFactory {
|
||||
Sensor sensor = new SensorImpl(deviceSerialNumber,
|
||||
fixTypeAndOptionalColonSeparatedSensorsSubId.length < 2 ? 0
|
||||
: Long.valueOf(fixTypeAndOptionalColonSeparatedSensorsSubId[1]));
|
||||
Fix fix = createFix(sensor, Type.valueOf(fixType), timePoint, valuesPerSubindex);
|
||||
result.add(fix);
|
||||
fixIndex++;
|
||||
final Type ft = Type.valueOf(fixType);
|
||||
if (ft != null) {
|
||||
Fix fix = createFix(sensor, ft, timePoint, valuesPerSubindex);
|
||||
result.add(fix);
|
||||
fixIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
+11
-3
@@ -39,6 +39,7 @@ import com.mongodb.WriteResult;
|
||||
import com.mongodb.util.JSON;
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResult.MergeState;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent;
|
||||
@@ -155,6 +156,7 @@ import com.sap.sailing.domain.base.impl.SeriesImpl;
|
||||
import com.sap.sailing.domain.base.impl.VenueImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.CourseDesignerMode;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.MarkType;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
@@ -168,8 +170,8 @@ import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.dto.EventType;
|
||||
import com.sap.sailing.domain.common.dto.AnniversaryType;
|
||||
import com.sap.sailing.domain.common.dto.EventType;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
@@ -206,7 +208,6 @@ import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongo
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.PlaceHolderDeviceIdentifierSerializationHandler;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.ranking.RankingMetricConstructor;
|
||||
@@ -1601,8 +1602,15 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
final Long finishingTimePointAsMillis = (Long) dbObject.get(FieldNames.RACE_LOG_FINISHING_TIME_AS_MILLIS.name());
|
||||
final TimePoint finishingTime = finishingTimePointAsMillis == null ? null : new MillisecondsTimePoint(finishingTimePointAsMillis);
|
||||
final String comment = (String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name());
|
||||
final String mergeStateAsString = (String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MERGE_STATE.name());
|
||||
final MergeState mergeState;
|
||||
if (mergeStateAsString == null) {
|
||||
mergeState = MergeState.OK;
|
||||
} else {
|
||||
mergeState = MergeState.valueOf(mergeStateAsString);
|
||||
}
|
||||
CompetitorResultImpl positionedCompetitor = new CompetitorResultImpl(
|
||||
competitorId, competitorDisplayName, rank == null ? rankCounter : rank, maxPointsReason, score, finishingTime, comment);
|
||||
competitorId, competitorDisplayName, rank == null ? rankCounter : rank, maxPointsReason, score, finishingTime, comment, mergeState);
|
||||
positionedCompetitors.add(positionedCompetitor);
|
||||
rankCounter++;
|
||||
}
|
||||
|
||||
+2
-1
@@ -80,7 +80,8 @@ public enum FieldNames {
|
||||
LEADERBOARD_IS_MEDAL_RACE_COLUMN, LEADERBOARD_CARRIED_POINTS, LEADERBOARD_CARRIED_POINTS_BY_ID,
|
||||
LEADERBOARD_SCORE_CORRECTIONS, LEADERBOARD_DISCARDING_THRESHOLDS,
|
||||
LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON, LEADERBOARD_CORRECTED_SCORE, LEADERBOARD_SCORE_CORRECTION_TIMESTAMP,
|
||||
LEADERBOARD_RANK, LEADERBOARD_SCORE_CORRECTION_COMMENT, LEADERBOARD_COLUMN_FACTORS, WRAPPED_REGATTA_LEADERBOARD_NAME,
|
||||
LEADERBOARD_RANK, LEADERBOARD_SCORE_CORRECTION_COMMENT, LEADERBOARD_SCORE_CORRECTION_MERGE_STATE,
|
||||
LEADERBOARD_COLUMN_FACTORS, WRAPPED_REGATTA_LEADERBOARD_NAME,
|
||||
ELMINATED_COMPETITORS,
|
||||
|
||||
// leaderboard group
|
||||
|
||||
+2
-1
@@ -86,6 +86,7 @@ import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
|
||||
import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle;
|
||||
import com.sap.sailing.domain.base.impl.FleetImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.Positioned;
|
||||
@@ -108,7 +109,6 @@ import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
|
||||
@@ -1239,6 +1239,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
result.put(FieldNames.RACE_LOG_FINISHING_TIME_AS_MILLIS.name(), competitorResult.getFinishingTime() == null ? null : competitorResult.getFinishingTime().asMillis());
|
||||
result.put(FieldNames.LEADERBOARD_RANK.name(), competitorResult.getOneBasedRank());
|
||||
result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name(), competitorResult.getComment());
|
||||
result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MERGE_STATE.name(), competitorResult.getMergeState().name());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -20,6 +20,7 @@ import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.QueryBuilder;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
@@ -30,7 +31,6 @@ import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongo
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.MongoSensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.FixReceivedListener;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.persistence.racelog.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.PlaceHolderDeviceIdentifierSerializationHandler;
|
||||
|
||||
public class PlaceHolderDeviceIdentifierMongoHandler extends PlaceHolderDeviceIdentifierSerializationHandler
|
||||
|
||||
+1
-1
@@ -24,6 +24,7 @@ import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Sideline;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
@@ -38,7 +39,6 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockDeviceAndSessionIdentifierWithGPSFixesDeserializer;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
|
||||
+1
-1
@@ -36,6 +36,7 @@ import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.base.impl.FleetImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.SeriesImpl;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
@@ -47,7 +48,6 @@ import com.sap.sailing.domain.leaderboard.impl.HighPoint;
|
||||
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
|
||||
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RaceLogFixTrackerManager;
|
||||
|
||||
+1
-1
@@ -16,9 +16,9 @@ import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCo
|
||||
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.tracking.impl.DoubleVectorFixImpl;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RegattaLogDeviceMappings;
|
||||
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
|
||||
import com.sap.sse.common.MultiTimeRange;
|
||||
|
||||
+1
-1
@@ -9,10 +9,10 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.Timeout;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoSensorFixStoreImpl;
|
||||
import com.sap.sailing.domain.racelog.tracking.FixReceivedListener;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
|
||||
|
||||
public class GPSFixStoreListenerTest extends AbstractGPSFixStoreTest {
|
||||
|
||||
+1
-1
@@ -31,6 +31,7 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
@@ -45,7 +46,6 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogsensortracking.SensorFixMapperFactory;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RaceLogFixTrackerManager;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
|
||||
+49
-87
@@ -54,7 +54,10 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
@@ -75,12 +78,12 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogsensortracking.SensorFixMapperFactory;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.BravoDataFixMapper;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.FixLoaderAndTracker;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
@@ -92,6 +95,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.domain.tracking.impl.SensorFixTrackImpl;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -178,18 +182,12 @@ public class SensorFixStoreAndLoadTest {
|
||||
public void testLoadAlreadyAddedFixes() throws InterruptedException {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -197,18 +195,12 @@ public class SensorFixStoreAndLoadTest {
|
||||
public void testAddFixesWhileTracking() throws InterruptedException {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -216,18 +208,12 @@ public class SensorFixStoreAndLoadTest {
|
||||
public void testNoFixesAreLoadedIfNoStoredFixIsInTimeRange() throws InterruptedException {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(AFTER_LAST_FIX), new MillisecondsTimePoint(END_OF_TRACKING)));
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 0);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -235,18 +221,12 @@ public class SensorFixStoreAndLoadTest {
|
||||
public void testFixesNotInMappedTimeRangeAreIgnoredWhileTracking() throws InterruptedException {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(AFTER_LAST_FIX), new MillisecondsTimePoint(END_OF_TRACKING)));
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 0);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -254,18 +234,12 @@ public class SensorFixStoreAndLoadTest {
|
||||
public void testCompetitorWithoutMappingHasNoTrack() throws InterruptedException {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
assertNull(trackedRace.getSensorTrack(comp2, BravoFixTrack.TRACK_NAME));
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -275,19 +249,13 @@ public class SensorFixStoreAndLoadTest {
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp2,
|
||||
device, new MillisecondsTimePoint(MID_OF_TRACKING + 1), new MillisecondsTimePoint(END_OF_TRACKING)));
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp2, BravoFixTrack.TRACK_NAME), 1);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -297,18 +265,12 @@ public class SensorFixStoreAndLoadTest {
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(MID_OF_TRACKING + 1), new MillisecondsTimePoint(END_OF_TRACKING)));
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 3);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -319,18 +281,12 @@ public class SensorFixStoreAndLoadTest {
|
||||
new MillisecondsTimePoint(MID_OF_TRACKING));
|
||||
regattaLog.add(mappingEvent);
|
||||
regattaLog.add(new RegattaLogRevokeEventImpl(author, mappingEvent, "Test purposes"));
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
assertNull(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME));
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -342,23 +298,16 @@ public class SensorFixStoreAndLoadTest {
|
||||
new MillisecondsTimePoint(END_OF_TRACKING));
|
||||
regattaLog.add(mappingEvent);
|
||||
regattaLog.add(new RegattaLogRevokeEventImpl(author, mappingEvent, "Test purposes"));
|
||||
|
||||
// non-revoked mapping timestamp 100-200
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
// Only Fixes from 100 to 200 may be included
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -371,25 +320,16 @@ public class SensorFixStoreAndLoadTest {
|
||||
RegattaLogCloseOpenEndedDeviceMappingEventImpl closeEvent = new RegattaLogCloseOpenEndedDeviceMappingEventImpl(
|
||||
new MillisecondsTimePoint(4), author, mappingEventId, new MillisecondsTimePoint(MID_OF_TRACKING));
|
||||
regattaLog.add(closeEvent);
|
||||
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
BravoFixTrack<Competitor> bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
|
||||
|
||||
testNumberOfRawFixes(bravoFixTrack, 2);
|
||||
|
||||
regattaLog.add(new RegattaLogRevokeEventImpl(author, closeEvent, "Test purposes"));
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
testNumberOfRawFixes(bravoFixTrack, 3);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -414,20 +354,14 @@ public class SensorFixStoreAndLoadTest {
|
||||
deviceTest, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
|
||||
addTestFixes();
|
||||
addBravoFixes();
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, TestFixTrackImpl.TRACK_NAME), 1);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -437,21 +371,14 @@ public class SensorFixStoreAndLoadTest {
|
||||
deviceTest, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
|
||||
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
addTestFixes();
|
||||
addBravoFixes();
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, TestFixTrackImpl.TRACK_NAME), 1);
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -461,18 +388,12 @@ public class SensorFixStoreAndLoadTest {
|
||||
deviceTest, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(END_OF_TRACKING)));
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
|
||||
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(END_OF_TRACKING)));
|
||||
|
||||
|
||||
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
addTestFixes();
|
||||
addBravoFixes();
|
||||
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
|
||||
BravoFixTrack<Competitor> bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
|
||||
assertEquals(FIX_RIDE_HEIGHT,
|
||||
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP)).getRideHeight());
|
||||
@@ -480,11 +401,9 @@ public class SensorFixStoreAndLoadTest {
|
||||
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP2)).getRideHeight());
|
||||
assertEquals(FIX_RIDE_HEIGHT3,
|
||||
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP3)).getRideHeight());
|
||||
|
||||
TestFixTrackImpl<Competitor> testFixTrack = trackedRace.getSensorTrack(comp, TestFixTrackImpl.TRACK_NAME);
|
||||
assertEquals(FIX_TEST_VALUE,
|
||||
testFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP)).getTestValue());
|
||||
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
}
|
||||
|
||||
@@ -501,7 +420,6 @@ public class SensorFixStoreAndLoadTest {
|
||||
}
|
||||
|
||||
private FixLoaderAndTracker createFixLoaderAndTracker() {
|
||||
|
||||
return new FixLoaderAndTracker(trackedRace, store, new SensorFixMapperFactory() {
|
||||
private TestDataFixMapper testDataFixMapper = new TestDataFixMapper();
|
||||
private BravoDataFixMapper bravoDataFixMapper = new BravoDataFixMapper();
|
||||
@@ -747,6 +665,50 @@ public class SensorFixStoreAndLoadTest {
|
||||
// only the initial 3 fixes are available
|
||||
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 3);
|
||||
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
|
||||
final DynamicGPSFixTrack<Competitor, GPSFixMoving> gpsFixTrack = trackedRace.getTrack(comp);
|
||||
final DegreePosition pos1 = new DegreePosition(0, 0);
|
||||
final DegreeBearingImpl course = new DegreeBearingImpl(0);
|
||||
final KnotSpeedWithBearingImpl speed = new KnotSpeedWithBearingImpl(10, course);
|
||||
final MillisecondsTimePoint timePoint = new MillisecondsTimePoint(FIX_TIMESTAMP);
|
||||
final MillisecondsTimePoint timePoint2 = new MillisecondsTimePoint(FIX_TIMESTAMP2);
|
||||
final MillisecondsTimePoint timePoint3 = new MillisecondsTimePoint(FIX_TIMESTAMP3);
|
||||
final TimePoint timePointBetween2And3 = new MillisecondsTimePoint((FIX_TIMESTAMP2+FIX_TIMESTAMP3)/2);
|
||||
final GPSFixMoving fix1 = new GPSFixMovingImpl(pos1, timePoint, speed);
|
||||
final Position pos2 = pos1.translateGreatCircle(course, speed.travel(timePoint.until(timePoint2)));
|
||||
final GPSFixMoving fix2 = new GPSFixMovingImpl(pos2, timePoint2, speed);
|
||||
final Position pos3 = pos2.translateGreatCircle(course, speed.travel(timePoint2.until(timePoint3)));
|
||||
final GPSFixMoving fix3 = new GPSFixMovingImpl(pos3, timePoint3, speed);
|
||||
gpsFixTrack.add(fix1);
|
||||
gpsFixTrack.add(fix2);
|
||||
gpsFixTrack.add(fix3);
|
||||
final BravoFixTrack<Competitor> bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
|
||||
final Distance foilingDistance = bravoFixTrack.getDistanceSpentFoiling(timePoint, timePoint3);
|
||||
final Distance distanceTraveled = gpsFixTrack.getDistanceTraveled(timePoint, timePoint3);
|
||||
assertEquals(distanceTraveled.getMeters(), foilingDistance.getMeters(), 0.001);
|
||||
final Duration foilingDuration = bravoFixTrack.getTimeSpentFoiling(timePoint, timePoint3);
|
||||
assertEquals(timePoint.until(timePoint3).asMillis(), foilingDuration.asMillis());
|
||||
|
||||
// now insert a GPS fix which leads to an extended distance traveled as it is not exactly on the previous track
|
||||
final DegreeBearingImpl temporaryCourse = new DegreeBearingImpl(90);
|
||||
final GPSFixMoving fixBetween2And3 = new GPSFixMovingImpl(
|
||||
pos2.translateGreatCircle(temporaryCourse, speed.add(new KnotSpeedWithBearingImpl(5, temporaryCourse)).travel(timePoint2.until(timePointBetween2And3))),
|
||||
timePointBetween2And3, speed);
|
||||
gpsFixTrack.add(fixBetween2And3);
|
||||
final Distance distanceTraveledDifferently = gpsFixTrack.getDistanceTraveled(timePoint, timePoint3);
|
||||
assertTrue(distanceTraveledDifferently.compareTo(distanceTraveled) > 0);
|
||||
final Distance foilingDistanceDifferent = bravoFixTrack.getDistanceSpentFoiling(timePoint, timePoint3);
|
||||
assertEquals(distanceTraveledDifferently.getMeters(), foilingDistanceDifferent.getMeters(), 0.001);
|
||||
|
||||
// now overwrite fix3 by a new one with increased speed, therefore extended distance:
|
||||
final SpeedWithBearing doubledSpeed = speed.add(speed);
|
||||
final GPSFixMoving fix3Faster = new GPSFixMovingImpl(
|
||||
pos2.translateGreatCircle(course, doubledSpeed.travel(timePoint2.until(timePoint3))),
|
||||
timePoint3, doubledSpeed);
|
||||
gpsFixTrack.add(fix3Faster, /* replace */ true);
|
||||
final Distance distanceTraveledFaster = gpsFixTrack.getDistanceTraveled(timePoint, timePoint3);
|
||||
assertTrue(distanceTraveledFaster.compareTo(distanceTraveled) > 0);
|
||||
final Distance foilingDistanceFaster = bravoFixTrack.getDistanceSpentFoiling(timePoint, timePoint3);
|
||||
assertEquals(distanceTraveledFaster.getMeters(), foilingDistanceFaster.getMeters(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-1
@@ -14,6 +14,7 @@ import org.mockito.Mockito;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoException;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
@@ -30,7 +31,6 @@ import com.sap.sailing.domain.racelog.tracking.FixReceivedListener;
|
||||
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
+1
-1
@@ -24,11 +24,11 @@ import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.FixLoaderAndTracker;
|
||||
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package com.sap.sailing.domain.racelog.tracking.test.mock;
|
||||
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
|
||||
|
||||
public class SmartphoneImeiIdentifier implements DeviceIdentifier {
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.domain.racelog.tracking.test.mock;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
|
||||
|
||||
public class SmartphoneImeiJsonHandler extends SmartphoneImeiSerializationHandler
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelog.tracking.test.mock;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
|
||||
public class SmartphoneImeiMongoHandler extends SmartphoneImeiSerializationHandler
|
||||
implements DeviceIdentifierMongoHandler {
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.domain.racelog.tracking.test.mock;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class SmartphoneImeiSerializationHandler {
|
||||
|
||||
+2
@@ -2,6 +2,8 @@ package com.sap.sailing.domain.racelogtracking;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
|
||||
/**
|
||||
* A device identifier used to identify a non-existent, virtual device, which is used only once as an
|
||||
* identifier to add a single fix to a track (i.e. pinging the location of that track's item).
|
||||
|
||||
+3
-2
@@ -10,7 +10,7 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixMapper;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.BravoFixTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.CompetitorBravoFixTrackImpl;
|
||||
|
||||
/**
|
||||
* {@link SensorFixMapper} implementation to handle {@link BravoFix}es.
|
||||
@@ -20,7 +20,8 @@ public class BravoDataFixMapper implements SensorFixMapper<BravoFix, DynamicSens
|
||||
@Override
|
||||
public DynamicSensorFixTrack<Competitor, BravoFix> getTrack(DynamicTrackedRace race, Competitor key) {
|
||||
return race.getOrCreateSensorTrack(key, BravoFixTrack.TRACK_NAME,
|
||||
() -> new BravoFixTrackImpl<Competitor>(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ false));
|
||||
() -> new CompetitorBravoFixTrackImpl(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ false,
|
||||
race.getTrack(key)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -11,7 +11,7 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixMapper;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.BravoFixTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.CompetitorBravoFixTrackImpl;
|
||||
|
||||
/**
|
||||
* {@link SensorFixMapper} implementation to handle {@link BravoExtendedFix}es.
|
||||
@@ -21,7 +21,8 @@ public class BravoExtendedDataFixMapper implements SensorFixMapper<BravoFix, Dyn
|
||||
@Override
|
||||
public DynamicSensorFixTrack<Competitor, BravoFix> getTrack(DynamicTrackedRace race, Competitor key) {
|
||||
return race.getOrCreateSensorTrack(key, BravoFixTrack.TRACK_NAME,
|
||||
() -> new BravoFixTrackImpl<Competitor>(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ true));
|
||||
() -> new CompetitorBravoFixTrackImpl(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ true,
|
||||
race.getTrack(key)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -11,7 +11,7 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixMapper;
|
||||
import com.sap.sailing.domain.tracking.BravoFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.BravoFixTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.CompetitorBravoFixTrackImpl;
|
||||
|
||||
/**
|
||||
* {@link SensorFixMapper} implementation to product {@link BravoExtendedFix}es from {@link DoubleVectorFix}es
|
||||
@@ -25,7 +25,8 @@ public class ExpeditionExtendedDataFixMapper implements SensorFixMapper<BravoFix
|
||||
@Override
|
||||
public DynamicSensorFixTrack<Competitor, BravoFix> getTrack(DynamicTrackedRace race, Competitor key) {
|
||||
return race.getOrCreateSensorTrack(key, BravoFixTrack.TRACK_NAME,
|
||||
() -> new BravoFixTrackImpl<Competitor>(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ true));
|
||||
() -> new CompetitorBravoFixTrackImpl(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ true,
|
||||
race.getTrack(key)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
|
||||
|
||||
public class PingDeviceIdentifierJsonHandler extends PingDeviceIdentifierSerializationHandler
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
|
||||
public class PingDeviceIdentifierMongoHandler extends PingDeviceIdentifierSerializationHandler
|
||||
implements DeviceIdentifierMongoHandler {
|
||||
|
||||
+1
-1
@@ -2,8 +2,8 @@ package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.PingDeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.PingDeviceIdentifierImpl;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.SmartphoneUUIDSerializationHandler;
|
||||
|
||||
public class SmartphoneUUIDMongoHandler extends SmartphoneUUIDSerializationHandler
|
||||
|
||||
+1
-1
@@ -4,8 +4,8 @@ import java.util.UUID;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
|
||||
|
||||
+1
-1
@@ -4,9 +4,9 @@ import java.util.UUID;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
+1
-1
@@ -2,8 +2,8 @@ package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifierStringSerializationHandler;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||
|
||||
+1
-1
@@ -23,6 +23,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMap
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
@@ -33,7 +34,6 @@ import com.sap.sailing.domain.racelog.tracking.FixReceivedListener;
|
||||
import com.sap.sailing.domain.racelog.tracking.SensorFixMapper;
|
||||
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
|
||||
import com.sap.sailing.domain.racelogsensortracking.SensorFixMapperFactory;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
|
||||
|
||||
+1
-1
@@ -22,8 +22,8 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMap
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.impl.BaseRegattaLogEventVisitor;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMappingFinder;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrack;
|
||||
|
||||
+11
-10
@@ -12,6 +12,7 @@ import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResult.MergeState;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
@@ -56,10 +57,10 @@ public class ConfirmedFinishPositioningListFinderTest extends
|
||||
public void testMostRecent() {
|
||||
RaceLogFinishPositioningConfirmedEvent event1 = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 1);
|
||||
RaceLogFinishPositioningConfirmedEvent event2 = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 2);
|
||||
final CompetitorResultImpl oldResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, MaxPointsReason.NONE, 1.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl oldResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.NONE, 2.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl oldResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, MaxPointsReason.NONE, 1.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResultImpl oldResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.NONE, 2.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResults olderResults = mockCompetitorResults(oldResultC1, oldResultC2);
|
||||
final CompetitorResultImpl newResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl newResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResults newerResults = mockCompetitorResults(newResultC2);
|
||||
when(event1.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(olderResults);
|
||||
when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(newerResults);
|
||||
@@ -74,16 +75,16 @@ public class ConfirmedFinishPositioningListFinderTest extends
|
||||
RaceLogFinishPositioningConfirmedEvent event2 = createEvent(/* priority */ 1, RaceLogFinishPositioningConfirmedEvent.class, 2);
|
||||
RaceLogFinishPositioningConfirmedEvent event3 = createEvent(/* priority */ 2, RaceLogFinishPositioningConfirmedEvent.class, 3);
|
||||
RaceLogFinishPositioningConfirmedEvent event4 = createEvent(/* priority */ 1, RaceLogFinishPositioningConfirmedEvent.class, 4);
|
||||
final CompetitorResultImpl e1ResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, MaxPointsReason.DNC, 6.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl e1ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.NONE, 2.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl e1ResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, MaxPointsReason.DNC, 6.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResultImpl e1ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.NONE, 2.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResults e1Results = mockCompetitorResults(e1ResultC1, e1ResultC2);
|
||||
final CompetitorResultImpl e2ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl e2ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResults e2Results = mockCompetitorResults(e2ResultC2);
|
||||
final CompetitorResultImpl e3ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DSQ, 6.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl e3ResultC3 = new CompetitorResultImpl("Comp3", "Comp 3", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl e3ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DSQ, 6.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResultImpl e3ResultC3 = new CompetitorResultImpl("Comp3", "Comp 3", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResults e3Results = mockCompetitorResults(e3ResultC2, e3ResultC3);
|
||||
final CompetitorResultImpl e4ResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, /* maxPointsReason */ null, /* score */ null, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl e4ResultC4 = new CompetitorResultImpl("Comp4", "Comp 4", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null);
|
||||
final CompetitorResultImpl e4ResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, /* maxPointsReason */ null, /* score */ null, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResultImpl e4ResultC4 = new CompetitorResultImpl("Comp4", "Comp 4", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
|
||||
final CompetitorResults e4Results = mockCompetitorResults(e4ResultC1, e4ResultC4);
|
||||
when(event1.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e1Results);
|
||||
when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e2Results);
|
||||
|
||||
+1
-1
@@ -17,9 +17,9 @@ import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCo
|
||||
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
+29
@@ -14,6 +14,30 @@ import com.sap.sse.common.TimePoint;
|
||||
*
|
||||
*/
|
||||
public interface CompetitorResult extends Serializable {
|
||||
public static enum MergeState {
|
||||
/**
|
||||
* No merge was necessary at competitor level.
|
||||
*/
|
||||
OK,
|
||||
|
||||
/**
|
||||
* A field-wise merge was necessary because an update was received that affected this competitor result
|
||||
* while locally this competitor result was in a "dirty" (modified) state. The merge was carried out
|
||||
* automatically because the fields changed in the dirty state did not overlap with the fields changed
|
||||
* in the version of the object received.
|
||||
*/
|
||||
WARNING,
|
||||
|
||||
/**
|
||||
* A field-wise merge was necessary because an update was received that affected this competitor result while
|
||||
* locally this competitor result was in a "dirty" (modified) state. The fields changed in the dirty state
|
||||
* overlap with the fields changed in the version of the object received. Field values from the local dirty state
|
||||
* have been preferred or have been appended in case of {@link String}-typed fields and need manual
|
||||
* intervention.
|
||||
*/
|
||||
ERROR
|
||||
};
|
||||
|
||||
Serializable getCompetitorId();
|
||||
|
||||
String getCompetitorDisplayName();
|
||||
@@ -27,4 +51,9 @@ public interface CompetitorResult extends Serializable {
|
||||
TimePoint getFinishingTime();
|
||||
|
||||
String getComment();
|
||||
|
||||
/**
|
||||
* Always returns a valid, non-{@code null} result. See {@link MergeState} for details.
|
||||
*/
|
||||
MergeState getMergeState();
|
||||
}
|
||||
+17
-2
@@ -23,8 +23,11 @@ public class CompetitorResultImpl implements CompetitorResult {
|
||||
|
||||
private final String comment;
|
||||
|
||||
private final MergeState mergeState;
|
||||
|
||||
public CompetitorResultImpl(Serializable competitorId, String competitorDisplayName, int oneBasedRank,
|
||||
MaxPointsReason maxPointsReason, Double score, TimePoint finishingTime, String comment) {
|
||||
MaxPointsReason maxPointsReason, Double score, TimePoint finishingTime, String comment,
|
||||
MergeState mergeState) {
|
||||
super();
|
||||
this.competitorId = competitorId;
|
||||
this.competitorDisplayName = competitorDisplayName;
|
||||
@@ -33,6 +36,7 @@ public class CompetitorResultImpl implements CompetitorResult {
|
||||
this.score = score;
|
||||
this.finishingTime = finishingTime;
|
||||
this.comment = comment;
|
||||
this.mergeState = mergeState;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,6 +74,11 @@ public class CompetitorResultImpl implements CompetitorResult {
|
||||
return comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MergeState getMergeState() {
|
||||
return mergeState == null ? MergeState.OK : mergeState; // default in case of having de-serialized an old version
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
@@ -81,6 +90,7 @@ public class CompetitorResultImpl implements CompetitorResult {
|
||||
result = prime * result + ((maxPointsReason == null) ? 0 : maxPointsReason.hashCode());
|
||||
result = prime * result + oneBasedRank;
|
||||
result = prime * result + ((score == null) ? 0 : score.hashCode());
|
||||
result = prime * result + ((mergeState == null) ? 0 : mergeState.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -122,6 +132,11 @@ public class CompetitorResultImpl implements CompetitorResult {
|
||||
return false;
|
||||
} else if (!score.equals(other.score))
|
||||
return false;
|
||||
if (mergeState == null) {
|
||||
if (other.mergeState != null)
|
||||
return false;
|
||||
} else if (!mergeState.equals(other.mergeState))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -129,7 +144,7 @@ public class CompetitorResultImpl implements CompetitorResult {
|
||||
public String toString() {
|
||||
return "CompetitorResultImpl [competitorId=" + competitorId + ", competitorName=" + competitorDisplayName + ", rank="
|
||||
+ oneBasedRank + ", maxPointsReason=" + maxPointsReason + ", score=" + score + ", finishingTime="
|
||||
+ finishingTime + ", comment=" + comment + "]";
|
||||
+ finishingTime + ", comment=" + comment + ", mergeState=" + mergeState + "]";
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
|
||||
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
|
||||
import com.sap.sailing.domain.tracking.impl.TimeRangeCache;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Function;
|
||||
@@ -263,4 +264,11 @@ public class NoAddingRaceLogWrapper implements RaceLog {
|
||||
public int size() {
|
||||
return innerRaceLog.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValueSum(TimePoint from, TimePoint to, T nullElement,
|
||||
com.sap.sailing.domain.tracking.Track.Adder<T> adder, TimeRangeCache<T> cache,
|
||||
com.sap.sailing.domain.tracking.Track.TimeRangeValueCalculator<T> valueCalculator) {
|
||||
return innerRaceLog.getValueSum(from, to, nullElement, adder, cache, valueCalculator);
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -158,6 +158,7 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState {
|
||||
public void forceNewDependentStartTime(TimePoint now, final Duration startTimeDifference, final SimpleRaceLogIdentifier dependentOnRace) {
|
||||
raceLog.add(new RaceLogDependentStartTimeEventImpl(now, author, raceLog.getCurrentPassId(), dependentOnRace, startTimeDifference));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFinishingTime(TimePoint timePoint) {
|
||||
@@ -166,7 +167,10 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState {
|
||||
|
||||
@Override
|
||||
public void setFinishedTime(TimePoint timePoint) {
|
||||
raceLog.add(new RaceLogRaceStatusEventImpl(timePoint, author, raceLog.getCurrentPassId(), RaceLogRaceStatus.FINISHED));
|
||||
raceLog.add(new RaceLogRaceStatusEventImpl(timePoint, author, raceLog.getCurrentPassId(),
|
||||
RaceLogRaceStatus.FINISHED));
|
||||
// ensure caches are synched
|
||||
forceUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import java.io.Serializable;
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.impl.AbstractLogEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.WithID;
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public class RegattaLogDeviceCompetitorMappingEventImpl extends RegattaLogDeviceMappingEventImpl<Competitor> implements
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public class RegattaLogDeviceMarkMappingEventImpl extends RegattaLogDeviceMappingEventImpl<Mark> implements
|
||||
|
||||
+1
-1
@@ -10,8 +10,8 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompeti
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingWithRegattaLogEventImpl;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMapping
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.domain.racelogtracking;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMappingFinder;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.WithID;
|
||||
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.racelogtracking;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
|
||||
|
||||
|
||||
|
||||
+2
@@ -2,6 +2,8 @@ package com.sap.sailing.domain.racelogtracking;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
|
||||
|
||||
public interface SmartphoneUUIDIdentifier extends DeviceIdentifier {
|
||||
String TYPE = "smartphoneUUID";
|
||||
|
||||
+1
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.racelogtracking;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.WithID;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.PlaceHolderDeviceIdentifier;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
|
||||
+27
@@ -5,6 +5,7 @@ import java.util.Iterator;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.impl.TimeRangeCache;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Timed;
|
||||
@@ -31,6 +32,29 @@ import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
* @author Axel Uhl (d043530)
|
||||
*/
|
||||
public interface Track<FixType extends Timed> extends Serializable {
|
||||
/**
|
||||
* An adding function to be used together with {@link Track#getValueSum(TimePoint, TimePoint, Object, Adder, TimeRangeCache, TimeRangeValueCalculator)}.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
static interface Adder<T> {
|
||||
/**
|
||||
* Adds two elements of type {@code T}. Neither argument must be {@code null}.
|
||||
*/
|
||||
T add(T t1, T t2);
|
||||
}
|
||||
|
||||
static interface TimeRangeValueCalculator<T> {
|
||||
/**
|
||||
* Calculates a value for fixes across a time range. When the method is called,
|
||||
* a read lock will previously have been {@link Track#lockForRead obtained} before,
|
||||
* so an implementing class does not need to worry about acquiring the lock.
|
||||
*/
|
||||
T calculate(TimePoint from, TimePoint to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks this track for reading by the calling thread. If the thread already holds the lock for this track,
|
||||
* the hold count will be incremented. Make sure to call {@link #unlockAfterRead()} in a <code>finally</code>
|
||||
@@ -209,6 +233,8 @@ public interface Track<FixType extends Timed> extends Serializable {
|
||||
*/
|
||||
Duration getAverageIntervalBetweenRawFixes();
|
||||
|
||||
<T> T getValueSum(TimePoint from, TimePoint to, T nullElement, Adder<T> adder, TimeRangeCache<T> cache, TimeRangeValueCalculator<T> valueCalculator);
|
||||
|
||||
/**
|
||||
* @return the number of raw fixes contained in the Track.
|
||||
*/
|
||||
@@ -218,4 +244,5 @@ public interface Track<FixType extends Timed> extends Serializable {
|
||||
* Tells whether the collection of {@link #getRawFixes() raw fixes} (no outliers removed) is empty
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
}
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
import com.sap.sse.util.impl.ArrayListNavigableSet;
|
||||
|
||||
/**
|
||||
* This cache looks "backwards." It contains pairs whose first component represents a <code>to</code> parameter used in
|
||||
* a calculation for a time range. It is ordered by this component. The second component is a navigable, ordered set of
|
||||
* pairs where the first pair component represents a <code>from</code> parameter used in the calculation's time range
|
||||
* and the second pair component represents the result of the calculation for this parameter combination.
|
||||
* <p>
|
||||
*
|
||||
* For implementation efficiency in combination with using an {@link ArrayListNavigableSet} for the values and in order
|
||||
* to be able to efficiently extend a cache entry for a single <code>to</code> fix, the navigable sets containing the
|
||||
* <code>from</code> fixes and results are ordered such that earlier fixes come later in the set. This way, extending
|
||||
* the cache entry for a <code>to</code> fix to an earlier <code>from</code> fix only requires appending to the set.
|
||||
* <p>
|
||||
*
|
||||
* <b>Invalidation</b>: When a new fix is added to the track, all cache entries for fixes at or later than the new fix's
|
||||
* time point are removed from this cache. Additionally, the fix insertion may have an impact on the
|
||||
* {@link #getEarliestFromAndResultAtOrAfterFrom(TimePoint, TimePoint) previous fix's} validity (track smoothing) and
|
||||
* therefore on its selection for result aggregation. Therefore, if fix addition turned the previous fix invalid, the
|
||||
* cache entries for the time points at or after the previous fix also need to be removed.
|
||||
* <p>
|
||||
*
|
||||
* <b>Cache use</b>: When a result across a time range is to be computed the calculating method should first look for a
|
||||
* cache entry for the <code>to</code> parameter. If one is found, the earliest entry in the navigable set for the
|
||||
* navigable set of <code>from</code> and result values that is at or after the requested <code>from</code> time point
|
||||
* is determined. If such an entry exists, the result is remembered and the algorithm is repeated recursively, using the
|
||||
* <code>from</code> value found in the cache as the new <code>to</code> value, and the <code>from</code> value
|
||||
* originally passed to the calculating method as <code>from</code> again. If no entry is found in the cache entry for
|
||||
* <code>to</code> that is at or after the requested <code>from</code> time, the result has to be computed "from
|
||||
* scratch."
|
||||
* <p>
|
||||
*
|
||||
* If a cache entry for <code>to</code> is not found, the latest cache entry before it is looked up. If one is found,
|
||||
* the result for the time range between the <code>to</code> time point requested and the <code>to</code> time point
|
||||
* found in the cache is computed by iterating the smoothened fixes for this interval. If none is found, the result is
|
||||
* computed by iterating backwards all the way to <code>from</code>.
|
||||
* <p>
|
||||
*
|
||||
* Once the calculating method has computed its value, it should {@link #cache(TimePoint, TimePoint, Object) add} the
|
||||
* result to the cache.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*/
|
||||
public class TimeRangeCache<T> {
|
||||
public static final int MAX_SIZE = 100;
|
||||
|
||||
private final NavigableSet<Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>>> timeRangeCache;
|
||||
|
||||
/**
|
||||
* The cache is to have limited size. Eviction shall happen based on a least-recently-used strategy. Usage is
|
||||
* defined as having been returned by {@link #getEarliestFromAndResultAtOrAfterFrom(TimePoint, TimePoint)} or
|
||||
* having been added by {@link #cache(TimePoint, TimePoint, Object)}.
|
||||
* <p>
|
||||
*
|
||||
* When an eldest entry is asked to be expunged from this map and the map has more than {@link #MAX_SIZE} elements,
|
||||
* the expunging will be admitted, and the entry is removed from the {@link #timeRangeCache} core structure. Reading
|
||||
* and writing this structure must happen under the {@link #lock write lock} because also reading the linked hash
|
||||
* map that counts access as "use" has a modifying effect on its internal structures.
|
||||
* <p>
|
||||
*
|
||||
* The key pairs are from/to pairs. Note that this is in some sense "the opposite direction" compared to the
|
||||
* alignment of the {@link #timeRangeCache} structure which has as its outer keys the "to" time point.<p>
|
||||
*
|
||||
* Read access is to be <code>synchronized<code> using this field's mutex; write access only happens under the
|
||||
* {@link #lock write lock} and therefore will have no contenders.
|
||||
*/
|
||||
private final LinkedHashMap<Util.Pair<TimePoint, TimePoint>, Void> lruCache;
|
||||
|
||||
private final NamedReentrantReadWriteLock lock;
|
||||
|
||||
private static final Comparator<Util.Pair<TimePoint, ?>> timePointInPairComparator = new Comparator<Util.Pair<TimePoint, ?>>() {
|
||||
@Override
|
||||
public int compare(Util.Pair<TimePoint, ?> o1, Util.Pair<TimePoint, ?> o2) {
|
||||
return o1.getA().compareTo(o2.getA());
|
||||
}
|
||||
};
|
||||
|
||||
public TimeRangeCache(String nameForLockLogging) {
|
||||
lock = new NamedReentrantReadWriteLock("lock for TimeRangeCache for "+nameForLockLogging, /* fair */ true);
|
||||
this.timeRangeCache = new ArrayListNavigableSet<Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>>>(timePointInPairComparator);
|
||||
this.lruCache = new LinkedHashMap<Util.Pair<TimePoint, TimePoint>, Void>(/* initial capacity */ 10, /* load factor */ 0.75f,
|
||||
/* access-based ordering */ true) {
|
||||
private static final long serialVersionUID = -6568235517111733193L;
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Entry<Pair<TimePoint, TimePoint>, Void> eldest) {
|
||||
final boolean expunge = size() > MAX_SIZE;
|
||||
if (expunge) {
|
||||
removeCacheEntry(eldest.getKey().getA(), eldest.getKey().getB());
|
||||
}
|
||||
return expunge;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return lruCache.size();
|
||||
}
|
||||
|
||||
private void removeCacheEntry(TimePoint from, TimePoint to) {
|
||||
assert lock.getWriteHoldCount() == 1; // we can be sure we are alone here; this only happens when adding a new entry, holding the write lock
|
||||
Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>> entryForTo = timeRangeCache.floor(createDummy(to));
|
||||
if (entryForTo.getA().equals(to)) {
|
||||
Pair<TimePoint, T> entryForFrom = entryForTo.getB().ceiling(new Util.Pair<TimePoint, T>(from, null));
|
||||
if (entryForFrom.getA().equals(from)) {
|
||||
entryForTo.getB().remove(entryForFrom);
|
||||
if (entryForTo.getB().isEmpty()) {
|
||||
timeRangeCache.remove(entryForTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the entry closest to but no later than <code>to</code>. If not found, <code>null</code> is returned. If
|
||||
* found, the earliest pair of from/result that is at or after <code>from</code> will be returned, together with
|
||||
* the <code>to</code> value of the entry. If there is no entry that is at or after <code>from</code>,
|
||||
* <code>null</code> is returned.
|
||||
*/
|
||||
public Util.Pair<TimePoint, Util.Pair<TimePoint, T>> getEarliestFromAndResultAtOrAfterFrom(TimePoint from, TimePoint to) {
|
||||
LockUtil.lockForRead(lock);
|
||||
try {
|
||||
Util.Pair<TimePoint, Util.Pair<TimePoint, T>> result = null;
|
||||
Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>> entryForTo = timeRangeCache.floor(createDummy(to));
|
||||
if (entryForTo != null) {
|
||||
final Util.Pair<TimePoint, T> fromCeiling = entryForTo.getB().ceiling(new Util.Pair<TimePoint, T>(from, null));
|
||||
if (fromCeiling != null) {
|
||||
result = new Util.Pair<TimePoint, Util.Pair<TimePoint, T>>(entryForTo.getA(), fromCeiling);
|
||||
}
|
||||
}
|
||||
// no writer can be active because we're holding the read lock; read access on the lruCache is synchronized using
|
||||
// the lruCache's mutex; this is necessary because we're using access-based LRU pinging where even getting an entry
|
||||
// modifies the internal parts of the data structure which is not thread safe.
|
||||
synchronized (lruCache) {
|
||||
lruCache.get(new Util.Pair<TimePoint, TimePoint>(from, to));
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
LockUtil.unlockAfterRead(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all cache entries that have a <code>to</code> time point that is at or after <code>timePoint</code>.
|
||||
*/
|
||||
public void invalidateAllAtOrLaterThan(TimePoint timePoint) {
|
||||
LockUtil.lockForWrite(lock);
|
||||
try {
|
||||
Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>> dummy = createDummy(timePoint);
|
||||
NavigableSet<Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>>> toRemove = timeRangeCache.tailSet(dummy, /* inclusive */ true);
|
||||
for (Iterator<Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>>> i=toRemove.iterator(); i.hasNext(); ) {
|
||||
Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>> entryToRemove = i.next();
|
||||
assert entryToRemove.getA().compareTo(timePoint) >= 0;
|
||||
for (Pair<TimePoint, T> fromAndResult : entryToRemove.getB()) {
|
||||
lruCache.remove(new Util.Pair<>(fromAndResult.getA(), entryToRemove.getA()));
|
||||
}
|
||||
i.remove();
|
||||
}
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
}
|
||||
}
|
||||
|
||||
private NavigableSet<Util.Pair<TimePoint, T>> getEntryForTo(TimePoint to) {
|
||||
NavigableSet<Util.Pair<TimePoint, T>> result = null;
|
||||
Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>> dummyForTo = createDummy(to);
|
||||
Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>> entryForTo = timeRangeCache.floor(dummyForTo);
|
||||
if (entryForTo != null && entryForTo.getA().equals(to)) {
|
||||
result = entryForTo.getB();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void cache(TimePoint from, TimePoint to, T result) {
|
||||
LockUtil.lockForWrite(lock);
|
||||
try {
|
||||
NavigableSet<Util.Pair<TimePoint, T>> entryForTo = getEntryForTo(to);
|
||||
if (entryForTo == null) {
|
||||
entryForTo = new ArrayListNavigableSet<Util.Pair<TimePoint, T>>(timePointInPairComparator);
|
||||
Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>> pairForTo = new Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>>(
|
||||
to, entryForTo);
|
||||
timeRangeCache.add(pairForTo);
|
||||
}
|
||||
entryForTo.add(new Util.Pair<TimePoint, T>(from, result));
|
||||
lruCache.put(new Util.Pair<TimePoint, TimePoint>(from, to), null);
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
}
|
||||
}
|
||||
|
||||
private Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>> createDummy(TimePoint to) {
|
||||
return new Util.Pair<TimePoint, NavigableSet<Util.Pair<TimePoint, T>>>(to, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all contents from this cache
|
||||
*/
|
||||
public void clear() {
|
||||
LockUtil.lockForWrite(lock);
|
||||
try {
|
||||
timeRangeCache.clear();
|
||||
lruCache.clear();
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+59
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Function;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
@@ -459,6 +460,64 @@ public class TrackImpl<FixType extends Timed> implements Track<FixType> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValueSum(TimePoint from, TimePoint to, T nullElement, Adder<T> adder, TimeRangeCache<T> cache, TimeRangeValueCalculator<T> valueCalculator) {
|
||||
return getValueSumRecursively(from, to, /* recursionLevel */ 0, nullElement, adder, cache, valueCalculator);
|
||||
}
|
||||
|
||||
private <T> T getValueSumRecursively(TimePoint from, TimePoint to, int recursionDepth, T nullElement,
|
||||
Adder<T> adder, TimeRangeCache<T> cache, TimeRangeValueCalculator<T> valueCalculator) {
|
||||
T result;
|
||||
if (!from.before(to)) {
|
||||
result = nullElement;
|
||||
} else {
|
||||
boolean perfectCacheHit = false;
|
||||
lockForRead();
|
||||
try {
|
||||
Util.Pair<TimePoint, Util.Pair<TimePoint, T>> bestCacheEntry = cache.getEarliestFromAndResultAtOrAfterFrom(from, to);
|
||||
if (bestCacheEntry != null) {
|
||||
perfectCacheHit = true; // potentially a cache hit; but if it doesn't span the full interval, it's not perfect; see below
|
||||
// compute the missing stretches between best cache entry's "from" and our "from" and the cache
|
||||
// entry's "to" and our "to"
|
||||
T valueFromFromToBeginningOfCacheEntry = nullElement;
|
||||
T valueFromEndOfCacheEntryToTo = nullElement;
|
||||
if (!bestCacheEntry.getB().getA().equals(from)) {
|
||||
assert bestCacheEntry.getB().getA().after(from);
|
||||
perfectCacheHit = false;
|
||||
valueFromFromToBeginningOfCacheEntry = getValueSumRecursively(from, bestCacheEntry
|
||||
.getB().getA(), recursionDepth + 1, nullElement, adder, cache, valueCalculator);
|
||||
}
|
||||
if (!bestCacheEntry.getA().equals(to)) {
|
||||
assert bestCacheEntry.getA().before(to);
|
||||
perfectCacheHit = false;
|
||||
valueFromEndOfCacheEntryToTo = getValueSumRecursively(bestCacheEntry.getA(), to,
|
||||
recursionDepth + 1, nullElement, adder, cache, valueCalculator);
|
||||
}
|
||||
if (valueFromEndOfCacheEntryToTo == null || bestCacheEntry.getB().getB() == null) {
|
||||
result = null;
|
||||
} else {
|
||||
result = adder.add(adder.add(valueFromFromToBeginningOfCacheEntry, bestCacheEntry.getB().getB()),
|
||||
valueFromEndOfCacheEntryToTo);
|
||||
}
|
||||
} else {
|
||||
if (from.compareTo(to) < 0) {
|
||||
result = valueCalculator.calculate(from, to);
|
||||
} else {
|
||||
result = nullElement;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
unlockAfterRead();
|
||||
}
|
||||
if (!perfectCacheHit && recursionDepth == 0) {
|
||||
cache.cache(from, to, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return fixes.size();
|
||||
|
||||
@@ -46,6 +46,16 @@ public class BearingTest {
|
||||
assertNull(new BearingWithConfidenceCluster<Void>(null).getAverage(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegativeAngle() {
|
||||
assertEquals(-10., new DegreeBearingImpl(-10.).getDegrees(), 0.000001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegativeAngleOverflow() {
|
||||
assertEquals(-10., new DegreeBearingImpl(-370.).getDegrees(), 0.000001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroConfidenceLeadsToNullBearingAverage() {
|
||||
BearingWithConfidenceCluster<Void> cluster = new BearingWithConfidenceCluster<Void>(null);
|
||||
|
||||
+9
-7
@@ -207,27 +207,29 @@ public class CompetitorProviderCacheInvalidationTest extends AbstractLeaderboard
|
||||
for (Competitor c : compLists[1]) {
|
||||
raceLog.add(new RaceLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), new LogEventAuthorImpl("Me", 0), 1, c));
|
||||
}
|
||||
Set<Competitor> allCompetitors = new HashSet<>();
|
||||
allCompetitors.addAll(compLists[0]);
|
||||
allCompetitors.addAll(compLists[1]);
|
||||
// expected are only the competitors in the RaceLog, because only one RaceColumn is
|
||||
// registered, which has the competitors registered in the RaceLog.
|
||||
assertRegattaAndRaceCompetitors(new HashSet<>(compLists[1]));
|
||||
assertRegattaAndRaceCompetitors(allCompetitors, new HashSet<>(compLists[1]));
|
||||
// Now we revoke that the race log provides the competitors for R1; the competitors should then
|
||||
// snap back to those competitors taken from the regatta log for both, the rentire leaderboard
|
||||
// as well as for the race column
|
||||
raceLog.revokeEvent(author, usesCompetitorsFromRaceLogEvent);
|
||||
assertRegattaAndRaceCompetitors(new HashSet<>(compLists[0]));
|
||||
assertRegattaAndRaceCompetitors(new HashSet<>(compLists[0]), new HashSet<>(compLists[0]));
|
||||
// And now re-introduce per-race competitors and validate again that the cache adjusts properly:
|
||||
raceLog.add(new RaceLogUseCompetitorsFromRaceLogEventImpl(MillisecondsTimePoint.now(), author, MillisecondsTimePoint.now(), UUID.randomUUID(), passId));
|
||||
assertRegattaAndRaceCompetitors(new HashSet<>(compLists[1]));
|
||||
assertRegattaAndRaceCompetitors(allCompetitors, new HashSet<>(compLists[1]));
|
||||
}
|
||||
|
||||
private void assertRegattaAndRaceCompetitors(Set<Competitor> expected) {
|
||||
private void assertRegattaAndRaceCompetitors(Set<Competitor> expectedAllCompetitors, Set<Competitor> expectedForRace) {
|
||||
Set<Competitor> actual = new HashSet<>();
|
||||
Util.addAll(competitorProviderFlexibleLeaderboard.getAllCompetitors(), actual);
|
||||
assertEquals(expected, actual);
|
||||
assertEquals(expectedAllCompetitors, actual);
|
||||
Set<Competitor> actualForRace = new HashSet<>();
|
||||
|
||||
//For the race only the competitors registered on RaceLog as RaceLogUseCompetitorsFromRaceLogEvent is present
|
||||
Set<Competitor> expectedForRace = new HashSet<>(expected);
|
||||
// For the race only the competitors registered on RaceLog as RaceLogUseCompetitorsFromRaceLogEvent is present
|
||||
Util.addAll(competitorProviderFlexibleLeaderboard.getAllCompetitors(
|
||||
flexibleLeaderboard.getRaceColumnByName("R1"),
|
||||
flexibleLeaderboard.getFleet(LeaderboardNameConstants.DEFAULT_FLEET_NAME)), actualForRace);
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ import org.junit.Test;
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResult.MergeState;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
|
||||
@@ -153,7 +154,7 @@ public class MarkPassingUpdateFromRaceLogFinishPositioingListTest extends Abstra
|
||||
int rank = 1;
|
||||
for (Pair<Competitor, TimePoint> finishingTime : finishingTimes) {
|
||||
results.add(new CompetitorResultImpl(finishingTime.getA().getId(), finishingTime.getA().getName(), rank++, /* maxPointsReason */
|
||||
null, /* score */null, finishingTime.getB(), /* comment */null));
|
||||
null, /* score */null, finishingTime.getB(), /* comment */null, MergeState.OK));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.impl.DistanceCache;
|
||||
import com.sap.sailing.domain.tracking.impl.TimeRangeCache;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.GPSFixTrackImpl;
|
||||
@@ -304,7 +304,7 @@ public class TrackTest {
|
||||
// The following getMaximumSpeedOverGround call will trigger a computeMaxSpeed(...) and a cache(...) call
|
||||
new Thread(()->
|
||||
assertEquals(1., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(7200000)).
|
||||
getB().getKnots(), 0.001)).start(); // produces a cache entry that ends
|
||||
getB().getKnots(), 0.01)).start(); // produces a cache entry that ends
|
||||
// now don't release the cacheBarrier as yet but add more fixes
|
||||
new Thread(() -> {
|
||||
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(3600000),
|
||||
@@ -442,7 +442,7 @@ public class TrackTest {
|
||||
@Test
|
||||
public void testDistanceTraveledBackwardsQuery() {
|
||||
final Set<com.sap.sse.common.Util.Triple<TimePoint, TimePoint, Distance>> cacheEntries = new HashSet<>();
|
||||
final DistanceCache distanceCache = new DistanceCache("test-DistanceCache") {
|
||||
final TimeRangeCache<Distance> distanceCache = new TimeRangeCache<Distance>("test-DistanceCache") {
|
||||
@Override
|
||||
public void cache(TimePoint from, TimePoint to, Distance distance) {
|
||||
super.cache(from, to, distance);
|
||||
@@ -453,7 +453,7 @@ public class TrackTest {
|
||||
DynamicGPSFixTrack<Object, GPSFix> track = new DynamicGPSFixTrackImpl<Object>(new Object(), /* millisecondsOverWhichToAverage */ 30000l) {
|
||||
private static final long serialVersionUID = -7277196393160609503L;
|
||||
@Override
|
||||
protected DistanceCache getDistanceCache() {
|
||||
protected TimeRangeCache<Distance> getDistanceCache() {
|
||||
return distanceCache;
|
||||
}
|
||||
};
|
||||
@@ -779,7 +779,7 @@ public class TrackTest {
|
||||
@Test
|
||||
public void testDistanceTraveledOnSmoothenedTrackThenAddingOutlier() {
|
||||
final Set<TimePoint> invalidationCalls = new HashSet<TimePoint>();
|
||||
final DistanceCache distanceCache = new DistanceCache("test-DistanceCache") {
|
||||
final TimeRangeCache<Distance> distanceCache = new TimeRangeCache<Distance>("test-DistanceCache") {
|
||||
@Override
|
||||
public void invalidateAllAtOrLaterThan(TimePoint timePoint) {
|
||||
super.invalidateAllAtOrLaterThan(timePoint);
|
||||
@@ -789,7 +789,7 @@ public class TrackTest {
|
||||
DynamicGPSFixTrack<Object, GPSFix> track = new DynamicGPSFixTrackImpl<Object>(new Object(), /* millisecondsOverWhichToAverage */ 30000l) {
|
||||
private static final long serialVersionUID = -7277196393160609503L;
|
||||
@Override
|
||||
protected DistanceCache getDistanceCache() {
|
||||
protected TimeRangeCache<Distance> getDistanceCache() {
|
||||
return distanceCache;
|
||||
}
|
||||
};
|
||||
@@ -811,7 +811,7 @@ public class TrackTest {
|
||||
}
|
||||
invalidationCalls.clear();
|
||||
assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.02);
|
||||
final com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> fullIntervalCacheEntry = distanceCache.getEarliestFromAndDistanceAtOrAfterFrom(now, start);
|
||||
final com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> fullIntervalCacheEntry = distanceCache.getEarliestFromAndResultAtOrAfterFrom(now, start);
|
||||
assertNotNull(fullIntervalCacheEntry); // no more entry for "to"-value start in cache
|
||||
assertEquals(start, fullIntervalCacheEntry.getA());
|
||||
assertEquals(now, fullIntervalCacheEntry.getB().getA());
|
||||
@@ -822,13 +822,13 @@ public class TrackTest {
|
||||
assertEquals(1, invalidationCalls.size());
|
||||
TimePoint timePointOfLastFixBeforeOutlier = track.getLastFixBefore(timePointForOutlier).getTimePoint();
|
||||
assertTrue(invalidationCalls.iterator().next().after(timePointOfLastFixBeforeOutlier)); // outlier doesn't turn its preceding element into an outlier
|
||||
assertNull(distanceCache.getEarliestFromAndDistanceAtOrAfterFrom(now, start)); // no more entry for "to"-value start in cache
|
||||
assertNull(distanceCache.getEarliestFromAndResultAtOrAfterFrom(now, start)); // no more entry for "to"-value start in cache
|
||||
invalidationCalls.clear();
|
||||
final TimePoint timePointOfLastOriginalFix = track.getLastRawFix().getTimePoint();
|
||||
assertEquals(speed.getMetersPerSecond() * (steps - 1),
|
||||
track.getDistanceTraveled(now, timePointOfLastOriginalFix).getMeters(), 0.02);
|
||||
final com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> newFullIntervalCacheEntry = distanceCache
|
||||
.getEarliestFromAndDistanceAtOrAfterFrom(now, timePointOfLastOriginalFix);
|
||||
.getEarliestFromAndResultAtOrAfterFrom(now, timePointOfLastOriginalFix);
|
||||
assertNotNull(newFullIntervalCacheEntry); // no more entry for "to"-value start in cache
|
||||
assertEquals(timePointOfLastOriginalFix, newFullIntervalCacheEntry.getA());
|
||||
assertEquals(now, newFullIntervalCacheEntry.getB().getA());
|
||||
@@ -845,7 +845,7 @@ public class TrackTest {
|
||||
invalidationCalls.clear();
|
||||
// expect the invalidation to have started after the single cache entry, so the cache entry still has to be there:
|
||||
final com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> stillPresentFullIntervalCacheEntry = distanceCache
|
||||
.getEarliestFromAndDistanceAtOrAfterFrom(now, timePointOfLastOriginalFix);
|
||||
.getEarliestFromAndResultAtOrAfterFrom(now, timePointOfLastOriginalFix);
|
||||
assertNull(stillPresentFullIntervalCacheEntry); // no more entry for "to"-value start in cache because new temporary outlier lies in previously cached interval
|
||||
GPSFix polishedLastFix = track.getLastFixBefore(new MillisecondsTimePoint(Long.MAX_VALUE)); // get the last smoothened fix...
|
||||
// ...which now is expected to be two fixes before lateOutlier because lateOutlier has previous fixes within the time range
|
||||
@@ -870,7 +870,7 @@ public class TrackTest {
|
||||
assertTrue(timePointForLateOutlier.compareTo(fix.getTimePoint()) < 0);
|
||||
// expect the invalidation to have started at the fix before the outlier, leaving the previous result ending at the fix right before the outlier intact
|
||||
final com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> stillStillPresentFullIntervalCacheEntry = distanceCache
|
||||
.getEarliestFromAndDistanceAtOrAfterFrom(now, timePointOfLastOriginalFix);
|
||||
.getEarliestFromAndResultAtOrAfterFrom(now, timePointOfLastOriginalFix);
|
||||
assertNull(stillStillPresentFullIntervalCacheEntry); // still nothing in the cache
|
||||
track.lockForRead();
|
||||
try {
|
||||
@@ -955,11 +955,11 @@ public class TrackTest {
|
||||
final Duration raceDuration = Duration.ONE_HOUR.times(48);
|
||||
final Speed speed = new KnotSpeedImpl(12);
|
||||
final Distance distancePerSample = speed.travel(fixTime, fixTime.plus(samplingInterval));
|
||||
final DistanceCache distanceCache = new DistanceCache("test-DistanceCache");
|
||||
final TimeRangeCache<Distance> distanceCache = new TimeRangeCache<>("test-DistanceCache");
|
||||
DynamicGPSFixTrack<Object, GPSFix> track = new DynamicGPSFixTrackImpl<Object>(new Object(), /* millisecondsOverWhichToAverage */ 30000l) {
|
||||
private static final long serialVersionUID = -7277196393160609503L;
|
||||
@Override
|
||||
protected DistanceCache getDistanceCache() {
|
||||
protected TimeRangeCache<Distance> getDistanceCache() {
|
||||
return distanceCache;
|
||||
}
|
||||
};
|
||||
@@ -980,13 +980,13 @@ public class TrackTest {
|
||||
queryTime = queryTime.plus(queryInterval);
|
||||
}
|
||||
}
|
||||
assertTrue(distanceCache.size() <= DistanceCache.MAX_SIZE);
|
||||
assertTrue(distanceCache.size() <= TimeRangeCache.MAX_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistanceCacheAccessForPartialStrip() {
|
||||
final Set<TimePoint> invalidationCalls = new HashSet<TimePoint>();
|
||||
final DistanceCache distanceCache = new DistanceCache("test-DistanceCache") {
|
||||
final TimeRangeCache<Distance> distanceCache = new TimeRangeCache<Distance>("test-DistanceCache") {
|
||||
@Override
|
||||
public void invalidateAllAtOrLaterThan(TimePoint timePoint) {
|
||||
super.invalidateAllAtOrLaterThan(timePoint);
|
||||
@@ -996,7 +996,7 @@ public class TrackTest {
|
||||
DynamicGPSFixTrack<Object, GPSFix> track = new DynamicGPSFixTrackImpl<Object>(new Object(), /* millisecondsOverWhichToAverage */ 30000l) {
|
||||
private static final long serialVersionUID = -7277196393160609503L;
|
||||
@Override
|
||||
protected DistanceCache getDistanceCache() {
|
||||
protected TimeRangeCache<Distance> getDistanceCache() {
|
||||
return distanceCache;
|
||||
}
|
||||
};
|
||||
@@ -1024,11 +1024,11 @@ public class TrackTest {
|
||||
assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.02);
|
||||
assertTrue(invalidationCalls.isEmpty());
|
||||
// expect a cache entry exactly for the strip's boundaries
|
||||
com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> stripCacheEntry = distanceCache.getEarliestFromAndDistanceAtOrAfterFrom(stripFrom, stripTo);
|
||||
com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> stripCacheEntry = distanceCache.getEarliestFromAndResultAtOrAfterFrom(stripFrom, stripTo);
|
||||
assertEquals(stripTo, stripCacheEntry.getA());
|
||||
assertEquals(stripFrom, stripCacheEntry.getB().getA());
|
||||
// expect a cache entry exactly for the full boundaries
|
||||
com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> fullCacheEntry = distanceCache.getEarliestFromAndDistanceAtOrAfterFrom(now, start);
|
||||
com.sap.sse.common.Util.Pair<TimePoint, com.sap.sse.common.Util.Pair<TimePoint, Distance>> fullCacheEntry = distanceCache.getEarliestFromAndResultAtOrAfterFrom(now, start);
|
||||
assertEquals(start, fullCacheEntry.getA());
|
||||
assertEquals(now, fullCacheEntry.getB().getA());
|
||||
}
|
||||
|
||||
+16
@@ -674,6 +674,16 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getDistanceFoiled(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getDurationFoiled(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint,
|
||||
WindPositionMode windPositionMode) {
|
||||
@@ -1155,4 +1165,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
public Speed getAverageSpeedOverGround(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getVelocityMadeGood(Competitor competitor, TimePoint timePoint,
|
||||
WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+17
@@ -60,6 +60,7 @@ import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.IsManagedByCache;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -360,6 +361,16 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getDistanceFoiled(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getDurationFoiled(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) {
|
||||
return null;
|
||||
@@ -707,4 +718,10 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
public Speed getAverageSpeedOverGround(Competitor competitor, TimePoint timePoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getVelocityMadeGood(Competitor competitor, TimePoint timePoint,
|
||||
WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+27
-1
@@ -269,7 +269,7 @@ public interface Leaderboard extends LeaderboardBase, HasRaceColumns {
|
||||
* competitor doesn't appear in any of the race column's attached tracked races. A 0.0 score is returned
|
||||
* if the competitor's result for <code>race</code> is discarded.
|
||||
*/
|
||||
Double getNetPoints(Competitor competitor, RaceColumn race, TimePoint timePoint) throws NoWindException;
|
||||
Double getNetPoints(Competitor competitor, RaceColumn race, TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Tells whether the contribution of <code>raceColumn</code> is discarded in the current leaderboard's standings for
|
||||
@@ -481,6 +481,26 @@ public interface Leaderboard extends LeaderboardBase, HasRaceColumns {
|
||||
* leaderboard
|
||||
*/
|
||||
Distance getTotalDistanceTraveled(Competitor competitor, TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Computes the distance the <code>competitor</code> has been foiling in the tracked races in this leaderboard, starting
|
||||
* to count in each race when the competitor passes the start line, aggregating up to <code>timePoint</code> or the
|
||||
* end of the last race, whichever is first.
|
||||
*
|
||||
* @return <code>null</code> if the <code>competitor</code> hasn't foiled any distance in any tracked race in this
|
||||
* leaderboard
|
||||
*/
|
||||
Distance getTotalDistanceFoiled(Competitor competitor, TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Computes the duration the <code>competitor</code> has foiled in the tracked races in this leaderboard, starting
|
||||
* to count in each race when the competitor passes the start line, aggregating up to <code>timePoint</code> or the
|
||||
* end of the last race, whichever is first.
|
||||
*
|
||||
* @return <code>null</code> if the <code>competitor</code> hasn't foiled at any time in any tracked race in this
|
||||
* leaderboard
|
||||
*/
|
||||
Duration getTotalDurationFoiled(Competitor competitor, TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Same as {@link #getNetPoints(Competitor, RaceColumn, TimePoint)}, only that for determining the discarded
|
||||
@@ -568,4 +588,10 @@ public interface Leaderboard extends LeaderboardBase, HasRaceColumns {
|
||||
BoatClass getBoatClass();
|
||||
|
||||
LeaderboardType getLeaderboardType();
|
||||
|
||||
/**
|
||||
* Tells if there is at least one non-{@code null} score for the given {@code competitor} in the
|
||||
* leaderboard.
|
||||
*/
|
||||
boolean hasScores(Competitor competitor, TimePoint timePoint);
|
||||
}
|
||||
+45
-6
@@ -19,6 +19,7 @@ import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -642,8 +643,12 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
|
||||
row.totalTimeSailedReachingInSeconds = totalTimeSailedReaching==null?null:totalTimeSailedReaching.asSeconds();
|
||||
final Duration totalTimeSailed = this.getTotalTimeSailed(competitor, timePoint);
|
||||
row.totalTimeSailedInSeconds = totalTimeSailed==null?null:totalTimeSailed.asSeconds();
|
||||
final Distance totalDistanceTraveledInMeters = this.getTotalDistanceTraveled(competitor, timePoint);
|
||||
row.totalDistanceTraveledInMeters = totalDistanceTraveledInMeters==null?null:totalDistanceTraveledInMeters.getMeters();
|
||||
final Distance totalDistanceTraveled = this.getTotalDistanceTraveled(competitor, timePoint);
|
||||
row.totalDistanceTraveledInMeters = totalDistanceTraveled==null?null:totalDistanceTraveled.getMeters();
|
||||
final Distance totalDistanceFoiled = this.getTotalDistanceFoiled(competitor, timePoint);
|
||||
row.totalDistanceFoiledInMeters = totalDistanceFoiled==null?null:totalDistanceFoiled.getMeters();
|
||||
final Duration totalDurationFoiled = this.getTotalDurationFoiled(competitor, timePoint);
|
||||
row.totalDurationFoiledInSeconds = totalDurationFoiled==null?null:totalDurationFoiled.asSeconds();
|
||||
}
|
||||
|
||||
private LeaderboardDTOCache getLeaderboardDTOCache() {
|
||||
@@ -821,6 +826,12 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
|
||||
result.currentHeelInDegrees = heel == null ? null : heel.getDegrees();
|
||||
Bearing pitch = trackedLeg.getPitch(timePoint);
|
||||
result.currentPitchInDegrees = pitch == null ? null : pitch.getDegrees();
|
||||
|
||||
Distance distanceFoiled = trackedLeg.getDistanceFoiled(timePoint);
|
||||
result.currentDistanceFoiledInMeters = distanceFoiled == null ? null : distanceFoiled.getMeters();
|
||||
Duration durationFoiled = trackedLeg.getDurationFoiled(timePoint);
|
||||
result.currentDurationFoiledInSeconds = durationFoiled == null ? null : durationFoiled.asSeconds();
|
||||
|
||||
result.currentSpeedOverGroundInKnots = speedOverGroundInKnots == null ? null : speedOverGroundInKnots;
|
||||
Distance distanceTraveled = trackedLeg.getDistanceTraveled(timePoint);
|
||||
result.distanceTraveledInMeters = distanceTraveled == null ? null : distanceTraveled.getMeters();
|
||||
@@ -858,7 +869,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
|
||||
if (trackedLeg.hasFinishedLeg(timePoint)) {
|
||||
velocityMadeGood = trackedLeg.getAverageVelocityMadeGood(timePoint);
|
||||
} else {
|
||||
velocityMadeGood = trackedLeg.getVelocityMadeGood(timePoint, WindPositionMode.EXACT);
|
||||
velocityMadeGood = trackedLeg.getVelocityMadeGood(timePoint, WindPositionMode.EXACT, cache);
|
||||
}
|
||||
result.velocityMadeGoodInKnots = velocityMadeGood == null ? null : velocityMadeGood.getKnots();
|
||||
Distance windwardDistanceToGo = trackedLeg.getWindwardDistanceToGo(timePoint, WindPositionMode.LEG_MIDDLE);
|
||||
@@ -1082,18 +1093,37 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
|
||||
|
||||
@Override
|
||||
public Distance getTotalDistanceTraveled(Competitor competitor, TimePoint timePoint) {
|
||||
Distance result = null;
|
||||
return getTotals(competitor, timePoint, Distance::add, TrackedRace::getDistanceTraveled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getTotalDistanceFoiled(Competitor competitor, TimePoint timePoint) {
|
||||
return getTotals(competitor, timePoint, Distance::add, TrackedRace::getDistanceFoiled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTotalDurationFoiled(Competitor competitor, TimePoint timePoint) {
|
||||
return getTotals(competitor, timePoint, Duration::plus, TrackedRace::getDurationFoiled);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private static interface ValueFromRaceGetter<T> {
|
||||
T get(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint);
|
||||
}
|
||||
|
||||
private <T> T getTotals(Competitor competitor, TimePoint timePoint, BiFunction<T, T, T> adder, ValueFromRaceGetter<T> valueGetter) {
|
||||
T result = null;
|
||||
for (TrackedRace trackedRace : getTrackedRaces()) {
|
||||
TimePoint startOfRace;
|
||||
if (Util.contains(trackedRace.getRace().getCompetitors(), competitor) &&
|
||||
(startOfRace=trackedRace.getStartOfRace()) != null &&
|
||||
!startOfRace.after(timePoint)) {
|
||||
Distance distanceSailedInRace = trackedRace.getDistanceTraveled(competitor, timePoint);
|
||||
T distanceSailedInRace = valueGetter.get(trackedRace, competitor, timePoint);
|
||||
if (distanceSailedInRace != null) {
|
||||
if (result == null) {
|
||||
result = distanceSailedInRace;
|
||||
} else {
|
||||
result = result.add(distanceSailedInRace);
|
||||
result = adder.apply(result, distanceSailedInRace);
|
||||
}
|
||||
} else {
|
||||
// if competitor has not finished one single race in the whole
|
||||
@@ -1118,4 +1148,13 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasScores(Competitor competitor, TimePoint timePoint) {
|
||||
for (final RaceColumn raceColumn : getRaceColumns()) {
|
||||
if (getTotalPoints(competitor, raceColumn, timePoint) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -425,13 +425,13 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) throws NoWindException {
|
||||
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
return getNetPoints(competitor, raceColumn, getRaceColumns(), timePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn,
|
||||
Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) throws NoWindException {
|
||||
Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
|
||||
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule()
|
||||
.getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
|
||||
return getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns);
|
||||
|
||||
+4
-8
@@ -181,9 +181,7 @@ public class CompetitorProviderFromRaceColumnsAndRegattaLike {
|
||||
if (allCompetitorsCache == null) {
|
||||
final Set<Competitor> result = new HashSet<>();
|
||||
final Set<RaceDefinition> raceDefinitions = new HashSet<>();
|
||||
boolean hasRaceColumns = false;
|
||||
for (RaceColumn rc : provider.getRaceColumns()) {
|
||||
hasRaceColumns = true;
|
||||
final Pair<Iterable<RaceDefinition>, Iterable<Competitor>> allCompetitorsInRaceColumnWithRaceDefinitionsConsidered = rc.getAllCompetitorsWithRaceDefinitionsConsidered();
|
||||
Util.addAll(allCompetitorsInRaceColumnWithRaceDefinitionsConsidered.getB(), result);
|
||||
Util.addAll(allCompetitorsInRaceColumnWithRaceDefinitionsConsidered.getA(), raceDefinitions);
|
||||
@@ -192,12 +190,10 @@ public class CompetitorProviderFromRaceColumnsAndRegattaLike {
|
||||
}
|
||||
}
|
||||
final RegattaLog regattaLog = provider.getRegattaLike().getRegattaLog();
|
||||
if (!hasRaceColumns) {
|
||||
// If no race exists, the regatta log-provided competitor registrations will not have
|
||||
// been considered yet; add them:
|
||||
final Set<Competitor> regattaLogProvidedCompetitors = new CompetitorsInLogAnalyzer<>(regattaLog).analyze();
|
||||
result.addAll(regattaLogProvidedCompetitors);
|
||||
}
|
||||
// If no race exists, the regatta log-provided competitor registrations will not have
|
||||
// been considered yet; add them:
|
||||
final Set<Competitor> regattaLogProvidedCompetitors = new CompetitorsInLogAnalyzer<>(regattaLog).analyze();
|
||||
result.addAll(regattaLogProvidedCompetitors);
|
||||
// else, don't add regatta log competitors because they have been added in each column already.
|
||||
// The competitors are collected from the races. Those, however, will be the regatta log
|
||||
// competitors if the race does not define its own.
|
||||
|
||||
+1
-1
@@ -280,7 +280,7 @@ public class DelegatingRegattaLeaderboardWithCompetitorElimination extends Abstr
|
||||
return getFullLeaderboard().getMaxPointsReason(competitor, race, timePoint);
|
||||
}
|
||||
|
||||
public Double getNetPoints(Competitor competitor, RaceColumn race, TimePoint timePoint) throws NoWindException {
|
||||
public Double getNetPoints(Competitor competitor, RaceColumn race, TimePoint timePoint) {
|
||||
return getFullLeaderboard().getNetPoints(competitor, race, timePoint);
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 1539 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user