mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-28 14:57:12 +00:00
Merge remote-tracking branch 'server/master'
This commit is contained in:
commit
c81ca32c8c
44 files changed
+406
-246
No files matched your search
-4
@@ -7,10 +7,6 @@ import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public interface PolarSheetsXYDiagramData extends Serializable {
|
||||
|
||||
List<Pair<Double, Double>> getPointsForAverageSpeedMovingAverage(Tack tack, LegType legType);
|
||||
|
||||
List<Pair<Double, Double>> getPointsForAverageConfidence(Tack tack, LegType legType);
|
||||
|
||||
List<Pair<Double, Double>> getPointsForAverageSpeedRegression(Tack tack, LegType legType);
|
||||
|
||||
}
|
||||
+1
-19
@@ -15,29 +15,11 @@ public class PolarSheetsXYDiagramDataImpl implements PolarSheetsXYDiagramData {
|
||||
PolarSheetsXYDiagramDataImpl() {
|
||||
}
|
||||
|
||||
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageSpeedMovingAverage;
|
||||
|
||||
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageSpeedRegression;
|
||||
|
||||
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageConfidence;
|
||||
|
||||
public PolarSheetsXYDiagramDataImpl(
|
||||
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> movingAverageSpeedDataLists,
|
||||
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists,
|
||||
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> averageConfidenceDataLists) {
|
||||
pointsForAverageSpeedMovingAverage = movingAverageSpeedDataLists;
|
||||
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists) {
|
||||
pointsForAverageSpeedRegression = regressionSpeedDataLists;
|
||||
pointsForAverageConfidence = averageConfidenceDataLists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pair<Double, Double>> getPointsForAverageSpeedMovingAverage(Tack tack, LegType legType) {
|
||||
return pointsForAverageSpeedMovingAverage.get(new Pair<LegType, Tack>(legType, tack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pair<Double, Double>> getPointsForAverageConfidence(Tack tack, LegType legType) {
|
||||
return pointsForAverageConfidence.get(new Pair<LegType, Tack>(legType, tack));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-30
@@ -8,6 +8,7 @@ import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
@@ -51,36 +52,6 @@ public interface PolarDataService {
|
||||
SpeedWithConfidence<Void> getSpeed(BoatClass boatClass, Speed windSpeed, Bearing trueWindAngle)
|
||||
throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param boatClass
|
||||
* @param windSpeed
|
||||
* @param legType
|
||||
* Should be {@link LegType#UPWIND} or {@link LegType#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.
|
||||
* @param useRegressionForSpeed TODO
|
||||
* @return The estimated average speed of a boat for the supplied parameters with the estimated average bearing to
|
||||
* the true 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, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
|
||||
/**
|
||||
* Generates a polar sheet for given races and settings using the provided executor for the worker threads. This
|
||||
@@ -242,5 +213,9 @@ public interface PolarDataService {
|
||||
*/
|
||||
void unregisterListener(BoatClass boatClass, PolarsChangedListener listener);
|
||||
|
||||
void registerDomainFactory(DomainFactory domainFactory);
|
||||
|
||||
void unregisterDomainFactory(DomainFactory domainFactory);
|
||||
|
||||
|
||||
}
|
||||
-22
@@ -4,12 +4,9 @@ import java.util.List;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.AxisTitle;
|
||||
import org.moxieapps.gwt.highcharts.client.Chart;
|
||||
import org.moxieapps.gwt.highcharts.client.PlotLine;
|
||||
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.plotOptions.Marker;
|
||||
import org.moxieapps.gwt.highcharts.client.plotOptions.SplinePlotOptions;
|
||||
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
@@ -58,33 +55,14 @@ public class PolarSheetsXYDiagramPopupPanel extends DialogBox {
|
||||
}
|
||||
|
||||
private void addSpeedAndConfidenceSeriesForTackAndLegType(PolarSheetsXYDiagramData result, Tack tack, LegType legType, boolean showByDefault) {
|
||||
Point[] pointsForUpwindStarboardAverageSpeedMovingAverage = toPointArray(result.getPointsForAverageSpeedMovingAverage(tack, legType));
|
||||
Series speedSeriesMovingAverage = chart.createSeries();
|
||||
speedSeriesMovingAverage.setName(tack + " " + legType + " Speed - MovingAverage");
|
||||
speedSeriesMovingAverage.setPoints(pointsForUpwindStarboardAverageSpeedMovingAverage);
|
||||
chart.addSeries(speedSeriesMovingAverage, false, false);
|
||||
|
||||
Point[] pointsForUpwindStarboardAverageSpeedRegression = toPointArray(result.getPointsForAverageSpeedRegression(tack, legType));
|
||||
Series speedSeriesRegression = chart.createSeries();
|
||||
speedSeriesRegression.setName(tack + " " + legType + " Speed - Regression");
|
||||
speedSeriesRegression.setPoints(pointsForUpwindStarboardAverageSpeedRegression);
|
||||
chart.addSeries(speedSeriesRegression, false, false);
|
||||
|
||||
Point[] pointsForUpwindStarboardAverageConfidence = toPointArray(result.getPointsForAverageConfidence(tack, legType));
|
||||
Series confidenceSeries = chart
|
||||
.createSeries()
|
||||
.setYAxis(1)
|
||||
.setType(Series.Type.SPLINE)
|
||||
.setPlotOptions(
|
||||
new SplinePlotOptions().setColor("#AA4643").setMarker(new Marker().setEnabled(false))
|
||||
.setDashStyle(PlotLine.DashStyle.SHORT_DOT));
|
||||
confidenceSeries.setName(tack + " " + legType + " Confidence");
|
||||
confidenceSeries.setPoints(pointsForUpwindStarboardAverageConfidence);
|
||||
chart.addSeries(confidenceSeries, false, false);
|
||||
|
||||
if (!showByDefault) {
|
||||
speedSeriesRegression.setVisible(false, false);
|
||||
confidenceSeries.setVisible(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-29
@@ -61,10 +61,10 @@ import com.sap.sailing.domain.abstractlog.AbstractLog;
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.AbortingFlagFinder;
|
||||
@@ -5585,45 +5585,20 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
@Override
|
||||
public PolarSheetsXYDiagramData createXYDiagramForBoatClass(String boatClassName) {
|
||||
BoatClass boatClass = getService().getBaseDomainFactory().getOrCreateBoatClass(boatClassName);
|
||||
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> movingAverageSpeedDataLists = new HashMap<>();
|
||||
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists = new HashMap<>();
|
||||
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> averageConfidenceDataLists = new HashMap<>();
|
||||
for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) {
|
||||
for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) {
|
||||
movingAverageSpeedDataLists.put(new Pair<LegType, Tack>(legType, tack),
|
||||
new ArrayList<Pair<Double, Double>>());
|
||||
regressionSpeedDataLists.put(new Pair<LegType, Tack>(legType, tack),
|
||||
new ArrayList<Pair<Double, Double>>());
|
||||
averageConfidenceDataLists.put(new Pair<LegType, Tack>(legType, tack),
|
||||
new ArrayList<Pair<Double, Double>>());
|
||||
}
|
||||
}
|
||||
for (double windInKnots = 0.1; windInKnots < 30; windInKnots = windInKnots + 0.1) {
|
||||
for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) {
|
||||
for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) {
|
||||
|
||||
try {
|
||||
SpeedWithBearingWithConfidence<Void> averageUpwindStarboardMovingAverage = getService()
|
||||
.getPolarDataService().getAverageSpeedWithBearing(boatClass,
|
||||
new KnotSpeedImpl(windInKnots), legType, tack, false);
|
||||
|
||||
movingAverageSpeedDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
|
||||
new Pair<Double, Double>(windInKnots, averageUpwindStarboardMovingAverage.getObject()
|
||||
.getKnots()));
|
||||
|
||||
|
||||
averageConfidenceDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
|
||||
new Pair<Double, Double>(windInKnots, averageUpwindStarboardMovingAverage
|
||||
.getConfidence()));
|
||||
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
// Do not add a point to the result
|
||||
}
|
||||
|
||||
try {
|
||||
SpeedWithBearingWithConfidence<Void> averageUpwindStarboardRegression = getService()
|
||||
.getPolarDataService().getAverageSpeedWithBearing(boatClass,
|
||||
new KnotSpeedImpl(windInKnots), legType, tack, true);
|
||||
new KnotSpeedImpl(windInKnots), legType, tack);
|
||||
|
||||
regressionSpeedDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
|
||||
new Pair<Double, Double>(windInKnots, averageUpwindStarboardRegression.getObject()
|
||||
@@ -5635,8 +5610,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
}
|
||||
}
|
||||
|
||||
PolarSheetsXYDiagramData data = new PolarSheetsXYDiagramDataImpl(movingAverageSpeedDataLists,
|
||||
regressionSpeedDataLists, averageConfidenceDataLists);
|
||||
PolarSheetsXYDiagramData data = new PolarSheetsXYDiagramDataImpl(regressionSpeedDataLists);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
+13
-1
@@ -49,10 +49,14 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
|
||||
import com.sap.sailing.polars.mining.BearingClusterGroup;
|
||||
import com.sap.sailing.polars.mining.CubicRegressionPerCourseProcessor;
|
||||
import com.sap.sailing.polars.mining.PolarDataMiner;
|
||||
import com.sap.sailing.polars.mining.SpeedRegressionPerAngleClusterProcessor;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
|
||||
public class PolarDataMinerTest {
|
||||
|
||||
@@ -74,11 +78,19 @@ public class PolarDataMinerTest {
|
||||
false, 3);
|
||||
}
|
||||
|
||||
private ClusterGroup<Bearing> createAngleClusterGroup() {
|
||||
return new BearingClusterGroup(0, 180, 5);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testGrouping() throws InterruptedException, TimeoutException, NoSuchMethodException,
|
||||
NotEnoughDataHasBeenAddedException {
|
||||
PolarDataMiner miner = new PolarDataMiner(createTestPolarSettings());
|
||||
PolarSheetGenerationSettings settings = createTestPolarSettings();
|
||||
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
|
||||
PolarDataMiner miner = new PolarDataMiner(settings,
|
||||
new CubicRegressionPerCourseProcessor(),
|
||||
new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup), angleClusterGroup);
|
||||
|
||||
BoatClass mockedBoatClass = mock(BoatClass.class);
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ Require-Bundle:
|
||||
com.sap.sse,
|
||||
com.sap.sse.shared.android,
|
||||
org.apache.commons.math;bundle-version="2.1.0",
|
||||
org.eclipse.osgi
|
||||
org.eclipse.osgi,
|
||||
com.sap.sse.replication;bundle-version="1.0.0",
|
||||
com.sap.sse.operationaltransformation;bundle-version="1.0.0"
|
||||
Import-Package:
|
||||
com.sap.sailing.util,
|
||||
com.sap.sse.common
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.sap.sailing.polars;
|
||||
|
||||
import com.sap.sailing.polars.impl.PolarDataServiceImpl;
|
||||
import com.sap.sse.replication.OperationWithResult;
|
||||
|
||||
public interface PolarDataOperation<T> extends OperationWithResult<PolarDataServiceImpl, T>{
|
||||
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import com.sap.sse.datamining.impl.data.FixClusterGroup;
|
||||
|
||||
public class SpeedClusterGroup extends FixClusterGroup<Speed> {
|
||||
|
||||
private static final long serialVersionUID = -3428022721991223921L;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.sap.sailing.polars.impl;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -9,6 +11,7 @@ import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sse.replication.Replicable;
|
||||
|
||||
public class Activator implements BundleActivator {
|
||||
|
||||
@@ -19,7 +22,11 @@ public class Activator implements BundleActivator {
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
logger.info("Registering PolarDataService");
|
||||
registrations.add(context.registerService(PolarDataService.class, new PolarDataServiceImpl(), null));
|
||||
PolarDataServiceImpl service = new PolarDataServiceImpl();
|
||||
registrations.add(context.registerService(PolarDataService.class, service, null));
|
||||
final Dictionary<String, String> replicableServiceProperties = new Hashtable<>();
|
||||
replicableServiceProperties.put(Replicable.OSGi_Service_Registry_ID_Property_Name, service.getId().toString());
|
||||
registrations.add(context.registerService(Replicable.class.getName(), service, replicableServiceProperties));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+174
-12
@@ -1,13 +1,23 @@
|
||||
package com.sap.sailing.polars.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.base.SpeedWithConfidence;
|
||||
import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl;
|
||||
@@ -22,17 +32,28 @@ import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.polars.PolarsChangedListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.PolarDataOperation;
|
||||
import com.sap.sailing.polars.aggregation.PolarFixAggregator;
|
||||
import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval;
|
||||
import com.sap.sailing.polars.data.PolarFix;
|
||||
import com.sap.sailing.polars.generation.PolarSheetGenerator;
|
||||
import com.sap.sailing.polars.mining.BearingClusterGroup;
|
||||
import com.sap.sailing.polars.mining.CubicRegressionPerCourseProcessor;
|
||||
import com.sap.sailing.polars.mining.PolarDataMiner;
|
||||
import com.sap.sailing.polars.mining.SpeedRegressionPerAngleClusterProcessor;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.replication.OperationExecutionListener;
|
||||
import com.sap.sse.replication.OperationWithResult;
|
||||
import com.sap.sse.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sse.replication.impl.OperationWithResultWithIdWrapper;
|
||||
import com.sap.sse.replication.impl.ReplicableWithObjectInputStream;
|
||||
import com.sap.sse.util.SmartFutureCache;
|
||||
|
||||
/**
|
||||
@@ -43,16 +64,48 @@ import com.sap.sse.util.SmartFutureCache;
|
||||
* @author Frederik Petersen (D054528)
|
||||
*
|
||||
*/
|
||||
public class PolarDataServiceImpl implements PolarDataService {
|
||||
public class PolarDataServiceImpl implements PolarDataService, ReplicableWithObjectInputStream<PolarDataServiceImpl, PolarDataOperation<?>>{
|
||||
|
||||
private final PolarDataMiner polarDataMiner;
|
||||
private static final Logger logger = Logger.getLogger(PolarDataServiceImpl.class.getSimpleName());
|
||||
|
||||
private PolarDataMiner polarDataMiner;
|
||||
|
||||
private final ConcurrentHashMap<OperationExecutionListener<PolarDataServiceImpl>, OperationExecutionListener<PolarDataServiceImpl>> operationExecutionListeners;
|
||||
|
||||
/**
|
||||
* The master from which this replicable is currently replicating, or <code>null</code> if this replicable is not
|
||||
* currently replicated from any master.
|
||||
*/
|
||||
private ReplicationMasterDescriptor replicatingFromMaster;
|
||||
|
||||
private final Set<OperationWithResult<PolarDataServiceImpl, ?>> operationsSentToMasterForReplication;
|
||||
|
||||
private ThreadLocal<Boolean> currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster = ThreadLocal
|
||||
.withInitial(() -> false);
|
||||
|
||||
private DomainFactory domainFactory;
|
||||
|
||||
public PolarDataServiceImpl() {
|
||||
this.polarDataMiner = new PolarDataMiner();
|
||||
PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createBackendPolarSettings();
|
||||
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
|
||||
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor();
|
||||
SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(
|
||||
angleClusterGroup);
|
||||
this.polarDataMiner = new PolarDataMiner(settings, cubicRegressionPerCourseProcessor,
|
||||
speedRegressionPerAngleClusterProcessor, angleClusterGroup);
|
||||
this.operationsSentToMasterForReplication = new HashSet<>();
|
||||
this.operationExecutionListeners = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
private ClusterGroup<Bearing> createAngleClusterGroup() {
|
||||
return new BearingClusterGroup(0, 180, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithConfidence<Void> getSpeed(BoatClass boatClass, Speed windSpeed, Bearing trueWindAngle) throws NotEnoughDataHasBeenAddedException {
|
||||
if (polarDataMiner == null) {
|
||||
throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?");
|
||||
}
|
||||
return polarDataMiner.estimateBoatSpeed(boatClass, windSpeed, trueWindAngle);
|
||||
}
|
||||
|
||||
@@ -64,9 +117,12 @@ public class PolarDataServiceImpl implements PolarDataService {
|
||||
|
||||
@Override
|
||||
public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
|
||||
LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException {
|
||||
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException {
|
||||
if (polarDataMiner == null) {
|
||||
throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?");
|
||||
}
|
||||
SpeedWithBearingWithConfidence<Void> averageSpeedAndCourseOverGround = polarDataMiner
|
||||
.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, useRegressionForSpeed);
|
||||
.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
|
||||
if (tack == Tack.PORT) {
|
||||
//Negative twa
|
||||
DegreeBearingImpl bearing = new DegreeBearingImpl(-averageSpeedAndCourseOverGround.getObject().getBearing()
|
||||
@@ -185,19 +241,16 @@ public class PolarDataServiceImpl implements PolarDataService {
|
||||
if (boatClass == null || windSpeed == null) {
|
||||
throw new IllegalArgumentException("Boatclass and windspeed cannot be null.");
|
||||
}
|
||||
SpeedWithBearingWithConfidence<Void> speed = polarDataMiner.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, true);
|
||||
if (polarDataMiner == null) {
|
||||
throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?");
|
||||
}
|
||||
SpeedWithBearingWithConfidence<Void> speed = polarDataMiner.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
|
||||
Bearing bearing = new DegreeBearingImpl(speed.getObject().getBearing().getDegrees() * 2);
|
||||
BearingWithConfidence<Void> bearingWithConfidence = new BearingWithConfidenceImpl<Void>(bearing, speed.getConfidence(),
|
||||
null);
|
||||
return bearingWithConfidence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
|
||||
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException {
|
||||
return getAverageSpeedWithBearing(boatClass, windSpeed, legType, tack, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertExistingFixes(TrackedRace trackedRace) {
|
||||
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
||||
@@ -217,4 +270,113 @@ public class PolarDataServiceImpl implements PolarDataService {
|
||||
polarDataMiner.unregisterListener(boatClass, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOperationExecutionListener(OperationExecutionListener<PolarDataServiceImpl> listener) {
|
||||
operationExecutionListeners.put(listener, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOperationExecutionListener(OperationExecutionListener<PolarDataServiceImpl> listener) {
|
||||
operationExecutionListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearReplicaState() throws MalformedURLException, IOException, InterruptedException {
|
||||
polarDataMiner = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster() {
|
||||
return currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster(boolean b) {
|
||||
currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster.set(b);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getId() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInputStream createObjectInputStreamResolvingAgainstCache(InputStream is) throws IOException {
|
||||
ObjectInputStream ois;
|
||||
if (domainFactory != null) {
|
||||
ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(is);
|
||||
} else {
|
||||
// TODO ensure that domainfactory is set here. Otherwise there can be issues with duplicate domain objects
|
||||
logger.warning("PolarDataService didn't have a domain factory attached. Replication to this service could fail.");
|
||||
ois = new ObjectInputStream(is);
|
||||
}
|
||||
return ois;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initiallyFillFromInternal(ObjectInputStream is) throws IOException, ClassNotFoundException,
|
||||
InterruptedException {
|
||||
PolarSheetGenerationSettings backendPolarSettings = (PolarSheetGenerationSettings) is.readObject();
|
||||
|
||||
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor = (CubicRegressionPerCourseProcessor) is.readObject();
|
||||
SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor = (SpeedRegressionPerAngleClusterProcessor) is.readObject();
|
||||
|
||||
polarDataMiner = new PolarDataMiner(backendPolarSettings,
|
||||
cubicRegressionPerCourseProcessor, speedRegressionPerAngleClusterProcessor,
|
||||
speedRegressionPerAngleClusterProcessor.getAngleCluster());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeForInitialReplicationInternal(ObjectOutputStream objectOutputStream) throws IOException {
|
||||
objectOutputStream.writeObject(polarDataMiner.getPolarSheetGenerationSettings());
|
||||
//objectOutputStream.writeObject(polarDataMiner.getMovingAverageProcessor());
|
||||
objectOutputStream.writeObject(polarDataMiner.getCubicRegressionPerCourseProcessor());
|
||||
objectOutputStream.writeObject(polarDataMiner.getSpeedRegressionPerAngleClusterProcessor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<OperationExecutionListener<PolarDataServiceImpl>> getOperationExecutionListeners() {
|
||||
return operationExecutionListeners.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplicationMasterDescriptor getMasterDescriptor() {
|
||||
return replicatingFromMaster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startedReplicatingFrom(ReplicationMasterDescriptor master) {
|
||||
this.replicatingFromMaster = master;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stoppedReplicatingFrom(ReplicationMasterDescriptor master) {
|
||||
this.replicatingFromMaster = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSentOperationToMaster(OperationWithResult<PolarDataServiceImpl, ?> operation) {
|
||||
return this.operationsSentToMasterForReplication.contains(operation);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addOperationSentToMasterForReplication(
|
||||
OperationWithResultWithIdWrapper<PolarDataServiceImpl, ?> operation) {
|
||||
this.operationsSentToMasterForReplication.add(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDomainFactory(DomainFactory domainFactory) {
|
||||
this.domainFactory = domainFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDomainFactory(DomainFactory domainFactory) {
|
||||
if (this.domainFactory == domainFactory) {
|
||||
this.domainFactory = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -24,8 +25,9 @@ import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImp
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class AngleAndSpeedRegression {
|
||||
public class AngleAndSpeedRegression implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 6343595388753945979L;
|
||||
private final IncrementalLeastSquares speedRegression = new IncrementalAnyOrderLeastSquaresImpl(3, false);
|
||||
private final IncrementalLeastSquares angleRegression = new IncrementalAnyOrderLeastSquaresImpl(3);
|
||||
|
||||
|
||||
+4
-1
@@ -1,7 +1,10 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class AverageAngleContainer {
|
||||
|
||||
public class AverageAngleContainer implements Serializable {
|
||||
private static final long serialVersionUID = -6370647955050312847L;
|
||||
private int dataCount = 0;
|
||||
private double angleSumDeg = 0.0;
|
||||
private double averageAngleDeg = 0.0;
|
||||
|
||||
+14
-7
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
@@ -18,6 +19,8 @@ import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
|
||||
public class BearingClusterGroup extends FixClusterGroup<Bearing>{
|
||||
|
||||
private static final long serialVersionUID = -3810975212669767738L;
|
||||
|
||||
public BearingClusterGroup(int startAngle, int endAngle, int clusterSize) {
|
||||
super("", createClusters(startAngle, endAngle, clusterSize));
|
||||
}
|
||||
@@ -35,13 +38,7 @@ public class BearingClusterGroup extends FixClusterGroup<Bearing>{
|
||||
|
||||
private static ClusterBoundary<Bearing> createBoundary(double angleInDeg, ComparisonStrategy strategy) {
|
||||
Bearing angle = new DegreeBearingImpl(angleInDeg);
|
||||
Comparator<Bearing> comparator = new Comparator<Bearing>() {
|
||||
|
||||
@Override
|
||||
public int compare(Bearing arg0, Bearing arg1) {
|
||||
return new Double(arg0.getDegrees()).compareTo(new Double(arg1.getDegrees()));
|
||||
}
|
||||
};
|
||||
Comparator<Bearing> comparator = new BearingComparator();
|
||||
return new ComparatorClusterBoundary<Bearing>(angle, strategy, comparator);
|
||||
}
|
||||
|
||||
@@ -50,5 +47,15 @@ public class BearingClusterGroup extends FixClusterGroup<Bearing>{
|
||||
return "";
|
||||
}
|
||||
|
||||
private static class BearingComparator implements Comparator<Bearing>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8166601046140275541L;
|
||||
|
||||
@Override
|
||||
public int compare(Bearing arg0, Bearing arg1) {
|
||||
return new Double(arg0.getDegrees()).compareTo(new Double(arg1.getDegrees()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
+15
-6
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@@ -22,17 +23,19 @@ import com.sap.sse.datamining.factories.GroupKeyFactory;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
|
||||
public class CubicRegressionPerCourseProcessor implements Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void> {
|
||||
public class CubicRegressionPerCourseProcessor implements
|
||||
Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3059764273262382648L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CubicRegressionPerCourseProcessor.class.getName());
|
||||
|
||||
private final Map<GroupKey, AngleAndSpeedRegression> regressions = new HashMap<>();
|
||||
|
||||
private ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
|
||||
|
||||
public CubicRegressionPerCourseProcessor(ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
/**
|
||||
* FIXME Make sure replication and listeners interact correctly
|
||||
*/
|
||||
private transient ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
|
||||
|
||||
@Override
|
||||
public boolean canProcessElements() {
|
||||
@@ -146,6 +149,10 @@ public class CubicRegressionPerCourseProcessor implements Processor<GroupedDataE
|
||||
throw new RuntimeException("Polar Data Miner failed.", failure);
|
||||
}
|
||||
|
||||
public void setListeners(ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<GroupedDataEntry<GPSFixMovingWithPolarContext>> getInputType() {
|
||||
@@ -187,4 +194,6 @@ public class CubicRegressionPerCourseProcessor implements Processor<GroupedDataE
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+2
-11
@@ -10,7 +10,6 @@ import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
|
||||
@@ -28,12 +27,11 @@ 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 MovingAveragePolarClusterKey, AngleClusterPolarClusterKey {
|
||||
public class GPSFixMovingWithPolarContext implements LegTypePolarClusterKey, AngleClusterPolarClusterKey {
|
||||
|
||||
private final GPSFixMoving fix;
|
||||
private final TrackedRace race;
|
||||
private final Competitor competitor;
|
||||
private final ClusterGroup<Speed> windSpeedClusterGroup;
|
||||
private final Set<WindSource> windSourcesToExcludeForSpeed;
|
||||
private final ClusterGroup<Bearing> angleClusterGroup;
|
||||
private final BearingWithConfidence<Void> absTrueWindAngle;
|
||||
@@ -42,11 +40,10 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
|
||||
private LegType legType;
|
||||
|
||||
public GPSFixMovingWithPolarContext(GPSFixMoving fix, TrackedRace race, Competitor competitor,
|
||||
ClusterGroup<Speed> windSpeedClusterGroup, ClusterGroup<Bearing> angleClusterGroup) {
|
||||
ClusterGroup<Bearing> angleClusterGroup) {
|
||||
this.fix = fix;
|
||||
this.race = race;
|
||||
this.competitor = competitor;
|
||||
this.windSpeedClusterGroup = windSpeedClusterGroup;
|
||||
this.angleClusterGroup = angleClusterGroup;
|
||||
this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed();
|
||||
this.absTrueWindAngle = computeTrueWindAngleAbsolute();
|
||||
@@ -89,12 +86,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cluster<Speed> getWindSpeedCluster() {
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = getWind();
|
||||
return windWithConfidence == null ? null : windSpeedClusterGroup.getClusterFor(windWithConfidence.getObject());
|
||||
}
|
||||
|
||||
public WindWithConfidence<Pair<Position, TimePoint>> getWind() {
|
||||
return wind;
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.util.Set;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
@@ -8,11 +8,11 @@ import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
|
||||
public interface MovingAverageProcessor extends Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>{
|
||||
public interface MovingAverageProcessor extends Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>, Serializable {
|
||||
SpeedWithBearingWithConfidence<Void> getAverageSpeedAndCourseOverGround(BoatClass boatClass,
|
||||
Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
Set<BoatClass> getAvailableBoatClasses();
|
||||
ClusterGroup<Speed> getSpeedCluster();
|
||||
}
|
||||
+7
-11
@@ -1,9 +1,7 @@
|
||||
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;
|
||||
@@ -33,6 +31,8 @@ import com.sap.sse.datamining.shared.GroupKey;
|
||||
|
||||
public class MovingAverageProcessorImpl implements MovingAverageProcessor {
|
||||
|
||||
private static final long serialVersionUID = 9016357546663534562L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MovingAverageProcessorImpl.class.getName());
|
||||
|
||||
private final Map<GroupKey, MovingAverageBoatSpeedEstimator> boatSpeedEstimators = new HashMap<>();
|
||||
@@ -41,10 +41,6 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor {
|
||||
|
||||
private final ClusterGroup<Speed> speedClusterGroup;
|
||||
|
||||
private final Set<BoatClass> availableBoatClasses = new HashSet<>();
|
||||
|
||||
|
||||
|
||||
public MovingAverageProcessorImpl(ClusterGroup<Speed> speedClusterGroup) {
|
||||
this.speedClusterGroup = speedClusterGroup;
|
||||
}
|
||||
@@ -79,7 +75,6 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor {
|
||||
BearingWithConfidence<Void> angleToTheWind = fix.getAbsoluteAngleToTheWind();
|
||||
WindWithConfidence<Pair<Position, TimePoint>> windSpeed = fix.getWind();
|
||||
SpeedWithBearingWithConfidence<TimePoint> boatSpeedWithConfidence = fix.getBoatSpeed();
|
||||
availableBoatClasses.add(element.getDataEntry().getBoatClass());
|
||||
WindWithConfidence<Pair<Position, TimePoint>> windWithConfidenceForSpeed = windSpeed;
|
||||
double confidenceForWindSpeed = windWithConfidenceForSpeed.getConfidence();
|
||||
double confidenceForWindBearing = angleToTheWind.getConfidence();
|
||||
@@ -158,10 +153,6 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor {
|
||||
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
|
||||
@@ -218,4 +209,9 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor {
|
||||
return compoundKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterGroup<Speed> getSpeedCluster() {
|
||||
return speedClusterGroup;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,10 +36,8 @@ import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
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.WindSpeedSteppingWithMaxDistance;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarsChangedListener;
|
||||
@@ -61,7 +59,6 @@ public class PolarDataMiner {
|
||||
private static final int EXECUTOR_QUEUE_SIZE = 100;
|
||||
private static final int THREAD_POOL_SIZE = Math.max((int) (Runtime.getRuntime().availableProcessors() * (3.0/4.0)), 3);
|
||||
private final ThreadPoolExecutor executor = createExecutor();
|
||||
private final PolarSheetGenerationSettings backendPolarSheetGenerationSettings;
|
||||
private final Map<TrackedRace, Set<GPSFixMovingWithOriginInfo>> fixesForRacesWhichAreStillLoading = new HashMap<>();
|
||||
|
||||
private final Queue<GPSFixMovingWithOriginInfo> fixQueue = new ConcurrentLinkedQueue<GPSFixMovingWithOriginInfo>();
|
||||
@@ -70,6 +67,19 @@ public class PolarDataMiner {
|
||||
|
||||
private final ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners = new ConcurrentHashMap<>();
|
||||
|
||||
private ParallelFilteringProcessor<GPSFixMovingWithOriginInfo> preFilteringProcessor;
|
||||
|
||||
private final PolarSheetGenerationSettings backendPolarSheetGenerationSettings;
|
||||
|
||||
/**
|
||||
* This processor uses two cubic regressions angle to the true wind over windspeed and boatspeed over windspeed for each
|
||||
* course (legtype tack combination)
|
||||
*/
|
||||
private final CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor;
|
||||
|
||||
private final SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor;
|
||||
private final ClusterGroup<Bearing> angleClusterGroup;
|
||||
|
||||
private ThreadPoolExecutor createExecutor() {
|
||||
return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(EXECUTOR_QUEUE_SIZE), new RejectedExecutionHandler() {
|
||||
@@ -92,28 +102,16 @@ public class PolarDataMiner {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This processor keeps track of the moving average of the speed values and the average angle for each course (legtype tack combination)
|
||||
*/
|
||||
private MovingAverageProcessor movingAverageProcessor;
|
||||
|
||||
/**
|
||||
* This processor uses two cubic regressions angle to the true wind over windspeed and boatspeed over windspeed for each
|
||||
* course (legtype tack combination)
|
||||
*/
|
||||
private CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor;
|
||||
|
||||
private SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor;
|
||||
private ParallelFilteringProcessor<GPSFixMovingWithOriginInfo> preFilteringProcessor;
|
||||
|
||||
public PolarDataMiner() {
|
||||
this(PolarSheetGenerationSettingsImpl.createBackendPolarSettings());
|
||||
}
|
||||
|
||||
public PolarDataMiner(PolarSheetGenerationSettings backendPolarSettings) {
|
||||
public PolarDataMiner(PolarSheetGenerationSettings backendPolarSettings,
|
||||
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor,
|
||||
SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor,
|
||||
ClusterGroup<Bearing> angleClusterGroup) {
|
||||
cubicRegressionPerCourseProcessor.setListeners(listeners);
|
||||
speedRegressionPerAngleClusterProcessor.setListeners(listeners);
|
||||
backendPolarSheetGenerationSettings = backendPolarSettings;
|
||||
this.cubicRegressionPerCourseProcessor = cubicRegressionPerCourseProcessor;
|
||||
this.speedRegressionPerAngleClusterProcessor = speedRegressionPerAngleClusterProcessor;
|
||||
this.angleClusterGroup = angleClusterGroup;
|
||||
try {
|
||||
setUpWorkflow();
|
||||
} catch (ClassCastException | NoSuchMethodException | SecurityException e) {
|
||||
@@ -124,23 +122,6 @@ public class PolarDataMiner {
|
||||
|
||||
private void setUpWorkflow() throws ClassCastException, NoSuchMethodException,
|
||||
SecurityException {
|
||||
WindSpeedSteppingWithMaxDistance stepping = backendPolarSheetGenerationSettings.getWindSpeedStepping();
|
||||
final ClusterGroup<Speed> speedClusterGroup = SpeedClusterGroupFromWindSteppingCreator
|
||||
.createSpeedClusterGroupFrom(stepping);
|
||||
movingAverageProcessor = new MovingAverageProcessorImpl(speedClusterGroup);
|
||||
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> movingAverageGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
|
||||
movingAverageGrouperResultReceivers.add(movingAverageProcessor);
|
||||
|
||||
Collection<ParameterizedFunction<?>> parameterizedDimensions = new ArrayList<>();
|
||||
for (Function<?> function : PolarDataDimensionCollectionFactory.getMovingAverageClusterKeyDimensions()) {
|
||||
parameterizedDimensions.add(new SimpleParameterizedFunction<>(function, ParameterProvider.NULL));
|
||||
}
|
||||
|
||||
Processor<GPSFixMovingWithPolarContext, GroupedDataEntry<GPSFixMovingWithPolarContext>> movingAverageGroupingProcessor = new ParallelMultiDimensionsValueNestingGroupingProcessor<GPSFixMovingWithPolarContext>(
|
||||
GPSFixMovingWithPolarContext.class, executor, movingAverageGrouperResultReceivers, parameterizedDimensions);
|
||||
|
||||
|
||||
cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor(listeners);
|
||||
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
|
||||
regressionPerCourseGrouperResultReceivers.add(cubicRegressionPerCourseProcessor);
|
||||
|
||||
@@ -151,8 +132,6 @@ public class PolarDataMiner {
|
||||
Processor<GPSFixMovingWithPolarContext, GroupedDataEntry<GPSFixMovingWithPolarContext>> cubicRegressionPerCourseGroupingProcessor = new ParallelMultiDimensionsValueNestingGroupingProcessor<GPSFixMovingWithPolarContext>(
|
||||
GPSFixMovingWithPolarContext.class, executor, regressionPerCourseGrouperResultReceivers, parameterizedDimensionsForCubicRegression);
|
||||
|
||||
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
|
||||
speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup, listeners);
|
||||
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerAngleClusterGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
|
||||
regressionPerAngleClusterGrouperResultReceivers.add(speedRegressionPerAngleClusterProcessor);
|
||||
|
||||
@@ -166,7 +145,6 @@ public class PolarDataMiner {
|
||||
|
||||
|
||||
Collection<Processor<GPSFixMovingWithPolarContext, ?>> filteringResultReceivers = new ArrayList<>();
|
||||
filteringResultReceivers.add(movingAverageGroupingProcessor);
|
||||
filteringResultReceivers.add(cubicRegressionPerCourseGroupingProcessor);
|
||||
filteringResultReceivers.add(regressionPerAngleClusterGroupingProcessor);
|
||||
|
||||
@@ -185,7 +163,7 @@ public class PolarDataMiner {
|
||||
protected GPSFixMovingWithPolarContext enrich(GPSFixMovingWithOriginInfo element) {
|
||||
GPSFixMovingWithPolarContext result = null;
|
||||
result = new GPSFixMovingWithPolarContext(element.getFix(), element.getTrackedRace(),
|
||||
element.getCompetitor(), speedClusterGroup, angleClusterGroup);
|
||||
element.getCompetitor(), angleClusterGroup);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -216,10 +194,6 @@ public class PolarDataMiner {
|
||||
}
|
||||
|
||||
|
||||
private ClusterGroup<Bearing> createAngleClusterGroup() {
|
||||
return new BearingClusterGroup(0, 180, 5);
|
||||
}
|
||||
|
||||
public void addFix(GPSFixMoving fix, Competitor competitor, TrackedRace trackedRace) {
|
||||
GPSFixMovingWithOriginInfo fixWithOriginInfo = new GPSFixMovingWithOriginInfo(fix, trackedRace, competitor);
|
||||
if (trackedRace.getStatus().getStatus() == TrackedRaceStatusEnum.LOADING) {
|
||||
@@ -387,7 +361,7 @@ public class PolarDataMiner {
|
||||
}
|
||||
|
||||
public Set<BoatClass> getAvailableBoatClasses() {
|
||||
return movingAverageProcessor.getAvailableBoatClasses();
|
||||
return speedRegressionPerAngleClusterProcessor.getAvailableBoatClasses();
|
||||
}
|
||||
|
||||
public int[] getDataCountsForWindSpeed(BoatClass boatClass, Speed windSpeed, int startAngleInclusive, int endAngleExclusive) {
|
||||
@@ -403,13 +377,9 @@ public class PolarDataMiner {
|
||||
}
|
||||
|
||||
public SpeedWithBearingWithConfidence<Void> getAverageSpeedAndCourseOverGround(BoatClass boatClass,
|
||||
Speed windSpeed, LegType legType, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException {
|
||||
Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException {
|
||||
SpeedWithBearingWithConfidence<Void> averageSpeedAndCourseOverGround = null;
|
||||
if (useRegressionForSpeed) {
|
||||
averageSpeedAndCourseOverGround = cubicRegressionPerCourseProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
|
||||
} else {
|
||||
averageSpeedAndCourseOverGround = movingAverageProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
|
||||
}
|
||||
return averageSpeedAndCourseOverGround;
|
||||
}
|
||||
|
||||
@@ -458,4 +428,16 @@ public class PolarDataMiner {
|
||||
listenersForBoatClass.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public CubicRegressionPerCourseProcessor getCubicRegressionPerCourseProcessor() {
|
||||
return cubicRegressionPerCourseProcessor;
|
||||
}
|
||||
|
||||
public SpeedRegressionPerAngleClusterProcessor getSpeedRegressionPerAngleClusterProcessor() {
|
||||
return speedRegressionPerAngleClusterProcessor;
|
||||
}
|
||||
|
||||
public PolarSheetGenerationSettings getPolarSheetGenerationSettings() {
|
||||
return backendPolarSheetGenerationSettings;
|
||||
}
|
||||
}
|
||||
+26
-4
@@ -1,6 +1,8 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -27,7 +29,10 @@ import com.sap.sse.datamining.factories.GroupKeyFactory;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
import com.sap.sse.datamining.shared.GroupKey;
|
||||
|
||||
public class SpeedRegressionPerAngleClusterProcessor implements Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>{
|
||||
public class SpeedRegressionPerAngleClusterProcessor implements
|
||||
Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3279917556091599077L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CubicRegressionPerCourseProcessor.class.getName());
|
||||
|
||||
@@ -37,11 +42,15 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
|
||||
|
||||
private final ClusterGroup<Bearing> angleClusterGroup;
|
||||
|
||||
private final ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
|
||||
/**
|
||||
* FIXME make sure listeners and replication interact correctly
|
||||
*/
|
||||
private transient ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
|
||||
|
||||
public SpeedRegressionPerAngleClusterProcessor(ClusterGroup<Bearing> angleClusterGroup, ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
|
||||
private final Set<BoatClass> availableBoatClasses = new HashSet<BoatClass>();
|
||||
|
||||
public SpeedRegressionPerAngleClusterProcessor(ClusterGroup<Bearing> angleClusterGroup) {
|
||||
this.angleClusterGroup = angleClusterGroup;
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,6 +79,7 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
|
||||
}
|
||||
GPSFixMovingWithPolarContext fix = element.getDataEntry();
|
||||
regression.addData(fix.getWind().getObject().getKnots(), fix.getBoatSpeed().getObject().getKnots());
|
||||
availableBoatClasses.add(boatClass);
|
||||
Set<PolarsChangedListener> listenersForBoatClass = listeners.get(fix.getBoatClass());
|
||||
if (listenersForBoatClass != null) {
|
||||
for (PolarsChangedListener listener : listenersForBoatClass) {
|
||||
@@ -155,6 +165,14 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
|
||||
return polynomialFunction;
|
||||
}
|
||||
|
||||
public void setListeners(ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
Set<BoatClass> getAvailableBoatClasses() {
|
||||
return availableBoatClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<GroupedDataEntry<GPSFixMovingWithPolarContext>> getInputType() {
|
||||
// TODO Auto-generated method stub
|
||||
@@ -195,4 +213,8 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
|
||||
return null;
|
||||
}
|
||||
|
||||
public ClusterGroup<Bearing> getAngleCluster() {
|
||||
return angleClusterGroup;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.sap.sailing.polars.mining;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.WindSpeedStepping;
|
||||
|
||||
public class WindSpeedLevel {
|
||||
public class WindSpeedLevel implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -4498750034316806342L;
|
||||
private final int level;
|
||||
private final WindSpeedStepping stepping;
|
||||
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.polars.regression;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
|
||||
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
@@ -10,7 +12,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
* @author Frederik Petersen (D054528)
|
||||
*
|
||||
*/
|
||||
public interface IncrementalLeastSquares {
|
||||
public interface IncrementalLeastSquares extends Serializable {
|
||||
|
||||
/**
|
||||
* Adds data to the least squares regression. This only updates the internal matrix and vector and will not trigger the
|
||||
|
||||
+14
-2
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.polars.regression.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@@ -29,6 +30,8 @@ import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
*/
|
||||
public class IncrementalAnyOrderLeastSquaresImpl implements IncrementalLeastSquares {
|
||||
|
||||
private static final long serialVersionUID = -5282614133220702724L;
|
||||
|
||||
private class NaNCheckerVisitor implements RealMatrixPreservingVisitor {
|
||||
|
||||
private boolean hasNaNEntry = false;
|
||||
@@ -64,10 +67,10 @@ public class IncrementalAnyOrderLeastSquaresImpl implements IncrementalLeastSqua
|
||||
|
||||
private AtomicBoolean functionNeedsUpdate = new AtomicBoolean(true);
|
||||
|
||||
private final NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresLock",
|
||||
private transient NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresLock",
|
||||
false);
|
||||
|
||||
private final NamedReentrantReadWriteLock cacheLock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresCacheLock",
|
||||
private transient NamedReentrantReadWriteLock cacheLock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresCacheLock",
|
||||
true);
|
||||
|
||||
private PolynomialFunction cachedFunction;
|
||||
@@ -297,6 +300,15 @@ public class IncrementalAnyOrderLeastSquaresImpl implements IncrementalLeastSqua
|
||||
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
lock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresLock",
|
||||
false);
|
||||
cacheLock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresCacheLock",
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNumberOfAddedPoints() {
|
||||
return numberOfPointsAdded.get();
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ public class PolarResource extends AbstractSailingServerResource {
|
||||
try {
|
||||
PolarDataService service = getService().getPolarDataService();
|
||||
SpeedWithBearingWithConfidence<Void> speedWithBearing = service.getAverageSpeedWithBearing(boatClass,
|
||||
windSpeed, legType, tack, true);
|
||||
windSpeed, legType, tack);
|
||||
String resultString = "Speed: " + speedWithBearing.getObject().getKnots() + "kn; Angle: "
|
||||
+ speedWithBearing.getObject().getBearing().getDegrees() + "°; Confidence: "
|
||||
+ speedWithBearing.getConfidence();
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
<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 -Dmongo.dbName=replica -Dreplicate.on.start=com.sap.sailing.server.impl.RacingEventServiceImpl,com.sap.sse.security.impl.SecurityServiceImpl,com.sap.sse.filestorage.impl.FileStorageManagementServiceImpl,com.sap.sse.mail.impl.MailServiceImpl -Dreplicate.master.queue.host=127.0.0.1 -Dreplicate.master.queue.port=5672 -Dreplicate.master.servlet.port=8888 -Dreplicate.master.servlet.host=127.0.0.1 -Dreplicate.master.exchange.name=sapsailinganalytics"/>
|
||||
<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 -Dmongo.dbName=replica -Dreplicate.on.start=com.sap.sailing.server.impl.RacingEventServiceImpl,com.sap.sse.security.impl.SecurityServiceImpl,com.sap.sse.filestorage.impl.FileStorageManagementServiceImpl,com.sap.sse.mail.impl.MailServiceImpl,com.sap.sailing.polars.impl.PolarDataServiceImpl -Dreplicate.master.queue.host=127.0.0.1 -Dreplicate.master.queue.port=5672 -Dreplicate.master.servlet.port=8888 -Dreplicate.master.servlet.host=127.0.0.1 -Dreplicate.master.exchange.name=sapsailinganalytics"/>
|
||||
<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"/>
|
||||
|
||||
+2
@@ -3241,6 +3241,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
public void setPolarDataService(PolarDataService service) {
|
||||
if (this.polarDataService == null) {
|
||||
polarDataService = service;
|
||||
polarDataService.registerDomainFactory(baseDomainFactory);
|
||||
setPolarDataServiceOnAllTrackedRaces(service);
|
||||
}
|
||||
}
|
||||
@@ -3266,6 +3267,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
|
||||
public void unsetPolarDataService(PolarDataService service) {
|
||||
if (polarDataService == service) {
|
||||
polarDataService.unregisterDomainFactory(baseDomainFactory);
|
||||
polarDataService = null;
|
||||
setPolarDataService(null);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,8 @@ public class PathImpl implements Path, Serializable {
|
||||
|
||||
if ((this.pathPoints.get(idx).getTimePoint().asMillis() >= nextTimePoint.asMillis())||(idx == this.pathPoints.size()-1)) {
|
||||
|
||||
if (idx == this.pathPoints.size()-1) {
|
||||
// for the last step, next-time-point needs to be aligned to the time-range of the course
|
||||
if (nextTimePoint.after(endTime)) {
|
||||
nextTimePoint = endTime;
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -57,9 +57,9 @@ public class PolarDiagramGPS extends PolarDiagramBase {
|
||||
for (int i = 0; i < windSpeeds.size(); i++) {
|
||||
try {
|
||||
beatPort = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), LegType.UPWIND,
|
||||
Tack.PORT, true).getObject();
|
||||
Tack.PORT).getObject();
|
||||
beatStar = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), LegType.UPWIND,
|
||||
Tack.STARBOARD, true).getObject();
|
||||
Tack.STARBOARD).getObject();
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
beatPort = null;
|
||||
beatStar = null;
|
||||
@@ -86,9 +86,9 @@ public class PolarDiagramGPS extends PolarDiagramBase {
|
||||
for (int i = 0; i < windSpeeds.size(); i++) {
|
||||
try {
|
||||
jibePort = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i),
|
||||
LegType.DOWNWIND, Tack.PORT, true).getObject();
|
||||
LegType.DOWNWIND, Tack.PORT).getObject();
|
||||
jibeStar = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i),
|
||||
LegType.DOWNWIND, Tack.STARBOARD, true).getObject();
|
||||
LegType.DOWNWIND, Tack.STARBOARD).getObject();
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
jibePort = null;
|
||||
jibeStar = null;
|
||||
|
||||
+4
-4
@@ -146,13 +146,13 @@ public class PolarDiagramGPSDirect implements PolarDiagram, Serializable {
|
||||
try {
|
||||
if (beatPort == null) {
|
||||
SpeedWithBearing beatPortRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
|
||||
LegType.UPWIND, Tack.PORT, true).getObject();
|
||||
LegType.UPWIND, Tack.PORT).getObject();
|
||||
beatPort = new KnotSpeedWithBearingImpl(beatPortRelative.getKnots(), this.wind.getBearing().reverse()
|
||||
.add(beatPortRelative.getBearing()));
|
||||
}
|
||||
if (beatStar == null) {
|
||||
SpeedWithBearing beatStarRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
|
||||
LegType.UPWIND, Tack.STARBOARD, true).getObject();
|
||||
LegType.UPWIND, Tack.STARBOARD).getObject();
|
||||
beatStar = new KnotSpeedWithBearingImpl(beatStarRelative.getKnots(), this.wind.getBearing().reverse()
|
||||
.add(beatStarRelative.getBearing()));
|
||||
}
|
||||
@@ -175,13 +175,13 @@ public class PolarDiagramGPSDirect implements PolarDiagram, Serializable {
|
||||
try {
|
||||
if (jibePort == null) {
|
||||
SpeedWithBearing jibePortRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
|
||||
LegType.DOWNWIND, Tack.PORT, true).getObject();
|
||||
LegType.DOWNWIND, Tack.PORT).getObject();
|
||||
jibePort = new KnotSpeedWithBearingImpl(jibePortRelative.getKnots(), this.wind.getBearing().reverse()
|
||||
.add(jibePortRelative.getBearing()));
|
||||
}
|
||||
if (jibeStar == null) {
|
||||
SpeedWithBearing jibeStarRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
|
||||
LegType.DOWNWIND, Tack.STARBOARD, true).getObject();
|
||||
LegType.DOWNWIND, Tack.STARBOARD).getObject();
|
||||
jibeStar = new KnotSpeedWithBearingImpl(jibeStarRelative.getKnots(), this.wind.getBearing().reverse()
|
||||
.add(jibeStarRelative.getBearing()));
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,5 +1,7 @@
|
||||
package com.sap.sse.datamining.test.util.components;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sse.datamining.shared.annotations.Dimension;
|
||||
|
||||
/*
|
||||
@@ -7,8 +9,9 @@ import com.sap.sse.datamining.shared.annotations.Dimension;
|
||||
* The tests will fail, because they are reflected via constant strings.
|
||||
*/
|
||||
|
||||
public class Number {
|
||||
public class Number implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int value;
|
||||
|
||||
public Number(int value) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.sap.sse.datamining.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
@@ -16,7 +17,7 @@ import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
* @see ClusterBoundary
|
||||
* @see ClusterGroup
|
||||
*/
|
||||
public interface Cluster<ElementType> {
|
||||
public interface Cluster<ElementType> extends Serializable {
|
||||
|
||||
public String getAsLocalizedString(Locale locale, ResourceBundleStringMessages stringMessages);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.sap.sse.datamining.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sse.datamining.impl.data.ComparisonStrategy;
|
||||
|
||||
/**
|
||||
@@ -11,7 +13,7 @@ import com.sap.sse.datamining.impl.data.ComparisonStrategy;
|
||||
*
|
||||
* @see Cluster
|
||||
*/
|
||||
public interface ClusterBoundary<ElementType> {
|
||||
public interface ClusterBoundary<ElementType> extends Serializable {
|
||||
|
||||
public boolean contains(ElementType value);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.sap.sse.datamining.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
@@ -14,7 +15,7 @@ import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
*
|
||||
* @see Cluster
|
||||
*/
|
||||
public interface ClusterGroup<ElementType> {
|
||||
public interface ClusterGroup<ElementType extends Serializable> extends Serializable {
|
||||
|
||||
public String getLocalizedName(Locale locale, ResourceBundleStringMessages stringMessages);
|
||||
|
||||
|
||||
+2
-1
@@ -1,11 +1,12 @@
|
||||
package com.sap.sse.datamining.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ClusterGroupRepository {
|
||||
|
||||
public void add(ClusterGroup<?> clusterGroup);
|
||||
|
||||
public <DataType> Collection<ClusterGroup<DataType>> getClusterGroupsFor(Class<DataType> type);
|
||||
public <DataType extends Serializable> Collection<ClusterGroup<DataType>> getClusterGroupsFor(Class<DataType> type);
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
|
||||
public abstract class AbstractCluster<ElementType> implements Cluster<ElementType> {
|
||||
|
||||
private static final long serialVersionUID = 1606840566021644768L;
|
||||
private final String messageKey;
|
||||
private Collection<ClusterBoundary<ElementType>> boundaries;
|
||||
|
||||
|
||||
+4
-1
@@ -1,9 +1,12 @@
|
||||
package com.sap.sse.datamining.impl.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sse.datamining.data.ClusterBoundary;
|
||||
|
||||
public abstract class AbstractClusterBoundary<ElementType> implements ClusterBoundary<ElementType> {
|
||||
public abstract class AbstractClusterBoundary<ElementType extends Serializable> implements ClusterBoundary<ElementType> {
|
||||
|
||||
private static final long serialVersionUID = 513488430319010656L;
|
||||
private final ElementType boundaryValue;
|
||||
private final ComparisonStrategy strategy;
|
||||
|
||||
|
||||
+2
@@ -8,6 +8,8 @@ import com.sap.sse.datamining.data.ClusterBoundary;
|
||||
|
||||
public class ClusterWithLowerAndUpperBoundaries<ElementType> extends AbstractCluster<ElementType> {
|
||||
|
||||
private static final long serialVersionUID = -845964568416163995L;
|
||||
|
||||
/**
|
||||
* A {@link Cluster} with a lower and an upper boundary. This <code>Cluster</code> contains
|
||||
* all elements, that are contained by the given <code>lowerBound</code> <b>and</b> the given
|
||||
|
||||
+1
@@ -7,6 +7,7 @@ import com.sap.sse.datamining.data.ClusterBoundary;
|
||||
|
||||
public class ClusterWithSingleBoundary<ElementType> extends AbstractCluster<ElementType> {
|
||||
|
||||
private static final long serialVersionUID = -3188802475809553490L;
|
||||
private static final char INFINITE = '\u221e';
|
||||
|
||||
/**
|
||||
|
||||
+5
-1
@@ -1,6 +1,10 @@
|
||||
package com.sap.sse.datamining.impl.data;
|
||||
|
||||
public class ComparableClusterBoundary<ElementType extends Comparable<ElementType>> extends AbstractClusterBoundary<ElementType> {
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ComparableClusterBoundary<ElementType extends Comparable<ElementType> & Serializable> extends AbstractClusterBoundary<ElementType> {
|
||||
|
||||
private static final long serialVersionUID = -930603995272128901L;
|
||||
|
||||
public ComparableClusterBoundary(ElementType boundaryValue, ComparisonStrategy strategy) {
|
||||
super(boundaryValue, strategy);
|
||||
|
||||
+3
-1
@@ -1,9 +1,11 @@
|
||||
package com.sap.sse.datamining.impl.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class ComparatorClusterBoundary<ElementType> extends AbstractClusterBoundary<ElementType> {
|
||||
public class ComparatorClusterBoundary<ElementType extends Serializable> extends AbstractClusterBoundary<ElementType> {
|
||||
|
||||
private static final long serialVersionUID = -8177984229875233720L;
|
||||
private final Comparator<? super ElementType> comparator;
|
||||
|
||||
public ComparatorClusterBoundary(ElementType boundaryValue, ComparisonStrategy strategy,
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package com.sap.sse.datamining.impl.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
@@ -24,7 +25,7 @@ public class CompoundClusterGroupRepository implements ClusterGroupRepository {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Collection<ClusterGroup<T>> getClusterGroupsFor(Class<T> type) {
|
||||
public <T extends Serializable> Collection<ClusterGroup<T>> getClusterGroupsFor(Class<T> type) {
|
||||
Collection<ClusterGroup<T>> allClusterGroups = new HashSet<>();
|
||||
for (ClusterGroupRepository clusterGroupRepository : repositories) {
|
||||
allClusterGroups.addAll(clusterGroupRepository.getClusterGroupsFor(type));
|
||||
|
||||
+5
-2
@@ -1,17 +1,20 @@
|
||||
package com.sap.sse.datamining.impl.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sse.datamining.data.Cluster;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
|
||||
public class FixClusterGroup<ElementType> implements ClusterGroup<ElementType> {
|
||||
public class FixClusterGroup<ElementType extends Serializable> implements ClusterGroup<ElementType> {
|
||||
|
||||
private static final long serialVersionUID = 2632796094234887943L;
|
||||
private final String messageKey;
|
||||
private final Collection<Cluster<ElementType>> clusters;
|
||||
private final Set<Cluster<ElementType>> clusters;
|
||||
|
||||
public FixClusterGroup(String messageKey, Collection<Cluster<ElementType>> clusters) {
|
||||
this.messageKey = messageKey;
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package com.sap.sse.datamining.impl.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -30,7 +31,7 @@ public class SimpleClusterGroupRepository implements ClusterGroupRepository {
|
||||
|
||||
@SuppressWarnings("unchecked") // Necessary because you can't use instanceof with generics
|
||||
@Override
|
||||
public <T> Collection<ClusterGroup<T>> getClusterGroupsFor(Class<T> type) {
|
||||
public <T extends Serializable> Collection<ClusterGroup<T>> getClusterGroupsFor(Class<T> type) {
|
||||
Collection<ClusterGroup<T>> specificClusterGroups = new HashSet<>();
|
||||
if (clusterGroupsMappedByType.containsKey(type)) {
|
||||
for (ClusterGroup<?> clusterGroup : clusterGroupsMappedByType.get(type)) {
|
||||
|
||||
+4
@@ -2,6 +2,7 @@ package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo;
|
||||
|
||||
import android.app.FragmentTransaction;
|
||||
import android.support.annotation.IdRes;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment;
|
||||
|
||||
@@ -21,6 +22,9 @@ public class BaseFragment extends RaceFragment {
|
||||
} else {
|
||||
fragment.getArguments().putAll(getRecentArguments());
|
||||
}
|
||||
if (getArguments() != null) {
|
||||
fragment.getArguments().putAll(getArguments());
|
||||
}
|
||||
FragmentTransaction transaction = getFragmentManager().beginTransaction();
|
||||
transaction.replace(viewId, fragment).commit();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user