mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-05 03:43:52 +00:00
Merge remote-tracking branch 'origin/raceboard-simulation'
This commit is contained in:
commit
0c759f2b78
144 files changed
+6844
-1621
No files matched your search
+2
@@ -30,4 +30,6 @@ public interface PolarSheetGenerationSettings extends Serializable{
|
||||
|
||||
boolean splitByWindgauges();
|
||||
|
||||
boolean areDefault();
|
||||
|
||||
}
|
||||
+1
-3
@@ -8,10 +8,8 @@ public interface PolarSheetsData extends Serializable {
|
||||
Number[][] getAveragedPolarDataByWindSpeed();
|
||||
|
||||
int getDataCount();
|
||||
|
||||
boolean isComplete();
|
||||
|
||||
Integer[] getDataCountPerAngleForWindspeed(int beaufort);
|
||||
Integer[] getDataCountPerAngleForWindspeed(int windIndex);
|
||||
|
||||
WindStepping getStepping();
|
||||
|
||||
|
||||
+10
@@ -10,4 +10,14 @@ public interface WindStepping extends Serializable{
|
||||
|
||||
Integer[] getRawStepping();
|
||||
|
||||
public abstract int getLevelIndexFloorForValue(double speed);
|
||||
|
||||
public abstract int getLevelIndexCeilingForValue(double speed);
|
||||
|
||||
double getDistanceToLevelFloor(double speed);
|
||||
|
||||
int hashCode();
|
||||
|
||||
boolean equals(Object obj);
|
||||
|
||||
}
|
||||
+83
-2
@@ -6,8 +6,8 @@ public class PolarSheetGenerationSettingsImpl implements PolarSheetGenerationSet
|
||||
|
||||
public static PolarSheetGenerationSettings createStandardPolarSettings() {
|
||||
Integer[] levels = { 4, 6, 8, 10, 12, 14, 16, 20, 25, 30 };
|
||||
WindSteppingWithMaxDistance windStepping = new WindSteppingWithMaxDistance(levels, 2.0);
|
||||
return new PolarSheetGenerationSettingsImpl(200, 0.1, 10, 20, 0.1, true, true, 2, 0.05, true, windStepping,
|
||||
WindSteppingWithMaxDistance windStepping = new WindSteppingWithMaxDistance(levels, 2.5);
|
||||
return new PolarSheetGenerationSettingsImpl(50, 0.1, 20, 20, 0.1, true, true, 2, 0.05, true, windStepping,
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -108,4 +108,85 @@ public class PolarSheetGenerationSettingsImpl implements PolarSheetGenerationSet
|
||||
return splitByWindGauges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areDefault() {
|
||||
return createStandardPolarSettings().equals(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(minimumConfidenceMeasure);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
result = prime * result + ((minimumDataCountPerAngle == null) ? 0 : minimumDataCountPerAngle.hashCode());
|
||||
result = prime * result + ((minimumDataCountPerGraph == null) ? 0 : minimumDataCountPerGraph.hashCode());
|
||||
temp = Double.doubleToLongBits(minimumWindConfidence);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
result = prime * result + ((numberOfHistogramColumns == null) ? 0 : numberOfHistogramColumns.hashCode());
|
||||
temp = Double.doubleToLongBits(outlierDetectionNeighboorhoodRadius);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(outlierMinimumNeighboorhoodPct);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
result = prime * result + (shouldRemoveOutliers ? 1231 : 1237);
|
||||
result = prime * result + (splitByWindGauges ? 1231 : 1237);
|
||||
result = prime * result + (useOnlyEstimationForWindDirection ? 1231 : 1237);
|
||||
result = prime * result + (useOnlyWindGaugesForWindSpeed ? 1231 : 1237);
|
||||
result = prime * result + ((windStepping == null) ? 0 : windStepping.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
PolarSheetGenerationSettingsImpl other = (PolarSheetGenerationSettingsImpl) obj;
|
||||
if (Double.doubleToLongBits(minimumConfidenceMeasure) != Double
|
||||
.doubleToLongBits(other.minimumConfidenceMeasure))
|
||||
return false;
|
||||
if (minimumDataCountPerAngle == null) {
|
||||
if (other.minimumDataCountPerAngle != null)
|
||||
return false;
|
||||
} else if (!minimumDataCountPerAngle.equals(other.minimumDataCountPerAngle))
|
||||
return false;
|
||||
if (minimumDataCountPerGraph == null) {
|
||||
if (other.minimumDataCountPerGraph != null)
|
||||
return false;
|
||||
} else if (!minimumDataCountPerGraph.equals(other.minimumDataCountPerGraph))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(minimumWindConfidence) != Double.doubleToLongBits(other.minimumWindConfidence))
|
||||
return false;
|
||||
if (numberOfHistogramColumns == null) {
|
||||
if (other.numberOfHistogramColumns != null)
|
||||
return false;
|
||||
} else if (!numberOfHistogramColumns.equals(other.numberOfHistogramColumns))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(outlierDetectionNeighboorhoodRadius) != Double
|
||||
.doubleToLongBits(other.outlierDetectionNeighboorhoodRadius))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(outlierMinimumNeighboorhoodPct) != Double
|
||||
.doubleToLongBits(other.outlierMinimumNeighboorhoodPct))
|
||||
return false;
|
||||
if (shouldRemoveOutliers != other.shouldRemoveOutliers)
|
||||
return false;
|
||||
if (splitByWindGauges != other.splitByWindGauges)
|
||||
return false;
|
||||
if (useOnlyEstimationForWindDirection != other.useOnlyEstimationForWindDirection)
|
||||
return false;
|
||||
if (useOnlyWindGaugesForWindSpeed != other.useOnlyWindGaugesForWindSpeed)
|
||||
return false;
|
||||
if (windStepping == null) {
|
||||
if (other.windStepping != null)
|
||||
return false;
|
||||
} else if (!windStepping.equals(other.windStepping))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+3
-9
@@ -12,8 +12,6 @@ public class PolarSheetsDataImpl implements PolarSheetsData {
|
||||
|
||||
private Number[][] averagedPolarDataByWindSpeed;
|
||||
|
||||
private boolean complete;
|
||||
|
||||
private int dataCount;
|
||||
|
||||
private WindStepping stepping;
|
||||
@@ -25,9 +23,10 @@ public class PolarSheetsDataImpl implements PolarSheetsData {
|
||||
//For GWT Serialization
|
||||
PolarSheetsDataImpl() {};
|
||||
|
||||
public PolarSheetsDataImpl(Number[][] averagedPolarDataByWindSpeed, boolean complete, int dataCount, Map<Integer,Integer[]> dataCountPerAngleForWindspeed, WindStepping stepping, Map<Integer, Map<Integer, PolarSheetsHistogramData>> histogramDataMap) {
|
||||
public PolarSheetsDataImpl(Number[][] averagedPolarDataByWindSpeed, int dataCount,
|
||||
Map<Integer, Integer[]> dataCountPerAngleForWindspeed, WindStepping stepping,
|
||||
Map<Integer, Map<Integer, PolarSheetsHistogramData>> histogramDataMap) {
|
||||
this.averagedPolarDataByWindSpeed = averagedPolarDataByWindSpeed;
|
||||
this.complete = complete;
|
||||
this.dataCount = dataCount;
|
||||
this.dataCountPerAngleForWindspeed = dataCountPerAngleForWindspeed;
|
||||
this.stepping = stepping;
|
||||
@@ -40,11 +39,6 @@ public class PolarSheetsDataImpl implements PolarSheetsData {
|
||||
return averagedPolarDataByWindSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataCount() {
|
||||
return dataCount;
|
||||
|
||||
+62
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.sap.sailing.domain.common.WindStepping;
|
||||
|
||||
public class WindSteppingImpl implements WindStepping {
|
||||
@@ -44,4 +46,64 @@ public class WindSteppingImpl implements WindStepping {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(levels);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
WindSteppingImpl other = (WindSteppingImpl) obj;
|
||||
if (!Arrays.equals(levels, other.levels))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevelIndexFloorForValue(double speed) {
|
||||
int result = -1;
|
||||
for (int i = 0; i < levels.length - 1; i++) {
|
||||
if (speed >= levels[i]) {
|
||||
result = i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistanceToLevelFloor(double speed) {
|
||||
double result = 0;
|
||||
int floor = getLevelIndexFloorForValue(speed);
|
||||
if (floor == -1) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = speed - levels[floor];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevelIndexCeilingForValue(double speed) {
|
||||
int floor = getLevelIndexFloorForValue(speed);
|
||||
int result;
|
||||
if (floor == -1) {
|
||||
result = -1;
|
||||
}
|
||||
if (levels[floor] == speed) {
|
||||
result = floor;
|
||||
} else {
|
||||
result = floor + 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -39,4 +39,30 @@ public class WindSteppingWithMaxDistance extends WindSteppingImpl {
|
||||
public double getMaxDistance() {
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(maxDistance);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
WindSteppingWithMaxDistance other = (WindSteppingWithMaxDistance) obj;
|
||||
if (Double.doubleToLongBits(maxDistance) != Double.doubleToLongBits(other.maxDistance))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Regular → Executable
+35
-36
@@ -1,36 +1,35 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Domain
|
||||
Bundle-SymbolicName: com.sap.sailing.domain
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-ClassPath: .
|
||||
Export-Package: com.sap.sailing.domain.base,
|
||||
com.sap.sailing.domain.base.impl,
|
||||
com.sap.sailing.domain.confidence,
|
||||
com.sap.sailing.domain.leaderboard,
|
||||
com.sap.sailing.domain.leaderboard.caching,
|
||||
com.sap.sailing.domain.leaderboard.impl,
|
||||
com.sap.sailing.domain.leaderboard.meta,
|
||||
com.sap.sailing.domain.markpassingcalculation,
|
||||
com.sap.sailing.domain.markpassingcalculation.splining,
|
||||
com.sap.sailing.domain.masterdataimport,
|
||||
com.sap.sailing.domain.polarsheets,
|
||||
com.sap.sailing.domain.racelog,
|
||||
com.sap.sailing.domain.racelog.impl,
|
||||
com.sap.sailing.domain.racelog.tracking,
|
||||
com.sap.sailing.domain.trackfiles,
|
||||
com.sap.sailing.domain.trackimport,
|
||||
com.sap.sailing.domain.tracking,
|
||||
com.sap.sailing.domain.tracking.impl,
|
||||
com.sap.sailing.util,
|
||||
com.sap.sailing.util.impl;x-friends:="com.sap.sailing.server.replication,com.sap.sailing.domain.test"
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
||||
com.sap.sailing.domain.common,
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
com.sap.sailing.geocoding,
|
||||
com.sap.sse.datamining.shared;bundle-version="1.0.0",
|
||||
com.sap.sse.common
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Domain
|
||||
Bundle-SymbolicName: com.sap.sailing.domain
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-ClassPath: .
|
||||
Export-Package: com.sap.sailing.domain.base,
|
||||
com.sap.sailing.domain.base.impl,
|
||||
com.sap.sailing.domain.confidence,
|
||||
com.sap.sailing.domain.leaderboard,
|
||||
com.sap.sailing.domain.leaderboard.caching,
|
||||
com.sap.sailing.domain.leaderboard.impl,
|
||||
com.sap.sailing.domain.leaderboard.meta,
|
||||
com.sap.sailing.domain.markpassingcalculation,
|
||||
com.sap.sailing.domain.markpassingcalculation.splining,
|
||||
com.sap.sailing.domain.masterdataimport,
|
||||
com.sap.sailing.domain.racelog,
|
||||
com.sap.sailing.domain.racelog.impl,
|
||||
com.sap.sailing.domain.racelog.tracking,
|
||||
com.sap.sailing.domain.trackfiles,
|
||||
com.sap.sailing.domain.trackimport,
|
||||
com.sap.sailing.domain.tracking,
|
||||
com.sap.sailing.domain.tracking.impl,
|
||||
com.sap.sailing.util,
|
||||
com.sap.sailing.util.impl;x-friends:="com.sap.sailing.server.replication,com.sap.sailing.domain.test"
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
||||
com.sap.sailing.domain.common,
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
com.sap.sailing.geocoding,
|
||||
com.sap.sse.datamining.shared;bundle-version="1.0.0",
|
||||
com.sap.sse.common
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AngleSpeedOddClassifier implements OddFixClassifier {
|
||||
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AngleSpeedOddClassifier.class.getName());
|
||||
|
||||
@Override
|
||||
public boolean classifiesAsOdd(PolarFix fix) {
|
||||
double angleToWind = fix.getAngleToWind();
|
||||
double speedInKnots = fix.getBoatSpeed().getKnots();
|
||||
if (angleToWind < 20 && angleToWind > -20) {
|
||||
if (speedInKnots > 2) {
|
||||
logger.log(Level.INFO, "Boat goes fast against the wind. Data-Point should have been excluded during maneuver check.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
|
||||
|
||||
public interface OddFixClassifier {
|
||||
|
||||
/**
|
||||
* Used for classifying fixes from a logical perspective.
|
||||
*
|
||||
* Example: An OddFixClassifier could check if a boat has high speed when going against the wind.
|
||||
*
|
||||
* @param polarFix to be classified
|
||||
* @return True if odd from a sailing perspective, false if it makes sense. Classification depends on the type of OddFixClassifier used.
|
||||
*/
|
||||
public boolean classifiesAsOdd(PolarFix polarFix);
|
||||
|
||||
}
|
||||
+3
-3
@@ -22,8 +22,8 @@ public interface DynamicTrackedRegatta extends TrackedRegatta {
|
||||
* may be <code>null</code> which means that no update will be fired to any
|
||||
* {@link DynamicRaceDefinitionSet}.
|
||||
*/
|
||||
DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, WindStore windStore,
|
||||
GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate);
|
||||
DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines,
|
||||
WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
|
||||
long millisecondsOverWhichToAverageSpeed, DynamicRaceDefinitionSet raceDefinitionSetToUpdate);
|
||||
|
||||
}
|
||||
-1
@@ -81,7 +81,6 @@ public class PolarSheetGenerationServiceTest {
|
||||
|
||||
PolarSheetsData results = triggerData.getData();
|
||||
|
||||
Assert.assertTrue(results.isComplete());
|
||||
Assert.assertNotNull(results);
|
||||
|
||||
Assert.assertEquals(4, results.getDataCount());
|
||||
|
||||
Regular → Executable
+3
-1
@@ -42,7 +42,9 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sse.gwt.adminconsole;bundle-version="1.0.0"
|
||||
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: javax.jms;version="1.1.0",
|
||||
Import-Package: com.sap.sailing.polars,
|
||||
com.sap.sailing.polars.factory,
|
||||
javax.jms;version="1.1.0",
|
||||
javax.servlet;version="3.1.0",
|
||||
javax.servlet.descriptor;version="3.1.0",
|
||||
javax.servlet.http;version="3.1.0",
|
||||
|
||||
Executable → Regular
+57
-57
@@ -1,57 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
|
||||
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
|
||||
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
||||
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/com.sap.sailing.gwt.ui"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="4"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" javaProject="com.sap.sailing.gwt.ui" path="1" type="4"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/resources" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/java" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.googlecode.java-diff-utils/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.common/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.json.simple/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.expeditionconnector/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/resources" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.udpconnector/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.mongodb/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.persistence/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter.persistence/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.operationaltransformation/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter.persistence/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.moxieapps.gwt.highcharts/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.geocoding/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server.replication/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.datamining.shared/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.common/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.datamining.shared/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-user.jar" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sailing.gwt.ui"/> </runtimeClasspathEntry> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.ui/src/main/java" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt.adminconsole/src" path="3" type="2"/> "/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/Search.html com.sap.sailing.gwt.ui.Search -startupUrl /security/ui/Login.html com.sap.sse.security.ui.Login -startupUrl /security/ui/EditProfile.html com.sap.sse.security.ui.EditProfile -startupUrl /security/ui/EmailValidation.html com.sap.sse.security.ui.EmailValidation com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.UserManagement com.sap.sailing.gwt.ui.Search com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.Home com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m"/>
|
||||
</launchConfiguration>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
|
||||
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
|
||||
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
||||
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/com.sap.sailing.gwt.ui"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="4"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" javaProject="com.sap.sailing.gwt.ui" path="1" type="4"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/resources" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/java" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.googlecode.java-diff-utils/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.common/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.json.simple/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.expeditionconnector/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.declination/resources" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.udpconnector/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.mongodb/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.persistence/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.swisstimingadapter.persistence/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.operationaltransformation/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.tractracadapter.persistence/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.moxieapps.gwt.highcharts/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.geocoding/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.server.replication/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.datamining.shared/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.common/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.datamining.shared/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-user.jar" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sailing.gwt.ui"/> </runtimeClasspathEntry> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.security.ui/src/main/java" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt.adminconsole/src" path="3" type="2"/> "/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/Search.html com.sap.sailing.gwt.ui.Search -startupUrl /security/ui/Login.html com.sap.sse.security.ui.Login -startupUrl /security/ui/EditProfile.html com.sap.sse.security.ui.EditProfile -startupUrl /security/ui/EmailValidation.html com.sap.sse.security.ui.EmailValidation com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.UserManagement com.sap.sailing.gwt.ui.Search com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.Home com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m"/>
|
||||
</launchConfiguration>
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.gwt.ui.actions;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
|
||||
import com.sap.sse.gwt.client.async.AsyncAction;
|
||||
|
||||
/**
|
||||
* An asynchronous action to determine whether a suitable polar diagram is available for the race shown on {@link RaceMap}
|
||||
*
|
||||
* @author Christopher Ronnewinkel (D036654)
|
||||
*
|
||||
*/
|
||||
public class GetPolarAction implements AsyncAction<Boolean> {
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final RegattaAndRaceIdentifier raceIdentifier;
|
||||
|
||||
public GetPolarAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier) {
|
||||
this.sailingService = sailingService;
|
||||
this.raceIdentifier = raceIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(AsyncCallback<Boolean> callback) {
|
||||
sailingService.getPolarResults(raceIdentifier, callback);
|
||||
}
|
||||
}
|
||||
Executable → Regular
+79
-71
@@ -136,6 +136,8 @@ public interface SailingService extends RemoteService {
|
||||
WindInfoForRaceDTO getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth,
|
||||
int numberOfFixes, double latDeg, double lngDeg, Collection<String> windSources) throws NoWindException;
|
||||
|
||||
Boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime);
|
||||
|
||||
CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString,
|
||||
@@ -355,10 +357,16 @@ public interface SailingService extends RemoteService {
|
||||
|
||||
void createCourseArea(UUID eventId, String courseAreaName);
|
||||
|
||||
List<String> getBoatClassNamesWithPolarSheetsAvailable();
|
||||
|
||||
void removeCourseArea(UUID eventId, UUID courseAreaId);
|
||||
|
||||
List<Util.Pair<String, String>> getLeaderboardsNamesOfMetaLeaderboard(String metaLeaderboardName);
|
||||
|
||||
PolarSheetGenerationResponse showCachedPolarSheetForBoatClass(String boatClassName);
|
||||
|
||||
|
||||
|
||||
Util.Pair<String, LeaderboardType> checkLeaderboardName(String leaderboardName);
|
||||
|
||||
/** for backward compatibility with the regatta overview */
|
||||
@@ -395,16 +403,16 @@ public interface SailingService extends RemoteService {
|
||||
|
||||
Iterable<CompetitorDTO> getCompetitors();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param leaderboardName
|
||||
* @param lookInRaceLogs If set to {@code true}, the {@link RaceLog}s are checked for the competitor registrations.
|
||||
* If set to {@code false}, the {@link RaceDefinition}s are checked instead.
|
||||
* @return
|
||||
*/
|
||||
Iterable<CompetitorDTO> getCompetitorsOfLeaderboard(String leaderboardName, boolean lookInRaceLogs);
|
||||
/**
|
||||
*
|
||||
* @param leaderboardName
|
||||
* @param lookInRaceLogs If set to {@code true}, the {@link RaceLog}s are checked for the competitor registrations.
|
||||
* If set to {@code false}, the {@link RaceDefinition}s are checked instead.
|
||||
* @return
|
||||
*/
|
||||
Iterable<CompetitorDTO> getCompetitorsOfLeaderboard(String leaderboardName, boolean lookInRaceLogs);
|
||||
|
||||
CompetitorDTO addOrUpdateCompetitor(CompetitorDTO competitor);
|
||||
CompetitorDTO addOrUpdateCompetitor(CompetitorDTO competitor);
|
||||
|
||||
void allowCompetitorResetToDefaults(Iterable<CompetitorDTO> competitors);
|
||||
|
||||
@@ -429,68 +437,68 @@ public interface SailingService extends RemoteService {
|
||||
void removeIgtimiAccount(String eMailOfAccountToRemove);
|
||||
|
||||
Map<RegattaAndRaceIdentifier, Integer> importWindFromIgtimi(List<RaceDTO> selectedRaces, boolean correctByDeclination) throws Exception;
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) throws Exception;
|
||||
|
||||
/**
|
||||
* Revoke the {@link DenoteForTrackingEvent}. This does not affect an existing {@code RaceLogRaceTracker}
|
||||
* or {@link TrackedRace} for this {@code RaceLog}.
|
||||
*
|
||||
* @see RaceLogTrackingAdapter#removeDenotationForRaceLogTracking
|
||||
*/
|
||||
void removeDenotationForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName) throws Exception;
|
||||
|
||||
/**
|
||||
* Performs all the necessary steps to start tracking the race.
|
||||
* The {@code RaceLog} needs to be denoted for racelog-tracking beforehand.
|
||||
*
|
||||
* @see RaceLogTrackingAdapter#startTracking
|
||||
*/
|
||||
void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName)
|
||||
throws NotDenotedForRaceLogTrackingException, Exception;
|
||||
|
||||
void setCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName, Set<CompetitorDTO> competitors);
|
||||
|
||||
Collection<CompetitorDTO> getCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
void addMarkToRaceLog(String leaderboardName, String raceColumnName, String fleetName, MarkDTO markDTO);
|
||||
|
||||
Collection<MarkDTO> getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
/**
|
||||
* Adds the course definition to the racelog, while trying to reuse existing marks, controlpoints and waypoints
|
||||
* from the previous course definition in the racelog.
|
||||
*/
|
||||
void addCourseDefinitionToRaceLog(String leaderboardName, String raceColumnName, String fleetName, List<Util.Pair<ControlPointDTO, PassingInstruction>> course);
|
||||
|
||||
RaceCourseDTO getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
/**
|
||||
* Adds a fix to the {@link GPSFixStore}, and creates a mapping with a virtual device for exactly the current timepoint.
|
||||
*/
|
||||
void pingMarkViaRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, MarkDTO mark, PositionDTO position);
|
||||
|
||||
void copyCourseAndCompetitorsToOtherRaceLogs(Util.Triple<String, String, String> raceLogFrom,
|
||||
Set<Util.Triple<String, String, String>> raceLogsTo);
|
||||
|
||||
void addDeviceMappingToRaceLog(String leaderboardName, String raceColumnName, String fleetName, DeviceMappingDTO mapping)
|
||||
throws TransformationException;
|
||||
|
||||
List<DeviceMappingDTO> getDeviceMappingsFromRaceLog(String leaderboardName, String raceColumnName, String fleetName)
|
||||
throws TransformationException;
|
||||
|
||||
List<String> getDeserializableDeviceIdentifierTypes();
|
||||
|
||||
void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName, DeviceMappingDTO mapping,
|
||||
Date closingTimePoint) throws NoCorrespondingServiceRegisteredException, TransformationException;
|
||||
|
||||
/**
|
||||
* Revoke the events in the {@code RaceLog} that are identified by the {@code eventIds}.
|
||||
* This only affects such events that implement {@link Revokable}.
|
||||
*/
|
||||
void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<Serializable> eventIds)
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) throws Exception;
|
||||
|
||||
/**
|
||||
* Revoke the {@link DenoteForTrackingEvent}. This does not affect an existing {@code RaceLogRaceTracker}
|
||||
* or {@link TrackedRace} for this {@code RaceLog}.
|
||||
*
|
||||
* @see RaceLogTrackingAdapter#removeDenotationForRaceLogTracking
|
||||
*/
|
||||
void removeDenotationForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName) throws Exception;
|
||||
|
||||
/**
|
||||
* Performs all the necessary steps to start tracking the race.
|
||||
* The {@code RaceLog} needs to be denoted for racelog-tracking beforehand.
|
||||
*
|
||||
* @see RaceLogTrackingAdapter#startTracking
|
||||
*/
|
||||
void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName)
|
||||
throws NotDenotedForRaceLogTrackingException, Exception;
|
||||
|
||||
void setCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName, Set<CompetitorDTO> competitors);
|
||||
|
||||
Collection<CompetitorDTO> getCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
void addMarkToRaceLog(String leaderboardName, String raceColumnName, String fleetName, MarkDTO markDTO);
|
||||
|
||||
Collection<MarkDTO> getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
/**
|
||||
* Adds the course definition to the racelog, while trying to reuse existing marks, controlpoints and waypoints
|
||||
* from the previous course definition in the racelog.
|
||||
*/
|
||||
void addCourseDefinitionToRaceLog(String leaderboardName, String raceColumnName, String fleetName, List<Util.Pair<ControlPointDTO, PassingInstruction>> course);
|
||||
|
||||
RaceCourseDTO getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName);
|
||||
|
||||
/**
|
||||
* Adds a fix to the {@link GPSFixStore}, and creates a mapping with a virtual device for exactly the current timepoint.
|
||||
*/
|
||||
void pingMarkViaRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, MarkDTO mark, PositionDTO position);
|
||||
|
||||
void copyCourseAndCompetitorsToOtherRaceLogs(Util.Triple<String, String, String> raceLogFrom,
|
||||
Set<Util.Triple<String, String, String>> raceLogsTo);
|
||||
|
||||
void addDeviceMappingToRaceLog(String leaderboardName, String raceColumnName, String fleetName, DeviceMappingDTO mapping)
|
||||
throws TransformationException;
|
||||
|
||||
List<DeviceMappingDTO> getDeviceMappingsFromRaceLog(String leaderboardName, String raceColumnName, String fleetName)
|
||||
throws TransformationException;
|
||||
|
||||
List<String> getDeserializableDeviceIdentifierTypes();
|
||||
|
||||
void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName, DeviceMappingDTO mapping,
|
||||
Date closingTimePoint) throws NoCorrespondingServiceRegisteredException, TransformationException;
|
||||
|
||||
/**
|
||||
* Revoke the events in the {@code RaceLog} that are identified by the {@code eventIds}.
|
||||
* This only affects such events that implement {@link Revokable}.
|
||||
*/
|
||||
void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<Serializable> eventIds)
|
||||
throws NotRevokableException;
|
||||
|
||||
Collection<String> getGPSFixImporterTypes();
|
||||
|
||||
+59
-52
@@ -183,6 +183,8 @@ public interface SailingServiceAsync extends BuildVersionRetriever {
|
||||
int numberOfFixes, Collection<String> windSourceTypeNames, boolean onlyUpToNewestEvent,
|
||||
boolean includeCombinedWindForAllLegMiddles, AsyncCallback<WindInfoForRaceDTO> callback);
|
||||
|
||||
void getPolarResults(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> callback);
|
||||
|
||||
void getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime, AsyncCallback<SimulatorResultsDTO> callback);
|
||||
|
||||
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind, AsyncCallback<Void> callback);
|
||||
@@ -515,10 +517,10 @@ public interface SailingServiceAsync extends BuildVersionRetriever {
|
||||
|
||||
void getCompetitors(AsyncCallback<Iterable<CompetitorDTO>> asyncCallback);
|
||||
|
||||
void getCompetitorsOfLeaderboard(String leaderboardName, boolean lookInRaceLogs,
|
||||
AsyncCallback<Iterable<CompetitorDTO>> asyncCallback);
|
||||
void getCompetitorsOfLeaderboard(String leaderboardName, boolean lookInRaceLogs,
|
||||
AsyncCallback<Iterable<CompetitorDTO>> asyncCallback);
|
||||
|
||||
void addOrUpdateCompetitor(CompetitorDTO competitor, AsyncCallback<CompetitorDTO> asyncCallback);
|
||||
void addOrUpdateCompetitor(CompetitorDTO competitor, AsyncCallback<CompetitorDTO> asyncCallback);
|
||||
|
||||
void allowCompetitorResetToDefaults(Iterable<CompetitorDTO> competitors, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
@@ -553,60 +555,65 @@ public interface SailingServiceAsync extends BuildVersionRetriever {
|
||||
|
||||
void importWindFromIgtimi(List<RaceDTO> selectedRaces, boolean correctByDeclination, AsyncCallback<Map<RegattaAndRaceIdentifier, Integer>> asyncCallback);
|
||||
|
||||
void getBoatClassNamesWithPolarSheetsAvailable(AsyncCallback<List<String>> asyncCallback);
|
||||
|
||||
void getEventById(UUID id, boolean withStatisticalData, AsyncCallback<EventDTO> callback);
|
||||
|
||||
|
||||
void showCachedPolarSheetForBoatClass(String boatClassName,
|
||||
AsyncCallback<PolarSheetGenerationResponse> asyncCallback);
|
||||
void getLeaderboardsByEvent(EventDTO event, AsyncCallback<List<StrippedLeaderboardDTO>> callback);
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName,
|
||||
String raceColumnName, String fleetName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName, AsyncCallback<Void> callback);
|
||||
|
||||
void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void setCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName,
|
||||
Set<CompetitorDTO> competitors, AsyncCallback<Void> callback);
|
||||
|
||||
void getCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Collection<CompetitorDTO>> callback);
|
||||
|
||||
void addMarkToRaceLog(String leaderboardName, String raceColumnName, String fleetName, MarkDTO markDTO,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Collection<MarkDTO>> callback);
|
||||
|
||||
void addCourseDefinitionToRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
List<Util.Pair<ControlPointDTO, PassingInstruction>> course, AsyncCallback<Void> callback);
|
||||
|
||||
void getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<RaceCourseDTO> callback);
|
||||
|
||||
void pingMarkViaRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, MarkDTO mark,
|
||||
PositionDTO position, AsyncCallback<Void> callback);
|
||||
|
||||
void getDeserializableDeviceIdentifierTypes(AsyncCallback<List<String>> callback);
|
||||
|
||||
void getDeviceMappingsFromRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<List<DeviceMappingDTO>> callback);
|
||||
|
||||
void addDeviceMappingToRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
DeviceMappingDTO mapping, AsyncCallback<Void> callback);
|
||||
|
||||
void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName,
|
||||
DeviceMappingDTO mapping, Date closingTimePoint, AsyncCallback<Void> callback);
|
||||
|
||||
void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<Serializable> eventIds,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName,
|
||||
String raceColumnName, String fleetName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void denoteForRaceLogTracking(String leaderboardName, AsyncCallback<Void> callback);
|
||||
|
||||
void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void setCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName,
|
||||
Set<CompetitorDTO> competitors, AsyncCallback<Void> callback);
|
||||
|
||||
void getCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Collection<CompetitorDTO>> callback);
|
||||
|
||||
void addMarkToRaceLog(String leaderboardName, String raceColumnName, String fleetName, MarkDTO markDTO,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Collection<MarkDTO>> callback);
|
||||
|
||||
void addCourseDefinitionToRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
List<Util.Pair<ControlPointDTO, PassingInstruction>> course, AsyncCallback<Void> callback);
|
||||
|
||||
void getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<RaceCourseDTO> callback);
|
||||
|
||||
void pingMarkViaRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, MarkDTO mark,
|
||||
PositionDTO position, AsyncCallback<Void> callback);
|
||||
|
||||
void getDeserializableDeviceIdentifierTypes(AsyncCallback<List<String>> callback);
|
||||
|
||||
void getDeviceMappingsFromRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<List<DeviceMappingDTO>> callback);
|
||||
|
||||
void addDeviceMappingToRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
DeviceMappingDTO mapping, AsyncCallback<Void> callback);
|
||||
|
||||
void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName,
|
||||
DeviceMappingDTO mapping, Date closingTimePoint, AsyncCallback<Void> callback);
|
||||
|
||||
void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<Serializable> eventIds,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void removeSeries(RegattaIdentifier regattaIdentifier, String seriesName, AsyncCallback<Void> callback);
|
||||
|
||||
void removeDenotationForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void copyCourseAndCompetitorsToOtherRaceLogs(Util.Triple<String, String, String> raceLogFrom,
|
||||
void removeDenotationForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void copyCourseAndCompetitorsToOtherRaceLogs(Util.Triple<String, String, String> raceLogFrom,
|
||||
Set<Util.Triple<String, String, String>> raceLogsTo, AsyncCallback<Void> callback);
|
||||
|
||||
void getGPSFixImporterTypes(AsyncCallback<Collection<String>> callback);
|
||||
@@ -642,4 +649,4 @@ public interface SailingServiceAsync extends BuildVersionRetriever {
|
||||
AsyncCallback<Iterable<LeaderboardSearchResultDTO>> callback);
|
||||
|
||||
void setStartTimeReceivedForRace(RaceIdentifier raceIdentifier, Date newStartTimeReceived, AsyncCallback<RaceDTO> callback);
|
||||
}
|
||||
}
|
||||
+4
@@ -967,6 +967,10 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages {
|
||||
String distanceToLine();
|
||||
String beatAngleTooltip();
|
||||
String beatAngle();
|
||||
|
||||
String showBoatClassChartsLabel();
|
||||
|
||||
String showDiagram();
|
||||
String runAutomaticallyTooltip();
|
||||
String rerunQueryAfterRefreshTooltip();
|
||||
String queryDefinitionProvider();
|
||||
|
||||
+3
-1
@@ -951,6 +951,8 @@ timeSinceStart={0} since start
|
||||
distanceToLine=Distance to start line
|
||||
beatAngleTooltip=The angle between the competitors direction and the wind
|
||||
beatAngle=Beat Angle
|
||||
showBoatClassChartsLabel=You can also view the overall diagram for the available boat classes.
|
||||
showDiagram=Show Diagram
|
||||
runAutomaticallyTooltip=Run the query automatically, after you changed e.g. the statistic or the grouping.
|
||||
rerunQueryAfterRefreshTooltip=Reruns the query after the tables have been refreshed.
|
||||
queryDefinitionProvider=Query Definition Provider
|
||||
@@ -1092,4 +1094,4 @@ serverError=An error occurred while attempting to contact the server. Please che
|
||||
remoteProcedureCall=Remote Procedure Call
|
||||
serverReplies=Server replies
|
||||
errorCommunicatingWithServer=Error communicating with server
|
||||
userManagement=User Management
|
||||
userManagement=User Management
|
||||
+2
@@ -947,6 +947,8 @@ timeSinceStart={0} seit dem Start
|
||||
distanceToLine=Abstand zur Startlinie
|
||||
beatAngleTooltip=Der Winkel zwischen Windrichtung und Fahrtrichtung des Teilnehmers
|
||||
beatAngle=Winkel zum Wind
|
||||
showBoatClassChartsLabel=Im folgenden können außerdem auch die existierenden Diagramme für die vorhandenen Bootsklassen angezeigt werden.
|
||||
showDiagram=Diagramm anzeigen
|
||||
runAutomaticallyTooltip=Führe die Anfrage automatisch durch, wenn zum Beispiel die Statistik oder die Gruppierung geändert wurde.
|
||||
rerunQueryAfterRefreshTooltip=Wiederholt die Anfrage nachdem die Tabellen aktualisiert wurden.
|
||||
queryDefinitionProvider=Anfragen-Definitions-Versorger
|
||||
|
||||
+43
-3
@@ -81,6 +81,7 @@ import com.sap.sailing.domain.common.impl.BoundsImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.RGBColor;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
|
||||
import com.sap.sailing.gwt.ui.actions.GetPolarAction;
|
||||
import com.sap.sailing.gwt.ui.actions.GetRaceMapDataAction;
|
||||
import com.sap.sailing.gwt.ui.actions.GetWindInfoAction;
|
||||
import com.sap.sailing.gwt.ui.client.ClientResources;
|
||||
@@ -123,6 +124,7 @@ import com.sap.sse.common.filter.Filter;
|
||||
import com.sap.sse.common.filter.FilterSet;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
|
||||
import com.sap.sse.gwt.client.player.TimeListener;
|
||||
import com.sap.sse.gwt.client.player.Timer;
|
||||
import com.sap.sse.gwt.client.player.Timer.PlayModes;
|
||||
@@ -309,6 +311,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
private WindStreamletsRaceboardOverlay streamletOverlay;
|
||||
private final boolean showViewStreamlets;
|
||||
private final boolean showViewSimulation;
|
||||
public static final String GET_POLAR_CATEGORY = "getPolar";
|
||||
private boolean hasPolar;
|
||||
private final RegattaAndRaceIdentifier raceIdentifier;
|
||||
|
||||
public RaceMap(SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor,
|
||||
@@ -338,6 +342,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
isMapInitialized = false;
|
||||
this.showViewStreamlets = showViewStreamlets;
|
||||
this.showViewSimulation = showViewSimulation;
|
||||
this.hasPolar = false;
|
||||
headerPanel = new FlowPanel();
|
||||
headerPanel.setStyleName("RaceMap-HeaderPanel");
|
||||
panelForLeftHeaderLabels = new AbsolutePanel();
|
||||
@@ -470,9 +475,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
|
||||
if (showViewSimulation) {
|
||||
// determine availability of polar diagram
|
||||
hasPolar();
|
||||
// initialize simulation canvas
|
||||
simulationOverlay = new RaceSimulationOverlay(getMap(), /* zIndex */ 0, timer, raceIdentifier, sailingService, stringMessages, asyncActionsExecutor);
|
||||
simulationOverlay = new RaceSimulationOverlay(getMap(), /* zIndex */ 0, raceIdentifier, sailingService, stringMessages, asyncActionsExecutor);
|
||||
simulationOverlay.addToMap();
|
||||
simulationOverlay.setVisible(false);
|
||||
}
|
||||
|
||||
createHeaderPanel(map);
|
||||
@@ -486,6 +494,26 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
|
||||
LoadApi.go(onLoad, loadLibraries, sensor, "key="+GoogleMapAPIKey.V3_APIKey);
|
||||
}
|
||||
|
||||
public void hasPolar() {
|
||||
GetPolarAction getPolar = new GetPolarAction(sailingService, raceIdentifier);
|
||||
asyncActionsExecutor.execute(getPolar, GET_POLAR_CATEGORY,
|
||||
new MarkedAsyncCallback<>(new AsyncCallback<Boolean>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
// TODO: add corresponding message to string-messages
|
||||
// Window.setStatus(stringMessages.errorFetchingWindStreamletData(caught.getMessage()));
|
||||
Window.setStatus(GET_POLAR_CATEGORY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
// store results
|
||||
hasPolar = result.booleanValue();
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a header panel where additional information can be displayed by using
|
||||
@@ -710,6 +738,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
public void onSuccess(RaceMapDataDTO raceMapDataDTO) {
|
||||
if (map != null && raceMapDataDTO != null) {
|
||||
quickRanks = raceMapDataDTO.quickRanks;
|
||||
if (showViewSimulation && settings.isShowSimulationOverlay()) {
|
||||
simulationOverlay.updateLeg(getCurrentLeg(), newTime, false);
|
||||
}
|
||||
// process response only if not received out of order
|
||||
if (startedProcessingRequestID < requestID) {
|
||||
startedProcessingRequestID = requestID;
|
||||
@@ -1918,7 +1949,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<RaceMapSettings> getSettingsDialogComponent() {
|
||||
return new RaceMapSettingsDialogComponent(settings, stringMessages, this.showViewSimulation);
|
||||
return new RaceMapSettingsDialogComponent(settings, stringMessages, this.showViewSimulation && this.hasPolar);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1981,7 +2012,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (newSettings.isShowSimulationOverlay() != settings.isShowSimulationOverlay()) {
|
||||
settings.setShowSimulationOverlay(newSettings.isShowSimulationOverlay());
|
||||
simulationOverlay.setVisible(newSettings.isShowSimulationOverlay());
|
||||
simulationOverlay.timeChanged(timer.getTime(), null);
|
||||
simulationOverlay.updateLeg(getCurrentLeg(), timer.getTime(), true);
|
||||
}
|
||||
if (requiredRedraw) {
|
||||
redraw();
|
||||
@@ -2186,6 +2217,15 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getCurrentLeg() {
|
||||
com.sap.sse.common.Util.Pair<Integer, CompetitorDTO> leaderWithLeg = this.getLeadingVisibleCompetitorWithOneBasedLegNumber(getCompetitorsToShow());
|
||||
if (leaderWithLeg == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return leaderWithLeg.getA();
|
||||
}
|
||||
}
|
||||
|
||||
private Image createSAPLogo() {
|
||||
ImageResource sapLogoResource = resources.sapLogoOverlay();
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.sap.sailing.gwt.ui.datamining.client.presentation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.Chart;
|
||||
import org.moxieapps.gwt.highcharts.client.Series;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.LinePlotOptions;
|
||||
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.datamining.ResultsPresenter;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
import com.sap.sse.datamining.shared.QueryResult;
|
||||
|
||||
/**
|
||||
* Expects the inner key in the group key to be the angle for the polar chart. (x-value) Maybe the angle should be
|
||||
* transfered as part of the result value in the future. But in the backend the angle is treated as a key (for polar
|
||||
* sheets) for grouping all polar fixes with the same rounded angle
|
||||
*
|
||||
* @author Frederik Petersen D054528
|
||||
*
|
||||
*/
|
||||
public class PolarChart implements ResultsPresenter<Number> {
|
||||
|
||||
private final Chart chart = createPolarChartWidget();
|
||||
|
||||
private final Map<String, Series> dataByKeyStringAndAngle = new HashMap<String, Series>();
|
||||
|
||||
@Override
|
||||
public Widget getWidget() {
|
||||
return chart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a polar diagram chart of the Line type.
|
||||
*/
|
||||
private Chart createPolarChartWidget() {
|
||||
Chart polarSheetChart = new Chart().setType(Series.Type.LINE)
|
||||
.setLinePlotOptions(new LinePlotOptions().setLineWidth(1))
|
||||
.setPolar(true).setHeight100().setWidth100();
|
||||
polarSheetChart.getYAxis().setMin(0);
|
||||
return polarSheetChart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showResult(QueryResult<Number> result) {
|
||||
resetChartData();
|
||||
Map<GroupKey, Number> results = result.getResults();
|
||||
if (!results.isEmpty()) {
|
||||
for (Entry<GroupKey, Number> resultEntry : results.entrySet()) {
|
||||
GroupKey key = resultEntry.getKey();
|
||||
StringBuilder keyStringBuilder = new StringBuilder();
|
||||
GroupKey currentKey = key;
|
||||
while (currentKey.hasSubKey()) {
|
||||
keyStringBuilder.append(currentKey.getMainKey());
|
||||
currentKey = currentKey.getSubKey();
|
||||
}
|
||||
int angle = Integer.parseInt(currentKey.toString());
|
||||
String keyString = keyStringBuilder.toString();
|
||||
Series series = dataByKeyStringAndAngle.get(keyString);
|
||||
if (series == null) {
|
||||
series = chart.createSeries();
|
||||
dataByKeyStringAndAngle.put(keyString, series);
|
||||
}
|
||||
series.addPoint(angle, resultEntry.getValue());
|
||||
series.setName(keyString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetChartData() {
|
||||
dataByKeyStringAndAngle.clear();
|
||||
chart.removeAllSeries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String error) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String mainError, Iterable<String> detailedErrors) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.sap.sailing.gwt.ui.polarsheets;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.AxisTitle;
|
||||
import org.moxieapps.gwt.highcharts.client.Chart;
|
||||
import org.moxieapps.gwt.highcharts.client.Point;
|
||||
import org.moxieapps.gwt.highcharts.client.Series;
|
||||
import org.moxieapps.gwt.highcharts.client.Series.Type;
|
||||
import org.moxieapps.gwt.highcharts.client.labels.XAxisLabels;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.AreaPlotOptions;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.PlotOptions.Stacking;
|
||||
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.user.client.Timer;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
/**
|
||||
* Shows the underlying distribution for any point in the polar diagrams
|
||||
* of the {@link PolarSheetsChartPanel}.
|
||||
*
|
||||
* @author d054528 Frederik Petersen
|
||||
*
|
||||
*/
|
||||
public class AngleOverDataSizeHistogramPanel extends DockLayoutPanel {
|
||||
|
||||
private final Chart chart;
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public AngleOverDataSizeHistogramPanel(StringMessages stringMessages) {
|
||||
super(Unit.PX);
|
||||
this.stringMessages = stringMessages;
|
||||
setSize("100%", "100%");
|
||||
|
||||
chart = createHistogramChart();
|
||||
chart.getElement().setAttribute("align", "top");
|
||||
add(chart);
|
||||
}
|
||||
|
||||
private Chart createHistogramChart() {
|
||||
Chart histogramChart = new Chart().setType(Type.AREA).setHeight100().setWidth100();
|
||||
histogramChart.setChartTitleText(stringMessages.histogram());
|
||||
histogramChart.getYAxis().setMin(0).setAxisTitle(new AxisTitle().setText(stringMessages.numberOfDataPoints()));
|
||||
histogramChart.getXAxis().setLabels(new XAxisLabels().setRotation(-90f).setY(10))
|
||||
.setAxisTitle(new AxisTitle().setText(stringMessages.beatAngle()));
|
||||
histogramChart.setAreaPlotOptions(new AreaPlotOptions().setStacking(Stacking.NORMAL).setLineColor("#666666")
|
||||
.setLineWidth(1).setMarker(new Marker().setLineWidth(1).setLineColor("#666666")));
|
||||
return histogramChart;
|
||||
}
|
||||
|
||||
public void addData(Map<Integer, PolarSheetsHistogramData> histogramDataPerAngle) {
|
||||
chart.setTitle("");
|
||||
Series series = chart.createSeries();
|
||||
|
||||
Point[] points = toPoints(histogramDataPerAngle);
|
||||
series.setPoints(points);
|
||||
chart.addSeries(series);
|
||||
}
|
||||
|
||||
private Point[] toPoints(Map<Integer, PolarSheetsHistogramData> histogramDataPerAngle) {
|
||||
Number[] xValues = new Number[360];
|
||||
Number[] yValues = new Number[360];
|
||||
for (int i = 0; i < 360; i++) {
|
||||
xValues[i] = i;
|
||||
yValues[i] = histogramDataPerAngle.get(i).getDataCount();
|
||||
}
|
||||
|
||||
return toPoints(xValues, yValues);
|
||||
}
|
||||
|
||||
public Point[] toPoints(Number[] xValues, Number[] yValues) {
|
||||
Point[] points = new Point[xValues.length];
|
||||
for (int i = 0; i < xValues.length; i++) {
|
||||
points[i] = new Point(xValues[i], yValues[i]);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
Timer timer = new Timer() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
chart.setSizeToMatchContainer();
|
||||
}
|
||||
};
|
||||
timer.schedule(200);
|
||||
super.onLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResize() {
|
||||
chart.setSizeToMatchContainer();
|
||||
super.onResize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+10
-4
@@ -42,10 +42,13 @@ public class PolarSheetsChartPanel extends DockLayoutPanel {
|
||||
private PolarSheetGenerationSettings settings;
|
||||
|
||||
private final Map<String,PolarSheetsData> polarSheetsDataMap;
|
||||
|
||||
private final AngleOverDataSizeHistogramPanel angleOverDataSizeHistogramPanel;
|
||||
|
||||
public PolarSheetsChartPanel(StringMessages stringMessages) {
|
||||
public PolarSheetsChartPanel(StringMessages stringMessages, AngleOverDataSizeHistogramPanel angleOverDataSizeHistogramPanel) {
|
||||
super(Unit.PCT);
|
||||
this.stringMessages = stringMessages;
|
||||
this.angleOverDataSizeHistogramPanel = angleOverDataSizeHistogramPanel;
|
||||
polarSheetsDataMap = new HashMap<String, PolarSheetsData>();
|
||||
setSize("100%", "100%");
|
||||
chart = createPolarSheetChart();
|
||||
@@ -121,10 +124,11 @@ public class PolarSheetsChartPanel extends DockLayoutPanel {
|
||||
createSeriesForWindspeed(seriesId, i, result.getStepping().getRawStepping()[i]);
|
||||
}
|
||||
Series series = seriesMap.get(seriesId)[i];
|
||||
series.setPoints(result.getAveragedPolarDataByWindSpeed()[i], false);
|
||||
//series.setPoints(result.getAveragedPolarDataByWindSpeed()[i], false);
|
||||
Point[] points = createPointsWithMarkerAlphaAccordingToDataCount(result, i);
|
||||
if (points != null) {
|
||||
series.setPoints(points);
|
||||
angleOverDataSizeHistogramPanel.addData(result.getHistogramDataMap().get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,14 +158,16 @@ public class PolarSheetsChartPanel extends DockLayoutPanel {
|
||||
Point[] points = new Point[360];
|
||||
List<Integer> dataCountList = Arrays.asList(result.getDataCountPerAngleForWindspeed(windspeed));
|
||||
Integer max = Collections.max(dataCountList);
|
||||
if (max <= 0) {
|
||||
if (max < settings.getMinimumDataCountPerAngle()) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < 360; i++) {
|
||||
if (result.getHistogramDataMap().get(windspeed) == null
|
||||
|| result.getHistogramDataMap().get(windspeed).get(i) == null
|
||||
|| result.getHistogramDataMap().get(windspeed).get(i).getConfidenceMeasure() < settings
|
||||
.getMinimumConfidenceMeasure()) {
|
||||
.getMinimumConfidenceMeasure()
|
||||
|| result.getHistogramDataMap().get(windspeed).get(i).getDataCount() < settings
|
||||
.getMinimumDataCountPerAngle()) {
|
||||
points[i] = new Point(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
+64
-4
@@ -12,9 +12,11 @@ import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.Timer;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.SplitLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
@@ -58,6 +60,7 @@ public class PolarSheetsPanel extends SplitLayoutPanel implements RaceSelectionC
|
||||
private List<RegattaAndRaceIdentifier> selectedRaces;
|
||||
private PolarSheetsChartPanel chartPanel;
|
||||
private PolarSheetsHistogramPanel histogramPanel;
|
||||
private AngleOverDataSizeHistogramPanel angleOverDataSizeHistogramPanel;
|
||||
|
||||
private Label polarSheetsGenerationLabel;
|
||||
private Label dataCountLabel;
|
||||
@@ -93,8 +96,10 @@ public class PolarSheetsPanel extends SplitLayoutPanel implements RaceSelectionC
|
||||
namingBox = new TextBox();
|
||||
namingContainer.add(namingBox);
|
||||
leftPanel.add(namingContainer);
|
||||
addBoatClassDiagramArea(leftPanel);
|
||||
DockLayoutPanel rightPanel = new DockLayoutPanel(Unit.PCT);
|
||||
PolarSheetsChartPanel polarSheetsChartPanel = createPolarSheetsChartPanel();
|
||||
angleOverDataSizeHistogramPanel = new AngleOverDataSizeHistogramPanel(stringMessages);
|
||||
PolarSheetsChartPanel polarSheetsChartPanel = createPolarSheetsChartPanel(angleOverDataSizeHistogramPanel);
|
||||
DockLayoutPanel polarChartAndControlPanel = new DockLayoutPanel(Unit.PCT);
|
||||
PolarChartControlPanel polarChartControlPanel = new PolarChartControlPanel(stringMessages,
|
||||
polarSheetsChartPanel);
|
||||
@@ -108,7 +113,11 @@ public class PolarSheetsPanel extends SplitLayoutPanel implements RaceSelectionC
|
||||
rightPanel.addNorth(polarChartAndControlPanel, 70);
|
||||
histogramPanel = new PolarSheetsHistogramPanel(stringMessages);
|
||||
histogramPanel.getElement().setAttribute("align", "top");
|
||||
rightPanel.addSouth(histogramPanel, 30);
|
||||
//rightPanel.addSouth(histogramPanel, 30);
|
||||
|
||||
|
||||
angleOverDataSizeHistogramPanel.getElement().setAttribute("align", "top");
|
||||
rightPanel.addSouth(angleOverDataSizeHistogramPanel, 30);
|
||||
|
||||
|
||||
add(rightPanel);
|
||||
@@ -119,6 +128,57 @@ public class PolarSheetsPanel extends SplitLayoutPanel implements RaceSelectionC
|
||||
chartPanel.setSettings(initialSettings);
|
||||
}
|
||||
|
||||
private void addBoatClassDiagramArea(VerticalPanel leftPanel) {
|
||||
leftPanel.add(new Label(stringMessages.showBoatClassChartsLabel()));
|
||||
final ListBox boatClassListBox = createBoatClassListBox();
|
||||
leftPanel.add(boatClassListBox);
|
||||
Button showBoatClassDiagramButton = new Button(stringMessages.showDiagram());
|
||||
showBoatClassDiagramButton.addClickHandler(new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
chartPanel.showLoadingInfo();
|
||||
sailingService.showCachedPolarSheetForBoatClass(
|
||||
boatClassListBox.getItemText(boatClassListBox.getSelectedIndex()),
|
||||
new AsyncCallback<PolarSheetGenerationResponse>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(caught.getLocalizedMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(PolarSheetGenerationResponse result) {
|
||||
String name = createNameForPolarSheet(result);
|
||||
chartPanel.getPolarSheetsDataMap().put(result.getId(), result.getData());
|
||||
chartPanel.setData(name, result.getData());
|
||||
chartPanel.hideLoadingInfo();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
leftPanel.add(showBoatClassDiagramButton);
|
||||
}
|
||||
|
||||
private ListBox createBoatClassListBox() {
|
||||
final ListBox boatClassListBox = new ListBox();
|
||||
sailingService.getBoatClassNamesWithPolarSheetsAvailable(new AsyncCallback<List<String>>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(caught.getLocalizedMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(List<String> result) {
|
||||
for (String item : result) {
|
||||
boatClassListBox.addItem(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return boatClassListBox;
|
||||
}
|
||||
|
||||
private void setEventListenersForPolarSheetChart() {
|
||||
PointSelectEventHandler pointSelectEventHandler = new PointSelectEventHandler() {
|
||||
@Override
|
||||
@@ -144,8 +204,8 @@ public class PolarSheetsPanel extends SplitLayoutPanel implements RaceSelectionC
|
||||
return polarSheetsGenerationStatusLabel;
|
||||
}
|
||||
|
||||
private PolarSheetsChartPanel createPolarSheetsChartPanel() {
|
||||
chartPanel = new PolarSheetsChartPanel(stringMessages);
|
||||
private PolarSheetsChartPanel createPolarSheetsChartPanel(AngleOverDataSizeHistogramPanel angleOverDataSizeHistogramPanel) {
|
||||
chartPanel = new PolarSheetsChartPanel(stringMessages, angleOverDataSizeHistogramPanel);
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
|
||||
+42
-22
@@ -190,7 +190,6 @@ import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
|
||||
import com.sap.sailing.domain.polarsheets.PolarSheetGenerationWorker;
|
||||
import com.sap.sailing.domain.racelog.RaceLog;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEventFactory;
|
||||
@@ -332,6 +331,7 @@ import com.sap.sailing.manage2sail.EventResultDescriptor;
|
||||
import com.sap.sailing.manage2sail.Manage2SailEventResultsParserImpl;
|
||||
import com.sap.sailing.manage2sail.RaceResultDescriptor;
|
||||
import com.sap.sailing.manage2sail.RegattaResultDescriptor;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.resultimport.ResultUrlProvider;
|
||||
import com.sap.sailing.resultimport.ResultUrlRegistry;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
@@ -395,7 +395,7 @@ import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SailingSimulator;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagramCSV;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagramGPS;
|
||||
import com.sap.sailing.simulator.impl.SailingSimulatorImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
|
||||
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
|
||||
@@ -439,7 +439,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
|
||||
private final ServiceTracker<DeviceIdentifierStringSerializationHandler, DeviceIdentifierStringSerializationHandler>
|
||||
deviceIdentifierStringSerializationHandlerTracker;
|
||||
|
||||
|
||||
private final com.sap.sailing.domain.tractracadapter.persistence.MongoObjectFactory tractracMongoObjectFactory;
|
||||
|
||||
private final DomainObjectFactory domainObjectFactory;
|
||||
@@ -472,7 +472,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
private final SwissTimingReplayService swissTimingReplayService;
|
||||
|
||||
private final QuickRanksLiveCache quickRanksLiveCache;
|
||||
|
||||
public SailingServiceImpl() {
|
||||
BundleContext context = Activator.getDefault();
|
||||
Activator activator = Activator.getInstance();
|
||||
@@ -1459,6 +1458,15 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier) {
|
||||
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
|
||||
BoatClass boatClass = trackedRace.getRace().getBoatClass();
|
||||
PolarDataService polarData = getService().getPolarDataService();
|
||||
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
|
||||
return new Boolean(polarDiagram != null);
|
||||
};
|
||||
|
||||
@Override
|
||||
public SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
|
||||
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
|
||||
@@ -1472,13 +1480,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
if (trackedLeg == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Waypoint fromWaypoint = trackedLeg.getLeg().getFrom();
|
||||
Position startPosition = trackedRace.getApproximatePosition(fromWaypoint, fromTimePoint);
|
||||
Waypoint fromWaypoint = trackedLeg.getLeg().getFrom();
|
||||
|
||||
// get next mark as end-position
|
||||
Waypoint toWaypoint = trackedLeg.getLeg().getTo();
|
||||
Position endPosition = trackedRace.getApproximatePosition(toWaypoint, fromTimePoint);
|
||||
|
||||
TimePoint startTimePoint = null;
|
||||
TimePoint endTimePoint = null;
|
||||
@@ -1495,9 +1500,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
}
|
||||
legDuration = endTimePoint.asMillis() - startTimePoint.asMillis();
|
||||
Position startPosition = trackedRace.getApproximatePosition(fromWaypoint, startTimePoint);
|
||||
Position endPosition = trackedRace.getApproximatePosition(toWaypoint, endTimePoint);
|
||||
|
||||
if (startTimePoint.asDate().equals(prevStartTime)) {
|
||||
return new SimulatorResultsDTO(startTimePoint.asDate(), 0, null, null, null, null);
|
||||
return new SimulatorResultsDTO(startTimePoint.asDate(), 0, 0, null, null, null, null);
|
||||
}
|
||||
|
||||
// determine legtype upwind/downwind/reaching
|
||||
@@ -1518,14 +1525,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
List<Position> course = new ArrayList<Position>();
|
||||
course.add(startPosition);
|
||||
course.add(endPosition);
|
||||
String csvFilePath = "PolarDiagram49STG.csv";
|
||||
PolarDiagram polarDiagram = null;
|
||||
try {
|
||||
polarDiagram = new PolarDiagramCSV(csvFilePath);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
BoatClass boatClass = trackedRace.getRace().getBoatClass();
|
||||
PolarDataService polarData = getService().getPolarDataService();
|
||||
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
|
||||
SimulationParameters simulationPars = new SimulationParametersImpl(course, polarDiagram, windField, SailingSimulatorConstants.ModeEvent, true, true);
|
||||
|
||||
// for upwind/downwind, run simulation with start-time, start-position, end-position and windfield
|
||||
@@ -1559,7 +1561,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
rcDTO.coursePositions.waypointPositions.add(posDTO);
|
||||
posDTO = SimulatorServiceUtils.toPositionDTO(endPosition);
|
||||
rcDTO.coursePositions.waypointPositions.add(posDTO);
|
||||
result = new SimulatorResultsDTO(startTimePoint.asDate(), legDuration, rcDTO, pathDTOs, null, null);
|
||||
result = new SimulatorResultsDTO(startTimePoint.asDate(), timeStep.asMillis(), legDuration, rcDTO, pathDTOs, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3883,15 +3885,33 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
for (RegattaAndRaceIdentifier race : selectedRaces) {
|
||||
trackedRaces.add(service.getTrackedRace(race));
|
||||
}
|
||||
PolarSheetGenerationWorker genWorker = new PolarSheetGenerationWorker(trackedRaces, settings, executor);
|
||||
genWorker.startPolarSheetGeneration();
|
||||
if (name == null || name.isEmpty()) {
|
||||
name = getCommonBoatClass(trackedRaces);
|
||||
}
|
||||
PolarSheetsData result = genWorker.get();
|
||||
PolarDataService polarDataService = service.getPolarDataService();
|
||||
PolarSheetsData result = polarDataService.generatePolarSheet(trackedRaces, settings, executor);
|
||||
return new PolarSheetGenerationResponseImpl(id, name, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getBoatClassNamesWithPolarSheetsAvailable() {
|
||||
Set<BoatClass> boatClasses = getService().getPolarDataService().getAllBoatClassesWithPolarSheetsAvailable();
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (BoatClass boatClass : boatClasses) {
|
||||
names.add(boatClass.getName());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetGenerationResponse showCachedPolarSheetForBoatClass(String boatClassName) {
|
||||
BoatClass boatClass = getService().getBaseDomainFactory().getOrCreateBoatClass(boatClassName);
|
||||
PolarSheetsData data = getService().getPolarDataService().getPolarSheetForBoatClass(boatClass);
|
||||
String name = boatClassName + "_OVERALL";
|
||||
String id = name;
|
||||
return new PolarSheetGenerationResponseImpl(id, name, data);
|
||||
}
|
||||
|
||||
private String getCommonBoatClass(Set<TrackedRace> trackedRaces) {
|
||||
BoatClass boatClass = null;
|
||||
for (TrackedRace race : trackedRaces) {
|
||||
@@ -5075,4 +5095,4 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -301,7 +301,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
windFieldDTO = this.createWindFieldDTO(wf, startTime, endTime, timeStep, params); // params.isShowStreamlets2(), params.isShowLines(), params.getSeedLines());
|
||||
}
|
||||
|
||||
return new SimulatorResultsDTO(null, 0, rcDTO, pathDTOs, windFieldDTO, simulatedPaths.notificationMessage);
|
||||
return new SimulatorResultsDTO(null, timeStep.asMillis(), 0, rcDTO, pathDTOs, windFieldDTO, simulatedPaths.notificationMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-1
@@ -7,6 +7,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
public class SimulatorResultsDTO implements IsSerializable {
|
||||
|
||||
private Date startTime;
|
||||
private long timeStep;
|
||||
private long legDuration;
|
||||
private RaceMapDataDTO raceCourse;
|
||||
private WindFieldDTO windField;
|
||||
@@ -15,6 +16,7 @@ public class SimulatorResultsDTO implements IsSerializable {
|
||||
|
||||
public SimulatorResultsDTO(){
|
||||
this.startTime = null;
|
||||
this.timeStep = 0;
|
||||
this.legDuration = 0;
|
||||
this.raceCourse = null;
|
||||
this.windField = null;
|
||||
@@ -22,8 +24,9 @@ public class SimulatorResultsDTO implements IsSerializable {
|
||||
this.notificationMessage = "";
|
||||
}
|
||||
|
||||
public SimulatorResultsDTO(final Date startTime, final long legDuration, final RaceMapDataDTO raceCourse, final PathDTO[] paths, final WindFieldDTO windField, final String notificationMessage) {
|
||||
public SimulatorResultsDTO(final Date startTime, final long timeStep, final long legDuration, final RaceMapDataDTO raceCourse, final PathDTO[] paths, final WindFieldDTO windField, final String notificationMessage) {
|
||||
this.startTime = startTime;
|
||||
this.timeStep = timeStep;
|
||||
this.legDuration = legDuration;
|
||||
this.raceCourse = raceCourse;
|
||||
this.paths = paths;
|
||||
@@ -39,6 +42,14 @@ public class SimulatorResultsDTO implements IsSerializable {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public long getTimeStep() {
|
||||
return this.timeStep;
|
||||
}
|
||||
|
||||
public void setTimeStep(long timeStep) {
|
||||
this.timeStep = timeStep;
|
||||
}
|
||||
|
||||
public long getLegDuration() {
|
||||
return this.legDuration;
|
||||
}
|
||||
|
||||
+30
-30
@@ -28,8 +28,6 @@ import com.sap.sailing.gwt.ui.simulator.util.ColorPalette;
|
||||
import com.sap.sailing.gwt.ui.simulator.util.ColorPaletteGenerator;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
|
||||
import com.sap.sse.gwt.client.player.TimeListener;
|
||||
import com.sap.sse.gwt.client.player.Timer;
|
||||
|
||||
/**
|
||||
* A Google Maps overlay based on an HTML5 canvas for drawing simulation results on the {@link RaceMap}.
|
||||
@@ -37,7 +35,7 @@ import com.sap.sse.gwt.client.player.Timer;
|
||||
* @author Christopher Ronnewinkel (D036654)
|
||||
*
|
||||
*/
|
||||
public class RaceSimulationOverlay extends FullCanvasOverlay implements TimeListener {
|
||||
public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
|
||||
public static final String GET_SIMULATION_CATEGORY = "getSimulation";
|
||||
private final String textColor = "Black";
|
||||
@@ -47,21 +45,18 @@ public class RaceSimulationOverlay extends FullCanvasOverlay implements TimeLis
|
||||
private double rectWidth = 20;
|
||||
private double rectHeight = 20;
|
||||
private final StringMessages stringMessages;
|
||||
private final Timer timer;
|
||||
private Date lastSimulationTime;
|
||||
private final long deltaSimulationTime = 15000;
|
||||
private final RegattaAndRaceIdentifier raceIdentifier;
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final AsyncActionsExecutor asyncActionsExecutor;
|
||||
private final ColorPalette colors;
|
||||
private SimulatorResultsDTO simulationResult;
|
||||
private PathDTO racePath;
|
||||
private int raceLeg = 0;
|
||||
private Date prevStartTime;
|
||||
private Canvas simulationLegend;
|
||||
|
||||
public RaceSimulationOverlay(MapWidget map, int zIndex, final Timer timer, RegattaAndRaceIdentifier raceIdentifier, SailingServiceAsync sailingService, StringMessages stringMessages, AsyncActionsExecutor asyncActionsExecutor) {
|
||||
public RaceSimulationOverlay(MapWidget map, int zIndex, RegattaAndRaceIdentifier raceIdentifier, SailingServiceAsync sailingService, StringMessages stringMessages, AsyncActionsExecutor asyncActionsExecutor) {
|
||||
super(map, zIndex);
|
||||
this.timer = timer;
|
||||
this.raceIdentifier = raceIdentifier;
|
||||
this.sailingService = sailingService;
|
||||
this.stringMessages = stringMessages;
|
||||
@@ -69,30 +64,22 @@ public class RaceSimulationOverlay extends FullCanvasOverlay implements TimeLis
|
||||
this.colors = new ColorPaletteGenerator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(final Date newTime, final Date oldTime) {
|
||||
if (lastSimulationTime == null) {
|
||||
lastSimulationTime = new Date(newTime.getTime() - deltaSimulationTime);
|
||||
}
|
||||
if (Math.abs(newTime.getTime() - lastSimulationTime.getTime()) >= deltaSimulationTime) {
|
||||
lastSimulationTime = newTime;
|
||||
this.simulate(newTime);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToMap() {
|
||||
if (timer != null) {
|
||||
timer.addTimeListener(this);
|
||||
}
|
||||
public void updateLeg(int newLeg, Date newTime, boolean clearCanvas) {
|
||||
if ((newLeg != raceLeg)&&(this.isVisible())) {
|
||||
raceLeg = newLeg;
|
||||
if (clearCanvas) {
|
||||
this.clearCanvas();
|
||||
}
|
||||
this.simulate(newTime);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromMap() {
|
||||
if (timer != null) {
|
||||
timer.removeTimeListener(this);
|
||||
}
|
||||
this.setVisible(false);
|
||||
public void setVisible(boolean isVisible) {
|
||||
super.setVisible(isVisible);
|
||||
if (simulationLegend != null) {
|
||||
simulationLegend.setVisible(isVisible);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,7 +164,20 @@ public class RaceSimulationOverlay extends FullCanvasOverlay implements TimeLis
|
||||
}
|
||||
}
|
||||
ctxt.stroke();
|
||||
ctxt.setGlobalAlpha(1.0);
|
||||
SimulatorWindDTO start = points.get(0);
|
||||
long timeStep = simulationResult.getTimeStep();
|
||||
for(SimulatorWindDTO point : points) {
|
||||
if ((point.timepoint - start.timepoint) % (timeStep) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Point px = mapProjection.fromLatLngToContainerPixel(LatLng.newInstance(point.position.latDeg, point.position.lngDeg));
|
||||
ctxt.beginPath();
|
||||
ctxt.arc(px.getX(), px.getY(), 1.5, 0, 2*Math.PI);
|
||||
ctxt.closePath();
|
||||
ctxt.stroke();
|
||||
}
|
||||
colorIdx--;
|
||||
}
|
||||
|
||||
|
||||
Regular → Executable
+31
-30
@@ -1,30 +1,31 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Test
|
||||
Bundle-SymbolicName: com.sap.sailing.mongodb.test
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Fragment-Host: com.sap.sse.mongodb
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.shared.android,
|
||||
com.sap.sailing.domain.test,
|
||||
com.tractrac.clientmodule;bundle-version="2.0.0",
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.server,
|
||||
com.sap.sailing.expeditionconnector,
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
com.sap.sailing.domain.swisstimingadapter,
|
||||
org.objenesis;bundle-version="1.3.0",
|
||||
org.junit4;bundle-version="4.8.2",
|
||||
org.hamcrest;bundle-version="1.1.0",
|
||||
org.mockito.mockito-core;bundle-version="1.9.5",
|
||||
com.sap.sailing.domain.racelogtrackingadapter.testsupport,
|
||||
com.sap.sailing.server.gateway;bundle-version="1.0.0",
|
||||
com.sap.sse.common
|
||||
Import-Package: com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain.common.impl,
|
||||
com.sap.sailing.domain.common.racelog,
|
||||
com.sap.sailing.domain.common.racelog.tracking
|
||||
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Test
|
||||
Bundle-SymbolicName: com.sap.sailing.mongodb.test
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Fragment-Host: com.sap.sse.mongodb
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.shared.android,
|
||||
com.sap.sailing.domain.test,
|
||||
com.tractrac.clientmodule;bundle-version="2.0.0",
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.server,
|
||||
com.sap.sailing.expeditionconnector,
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
com.sap.sailing.domain.swisstimingadapter,
|
||||
org.objenesis;bundle-version="1.3.0",
|
||||
org.junit4;bundle-version="4.8.2",
|
||||
org.hamcrest;bundle-version="1.1.0",
|
||||
org.mockito.mockito-core;bundle-version="1.9.5",
|
||||
com.sap.sailing.polars;bundle-version="1.0.0",
|
||||
com.sap.sailing.domain.racelogtrackingadapter.testsupport,
|
||||
com.sap.sailing.server.gateway;bundle-version="1.0.0",
|
||||
com.sap.sse.common
|
||||
Import-Package: com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain.common.impl,
|
||||
com.sap.sailing.domain.common.racelog,
|
||||
com.sap.sailing.domain.common.racelog.tracking
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.sap.sailing.polars.test</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>
|
||||
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
pluginProject.extensions=false
|
||||
resolve.requirebundle=false
|
||||
@@ -0,0 +1,12 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: PolarsTest
|
||||
Bundle-SymbolicName: com.sap.sailing.polars.test
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Fragment-Host: com.sap.sailing.polars
|
||||
Import-Package: com.sap.sailing.domain.test.mock,
|
||||
org.junit;version="4.8.2"
|
||||
Require-Bundle: org.mockito.mockito-core;bundle-version="1.9.5",
|
||||
org.hamcrest;bundle-version="1.1.0"
|
||||
@@ -0,0 +1,4 @@
|
||||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package com.sap.sailing.polars.caching.test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.caching.PolarFixCacheRaceInterval;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class PolarFixCacheRaceIntervalTest {
|
||||
|
||||
@Test
|
||||
public void testIntervalJoin() {
|
||||
TrackedRace mockedTrackedRace1 = mock(TrackedRace.class);
|
||||
TrackedRace mockedTrackedRace2 = mock(TrackedRace.class);
|
||||
|
||||
Competitor mockedCompetitor1 = mock(Competitor.class);
|
||||
Competitor mockedCompetitor2 = mock(Competitor.class);
|
||||
|
||||
Calendar calender = Calendar.getInstance();
|
||||
calender.set(2014, 3, 17, 16, 0, 0);
|
||||
TimePoint timePoint1 = new MillisecondsTimePoint(calender.getTime());
|
||||
calender.set(2014, 3, 17, 16, 10, 0);
|
||||
TimePoint timePoint2 = new MillisecondsTimePoint(calender.getTime());
|
||||
|
||||
PolarFixCacheRaceInterval interval1 = createInterval1(
|
||||
mockedTrackedRace1, mockedTrackedRace2, mockedCompetitor1,
|
||||
mockedCompetitor2, timePoint1, timePoint2);
|
||||
|
||||
PolarFixCacheRaceInterval interval2 = createInterval2(
|
||||
mockedTrackedRace1, mockedTrackedRace2, mockedCompetitor1,
|
||||
timePoint2);
|
||||
PolarFixCacheRaceInterval joined = interval1.join(interval2);
|
||||
|
||||
Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> joinedMap = joined
|
||||
.getCompetitorAndTimepointsForRace();
|
||||
|
||||
Map<Competitor, Pair<TimePoint, TimePoint>> explicitIntervalForRace1 = joinedMap.get(mockedTrackedRace1);
|
||||
assertThat(explicitIntervalForRace1, notNullValue(Map.class));
|
||||
Pair<TimePoint, TimePoint> explicitIntervalForCompetitor1 = explicitIntervalForRace1.get(mockedCompetitor1);
|
||||
assertThat(explicitIntervalForCompetitor1, notNullValue(Pair.class));
|
||||
|
||||
TimePoint start1 = explicitIntervalForCompetitor1.getA();
|
||||
TimePoint end1 = explicitIntervalForCompetitor1.getB();
|
||||
|
||||
assertThat(start1, is(timePoint1));
|
||||
assertThat(end1, is(timePoint2));
|
||||
|
||||
}
|
||||
|
||||
private PolarFixCacheRaceInterval createInterval1(
|
||||
TrackedRace mockedTrackedRace1, TrackedRace mockedTrackedRace2,
|
||||
Competitor mockedCompetitor1, Competitor mockedCompetitor2,
|
||||
TimePoint timePoint1, TimePoint timePoint2) {
|
||||
Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> competitorAndTimepointsForRace = new HashMap<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>>();
|
||||
HashMap<Competitor, Pair<TimePoint, TimePoint>> mapForRace1 = new HashMap<Competitor, Pair<TimePoint, TimePoint>>();
|
||||
mapForRace1.put(mockedCompetitor1, new Pair<TimePoint, TimePoint>(timePoint1, timePoint1));
|
||||
competitorAndTimepointsForRace.put(mockedTrackedRace1, mapForRace1);
|
||||
HashMap<Competitor, Pair<TimePoint, TimePoint>> mapForRace2 = new HashMap<Competitor, Pair<TimePoint, TimePoint>>();
|
||||
mapForRace2.put(mockedCompetitor2, new Pair<TimePoint, TimePoint>(timePoint1, timePoint2));
|
||||
competitorAndTimepointsForRace.put(mockedTrackedRace2, mapForRace2);
|
||||
PolarFixCacheRaceInterval interval1 = new PolarFixCacheRaceInterval(
|
||||
competitorAndTimepointsForRace);
|
||||
return interval1;
|
||||
}
|
||||
|
||||
private PolarFixCacheRaceInterval createInterval2(
|
||||
TrackedRace mockedTrackedRace1, TrackedRace mockedTrackedRace2,
|
||||
Competitor mockedCompetitor1, TimePoint timePoint2) {
|
||||
Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> competitorAndTimepointsForRace = new HashMap<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>>();
|
||||
HashMap<Competitor, Pair<TimePoint, TimePoint>> mapForRace1 = new HashMap<Competitor, Pair<TimePoint, TimePoint>>();
|
||||
mapForRace1.put(mockedCompetitor1, new Pair<TimePoint, TimePoint>(
|
||||
timePoint2, timePoint2));
|
||||
competitorAndTimepointsForRace.put(mockedTrackedRace1, mapForRace1);
|
||||
PolarFixCacheRaceInterval interval2 = new PolarFixCacheRaceInterval(
|
||||
competitorAndTimepointsForRace);
|
||||
return interval2;
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.sap.sailing.polars.clusters.test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.polars.clusters.SpeedClusterGroup;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
|
||||
public class SpeedClusterGroupTest {
|
||||
|
||||
@Test
|
||||
public void testWithZeroLevels() {
|
||||
double[] levelMidsInKnots = {};
|
||||
SpeedClusterGroup group = new SpeedClusterGroup("test", levelMidsInKnots, 4);
|
||||
assertThat(group.getClusterFor(new KnotSpeedImpl(0)), nullValue());
|
||||
assertThat(group.getClusterFor(new KnotSpeedImpl(6)), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithOneLevelReachingZero() {
|
||||
double[] levelMidsInKnots = { 4 };
|
||||
SpeedClusterGroup group = new SpeedClusterGroup("test", levelMidsInKnots, 4);
|
||||
Cluster<Speed> clusterForZero = group.getClusterFor(new KnotSpeedImpl(0));
|
||||
assertThat(clusterForZero, notNullValue());
|
||||
Cluster<Speed> clusterForSix = group.getClusterFor(new KnotSpeedImpl(6));
|
||||
assertThat(clusterForSix, notNullValue());
|
||||
assertThat(clusterForSix == clusterForZero, equalTo(true));
|
||||
assertThat(group.getClusterFor(new KnotSpeedImpl(9)), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithOneLevelNotReachingZero() {
|
||||
double[] levelMidsInKnots = { 7 };
|
||||
SpeedClusterGroup group = new SpeedClusterGroup("test", levelMidsInKnots, 4);
|
||||
Cluster<Speed> clusterForNine = group.getClusterFor(new KnotSpeedImpl(9));
|
||||
assertThat(clusterForNine, notNullValue());
|
||||
Cluster<Speed> clusterForSix = group.getClusterFor(new KnotSpeedImpl(6));
|
||||
assertThat(clusterForSix, notNullValue());
|
||||
assertThat(clusterForSix == clusterForNine, equalTo(true));
|
||||
assertThat(group.getClusterFor(new KnotSpeedImpl(0)), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMultipleLevelsWithNoEmptyRoomInbetween() {
|
||||
double[] levelMidsInKnots = { 4, 6, 8, 10, 12, 15 };
|
||||
SpeedClusterGroup group = new SpeedClusterGroup("test", levelMidsInKnots, 4);
|
||||
Cluster<Speed> clusterForFourteen = group.getClusterFor(new KnotSpeedImpl(14));
|
||||
assertThat(clusterForFourteen, notNullValue());
|
||||
Cluster<Speed> clusterForThirteen = group.getClusterFor(new KnotSpeedImpl(13));
|
||||
assertThat(clusterForThirteen, notNullValue());
|
||||
assertThat(clusterForThirteen == clusterForFourteen, equalTo(false));
|
||||
assertThat(group.getClusterFor(new KnotSpeedImpl(20)), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMultipleLevelsWithRoomInbetween() {
|
||||
double[] levelMidsInKnots = { 4, 6, 15 };
|
||||
SpeedClusterGroup group = new SpeedClusterGroup("test", levelMidsInKnots, 4);
|
||||
Cluster<Speed> clusterForFourteen = group.getClusterFor(new KnotSpeedImpl(14));
|
||||
assertThat(clusterForFourteen, notNullValue());
|
||||
Cluster<Speed> clusterForSeven = group.getClusterFor(new KnotSpeedImpl(7));
|
||||
assertThat(clusterForSeven, notNullValue());
|
||||
assertThat(clusterForSeven == clusterForFourteen, equalTo(false));
|
||||
assertThat(group.getClusterFor(new KnotSpeedImpl(10.5)), nullValue());
|
||||
}
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
package com.sap.sailing.polars.mining.test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.closeTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
|
||||
import com.sap.sailing.polars.mining.PolarDataMiner;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class PolarDataMinerTest {
|
||||
|
||||
private static final int MILLISECONDS_OVER_WHICH_TO_AVERAGE_SPEED = 30;
|
||||
private static final double EPSILON = 1E-4;
|
||||
|
||||
@Test
|
||||
public void testGrouping() throws InterruptedException, TimeoutException, NoSuchMethodException,
|
||||
NotEnoughDataHasBeenAddedException {
|
||||
PolarDataMiner miner = new PolarDataMiner();
|
||||
|
||||
BoatClass mockedBoatClass = mock(BoatClass.class);
|
||||
|
||||
GPSFixMoving fix1_1 = createMockedFix(13, 00, 54.431952, 10.186767, 45, 10.5);
|
||||
GPSFixMoving fix1_2 = createMockedFix(13, 30, 54.485034, 10.538303, 44.8, 10.6);
|
||||
Competitor competitor1 = mock(Competitor.class);
|
||||
|
||||
GPSFixMoving fix2_1 = createMockedFix(13, 00, 54.443942, 10.172739, 42.2, 10);
|
||||
GPSFixMoving fix2_2 = createMockedFix(13, 30, 54.425394, 10.177404, 41.8, 10.1);
|
||||
Competitor competitor2 = mock(Competitor.class);
|
||||
|
||||
GPSFixMoving fix3_1 = createMockedFix(13, 45, 54.873740, 10.193648, 43.2, 10);
|
||||
Competitor competitor3 = mock(Competitor.class);
|
||||
|
||||
Map<Competitor, Set<GPSFixMoving>> fixesPerCompetitor = new HashMap<Competitor, Set<GPSFixMoving>>();
|
||||
|
||||
Set<GPSFixMoving> setForCompetitor1 = new HashSet<GPSFixMoving>();
|
||||
setForCompetitor1.add(fix1_1);
|
||||
setForCompetitor1.add(fix1_2);
|
||||
fixesPerCompetitor.put(competitor1, setForCompetitor1);
|
||||
|
||||
Set<GPSFixMoving> setForCompetitor2 = new HashSet<GPSFixMoving>();
|
||||
setForCompetitor2.add(fix2_1);
|
||||
setForCompetitor2.add(fix2_2);
|
||||
fixesPerCompetitor.put(competitor2, setForCompetitor2);
|
||||
|
||||
Set<GPSFixMoving> setForCompetitor3 = new HashSet<GPSFixMoving>();
|
||||
setForCompetitor2.add(fix3_1);
|
||||
fixesPerCompetitor.put(competitor3, setForCompetitor3);
|
||||
|
||||
|
||||
TrackedRace trackedRace = createMockedTrackedRace(fixesPerCompetitor, mockedBoatClass);
|
||||
|
||||
for (Entry<Competitor, Set<GPSFixMoving>> entry : fixesPerCompetitor.entrySet()) {
|
||||
Competitor competitor = entry.getKey();
|
||||
Set<GPSFixMoving> fixSet = entry.getValue();
|
||||
for (GPSFixMoving fix : fixSet) {
|
||||
miner.addFix(fix, competitor, trackedRace);
|
||||
}
|
||||
}
|
||||
|
||||
int millisLeft = 500000;
|
||||
while (miner.isCurrentlyActiveAndOrHasQueue() && millisLeft > 0) {
|
||||
Thread.sleep(100);
|
||||
millisLeft = millisLeft - 100;
|
||||
if (miner.isCurrentlyActiveAndOrHasQueue() && millisLeft <= 0) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
|
||||
SpeedWithConfidence<Void> estimatedSpeed1 = miner.estimateBoatSpeed(mockedBoatClass, new KnotSpeedImpl(15),
|
||||
new DegreeBearingImpl(44.9));
|
||||
assertThat(estimatedSpeed1, is(notNullValue()));
|
||||
assertThat(estimatedSpeed1.getObject().getKnots(), is(closeTo(10.55, EPSILON)));
|
||||
|
||||
SpeedWithConfidence<Void> estimatedSpeed2 = miner.estimateBoatSpeed(mockedBoatClass, new KnotSpeedImpl(15),
|
||||
new DegreeBearingImpl(42));
|
||||
assertThat(estimatedSpeed2, is(notNullValue()));
|
||||
assertThat(estimatedSpeed2.getObject().getKnots(), is(closeTo(10.05, EPSILON)));
|
||||
|
||||
SpeedWithConfidence<Void> estimatedSpeed3 = miner.estimateBoatSpeed(mockedBoatClass, new KnotSpeedImpl(15),
|
||||
new DegreeBearingImpl(42.8));
|
||||
assertThat(estimatedSpeed3, is(notNullValue()));
|
||||
assertThat(estimatedSpeed3.getObject().getKnots(), is(closeTo(10, EPSILON)));
|
||||
}
|
||||
|
||||
private GPSFixMoving createMockedFix(int hour, int minute, double lat, double lng, double bearingRaw, double speed) {
|
||||
GPSFixMoving fix = mock(GPSFixMoving.class);
|
||||
when(fix.getPosition()).thenReturn(new DegreePosition(lat, lng));
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2014, 4, 3, hour, minute);
|
||||
TimePoint fixTimePoint = new MillisecondsTimePoint(cal.getTime());
|
||||
when(fix.getTimePoint()).thenReturn(fixTimePoint);
|
||||
Bearing bearing = new DegreeBearingImpl(bearingRaw);
|
||||
SpeedWithBearing speedWithBearing = new KnotSpeedWithBearingImpl(speed, bearing);
|
||||
when(fix.getSpeed()).thenReturn(speedWithBearing);
|
||||
return fix;
|
||||
}
|
||||
|
||||
private TrackedRace createMockedTrackedRace(Map<Competitor, Set<GPSFixMoving>> fixesPerCompetitor,
|
||||
BoatClass mockedBoatClass) {
|
||||
TrackedRace trackedRace = mock(TrackedRace.class);
|
||||
|
||||
for (Entry<Competitor, Set<GPSFixMoving>> competitorEntry : fixesPerCompetitor.entrySet()) {
|
||||
Competitor competitor = competitorEntry.getKey();
|
||||
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = new DynamicGPSFixMovingTrackImpl<Competitor>(
|
||||
competitor, MILLISECONDS_OVER_WHICH_TO_AVERAGE_SPEED);
|
||||
when(trackedRace.getTrack(competitor)).thenReturn(track);
|
||||
for (GPSFixMoving fix : competitorEntry.getValue()) {
|
||||
track.add(fix);
|
||||
}
|
||||
}
|
||||
|
||||
RaceDefinition mockedRaceDefinition = createMockedRaceDefinition();
|
||||
when(mockedRaceDefinition.getBoatClass()).thenReturn(mockedBoatClass);
|
||||
when(trackedRace.getRace()).thenReturn(mockedRaceDefinition);
|
||||
|
||||
for (Competitor competitor : fixesPerCompetitor.keySet()) {
|
||||
MarkPassing markpassing = createMockedStartMarkPassing();
|
||||
when(trackedRace.getMarkPassing(eq(competitor), any(Waypoint.class))).thenReturn(markpassing);
|
||||
}
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2014, 4, 3, 12, 00);
|
||||
TimePoint startOfRace = new MillisecondsTimePoint(cal.getTime());
|
||||
|
||||
cal.set(2014, 4, 3, 15, 00);
|
||||
TimePoint endOfRace = new MillisecondsTimePoint(cal.getTime());
|
||||
|
||||
when(trackedRace.getStartOfRace()).thenReturn(startOfRace);
|
||||
when(trackedRace.getEndOfRace()).thenReturn(endOfRace);
|
||||
|
||||
Bearing windBearing = new DegreeBearingImpl(180);
|
||||
SpeedWithBearing windSpeed = new KnotSpeedWithBearingImpl(15, windBearing);
|
||||
|
||||
Wind wind = new WindImpl(new DegreePosition(54.431952, 10.186767), startOfRace, windSpeed);
|
||||
WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = new WindWithConfidenceImpl<>(wind, 0.5, null, false);
|
||||
// Always return same wind
|
||||
when(trackedRace.getWind(any(Position.class), any(TimePoint.class))).thenReturn(wind);
|
||||
when(trackedRace.getWind(any(Position.class), any(TimePoint.class), any())).thenReturn(wind);
|
||||
when(trackedRace.getWindWithConfidence(any(Position.class), any(TimePoint.class), any())).thenReturn(windWithConfidence);
|
||||
|
||||
return trackedRace;
|
||||
}
|
||||
|
||||
private MarkPassing createMockedStartMarkPassing() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2014, 4, 3, 12, 15);
|
||||
TimePoint startOfRaceForCompetitor = new MillisecondsTimePoint(cal.getTime());
|
||||
|
||||
MarkPassing passing = mock(MarkPassing.class);
|
||||
when(passing.getTimePoint()).thenReturn(startOfRaceForCompetitor);
|
||||
return passing;
|
||||
}
|
||||
|
||||
private RaceDefinition createMockedRaceDefinition() {
|
||||
RaceDefinition raceDefinition = mock(RaceDefinition.class);
|
||||
Course mockedCourse = createMockedCourse();
|
||||
when(raceDefinition.getCourse()).thenReturn(mockedCourse);
|
||||
BoatClass mockedBoatClass = mock(BoatClass.class);
|
||||
when(mockedBoatClass.getManeuverDegreeAngleThreshold()).thenReturn(20.0);
|
||||
when(raceDefinition.getBoatClass()).thenReturn(mockedBoatClass);
|
||||
return raceDefinition;
|
||||
}
|
||||
|
||||
private Course createMockedCourse() {
|
||||
Course course = mock(Course.class);
|
||||
return course;
|
||||
}
|
||||
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
package com.sap.sailing.polars.regression.test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.hamcrest.number.IsCloseTo;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.polars.regression.IncrementalLinearRegressionProcessor;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.impl.IncrementalLeastSquaresProcessor;
|
||||
|
||||
public class IncrementalLinearRegressionTest {
|
||||
|
||||
private static double EPSILON = 1E-12;
|
||||
|
||||
private static double VAGUE_EPSILON = 0.1;
|
||||
|
||||
private IncrementalLinearRegressionProcessor createRegressionProcessor() {
|
||||
IncrementalLinearRegressionProcessor processor = new IncrementalLeastSquaresProcessor();
|
||||
return processor;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegressionWithTwoDataPoints() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor processor = createRegressionProcessor();
|
||||
|
||||
double x1 = 3;
|
||||
double y1 = 7;
|
||||
processor.addMeasuredPoint(x1, y1);
|
||||
|
||||
double x2 = 6;
|
||||
double y2 = 14;
|
||||
processor.addMeasuredPoint(x2, y2);
|
||||
|
||||
double y = processor.getEstimatedY(x1);
|
||||
assertThat(y, new IsCloseTo(y1, EPSILON));
|
||||
|
||||
y = processor.getEstimatedY(x2);
|
||||
assertThat(y, new IsCloseTo(y2, EPSILON));
|
||||
|
||||
y = processor.getEstimatedY(4.5);
|
||||
assertThat(y, new IsCloseTo(10.5, EPSILON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegressionWithMultipleDataPoints() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor processor = createRegressionProcessor();
|
||||
|
||||
for (int i = -50; i < 51; i++) {
|
||||
processor.addMeasuredPoint(i, i);
|
||||
}
|
||||
|
||||
double y = processor.getEstimatedY(-2);
|
||||
assertThat(y, new IsCloseTo(-2, EPSILON));
|
||||
|
||||
// 2 Points off the line
|
||||
processor.addMeasuredPoint(-8, -3);
|
||||
processor.addMeasuredPoint(8, -3);
|
||||
|
||||
|
||||
y = processor.getEstimatedY(-2);
|
||||
assertThat(y, new IsCloseTo(-2, VAGUE_EPSILON));
|
||||
y = processor.getEstimatedY(20);
|
||||
assertThat(y, new IsCloseTo(20, VAGUE_EPSILON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegressionWithABigAmountOfDataPoints() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor processor = createRegressionProcessor();
|
||||
|
||||
for (int i = -1000; i < 1000; i++) {
|
||||
// For every even number + 1, else - 1
|
||||
double y = i % 2 == 0 ? i + 1 : i - 1;
|
||||
processor.addMeasuredPoint(i, y);
|
||||
}
|
||||
|
||||
double y = processor.getEstimatedY(-2);
|
||||
assertThat(y, new IsCloseTo(-2, VAGUE_EPSILON));
|
||||
y = processor.getEstimatedY(20);
|
||||
assertThat(y, new IsCloseTo(20, VAGUE_EPSILON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegressionWithZeroValueData() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor processor = createRegressionProcessor();
|
||||
|
||||
double x1 = 0;
|
||||
double y1 = 0;
|
||||
processor.addMeasuredPoint(x1, y1);
|
||||
|
||||
double x2 = 5;
|
||||
double y2 = 0;
|
||||
processor.addMeasuredPoint(x2, y2);
|
||||
|
||||
double y = processor.getEstimatedY(x1);
|
||||
assertThat(y, new IsCloseTo(y1, EPSILON));
|
||||
|
||||
y = processor.getEstimatedY(x2);
|
||||
assertThat(y, new IsCloseTo(y2, EPSILON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegressionWithNegativeData() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor processor = createRegressionProcessor();
|
||||
|
||||
double x1 = -5;
|
||||
double y1 = -5;
|
||||
processor.addMeasuredPoint(x1, y1);
|
||||
|
||||
double x2 = 5;
|
||||
double y2 = 5;
|
||||
processor.addMeasuredPoint(x2, y2);
|
||||
|
||||
double y = processor.getEstimatedY(x1);
|
||||
assertThat(y, new IsCloseTo(y1, EPSILON));
|
||||
|
||||
y = processor.getEstimatedY(x2);
|
||||
assertThat(y, new IsCloseTo(y2, EPSILON));
|
||||
|
||||
y = processor.getEstimatedY(0);
|
||||
assertThat(y, new IsCloseTo(0, EPSILON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegressionWithSmallValuedData() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor processor = createRegressionProcessor();
|
||||
|
||||
double x1 = 5E-9;
|
||||
double y1 = 5E-9;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
double yTimesI = y1 * i;
|
||||
double xTimesI = x1 * i;
|
||||
processor.addMeasuredPoint(xTimesI, yTimesI);
|
||||
if (i > 0) {
|
||||
double y = processor.getEstimatedY(xTimesI);
|
||||
assertThat(y, new IsCloseTo(yTimesI, EPSILON));
|
||||
}
|
||||
}
|
||||
// Add data that is off the line but offsetting each other
|
||||
processor.addMeasuredPoint(-x1, y1);
|
||||
processor.addMeasuredPoint(x1, -y1);
|
||||
|
||||
double y = processor.getEstimatedY(0);
|
||||
assertThat(y, new IsCloseTo(0, EPSILON));
|
||||
}
|
||||
|
||||
@Test(expected = NotEnoughDataHasBeenAddedException.class)
|
||||
public void testNoDataExceptionThrowing() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor processor = createRegressionProcessor();
|
||||
processor.getEstimatedY(15);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that y is constant for only one added data point
|
||||
*
|
||||
* @throws NotEnoughDataHasBeenAddedException
|
||||
*/
|
||||
@Test
|
||||
public void testRegressionWithOneDataPoint() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor processor = createRegressionProcessor();
|
||||
|
||||
double x1 = 3;
|
||||
double y1 = 5;
|
||||
processor.addMeasuredPoint(x1, y1);
|
||||
|
||||
double y = processor.getEstimatedY(20);
|
||||
assertThat(y, is(y1));
|
||||
}
|
||||
|
||||
/*
|
||||
* The following tests and the data are taken from: org.apache.commons.math3.stat.regression.SimpleRegressionTest
|
||||
*
|
||||
* http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/regression/
|
||||
* SimpleRegressionTest.java?view=markup
|
||||
*
|
||||
* They are adapted to use the IncrementalLinearRegressionProcessor, but the data and the asserts were kept as is
|
||||
*/
|
||||
|
||||
/*
|
||||
* NIST "Norris" refernce data set from
|
||||
* http://www.itl.nist.gov/div898/strd/lls/data/LINKS/DATA/Norris.dat
|
||||
* Strangely, order is {y,x}
|
||||
*/
|
||||
private double[][] data = { { 0.1, 0.2 }, {338.8, 337.4 }, {118.1, 118.2 },
|
||||
{888.0, 884.6 }, {9.2, 10.1 }, {228.1, 226.5 }, {668.5, 666.3 }, {998.5, 996.3 },
|
||||
{449.1, 448.6 }, {778.9, 777.0 }, {559.2, 558.2 }, {0.3, 0.4 }, {0.1, 0.6 }, {778.1, 775.5 },
|
||||
{668.8, 666.9 }, {339.3, 338.0 }, {448.9, 447.5 }, {10.8, 11.6 }, {557.7, 556.0 },
|
||||
{228.3, 228.1 }, {998.0, 995.8 }, {888.8, 887.6 }, {119.6, 120.2 }, {0.3, 0.3 },
|
||||
{0.6, 0.3 }, {557.6, 556.8 }, {339.3, 339.1 }, {888.0, 887.2 }, {998.5, 999.0 },
|
||||
{778.9, 779.0 }, {10.2, 11.1 }, {117.6, 118.3 }, {228.9, 229.2 }, {668.4, 669.1 },
|
||||
{449.2, 448.9 }, {0.2, 0.5 }
|
||||
};
|
||||
|
||||
|
||||
@Test
|
||||
public void testNorris() throws NotEnoughDataHasBeenAddedException {
|
||||
IncrementalLinearRegressionProcessor regression = createRegressionProcessor();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
regression.addMeasuredPoint(data[i][1], data[i][0]);
|
||||
}
|
||||
// Tests against certified values from
|
||||
// http://www.itl.nist.gov/div898/strd/lls/data/LINKS/DATA/Norris.dat
|
||||
assertThat(regression.getSlope(), new IsCloseTo(1.00211681802045, EPSILON));
|
||||
assertThat(regression.getIntercept(), new IsCloseTo(-0.262323073774029, EPSILON));
|
||||
// ------------ End certified data tests
|
||||
assertThat(regression.getEstimatedY(0), new IsCloseTo(-0.262323073774029, EPSILON));
|
||||
assertThat(regression.getEstimatedY(1), new IsCloseTo(1.00211681802045 - 0.26232307377402, EPSILON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerfect() {
|
||||
IncrementalLinearRegressionProcessor regression = createRegressionProcessor();
|
||||
int n = 100;
|
||||
for (int i = 0; i < n; i++) {
|
||||
regression.addMeasuredPoint(((double) i) / (n - 1), i);
|
||||
}
|
||||
assertTrue(regression.getSlope() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerfectNegative() {
|
||||
IncrementalLinearRegressionProcessor regression = createRegressionProcessor();
|
||||
int n = 100;
|
||||
for (int i = 0; i < n; i++) {
|
||||
regression.addMeasuredPoint(-((double) i) / (n - 1), i);
|
||||
}
|
||||
assertTrue(regression.getSlope() < 0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
package com.sap.sailing.polars.test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.closeTo;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.analysis.PolarSheetAnalyzer;
|
||||
import com.sap.sailing.polars.analysis.impl.PolarSheetAnalyzerImpl;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
|
||||
public class PolarSheetAnalyzerTest {
|
||||
|
||||
@Test
|
||||
public void testSpeedAndBearingCalculation() throws NotEnoughDataHasBeenAddedException {
|
||||
|
||||
PolarSheetAnalyzer analyzer = new PolarSheetAnalyzerImpl(createMockedPolarDataService());
|
||||
BoatClass boatClass = mock(BoatClass.class);
|
||||
|
||||
SpeedWithBearingWithConfidence<Void> result = analyzer.getAverageUpwindSpeedWithBearingOnStarboardTackFor(boatClass,
|
||||
new KnotSpeedImpl(14));
|
||||
assertThat(result.getObject().getKnots(), closeTo(8.5, 0.1));
|
||||
assertThat(result.getObject().getBearing().getDegrees(), closeTo(50, 0.1));
|
||||
assertThat(result.getConfidence(), closeTo(0.7, 0.1));
|
||||
|
||||
SpeedWithBearingWithConfidence<Void> result2 = analyzer.getAverageDownwindSpeedWithBearingOnStarboardTackFor(boatClass,
|
||||
new KnotSpeedImpl(14));
|
||||
assertThat(result2.getObject().getKnots(), closeTo(14.2, 0.1));
|
||||
assertThat(result2.getObject().getBearing().getDegrees(), closeTo(142.8, 0.1));
|
||||
assertThat(result2.getConfidence(), closeTo(0.6, 0.1));
|
||||
|
||||
SpeedWithBearingWithConfidence<Void> result3 = analyzer.getAverageUpwindSpeedWithBearingOnPortTackFor(boatClass,
|
||||
new KnotSpeedImpl(14));
|
||||
assertThat(result3.getObject().getKnots(), closeTo(8.6, 0.1));
|
||||
assertThat(result3.getObject().getBearing().getDegrees(), closeTo(-49.5, 0.1));
|
||||
assertThat(result3.getConfidence(), closeTo(0.7, 0.1));
|
||||
|
||||
SpeedWithBearingWithConfidence<Void> result4 = analyzer.getAverageDownwindSpeedWithBearingOnPortTackFor(boatClass,
|
||||
new KnotSpeedImpl(14));
|
||||
assertThat(result4.getObject().getKnots(), closeTo(13.5, 0.1));
|
||||
assertThat(result4.getObject().getBearing().getDegrees(), closeTo(-143.6, 0.1));
|
||||
assertThat(result4.getConfidence(), closeTo(0.25, 0.1));
|
||||
|
||||
}
|
||||
|
||||
private PolarDataService createMockedPolarDataService() throws NotEnoughDataHasBeenAddedException {
|
||||
PolarDataService mockedPolarDataService = mock(PolarDataService.class);
|
||||
Integer[] data = createCounts();
|
||||
when(mockedPolarDataService.getDataCountsForWindSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
any(Integer.class), any(Integer.class))).thenReturn(data);
|
||||
|
||||
//Starboard Upwind
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(49)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(8.478048671702888), 0.5, null));
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(50)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(8.466303997538812), 0.5, null));
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(51)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(8.583383077026435), 0.5, null));
|
||||
|
||||
//Starboard Downwind
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(141)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(13.794354053931528), 0.5, null));
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(142)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(13.665782579628802), 0.5, null));
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(143)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(14.169301888320263), 0.5, null));
|
||||
|
||||
//Port Upwind
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(-48)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(8.445599410456111), 0.5, null));
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(-50)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(8.553274292235153), 0.5, null));
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(-49)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(8.614582090896583), 0.5, null));
|
||||
|
||||
//Port Downwind
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(-145)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(13.78894715705271), 0.5, null));
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(-144)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(13.420656294986587), 0.5, null));
|
||||
when(mockedPolarDataService.getSpeed(any(BoatClass.class), argThat(new SpeedMatcher(14)),
|
||||
argThat(new BearingMatcher(-143)))).thenReturn(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(13.268607457651942), 0.5, null));
|
||||
|
||||
return mockedPolarDataService;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following data is taken from a real race. (49ER yellow R2, KW 2014)
|
||||
* Only the data for windspeed 14kn is used. The first block contains the
|
||||
* boatspeeds for every angle to the wind. The second block contains the
|
||||
* datacount for each angle (number of underlying fixes).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Integer[] createCounts() {
|
||||
Integer[] dataCountsPerAngle = { 0, 0, 2, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 3, 1, 2, 1, 6, 2, 2, 2, 1, 6, 6, 17,
|
||||
13, 19, 30, 43, 32, 50, 48, 57, 70, 76, 107, 129, 177, 186, 222, 237, 275, 285, 321, 322, 401, 451,
|
||||
466, 413, 468, 479, 459, 429, 360, 345, 317, 288, 278, 202, 175, 130, 113, 104, 100, 73, 45, 51, 52,
|
||||
37, 40, 36, 26, 23, 32, 33, 29, 29, 22, 24, 27, 23, 22, 23, 22, 21, 15, 18, 20, 14, 15, 21, 20, 19, 6,
|
||||
12, 10, 9, 10, 8, 1, 9, 6, 6, 14, 16, 7, 7, 6, 2, 5, 3, 6, 5, 8, 7, 14, 14, 12, 9, 20, 14, 22, 28, 14,
|
||||
20, 22, 29, 30, 38, 45, 50, 72, 87, 117, 114, 110, 145, 148, 156, 165, 150, 194, 224, 211, 196, 199,
|
||||
198, 182, 155, 125, 85, 69, 65, 49, 46, 61, 47, 48, 51, 45, 21, 14, 8, 9, 8, 8, 3, 7, 5, 2, 10, 8, 7,
|
||||
7, 10, 8, 13, 13, 11, 5, 9, 9, 8, 15, 6, 3, 5, 11, 9, 12, 5, 13, 12, 18, 15, 31, 25, 35, 36, 39, 59,
|
||||
71, 55, 52, 64, 72, 66, 70, 89, 104, 81, 120, 130, 117, 107, 113, 137, 136, 126, 108, 103, 92, 85, 76,
|
||||
65, 75, 75, 70, 57, 49, 49, 35, 44, 35, 18, 22, 17, 18, 10, 6, 4, 10, 9, 10, 8, 4, 4, 4, 10, 4, 4, 4,
|
||||
9, 8, 8, 7, 7, 6, 4, 7, 4, 1, 6, 6, 4, 6, 5, 5, 5, 6, 5, 9, 7, 12, 16, 10, 25, 25, 30, 29, 47, 44, 31,
|
||||
69, 68, 79, 62, 66, 86, 72, 84, 89, 75, 73, 62, 104, 110, 147, 137, 170, 204, 310, 347, 354, 377, 433,
|
||||
457, 419, 436, 467, 502, 513, 525, 463, 422, 405, 363, 309, 282, 262, 186, 162, 123, 97, 81, 45, 35,
|
||||
30, 24, 20, 12, 9, 8, 5, 6, 4, 6, 7, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1 };
|
||||
return dataCountsPerAngle;
|
||||
}
|
||||
|
||||
private class SpeedMatcher extends ArgumentMatcher<Speed> {
|
||||
|
||||
private final double speedToMatchInKnots;
|
||||
|
||||
public SpeedMatcher(double speedToMatchInKnots) {
|
||||
this.speedToMatchInKnots = speedToMatchInKnots;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(Object argument) {
|
||||
boolean result = false;
|
||||
if (argument != null) {
|
||||
Speed speed = (Speed) argument;
|
||||
if (speed.getKnots() > speedToMatchInKnots - 0.05 && speed.getKnots() < speedToMatchInKnots + 0.05) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class BearingMatcher extends ArgumentMatcher<Bearing> {
|
||||
|
||||
private final double bearingToMatchInDegrees;
|
||||
|
||||
public BearingMatcher(double bearingToMatchInDegrees) {
|
||||
this.bearingToMatchInDegrees = bearingToMatchInDegrees;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object argument) {
|
||||
boolean result = false;
|
||||
if (argument != null) {
|
||||
Bearing bearing = (Bearing) argument;
|
||||
if (bearing.getDegrees() > bearingToMatchInDegrees - 0.4999999
|
||||
&& bearing.getDegrees() < bearingToMatchInDegrees + 0.49999999) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+65
-58
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
package com.sap.sailing.polars.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -9,6 +9,7 @@ import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
@@ -44,10 +45,6 @@ import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSteppingWithMaxDistance;
|
||||
import com.sap.sailing.domain.polarsheets.DataPointWithOriginInfo;
|
||||
import com.sap.sailing.domain.polarsheets.PerRaceAndCompetitorPolarSheetGenerationWorker;
|
||||
import com.sap.sailing.domain.polarsheets.PolarSheetGenerationWorker;
|
||||
import com.sap.sailing.domain.polarsheets.PolarSheetHistogramBuilder;
|
||||
import com.sap.sailing.domain.test.mock.MockedTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
@@ -61,11 +58,19 @@ import com.sap.sailing.domain.tracking.impl.MarkPassingByTimeComparator;
|
||||
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
|
||||
import com.sap.sailing.polars.aggregation.PolarFixAggregationWorker;
|
||||
import com.sap.sailing.polars.aggregation.PolarFixAggregator;
|
||||
import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval;
|
||||
import com.sap.sailing.polars.data.DataPointWithOriginInfo;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sailing.polars.data.impl.DataPointWithOriginInfoImpl;
|
||||
import com.sap.sailing.polars.generation.PolarSheetGenerator;
|
||||
import com.sap.sailing.polars.generation.PolarSheetHistogramBuilder;
|
||||
|
||||
public class PolarSheetGenerationTest {
|
||||
|
||||
@Test
|
||||
public void testPolarSheetRawDataGeneration() throws InterruptedException {
|
||||
public void testPolarSheetRawDataGeneration() throws InterruptedException, ExecutionException {
|
||||
Executor executor = new ThreadPoolExecutor(/* corePoolSize */Runtime.getRuntime().availableProcessors(),
|
||||
/* maximumPoolSize */Runtime.getRuntime().availableProcessors(),
|
||||
/* keepAliveTime */60, TimeUnit.SECONDS,
|
||||
@@ -81,27 +86,29 @@ public class PolarSheetGenerationTest {
|
||||
TimePoint startTime = new MillisecondsTimePoint(9);
|
||||
TimePoint endTime = new MillisecondsTimePoint(80);
|
||||
// Only used for storing and exporting results in this test case:
|
||||
PolarSheetGenerationWorker resultContainer = new PolarSheetGenerationWorker(new HashSet<TrackedRace>(),
|
||||
PolarFixAggregator resultContainer = new PolarFixAggregator(new SimplePolarFixRaceInterval(
|
||||
new HashSet<TrackedRace>()),
|
||||
settings, executor);
|
||||
|
||||
BoatClass forelle = new BoatClassImpl("Forelle", true);
|
||||
Competitor competitor = new CompetitorImpl(UUID.randomUUID(), "Hans Frantz", Color.RED, new TeamImpl("SAP", null, null),
|
||||
new BoatImpl("Schnelle Forelle", forelle, "GER000"));
|
||||
|
||||
PerRaceAndCompetitorPolarSheetGenerationWorker task = new PerRaceAndCompetitorPolarSheetGenerationWorker(race,
|
||||
resultContainer, startTime, endTime, competitor, settings);
|
||||
PolarFixAggregationWorker task = new PolarFixAggregationWorker(race,
|
||||
resultContainer, startTime, endTime,
|
||||
competitor, settings, null);
|
||||
|
||||
executor.execute(task);
|
||||
|
||||
double timeUntilTimeout = 1000;
|
||||
while (!task.isDone() && timeUntilTimeout > 0) {
|
||||
Thread.sleep(100);
|
||||
timeUntilTimeout = timeUntilTimeout - 0.1;
|
||||
}
|
||||
|
||||
Set<PolarFix> fixes = resultContainer.getAggregationResultAsSingleList();
|
||||
|
||||
Assert.assertTrue(task.isDone());
|
||||
|
||||
PolarSheetsData data = resultContainer.getPolarData();
|
||||
PolarSheetGenerator generator = new PolarSheetGenerator(fixes, settings);
|
||||
PolarSheetsData data = generator.generate();
|
||||
Assert.assertEquals(4, data.getDataCount());
|
||||
Assert.assertEquals(4.0, data.getAveragedPolarDataByWindSpeed()[0][45]);
|
||||
Assert.assertEquals(2.0, data.getAveragedPolarDataByWindSpeed()[0][55]);
|
||||
@@ -119,15 +126,15 @@ public class PolarSheetGenerationTest {
|
||||
|
||||
|
||||
List<DataPointWithOriginInfo> rawData = new ArrayList<DataPointWithOriginInfo>();
|
||||
rawData.add(new DataPointWithOriginInfo(1.09, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfo(1.0, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfo(1.11, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfo(1.46, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfo(1.56, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfo(2.05, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfo(2.09, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfo(3.0, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfo(2.999, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(1.09, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(1.0, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(1.11, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(1.46, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(1.56, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(2.05, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(2.09, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(3.0, "", ""));
|
||||
rawData.add(new DataPointWithOriginInfoImpl(2.999, "", ""));
|
||||
PolarSheetsHistogramData result = builder.build(rawData, 0, 0);
|
||||
Number[] xValues = result.getxValues();
|
||||
Assert.assertEquals(10, xValues.length);
|
||||
@@ -144,49 +151,49 @@ public class PolarSheetGenerationTest {
|
||||
public void testOutlierNeighborhoodAlgorithm() {
|
||||
PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createStandardPolarSettings();
|
||||
List<DataPointWithOriginInfo> values = new ArrayList<DataPointWithOriginInfo>();
|
||||
values.add(new DataPointWithOriginInfo(0., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfo(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(0., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
values.add(new DataPointWithOriginInfoImpl(20., "", ""));
|
||||
int[] count = new int[1];
|
||||
count[0] = values.size();
|
||||
Map<Integer, List<DataPointWithOriginInfo>> valuesInMap = new HashMap<Integer, List<DataPointWithOriginInfo>>();
|
||||
valuesInMap.put(0, values);
|
||||
double pct = PolarSheetGenerationWorker.getNeighboorhoodSizePercentage(count, valuesInMap, 0, 0,
|
||||
new DataPointWithOriginInfo(0.0, "", ""), settings);
|
||||
double pct = PolarSheetGenerator.getNeighboorhoodSizePercentage(count, valuesInMap, 0, 0,
|
||||
new DataPointWithOriginInfoImpl(0.0, "", ""), settings);
|
||||
|
||||
Assert.assertTrue(pct < 0.05);
|
||||
|
||||
pct = PolarSheetGenerationWorker.getNeighboorhoodSizePercentage(count, valuesInMap, 0, 2,
|
||||
new DataPointWithOriginInfo(20.0, "", ""), settings);
|
||||
pct = PolarSheetGenerator.getNeighboorhoodSizePercentage(count, valuesInMap, 0, 2,
|
||||
new DataPointWithOriginInfoImpl(20.0, "", ""), settings);
|
||||
|
||||
Assert.assertTrue(pct > 0.05);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.sap.sailing.polars</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.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,23 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Domain
|
||||
Bundle-SymbolicName: com.sap.sailing.polars
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-ClassPath: .
|
||||
Export-Package:
|
||||
com.sap.sailing.polars,
|
||||
com.sap.sailing.polars.analysis,
|
||||
com.sap.sailing.polars.data,
|
||||
com.sap.sailing.polars.factory,
|
||||
com.sap.sailing.polars.regression
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle:
|
||||
com.sap.sailing.domain.common;bundle-version="1.0.0",
|
||||
com.sap.sailing.domain,
|
||||
com.sap.sse.datamining,
|
||||
com.sap.sse.datamining.shared;bundle-version="1.0.0"
|
||||
Import-Package:
|
||||
com.sap.sailing.util,
|
||||
com.sap.sse.common
|
||||
@@ -0,0 +1,4 @@
|
||||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
||||
@@ -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.polars</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.polars;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
|
||||
public class NoPolarDataAvailableException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -6939576877174310618L;
|
||||
|
||||
private final BoatClass boatClass;
|
||||
private final Speed windSpeed;
|
||||
private final Bearing bearingToTheWind;
|
||||
|
||||
public NoPolarDataAvailableException(BoatClass boatClass, Speed windSpeed, Bearing bearingToTheWind) {
|
||||
this.boatClass = boatClass;
|
||||
this.windSpeed = windSpeed;
|
||||
this.bearingToTheWind = bearingToTheWind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return String
|
||||
.format("There was no polar data available for boat class '%s' for an angle to the wind of %.1f degrees and the wind speed of %.1f knots.",
|
||||
boatClass.getName(), bearingToTheWind.getDegrees(), windSpeed.getKnots());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.sap.sailing.polars;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.analysis.PolarSheetAnalyzer;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
|
||||
/**
|
||||
* Public Facade interface allowing access to the polars of {@link BoatClass}es.
|
||||
*
|
||||
* It uses a {@link PolarSheetAnalyzer} for more advanced analysis. It's methods are facaded in this interface for
|
||||
* central access.
|
||||
*
|
||||
* The interesting methods for a user are {@link #getSpeed(BoatClass, Speed, Bearing)} if data for a specific angle is
|
||||
* needed and {@link #getAverageSpeedWithBearing(BoatClass, Speed, LegType, Tack)}
|
||||
* which also returns the average angle for the provided parameters.
|
||||
*
|
||||
* @author Frederik Petersen (D054528)
|
||||
*
|
||||
*/
|
||||
public interface PolarDataService {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param boatClass
|
||||
* @param windSpeed
|
||||
* @param bearingToTheWind
|
||||
* Boat's direction relative to the wind. either in -180 -> +180 or 0 -> 359 degrees
|
||||
* @return The speed the boat is moving at for the specified wind and bearing according to the polar diagram.
|
||||
* @throws NotEnoughDataHasBeenAddedException
|
||||
*/
|
||||
SpeedWithConfidence<Void> getSpeed(BoatClass boatClass, Speed windSpeed, Bearing bearingToTheWind)
|
||||
throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param boatClass
|
||||
* @param windSpeed
|
||||
* @param legType
|
||||
* Should be UpWind or DownWind, there is no information for other courses yet. Use getSpeed for the
|
||||
* desired angle to get rawer information on other courses for now.
|
||||
* @param tack
|
||||
* Polar data can vary depending on the tack the boat is on.
|
||||
* @return The estimated average speed of a boat for the supplied parameters with the estimated average bearing to
|
||||
* the wind and a confidence which consists of the confidences of the wind speed, and boat speed sources (50%)
|
||||
* and a confidence calculated using the amount of underlying fixes (50%). 0 <= confidence < 1<br/>
|
||||
* A value with zero confidence doesn't have any significance!<br/><br/>
|
||||
*
|
||||
* The bearing is somewhere between -179 to +180<br/><br/>
|
||||
*
|
||||
* Get the speed using returnValue.getObject()<br/><br/>
|
||||
*
|
||||
* Returns null if the leg type is not up or downwind.
|
||||
*
|
||||
* @throws NotEnoughDataHasBeenAddedException
|
||||
* If there is not enough data to supply a value with some kind of significance.
|
||||
*/
|
||||
SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
|
||||
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
|
||||
/**
|
||||
* Generates a polar sheet for geven races and settings using the provided executor for the worker threads. This
|
||||
* method does not access a cache for now.
|
||||
*
|
||||
* @param trackedRaces
|
||||
* The set of races to generate the diagram for.
|
||||
* @param settings
|
||||
* Settings as supplied by the user.
|
||||
* @param executor
|
||||
* The executor to run the worker threads with.
|
||||
* @return The generated polar sheet with meta data.
|
||||
*/
|
||||
PolarSheetsData generatePolarSheet(Set<TrackedRace> trackedRaces, PolarSheetGenerationSettings settings,
|
||||
Executor executor) throws InterruptedException, ExecutionException;
|
||||
|
||||
void newRaceFinishedTracking(TrackedRace trackedRace);
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* The {@link BoatClass} to obtain fixes for.
|
||||
* @return All raw polar fixes for the {@link BoatClass}. The implementation is responsible for deciding wether a
|
||||
* cache is used or not.
|
||||
*/
|
||||
Set<PolarFix> getPolarFixesForBoatClass(BoatClass key);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param boatClass
|
||||
* The {@link BoatClass} to obtain the polar sheet for.
|
||||
* @return The polar sheet for all existing races of the {@link BoatClass}.
|
||||
*/
|
||||
PolarSheetsData getPolarSheetForBoatClass(BoatClass boatClass);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The {@link BoatClass}es for which there are polar sheets available via
|
||||
* {@link PolarDataService#getPolarSheetForBoatClass(BoatClass)}
|
||||
*/
|
||||
Set<BoatClass> getAllBoatClassesWithPolarSheetsAvailable();
|
||||
|
||||
void competitorPositionChanged(GPSFixMoving fix, Competitor competitor, TrackedRace createdTrackedRace);
|
||||
|
||||
/**
|
||||
* Returns underlying datacount for a given boat class and windspeed.
|
||||
* @param boatClass
|
||||
* @param windSpeed
|
||||
* @param startAngleInclusive between 0 and 359; smaller than (or equal to) endAngleExclusive
|
||||
* @param endAngleExclusive between 0 and 359; bigger than startAngleInclusive
|
||||
* @return array with datacount for all angles in the given area, else null
|
||||
*/
|
||||
Integer[] getDataCountsForWindSpeed(BoatClass boatClass, Speed windSpeed, int startAngleInclusive, int endAngleExclusive);
|
||||
|
||||
|
||||
}
|
||||
+48
-22
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
package com.sap.sailing.polars.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -19,22 +19,22 @@ import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sailing.polars.data.impl.PolarFixImpl;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
/**
|
||||
* Iterates through the fixes of one competitor in one tracked race and fills the {@link PolarSheetGenerationWorker}
|
||||
* Iterates through the fixes of one competitor in one tracked race and fills the {@link PolarFixAggregator}
|
||||
* with datapoints that are found for the speed of the boat and its angle to the wind
|
||||
*
|
||||
* @author D054528 Frederik Petersen
|
||||
*
|
||||
*/
|
||||
public class PerRaceAndCompetitorPolarSheetGenerationWorker implements Runnable {
|
||||
|
||||
// private static final Logger logger = Logger.getLogger(PerRaceAndCompetitorPolarSheetGenerationWorker.class.getName());
|
||||
public class PolarFixAggregationWorker implements Runnable {
|
||||
|
||||
private final TrackedRace race;
|
||||
|
||||
private final PolarSheetGenerationWorker polarSheetGenerationWorker;
|
||||
private final PolarFixAggregator polarSheetGenerationWorker;
|
||||
|
||||
private TimePoint startTime;
|
||||
|
||||
@@ -50,9 +50,11 @@ public class PerRaceAndCompetitorPolarSheetGenerationWorker implements Runnable
|
||||
|
||||
private PolarSheetGenerationSettings settings;
|
||||
|
||||
public PerRaceAndCompetitorPolarSheetGenerationWorker(TrackedRace race,
|
||||
PolarSheetGenerationWorker polarSheetGenerationWorker, TimePoint startTime, TimePoint endTime,
|
||||
Competitor competitor, PolarSheetGenerationSettings settings) {
|
||||
private Pair<TimePoint, TimePoint> intervalBeginningAndEnd;
|
||||
|
||||
public PolarFixAggregationWorker(TrackedRace race, PolarFixAggregator polarSheetGenerationWorker,
|
||||
TimePoint startTime, TimePoint endTime, Competitor competitor, PolarSheetGenerationSettings settings,
|
||||
Pair<TimePoint, TimePoint> intervalBeginningAndEnd) {
|
||||
super();
|
||||
this.race = race;
|
||||
this.polarSheetGenerationWorker = polarSheetGenerationWorker;
|
||||
@@ -60,9 +62,24 @@ public class PerRaceAndCompetitorPolarSheetGenerationWorker implements Runnable
|
||||
this.endTime = endTime;
|
||||
this.competitor = competitor;
|
||||
this.settings = settings;
|
||||
this.intervalBeginningAndEnd = intervalBeginningAndEnd;
|
||||
optimizeStartTime();
|
||||
optimizeEndTime();
|
||||
checkIfRaceAborted();
|
||||
checkIfIntervalBeforeOrAfterRace();
|
||||
}
|
||||
|
||||
private void checkIfIntervalBeforeOrAfterRace() {
|
||||
if (intervalBeginningAndEnd != null) {
|
||||
TimePoint intervalStart = intervalBeginningAndEnd.getA();
|
||||
if (intervalStart.after(endTime)) {
|
||||
noConfidence = true;
|
||||
}
|
||||
TimePoint intervalEnd = intervalBeginningAndEnd.getB();
|
||||
if (intervalEnd.before(startTime)) {
|
||||
noConfidence = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIfRaceAborted() {
|
||||
@@ -108,7 +125,17 @@ public class PerRaceAndCompetitorPolarSheetGenerationWorker implements Runnable
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = race.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
try {
|
||||
Iterator<GPSFixMoving> fixesIterator = track.getFixesIterator(startTime, true);
|
||||
Iterator<GPSFixMoving> fixesIterator;
|
||||
if (intervalBeginningAndEnd != null) {
|
||||
TimePoint startOfIntervalToCheck = intervalBeginningAndEnd.getA().before(startTime) ? startTime
|
||||
: intervalBeginningAndEnd.getA();
|
||||
TimePoint endOfIntervalToCheck = intervalBeginningAndEnd.getB().after(endTime) ? endTime
|
||||
: intervalBeginningAndEnd.getB();
|
||||
fixesIterator = track.getFixes(startOfIntervalToCheck, true, endOfIntervalToCheck, true).iterator();
|
||||
} else {
|
||||
// No timepoint interval given
|
||||
fixesIterator = track.getFixesIterator(startTime, true);
|
||||
}
|
||||
TimePoint lastConsideredTimePoint = null;
|
||||
if (finishedEarlyAtWaypoint != -1) {
|
||||
NavigableSet<MarkPassing> markPassings = race.getMarkPassings(competitor);
|
||||
@@ -136,40 +163,39 @@ public class PerRaceAndCompetitorPolarSheetGenerationWorker implements Runnable
|
||||
private void addFixIfValid(GPSFixTrack<Competitor, GPSFixMoving> track, GPSFixMoving fix) {
|
||||
if (!track.hasDirectionChange(fix.getTimePoint(), race.getRace().getBoatClass()
|
||||
.getManeuverDegreeAngleThreshold())) {
|
||||
List<Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>>> windWithConfidenceList = new ArrayList<Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>>>();
|
||||
List<Pair<String, WindWithConfidence<Pair<Position, TimePoint>>>> windWithConfidenceList = new ArrayList<Pair<String, WindWithConfidence<Pair<Position, TimePoint>>>>();
|
||||
if (settings.useOnlyWindGaugesForWindSpeed()) {
|
||||
if (settings.splitByWindgauges()) {
|
||||
windWithConfidenceList.addAll(addAllWindsOfWindGaugesSplitOneByOne(fix));
|
||||
} else {
|
||||
windWithConfidenceList
|
||||
.add(new Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>>(
|
||||
.add(new Pair<String, WindWithConfidence<Pair<Position, TimePoint>>>(
|
||||
createWindGaugesString(race), race.getWindWithConfidence(
|
||||
fix.getPosition(), fix.getTimePoint(),
|
||||
collectWindSourcesToIgnoreForSpeed())));
|
||||
}
|
||||
} else {
|
||||
windWithConfidenceList.add(new Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>>(
|
||||
windWithConfidenceList.add(new Pair<String, WindWithConfidence<Pair<Position, TimePoint>>>(
|
||||
"Combined", race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint())));
|
||||
}
|
||||
|
||||
for (Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>> windWithSourceIdStringPair : windWithConfidenceList) {
|
||||
WindWithConfidence<Util.Pair<Position, TimePoint>> windWithConfidence = windWithSourceIdStringPair
|
||||
for (Pair<String, WindWithConfidence<Pair<Position, TimePoint>>> windWithSourceIdStringPair : windWithConfidenceList) {
|
||||
WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = windWithSourceIdStringPair
|
||||
.getB();
|
||||
if (windWithConfidence != null && windWithConfidence.useSpeed()
|
||||
&& windWithConfidence.getConfidence() >= settings.getMinimumWindConfidence()) {
|
||||
PolarFix polarFix = new PolarFix(fix, race, track, windWithConfidence.getObject(),
|
||||
PolarFix polarFix = new PolarFixImpl(fix, race, track, windWithConfidence.getObject(),
|
||||
settings, windWithSourceIdStringPair.getA());
|
||||
polarSheetGenerationWorker.addPolarData(polarFix);
|
||||
polarSheetGenerationWorker.addPolarFix(race.getRaceIdentifier(), polarFix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<? extends Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>>> addAllWindsOfWindGaugesSplitOneByOne(
|
||||
private Collection<? extends Pair<String, WindWithConfidence<Pair<Position, TimePoint>>>> addAllWindsOfWindGaugesSplitOneByOne(
|
||||
GPSFixMoving fix) {
|
||||
Iterable<WindSource> windGaugeSources = race.getWindSources(WindSourceType.EXPEDITION);
|
||||
List<Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>>> windWithConfidenceList
|
||||
= new ArrayList<Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>>>();
|
||||
List<Pair<String, WindWithConfidence<Pair<Position, TimePoint>>>> windWithConfidenceList = new ArrayList<Pair<String, WindWithConfidence<Pair<Position, TimePoint>>>>();
|
||||
for (WindSource windGaugeSource : windGaugeSources) {
|
||||
Iterable<WindSource> allSources = race.getWindSources();
|
||||
Set<WindSource> allSourcesButTheSingleWindGaugeSource = new HashSet<WindSource>();
|
||||
@@ -178,7 +204,7 @@ public class PerRaceAndCompetitorPolarSheetGenerationWorker implements Runnable
|
||||
allSourcesButTheSingleWindGaugeSource.add(windSource);
|
||||
}
|
||||
}
|
||||
windWithConfidenceList.add(new Util.Pair<String, WindWithConfidence<Util.Pair<Position, TimePoint>>>(
|
||||
windWithConfidenceList.add(new Pair<String, WindWithConfidence<Pair<Position, TimePoint>>>(
|
||||
windGaugeSource.getId().toString(), race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(),
|
||||
allSourcesButTheSingleWindGaugeSource)));
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package com.sap.sailing.polars.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
/**
|
||||
* Allows extracting data about average speed for each angle creating the foundation of polar-sheet generation. Tasks
|
||||
* are assigned to the executor per race & per competitor and the results are filled on the go to allow progress
|
||||
* indication in the polar-sheet itself.
|
||||
*
|
||||
* @author D054528 Frederik Petersen
|
||||
*
|
||||
*/
|
||||
public class PolarFixAggregator implements Future<Map<RegattaAndRaceIdentifier, List<PolarFix>>> {
|
||||
|
||||
private final Set<PolarFixAggregationWorker> workers;
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
private final Map<RegattaAndRaceIdentifier, List<PolarFix>> fixes = new HashMap<RegattaAndRaceIdentifier, List<PolarFix>>();
|
||||
|
||||
/**
|
||||
* Will prepare the {@link PolarFixAggregationWorker}s per race & per competitor. This includes determining start
|
||||
* and end time.
|
||||
*
|
||||
* @param updateInterval
|
||||
* from which the data is to be collected
|
||||
* @param settings
|
||||
* @param executor
|
||||
* executes the tasks upon {@link #startPolarFixAggregation()}
|
||||
*/
|
||||
public PolarFixAggregator(PolarFixRaceInterval updateInterval, PolarSheetGenerationSettings settings,
|
||||
Executor executor) {
|
||||
this.executor = executor;
|
||||
workers = new HashSet<PolarFixAggregationWorker>();
|
||||
for (Entry<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> entry : updateInterval
|
||||
.getCompetitorAndTimepointsForRace().entrySet()) {
|
||||
TrackedRace race = entry.getKey();
|
||||
TimePoint startTime = race.getStartOfRace();
|
||||
TimePoint endTime = race.getEndOfRace();
|
||||
if (endTime == null) {
|
||||
endTime = race.getTimePointOfNewestEvent();
|
||||
}
|
||||
RaceDefinition raceDefinition = race.getRace();
|
||||
|
||||
Map<Competitor, Pair<TimePoint, TimePoint>> detailedInterval = entry.getValue();
|
||||
if (detailedInterval == null) {
|
||||
Iterable<Competitor> competitors = raceDefinition.getCompetitors();
|
||||
for (Competitor competitor : competitors) {
|
||||
PolarFixAggregationWorker task = new PolarFixAggregationWorker(race, this, startTime, endTime,
|
||||
competitor, settings, null);
|
||||
workers.add(task);
|
||||
}
|
||||
} else {
|
||||
for (Entry<Competitor, Pair<TimePoint, TimePoint>> competitorEntry : detailedInterval.entrySet()) {
|
||||
Competitor competitor = competitorEntry.getKey();
|
||||
Pair<TimePoint, TimePoint> intervalBeginningAndEnd = competitorEntry.getValue();
|
||||
PolarFixAggregationWorker task = new PolarFixAggregationWorker(race, this, startTime, endTime,
|
||||
competitor, settings, intervalBeginningAndEnd);
|
||||
workers.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the {@link PolarFixAggregationWorker}s
|
||||
*/
|
||||
public void startPolarFixAggregation() {
|
||||
for (Runnable task : workers) {
|
||||
executor.execute(task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called from {@link PolarFixAggregationWorker} for adding a datapoint to the list of
|
||||
* results
|
||||
* wind's speed in knots
|
||||
*/
|
||||
protected void addPolarFix(RegattaAndRaceIdentifier raceId, PolarFix polarFix) {
|
||||
synchronized (fixes) {
|
||||
List<PolarFix> existingList = fixes.get(raceId);
|
||||
if (existingList == null) {
|
||||
existingList = new ArrayList<PolarFix>();
|
||||
fixes.put(raceId, existingList);
|
||||
}
|
||||
existingList.add(polarFix);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allWorkersDone() {
|
||||
boolean complete = true;
|
||||
for (PolarFixAggregationWorker task : workers) {
|
||||
if (!task.isDone()) {
|
||||
complete = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return complete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return allWorkersDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegattaAndRaceIdentifier, List<PolarFix>> get() throws InterruptedException, ExecutionException {
|
||||
while (!isDone()) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
return fixes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegattaAndRaceIdentifier, List<PolarFix>> get(long timeout, TimeUnit unit) throws InterruptedException,
|
||||
ExecutionException,
|
||||
TimeoutException {
|
||||
long timeRun = 0;
|
||||
long timeoutInMillis = unit.toMillis(timeout);
|
||||
while (!isDone() && timeRun < timeoutInMillis) {
|
||||
Thread.sleep(100);
|
||||
timeRun = timeRun + 100;
|
||||
}
|
||||
if (timeRun >= timeoutInMillis) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
return fixes;
|
||||
}
|
||||
|
||||
public Set<PolarFix> getAggregationResultAsSingleList() throws InterruptedException,
|
||||
ExecutionException {
|
||||
Set<PolarFix> fixes = new HashSet<PolarFix>();
|
||||
Map<RegattaAndRaceIdentifier, List<PolarFix>> aggregationResult = get();
|
||||
for (List<PolarFix> list : aggregationResult.values()) {
|
||||
fixes.addAll(list);
|
||||
}
|
||||
return fixes;
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.sap.sailing.polars.aggregation;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public interface PolarFixRaceInterval {
|
||||
|
||||
Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> getCompetitorAndTimepointsForRace();
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.sap.sailing.polars.aggregation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class SimplePolarFixRaceInterval implements PolarFixRaceInterval {
|
||||
|
||||
|
||||
private final Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> intervalMap;
|
||||
|
||||
public SimplePolarFixRaceInterval(Set<TrackedRace> races) {
|
||||
intervalMap = new HashMap<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>>();
|
||||
for (TrackedRace race : races) {
|
||||
intervalMap.put(race, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> getCompetitorAndTimepointsForRace() {
|
||||
return intervalMap;
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.sap.sailing.polars.analysis;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
|
||||
public interface PolarSheetAnalyzer {
|
||||
|
||||
SpeedWithBearingWithConfidence<Void> getAverageUpwindSpeedWithBearingOnStarboardTackFor(BoatClass boatClass,
|
||||
Speed windSpeed) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
SpeedWithBearingWithConfidence<Void> getAverageDownwindSpeedWithBearingOnStarboardTackFor(BoatClass boatClass,
|
||||
Speed windSpeed) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
SpeedWithBearingWithConfidence<Void> getAverageUpwindSpeedWithBearingOnPortTackFor(BoatClass boatClass,
|
||||
Speed windSpeed) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
SpeedWithBearingWithConfidence<Void> getAverageDownwindSpeedWithBearingOnPortTackFor(BoatClass boatClass,
|
||||
Speed windSpeed) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
package com.sap.sailing.polars.analysis.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.analysis.PolarSheetAnalyzer;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
|
||||
/**
|
||||
* Extracts typical measures from polar sheets.
|
||||
*
|
||||
* @author Frederik Petersen (D054528)
|
||||
*
|
||||
*/
|
||||
public class PolarSheetAnalyzerImpl implements PolarSheetAnalyzer {
|
||||
|
||||
private static final int MINIMUM_DATA_COUNT_FOR_ONE_ANGLE = 5;
|
||||
private PolarDataService polarDataService;
|
||||
|
||||
public PolarSheetAnalyzerImpl(PolarDataService polarDataService) {
|
||||
this.polarDataService = polarDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearingWithConfidence<Void> getAverageUpwindSpeedWithBearingOnStarboardTackFor(BoatClass boatClass, Speed windSpeed)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
int startAngleInclusive = 1;
|
||||
int endAngleExclusive = 90;
|
||||
SpeedWithBearingWithConfidence<Void> speedWithBearing = estimateAnglePeakAndAverageSpeed(boatClass, windSpeed, startAngleInclusive,
|
||||
endAngleExclusive);
|
||||
return speedWithBearing;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SpeedWithBearingWithConfidence<Void> getAverageDownwindSpeedWithBearingOnStarboardTackFor(BoatClass boatClass, Speed windSpeed)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
int startAngleInclusive = 91;
|
||||
int endAngleExclusive = 180;
|
||||
SpeedWithBearingWithConfidence<Void> speedWithBearing = estimateAnglePeakAndAverageSpeed(boatClass, windSpeed, startAngleInclusive,
|
||||
endAngleExclusive);
|
||||
return speedWithBearing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearingWithConfidence<Void> getAverageDownwindSpeedWithBearingOnPortTackFor(BoatClass boatClass, Speed windSpeed)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
int startAngleInclusive = 181;
|
||||
int endAngleExclusive = 270;
|
||||
SpeedWithBearingWithConfidence<Void> speedWithBearing = estimateAnglePeakAndAverageSpeed(boatClass, windSpeed, startAngleInclusive,
|
||||
endAngleExclusive);
|
||||
return speedWithBearing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearingWithConfidence<Void> getAverageUpwindSpeedWithBearingOnPortTackFor(BoatClass boatClass, Speed windSpeed)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
int startAngleInclusive = 271;
|
||||
int endAngleExclusive = 360;
|
||||
SpeedWithBearingWithConfidence<Void> speedWithBearing = estimateAnglePeakAndAverageSpeed(boatClass, windSpeed, startAngleInclusive,
|
||||
endAngleExclusive);
|
||||
return speedWithBearing;
|
||||
}
|
||||
|
||||
private SpeedWithBearingWithConfidence<Void> estimateAnglePeakAndAverageSpeed(BoatClass boatClass, Speed windSpeed,
|
||||
int startAngleInclusive, int endAngleExclusive) throws NotEnoughDataHasBeenAddedException {
|
||||
Integer[] dataCountPerAngle = getDataCountArray(boatClass, windSpeed, startAngleInclusive, endAngleExclusive);
|
||||
|
||||
|
||||
|
||||
double estimatedPeak = estimatePeak(boatClass, windSpeed, startAngleInclusive, endAngleExclusive, dataCountPerAngle);
|
||||
|
||||
double convertedAngleIfOver180 = convertAngleIfNecessary(estimatedPeak);
|
||||
|
||||
SpeedWithConfidence<Void> averagedSpeedWithConfidence = estimatedSpeed(boatClass, windSpeed, convertedAngleIfOver180);
|
||||
|
||||
double originConfidence = averagedSpeedWithConfidence.getConfidence();
|
||||
|
||||
double overallConfidence = (originConfidence + calcDataCountConfidence(dataCountPerAngle, estimatedPeak)) / 2;
|
||||
|
||||
Bearing bearing = new DegreeBearingImpl(convertedAngleIfOver180);
|
||||
SpeedWithBearing speedWithBearing = new KnotSpeedWithBearingImpl(averagedSpeedWithConfidence.getObject().getKnots(), bearing);
|
||||
return new SpeedWithBearingWithConfidenceImpl<>(speedWithBearing, overallConfidence, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the formula 1-e^((‑x)/150) to create a confidence for the estimated peak.
|
||||
*
|
||||
* If the peak has 100 data points underlying, the confidence will be approx. 0.5
|
||||
*
|
||||
* @param dataCountPerAngle
|
||||
* @param estimatedPeak
|
||||
* @return
|
||||
*/
|
||||
private double calcDataCountConfidence(Integer[] dataCountPerAngle, double estimatedPeak) {
|
||||
int dataCount = dataCountPerAngle[(int) Math.round(estimatedPeak)];
|
||||
double confidence = 1 - Math.pow(Math.E, - dataCount / 150);
|
||||
return confidence;
|
||||
}
|
||||
|
||||
private Integer[] getDataCountArray(BoatClass boatClass, Speed windSpeed, int startAngleInclusive, int endAngleExclusive) {
|
||||
Integer[] dataCountPerAngle = polarDataService.getDataCountsForWindSpeed(boatClass, windSpeed, startAngleInclusive, endAngleExclusive);
|
||||
return dataCountPerAngle;
|
||||
}
|
||||
|
||||
private double convertAngleIfNecessary(double estimatedPeak) {
|
||||
double convertedAngleIfOver180 = estimatedPeak;
|
||||
if (estimatedPeak > 180) {
|
||||
convertedAngleIfOver180 = estimatedPeak - 360;
|
||||
}
|
||||
return convertedAngleIfOver180;
|
||||
}
|
||||
|
||||
private SpeedWithConfidence<Void> estimatedSpeed(BoatClass boatClass, Speed windSpeed, double estimatedPeak)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
SpeedWithConfidence<Void> speed = polarDataService.getSpeed(boatClass, windSpeed, new DegreeBearingImpl(
|
||||
estimatedPeak));
|
||||
return speed;
|
||||
}
|
||||
|
||||
private double estimatePeak(BoatClass boatClass, Speed windSpeed, int startAngleInclusive, int endAngleExclusive, Integer[] dataCountPerAngle)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
|
||||
// Find peak by averaging the angles that have at least 50% of the max datacount
|
||||
List<Integer> dataCountList = Arrays.asList(Arrays.copyOfRange(dataCountPerAngle, startAngleInclusive,
|
||||
endAngleExclusive));
|
||||
int maxDataCount = Collections.max(dataCountList);
|
||||
if (maxDataCount < MINIMUM_DATA_COUNT_FOR_ONE_ANGLE) {
|
||||
// The angle with the most data points doesn't have sufficient data, for the polar data to have any
|
||||
// significance.
|
||||
throw new NotEnoughDataHasBeenAddedException("Only " + maxDataCount
|
||||
+ " points have been added for the angle with the most points. No significance.");
|
||||
}
|
||||
int sumOfAllUpperHalfAngles = 0;
|
||||
int numberOfAnglesAdded = 0;
|
||||
for (int i = startAngleInclusive; i < endAngleExclusive; i++) {
|
||||
Integer dataCount = dataCountPerAngle[i];
|
||||
if (dataCount > maxDataCount / 2) {
|
||||
sumOfAllUpperHalfAngles = sumOfAllUpperHalfAngles + i * dataCount;
|
||||
numberOfAnglesAdded = numberOfAnglesAdded + dataCount;
|
||||
}
|
||||
}
|
||||
|
||||
double estimatedPeak = (double) sumOfAllUpperHalfAngles / (double) numberOfAnglesAdded;
|
||||
return estimatedPeak;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.sap.sailing.polars.caching;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
|
||||
public class NoCacheEntryException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 5547683568438235668L;
|
||||
private final Set<TrackedRace> notCached;
|
||||
private final Set<PolarFix> resultList;
|
||||
|
||||
public NoCacheEntryException(Set<TrackedRace> notCached, Set<PolarFix> resultList) {
|
||||
this.notCached = notCached;
|
||||
this.resultList = resultList;
|
||||
}
|
||||
|
||||
public Set<TrackedRace> getNotCached() {
|
||||
return notCached;
|
||||
}
|
||||
|
||||
public Set<PolarFix> getCachedResultList() {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.sap.sailing.polars.caching;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sailing.util.SmartFutureCache;
|
||||
|
||||
public class PolarFixCache extends
|
||||
SmartFutureCache<BoatClass, Map<RegattaAndRaceIdentifier, List<PolarFix>>, PolarFixCacheRaceInterval> {
|
||||
|
||||
private final List<PolarFixCacheUpdateDoneListener> cacheUpdateDoneListeners = new ArrayList<PolarFixCacheUpdateDoneListener>();
|
||||
|
||||
public PolarFixCache(Executor executor) {
|
||||
super(new PolarFixCacheUpdater(executor), "polarFixCache");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cache(BoatClass key, Map<RegattaAndRaceIdentifier, List<PolarFix>> value) {
|
||||
super.cache(key, value);
|
||||
synchronized (cacheUpdateDoneListeners) {
|
||||
for (PolarFixCacheUpdateDoneListener listener : cacheUpdateDoneListeners) {
|
||||
listener.cacheUpdateDoneForBoatClass(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(PolarFixCacheUpdateDoneListener listener) {
|
||||
synchronized (cacheUpdateDoneListeners) {
|
||||
cacheUpdateDoneListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(PolarFixCacheUpdateDoneListener listener) {
|
||||
synchronized (cacheUpdateDoneListeners) {
|
||||
if (cacheUpdateDoneListeners.contains(listener)) {
|
||||
cacheUpdateDoneListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<PolarFix> getFixesForTrackedRaces(Set<TrackedRace> trackedRaces) throws NoCacheEntryException {
|
||||
Set<PolarFix> resultList = new HashSet<PolarFix>();
|
||||
Set<TrackedRace> notCached = new HashSet<TrackedRace>();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
Map<RegattaAndRaceIdentifier, List<PolarFix>> result = get(trackedRace.getRace().getBoatClass(), false);
|
||||
List<PolarFix> resultForRace = result.get(trackedRace.getRaceIdentifier());
|
||||
if (resultForRace == null) {
|
||||
notCached.add(trackedRace);
|
||||
} else {
|
||||
resultList.addAll(resultForRace);
|
||||
}
|
||||
}
|
||||
if (notCached.size() > 0) {
|
||||
throw new NoCacheEntryException(notCached, resultList);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package com.sap.sailing.polars.caching;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.aggregation.PolarFixRaceInterval;
|
||||
import com.sap.sailing.util.SmartFutureCache.UpdateInterval;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class PolarFixCacheRaceInterval implements UpdateInterval<PolarFixCacheRaceInterval>, PolarFixRaceInterval {
|
||||
|
||||
private final Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> competitorAndTimepointsForRace;
|
||||
|
||||
public PolarFixCacheRaceInterval(
|
||||
Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> competitorAndTimepointsForRace) {
|
||||
this.competitorAndTimepointsForRace = competitorAndTimepointsForRace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> getCompetitorAndTimepointsForRace() {
|
||||
return competitorAndTimepointsForRace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarFixCacheRaceInterval join(PolarFixCacheRaceInterval otherUpdateInterval) {
|
||||
Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> joinedInterval = new HashMap<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>>();
|
||||
Set<TrackedRace> racesContainedInEitherMap = new HashSet<TrackedRace>();
|
||||
for (TrackedRace race : competitorAndTimepointsForRace.keySet()) {
|
||||
racesContainedInEitherMap.add(race);
|
||||
}
|
||||
Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> otherUpdateIntervalInExplicitForm = otherUpdateInterval
|
||||
.getCompetitorAndTimepointsForRace();
|
||||
for (TrackedRace race : otherUpdateIntervalInExplicitForm.keySet()) {
|
||||
racesContainedInEitherMap.add(race);
|
||||
}
|
||||
|
||||
for (TrackedRace race : racesContainedInEitherMap) {
|
||||
HashMap<Competitor, Pair<TimePoint, TimePoint>> joinedMap = new HashMap<Competitor, Pair<TimePoint, TimePoint>>();
|
||||
Map<Competitor, Pair<TimePoint, TimePoint>> mapOfTimpointCompetitorPairs = competitorAndTimepointsForRace
|
||||
.get(race);
|
||||
if (mapOfTimpointCompetitorPairs != null) {
|
||||
joinedMap.putAll(mapOfTimpointCompetitorPairs);
|
||||
}
|
||||
Map<Competitor, Pair<TimePoint, TimePoint>> mapOfOtherTimpointCompetitorPairs = otherUpdateIntervalInExplicitForm
|
||||
.get(race);
|
||||
if (mapOfOtherTimpointCompetitorPairs != null) {
|
||||
mergeMap(joinedMap, mapOfOtherTimpointCompetitorPairs);
|
||||
}
|
||||
joinedInterval.put(race, joinedMap);
|
||||
}
|
||||
return new PolarFixCacheRaceInterval(joinedInterval);
|
||||
}
|
||||
|
||||
private void mergeMap(HashMap<Competitor, Pair<TimePoint, TimePoint>> joinedMap,
|
||||
Map<Competitor, Pair<TimePoint, TimePoint>> mapOfOtherTimpointCompetitorPairs) {
|
||||
for (Entry<Competitor, Pair<TimePoint, TimePoint>> otherEntry : mapOfOtherTimpointCompetitorPairs.entrySet()) {
|
||||
|
||||
Competitor competitor = otherEntry.getKey();
|
||||
Pair<TimePoint, TimePoint> otherValue = otherEntry.getValue();
|
||||
Pair<TimePoint, TimePoint> existingValue = joinedMap.get(competitor);
|
||||
if (existingValue != null) {
|
||||
Pair<TimePoint, TimePoint> joinedTimepointInterval = joinTimepointIntervals(existingValue, otherValue);
|
||||
joinedMap.put(competitor, joinedTimepointInterval);
|
||||
} else {
|
||||
joinedMap.put(competitor, otherValue);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method ignores a possible gap between the two intervals.
|
||||
*
|
||||
* @param existingValue
|
||||
* @param otherValue
|
||||
* @return
|
||||
*/
|
||||
private Pair<TimePoint, TimePoint> joinTimepointIntervals(Pair<TimePoint, TimePoint> existingValue,
|
||||
Pair<TimePoint, TimePoint> otherValue) {
|
||||
TimePoint startExisting = existingValue.getA();
|
||||
TimePoint endExisting = existingValue.getB();
|
||||
TimePoint startOther = otherValue.getA();
|
||||
TimePoint endOther = otherValue.getB();
|
||||
|
||||
TimePoint startNew = startExisting.before(startOther) ? startExisting : startOther;
|
||||
TimePoint endNew = endExisting.after(endOther) ? endExisting : endOther;
|
||||
|
||||
return new Pair<TimePoint, TimePoint>(startNew, endNew);
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.sap.sailing.polars.caching;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
|
||||
public interface PolarFixCacheUpdateDoneListener {
|
||||
|
||||
void cacheUpdateDoneForBoatClass(BoatClass key);
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.sap.sailing.polars.caching;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
|
||||
import com.sap.sailing.polars.aggregation.PolarFixAggregator;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sailing.util.SmartFutureCache.CacheUpdater;
|
||||
|
||||
public class PolarFixCacheUpdater implements
|
||||
CacheUpdater<BoatClass, Map<RegattaAndRaceIdentifier, List<PolarFix>>, PolarFixCacheRaceInterval> {
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
public PolarFixCacheUpdater(Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegattaAndRaceIdentifier, List<PolarFix>> computeCacheUpdate(BoatClass key,
|
||||
PolarFixCacheRaceInterval updateInterval) throws Exception {
|
||||
PolarFixAggregator aggregator = new PolarFixAggregator(updateInterval,
|
||||
PolarSheetGenerationSettingsImpl.createStandardPolarSettings(), executor);
|
||||
Thread.sleep(updateInterval.getCompetitorAndTimepointsForRace().keySet().iterator().next()
|
||||
.getMillisecondsOverWhichToAverageSpeed() / 2);
|
||||
aggregator.startPolarFixAggregation();
|
||||
|
||||
return aggregator.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegattaAndRaceIdentifier, List<PolarFix>> provideNewCacheValue(BoatClass key,
|
||||
Map<RegattaAndRaceIdentifier, List<PolarFix>> oldCacheValue,
|
||||
Map<RegattaAndRaceIdentifier, List<PolarFix>> computedCacheUpdate, PolarFixCacheRaceInterval updateInterval) {
|
||||
Map<RegattaAndRaceIdentifier, List<PolarFix>> newCacheValue = new HashMap<RegattaAndRaceIdentifier, List<PolarFix>>();
|
||||
if (oldCacheValue != null) {
|
||||
newCacheValue.putAll(oldCacheValue);
|
||||
}
|
||||
for (Entry<RegattaAndRaceIdentifier, List<PolarFix>> newEntry : computedCacheUpdate.entrySet()) {
|
||||
List<PolarFix> oldList = newCacheValue.get(newEntry.getKey());
|
||||
if (oldList != null) {
|
||||
oldList.addAll(newEntry.getValue());
|
||||
} else {
|
||||
newCacheValue.put(newEntry.getKey(), newEntry.getValue());
|
||||
}
|
||||
}
|
||||
return newCacheValue;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.polars.caching;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.util.SmartFutureCache;
|
||||
|
||||
public class PolarSheetPerBoatClassCache extends
|
||||
SmartFutureCache<BoatClass, PolarSheetsData, com.sap.sailing.util.SmartFutureCache.EmptyUpdateInterval>
|
||||
implements PolarFixCacheUpdateDoneListener {
|
||||
|
||||
public PolarSheetPerBoatClassCache(PolarDataService polarDataService) {
|
||||
super(new PolarSheetPerBoatClassCacheUpdater(polarDataService), "PolarSheetPerBoatClassCache");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheUpdateDoneForBoatClass(BoatClass key) {
|
||||
triggerUpdate(key, new EmptyUpdateInterval());
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.sap.sailing.polars.caching;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.generation.PolarSheetGenerator;
|
||||
import com.sap.sailing.util.SmartFutureCache.CacheUpdater;
|
||||
import com.sap.sailing.util.SmartFutureCache.EmptyUpdateInterval;
|
||||
|
||||
public class PolarSheetPerBoatClassCacheUpdater implements
|
||||
CacheUpdater<BoatClass, PolarSheetsData, EmptyUpdateInterval> {
|
||||
|
||||
private final PolarDataService polarDataService;
|
||||
|
||||
public PolarSheetPerBoatClassCacheUpdater(PolarDataService polarDataService) {
|
||||
this.polarDataService = polarDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetsData computeCacheUpdate(BoatClass key, EmptyUpdateInterval updateInterval) throws Exception {
|
||||
PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createStandardPolarSettings();
|
||||
PolarSheetGenerator generator = new PolarSheetGenerator(polarDataService.getPolarFixesForBoatClass(key),
|
||||
settings);
|
||||
PolarSheetsData generationResult = generator.generate();
|
||||
return generationResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetsData provideNewCacheValue(BoatClass key, PolarSheetsData oldCacheValue,
|
||||
PolarSheetsData computedCacheUpdate, EmptyUpdateInterval updateInterval) {
|
||||
return computedCacheUpdate;
|
||||
}
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package com.sap.sailing.polars.clusters;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.data.ClusterBoundary;
|
||||
import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries;
|
||||
import com.sap.sse.datamining.impl.data.ComparableClusterBoundary;
|
||||
import com.sap.sse.datamining.impl.data.ComparisonStrategy;
|
||||
import com.sap.sse.datamining.impl.data.FixClusterGroup;
|
||||
|
||||
public class SpeedClusterGroup extends FixClusterGroup<Speed> {
|
||||
|
||||
/**
|
||||
* A {@link SpeedClusterGroup} lets the user set the level mids for all its clusters. The Boundaries will
|
||||
* automatically be determined. They are in the middle between each level mid but only if the distance between level
|
||||
* mid and boundary is smaller or equal {@code maxDistance}
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param levelMidsInKnots
|
||||
* sorted low -> high. E.g. [2,4,6,10,15,20,30]
|
||||
* @param maxDistanceInKnots
|
||||
* the clusters will max span <-maxDistanceInKnots-|mid|-maxDistanceinKnots->
|
||||
*/
|
||||
public SpeedClusterGroup(String name, double[] levelMidsInKnots, double maxDistanceInKnots) {
|
||||
super(name, createClustersForLevelMids(levelMidsInKnots, maxDistanceInKnots));
|
||||
}
|
||||
|
||||
private static Collection<Cluster<Speed>> createClustersForLevelMids(double[] levelMidsInKnots,
|
||||
double maxDistanceInKnots) {
|
||||
ArrayList<Cluster<Speed>> clusterList = new ArrayList<Cluster<Speed>>();
|
||||
for (int index = 0; index < levelMidsInKnots.length; index++) {
|
||||
ClusterBoundary<Speed> lowerBoundary = createLowerBoundary(levelMidsInKnots, maxDistanceInKnots, index);
|
||||
ClusterBoundary<Speed> upperBoundary = createUpperBoundary(levelMidsInKnots, maxDistanceInKnots, index);
|
||||
Cluster<Speed> cluster = new ClusterWithLowerAndUpperBoundaries<Speed>(levelMidsInKnots[index] + "kn", lowerBoundary,
|
||||
upperBoundary);
|
||||
clusterList.add(cluster);
|
||||
}
|
||||
return clusterList;
|
||||
}
|
||||
|
||||
private static ClusterBoundary<Speed> createUpperBoundary(double[] levelMidsInKnots, double maxDistanceInKnots,
|
||||
int index) {
|
||||
ClusterBoundary<Speed> upperBoundary;
|
||||
double upperBoundaryValue;
|
||||
if (index == levelMidsInKnots.length - 1) {
|
||||
upperBoundaryValue = levelMidsInKnots[index] + maxDistanceInKnots;
|
||||
} else {
|
||||
double biggestPossibleUpperBoundary = levelMidsInKnots[index] + maxDistanceInKnots;
|
||||
double midBetweenCurrentLevelMidAndUpperLevelMid = levelMidsInKnots[index]
|
||||
+ (0.5 * (levelMidsInKnots[index + 1] - levelMidsInKnots[index]));
|
||||
upperBoundaryValue = biggestPossibleUpperBoundary < midBetweenCurrentLevelMidAndUpperLevelMid ? biggestPossibleUpperBoundary
|
||||
: midBetweenCurrentLevelMidAndUpperLevelMid;
|
||||
}
|
||||
upperBoundary = new ComparableClusterBoundary<Speed>(new KnotSpeedImpl(upperBoundaryValue),
|
||||
ComparisonStrategy.LOWER_THAN);
|
||||
return upperBoundary;
|
||||
}
|
||||
|
||||
private static ClusterBoundary<Speed> createLowerBoundary(double[] levelMidsInKnots, double maxDistanceInKnots,
|
||||
int index) {
|
||||
ClusterBoundary<Speed> lowerBoundary;
|
||||
double lowerBoundaryValue;
|
||||
if (index > 0) {
|
||||
double lowestPossibleLowerBoundary = levelMidsInKnots[index] - maxDistanceInKnots;
|
||||
double midBetweenLowerLevelMidAndCurrentLevelMid = levelMidsInKnots[index - 1]
|
||||
+ (0.5 * (levelMidsInKnots[index] - levelMidsInKnots[index - 1]));
|
||||
lowerBoundaryValue = lowestPossibleLowerBoundary > midBetweenLowerLevelMidAndCurrentLevelMid ? lowestPossibleLowerBoundary
|
||||
: midBetweenLowerLevelMidAndCurrentLevelMid;
|
||||
} else {
|
||||
double lowestPossibleLowerBoundary = levelMidsInKnots[index] - maxDistanceInKnots;
|
||||
lowerBoundaryValue = lowestPossibleLowerBoundary <= 0 ? 0 : lowestPossibleLowerBoundary;
|
||||
}
|
||||
lowerBoundary = new ComparableClusterBoundary<Speed>(new KnotSpeedImpl(lowerBoundaryValue),
|
||||
ComparisonStrategy.GREATER_EQUALS_THAN);
|
||||
return lowerBoundary;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
package com.sap.sailing.polars.data;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.sap.sailing.polars.data;
|
||||
|
||||
public interface DataPointWithOriginInfo extends Comparable<DataPointWithOriginInfo> {
|
||||
|
||||
public abstract Double getRawData();
|
||||
|
||||
public abstract String getWindGaugeIdString();
|
||||
|
||||
public abstract String getDayString();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.sap.sailing.polars.data;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
|
||||
public interface PolarFix {
|
||||
|
||||
public abstract SpeedWithBearing getBoatSpeed();
|
||||
|
||||
public abstract Speed getWindSpeed();
|
||||
|
||||
public abstract double getAngleToWind();
|
||||
|
||||
public abstract String getGaugeIdString();
|
||||
|
||||
public abstract String getDayString();
|
||||
|
||||
}
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
package com.sap.sailing.polars.data.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.polars.data.BoatAndWindSpeedWithOriginInfo;
|
||||
|
||||
public class BoatAndWindSpeedWithOriginInfoImpl implements BoatAndWindSpeedWithOriginInfo {
|
||||
|
||||
+8
-3
@@ -1,6 +1,8 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
package com.sap.sailing.polars.data.impl;
|
||||
|
||||
public class DataPointWithOriginInfo implements Comparable<DataPointWithOriginInfo>{
|
||||
import com.sap.sailing.polars.data.DataPointWithOriginInfo;
|
||||
|
||||
public class DataPointWithOriginInfoImpl implements DataPointWithOriginInfo {
|
||||
|
||||
private Double rawData;
|
||||
|
||||
@@ -8,20 +10,23 @@ public class DataPointWithOriginInfo implements Comparable<DataPointWithOriginIn
|
||||
|
||||
private String dayString;
|
||||
|
||||
public DataPointWithOriginInfo(Double rawData, String windGaugeIdString, String dayString) {
|
||||
public DataPointWithOriginInfoImpl(Double rawData, String windGaugeIdString, String dayString) {
|
||||
this.rawData = rawData;
|
||||
this.windGaugeIdString = windGaugeIdString;
|
||||
this.dayString = dayString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRawData() {
|
||||
return rawData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWindGaugeIdString() {
|
||||
return windGaugeIdString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDayString() {
|
||||
return dayString;
|
||||
}
|
||||
+9
-3
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
package com.sap.sailing.polars.data.impl;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.HashSet;
|
||||
@@ -17,8 +17,9 @@ import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
|
||||
public class PolarFix {
|
||||
public class PolarFixImpl implements PolarFix {
|
||||
|
||||
private SpeedWithBearing boatSpeed;
|
||||
private Speed windSpeed;
|
||||
@@ -26,7 +27,7 @@ public class PolarFix {
|
||||
private String gaugeIdString;
|
||||
private String dayString;
|
||||
|
||||
public PolarFix(GPSFixMoving fix, TrackedRace race, GPSFixTrack<Competitor, GPSFixMoving> track, Wind windSpeed,
|
||||
public PolarFixImpl(GPSFixMoving fix, TrackedRace race, GPSFixTrack<Competitor, GPSFixMoving> track, Wind windSpeed,
|
||||
PolarSheetGenerationSettings settings, String gaugeIdString) {
|
||||
boatSpeed = track.getEstimatedSpeed(fix.getTimePoint());
|
||||
Bearing bearing = boatSpeed.getBearing();
|
||||
@@ -93,22 +94,27 @@ public class PolarFix {
|
||||
return windSourcesToExclude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getBoatSpeed() {
|
||||
return boatSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getWindSpeed() {
|
||||
return windSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAngleToWind() {
|
||||
return angleToWind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGaugeIdString() {
|
||||
return gaugeIdString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDayString() {
|
||||
return dayString;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.sap.sailing.polars.factory;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.factory.impl.PolarDataServiceImplFactory;
|
||||
|
||||
public abstract class PolarDataServiceFactory {
|
||||
|
||||
public static PolarDataService createStandardPolarDataService(Executor executor) {
|
||||
PolarDataServiceFactory factory = new PolarDataServiceImplFactory();
|
||||
return factory.createPolarDataService(executor);
|
||||
}
|
||||
|
||||
protected abstract PolarDataService createPolarDataService(Executor executor);
|
||||
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.sap.sailing.polars.factory.impl;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.factory.PolarDataServiceFactory;
|
||||
import com.sap.sailing.polars.impl.PolarDataServiceImpl;
|
||||
|
||||
public class PolarDataServiceImplFactory extends PolarDataServiceFactory {
|
||||
|
||||
@Override
|
||||
public PolarDataService createPolarDataService(Executor executor) {
|
||||
return new PolarDataServiceImpl(executor);
|
||||
}
|
||||
|
||||
}
|
||||
+277
-387
@@ -1,387 +1,277 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetsDataImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSteppingWithMaxDistance;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* Allows extracting data about average speed for each angle creating the foundation of polar-sheet generation. Tasks
|
||||
* are assigned to the executor per race & per competitor and the results are filled on the go to allow progress
|
||||
* indication in the polar-sheet itself.
|
||||
*
|
||||
* @author D054528 Frederik Petersen
|
||||
*
|
||||
*/
|
||||
public class PolarSheetGenerationWorker implements Future<PolarSheetsData>{
|
||||
|
||||
private final Set<PerRaceAndCompetitorPolarSheetGenerationWorker> workers;
|
||||
|
||||
private final List<List<BoatAndWindSpeedWithOriginInfo>> polarData;
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
private WindSteppingWithMaxDistance stepping;
|
||||
|
||||
private PolarSheetGenerationSettings settings;
|
||||
|
||||
/**
|
||||
* Will prepare the {@link PerRaceAndCompetitorPolarSheetGenerationWorker}s per race & per competitor. This includes
|
||||
* determining start and end time.
|
||||
*
|
||||
* @param trackedRaces
|
||||
* from which the data is to be collected
|
||||
* @param settings
|
||||
* @param executor
|
||||
* executes the tasks upon {@link #startPolarSheetGeneration()}
|
||||
*/
|
||||
public PolarSheetGenerationWorker(Set<TrackedRace> trackedRaces, PolarSheetGenerationSettings settings,
|
||||
Executor executor) {
|
||||
this.settings = settings;
|
||||
stepping = settings.getWindStepping();;
|
||||
polarData = initializePolarDataContainer();
|
||||
this.executor = executor;
|
||||
workers = new HashSet<PerRaceAndCompetitorPolarSheetGenerationWorker>();
|
||||
for (TrackedRace race : trackedRaces) {
|
||||
TimePoint startTime = race.getStartOfRace();
|
||||
TimePoint endTime = race.getEndOfRace();
|
||||
if (endTime == null) {
|
||||
endTime = race.getTimePointOfNewestEvent();
|
||||
}
|
||||
RaceDefinition raceDefinition = race.getRace();
|
||||
Iterable<Competitor> competitors = raceDefinition.getCompetitors();
|
||||
|
||||
for (Competitor competitor : competitors) {
|
||||
PerRaceAndCompetitorPolarSheetGenerationWorker task = new PerRaceAndCompetitorPolarSheetGenerationWorker(
|
||||
race, this, startTime, endTime, competitor, settings);
|
||||
workers.add(task);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private List<List<BoatAndWindSpeedWithOriginInfo>> initializePolarDataContainer() {
|
||||
List<List<BoatAndWindSpeedWithOriginInfo>> container = new ArrayList<List<BoatAndWindSpeedWithOriginInfo>>();
|
||||
for (int i = 0; i < 360; i++) {
|
||||
container.add(new ArrayList<BoatAndWindSpeedWithOriginInfo>());
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the {@link PerRaceAndCompetitorPolarSheetGenerationWorker}s
|
||||
*/
|
||||
public void startPolarSheetGeneration() {
|
||||
for (Runnable task : workers) {
|
||||
executor.execute(task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called from {@link PerRaceAndCompetitorPolarSheetGenerationWorker} for adding a datapoint to the list of
|
||||
* results
|
||||
*
|
||||
* @param roundedAngle
|
||||
* boat's angle to the wind
|
||||
* @param boatSpeed
|
||||
* boat's speed in knots
|
||||
* @param windSpeed
|
||||
* wind's speed in knots
|
||||
*/
|
||||
protected void addPolarData(PolarFix polarFix) {
|
||||
long roundedAngle = Math.round(polarFix.getAngleToWind());
|
||||
Speed boatSpeed = polarFix.getBoatSpeed();
|
||||
Speed windSpeed = polarFix.getWindSpeed();
|
||||
int angle = (int) roundedAngle;
|
||||
if (angle < 0) {
|
||||
angle = (360 + angle);
|
||||
}
|
||||
BoatAndWindSpeedWithOriginInfo speeds = new BoatAndWindSpeedWithOriginInfoImpl(boatSpeed, windSpeed,
|
||||
polarFix.getGaugeIdString(), polarFix.getDayString());
|
||||
polarData.get(angle).add(speeds);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return results already averaged per angle. Also datacount overall and per angle. And a completion flag to show
|
||||
* if the complete polar sheet has been generated or if the current results are only an intermediate
|
||||
* product.
|
||||
*/
|
||||
public PolarSheetsData getPolarData() {
|
||||
|
||||
// Do this before working through data, since it's possible that remaining data is processed by the workers
|
||||
// during the process of filling the result data.
|
||||
boolean complete = allWorkersDone();
|
||||
|
||||
PolarSheetHistogramBuilder histogramBuilder = new PolarSheetHistogramBuilder(settings);
|
||||
|
||||
int levelCount = stepping.getNumberOfLevels();
|
||||
Number[][] averagedPolarDataByWindSpeed = new Number[levelCount][360];
|
||||
Integer[] dataCountPerAngle = new Integer[360];
|
||||
int dataCount = 0;
|
||||
Map<Integer, Integer[]> dataCountPerAngleForWindspeed = new HashMap<Integer, Integer[]>();
|
||||
Map<Integer, Map<Integer, PolarSheetsHistogramData>> histogramDataMap = new HashMap<Integer, Map<Integer, PolarSheetsHistogramData>>();
|
||||
Map<Integer, Integer> totalDataCountPerWindSpeed = new HashMap<Integer, Integer>();
|
||||
for (int levelIndex = 0; levelIndex < levelCount; levelIndex++) {
|
||||
dataCountPerAngleForWindspeed.put(levelIndex, new Integer[360]);
|
||||
histogramDataMap.put(levelIndex, new HashMap<Integer, PolarSheetsHistogramData>());
|
||||
totalDataCountPerWindSpeed.put(levelIndex, 0);
|
||||
}
|
||||
for (int angleIndex = 0; angleIndex < 360; angleIndex++) {
|
||||
// Avoid Concurrent modification of lists, so get current state as an array; lock would slow things down
|
||||
BoatAndWindSpeedWithOriginInfo[] values = polarData.get(angleIndex).toArray(
|
||||
new BoatAndWindSpeedWithOriginInfo[polarData.get(angleIndex).size()]);
|
||||
dataCount = dataCount + values.length;
|
||||
dataCountPerAngle[angleIndex] = values.length;
|
||||
double[] sumsPerWindSpeed = new double[levelCount];
|
||||
int[] dataCountPerWindSpeed = new int[levelCount];
|
||||
Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel = new HashMap<Integer, List<DataPointWithOriginInfo>>();
|
||||
gatherPolarData(values, sumsPerWindSpeed, dataCountPerWindSpeed, dataSetForWindLevel);
|
||||
|
||||
calculateStatisticalMeasuresAndHistogramData(histogramBuilder, levelCount, averagedPolarDataByWindSpeed,
|
||||
dataCountPerAngleForWindspeed, histogramDataMap, totalDataCountPerWindSpeed, angleIndex,
|
||||
sumsPerWindSpeed, dataCountPerWindSpeed, dataSetForWindLevel);
|
||||
|
||||
}
|
||||
|
||||
for (int j = 0; j < levelCount; j++) {
|
||||
for (PolarSheetsHistogramData histogramData : histogramDataMap.get(j).values()) {
|
||||
Double polarSheetPointConfidenceMeasure = Math.min(1, histogramData.getCoefficiantOfVariation()
|
||||
* (histogramData.getDataCount() / (double) totalDataCountPerWindSpeed.get(j)) * 80);
|
||||
histogramData.setConfidenceMeasure(polarSheetPointConfidenceMeasure);
|
||||
}
|
||||
}
|
||||
|
||||
PolarSheetsData data = new PolarSheetsDataImpl(averagedPolarDataByWindSpeed, complete, dataCount,
|
||||
dataCountPerAngleForWindspeed, stepping, histogramDataMap);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void gatherPolarData(BoatAndWindSpeedWithOriginInfo[] values, double[] sumsPerWindSpeed,
|
||||
int[] dataCountPerWindSpeed, Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel) {
|
||||
for (BoatAndWindSpeedWithOriginInfo singleDataPoint : values) {
|
||||
if (singleDataPoint != null) {
|
||||
double windSpeed = singleDataPoint.getWindSpeed().getKnots();
|
||||
int level = stepping.getLevelIndexForValue(windSpeed);
|
||||
if (level >= 0) {
|
||||
double speed = singleDataPoint.getBoatSpeed().getKnots();
|
||||
String windGaugesIdString = singleDataPoint.getWindGaugesIdString();
|
||||
String dayString = singleDataPoint.getDayString();
|
||||
if (!dataSetForWindLevel.containsKey(level)) {
|
||||
dataSetForWindLevel.put(level, new ArrayList<DataPointWithOriginInfo>());
|
||||
}
|
||||
dataSetForWindLevel.get(level).add(
|
||||
new DataPointWithOriginInfo(speed, windGaugesIdString, dayString));
|
||||
sumsPerWindSpeed[level] = sumsPerWindSpeed[level] + speed;
|
||||
dataCountPerWindSpeed[level]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateStatisticalMeasuresAndHistogramData(PolarSheetHistogramBuilder histogramBuilder,
|
||||
int levelCount, Number[][] averagedPolarDataByWindSpeed,
|
||||
Map<Integer, Integer[]> dataCountPerAngleForWindspeed,
|
||||
Map<Integer, Map<Integer, PolarSheetsHistogramData>> histogramDataMap,
|
||||
Map<Integer, Integer> totalDataCountPerWindSpeed, int angleIndex, double[] sumsPerWindSpeed,
|
||||
int[] dataCountPerWindSpeed, Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel) {
|
||||
for (int levelIndex = 0; levelIndex < levelCount; levelIndex++) {
|
||||
if (settings.shouldRemoveOutliers() && dataSetForWindLevel.get(levelIndex) != null) {
|
||||
List<DataPointWithOriginInfo> withoutOutliers = new ArrayList<DataPointWithOriginInfo>();
|
||||
Collections.sort(dataSetForWindLevel.get(levelIndex));
|
||||
if (dataCountPerWindSpeed[levelIndex] > /* Minimum data count for outlier detection */10) {
|
||||
performOutlierExclusion(sumsPerWindSpeed, dataCountPerWindSpeed, dataSetForWindLevel,
|
||||
levelIndex, withoutOutliers);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (dataCountPerWindSpeed[levelIndex] < settings.getMinimumDataCountPerAngle()) {
|
||||
dataSetForWindLevel.put(levelIndex, new ArrayList<DataPointWithOriginInfo>());
|
||||
sumsPerWindSpeed[levelIndex] = 0;
|
||||
dataCountPerWindSpeed[levelIndex] = 0;
|
||||
}
|
||||
totalDataCountPerWindSpeed.put(levelIndex, totalDataCountPerWindSpeed.get(levelIndex)
|
||||
+ dataCountPerWindSpeed[levelIndex]);
|
||||
Double average = sumsPerWindSpeed[levelIndex] / dataCountPerWindSpeed[levelIndex];
|
||||
if (average.isNaN()) {
|
||||
average = new Double(0);
|
||||
}
|
||||
averagedPolarDataByWindSpeed[levelIndex][angleIndex] = average;
|
||||
dataCountPerAngleForWindspeed.get(levelIndex)[angleIndex] = dataCountPerWindSpeed[levelIndex];
|
||||
double coefficiantOfVariation = 0;
|
||||
if (dataCountPerWindSpeed[levelIndex] > 0 && average > 0) {
|
||||
Double variance = sumsPerWindSpeed[levelIndex] / dataCountPerWindSpeed[levelIndex];
|
||||
Double standardDeviation = Math.sqrt(variance);
|
||||
coefficiantOfVariation = standardDeviation / average;
|
||||
}
|
||||
List<DataPointWithOriginInfo> rawData = dataSetForWindLevel.get(levelIndex);
|
||||
if (rawData == null || rawData.size() <= 0) {
|
||||
continue;
|
||||
}
|
||||
PolarSheetsHistogramData histogramData = histogramBuilder.build(rawData, angleIndex,
|
||||
coefficiantOfVariation);
|
||||
histogramDataMap.get(levelIndex).put(angleIndex, histogramData);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void performOutlierExclusion(double[] sumsPerWindSpeed, int[] dataCountPerWindSpeed,
|
||||
Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel, int levelIndex,
|
||||
List<DataPointWithOriginInfo> withoutOutliers) {
|
||||
for (int dataIndex = 0; dataIndex < dataSetForWindLevel.get(levelIndex).size(); dataIndex++) {
|
||||
DataPointWithOriginInfo dataPoint = dataSetForWindLevel.get(levelIndex).get(dataIndex);
|
||||
double pct = getNeighboorhoodSizePercentage(dataCountPerWindSpeed, dataSetForWindLevel,
|
||||
levelIndex, dataIndex, dataPoint, settings);
|
||||
if (pct >= settings.getOutlierMinimumNeighborhoodPct()) {
|
||||
withoutOutliers.add(dataPoint);
|
||||
} else {
|
||||
sumsPerWindSpeed[levelIndex] = sumsPerWindSpeed[levelIndex] - dataPoint.getRawData();
|
||||
dataCountPerWindSpeed[levelIndex]--;
|
||||
}
|
||||
}
|
||||
dataSetForWindLevel.put(levelIndex, withoutOutliers);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the pct of the points neighborhoods based on a distance (in the settings) compared
|
||||
* to the complete dataset.
|
||||
*/
|
||||
public static double getNeighboorhoodSizePercentage(int[] dataCountPerWindSpeed,
|
||||
Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel, int levelIndex, int dataIndex,
|
||||
DataPointWithOriginInfo dataPoint, PolarSheetGenerationSettings settings) {
|
||||
int neighborCount = 0;
|
||||
double pct = .0;
|
||||
|
||||
int index = dataIndex;
|
||||
// Left side
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
done = true;
|
||||
} else {
|
||||
Double dataPointToCheckForNeighborStatus = dataSetForWindLevel.get(levelIndex).get(
|
||||
index).getRawData();
|
||||
if (dataPoint.getRawData() - dataPointToCheckForNeighborStatus <= settings
|
||||
.getOutlierDetectionNeighborhoodRadius()) {
|
||||
neighborCount++;
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
pct = (double) neighborCount / (double) dataCountPerWindSpeed[levelIndex];
|
||||
if (pct >= settings.getOutlierMinimumNeighborhoodPct()) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
index = dataIndex;
|
||||
// Right side
|
||||
done = false;
|
||||
while (!done) {
|
||||
index++;
|
||||
if (index >= dataCountPerWindSpeed[levelIndex]) {
|
||||
done = true;
|
||||
} else {
|
||||
Double dataPointToCheckForNeighborStatus = dataSetForWindLevel.get(levelIndex).get(
|
||||
index).getRawData();
|
||||
if (dataPointToCheckForNeighborStatus - dataPoint.getRawData() <= settings
|
||||
.getOutlierDetectionNeighborhoodRadius()) {
|
||||
neighborCount++;
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
pct = (double) neighborCount / (double) dataCountPerWindSpeed[levelIndex];
|
||||
if (pct >= settings.getOutlierMinimumNeighborhoodPct()) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
pct = (double) neighborCount / (double) dataCountPerWindSpeed[levelIndex];
|
||||
return pct;
|
||||
}
|
||||
|
||||
private boolean allWorkersDone() {
|
||||
boolean complete = true;
|
||||
for (PerRaceAndCompetitorPolarSheetGenerationWorker task : workers) {
|
||||
if (!task.isDone()) {
|
||||
complete = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return complete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to present more detailed data.
|
||||
*
|
||||
* @return The complete set of datapoints that have been added. Can be quite big, depending on the amount of races
|
||||
* and competitors.
|
||||
*/
|
||||
public List<List<BoatAndWindSpeedWithOriginInfo>> getCompleteData() {
|
||||
return polarData;
|
||||
}
|
||||
|
||||
public WindSteppingWithMaxDistance getStepping() {
|
||||
return stepping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return allWorkersDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetsData get() throws InterruptedException, ExecutionException {
|
||||
while (!isDone()) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
return getPolarData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetsData get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
long timeRun = 0;
|
||||
long timeoutInMillis = unit.toMillis(timeout);
|
||||
while (!isDone() && timeRun < timeoutInMillis) {
|
||||
Thread.sleep(100);
|
||||
timeRun = timeRun + 100;
|
||||
}
|
||||
if (timeRun >= timeoutInMillis) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
return getPolarData();
|
||||
}
|
||||
|
||||
}
|
||||
package com.sap.sailing.polars.generation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetsDataImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSteppingWithMaxDistance;
|
||||
import com.sap.sailing.polars.data.BoatAndWindSpeedWithOriginInfo;
|
||||
import com.sap.sailing.polars.data.DataPointWithOriginInfo;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sailing.polars.data.impl.BoatAndWindSpeedWithOriginInfoImpl;
|
||||
import com.sap.sailing.polars.data.impl.DataPointWithOriginInfoImpl;
|
||||
|
||||
public class PolarSheetGenerator {
|
||||
|
||||
private final List<List<BoatAndWindSpeedWithOriginInfo>> polarData;
|
||||
|
||||
private WindSteppingWithMaxDistance stepping;
|
||||
|
||||
private PolarSheetGenerationSettings settings;
|
||||
|
||||
private final Set<PolarFix> fixes;
|
||||
|
||||
public PolarSheetGenerator(Set<PolarFix> fixes, PolarSheetGenerationSettings settings) {
|
||||
this.settings = settings;
|
||||
this.fixes = fixes;
|
||||
stepping = settings.getWindStepping();
|
||||
polarData = initializePolarDataContainer();
|
||||
}
|
||||
|
||||
private List<List<BoatAndWindSpeedWithOriginInfo>> initializePolarDataContainer() {
|
||||
List<List<BoatAndWindSpeedWithOriginInfo>> container = new ArrayList<List<BoatAndWindSpeedWithOriginInfo>>();
|
||||
for (int i = 0; i < 360; i++) {
|
||||
container.add(new ArrayList<BoatAndWindSpeedWithOriginInfo>());
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
private void addPolarFix(PolarFix polarFix) {
|
||||
long roundedAngle = Math.round(polarFix.getAngleToWind());
|
||||
Speed boatSpeed = polarFix.getBoatSpeed();
|
||||
Speed windSpeed = polarFix.getWindSpeed();
|
||||
int angle = (int) roundedAngle;
|
||||
if (angle < 0) {
|
||||
angle = (360 + angle);
|
||||
}
|
||||
BoatAndWindSpeedWithOriginInfo speeds = new BoatAndWindSpeedWithOriginInfoImpl(boatSpeed, windSpeed,
|
||||
polarFix.getGaugeIdString(), polarFix.getDayString());
|
||||
polarData.get(angle).add(speeds);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return results already averaged per angle. Also datacount overall and per angle. And a completion flag to show
|
||||
* if the complete polar sheet has been generated or if the current results are only an intermediate
|
||||
* product.
|
||||
*/
|
||||
public PolarSheetsData generate() {
|
||||
|
||||
for (PolarFix fix : fixes) {
|
||||
addPolarFix(fix);
|
||||
}
|
||||
|
||||
PolarSheetHistogramBuilder histogramBuilder = new PolarSheetHistogramBuilder(settings);
|
||||
|
||||
int levelCount = stepping.getNumberOfLevels();
|
||||
Number[][] averagedPolarDataByWindSpeed = new Number[levelCount][360];
|
||||
Integer[] dataCountPerAngle = new Integer[360];
|
||||
int dataCount = 0;
|
||||
Map<Integer, Integer[]> dataCountPerAngleForWindspeed = new HashMap<Integer, Integer[]>();
|
||||
Map<Integer, Map<Integer, PolarSheetsHistogramData>> histogramDataMap = new HashMap<Integer, Map<Integer, PolarSheetsHistogramData>>();
|
||||
Map<Integer, Integer> totalDataCountPerWindSpeed = new HashMap<Integer, Integer>();
|
||||
for (int levelIndex = 0; levelIndex < levelCount; levelIndex++) {
|
||||
dataCountPerAngleForWindspeed.put(levelIndex, new Integer[360]);
|
||||
histogramDataMap.put(levelIndex, new HashMap<Integer, PolarSheetsHistogramData>());
|
||||
totalDataCountPerWindSpeed.put(levelIndex, 0);
|
||||
}
|
||||
for (int angleIndex = 0; angleIndex < 360; angleIndex++) {
|
||||
// Avoid Concurrent modification of lists, so get current state as an array; lock would slow things down
|
||||
BoatAndWindSpeedWithOriginInfo[] values = polarData.get(angleIndex).toArray(
|
||||
new BoatAndWindSpeedWithOriginInfo[polarData.get(angleIndex).size()]);
|
||||
dataCount = dataCount + values.length;
|
||||
dataCountPerAngle[angleIndex] = values.length;
|
||||
double[] sumsPerWindSpeed = new double[levelCount];
|
||||
int[] dataCountPerWindSpeed = new int[levelCount];
|
||||
Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel = new HashMap<Integer, List<DataPointWithOriginInfo>>();
|
||||
gatherPolarData(values, sumsPerWindSpeed, dataCountPerWindSpeed, dataSetForWindLevel);
|
||||
|
||||
calculateStatisticalMeasuresAndHistogramData(histogramBuilder, levelCount, averagedPolarDataByWindSpeed,
|
||||
dataCountPerAngleForWindspeed, histogramDataMap, totalDataCountPerWindSpeed, angleIndex,
|
||||
sumsPerWindSpeed, dataCountPerWindSpeed, dataSetForWindLevel);
|
||||
|
||||
}
|
||||
|
||||
for (int j = 0; j < levelCount; j++) {
|
||||
for (PolarSheetsHistogramData histogramData : histogramDataMap.get(j).values()) {
|
||||
Double polarSheetPointConfidenceMeasure = Math.min(1, histogramData.getCoefficiantOfVariation()
|
||||
* (histogramData.getDataCount() / (double) totalDataCountPerWindSpeed.get(j)) * 80);
|
||||
histogramData.setConfidenceMeasure(polarSheetPointConfidenceMeasure);
|
||||
}
|
||||
}
|
||||
|
||||
PolarSheetsData data = new PolarSheetsDataImpl(averagedPolarDataByWindSpeed, dataCount,
|
||||
dataCountPerAngleForWindspeed, stepping, histogramDataMap);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void gatherPolarData(BoatAndWindSpeedWithOriginInfo[] values, double[] sumsPerWindSpeed,
|
||||
int[] dataCountPerWindSpeed, Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel) {
|
||||
for (BoatAndWindSpeedWithOriginInfo singleDataPoint : values) {
|
||||
if (singleDataPoint != null) {
|
||||
double windSpeed = singleDataPoint.getWindSpeed().getKnots();
|
||||
int level = stepping.getLevelIndexForValue(windSpeed);
|
||||
if (level >= 0) {
|
||||
double speed = singleDataPoint.getBoatSpeed().getKnots();
|
||||
String windGaugesIdString = singleDataPoint.getWindGaugesIdString();
|
||||
String dayString = singleDataPoint.getDayString();
|
||||
if (!dataSetForWindLevel.containsKey(level)) {
|
||||
dataSetForWindLevel.put(level, new ArrayList<DataPointWithOriginInfo>());
|
||||
}
|
||||
dataSetForWindLevel.get(level).add(
|
||||
new DataPointWithOriginInfoImpl(speed, windGaugesIdString, dayString));
|
||||
sumsPerWindSpeed[level] = sumsPerWindSpeed[level] + speed;
|
||||
dataCountPerWindSpeed[level]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateStatisticalMeasuresAndHistogramData(PolarSheetHistogramBuilder histogramBuilder,
|
||||
int levelCount, Number[][] averagedPolarDataByWindSpeed,
|
||||
Map<Integer, Integer[]> dataCountPerAngleForWindspeed,
|
||||
Map<Integer, Map<Integer, PolarSheetsHistogramData>> histogramDataMap,
|
||||
Map<Integer, Integer> totalDataCountPerWindSpeed, int angleIndex, double[] sumsPerWindSpeed,
|
||||
int[] dataCountPerWindSpeed, Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel) {
|
||||
for (int levelIndex = 0; levelIndex < levelCount; levelIndex++) {
|
||||
if (settings.shouldRemoveOutliers() && dataSetForWindLevel.get(levelIndex) != null) {
|
||||
List<DataPointWithOriginInfo> withoutOutliers = new ArrayList<DataPointWithOriginInfo>();
|
||||
Collections.sort(dataSetForWindLevel.get(levelIndex));
|
||||
if (dataCountPerWindSpeed[levelIndex] > /* Minimum data count for outlier detection */10) {
|
||||
performOutlierExclusion(sumsPerWindSpeed, dataCountPerWindSpeed, dataSetForWindLevel,
|
||||
levelIndex, withoutOutliers);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (dataCountPerWindSpeed[levelIndex] < settings.getMinimumDataCountPerAngle()) {
|
||||
dataSetForWindLevel.put(levelIndex, new ArrayList<DataPointWithOriginInfo>());
|
||||
sumsPerWindSpeed[levelIndex] = 0;
|
||||
dataCountPerWindSpeed[levelIndex] = 0;
|
||||
}
|
||||
totalDataCountPerWindSpeed.put(levelIndex, totalDataCountPerWindSpeed.get(levelIndex)
|
||||
+ dataCountPerWindSpeed[levelIndex]);
|
||||
Double average = sumsPerWindSpeed[levelIndex] / dataCountPerWindSpeed[levelIndex];
|
||||
if (average.isNaN()) {
|
||||
average = new Double(0);
|
||||
}
|
||||
averagedPolarDataByWindSpeed[levelIndex][angleIndex] = average;
|
||||
dataCountPerAngleForWindspeed.get(levelIndex)[angleIndex] = dataCountPerWindSpeed[levelIndex];
|
||||
double coefficiantOfVariation = 0;
|
||||
if (dataCountPerWindSpeed[levelIndex] > 0 && average > 0) {
|
||||
Double variance = sumsPerWindSpeed[levelIndex] / dataCountPerWindSpeed[levelIndex];
|
||||
Double standardDeviation = Math.sqrt(variance);
|
||||
coefficiantOfVariation = standardDeviation / average;
|
||||
}
|
||||
List<DataPointWithOriginInfo> rawData = dataSetForWindLevel.get(levelIndex);
|
||||
if (rawData == null || rawData.size() <= 0) {
|
||||
continue;
|
||||
}
|
||||
PolarSheetsHistogramData histogramData = histogramBuilder.build(rawData, angleIndex,
|
||||
coefficiantOfVariation);
|
||||
histogramDataMap.get(levelIndex).put(angleIndex, histogramData);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void performOutlierExclusion(double[] sumsPerWindSpeed, int[] dataCountPerWindSpeed,
|
||||
Map<Integer, List<DataPointWithOriginInfo>> dataSetForWindLevel, int levelIndex,
|
||||
List<DataPointWithOriginInfo> withoutOutliers) {
|
||||
for (int dataIndex = 0; dataIndex < dataSetForWindLevel.get(levelIndex).size(); dataIndex++) {
|
||||
DataPointWithOriginInfo dataPoint = dataSetForWindLevel.get(levelIndex).get(dataIndex);
|
||||
double pct = getNeighboorhoodSizePercentage(dataCountPerWindSpeed, dataSetForWindLevel,
|
||||
levelIndex, dataIndex, dataPoint, settings);
|
||||
if (pct >= settings.getOutlierMinimumNeighborhoodPct()) {
|
||||
withoutOutliers.add(dataPoint);
|
||||
} else {
|
||||
sumsPerWindSpeed[levelIndex] = sumsPerWindSpeed[levelIndex] - dataPoint.getRawData();
|
||||
dataCountPerWindSpeed[levelIndex]--;
|
||||
}
|
||||
}
|
||||
dataSetForWindLevel.put(levelIndex, withoutOutliers);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the pct of the points neighborhoods based on a distance (in the settings) compared
|
||||
* to the complete dataset.
|
||||
*/
|
||||
public static double getNeighboorhoodSizePercentage(int[] dataCountPerWindSpeed,
|
||||
Map<Integer, List<DataPointWithOriginInfo>> valuesInMap, int levelIndex, int dataIndex,
|
||||
DataPointWithOriginInfo dataPoint, PolarSheetGenerationSettings settings) {
|
||||
int neighborCount = 0;
|
||||
double pct = .0;
|
||||
|
||||
int index = dataIndex;
|
||||
// Left side
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
done = true;
|
||||
} else {
|
||||
Double dataPointToCheckForNeighborStatus = valuesInMap.get(levelIndex).get(
|
||||
index).getRawData();
|
||||
if (dataPoint.getRawData() - dataPointToCheckForNeighborStatus <= settings
|
||||
.getOutlierDetectionNeighborhoodRadius()) {
|
||||
neighborCount++;
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
pct = (double) neighborCount / (double) dataCountPerWindSpeed[levelIndex];
|
||||
if (pct >= settings.getOutlierMinimumNeighborhoodPct()) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
index = dataIndex;
|
||||
// Right side
|
||||
done = false;
|
||||
while (!done) {
|
||||
index++;
|
||||
if (index >= dataCountPerWindSpeed[levelIndex]) {
|
||||
done = true;
|
||||
} else {
|
||||
Double dataPointToCheckForNeighborStatus = valuesInMap.get(levelIndex).get(
|
||||
index).getRawData();
|
||||
if (dataPointToCheckForNeighborStatus - dataPoint.getRawData() <= settings
|
||||
.getOutlierDetectionNeighborhoodRadius()) {
|
||||
neighborCount++;
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
pct = (double) neighborCount / (double) dataCountPerWindSpeed[levelIndex];
|
||||
if (pct >= settings.getOutlierMinimumNeighborhoodPct()) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
pct = (double) neighborCount / (double) dataCountPerWindSpeed[levelIndex];
|
||||
return pct;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Can be used to present more detailed data.
|
||||
*
|
||||
* @return The complete set of datapoints that have been added. Can be quite big, depending on the amount of races
|
||||
* and competitors.
|
||||
*/
|
||||
public List<List<BoatAndWindSpeedWithOriginInfo>> getCompleteData() {
|
||||
return polarData;
|
||||
}
|
||||
|
||||
public WindSteppingWithMaxDistance getStepping() {
|
||||
return stepping;
|
||||
}
|
||||
|
||||
}
|
||||
+7
-6
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.polarsheets;
|
||||
package com.sap.sailing.polars.generation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -8,6 +8,7 @@ import java.util.Map;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl;
|
||||
import com.sap.sailing.polars.data.DataPointWithOriginInfo;
|
||||
|
||||
public class PolarSheetHistogramBuilder {
|
||||
|
||||
@@ -17,10 +18,10 @@ public class PolarSheetHistogramBuilder {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public PolarSheetsHistogramData build(List<DataPointWithOriginInfo> dataPointsWithOriginInfo, int angleIndex,
|
||||
public PolarSheetsHistogramData build(List<DataPointWithOriginInfo> rawData, int angleIndex,
|
||||
double coefficiantOfVariation) {
|
||||
DataPointWithOriginInfo minPoint = Collections.min(dataPointsWithOriginInfo);
|
||||
DataPointWithOriginInfo maxPoint = Collections.max(dataPointsWithOriginInfo);
|
||||
DataPointWithOriginInfo minPoint = Collections.min(rawData);
|
||||
DataPointWithOriginInfo maxPoint = Collections.max(rawData);
|
||||
|
||||
Double min = minPoint.getRawData();
|
||||
Double max = maxPoint.getRawData();
|
||||
@@ -39,7 +40,7 @@ public class PolarSheetHistogramBuilder {
|
||||
for (int i = 0; i < yValues.length; i++) {
|
||||
yValues[i] = 0;
|
||||
}
|
||||
for (DataPointWithOriginInfo dataPoint : dataPointsWithOriginInfo) {
|
||||
for (DataPointWithOriginInfo dataPoint : rawData) {
|
||||
double notRoundedYet = (dataPoint.getRawData() - min) / range;
|
||||
int u = (int) notRoundedYet;
|
||||
if (u == numberOfColumns) {
|
||||
@@ -61,7 +62,7 @@ public class PolarSheetHistogramBuilder {
|
||||
|
||||
|
||||
PolarSheetsHistogramData histogramData = new PolarSheetsHistogramDataImpl(angleIndex, xValues, yValues,
|
||||
yValuesByGaugeIds, yValuesByDay, yValuesByDayAndGaugeId, dataPointsWithOriginInfo.size(), coefficiantOfVariation);
|
||||
yValuesByGaugeIds, yValuesByDay, yValuesByDayAndGaugeId, rawData.size(), coefficiantOfVariation);
|
||||
return histogramData;
|
||||
}
|
||||
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
package com.sap.sailing.polars.impl;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.aggregation.PolarFixAggregator;
|
||||
import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval;
|
||||
import com.sap.sailing.polars.analysis.PolarSheetAnalyzer;
|
||||
import com.sap.sailing.polars.analysis.impl.PolarSheetAnalyzerImpl;
|
||||
import com.sap.sailing.polars.caching.PolarFixCache;
|
||||
import com.sap.sailing.polars.caching.PolarSheetPerBoatClassCache;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sailing.polars.generation.PolarSheetGenerator;
|
||||
import com.sap.sailing.polars.mining.PolarDataMiner;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.util.SmartFutureCache;
|
||||
|
||||
/**
|
||||
* Uses two chained {@link SmartFutureCache}s. One to store {@link PolarFix}es extracted from {@link TrackedRace}s and
|
||||
* the other one for storing one polar sheet per boat class. This allows quick access to desired measures like optimal
|
||||
* beat angles.
|
||||
*
|
||||
* @author Frederik Petersen (D054528)
|
||||
*
|
||||
*/
|
||||
public class PolarDataServiceImpl implements PolarDataService {
|
||||
|
||||
private final PolarFixCache polarFixCache;
|
||||
private final PolarSheetPerBoatClassCache polarSheetPerBoatClassCache;
|
||||
|
||||
private final PolarSheetAnalyzer polarSheetAnalyzer;
|
||||
|
||||
private final PolarDataMiner polarDataMiner;
|
||||
|
||||
public PolarDataServiceImpl(Executor executor) {
|
||||
this.polarFixCache = new PolarFixCache(executor);
|
||||
this.polarSheetPerBoatClassCache = new PolarSheetPerBoatClassCache(this);
|
||||
polarFixCache.addListener(polarSheetPerBoatClassCache);
|
||||
this.polarSheetAnalyzer = new PolarSheetAnalyzerImpl(this);
|
||||
this.polarDataMiner = new PolarDataMiner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithConfidence<Void> getSpeed(BoatClass boatClass, Speed windSpeed, Bearing bearingToTheWind)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
return polarDataMiner.estimateBoatSpeed(boatClass, windSpeed, bearingToTheWind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
|
||||
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException {
|
||||
SpeedWithBearingWithConfidence<Void> speedWithBearing = null;
|
||||
if (tack.equals(Tack.STARBOARD)) {
|
||||
if (legType.equals(LegType.UPWIND)) {
|
||||
speedWithBearing = polarSheetAnalyzer.getAverageUpwindSpeedWithBearingOnStarboardTackFor(boatClass, windSpeed);
|
||||
} else if (legType.equals(LegType.DOWNWIND)) {
|
||||
speedWithBearing = polarSheetAnalyzer.getAverageDownwindSpeedWithBearingOnStarboardTackFor(boatClass, windSpeed);
|
||||
}
|
||||
} else if (tack.equals(Tack.PORT)) {
|
||||
if (legType.equals(LegType.UPWIND)) {
|
||||
return polarSheetAnalyzer.getAverageUpwindSpeedWithBearingOnPortTackFor(boatClass, windSpeed);
|
||||
} else if (legType.equals(LegType.DOWNWIND)) {
|
||||
return polarSheetAnalyzer.getAverageDownwindSpeedWithBearingOnPortTackFor(boatClass, windSpeed);
|
||||
}
|
||||
}
|
||||
return speedWithBearing;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PolarSheetsData generatePolarSheet(Set<TrackedRace> trackedRaces, PolarSheetGenerationSettings settings,
|
||||
Executor executor) throws InterruptedException, ExecutionException {
|
||||
Set<PolarFix> fixes;
|
||||
// If settings are default, look into cache
|
||||
// if (settings.areDefault()) {
|
||||
// try {
|
||||
// fixes = polarFixCache.getFixesForTrackedRaces(trackedRaces);
|
||||
// } catch (NoCacheEntryException e) {
|
||||
// // If there is no cache entry for at least one of the races: Aggregate for non-cached races.
|
||||
// fixes = e.getCachedResultList();
|
||||
// PolarFixAggregator aggregator = new PolarFixAggregator(
|
||||
// new SimplePolarFixRaceInterval(e.getNotCached()),
|
||||
// settings, executor);
|
||||
// aggregator.startPolarFixAggregation();
|
||||
// fixes.addAll(aggregator.getAggregationResultAsSingleList());
|
||||
// }
|
||||
// } else {
|
||||
PolarFixAggregator aggregator = new PolarFixAggregator(new SimplePolarFixRaceInterval(trackedRaces), settings,
|
||||
executor);
|
||||
aggregator.startPolarFixAggregation();
|
||||
fixes = aggregator.getAggregationResultAsSingleList();
|
||||
// }
|
||||
PolarSheetGenerator generator = new PolarSheetGenerator(fixes, settings);
|
||||
return generator.generate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newRaceFinishedTracking(TrackedRace trackedRace) {
|
||||
// TODO add a similar listening method, that deletes all cached data on removal of race
|
||||
// HashSet<TrackedRace> set = new HashSet<TrackedRace>();
|
||||
// set.add(trackedRace);
|
||||
// polarFixCache.triggerUpdate(trackedRace.getRace().getBoatClass(), new PolarFixCacheRaceInterval(set));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PolarFix> getPolarFixesForBoatClass(BoatClass key) {
|
||||
Map<RegattaAndRaceIdentifier, List<PolarFix>> fixesInMap = polarFixCache.get(key, false);
|
||||
Set<PolarFix> resultSet = new HashSet<PolarFix>();
|
||||
for (List<PolarFix> value : fixesInMap.values()) {
|
||||
resultSet.addAll(value);
|
||||
}
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarSheetsData getPolarSheetForBoatClass(BoatClass boatClass) {
|
||||
return polarDataMiner.createFullSheetForBoatClass(boatClass);
|
||||
//return polarSheetPerBoatClassCache.get(boatClass, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<BoatClass> getAllBoatClassesWithPolarSheetsAvailable() {
|
||||
return polarDataMiner.getAvailableBoatClasses();
|
||||
//return polarSheetPerBoatClassCache.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void competitorPositionChanged(final GPSFixMoving fix, final Competitor competitor,
|
||||
final TrackedRace createdTrackedRace) {
|
||||
polarDataMiner.addFix(fix, competitor, createdTrackedRace);
|
||||
// TODO build datamining pipeline for the cache
|
||||
|
||||
// PolarFixCacheRaceInterval interval = new PolarFixCacheRaceInterval(createIntervalSpecification(
|
||||
// createdTrackedRace, competitor, timePoint));
|
||||
// polarFixCache.triggerUpdate(createdTrackedRace.getRace().getBoatClass(), interval);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer[] getDataCountsForWindSpeed(BoatClass boatClass, Speed windSpeed, int startAngleInclusive, int endAngleExclusive) {
|
||||
return polarDataMiner.getDataCountsForWindSpeed(boatClass, windSpeed, startAngleInclusive, endAngleExclusive);
|
||||
}
|
||||
|
||||
// private Map<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> createIntervalSpecification(
|
||||
// TrackedRace createdTrackedRace, Competitor competitor, TimePoint timePoint) {
|
||||
// HashMap<TrackedRace, Map<Competitor, Pair<TimePoint, TimePoint>>> result = new HashMap<TrackedRace,
|
||||
// Map<Competitor, Pair<TimePoint, TimePoint>>>();
|
||||
// HashMap<Competitor, Pair<TimePoint, TimePoint>> competitorMap = new HashMap<Competitor, Pair<TimePoint,
|
||||
// TimePoint>>();
|
||||
// competitorMap.put(competitor, new Pair<TimePoint, TimePoint>(timePoint, timePoint));
|
||||
// result.put(createdTrackedRace, competitorMap);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractSimpleParallelProcessor;
|
||||
|
||||
public abstract class AbstractEnrichingProcessor<InputType, ResultType> extends
|
||||
AbstractSimpleParallelProcessor<InputType, ResultType> {
|
||||
|
||||
public AbstractEnrichingProcessor(Class<InputType> inputType, Class<ResultType> resultType,
|
||||
ExecutorService executor, Collection<Processor<ResultType, ?>> resultReceivers) {
|
||||
super(inputType, resultType, executor, resultReceivers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Callable<ResultType> createInstruction(final InputType element) {
|
||||
return new Callable<ResultType>() {
|
||||
|
||||
@Override
|
||||
public ResultType call() throws Exception {
|
||||
return enrich(element);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract ResultType enrich(InputType element);
|
||||
|
||||
@Override
|
||||
protected void setAdditionalData(AdditionalResultDataBuilder additionalDataBuilder) {
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
public class GPSFixMovingWithOriginInfo {
|
||||
|
||||
private final GPSFixMoving fix;
|
||||
private final TrackedRace trackedRace;
|
||||
private final Competitor competitor;
|
||||
|
||||
public GPSFixMovingWithOriginInfo(GPSFixMoving fix, TrackedRace trackedRace, Competitor competitor) {
|
||||
this.fix = fix;
|
||||
this.trackedRace = trackedRace;
|
||||
this.competitor = competitor;
|
||||
}
|
||||
|
||||
public GPSFixMoving getFix() {
|
||||
return fix;
|
||||
}
|
||||
|
||||
public TrackedRace getTrackedRace() {
|
||||
return trackedRace;
|
||||
}
|
||||
|
||||
public Competitor getCompetitor() {
|
||||
return competitor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.confidence.ConfidenceFactory;
|
||||
import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
|
||||
public class GPSFixMovingWithPolarContext implements PolarClusterKey {
|
||||
|
||||
private final GPSFixMoving fix;
|
||||
private final TrackedRace race;
|
||||
private final Competitor competitor;
|
||||
private final ClusterGroup<Speed> windSpeedClusterGroup;
|
||||
private final Set<WindSource> windSourcesToExcludeForBearing;
|
||||
private final Set<WindSource> windSourcesToExcludeForSpeed;
|
||||
|
||||
public GPSFixMovingWithPolarContext(GPSFixMoving fix, TrackedRace race, Competitor competitor,
|
||||
ClusterGroup<Speed> windSpeedClusterGroup) {
|
||||
this.fix = fix;
|
||||
this.race = race;
|
||||
this.competitor = competitor;
|
||||
this.windSpeedClusterGroup = windSpeedClusterGroup;
|
||||
this.windSourcesToExcludeForBearing = collectWindSourcesToIgnoreForBearing();
|
||||
this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed();
|
||||
}
|
||||
|
||||
public GPSFixMoving getFix() {
|
||||
return fix;
|
||||
}
|
||||
|
||||
public TrackedRace getRace() {
|
||||
return race;
|
||||
}
|
||||
|
||||
public Competitor getCompetitor() {
|
||||
return competitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoundedAngleToTheWind getRoundedAngleToTheWind() {
|
||||
return new RoundedAngleToTheWind(getAngleToTheWind().getObject());
|
||||
}
|
||||
|
||||
public BearingWithConfidence<Integer> getAngleToTheWind() {
|
||||
SpeedWithBearing boatSpeed = race.getTrack(competitor).getEstimatedSpeed(fix.getTimePoint());
|
||||
WindWithConfidence<Pair<Position, TimePoint>> wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForBearing);
|
||||
|
||||
BearingWithConfidenceImpl<Integer> result = null;
|
||||
if (wind != null && boatSpeed != null) {
|
||||
Bearing bearing = boatSpeed.getBearing();
|
||||
Bearing difference = wind.getObject().getFrom().getDifferenceTo(bearing);
|
||||
result = new BearingWithConfidenceImpl<Integer>(difference, wind.getConfidence(), 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cluster<Speed> getWindSpeedCluster() {
|
||||
Speed windSpeed = getWindSpeed().getObject();
|
||||
return windSpeedClusterGroup.getClusterFor(windSpeed);
|
||||
}
|
||||
|
||||
public WindWithConfidence<Pair<Position, TimePoint>> getWindSpeed() {
|
||||
WindWithConfidence<Pair<Position, TimePoint>> wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForSpeed);
|
||||
return wind;
|
||||
}
|
||||
|
||||
public SpeedWithBearingWithConfidence<TimePoint> getBoatSpeed() {
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = race.getTrack(competitor);
|
||||
return track.getEstimatedSpeed(fix.getTimePoint(), ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(
|
||||
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
|
||||
track.getMillisecondsOverWhichToAverageSpeed()/2, /* minimumConfidence */ 0.00000001));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatClass getBoatClass() {
|
||||
return race.getRace().getBoatClass();
|
||||
}
|
||||
|
||||
private Set<WindSource> collectWindSourcesToIgnoreForBearing() {
|
||||
Set<WindSource> windSourcesToExclude = new HashSet<WindSource>();
|
||||
Iterable<WindSource> combinedSources = race.getWindSources(WindSourceType.COMBINED);
|
||||
for (WindSource combinedSource : combinedSources) {
|
||||
windSourcesToExclude.add(combinedSource);
|
||||
}
|
||||
Iterable<WindSource> courseSources = race.getWindSources(WindSourceType.COURSE_BASED);
|
||||
for (WindSource courseSource : courseSources) {
|
||||
windSourcesToExclude.add(courseSource);
|
||||
}
|
||||
|
||||
Iterable<WindSource> expSources = race.getWindSources(WindSourceType.EXPEDITION);
|
||||
for (WindSource expSource : expSources) {
|
||||
windSourcesToExclude.add(expSource);
|
||||
}
|
||||
Iterable<WindSource> rcSources = race.getWindSources(WindSourceType.RACECOMMITTEE);
|
||||
for (WindSource rcSource : rcSources) {
|
||||
windSourcesToExclude.add(rcSource);
|
||||
}
|
||||
Iterable<WindSource> webSources = race.getWindSources(WindSourceType.WEB);
|
||||
for (WindSource webSource : webSources) {
|
||||
windSourcesToExclude.add(webSource);
|
||||
}
|
||||
return windSourcesToExclude;
|
||||
}
|
||||
|
||||
private Set<WindSource> collectWindSourcesToIgnoreForSpeed() {
|
||||
Set<WindSource> windSourcesToExclude = new HashSet<WindSource>();
|
||||
Iterable<WindSource> combinedSources = race.getWindSources(WindSourceType.COMBINED);
|
||||
for (WindSource combinedSource : combinedSources) {
|
||||
windSourcesToExclude.add(combinedSource);
|
||||
}
|
||||
Iterable<WindSource> courseSources = race.getWindSources(WindSourceType.COURSE_BASED);
|
||||
for (WindSource courseSource : courseSources) {
|
||||
windSourcesToExclude.add(courseSource);
|
||||
}
|
||||
Iterable<WindSource> trackBasedSources = race.getWindSources(WindSourceType.TRACK_BASED_ESTIMATION);
|
||||
for (WindSource trackBasedSource : trackBasedSources) {
|
||||
windSourcesToExclude.add(trackBasedSource);
|
||||
}
|
||||
Iterable<WindSource> rcSources = race.getWindSources(WindSourceType.RACECOMMITTEE);
|
||||
for (WindSource rcSource : rcSources) {
|
||||
windSourcesToExclude.add(rcSource);
|
||||
}
|
||||
Iterable<WindSource> webSources = race.getWindSources(WindSourceType.WEB);
|
||||
for (WindSource webSource : webSources) {
|
||||
windSourcesToExclude.add(webSource);
|
||||
}
|
||||
return windSourcesToExclude;
|
||||
}
|
||||
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.polars.regression.BoatSpeedEstimator;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.datamining.factories.GroupKeyFactory;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
|
||||
public class IncrementalRegressionProcessor implements Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>,Void> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(IncrementalRegressionProcessor.class.getName());
|
||||
|
||||
private final Map<GroupKey, BoatSpeedEstimator> boatSpeedEstimators = new HashMap<GroupKey, BoatSpeedEstimator>();
|
||||
|
||||
private final ClusterGroup<Speed> speedClusterGroup;
|
||||
|
||||
private final Set<BoatClass> availableBoatClasses = new HashSet<>();
|
||||
|
||||
public IncrementalRegressionProcessor(ClusterGroup<Speed> speedClusterGroup) {
|
||||
this.speedClusterGroup = speedClusterGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processElement(GroupedDataEntry<GPSFixMovingWithPolarContext> element) {
|
||||
GroupKey key = element.getKey();
|
||||
BoatSpeedEstimator boatSpeedEstimator;
|
||||
synchronized (boatSpeedEstimators) {
|
||||
if (!boatSpeedEstimators.containsKey(key)) {
|
||||
boatSpeedEstimators.put(key, new BoatSpeedEstimator());
|
||||
availableBoatClasses.add(element.getDataEntry().getBoatClass());
|
||||
}
|
||||
|
||||
boatSpeedEstimator = boatSpeedEstimators.get(key);
|
||||
}
|
||||
GPSFixMovingWithPolarContext fix = element.getDataEntry();
|
||||
|
||||
BearingWithConfidence<Integer> angleToTheWind = fix.getAngleToTheWind();
|
||||
|
||||
|
||||
|
||||
|
||||
if (angleToTheWind != null) {
|
||||
WindWithConfidence<Pair<Position, TimePoint>> windWithConfidenceForSpeed = fix.getWindSpeed();
|
||||
SpeedWithBearingWithConfidence<TimePoint> boatSpeedWithConfidence = fix.getBoatSpeed();
|
||||
double confidenceForWindSpeed = windWithConfidenceForSpeed.getConfidence();
|
||||
double confidenceForWindBearing = angleToTheWind.getConfidence();
|
||||
double confidenceForBoatSpeed = boatSpeedWithConfidence.getConfidence();
|
||||
double averagedConfidence = (confidenceForBoatSpeed + confidenceForWindBearing + confidenceForWindSpeed) / 3;
|
||||
boatSpeedEstimator.addData(windWithConfidenceForSpeed.getObject().getKnots(), angleToTheWind.getObject()
|
||||
.getDegrees(), boatSpeedWithConfidence.getObject().getKnots(), averagedConfidence);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() throws InterruptedException {
|
||||
// Nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdditionalResultDataBuilder getAdditionalResultData(AdditionalResultDataBuilder additionalDataBuilder) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Pair<SpeedWithConfidence<Void>, Integer> estimateBoatSpeed(final BoatClass boatClass, final Speed windSpeed,
|
||||
final Bearing angleToTheWind)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
int dataCount = 0;
|
||||
PolarClusterKey key = new PolarClusterKey() {
|
||||
@Override
|
||||
public RoundedAngleToTheWind getRoundedAngleToTheWind() {
|
||||
return new RoundedAngleToTheWind(angleToTheWind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatClass getBoatClass() {
|
||||
return boatClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cluster<Speed> getWindSpeedCluster() {
|
||||
return speedClusterGroup.getClusterFor(windSpeed);
|
||||
}
|
||||
};
|
||||
GroupKey compoundKey;
|
||||
try {
|
||||
compoundKey = GroupKeyFactory.createCompoundKeyFor(key, PolarDataDimensionCollectionFactory
|
||||
.getClusterKeyDimensions().iterator());
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
BoatSpeedEstimator boatSpeedEstimator = boatSpeedEstimators.get(compoundKey);
|
||||
if (boatSpeedEstimator == null) {
|
||||
throw new NotEnoughDataHasBeenAddedException();
|
||||
}
|
||||
KnotSpeedImpl speedWithoutConfidence = new KnotSpeedImpl(boatSpeedEstimator.estimateSpeed(windSpeed.getKnots(),
|
||||
angleToTheWind.getDegrees()));
|
||||
dataCount = boatSpeedEstimator.getDataCount();
|
||||
double confidence = boatSpeedEstimator.getConfidence();
|
||||
return new Pair<SpeedWithConfidence<Void>, Integer>(new SpeedWithConfidenceImpl<Void>(
|
||||
speedWithoutConfidence, confidence, null), dataCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable failure) {
|
||||
logger.severe("Polar Data Mining Pipe failed.");
|
||||
throw new RuntimeException("Polar Data Miner failed.", failure);
|
||||
}
|
||||
|
||||
public Set<BoatClass> getAvailableBoatClasses() {
|
||||
return availableBoatClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<GroupedDataEntry<GPSFixMovingWithPolarContext>> getInputType() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Void> getResultType() {
|
||||
// No result type here, since this is a special case of a processor. It's the end of the pipe so to say.
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.shared.annotations.Dimension;
|
||||
|
||||
public interface PolarClusterKey {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return degrees boat to windDirection in DEG
|
||||
*/
|
||||
@Dimension(messageKey = "angleToWind")
|
||||
RoundedAngleToTheWind getRoundedAngleToTheWind();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return wind speed cluster
|
||||
*/
|
||||
@Dimension(messageKey = "windSpeed")
|
||||
Cluster<Speed> getWindSpeedCluster();
|
||||
|
||||
@Dimension(messageKey = "boatClass")
|
||||
BoatClass getBoatClass();
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sse.datamining.factories.FunctionFactory;
|
||||
import com.sap.sse.datamining.functions.Function;
|
||||
|
||||
public class PolarDataDimensionCollectionFactory {
|
||||
|
||||
public static Collection<Function<?>> getClusterKeyDimensions() throws NoSuchMethodException {
|
||||
Collection<Function<?>> dimensions = new ArrayList<>();
|
||||
FunctionFactory functionFactory = new FunctionFactory();
|
||||
Function<RoundedAngleToTheWind> angleFunction = functionFactory
|
||||
.createMethodWrappingFunction(PolarClusterKey.class.getMethod("getRoundedAngleToTheWind",
|
||||
new Class<?>[0]));
|
||||
Function<WindSpeedLevel> windSpeedFunction = functionFactory.createMethodWrappingFunction(PolarClusterKey.class
|
||||
.getMethod("getWindSpeedCluster", new Class<?>[0]));
|
||||
Function<BoatClass> boatClassFunction = functionFactory.createMethodWrappingFunction(PolarClusterKey.class
|
||||
.getMethod("getBoatClass", new Class<?>[0]));
|
||||
|
||||
dimensions.add(boatClassFunction);
|
||||
dimensions.add(angleFunction);
|
||||
dimensions.add(windSpeedFunction);
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
|
||||
import com.sap.sailing.domain.common.PolarSheetsData;
|
||||
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetsDataImpl;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSteppingWithMaxDistance;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.datamining.functions.Function;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
import com.sap.sse.datamining.impl.components.ParallelFilteringProcessor;
|
||||
import com.sap.sse.datamining.impl.components.ParallelMultiDimensionsValueNestingGroupingProcessor;
|
||||
|
||||
public class PolarDataMiner {
|
||||
|
||||
private static final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
||||
private static final ThreadPoolExecutor executor = createExecutor();
|
||||
private final PolarSheetGenerationSettings defaultPolarSheetGenerationSettings;
|
||||
|
||||
private static ThreadPoolExecutor createExecutor() {
|
||||
return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>());
|
||||
}
|
||||
|
||||
|
||||
private AbstractEnrichingProcessor<GPSFixMovingWithOriginInfo, GPSFixMovingWithPolarContext> enrichingProcessor;
|
||||
private IncrementalRegressionProcessor incrementalRegressionProcessor;
|
||||
|
||||
public PolarDataMiner() {
|
||||
defaultPolarSheetGenerationSettings = PolarSheetGenerationSettingsImpl.createStandardPolarSettings();
|
||||
try {
|
||||
setUpWorkflow();
|
||||
} catch (ClassCastException | NoSuchMethodException | SecurityException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void setUpWorkflow() throws ClassCastException, NoSuchMethodException,
|
||||
SecurityException {
|
||||
WindSteppingWithMaxDistance stepping = defaultPolarSheetGenerationSettings.getWindStepping();
|
||||
final ClusterGroup<Speed> speedClusterGroup = SpeedClusterGroupFromWindSteppingCreator
|
||||
.createSpeedClusterGroupFrom(stepping);
|
||||
incrementalRegressionProcessor = new IncrementalRegressionProcessor(speedClusterGroup);
|
||||
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> grouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
|
||||
grouperResultReceivers.add(incrementalRegressionProcessor);
|
||||
|
||||
Collection<Function<?>> dimensions = PolarDataDimensionCollectionFactory.getClusterKeyDimensions();
|
||||
|
||||
Processor<GPSFixMovingWithPolarContext, GroupedDataEntry<GPSFixMovingWithPolarContext>> groupingProcessor = new ParallelMultiDimensionsValueNestingGroupingProcessor<GPSFixMovingWithPolarContext>(
|
||||
GPSFixMovingWithPolarContext.class, executor, grouperResultReceivers, dimensions);
|
||||
|
||||
Collection<Processor<GPSFixMovingWithPolarContext, ?>> filteringResultReceivers = Arrays.asList(groupingProcessor);
|
||||
Processor<GPSFixMovingWithPolarContext, GPSFixMovingWithPolarContext> filteringProcessor = new ParallelFilteringProcessor<GPSFixMovingWithPolarContext>(
|
||||
GPSFixMovingWithPolarContext.class, executor, filteringResultReceivers, new PolarFixFilterCriteria());
|
||||
|
||||
Collection<Processor<GPSFixMovingWithPolarContext, ?>> enrichingResultReceivers = Arrays
|
||||
.asList(filteringProcessor);
|
||||
|
||||
|
||||
enrichingProcessor = new AbstractEnrichingProcessor<GPSFixMovingWithOriginInfo, GPSFixMovingWithPolarContext>(
|
||||
GPSFixMovingWithOriginInfo.class, GPSFixMovingWithPolarContext.class, executor, enrichingResultReceivers) {
|
||||
|
||||
@Override
|
||||
protected GPSFixMovingWithPolarContext enrich(GPSFixMovingWithOriginInfo element) {
|
||||
return new GPSFixMovingWithPolarContext(element.getFix(), element.getTrackedRace(), element.getCompetitor(),
|
||||
speedClusterGroup);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void addFix(GPSFixMoving fix, Competitor competitor, TrackedRace trackedRace) {
|
||||
enrichingProcessor.processElement(new GPSFixMovingWithOriginInfo(fix, trackedRace,
|
||||
competitor));
|
||||
}
|
||||
|
||||
public boolean isCurrentlyActiveAndOrHasQueue() {
|
||||
boolean isActive = executor.getActiveCount() > 0;
|
||||
boolean hasQueue = executor.getQueue().size() > 0;
|
||||
return isActive || hasQueue;
|
||||
}
|
||||
|
||||
public SpeedWithConfidence<Void> estimateBoatSpeed(BoatClass boatClass, Speed windSpeed, Bearing angleToTheWind)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
return incrementalRegressionProcessor.estimateBoatSpeed(boatClass, windSpeed, angleToTheWind).getA();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public PolarSheetsData createFullSheetForBoatClass(BoatClass boatClass) {
|
||||
Integer[] defaultWindSpeeds = defaultPolarSheetGenerationSettings.getWindStepping().getRawStepping();
|
||||
Number[][] averagedPolarDataByWindSpeed = new Number[defaultWindSpeeds.length][360];
|
||||
|
||||
Map<Integer, Integer[]> dataCountPerAngleForWindspeed = new HashMap<>();
|
||||
Map<Integer, Map<Integer, PolarSheetsHistogramData>> histogramDataMap = new HashMap<>();
|
||||
|
||||
int totalDataCount = 0;
|
||||
|
||||
for (int windIndex = 0; windIndex < defaultWindSpeeds.length; windIndex++) {
|
||||
Integer windSpeed = defaultWindSpeeds[windIndex];
|
||||
|
||||
Integer[] perAngle = new Integer[360];
|
||||
Map<Integer, PolarSheetsHistogramData> perWindSpeed = new HashMap<>();
|
||||
for (int angle = 0; angle < 360; angle++) {
|
||||
Pair<SpeedWithConfidence<Void>, Integer> speedWithConfidenceAndDataCount;
|
||||
try {
|
||||
int convertedAngle = convertAngleIfNecessary(angle);
|
||||
speedWithConfidenceAndDataCount = incrementalRegressionProcessor.estimateBoatSpeed(boatClass,
|
||||
new KnotSpeedImpl(windSpeed), new DegreeBearingImpl(convertedAngle));
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
// No data so put in a 0 speed with 0 confidence
|
||||
speedWithConfidenceAndDataCount = new Pair<SpeedWithConfidence<Void>, Integer>(
|
||||
new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(0), 0, null), 0);
|
||||
}
|
||||
|
||||
averagedPolarDataByWindSpeed[windIndex][angle] = speedWithConfidenceAndDataCount.getA().getObject().getKnots();
|
||||
int dataCount = speedWithConfidenceAndDataCount.getB();
|
||||
|
||||
totalDataCount = totalDataCount + dataCount;
|
||||
//FIXME hard coded
|
||||
double coefficiantOfVariation = 0.8;
|
||||
double confidenceMeasure = 0.5;
|
||||
|
||||
PolarSheetsHistogramDataImpl polarSheetsHistogramDataImpl = createEmptyHistogramData(perAngle, angle,
|
||||
dataCount, coefficiantOfVariation, confidenceMeasure);
|
||||
perWindSpeed.put(angle, polarSheetsHistogramDataImpl);
|
||||
}
|
||||
histogramDataMap.put(windIndex, perWindSpeed);
|
||||
dataCountPerAngleForWindspeed.put(windIndex, perAngle);
|
||||
}
|
||||
|
||||
|
||||
PolarSheetsData data = new PolarSheetsDataImpl(averagedPolarDataByWindSpeed, totalDataCount,
|
||||
dataCountPerAngleForWindspeed, defaultPolarSheetGenerationSettings.getWindStepping(), histogramDataMap);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private int convertAngleIfNecessary(int angle) {
|
||||
int convertedAngle = angle;
|
||||
if (angle > 180) {
|
||||
convertedAngle = angle - 360;
|
||||
}
|
||||
return convertedAngle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private PolarSheetsHistogramDataImpl createEmptyHistogramData(Integer[] perAngle, int angle, int dataCount,
|
||||
double coefficiantOfVariation, double confidenceMeasure) {
|
||||
perAngle[angle] = dataCount;
|
||||
Number[] xValues = {};
|
||||
Number[] yValues = {};;
|
||||
Map<String, Integer[]> yValuesByGaugeIds = new HashMap<>();
|
||||
Map<String, Integer[]> yValuesByDay = new HashMap<>();
|
||||
Map<String, Integer[]> yValuesByDayAndGaugeId = new HashMap<>();
|
||||
|
||||
|
||||
PolarSheetsHistogramDataImpl polarSheetsHistogramDataImpl = new PolarSheetsHistogramDataImpl(angle, xValues, yValues, yValuesByGaugeIds,
|
||||
yValuesByDay, yValuesByDayAndGaugeId, dataCount, coefficiantOfVariation);
|
||||
|
||||
polarSheetsHistogramDataImpl.setConfidenceMeasure(confidenceMeasure);
|
||||
return polarSheetsHistogramDataImpl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Set<BoatClass> getAvailableBoatClasses() {
|
||||
return incrementalRegressionProcessor.getAvailableBoatClasses();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Integer[] getDataCountsForWindSpeed(BoatClass boatClass, Speed windSpeed, int startAngleInclusive, int endAngleExclusive) {
|
||||
Integer[] dataCounts = new Integer[360];
|
||||
for (int angle = 0; angle < 360; angle++) {
|
||||
if (angle >= startAngleInclusive && angle < endAngleExclusive) {
|
||||
try {
|
||||
dataCounts[angle] = incrementalRegressionProcessor.estimateBoatSpeed(boatClass, windSpeed,
|
||||
new DegreeBearingImpl(convertAngleIfNecessary(angle))).getB();
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
dataCounts[angle] = 0;
|
||||
}
|
||||
} else {
|
||||
dataCounts[angle] = null;
|
||||
}
|
||||
}
|
||||
return dataCounts;
|
||||
}
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.datamining.components.FilterCriterion;
|
||||
|
||||
public class PolarFixFilterCriteria implements FilterCriterion<GPSFixMovingWithPolarContext> {
|
||||
|
||||
@Override
|
||||
public boolean matches(GPSFixMovingWithPolarContext element) {
|
||||
boolean afterStartTime = isAfterStartTime(element);
|
||||
boolean beforeFinishTime = isBeforeFinishTime(element);
|
||||
boolean noDirectionChange = !hasDirectionChange(element);
|
||||
return (afterStartTime && beforeFinishTime && noDirectionChange);
|
||||
}
|
||||
|
||||
private boolean hasDirectionChange(GPSFixMovingWithPolarContext element) {
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = element.getRace().getTrack(element.getCompetitor());
|
||||
return track.hasDirectionChange(element.getFix().getTimePoint(), element.getRace().getRace().getBoatClass()
|
||||
.getManeuverDegreeAngleThreshold());
|
||||
}
|
||||
|
||||
private boolean isBeforeFinishTime(GPSFixMovingWithPolarContext element) {
|
||||
TimePoint timepointOfFix = element.getFix().getTimePoint();
|
||||
boolean isBeforeFinish;
|
||||
TimePoint finishTime = calculateFinishTime(element.getRace(), element.getCompetitor());
|
||||
isBeforeFinish = timepointOfFix.before(finishTime);
|
||||
return isBeforeFinish;
|
||||
}
|
||||
|
||||
private TimePoint calculateFinishTime(TrackedRace race, Competitor competitor) {
|
||||
TimePoint finishTime = race.getEndOfRace();
|
||||
Course course = race.getRace().getCourse();
|
||||
if (course.getLastWaypoint() != course.getFirstWaypoint()) {
|
||||
MarkPassing finishPassing = race.getMarkPassing(competitor, course.getLastWaypoint());
|
||||
if (finishPassing != null) {
|
||||
TimePoint passedFinishTimePoint = finishPassing.getTimePoint();
|
||||
if (passedFinishTimePoint.before(finishTime)) {
|
||||
finishTime = passedFinishTimePoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
return finishTime;
|
||||
}
|
||||
|
||||
private boolean isAfterStartTime(GPSFixMovingWithPolarContext element) {
|
||||
TimePoint timepointOfFix = element.getFix().getTimePoint();
|
||||
boolean isAfterStart;
|
||||
try {
|
||||
TimePoint startTime = calculateStartTime(element.getRace(), element.getCompetitor());
|
||||
isAfterStart = timepointOfFix.after(startTime);
|
||||
} catch (CompetitorDidNotStartYetException exception) {
|
||||
isAfterStart = false;
|
||||
}
|
||||
return isAfterStart;
|
||||
}
|
||||
|
||||
private TimePoint calculateStartTime(TrackedRace race, Competitor competitor) throws CompetitorDidNotStartYetException {
|
||||
MarkPassing startPassing = race.getMarkPassing(competitor, race.getRace().getCourse().getFirstWaypoint());
|
||||
if (startPassing == null) {
|
||||
throw new CompetitorDidNotStartYetException();
|
||||
}
|
||||
TimePoint raceStartTime = race.getStartOfRace();
|
||||
TimePoint startTime;
|
||||
TimePoint passedStartTimePoint = startPassing.getTimePoint();
|
||||
if (passedStartTimePoint.after(raceStartTime)) {
|
||||
startTime = passedStartTimePoint;
|
||||
} else {
|
||||
startTime = raceStartTime;
|
||||
}
|
||||
return startTime;
|
||||
}
|
||||
|
||||
private class CompetitorDidNotStartYetException extends Exception {
|
||||
private static final long serialVersionUID = 7906688735433666009L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<GPSFixMovingWithPolarContext> getElementType() {
|
||||
return GPSFixMovingWithPolarContext.class;
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
|
||||
public class RoundedAngleToTheWind {
|
||||
|
||||
private final int angle;
|
||||
|
||||
public RoundedAngleToTheWind(Bearing angleToTheWind) {
|
||||
this.angle = (int) Math.round(angleToTheWind.getDegrees());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + angle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + angle;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
RoundedAngleToTheWind other = (RoundedAngleToTheWind) obj;
|
||||
if (angle != other.angle)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.WindSteppingWithMaxDistance;
|
||||
import com.sap.sailing.polars.clusters.SpeedClusterGroup;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
|
||||
public class SpeedClusterGroupFromWindSteppingCreator {
|
||||
|
||||
public static ClusterGroup<Speed> createSpeedClusterGroupFrom(WindSteppingWithMaxDistance windStepping) {
|
||||
double maxDistance = windStepping.getMaxDistance();
|
||||
Integer[] rawIntegerStepping = windStepping.getRawStepping();
|
||||
double[] rawDoubleLevelMids = new double[rawIntegerStepping.length];
|
||||
for (int i = 0; i < rawIntegerStepping.length; i++) {
|
||||
rawDoubleLevelMids[i] = rawIntegerStepping[i];
|
||||
}
|
||||
|
||||
return new SpeedClusterGroup("Speed Cluster Group", rawDoubleLevelMids, maxDistance);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.WindStepping;
|
||||
|
||||
public class WindSpeedLevel {
|
||||
|
||||
private final int level;
|
||||
private final WindStepping stepping;
|
||||
|
||||
public WindSpeedLevel(Speed windSpeed, WindStepping stepping) {
|
||||
this.level = stepping.getLevelIndexForValue(windSpeed.getKnots());
|
||||
this.stepping = stepping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// FIXME right now the toString equals for different steppings. This will resolve in an equal groupkey in the
|
||||
// datamining framework. The current approach is to use only the default WindStepping.
|
||||
return "" + level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + level;
|
||||
result = prime * result + ((stepping == null) ? 0 : stepping.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
WindSpeedLevel other = (WindSpeedLevel) obj;
|
||||
if (level != other.level)
|
||||
return false;
|
||||
if (stepping == null) {
|
||||
if (other.stepping != null)
|
||||
return false;
|
||||
} else if (!stepping.equals(other.stepping))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.sap.sailing.polars.regression;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import com.sap.sailing.polars.mining.IncrementalRegressionProcessor;
|
||||
import com.sap.sailing.polars.regression.impl.IncrementalLeastSquaresProcessor;
|
||||
|
||||
/**
|
||||
* Combines two linear regression processors. One with the angle to the wind as the x axis and the other with the wind
|
||||
* speed on the x axis. Both y axis represent the boat speed.
|
||||
*
|
||||
* {@link #estimateSpeed(double, double)} returns the average of the estimation of both regressions.
|
||||
*
|
||||
* Note that this class should only be used for a small interval on a polar sheet. The
|
||||
* {@link IncrementalRegressionProcessor} is one example for that. It has one instance of the {@link BoatSpeedEstimator}
|
||||
* for each wind speed level and rounded angle combination.
|
||||
*
|
||||
* @author Frederik Petersen (D054528)
|
||||
*
|
||||
*/
|
||||
public class BoatSpeedEstimator {
|
||||
|
||||
private IncrementalLinearRegressionProcessor angleRegression = new IncrementalLeastSquaresProcessor();
|
||||
|
||||
private IncrementalLinearRegressionProcessor windSpeedRegression = new IncrementalLeastSquaresProcessor();
|
||||
|
||||
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
|
||||
|
||||
private double confidenceSum = 0;
|
||||
|
||||
private int dataCount = 0;
|
||||
|
||||
public double estimateSpeed(double windSpeed, double angleToTheWind) throws NotEnoughDataHasBeenAddedException {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
double angleEstimated = angleRegression.getEstimatedY(angleToTheWind);
|
||||
double windSpeedEstimated = windSpeedRegression.getEstimatedY(windSpeed);
|
||||
return (angleEstimated + windSpeedEstimated) / 2.0;
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void addData(double windSpeed, double angleToTheWind, double boatSpeed, double confidence) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
angleRegression.addMeasuredPoint(angleToTheWind, boatSpeed);
|
||||
windSpeedRegression.addMeasuredPoint(windSpeed, boatSpeed);
|
||||
dataCount++;
|
||||
confidenceSum = confidenceSum + confidence;
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getDataCount() {
|
||||
return dataCount;
|
||||
}
|
||||
|
||||
public double getConfidence() {
|
||||
return confidenceSum / dataCount;
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.sap.sailing.polars.regression;
|
||||
|
||||
public interface IncrementalLinearRegressionProcessor {
|
||||
|
||||
double getEstimatedY(double x) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
void addMeasuredPoint(double x, double y);
|
||||
|
||||
double getSlope();
|
||||
|
||||
double getIntercept();
|
||||
|
||||
int getDataCount();
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.sap.sailing.polars.regression;
|
||||
|
||||
public class NotEnoughDataHasBeenAddedException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 4134116458606258315L;
|
||||
|
||||
public NotEnoughDataHasBeenAddedException() {
|
||||
super("No data has been added to the Processor yet. At least to value-pairs have to be added.");
|
||||
}
|
||||
|
||||
public NotEnoughDataHasBeenAddedException(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package com.sap.sailing.polars.regression.impl;
|
||||
|
||||
import com.sap.sailing.polars.regression.IncrementalLinearRegressionProcessor;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
|
||||
/**
|
||||
* Allows a linear regression of a 2 dimensional and growing dataset. It has a complexity of O(1)
|
||||
*
|
||||
* The algorithm and variable naming is similar to the <a
|
||||
* href="https://de.wikipedia.org/wiki/Methode_der_kleinsten_Quadrate#Lineare_Modellfunktion">german wikipedia
|
||||
* article</a>
|
||||
*
|
||||
* The difference is that some parts of the equation are memorized as fields and updated incrementally.
|
||||
*
|
||||
* @author Frederik Petersen (D054528)
|
||||
*
|
||||
*/
|
||||
public class IncrementalLeastSquaresProcessor implements IncrementalLinearRegressionProcessor {
|
||||
|
||||
private double alpha1 = 0;
|
||||
|
||||
private double alpha0 = 0;
|
||||
|
||||
private double partA = 0;
|
||||
|
||||
private double partB = 0;
|
||||
|
||||
private double meanOfX = 0;
|
||||
|
||||
private double meanOfY = 0;
|
||||
|
||||
private int numberOfPointsAdded = 0;
|
||||
|
||||
@Override
|
||||
public double getEstimatedY(double x) throws NotEnoughDataHasBeenAddedException {
|
||||
if (numberOfPointsAdded < 1) {
|
||||
throw new NotEnoughDataHasBeenAddedException();
|
||||
}
|
||||
|
||||
double result;
|
||||
if (numberOfPointsAdded < 2) {
|
||||
// Return the y value of the only added data point.
|
||||
result = meanOfY;
|
||||
} else {
|
||||
result = alpha0 + alpha1 * x;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMeasuredPoint(double x, double y) {
|
||||
numberOfPointsAdded++;
|
||||
|
||||
calculatePartA(x, y);
|
||||
calculatePartB(x, y);
|
||||
|
||||
addToArithmeticMeanOfX(x);
|
||||
addToArithmeticMeanOfY(y);
|
||||
|
||||
calculateFactor1();
|
||||
calculateFactor2();
|
||||
}
|
||||
|
||||
private void calculateFactor2() {
|
||||
alpha0 = meanOfY - alpha1 * meanOfX;
|
||||
}
|
||||
|
||||
private void calculateFactor1() {
|
||||
double numerator = calculateNumeratorOfFactor1();
|
||||
double denominator = calculateDenominatorOfFactor1();
|
||||
if (denominator == 0) {
|
||||
alpha1 = 0;
|
||||
} else {
|
||||
alpha1 = numerator / denominator;
|
||||
}
|
||||
}
|
||||
|
||||
private double calculateNumeratorOfFactor1() {
|
||||
return partA - numberOfPointsAdded * meanOfX * meanOfY;
|
||||
}
|
||||
|
||||
private double calculateDenominatorOfFactor1() {
|
||||
return partB - numberOfPointsAdded * meanOfX * meanOfX;
|
||||
}
|
||||
|
||||
private void addToArithmeticMeanOfY(double y) {
|
||||
meanOfY = addToMean(y, meanOfY);
|
||||
}
|
||||
|
||||
private void addToArithmeticMeanOfX(double x) {
|
||||
meanOfX = addToMean(x, meanOfX);
|
||||
}
|
||||
|
||||
private double addToMean(double z, double oldMean) {
|
||||
return oldMean + (z - oldMean) / numberOfPointsAdded;
|
||||
}
|
||||
|
||||
private void calculatePartB(double x, double y) {
|
||||
partB = partB + x * x;
|
||||
}
|
||||
|
||||
private void calculatePartA(double x, double y) {
|
||||
partA = partA + x * y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSlope() {
|
||||
return alpha1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIntercept() {
|
||||
return alpha0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataCount() {
|
||||
return numberOfPointsAdded;
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.sap.sailing.server.gateway.deserialization.impl;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.SpeedWithConfidenceWithIntegerRelationJsonSerializer;
|
||||
|
||||
public class SpeedWithConfidenceWithIntegerRelationJsonDeserializer implements
|
||||
JsonDeserializer<SpeedWithConfidence<Integer>> {
|
||||
|
||||
@Override
|
||||
public SpeedWithConfidence<Integer> deserialize(JSONObject object) throws JsonDeserializationException {
|
||||
double speedInKnots = (Double) object.get(SpeedWithConfidenceWithIntegerRelationJsonSerializer.FIELD_SPEED);
|
||||
double confidence = (Double) object.get(SpeedWithConfidenceWithIntegerRelationJsonSerializer.FIELD_CONFIDENCE);
|
||||
int relativeToValue = (Integer) object
|
||||
.get(SpeedWithConfidenceWithIntegerRelationJsonSerializer.FIELD_RELATION_INT);
|
||||
Speed speed = new KnotSpeedImpl(speedInKnots);
|
||||
return new SpeedWithConfidenceImpl<Integer>(speed, confidence, relativeToValue);
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.sap.sailing.server.gateway.serialization.impl;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
|
||||
public class SpeedWithConfidenceWithIntegerRelationJsonSerializer implements
|
||||
JsonSerializer<SpeedWithConfidence<Integer>> {
|
||||
|
||||
public static final String FIELD_SPEED = "speed";
|
||||
public static final String FIELD_CONFIDENCE = "confidence";
|
||||
public static final String FIELD_RELATION_INT = "relationInt";
|
||||
|
||||
@Override
|
||||
public JSONObject serialize(SpeedWithConfidence<Integer> speed) {
|
||||
JSONObject object = new JSONObject();
|
||||
object.put(FIELD_SPEED, speed.getObject().getKnots());
|
||||
object.put(FIELD_CONFIDENCE, speed.getConfidence());
|
||||
object.put(FIELD_RELATION_INT, speed.getRelativeTo());
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +1,50 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Sailing Server Gateway
|
||||
Bundle-SymbolicName: com.sap.sailing.server.gateway
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package: com.sap.sailing.server,
|
||||
com.sap.sailing.server.operationaltransformation,
|
||||
com.sap.sailing.server.racelog.tracking,
|
||||
javax.ws.rs;version="1.1.1",
|
||||
javax.ws.rs.core;version="1.1.1",
|
||||
javax.ws.rs.ext;version="1.1.1",
|
||||
org.apache.commons.lang,
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework;version="1.3.0",
|
||||
org.osgi.util.tracker;version="1.3.1"
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.expeditionconnector,
|
||||
com.sap.sailing.declination,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sse.mongodb,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
javax.servlet;bundle-version="2.6.0",
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.udpconnector,
|
||||
org.jdom;bundle-version="1.0.0",
|
||||
com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0",
|
||||
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
||||
com.sap.sailing.server.trackfiles;bundle-version="1.0.0",
|
||||
org.eclipse.jetty.websocket.api;bundle-version="9.0.4",
|
||||
org.eclipse.jetty.websocket.server;bundle-version="9.0.4",
|
||||
org.eclipse.jetty.websocket.servlet;bundle-version="9.0.4",
|
||||
org.eclipse.jetty.websocket.client;bundle-version="9.0.4",
|
||||
org.eclipse.jetty.websocket.common;bundle-version="9.0.4",
|
||||
javax.validation;bundle-version="1.0.0",
|
||||
com.sun.jersey;bundle-version="1.17.0",
|
||||
org.objectweb.asm;bundle-version="3.3.1",
|
||||
org.apache.commons.fileupload;bundle-version="1.2.2",
|
||||
com.sap.sailing.domain.igtimiadapter;bundle-version="1.0.0",
|
||||
com.sap.sse.common
|
||||
Bundle-ClassPath: .
|
||||
Web-ContextPath: /sailingserver
|
||||
Export-Package: com.sap.sailing.server.gateway,
|
||||
com.sap.sailing.server.gateway.jaxrs,
|
||||
com.sap.sailing.server.gateway.jaxrs.spi
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Sailing Server Gateway
|
||||
Bundle-SymbolicName: com.sap.sailing.server.gateway
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package: com.sap.sailing.polars,
|
||||
com.sap.sailing.polars.regression,
|
||||
com.sap.sailing.server,
|
||||
com.sap.sailing.server.operationaltransformation,
|
||||
com.sap.sailing.server.racelog.tracking,
|
||||
javax.ws.rs;version="1.1.1",
|
||||
javax.ws.rs.core;version="1.1.1",
|
||||
javax.ws.rs.ext;version="1.1.1",
|
||||
org.apache.commons.lang,
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework;version="1.3.0",
|
||||
org.osgi.util.tracker;version="1.3.1"
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.expeditionconnector,
|
||||
com.sap.sailing.declination,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sse.mongodb,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
javax.servlet;bundle-version="2.6.0",
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.udpconnector,
|
||||
org.jdom;bundle-version="1.0.0",
|
||||
com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0",
|
||||
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
|
||||
com.sap.sailing.server.trackfiles;bundle-version="1.0.0",
|
||||
org.eclipse.jetty.websocket.api;bundle-version="9.0.4",
|
||||
org.eclipse.jetty.websocket.server;bundle-version="9.0.4",
|
||||
org.eclipse.jetty.websocket.servlet;bundle-version="9.0.4",
|
||||
org.eclipse.jetty.websocket.client;bundle-version="9.0.4",
|
||||
org.eclipse.jetty.websocket.common;bundle-version="9.0.4",
|
||||
javax.validation;bundle-version="1.0.0",
|
||||
com.sun.jersey;bundle-version="1.17.0",
|
||||
org.objectweb.asm;bundle-version="3.3.1",
|
||||
org.apache.commons.fileupload;bundle-version="1.2.2",
|
||||
com.sap.sailing.domain.igtimiadapter;bundle-version="1.0.0",
|
||||
com.sap.sse.common
|
||||
Bundle-ClassPath: .
|
||||
Web-ContextPath: /sailingserver
|
||||
Export-Package: com.sap.sailing.server.gateway,
|
||||
com.sap.sailing.server.gateway.jaxrs,
|
||||
com.sap.sailing.server.gateway.jaxrs.spi
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.sap.sailing.server.gateway.jaxrs.api;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
|
||||
|
||||
/**
|
||||
* Right now this service is only used for quick debugging and testing of the polar api. It used plain text responses.
|
||||
* JSON should be used if this resource is to be consumed.
|
||||
*
|
||||
* @author Frederik Petersen
|
||||
*
|
||||
*/
|
||||
@Path("/v1/polars")
|
||||
public class PolarResource extends AbstractSailingServerResource {
|
||||
|
||||
@GET
|
||||
@Produces("text/plain;charset=UTF-8")
|
||||
@Path("{boatClassName}")
|
||||
public Response getSpeed(@PathParam("boatClassName") String boatClassName, @QueryParam("angle") double angle,
|
||||
@QueryParam("windspeed") double windSpeed) {
|
||||
BoatClass boatClass = getService().getDomainObjectFactory().getBaseDomainFactory()
|
||||
.getOrCreateBoatClass(boatClassName);
|
||||
SpeedWithConfidence<Void> speedWithConfidence;
|
||||
ResponseBuilder responseBuilder;
|
||||
try {
|
||||
speedWithConfidence = getService().getPolarDataService().getSpeed(boatClass, new KnotSpeedImpl(windSpeed),
|
||||
new DegreeBearingImpl(angle));
|
||||
String resultString = "Speed: " + speedWithConfidence.getObject().getKnots() + "kn; Confidence: "
|
||||
+ speedWithConfidence.getConfidence();
|
||||
responseBuilder = Response.ok(resultString, MediaType.TEXT_PLAIN);
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
responseBuilder = Response.noContent();
|
||||
}
|
||||
|
||||
return responseBuilder.build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces("text/plain;charset=UTF-8")
|
||||
@Path("average/{boatClassName}")
|
||||
public Response getAverageSpeedAndBearing(@PathParam("boatClassName") String boatClassName,
|
||||
@QueryParam("windspeed") double wSpeed, @QueryParam("legtype") LegType legType, @QueryParam("tack") Tack tack) {
|
||||
BoatClass boatClass = getService().getDomainObjectFactory().getBaseDomainFactory()
|
||||
.getOrCreateBoatClass(boatClassName);
|
||||
ResponseBuilder responseBuilder;
|
||||
Speed windSpeed = new KnotSpeedImpl(wSpeed);
|
||||
try {
|
||||
PolarDataService service = getService().getPolarDataService();
|
||||
SpeedWithBearingWithConfidence<Void> speedWithBearing = service.getAverageSpeedWithBearing(boatClass,
|
||||
windSpeed, legType, tack);
|
||||
String resultString = "Speed: " + speedWithBearing.getObject().getKnots() + "kn; Angle: "
|
||||
+ speedWithBearing.getObject().getBearing().getDegrees() + "°; Confidence: "
|
||||
+ speedWithBearing.getConfidence();
|
||||
responseBuilder = Response.ok(resultString, MediaType.TEXT_PLAIN);
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
responseBuilder = Response.noContent();
|
||||
}
|
||||
|
||||
return responseBuilder.build();
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -13,6 +13,7 @@ public class RestApiApplication extends Application {
|
||||
classes.add(EventsResource.class);
|
||||
classes.add(RegattasResource.class);
|
||||
classes.add(LeaderboardsResource.class);
|
||||
classes.add(PolarResource.class);
|
||||
classes.add(SearchResource.class);
|
||||
return classes;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Server Replication Test
|
||||
Bundle-SymbolicName: com.sap.sailing.server.replication.test
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Fragment-Host: com.sap.sailing.server.replication
|
||||
Import-Package: com.rabbitmq.client;version="2.8.4"
|
||||
Require-Bundle: com.sap.sailing.server,
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.test,
|
||||
com.sap.sse.mongodb,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.tractrac.clientmodule;bundle-version="2.0.0",
|
||||
com.sap.sailing.expeditionconnector,
|
||||
com.sap.sailing.domain.swisstimingadapter,
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
org.junit4;bundle-version="4.8.2",
|
||||
org.hamcrest;bundle-version="1.1.0",
|
||||
com.sap.sse.common,
|
||||
org.mockito.mockito-core;bundle-version="1.9.5"
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Server Replication Test
|
||||
Bundle-SymbolicName: com.sap.sailing.server.replication.test
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Fragment-Host: com.sap.sailing.server.replication
|
||||
Import-Package: com.rabbitmq.client;version="2.8.4"
|
||||
Require-Bundle: com.sap.sailing.server,
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.test,
|
||||
com.sap.sse.mongodb,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.tractrac.clientmodule;bundle-version="2.0.0",
|
||||
com.sap.sailing.expeditionconnector,
|
||||
com.sap.sailing.domain.swisstimingadapter,
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
org.junit4;bundle-version="4.8.2",
|
||||
org.hamcrest;bundle-version="1.1.0",
|
||||
com.sap.sailing.polars;bundle-version="1.0.0",
|
||||
com.sap.sse.common,
|
||||
org.mockito.mockito-core;bundle-version="1.9.5"
|
||||
+3
-3
@@ -137,12 +137,12 @@ public class MasterDataImportTest {
|
||||
private Set<Serializable> storedLogUUIDs = new HashSet<Serializable>();
|
||||
|
||||
@After
|
||||
public void tearDown() throws MalformedURLException, IOException, InterruptedException {
|
||||
public void tearDown() {
|
||||
deleteAllDataFromDatabase();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws MalformedURLException, IOException, InterruptedException {
|
||||
public void setUp() {
|
||||
deleteAllDataFromDatabase();
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ public class MasterDataImportTest {
|
||||
return spyResource;
|
||||
}
|
||||
|
||||
private void deleteAllDataFromDatabase() throws MalformedURLException, IOException, InterruptedException {
|
||||
private void deleteAllDataFromDatabase() {
|
||||
MongoDBService service = MongoDBConfiguration.getDefaultTestConfiguration().getService();
|
||||
service.getDB().getWriteConcern().fsync();
|
||||
service.getDB().dropDatabase();
|
||||
|
||||
Regular → Executable
+45
-42
@@ -1,42 +1,45 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Sailing Server
|
||||
Bundle-SymbolicName: com.sap.sailing.server
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Activator: com.sap.sailing.server.impl.Activator
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package: com.sap.sailing.server.gateway.deserialization,
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework;version="1.3.0",
|
||||
org.osgi.util.tracker;version="1.3.1"
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.expeditionconnector,
|
||||
com.sap.sailing.declination,
|
||||
com.sap.sse.mongodb,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.udpconnector,
|
||||
com.sap.sailing.operationaltransformation,
|
||||
com.sap.sailing.domain.shared.android,
|
||||
com.sap.sailing.server.gateway.serialization,
|
||||
com.sap.sse.common
|
||||
Bundle-ClassPath: .
|
||||
Export-Package: com.sap.sailing.server,
|
||||
com.sap.sailing.server.impl;
|
||||
x-friends:="com.sap.sailing.mongodb.test,
|
||||
com.sap.sailing.server.test,
|
||||
com.sap.sailing.server.gateway.test,
|
||||
com.sap.sailing.domain.swisstimingadapter.test,
|
||||
com.sap.sailing.gwt.ui.test,
|
||||
com.sap.sailing.server.replication.test,
|
||||
com.sap.sailing.domain.racelogtrackingadapter.test",
|
||||
com.sap.sailing.server.masterdata,
|
||||
com.sap.sailing.server.operationaltransformation,
|
||||
com.sap.sailing.server.racelog.tracking,
|
||||
com.sap.sailing.server.test.support;
|
||||
x-friends:="com.sap.sailing.server.gateway.test.support"
|
||||
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Sailing Server
|
||||
Bundle-SymbolicName: com.sap.sailing.server
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Activator: com.sap.sailing.server.impl.Activator
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package: com.sap.sailing.polars,
|
||||
com.sap.sailing.polars.factory,
|
||||
com.sap.sailing.server.gateway.deserialization,
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework;version="1.3.0",
|
||||
org.osgi.util.tracker;version="1.3.1"
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.expeditionconnector,
|
||||
com.sap.sailing.declination,
|
||||
com.sap.sse.mongodb,
|
||||
com.mongodb.driver;bundle-version="2.6.2",
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.udpconnector,
|
||||
com.sap.sailing.operationaltransformation,
|
||||
com.sap.sailing.domain.shared.android,
|
||||
com.sap.sailing.server.gateway.serialization,
|
||||
com.sap.sailing.polars,
|
||||
com.sap.sse.common
|
||||
Bundle-ClassPath: .
|
||||
Export-Package: com.sap.sailing.server,
|
||||
com.sap.sailing.server.impl;
|
||||
x-friends:="com.sap.sailing.mongodb.test,
|
||||
com.sap.sailing.server.test,
|
||||
com.sap.sailing.server.gateway.test,
|
||||
com.sap.sailing.domain.swisstimingadapter.test,
|
||||
com.sap.sailing.gwt.ui.test,
|
||||
com.sap.sailing.server.replication.test,
|
||||
com.sap.sailing.domain.racelogtrackingadapter.test",
|
||||
com.sap.sailing.server.masterdata,
|
||||
com.sap.sailing.server.operationaltransformation,
|
||||
com.sap.sailing.server.racelog.tracking,
|
||||
com.sap.sailing.server.test.support;
|
||||
x-friends:="com.sap.sailing.server.gateway.test.support"
|
||||
|
||||
@@ -33,5 +33,5 @@
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.replication@4:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mongodb@default:default,com.sap.sse.security.ui@6:true,com.sap.sse.security.userstore.mongodb@4:true,com.sap.sse.security@5:true,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.polars@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.replication@4:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mongodb@default:default,com.sap.sse.security.ui@6:true,com.sap.sse.security.userstore.mongodb@4:true,com.sap.sse.security@5:true,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,36 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
|
||||
<booleanAttribute key="append.args" value="true"/>
|
||||
<booleanAttribute key="automaticAdd" value="false"/>
|
||||
<booleanAttribute key="automaticValidate" value="false"/>
|
||||
<stringAttribute key="bootstrap" value=""/>
|
||||
<stringAttribute key="checked" value="[NONE]"/>
|
||||
<booleanAttribute key="clearConfig" value="false"/>
|
||||
<stringAttribute key="configLocation" value="${workspace_loc}/target"/>
|
||||
<booleanAttribute key="default" value="true"/>
|
||||
<booleanAttribute key="default_auto_start" value="true"/>
|
||||
<intAttribute key="default_start_level" value="4"/>
|
||||
<booleanAttribute key="includeOptional" value="true"/>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dexpedition.udp.port=2010 -Xmx4096m -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback -Dtractrac.mtb.cache.dir=/Users/Lennart/Projects/SAP_Sailing/tmp/mtb"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
||||
<stringAttribute key="pde.version" value="3.3"/>
|
||||
<stringAttribute key="profilingTraceType-ALLOCATION_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%INCREASE_COUNT%CTX_KEY%8192%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ADAPTIVE%CTX_KEY%false%CTX_ENTRY%KEY_MIN_SIZE%CTX_KEY%32%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%CLASS_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_MAX_SIZE%CTX_KEY%65536%CTX_ENTRY%KEY_INC_LINE_NRS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-IO_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-METHOD_PARAMETER_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-NETWORK_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_RESOLVE_ALL_HOSTS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<booleanAttribute key="show_selected_only" value="false"/>
|
||||
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.replication@4:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mongodb@default:default,com.sap.sse.security.ui@default:default,com.sap.sse.security.userstore.mongodb@default:default,com.sap.sse.security@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
</launchConfiguration>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
|
||||
<booleanAttribute key="append.args" value="true"/>
|
||||
<booleanAttribute key="automaticAdd" value="false"/>
|
||||
<booleanAttribute key="automaticValidate" value="false"/>
|
||||
<stringAttribute key="bootstrap" value=""/>
|
||||
<stringAttribute key="checked" value="[NONE]"/>
|
||||
<booleanAttribute key="clearConfig" value="false"/>
|
||||
<stringAttribute key="configLocation" value="${workspace_loc}/target"/>
|
||||
<booleanAttribute key="default" value="true"/>
|
||||
<booleanAttribute key="default_auto_start" value="true"/>
|
||||
<intAttribute key="default_start_level" value="4"/>
|
||||
<booleanAttribute key="includeOptional" value="true"/>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dexpedition.udp.port=2010 -Xmx4096m -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback -Dtractrac.mtb.cache.dir=/Users/Lennart/Projects/SAP_Sailing/tmp/mtb"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
||||
<stringAttribute key="pde.version" value="3.3"/>
|
||||
<stringAttribute key="profilingTraceType-ALLOCATION_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%INCREASE_COUNT%CTX_KEY%8192%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ADAPTIVE%CTX_KEY%false%CTX_ENTRY%KEY_MIN_SIZE%CTX_KEY%32%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%CLASS_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_MAX_SIZE%CTX_KEY%65536%CTX_ENTRY%KEY_INC_LINE_NRS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-IO_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-METHOD_PARAMETER_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-NETWORK_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_RESOLVE_ALL_HOSTS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
<booleanAttribute key="show_selected_only" value="false"/>
|
||||
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.polars@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.replication@4:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mongodb@default:default,com.sap.sse.security.ui@default:default,com.sap.sse.security.userstore.mongodb@default:default,com.sap.sse.security@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,31 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
|
||||
<booleanAttribute key="append.args" value="true"/>
|
||||
<booleanAttribute key="automaticAdd" value="false"/>
|
||||
<booleanAttribute key="automaticValidate" value="false"/>
|
||||
<stringAttribute key="bootstrap" value=""/>
|
||||
<stringAttribute key="checked" value="[NONE]"/>
|
||||
<booleanAttribute key="clearConfig" value="false"/>
|
||||
<stringAttribute key="configLocation" value="${workspace_loc}/target"/>
|
||||
<booleanAttribute key="default" value="true"/>
|
||||
<booleanAttribute key="default_auto_start" value="true"/>
|
||||
<intAttribute key="default_start_level" value="4"/>
|
||||
<booleanAttribute key="includeOptional" value="true"/>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djetty.port=8889 -Dreplication.exchangeName=sapsailinganalytics-replica -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dexpedition.udp.port=2011 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
||||
<stringAttribute key="pde.version" value="3.3"/>
|
||||
<booleanAttribute key="show_selected_only" value="false"/>
|
||||
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.felix.shell.remote@default:default,org.apache.felix.shell@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.hamcrest.integration@default:default,org.hamcrest.library@default:default,org.hamcrest.text@default:default,org.hamcrest@default:default,org.jdom@default:default,org.junit4@default:default,org.mockito.mockito-core@default:default,org.objectweb.asm@default:default,org.objenesis@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:true,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@5:true,com.sap.sailing.domain.swisstimingreplayadapter@5:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@5:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xmlexport@default:default,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mongodb@default:default,com.sap.sse.security.ui@default:default,com.sap.sse.security.userstore.mongodb@default:default,com.sap.sse.security@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="yk-options" value=" additional-options2=onexit\=snapshot "/>
|
||||
</launchConfiguration>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
|
||||
<booleanAttribute key="append.args" value="true"/>
|
||||
<booleanAttribute key="automaticAdd" value="false"/>
|
||||
<booleanAttribute key="automaticValidate" value="false"/>
|
||||
<stringAttribute key="bootstrap" value=""/>
|
||||
<stringAttribute key="checked" value="[NONE]"/>
|
||||
<booleanAttribute key="clearConfig" value="false"/>
|
||||
<stringAttribute key="configLocation" value="${workspace_loc}/target"/>
|
||||
<booleanAttribute key="default" value="true"/>
|
||||
<booleanAttribute key="default_auto_start" value="true"/>
|
||||
<intAttribute key="default_start_level" value="4"/>
|
||||
<booleanAttribute key="includeOptional" value="true"/>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djetty.port=8889 -Dreplication.exchangeName=sapsailinganalytics-replica -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dexpedition.udp.port=2011 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
||||
<stringAttribute key="pde.version" value="3.3"/>
|
||||
<booleanAttribute key="show_selected_only" value="false"/>
|
||||
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.felix.shell.remote@default:default,org.apache.felix.shell@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.hamcrest.integration@default:default,org.hamcrest.library@default:default,org.hamcrest.text@default:default,org.hamcrest@default:default,org.jdom@default:default,org.junit4@default:default,org.mockito.mockito-core@default:default,org.objectweb.asm@default:default,org.objenesis@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:true,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@5:true,com.sap.sailing.domain.swisstimingreplayadapter@5:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@5:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.polars@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xmlexport@default:default,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mongodb@default:default,com.sap.sse.security.ui@default:default,com.sap.sse.security.userstore.mongodb@default:default,com.sap.sse.security@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="yk-options" value=" additional-options2=onexit\=snapshot "/>
|
||||
</launchConfiguration>
|
||||
+2
-2
@@ -16,7 +16,7 @@
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0_20"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jre1.8.0_20"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djetty.port=8889 -Dreplication.exchangeName=sapsailinganalytics-replica -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dexpedition.udp.port=2011 -Xmx6000m -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar -Djava.library.path=${project_loc:com.sap.sailing.monitoring}/../../configuration/native-libraries -Dtractrac.mtb.cache.dir=/Users/spamies/Projects/sailing/tmp/mtb"/>
|
||||
@@ -27,6 +27,6 @@
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.autoload@5:true,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:true,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@5:true,com.sap.sailing.domain.swisstimingreplayadapter@5:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@5:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xmlexport@default:default,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mongodb@default:default,com.sap.sse.security.ui@default:default,com.sap.sse.security.userstore.mongodb@default:default,com.sap.sse.security@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.autoload@5:true,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:true,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@5:true,com.sap.sailing.domain.swisstimingreplayadapter@5:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@5:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.polars@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xmlexport@default:default,com.sap.sailing.xrr.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mongodb@default:default,com.sap.sse.security.ui@default:default,com.sap.sse.security.userstore.mongodb@default:default,com.sap.sse.security@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="yk-options" value=" additional-options2=onexit\=snapshot "/>
|
||||
</launchConfiguration>
|
||||
Loaded 100 of 144 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user