mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-08 21:30:57 +00:00
Merge branch 'master' into ubilabs--tracking_app--develop
This commit is contained in:
commit
ff1b0c6f87
136 files changed
+5699
-1564
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.datamining.data;
|
||||
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
|
||||
public interface HasLeaderboardContext {
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.datamining.data;
|
||||
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
|
||||
public interface HasLeaderboardGroupContext {
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
|
||||
public class LeaderboardGroupWithContext implements HasLeaderboardGroupContext {
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
|
||||
public class LeaderboardWithContext implements HasLeaderboardContext {
|
||||
|
||||
|
||||
+1
-1
@@ -20,11 +20,11 @@ import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeed;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
public interface LegIdentifier extends RegattaAndRaceIdentifier {
|
||||
RaceIdentifier getRaceIdentifier();
|
||||
String getLegName();
|
||||
int getLegNumber();
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
public class LegIdentifierImpl extends RegattaNameAndRaceName implements LegIdentifier {
|
||||
private static final long serialVersionUID = 3599904513673776450L;
|
||||
private RaceIdentifier raceIdentifier = null;
|
||||
private String legName;
|
||||
|
||||
LegIdentifierImpl() {}
|
||||
|
||||
public LegIdentifierImpl(RegattaAndRaceIdentifier raceIdentifier, String legName) {
|
||||
super(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName());
|
||||
this.raceIdentifier = raceIdentifier;
|
||||
this.legName = legName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceIdentifier getRaceIdentifier() {
|
||||
return this.raceIdentifier;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getLegName() {
|
||||
return legName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLegNumber() {
|
||||
return Integer.parseInt(legName)-1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getRegattaName() + "/" + getRaceName() + "/" + getLegName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((legName == null) ? 0 : legName.hashCode());
|
||||
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;
|
||||
LegIdentifierImpl other = (LegIdentifierImpl) obj;
|
||||
if (legName == null) {
|
||||
if (other.legName != null)
|
||||
return false;
|
||||
} else if (!legName.equals(other.legName))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -149,7 +149,9 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
|
||||
Wind combinedWindDirection = combinedTrack.getAveragedWind(/* position */ null, now);
|
||||
// The course layout makes a wind estimation around 7deg. The confidence of the cluster based wind estimation is a lot
|
||||
// higher that that of the course layout wind (currently at approximately 10E-13), we will end up quite near 180 deg.
|
||||
assertEquals(180.0, combinedWindDirection.getBearing().getDegrees(), 0.2);
|
||||
// Update 04/24/15: Since polar data service is not available here, the confidence will not be as good as it once was.
|
||||
// So we have quite a big delta in the assert
|
||||
assertEquals(180.0, combinedWindDirection.getBearing().getDegrees(), 0.9);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+5
@@ -40,6 +40,7 @@ import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
|
||||
@@ -904,4 +905,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPolarDataService(PolarDataService polarDataService) {
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -29,6 +29,7 @@ import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
@@ -591,12 +592,12 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
public GPSFixTrack<Mark, GPSFix> getTrack(Mark mark) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getGateStartGolfDownTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isUsingMarkPassingCalculator() {
|
||||
// TODO Auto-generated method stub
|
||||
@@ -608,5 +609,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setPolarDataService(PolarDataService polarDataService) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ Export-Package: com.sap.sailing.domain.base,
|
||||
com.sap.sailing.domain.markpassingcalculation.impl,
|
||||
com.sap.sailing.domain.markpassingcalculation.splining,
|
||||
com.sap.sailing.domain.masterdataimport,
|
||||
com.sap.sailing.domain.polars,
|
||||
com.sap.sailing.domain.racelog,
|
||||
com.sap.sailing.domain.racelog.impl,
|
||||
com.sap.sailing.domain.racelog.tracking,
|
||||
@@ -38,4 +39,5 @@ Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sse.datamining.shared,
|
||||
com.sap.sse.common,
|
||||
com.sap.sse,
|
||||
com.sap.sse.shared.android
|
||||
com.sap.sse.shared.android,
|
||||
org.apache.commons.math
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.polars;
|
||||
package com.sap.sailing.domain.polars;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.polars.regression;
|
||||
package com.sap.sailing.domain.polars;
|
||||
|
||||
|
||||
public class NotEnoughDataHasBeenAddedException extends Exception {
|
||||
Executable → Regular
+20
-3
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.polars;
|
||||
package com.sap.sailing.domain.polars;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -17,10 +17,9 @@ 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.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.mining.MovingAverageProcessor;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
/**
|
||||
@@ -206,7 +205,25 @@ public interface PolarDataService {
|
||||
*/
|
||||
PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, double trueWindAngle) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
/**
|
||||
* For Upwind and Downwind returns the typical angle needed for a maneuver.
|
||||
*
|
||||
* @param boatClass
|
||||
* @param legType needs to be Upwind or Downwind
|
||||
* @param windSpeed Since the maneuver angle is windSpeed depended, supply it here
|
||||
* @return angle with confidence as supplied by polars. Angle is always >= 0
|
||||
* @throws NotEnoughDataHasBeenAddedException
|
||||
*/
|
||||
BearingWithConfidence<Void> getManeuverAngle(BoatClass boatClass, LegType legType, Speed windSpeed) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
void raceFinishedLoading(TrackedRace race);
|
||||
|
||||
/**
|
||||
* See {@link #getAverageSpeedWithBearing(BoatClass, Speed, LegType, Tack, boolean)}
|
||||
* Always use regression
|
||||
*/
|
||||
SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
|
||||
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.dto.TrackedRaceDTO;
|
||||
import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
@@ -770,4 +771,6 @@ public interface TrackedRace extends Serializable {
|
||||
|
||||
boolean isUsingMarkPassingCalculator();
|
||||
|
||||
void setPolarDataService(PolarDataService polarDataService);
|
||||
|
||||
}
|
||||
+111
-33
@@ -101,6 +101,8 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager;
|
||||
import com.sap.sailing.domain.confidence.ConfidenceFactory;
|
||||
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
@@ -317,6 +319,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
*/
|
||||
private transient ShortTimeWindCache shortTimeWindCache;
|
||||
|
||||
private transient PolarDataService polarDataService;
|
||||
|
||||
public TrackedRaceImpl(final TrackedRegatta trackedRegatta, RaceDefinition race,
|
||||
final Iterable<Sideline> sidelines, final WindStore windStore, final GPSFixStore gpsFixStore,
|
||||
long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind,
|
||||
@@ -1860,40 +1864,66 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
BearingWithConfidence<TimePoint> resultBearing = null;
|
||||
ScalablePosition scaledPosition = null;
|
||||
int numberOfFixesConsideredForScaledPosition = 0;
|
||||
Set<WindSource> estimationExcluded = new HashSet<>();
|
||||
estimationExcluded.addAll(getWindSources(WindSourceType.TRACK_BASED_ESTIMATION));
|
||||
estimationExcluded.addAll(getWindSources(WindSourceType.COURSE_BASED));
|
||||
if (bearings != null) {
|
||||
BearingWithConfidenceCluster<TimePoint>[] bearingClustersUpwind = bearings.get(LegType.UPWIND).getA().splitInTwo(
|
||||
getMinimumAngleBetweenDifferentTacksUpwind(), timePoint);
|
||||
if (!bearingClustersUpwind[0].isEmpty() && !bearingClustersUpwind[1].isEmpty()) {
|
||||
BearingWithConfidence<TimePoint> average0 = bearingClustersUpwind[0].getAverage(timePoint);
|
||||
BearingWithConfidence<TimePoint> average1 = bearingClustersUpwind[1].getAverage(timePoint);
|
||||
upwindNumberOfRelevantBoats = Math
|
||||
.min(bearingClustersUpwind[0].size(), bearingClustersUpwind[1].size());
|
||||
confidence = Math.min(average0.getConfidence(), average1.getConfidence())
|
||||
* getRace().getBoatClass().getUpwindWindEstimationConfidence(upwindNumberOfRelevantBoats);
|
||||
reversedUpwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject()
|
||||
.middle(average1.getObject()).reverse(), confidence, timePoint);
|
||||
scaledPosition = bearings.get(LegType.UPWIND).getB();
|
||||
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.UPWIND).getA().size();
|
||||
int numberOfFixesUpwind = bearings.get(LegType.UPWIND).getA().size();
|
||||
if (numberOfFixesUpwind > 0) {
|
||||
ScalablePosition upwindPosition = bearings.get(LegType.UPWIND).getB();
|
||||
Pair<Double, Double> minimumAngleBetweenDifferentTacksUpwindWithConfidence = getMinimumAngleBetweenDifferentTacksUpwind(getWind(
|
||||
upwindPosition.divide(numberOfFixesUpwind), timePoint, estimationExcluded));
|
||||
BearingWithConfidenceCluster<TimePoint>[] bearingClustersUpwind = bearings
|
||||
.get(LegType.UPWIND)
|
||||
.getA()
|
||||
.splitInTwo(
|
||||
minimumAngleBetweenDifferentTacksUpwindWithConfidence.getA(),
|
||||
timePoint);
|
||||
if (!bearingClustersUpwind[0].isEmpty() && !bearingClustersUpwind[1].isEmpty()) {
|
||||
BearingWithConfidence<TimePoint> average0 = bearingClustersUpwind[0].getAverage(timePoint);
|
||||
BearingWithConfidence<TimePoint> average1 = bearingClustersUpwind[1].getAverage(timePoint);
|
||||
upwindNumberOfRelevantBoats = Math.min(bearingClustersUpwind[0].size(),
|
||||
bearingClustersUpwind[1].size());
|
||||
confidence = Math.min(average0.getConfidence(), average1.getConfidence())
|
||||
* getRace().getBoatClass().getUpwindWindEstimationConfidence(upwindNumberOfRelevantBoats)
|
||||
* minimumAngleBetweenDifferentTacksUpwindWithConfidence.getB();
|
||||
reversedUpwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject()
|
||||
.middle(average1.getObject()).reverse(), confidence, timePoint);
|
||||
scaledPosition = upwindPosition;
|
||||
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.UPWIND).getA().size();
|
||||
}
|
||||
}
|
||||
BearingWithConfidenceImpl<TimePoint> downwindAverage = null;
|
||||
int downwindNumberOfRelevantBoats = 0;
|
||||
BearingWithConfidenceCluster<TimePoint>[] bearingClustersDownwind = bearings.get(LegType.DOWNWIND).getA()
|
||||
.splitInTwo(getMinimumAngleBetweenDifferentTacksDownwind(), timePoint);
|
||||
if (!bearingClustersDownwind[0].isEmpty() && !bearingClustersDownwind[1].isEmpty()) {
|
||||
BearingWithConfidence<TimePoint> average0 = bearingClustersDownwind[0].getAverage(timePoint);
|
||||
BearingWithConfidence<TimePoint> average1 = bearingClustersDownwind[1].getAverage(timePoint);
|
||||
downwindNumberOfRelevantBoats = Math.min(bearingClustersDownwind[0].size(),
|
||||
bearingClustersDownwind[1].size());
|
||||
confidence = Math.min(average0.getConfidence(), average1.getConfidence())
|
||||
* getRace().getBoatClass().getDownwindWindEstimationConfidence(downwindNumberOfRelevantBoats);
|
||||
downwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject().middle(
|
||||
average1.getObject()), confidence, timePoint);
|
||||
if (scaledPosition == null) {
|
||||
scaledPosition = bearings.get(LegType.DOWNWIND).getB();
|
||||
} else {
|
||||
scaledPosition.add(bearings.get(LegType.DOWNWIND).getB());
|
||||
int numberOfFixesDownwind = bearings.get(LegType.DOWNWIND).getA().size();
|
||||
if (numberOfFixesDownwind > 0) {
|
||||
ScalablePosition downwindPosition = bearings.get(LegType.DOWNWIND).getB();
|
||||
Pair<Double, Double> minimumAngleBetweenDifferentTacksDownwindWithConfidence = getMinimumAngleBetweenDifferentTacksDownwind(getWind(
|
||||
downwindPosition.divide(numberOfFixesDownwind), timePoint, estimationExcluded));
|
||||
BearingWithConfidenceCluster<TimePoint>[] bearingClustersDownwind = bearings
|
||||
.get(LegType.DOWNWIND)
|
||||
.getA()
|
||||
.splitInTwo(
|
||||
minimumAngleBetweenDifferentTacksDownwindWithConfidence.getA(),
|
||||
timePoint);
|
||||
if (!bearingClustersDownwind[0].isEmpty() && !bearingClustersDownwind[1].isEmpty()) {
|
||||
BearingWithConfidence<TimePoint> average0 = bearingClustersDownwind[0].getAverage(timePoint);
|
||||
BearingWithConfidence<TimePoint> average1 = bearingClustersDownwind[1].getAverage(timePoint);
|
||||
downwindNumberOfRelevantBoats = Math.min(bearingClustersDownwind[0].size(),
|
||||
bearingClustersDownwind[1].size());
|
||||
confidence = Math.min(average0.getConfidence(), average1.getConfidence())
|
||||
* getRace().getBoatClass().getDownwindWindEstimationConfidence(
|
||||
downwindNumberOfRelevantBoats)
|
||||
* minimumAngleBetweenDifferentTacksDownwindWithConfidence.getB();
|
||||
downwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject().middle(
|
||||
average1.getObject()), confidence, timePoint);
|
||||
if (scaledPosition == null) {
|
||||
scaledPosition = downwindPosition;
|
||||
} else {
|
||||
scaledPosition.add(downwindPosition);
|
||||
}
|
||||
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.DOWNWIND).getA().size();
|
||||
}
|
||||
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.DOWNWIND).getA().size();
|
||||
}
|
||||
BearingWithConfidenceCluster<TimePoint> resultCluster = new BearingWithConfidenceCluster<TimePoint>(weigher);
|
||||
assert upwindNumberOfRelevantBoats == 0 || reversedUpwindAverage != null;
|
||||
@@ -2715,12 +2745,55 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
return getRace().getBoatClass().getManeuverDegreeAngleThreshold();
|
||||
}
|
||||
|
||||
private double getMinimumAngleBetweenDifferentTacksDownwind() {
|
||||
return getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksDownwind();
|
||||
private Pair<Double, Double> getMinimumAngleBetweenDifferentTacksDownwind(Wind wind) {
|
||||
Pair<Double, Double> result;
|
||||
double defaultAngle = getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksDownwind();
|
||||
double threshold = 20;
|
||||
result = usePolarsIfPossible(wind, defaultAngle, LegType.DOWNWIND, threshold);
|
||||
return result;
|
||||
}
|
||||
|
||||
private double getMinimumAngleBetweenDifferentTacksUpwind() {
|
||||
return getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksUpwind();
|
||||
private Pair<Double, Double> usePolarsIfPossible(Wind wind, double defaultAngle, LegType legType, double threshold) {
|
||||
Pair<Double, Double> result;
|
||||
if (polarDataService != null) {
|
||||
try {
|
||||
BearingWithConfidence<Void> average = polarDataService
|
||||
.getManeuverAngle(getRace().getBoatClass(), legType, wind);
|
||||
double averageAngleInDegMinusThreshold = average.getObject().getDegrees() - threshold;
|
||||
if (averageAngleInDegMinusThreshold < defaultAngle) {
|
||||
result = new Pair<Double, Double>(defaultAngle, 0.1);
|
||||
} else {
|
||||
result = new Pair<Double, Double>(averageAngleInDegMinusThreshold, average.getConfidence());
|
||||
}
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
result = new Pair<Double, Double>(defaultAngle, 0.1);
|
||||
}
|
||||
} else {
|
||||
result = new Pair<Double, Double>(defaultAngle, 0.1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Pair<Double, Double> getMinimumAngleBetweenDifferentTacksUpwind(Wind wind) {
|
||||
Pair<Double, Double> result;
|
||||
double defaultAngle = getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksUpwind();
|
||||
if (polarDataService != null) {
|
||||
try {
|
||||
BearingWithConfidence<Void> average = polarDataService
|
||||
.getManeuverAngle(getRace().getBoatClass(), LegType.UPWIND, wind);
|
||||
double averageAngleInDegMinusThreshold = average.getObject().getDegrees() - 10;
|
||||
if (averageAngleInDegMinusThreshold < defaultAngle) {
|
||||
result = new Pair<Double, Double>(defaultAngle, 0.1);
|
||||
} else {
|
||||
result = new Pair<Double, Double>(averageAngleInDegMinusThreshold, average.getConfidence());
|
||||
}
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
result = new Pair<Double, Double>(defaultAngle, 0.1);
|
||||
}
|
||||
} else {
|
||||
result = new Pair<Double, Double>(defaultAngle, 0.1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private long getApproximateManeuverDurationInMilliseconds() {
|
||||
@@ -3455,5 +3528,10 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPolarDataService(PolarDataService polarDataService) {
|
||||
this.polarDataService = polarDataService;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -444,4 +444,11 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.polars"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
</feature>
|
||||
+5
@@ -38,6 +38,7 @@ import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
|
||||
@@ -902,4 +903,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPolarDataService(PolarDataService polarDataService) {
|
||||
}
|
||||
}
|
||||
@@ -49,10 +49,7 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
org.apache.shiro.core;bundle-version="1.2.2"
|
||||
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: com.sap.sailing.polars,
|
||||
com.sap.sailing.polars.factory,
|
||||
com.sap.sailing.polars.regression,
|
||||
javax.jms;version="1.1.0",
|
||||
Import-Package: 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",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 281 KiB After Width: | Height: | Size: 286 KiB |
+1
@@ -41,6 +41,7 @@ public interface TextMessages extends Messages {
|
||||
String overview();
|
||||
String sapSailing();
|
||||
String search();
|
||||
String startSimulator();
|
||||
|
||||
String countdownDays();
|
||||
String countdownHours();
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ whatsNew=What''s new
|
||||
overview=Overview
|
||||
sapSailing=SAP Sailing
|
||||
search=Search
|
||||
startSimulator=Start Simulator
|
||||
|
||||
countdownDays=Days
|
||||
countdownHours=Hrs
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ whatsNew=Neuigkeiten
|
||||
overview=Übersicht
|
||||
sapSailing=SAP Sailing
|
||||
search=Suche
|
||||
startSimulator=Simulator starten
|
||||
|
||||
countdownDays=Tage
|
||||
countdownHours=Std.
|
||||
|
||||
+9
@@ -1,5 +1,8 @@
|
||||
package com.sap.sailing.gwt.home.client.app;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.place.shared.PlaceController;
|
||||
import com.sap.sailing.gwt.home.client.place.aboutus.AboutUsPlace;
|
||||
import com.sap.sailing.gwt.home.client.place.contact.ContactPlace;
|
||||
@@ -17,6 +20,7 @@ import com.sap.sailing.gwt.home.client.place.sponsoring.SponsoringPlace;
|
||||
import com.sap.sailing.gwt.home.client.place.start.StartPlace;
|
||||
import com.sap.sailing.gwt.home.client.place.whatsnew.WhatsNewPlace;
|
||||
import com.sap.sailing.gwt.home.client.place.whatsnew.WhatsNewPlace.WhatsNewNavigationTabs;
|
||||
import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory;
|
||||
|
||||
public class HomePlacesNavigator extends AbstractPlaceNavigator {
|
||||
|
||||
@@ -40,6 +44,11 @@ public class HomePlacesNavigator extends AbstractPlaceNavigator {
|
||||
return createLocalPlaceNavigation(new WhatsNewPlace(navigationTab), new WhatsNewPlace.Tokenizer());
|
||||
}
|
||||
|
||||
public String getSimulatorURL() {
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
return EntryPointLinkFactory.createSimulatorLink(parameters);
|
||||
}
|
||||
|
||||
public PlaceNavigation<SponsoringPlace> getSponsoringNavigation() {
|
||||
return createGlobalPlaceNavigation(new SponsoringPlace(), new SponsoringPlace.Tokenizer());
|
||||
}
|
||||
|
||||
+11
-11
@@ -28,15 +28,15 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
|
||||
private static final HyperlinkImpl HYPERLINK_IMPL = GWT.create(HyperlinkImpl.class);
|
||||
|
||||
@UiField HTML sailingAnalyticsNotes;
|
||||
// @UiField HTML sailingSimulatorNotes;
|
||||
@UiField HTML sailingSimulatorNotes;
|
||||
@UiField HTML raceCommitteeAppNotes;
|
||||
|
||||
@UiField Anchor sailingAnalyticsNotesAnchor;
|
||||
// @UiField Anchor sailingSimulatorNotesAnchor;
|
||||
@UiField Anchor sailingSimulatorNotesAnchor;
|
||||
@UiField Anchor raceCommitteeAppNotesAnchor;
|
||||
|
||||
private final PlaceNavigation<WhatsNewPlace> sailingAnalyticNotesNavigation;
|
||||
// private final PlaceNavigation<WhatsNewPlace> sailingSimulatorNoteNavigation;
|
||||
private final PlaceNavigation<WhatsNewPlace> sailingSimulatorNoteNavigation;
|
||||
private final PlaceNavigation<WhatsNewPlace> raceCommitteeAppNotesNavigation;
|
||||
|
||||
private final List<Anchor> links;
|
||||
@@ -49,19 +49,19 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
sailingAnalyticsNotes.setHTML(WhatsNewResources.INSTANCE.getSailingAnalyticsNotesHtml().getText());
|
||||
// sailingSimulatorNotes.setHTML(WhatsNewResources.INSTANCE.getSailingSimulatorNotesHtml().getText());
|
||||
sailingSimulatorNotes.setHTML(WhatsNewResources.INSTANCE.getSailingSimulatorNotesHtml().getText());
|
||||
raceCommitteeAppNotes.setHTML(WhatsNewResources.INSTANCE.getRaceCommitteeAppNotesHtml().getText());
|
||||
|
||||
sailingAnalyticNotesNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics);
|
||||
// sailingSimulatorNoteNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator);
|
||||
sailingSimulatorNoteNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator);
|
||||
raceCommitteeAppNotesNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.RaceCommiteeApp);
|
||||
|
||||
sailingAnalyticsNotesAnchor.setHref(sailingAnalyticNotesNavigation.getTargetUrl());
|
||||
// sailingSimulatorNotesAnchor.setHref(sailingSimulatorNoteNavigation.getTargetUrl());
|
||||
sailingSimulatorNotesAnchor.setHref(sailingSimulatorNoteNavigation.getTargetUrl());
|
||||
raceCommitteeAppNotesAnchor.setHref(raceCommitteeAppNotesNavigation.getTargetUrl());
|
||||
|
||||
links = Arrays.asList(new Anchor[] { sailingAnalyticsNotesAnchor, /*sailingSimulatorNotesAnchor,*/ raceCommitteeAppNotesAnchor });
|
||||
contentWidgets = Arrays.asList(new HTML[] { sailingAnalyticsNotes, /*sailingSimulatorNotes,*/ raceCommitteeAppNotes });
|
||||
links = Arrays.asList(new Anchor[] { sailingAnalyticsNotesAnchor, sailingSimulatorNotesAnchor, raceCommitteeAppNotesAnchor });
|
||||
contentWidgets = Arrays.asList(new HTML[] { sailingAnalyticsNotes, sailingSimulatorNotes, raceCommitteeAppNotes });
|
||||
|
||||
switch(navigationTab) {
|
||||
case PostRaceAnalytics:
|
||||
@@ -73,7 +73,7 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
|
||||
setActiveContent(sailingAnalyticsNotes, sailingAnalyticsNotesAnchor);
|
||||
break;
|
||||
case SailingSimulator:
|
||||
// setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor);
|
||||
setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor);
|
||||
break;
|
||||
case TrainingDiary:
|
||||
break;
|
||||
@@ -85,13 +85,13 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
|
||||
setActiveContent(sailingAnalyticsNotes, sailingAnalyticsNotesAnchor);
|
||||
handleClickEventWithLocalNavigation(event, sailingAnalyticNotesNavigation);
|
||||
}
|
||||
/*
|
||||
|
||||
@UiHandler("sailingSimulatorNotesAnchor")
|
||||
void featuresClicked(ClickEvent event) {
|
||||
setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor);
|
||||
handleClickEventWithLocalNavigation(event, sailingSimulatorNoteNavigation);
|
||||
}
|
||||
*/
|
||||
|
||||
@UiHandler("raceCommitteeAppNotesAnchor")
|
||||
void releaseNotesClicked(ClickEvent event) {
|
||||
setActiveContent(raceCommitteeAppNotes, raceCommitteeAppNotesAnchor);
|
||||
|
||||
+1
-5
@@ -10,9 +10,7 @@
|
||||
<div class="{res.mainCss.grid}">
|
||||
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
|
||||
<g:Anchor ui:field="sailingAnalyticsNotesAnchor" href="javascript:;" styleName="{local_res.css.whatsnew_nav_link}"><ui:text from='{i18n.solutionsSAPHeadline}'/></g:Anchor>
|
||||
<!--
|
||||
<g:Anchor ui:field="sailingSimulatorNotesAnchor" href="javascript:;" styleName="{local_res.css.whatsnew_nav_link}"><ui:text from='{i18n.solutionsSimulatorHeadline}'/></g:Anchor>
|
||||
-->
|
||||
<g:Anchor ui:field="sailingSimulatorNotesAnchor" href="javascript:;" styleName="{local_res.css.whatsnew_nav_link}"><ui:text from='{i18n.solutionsSimulatorHeadline}'/></g:Anchor>
|
||||
<g:Anchor ui:field="raceCommitteeAppNotesAnchor" href="javascript:;" styleName="{local_res.css.whatsnew_nav_link}"><ui:text from='{i18n.solutionsRaceHeadline}'/></g:Anchor>
|
||||
</div>
|
||||
</div>
|
||||
@@ -20,9 +18,7 @@
|
||||
<div class="{res.mainCss.grid}">
|
||||
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
|
||||
<g:HTML ui:field="sailingAnalyticsNotes" />
|
||||
<!--
|
||||
<g:HTML ui:field="sailingSimulatorNotes" />
|
||||
-->
|
||||
<g:HTML ui:field="raceCommitteeAppNotes" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+12
-1
@@ -44,6 +44,8 @@ public class Solutions extends Composite {
|
||||
|
||||
@UiField Anchor sailingAnalyticsDetailsAnchor;
|
||||
@UiField Anchor raceCommitteeAppDetailsAnchor;
|
||||
@UiField Anchor simulatorStartAnchor;
|
||||
@UiField Anchor simulatorAppDetailsAnchor;
|
||||
|
||||
private final PlaceNavigation<SolutionsPlace> sailingAnalyticsNavigation;
|
||||
private final PlaceNavigation<SolutionsPlace> raceCommitteeAppNavigation;
|
||||
@@ -55,6 +57,7 @@ public class Solutions extends Composite {
|
||||
|
||||
private final PlaceNavigation<WhatsNewPlace> sailingAnalyticsDetailsNavigation;
|
||||
private final PlaceNavigation<WhatsNewPlace> raceCommitteeAppDetailsNavigation;
|
||||
private final PlaceNavigation<WhatsNewPlace> simulatorAppDetailsNavigation;
|
||||
private final HomePlacesNavigator placesNavigator;
|
||||
|
||||
public Solutions(SolutionsNavigationTabs navigationTab, HomePlacesNavigator placesNavigator) {
|
||||
@@ -67,9 +70,12 @@ public class Solutions extends Composite {
|
||||
|
||||
sailingAnalyticsDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics);
|
||||
raceCommitteeAppDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.RaceCommiteeApp);
|
||||
simulatorAppDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator);
|
||||
|
||||
sailingAnalyticsDetailsAnchor.setHref(sailingAnalyticsDetailsNavigation.getTargetUrl());
|
||||
raceCommitteeAppDetailsAnchor.setHref(raceCommitteeAppDetailsNavigation.getTargetUrl());
|
||||
simulatorAppDetailsAnchor.setHref(simulatorAppDetailsNavigation.getTargetUrl());
|
||||
simulatorStartAnchor.setHref(placesNavigator.getSimulatorURL());
|
||||
|
||||
sailingAnalyticsNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.SailingAnalytics);
|
||||
raceCommitteeAppNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.RaceCommiteeApp);
|
||||
@@ -127,7 +133,12 @@ public class Solutions extends Composite {
|
||||
public void sailingAnalyticsDetailsClicked(ClickEvent e) {
|
||||
handleClickEventWithPlaceController(e, sailingAnalyticsDetailsNavigation);
|
||||
}
|
||||
|
||||
|
||||
@UiHandler("simulatorAppDetailsAnchor")
|
||||
public void simulatorAppDetailsAnchorClicked(ClickEvent e) {
|
||||
handleClickEventWithPlaceController(e, simulatorAppDetailsNavigation);
|
||||
}
|
||||
|
||||
private void scrollToView(SolutionsNavigationTabs navigationTab) {
|
||||
switch (navigationTab) {
|
||||
case SailingAnalytics:
|
||||
|
||||
+3
-1
@@ -67,7 +67,9 @@
|
||||
<div class="{res.mediaCss.small5} {res.mediaCss.smalloffset7} {res.mediaCss.columns}">
|
||||
<h2><ui:text from='{i18n.solutionsSimulatorHeadline}'/></h2>
|
||||
<p><ui:text from='{i18n.solutionsSimulatorText}'/></p>
|
||||
<!-- <a href="#" class="{res.mainCss.button}">Learn More</a> -->
|
||||
<g:Anchor ui:field="simulatorAppDetailsAnchor" styleName="{res.mainCss.button}"><ui:text from='{i18n.whatsNew}'/></g:Anchor>
|
||||
<span> </span>
|
||||
<g:Anchor ui:field="simulatorStartAnchor" target="_blank" styleName="{res.mainCss.button}"><ui:text from='{i18n.startSimulator}'/></g:Anchor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+6
-3
@@ -5,6 +5,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
@@ -20,10 +21,11 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
|
||||
private final Map<CompetitorDTO, Date> to;
|
||||
private final boolean extrapolate;
|
||||
private final Date date;
|
||||
|
||||
private final LegIdentifier simulationLegIdentifier;
|
||||
|
||||
public GetRaceMapDataAction(SailingServiceAsync sailingService, Iterable<CompetitorDTO> allCompetitors,
|
||||
RegattaAndRaceIdentifier raceIdentifier, Date date, Map<CompetitorDTO, Date> from,
|
||||
Map<CompetitorDTO, Date> to, boolean extrapolate) {
|
||||
Map<CompetitorDTO, Date> to, boolean extrapolate, LegIdentifier simulationLegIdentifier) {
|
||||
this.allCompetitors = allCompetitors;
|
||||
this.sailingService = sailingService;
|
||||
this.raceIdentifier = raceIdentifier;
|
||||
@@ -31,6 +33,7 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.extrapolate = extrapolate;
|
||||
this.simulationLegIdentifier = simulationLegIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,7 +49,7 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
|
||||
}
|
||||
|
||||
sailingService.getRaceMapData(raceIdentifier, date, fromByCompetitorIdAsString, toByCompetitorIdAsString,
|
||||
extrapolate, new AsyncCallback<CompactRaceMapDataDTO>() {
|
||||
extrapolate, simulationLegIdentifier, new AsyncCallback<CompactRaceMapDataDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
callback.onFailure(caught);
|
||||
|
||||
+6
-11
@@ -1,12 +1,11 @@
|
||||
package com.sap.sailing.gwt.ui.actions;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
|
||||
import com.sap.sailing.gwt.ui.shared.SimulatorResultsDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.RaceSimulationOverlay;
|
||||
import com.sap.sse.gwt.client.async.AsyncAction;
|
||||
|
||||
/**
|
||||
@@ -18,19 +17,15 @@ import com.sap.sse.gwt.client.async.AsyncAction;
|
||||
*/
|
||||
public class GetSimulationAction implements AsyncAction<SimulatorResultsDTO> {
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final RegattaAndRaceIdentifier raceIdentifier;
|
||||
private final Date from;
|
||||
private final Date prevStartTime;
|
||||
private final LegIdentifier legIdentifier;
|
||||
|
||||
public GetSimulationAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
|
||||
public GetSimulationAction(SailingServiceAsync sailingService, LegIdentifier legIdentifier) {
|
||||
this.sailingService = sailingService;
|
||||
this.raceIdentifier = raceIdentifier;
|
||||
this.from = from;
|
||||
this.prevStartTime = prevStartTime;
|
||||
this.legIdentifier = legIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(AsyncCallback<SimulatorResultsDTO> callback) {
|
||||
sailingService.getSimulatorResults(raceIdentifier, from, prevStartTime, callback);
|
||||
sailingService.getSimulatorResults(legIdentifier, callback);
|
||||
}
|
||||
}
|
||||
+4
@@ -9,6 +9,10 @@ public class EntryPointLinkFactory extends AbstractEntryPointLinkFactory {
|
||||
return createEntryPointLink("/gwt/RaceBoard.html", parameters);
|
||||
}
|
||||
|
||||
public static String createSimulatorLink(Map<String, String> parameters) {
|
||||
return createEntryPointLink("/gwt/Simulator.html", parameters);
|
||||
}
|
||||
|
||||
public static String createLeaderboardLink(Map<String, String> parameters) {
|
||||
return createEntryPointLink("/gwt/Leaderboard.html", parameters);
|
||||
}
|
||||
|
||||
+3
-2
@@ -16,6 +16,7 @@ import com.sap.sailing.domain.base.RemoteSailingServerReference;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
@@ -143,10 +144,10 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
|
||||
boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime);
|
||||
SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier);
|
||||
|
||||
CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString,
|
||||
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate) throws NoWindException;
|
||||
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate, LegIdentifier simulationLegIdentifier) throws NoWindException;
|
||||
|
||||
RaceTimesInfoDTO getRaceTimesInfo(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ import com.sap.sailing.domain.base.RemoteSailingServerReference;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.PolarSheetGenerationResponse;
|
||||
@@ -190,7 +191,7 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
|
||||
|
||||
void getPolarResults(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> callback);
|
||||
|
||||
void getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime, AsyncCallback<SimulatorResultsDTO> callback);
|
||||
void getSimulatorResults(LegIdentifier legIdentifier, AsyncCallback<SimulatorResultsDTO> callback);
|
||||
|
||||
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind, AsyncCallback<Void> callback);
|
||||
|
||||
@@ -335,7 +336,7 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
|
||||
* identified by <code>raceIdentifier</code> will be used, considering that race's delay.
|
||||
*/
|
||||
void getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString,
|
||||
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate, AsyncCallback<CompactRaceMapDataDTO> callback);
|
||||
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate, LegIdentifier simulationLegIdentifier, AsyncCallback<CompactRaceMapDataDTO> callback);
|
||||
|
||||
void getReplicaInfo(AsyncCallback<ReplicationStateDTO> callback);
|
||||
|
||||
|
||||
+1194
File diff suppressed because it is too large.
Load diff
+9
-14
@@ -307,6 +307,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
private boolean isMapInitialized;
|
||||
|
||||
private Date lastTimeChangeBeforeInitialization;
|
||||
|
||||
private int lastLegNumber;
|
||||
|
||||
/**
|
||||
* The last quick ranks received from a call to {@link SailingServiceAsync#getQuickRanks(RaceIdentifier, Date, AsyncCallback)} upon
|
||||
@@ -739,7 +741,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
// next, do the full thing; being the later call, if request throttling kicks in, the later call
|
||||
// supersedes the earlier call which may get dropped then
|
||||
GetRaceMapDataAction getRaceMapDataAction = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), race,
|
||||
useNullAsTimePoint() ? null : newTime, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true);
|
||||
useNullAsTimePoint() ? null : newTime, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true, (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null));
|
||||
asyncActionsExecutor.execute(getRaceMapDataAction, GET_RACE_MAP_DATA_CATEGORY,
|
||||
getRaceMapDataCallback(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID));
|
||||
|
||||
@@ -820,7 +822,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
final GetRaceMapDataAction result;
|
||||
if (!fromTimes.isEmpty()) {
|
||||
result = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(),
|
||||
race, useNullAsTimePoint() ? null : newTime, fromTimes, toTimes, /* extrapolate */true);
|
||||
race, useNullAsTimePoint() ? null : newTime, fromTimes, toTimes, /* extrapolate */true, (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
@@ -843,7 +845,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (map != null && raceMapDataDTO != null) {
|
||||
quickRanks = raceMapDataDTO.quickRanks;
|
||||
if (showViewSimulation && settings.isShowSimulationOverlay()) {
|
||||
simulationOverlay.updateLeg(getCurrentLeg(), newTime, /* clearCanvas */ false);
|
||||
lastLegNumber = raceMapDataDTO.coursePositions.currentLegNumber;
|
||||
simulationOverlay.updateLeg(Math.max(lastLegNumber,1), /* clearCanvas */ false, raceMapDataDTO.simulationResultVersion);
|
||||
}
|
||||
// process response only if not received out of order
|
||||
if (startedProcessingRequestID < requestID) {
|
||||
@@ -2228,7 +2231,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
if (newSettings.isShowSimulationOverlay() != settings.isShowSimulationOverlay()) {
|
||||
settings.setShowSimulationOverlay(newSettings.isShowSimulationOverlay());
|
||||
simulationOverlay.setVisible(newSettings.isShowSimulationOverlay());
|
||||
simulationOverlay.updateLeg(getCurrentLeg(), timer.getTime(), true);
|
||||
if (newSettings.isShowSimulationOverlay()) {
|
||||
simulationOverlay.updateLeg(Math.max(lastLegNumber,1), true, -1 /* ensure ui-update */);
|
||||
}
|
||||
}
|
||||
if (newSettings.isWindUp() != settings.isWindUp()) {
|
||||
settings.setWindUp(newSettings.isWindUp());
|
||||
@@ -2437,16 +2442,6 @@ 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();
|
||||
Image sapLogo = new Image(sapLogoResource);
|
||||
|
||||
+55
-104
@@ -137,6 +137,7 @@ import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
@@ -221,6 +222,8 @@ 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.persistence.MongoRegattaLogStoreFactory;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.RaceStateOfSameDayHelper;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
@@ -340,8 +343,6 @@ 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.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.resultimport.ResultUrlProvider;
|
||||
import com.sap.sailing.resultimport.ResultUrlRegistry;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
@@ -395,24 +396,20 @@ import com.sap.sailing.server.operationaltransformation.UpdateLeaderboardScoreCo
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateRaceDelayToLive;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateSeries;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateSpecificRegatta;
|
||||
import com.sap.sailing.server.simulation.SimulationService;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SailingSimulator;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.SimulationResults;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
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;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
|
||||
import com.sap.sailing.simulator.windfield.impl.WindFieldTrackedRaceImpl;
|
||||
import com.sap.sailing.simulator.impl.SparsePolarDataException;
|
||||
import com.sap.sailing.xrr.schema.RegattaResults;
|
||||
import com.sap.sailing.xrr.structureimport.SeriesParameters;
|
||||
import com.sap.sailing.xrr.structureimport.StructureImporter;
|
||||
import com.sap.sailing.xrr.structureimport.buildstructure.SetRacenumberFromSeries;
|
||||
import com.sap.sse.BuildVersion;
|
||||
import com.sap.sse.common.CountryCode;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
@@ -421,7 +418,6 @@ import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
import com.sap.sse.common.mail.MailException;
|
||||
@@ -1435,107 +1431,55 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
} else {
|
||||
BoatClass boatClass = trackedRace.getRace().getBoatClass();
|
||||
PolarDataService polarData = getService().getPolarDataService();
|
||||
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
|
||||
PolarDiagram polarDiagram;
|
||||
try {
|
||||
polarDiagram = new PolarDiagramGPS(boatClass, polarData);
|
||||
} catch (SparsePolarDataException e) {
|
||||
polarDiagram = null;
|
||||
// TODO: raise a UI message, to inform user about missing polar data resulting in unability to simulate
|
||||
}
|
||||
result = polarDiagram != null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
|
||||
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
|
||||
public SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier) {
|
||||
// get simulation-results from smart-future-cached simulation-service
|
||||
SimulatorResultsDTO result = null;
|
||||
|
||||
if (trackedRace != null) {
|
||||
TimePoint fromTimePoint = from == null ? new MillisecondsTimePoint(trackedRace.getStartOfRace().asMillis() + 10000) : new MillisecondsTimePoint(from);
|
||||
|
||||
// get previous mark or start line as start-position
|
||||
TrackedLeg trackedLeg = trackedRace.getCurrentLeg(fromTimePoint);
|
||||
if (trackedLeg == null) {
|
||||
return result;
|
||||
}
|
||||
Waypoint fromWaypoint = trackedLeg.getLeg().getFrom();
|
||||
|
||||
// get next mark as end-position
|
||||
Waypoint toWaypoint = trackedLeg.getLeg().getTo();
|
||||
|
||||
TimePoint startTimePoint = null;
|
||||
TimePoint endTimePoint = null;
|
||||
Iterable<Util.Pair<Waypoint, Util.Pair<TimePoint, TimePoint>>> markPassings = trackedRace.getMarkPassingsTimes();
|
||||
long legDuration = 0;
|
||||
synchronized(markPassings) {
|
||||
for(Pair<Waypoint, Pair<TimePoint, TimePoint>> markPassing : markPassings) {
|
||||
if (markPassing.getA().equals(fromWaypoint)) {
|
||||
startTimePoint = markPassing.getB().getA();
|
||||
}
|
||||
if (markPassing.getA().equals(toWaypoint)) {
|
||||
endTimePoint = markPassing.getB().getA();
|
||||
}
|
||||
SimulationService simulationService = getService().getSimulationService();
|
||||
if (simulationService == null)
|
||||
return result;
|
||||
SimulationResults simulationResults = simulationService.getSimulationResults(legIdentifier);
|
||||
if (simulationResults == null)
|
||||
return result;
|
||||
// prepare simulator-results-dto
|
||||
Map<PathType, Path> paths = simulationResults.getPaths();
|
||||
if (paths != null) {
|
||||
int noOfPaths = paths.size();
|
||||
PathDTO[] pathDTOs = new PathDTO[noOfPaths];
|
||||
int index = noOfPaths - 1;
|
||||
for (Entry<PathType, Path> entry : paths.entrySet()) {
|
||||
pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
|
||||
// fill pathDTO with path points where speed is true wind speed
|
||||
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
|
||||
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
|
||||
wList.add(createSimulatorWindDTO(p));
|
||||
}
|
||||
pathDTOs[index].setPoints(wList);
|
||||
pathDTOs[index].setAlgorithmTimedOut(entry.getValue().getAlgorithmTimedOut());
|
||||
pathDTOs[index].setMixedLeg(entry.getValue().getMixedLeg());
|
||||
index--;
|
||||
}
|
||||
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, 0, null, null, null, null);
|
||||
}
|
||||
|
||||
// determine legtype upwind/downwind/reaching
|
||||
LegType legType = null;
|
||||
try {
|
||||
legType = trackedLeg.getLegType(fromTimePoint);
|
||||
} catch (NoWindException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// get windfield
|
||||
WindFieldGenerator windField = new WindFieldTrackedRaceImpl(trackedRace);
|
||||
Duration timeStep = new MillisecondsDurationImpl(15 * 1000);
|
||||
windField.generate(startTimePoint, null, timeStep);
|
||||
|
||||
// prepare simulation-parameters
|
||||
List<Position> course = new ArrayList<>();
|
||||
course.add(startPosition);
|
||||
course.add(endPosition);
|
||||
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
|
||||
SailingSimulator simulator = new SailingSimulatorImpl(simulationPars);
|
||||
Map<String, Path> pathsAndNames = null;
|
||||
if (legType != LegType.REACHING) {
|
||||
pathsAndNames = simulator.getAllPathsEvenTimed(timeStep.asMillis(), null);
|
||||
}
|
||||
|
||||
// prepare simulator-results-dto
|
||||
if (pathsAndNames != null) {
|
||||
int noOfPaths = pathsAndNames.size();
|
||||
PathDTO[] pathDTOs = new PathDTO[noOfPaths];
|
||||
int index = noOfPaths - 1;
|
||||
for (Entry<String, Path> entry : pathsAndNames.entrySet()) {
|
||||
pathDTOs[index] = new PathDTO(entry.getKey());
|
||||
// fill pathDTO with path points where speed is true wind speed
|
||||
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
|
||||
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
|
||||
wList.add(createSimulatorWindDTO(p));
|
||||
}
|
||||
pathDTOs[index].setPoints(wList);
|
||||
index--;
|
||||
}
|
||||
RaceMapDataDTO rcDTO;
|
||||
rcDTO = new RaceMapDataDTO();
|
||||
rcDTO.coursePositions = new CoursePositionsDTO();
|
||||
rcDTO.coursePositions.waypointPositions = new ArrayList<>();
|
||||
rcDTO.coursePositions.waypointPositions.add(startPosition);
|
||||
rcDTO.coursePositions.waypointPositions.add(endPosition);
|
||||
result = new SimulatorResultsDTO(startTimePoint.asDate(), timeStep.asMillis(), legDuration, rcDTO, pathDTOs, null, null);
|
||||
}
|
||||
RaceMapDataDTO rcDTO;
|
||||
rcDTO = new RaceMapDataDTO();
|
||||
rcDTO.coursePositions = new CoursePositionsDTO();
|
||||
rcDTO.coursePositions.waypointPositions = new ArrayList<Position>();
|
||||
rcDTO.coursePositions.waypointPositions.add(simulationResults.getStartPosition());
|
||||
rcDTO.coursePositions.waypointPositions.add(simulationResults.getEndPosition());
|
||||
result = new SimulatorResultsDTO(simulationResults.hashCode(), simulationResults.getStartTime(), simulationResults.getTimeStep(),
|
||||
simulationResults.getLegDuration(), rcDTO, pathDTOs, null, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1611,13 +1555,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
@Override
|
||||
public CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date,
|
||||
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
|
||||
boolean extrapolate) throws NoWindException {
|
||||
boolean extrapolate, LegIdentifier simulationLegIdentifier) throws NoWindException {
|
||||
final Map<CompetitorDTO, List<GPSFixDTO>> boatPositions = getBoatPositions(raceIdentifier,
|
||||
fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate);
|
||||
final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date);
|
||||
final List<SidelineDTO> courseSidelines = getCourseSidelines(raceIdentifier, date);
|
||||
final List<QuickRankDTO> quickRanks = getQuickRanks(raceIdentifier, date);
|
||||
return new CompactRaceMapDataDTO(boatPositions, coursePositions, courseSidelines, quickRanks);
|
||||
int simulationResultVersion = 0;
|
||||
if (simulationLegIdentifier != null) {
|
||||
SimulationService simulationService = getService().getSimulationService();
|
||||
simulationResultVersion = simulationService.getSimulationResultsVersion(simulationLegIdentifier);
|
||||
}
|
||||
return new CompactRaceMapDataDTO(boatPositions, coursePositions, courseSidelines, quickRanks, simulationResultVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1896,6 +1845,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
} else {
|
||||
dateAsTimePoint = new MillisecondsTimePoint(date);
|
||||
}
|
||||
result.totalLegsCount = trackedRace.getRace().getCourse().getLegs().size();
|
||||
result.currentLegNumber = trackedRace.getLastLegStarted(dateAsTimePoint);
|
||||
result.marks = new HashSet<MarkDTO>();
|
||||
result.waypointPositions = new ArrayList<>();
|
||||
Set<Mark> marks = new HashSet<Mark>();
|
||||
|
||||
+176
-107
@@ -9,6 +9,11 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
|
||||
@@ -21,6 +26,7 @@ import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
|
||||
import com.sap.sailing.gwt.ui.client.SimulatorService;
|
||||
import com.sap.sailing.gwt.ui.shared.BoatClassDTOsAndNotificationMessage;
|
||||
@@ -50,11 +56,14 @@ import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternDisplay;
|
||||
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternDisplayManager;
|
||||
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternNotFoundException;
|
||||
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternSetting;
|
||||
import com.sap.sailing.server.simulation.SimulationService;
|
||||
import com.sap.sailing.server.simulation.SimulationServiceFactory;
|
||||
import com.sap.sailing.simulator.BoatClassProperties;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SailingSimulator;
|
||||
import com.sap.sailing.simulator.Simulator;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
@@ -64,7 +73,7 @@ import com.sap.sailing.simulator.impl.PathGenerator1Turner;
|
||||
import com.sap.sailing.simulator.impl.PathImpl;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagramCSV;
|
||||
import com.sap.sailing.simulator.impl.ReadingConfigurationFileStatus;
|
||||
import com.sap.sailing.simulator.impl.SailingSimulatorImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulatorImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
|
||||
import com.sap.sailing.simulator.impl.TimedPositionImpl;
|
||||
import com.sap.sailing.simulator.impl.TimedPositionWithSpeedImpl;
|
||||
@@ -77,6 +86,7 @@ import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class SimulatorServiceImpl extends RemoteServiceServlet implements SimulatorService {
|
||||
|
||||
private static final long serialVersionUID = 4445427185387524086L;
|
||||
@@ -89,11 +99,23 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
// private static final double TOTAL_TIME_SCALE_FACTOR = 0.9;
|
||||
private static final int DEFAULT_STEP_MAX = 800;
|
||||
private static final long DEFAULT_TIMESTEP = 6666;
|
||||
private final SimulationService simulationService;
|
||||
|
||||
private double stepSizeMeters = 0.0;
|
||||
private WindControlParameters controlParameters = new WindControlParameters(0, 0);
|
||||
private SpeedWithBearing averageWind = null;
|
||||
|
||||
public SimulatorServiceImpl() {
|
||||
final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
||||
Executor simulatorExecutor = new ThreadPoolExecutor(/* corePoolSize */THREAD_POOL_SIZE,
|
||||
/* maximumPoolSize */THREAD_POOL_SIZE,
|
||||
/* keepAliveTime */60, TimeUnit.SECONDS,
|
||||
/* workQueue */new LinkedBlockingQueue<Runnable>());
|
||||
// TODO: initialize smart-future-cache for simulation-results and add to simulation-service
|
||||
simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Position[] getRaceLocations() {
|
||||
Position lakeGarda = new DegreePosition(45.57055337226086, 10.693345069885254);
|
||||
@@ -185,7 +207,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
throw new WindPatternNotFoundException("Please select a valid wind pattern.");
|
||||
}
|
||||
|
||||
Position[][] grid = bd.generatePositions(params.getxRes(), params.getyRes(), params.getBorderY(), params.getBorderX());
|
||||
Position[][] grid = bd.generatePositions(params.getxRes(), params.getyRes(), params.getBorderY(),
|
||||
params.getBorderX());
|
||||
wf.setPositionGrid(grid);
|
||||
|
||||
TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime());
|
||||
@@ -220,13 +243,13 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulatorResultsDTO getSimulatorResults(char mode, char rcDirection, WindFieldGenParamsDTO params, WindPatternDisplay pattern, boolean withWindField,
|
||||
SimulatorUISelectionDTO selection) throws WindPatternNotFoundException,
|
||||
ConfigurationException {
|
||||
public SimulatorResultsDTO getSimulatorResults(char mode, char rcDirection, WindFieldGenParamsDTO params,
|
||||
WindPatternDisplay pattern, boolean withWindField, SimulatorUISelectionDTO selection)
|
||||
throws WindPatternNotFoundException, ConfigurationException {
|
||||
WindFieldGenerator wf = null;
|
||||
List<Position> course = null;
|
||||
TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime());
|
||||
@@ -235,7 +258,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
this.controlParameters.resetBlastRandomStream = params.isKeepState();
|
||||
this.retreiveWindControlParameters(pattern);
|
||||
if (rcDirection == SailingSimulatorConstants.LegTypeDownwind) {
|
||||
this.controlParameters.baseWindBearing += 180.0;
|
||||
this.controlParameters.baseWindBearing += 180.0;
|
||||
}
|
||||
|
||||
wf = wfGenFactory.createWindFieldGenerator(pattern.getWindPatternName(), null, this.controlParameters);
|
||||
@@ -259,13 +282,14 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
gridRes[0] = params.getxRes();
|
||||
gridRes[1] = params.getyRes();
|
||||
gridRes[2] = params.getBorderY();
|
||||
gridRes[3] = params.getBorderX();
|
||||
gridRes[3] = params.getBorderX();
|
||||
wf.setGridResolution(gridRes);
|
||||
|
||||
wf.generate(startTime, null, timeStep);
|
||||
Long longestPathTime = 0L;
|
||||
|
||||
SimulatedPathsEvenTimedResultDTO simulatedPaths = this.getSimulatedPathsEvenTimed(course, wf, mode, selection, params.showOmniscient, params.showOpportunist);
|
||||
SimulatedPathsEvenTimedResultDTO simulatedPaths = this.getSimulatedPathsEvenTimed(course, wf, mode, selection,
|
||||
params.showOmniscient, params.showOpportunist);
|
||||
PathDTO[] pathDTOs = simulatedPaths.pathDTOs;
|
||||
RaceMapDataDTO rcDTO = simulatedPaths.raceMapDataDTO;
|
||||
|
||||
@@ -283,10 +307,13 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
|
||||
WindFieldDTO windFieldDTO = null;
|
||||
if (pattern != null) {
|
||||
windFieldDTO = this.createWindFieldDTO(wf, startTime, endTime, timeStep, params); // params.isShowStreamlets2(), params.isShowLines(), params.getSeedLines());
|
||||
windFieldDTO = this.createWindFieldDTO(wf, startTime, endTime, timeStep, params); // params.isShowStreamlets2(),
|
||||
// params.isShowLines(),
|
||||
// params.getSeedLines());
|
||||
}
|
||||
|
||||
return new SimulatorResultsDTO(null, timeStep.asMillis(), 0, rcDTO, pathDTOs, windFieldDTO, simulatedPaths.notificationMessage);
|
||||
return new SimulatorResultsDTO(0, null, timeStep.asMillis(), 0, rcDTO, pathDTOs, windFieldDTO,
|
||||
simulatedPaths.notificationMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -349,20 +376,23 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
@Override
|
||||
public ResponseTotalTimeDTO getTotalTime(RequestTotalTimeDTO requestData) throws ConfigurationException {
|
||||
|
||||
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getAverage(requestData.allPoints)
|
||||
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
|
||||
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils
|
||||
.getAverage(requestData.allPoints) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
|
||||
|
||||
this.stepSizeMeters = SimulatorServiceUtils.knotsToMetersPerSecond(this.averageWind.getKnots()) * (requestData.stepDurationMilliseconds / 1000.);
|
||||
this.stepSizeMeters = SimulatorServiceUtils.knotsToMetersPerSecond(this.averageWind.getKnots())
|
||||
* (requestData.stepDurationMilliseconds / 1000.);
|
||||
|
||||
// List<Position> points = SimulatorServiceUtils.getIntermediatePoints2(requestData.turnPoints,
|
||||
// this.stepSizeMeters);
|
||||
// int noOfPointsMinus1 = points.size() - 1;
|
||||
|
||||
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(requestData.selection.boatClassIndex);
|
||||
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this
|
||||
.getPolarDiagram(requestData.selection.boatClassIndex);
|
||||
PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
|
||||
String notificationMessage = polarDiagramAndNotificationMessage.getB();
|
||||
|
||||
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, polarDiagram, null, SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, polarDiagram, null,
|
||||
null, SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
Path gpsTrack = simulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
|
||||
|
||||
// Position startPoint = null;
|
||||
@@ -405,14 +435,12 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
//
|
||||
// double totalTimeSeconds = (timepointAsMillis - courseStartPoint.timepoint) / 1000;
|
||||
//
|
||||
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1).getTimePoint().asMillis() - gpsTrack
|
||||
.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
|
||||
|
||||
|
||||
//while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
|
||||
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
|
||||
//}
|
||||
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1)
|
||||
.getTimePoint().asMillis() - gpsTrack.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
|
||||
|
||||
// while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
|
||||
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
|
||||
// }
|
||||
|
||||
long startTimePoint = requestData.allPoints.get(0).timepoint;
|
||||
long segmentTime = 0;
|
||||
@@ -425,8 +453,9 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
|
||||
totalTime += segmentTime;
|
||||
|
||||
segmentTime = getTimeMillisecondsBetween(requestData.turnPoints.get(index), requestData.turnPoints.get(index + 1), this.stepSizeMeters,
|
||||
requestData.useRealAverageWindSpeed, gpsTrack, polarDiagram, startTimePoint + totalTime);
|
||||
segmentTime = getTimeMillisecondsBetween(requestData.turnPoints.get(index),
|
||||
requestData.turnPoints.get(index + 1), this.stepSizeMeters, requestData.useRealAverageWindSpeed,
|
||||
gpsTrack, polarDiagram, startTimePoint + totalTime);
|
||||
|
||||
System.out.println("Total time of segment " + segmentIndex + " = " + segmentTime + " milliseconds");
|
||||
}
|
||||
@@ -437,25 +466,30 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
|
||||
System.out.println("TotalTimeGPS: " + totalTimeGPSTrackSeconds + " TotalTimePoly: " + totalTimeSeconds);
|
||||
|
||||
return new ResponseTotalTimeDTO(totalTimeSeconds, totalTimeSeconds/totalTimeGPSTrackSeconds, notificationMessage);
|
||||
return new ResponseTotalTimeDTO(totalTimeSeconds, totalTimeSeconds / totalTimeGPSTrackSeconds,
|
||||
notificationMessage);
|
||||
}
|
||||
|
||||
//@Override
|
||||
// @Override
|
||||
public ResponseTotalTimeDTO getTotalTimeOld(RequestTotalTimeDTO requestData) throws ConfigurationException {
|
||||
|
||||
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getAverage(requestData.allPoints)
|
||||
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
|
||||
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils
|
||||
.getAverage(requestData.allPoints) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
|
||||
|
||||
this.stepSizeMeters = SimulatorServiceUtils.knotsToMetersPerSecond(this.averageWind.getKnots()) * (requestData.stepDurationMilliseconds / 1000.);
|
||||
this.stepSizeMeters = SimulatorServiceUtils.knotsToMetersPerSecond(this.averageWind.getKnots())
|
||||
* (requestData.stepDurationMilliseconds / 1000.);
|
||||
|
||||
List<Position> points = SimulatorServiceUtils.getIntermediatePoints2(requestData.turnPoints, this.stepSizeMeters);
|
||||
List<Position> points = SimulatorServiceUtils.getIntermediatePoints2(requestData.turnPoints,
|
||||
this.stepSizeMeters);
|
||||
int noOfPointsMinus1 = points.size() - 1;
|
||||
|
||||
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(requestData.selection.boatClassIndex);
|
||||
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this
|
||||
.getPolarDiagram(requestData.selection.boatClassIndex);
|
||||
PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
|
||||
String notificationMessage = polarDiagramAndNotificationMessage.getB();
|
||||
|
||||
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, polarDiagram, null, SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, polarDiagram, null,
|
||||
null, SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
Path gpsTrack = simulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
|
||||
|
||||
Position startPoint = null;
|
||||
@@ -476,17 +510,18 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
endPoint = points.get(index + 1);
|
||||
distanceMeters = startPoint.getDistance(endPoint).getMeters();
|
||||
|
||||
windAtTimePoint = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis, gpsTrack)
|
||||
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
|
||||
windAtTimePoint = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(
|
||||
timepointAsMillis, gpsTrack) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
|
||||
|
||||
boatBearingDeg = SimulatorServiceUtils.getInitialBearing(startPoint, endPoint);
|
||||
polarDiagram.setWind(windAtTimePoint);
|
||||
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg)).getMetersPerSecond();
|
||||
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg))
|
||||
.getMetersPerSecond();
|
||||
stepTimeMilliseconds = (long) ((distanceMeters / boatSpeedMetersPerSecond) * 1000);
|
||||
//problem right here
|
||||
//boatSpeed might be 0 for very small distances
|
||||
//this is a rough fix
|
||||
if(boatSpeedMetersPerSecond == 0.0) {
|
||||
// problem right here
|
||||
// boatSpeed might be 0 for very small distances
|
||||
// this is a rough fix
|
||||
if (boatSpeedMetersPerSecond == 0.0) {
|
||||
stepTimeMilliseconds = 1000;
|
||||
}
|
||||
|
||||
@@ -496,23 +531,23 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
|
||||
double totalTimeSeconds = (timepointAsMillis - requestData.allPoints.get(0).timepoint) / 1000;
|
||||
|
||||
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1).getTimePoint().asMillis() - gpsTrack
|
||||
.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
|
||||
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1)
|
||||
.getTimePoint().asMillis() - gpsTrack.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
|
||||
|
||||
// while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
|
||||
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
|
||||
// }
|
||||
System.out.println("TotalTimeGPS: " + totalTimeGPSTrackSeconds + " TotalTimePoly: " + totalTimeSeconds);
|
||||
|
||||
//while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
|
||||
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
|
||||
//}
|
||||
System.out.println("TotalTimeGPS: "+totalTimeGPSTrackSeconds+" TotalTimePoly: "+totalTimeSeconds);
|
||||
|
||||
return new ResponseTotalTimeDTO((long) totalTimeSeconds, (double)totalTimeSeconds/(double)totalTimeGPSTrackSeconds, notificationMessage);
|
||||
return new ResponseTotalTimeDTO((long) totalTimeSeconds, (double) totalTimeSeconds
|
||||
/ (double) totalTimeGPSTrackSeconds, notificationMessage);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Response1TurnerDTO get1Turner(Request1TurnerDTO requestData) throws ConfigurationException {
|
||||
|
||||
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(requestData.selection.boatClassIndex);
|
||||
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this
|
||||
.getPolarDiagram(requestData.selection.boatClassIndex);
|
||||
PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
|
||||
String notificationMessage = polarDiagramAndNotificationMessage.getB();
|
||||
|
||||
@@ -522,16 +557,19 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
Position oldMovedPosition = requestData.oldMovedPoint;
|
||||
Position newMovedPosition = requestData.newMovedPoint;
|
||||
Bearing oldMovedToNewMovedBearing = oldMovedPosition.getBearingGreatCircle(newMovedPosition);
|
||||
boolean areTowardsSameDirection = SimulatorServiceUtils.areTowardsSameDirection(oldMovedToNewMovedBearing, new DegreeBearingImpl(
|
||||
requestData.startToEndBearingDegrees));
|
||||
boolean areTowardsSameDirection = SimulatorServiceUtils.areTowardsSameDirection(oldMovedToNewMovedBearing,
|
||||
new DegreeBearingImpl(requestData.startToEndBearingDegrees));
|
||||
|
||||
System.out.println("oldMovedToNewMovedBearing = " + oldMovedToNewMovedBearing.getDegrees() + " degrees");
|
||||
System.out.println("requestData.startToEndBearingDegrees = " + requestData.startToEndBearingDegrees + " degrees");
|
||||
System.out.println("requestData.startToEndBearingDegrees = " + requestData.startToEndBearingDegrees
|
||||
+ " degrees");
|
||||
System.out.println("areTowardsSameDirection = " + areTowardsSameDirection);
|
||||
|
||||
SimulationParameters simulationParameters = new SimulationParametersImpl(null, polarDiagram, null, SailingSimulatorConstants.ModeMeasured, true, true);
|
||||
SailingSimulator sailingSimulator = new SailingSimulatorImpl(simulationParameters);
|
||||
Path gpsWind = sailingSimulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
|
||||
SimulationParameters simulationParameters = new SimulationParametersImpl(null, polarDiagram, null, null,
|
||||
SailingSimulatorConstants.ModeMeasured, true, true);
|
||||
Simulator sailingSimulator = new SimulatorImpl(simulationParameters);
|
||||
Path gpsWind = sailingSimulator.getLegGPSTrack(SimulatorServiceUtils
|
||||
.toSimulatorUISelection(requestData.selection));
|
||||
|
||||
Grid grid = new CurvedGrid(oldMovedPosition, newMovedPosition);
|
||||
this.controlParameters.baseWindBearing += grid.getSouth().getDegrees();
|
||||
@@ -548,8 +586,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
Position realStart = areTowardsSameDirection ? oldMovedPosition : newMovedPosition;
|
||||
Position realEnd = areTowardsSameDirection ? newMovedPosition : oldMovedPosition;
|
||||
|
||||
leftSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime, true, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP);
|
||||
rightSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime, false, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP);
|
||||
leftSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime,
|
||||
true, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP);
|
||||
rightSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime,
|
||||
false, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP);
|
||||
|
||||
boolean isLeftSide1TurnerOnTheInside = SimulatorServiceUtils.isPointInsideTriangle(leftSide1Turner.getPosition(),
|
||||
requestData.beforeMovedPoint,
|
||||
@@ -579,8 +619,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
} else if (SimulatorServiceUtils.equals(rightSide1Turner.getPosition(), newMovedPosition, 0.0001)) {
|
||||
System.out.println("voi folosi endPosition = rightSide1Turner!");
|
||||
correct1Turner = rightSide1Turner;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
System.out.println("nu ar trebui sa ajunga aici NICIODATA!");
|
||||
}
|
||||
}
|
||||
@@ -588,11 +627,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
long timeStepMilliseconds = 2000;
|
||||
double minimumDistanceMeters = 4.0;
|
||||
|
||||
List<TimedPositionWithSpeed> path = pathGenerator.getIntersectionOptimalTowardWind(windFieldGenerator, polarDiagram, edgeStart, edgeEnd,
|
||||
correct1Turner,
|
||||
true,
|
||||
timeStepMilliseconds, minimumDistanceMeters);
|
||||
|
||||
List<TimedPositionWithSpeed> path = pathGenerator.getIntersectionOptimalTowardWind(windFieldGenerator,
|
||||
polarDiagram, edgeStart, edgeEnd, correct1Turner, true, timeStepMilliseconds, minimumDistanceMeters);
|
||||
|
||||
return new Response1TurnerDTO(SimulatorServiceUtils.toSimulatorWindDTOList(path), SimulatorServiceUtils.toSimulatorWindDTO(leftSide1Turner),
|
||||
SimulatorServiceUtils.toSimulatorWindDTO(rightSide1Turner), oldMovedPosition,
|
||||
@@ -607,7 +643,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
selectedRaceIndex = 0;
|
||||
}
|
||||
|
||||
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, null, null, SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, null, null, null,
|
||||
SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
|
||||
return simulator.getLegsNames(selectedRaceIndex);
|
||||
}
|
||||
@@ -615,7 +652,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
@Override
|
||||
public List<String> getRacesNames() {
|
||||
|
||||
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, null, null, SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, null, null, null,
|
||||
SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
|
||||
return simulator.getRacesNames();
|
||||
}
|
||||
@@ -627,9 +665,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
selectedRaceIndex = 0;
|
||||
}
|
||||
|
||||
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, null, null, SailingSimulatorConstants.ModeMeasured,true, true));
|
||||
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, null, null, null,
|
||||
SailingSimulatorConstants.ModeMeasured, true, true));
|
||||
|
||||
return simulator.getComeptitorsNames(selectedRaceIndex);
|
||||
return simulator.getCompetitorsNames(selectedRaceIndex);
|
||||
}
|
||||
|
||||
private void retreiveWindControlParameters(WindPatternDisplay pattern) {
|
||||
@@ -687,11 +726,11 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
|
||||
SimulatorWindDTO result = new SimulatorWindDTO();
|
||||
if (speedWithBearing == null) {
|
||||
result.trueWindBearingDeg = 0.0;
|
||||
result.trueWindSpeedInKnots = 0.0;
|
||||
result.trueWindBearingDeg = 0.0;
|
||||
result.trueWindSpeedInKnots = 0.0;
|
||||
} else {
|
||||
result.trueWindBearingDeg = speedWithBearing.getBearing().getDegrees();
|
||||
result.trueWindSpeedInKnots = speedWithBearing.getKnots();
|
||||
result.trueWindBearingDeg = speedWithBearing.getBearing().getDegrees();
|
||||
result.trueWindSpeedInKnots = speedWithBearing.getKnots();
|
||||
}
|
||||
|
||||
if (position != null) {
|
||||
@@ -779,9 +818,9 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: throws null pointer exception for when reading serialized paths.
|
||||
//TODO: should windlines also be serialized?
|
||||
//logger.info("Added : " + windFieldDTO.getWindLinesDTO().getWindLinesMap().size() + " wind lines");
|
||||
// TODO: throws null pointer exception for when reading serialized paths.
|
||||
// TODO: should windlines also be serialized?
|
||||
// logger.info("Added : " + windFieldDTO.getWindLinesDTO().getWindLinesMap().size() + " wind lines");
|
||||
}
|
||||
|
||||
private void getWindLinesFromEndLine(WindFieldGenerator wf, WindFieldDTO windFieldDTO, TimePoint startTime,
|
||||
@@ -850,22 +889,49 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
}
|
||||
}
|
||||
|
||||
private SimulatedPathsEvenTimedResultDTO getSimulatedPathsEvenTimed(List<Position> course, WindFieldGenerator wf, char mode,
|
||||
SimulatorUISelectionDTO selection, boolean showOmniscient, boolean showOpportunist) throws ConfigurationException {
|
||||
|
||||
private SimulatedPathsEvenTimedResultDTO getSimulatedPathsEvenTimed(List<Position> course, WindFieldGenerator wf,
|
||||
char mode, SimulatorUISelectionDTO selection, boolean showOmniscient, boolean showOpportunist)
|
||||
throws ConfigurationException {
|
||||
LOGGER.info("Retrieving simulated paths");
|
||||
|
||||
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(selection.boatClassIndex);
|
||||
PolarDiagram pd = polarDiagramAndNotificationMessage.getA();
|
||||
|
||||
SimulationParameters sp = new SimulationParametersImpl(course, pd, wf, mode, showOmniscient, showOpportunist);
|
||||
SailingSimulator simulator = new SailingSimulatorImpl(sp);
|
||||
|
||||
Map<String, Path> pathsAndNames = null;
|
||||
|
||||
pathsAndNames = simulator.getAllPathsEvenTimed(wf.getTimeStep().asMillis(),
|
||||
(mode == SailingSimulatorConstants.ModeMeasured) ? SimulatorServiceUtils.toSimulatorUISelection(selection) : null);
|
||||
|
||||
int[] gridRes = wf.getGridResolution();
|
||||
Position[] gridArea = wf.getGridAreaGps();
|
||||
LOGGER.info("showOmniscient : "+showOmniscient);
|
||||
LOGGER.info("showOpportunist: "+showOpportunist);
|
||||
if (gridArea != null) {
|
||||
// initialize grid of supporting location for windfield
|
||||
Grid bd = new CurvedGrid(gridArea[0], gridArea[1]);
|
||||
// set base wind bearing
|
||||
wf.getWindParameters().baseWindBearing += bd.getSouth().getDegrees();
|
||||
LOGGER.info("base wind: " + pd.getWind().getKnots() + " kn, "
|
||||
+ ((wf.getWindParameters().baseWindBearing) % 360.0) + "\u00B0");
|
||||
// set water current
|
||||
SpeedWithBearing current = new KnotSpeedWithBearingImpl(wf.getWindParameters().curSpeed, new DegreeBearingImpl(wf.getWindParameters().curBearing));
|
||||
if (wf.getWindParameters().curSpeed > 0) {
|
||||
pd.initializeSOGwithCurrent(); // polar-diagram is extended with data to support water currents
|
||||
}
|
||||
pd.setCurrent(current);
|
||||
if (pd.getCurrent() != null) {
|
||||
LOGGER.info("water current: " + pd.getCurrent().getKnots() + " kn, "
|
||||
+ pd.getCurrent().getBearing().getDegrees() + "\u00B0");
|
||||
}
|
||||
wf.setBoundary(bd);
|
||||
Position[][] positionGrid = bd.generatePositions(gridRes[0], gridRes[1], gridRes[2], gridRes[3]);
|
||||
wf.setPositionGrid(positionGrid);
|
||||
wf.generate(wf.getStartTime(), wf.getEndTime(), wf.getTimeStep());
|
||||
}
|
||||
SimulationParameters sp = new SimulationParametersImpl(course, pd, wf, null, mode, showOmniscient, showOpportunist);
|
||||
Map<PathType, Path> pathsAndNames = null;
|
||||
try {
|
||||
pathsAndNames = simulationService.getAllPathsEvenTimed(sp, wf.getTimeStep().asMillis());
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
int noOfPaths = pathsAndNames.size();
|
||||
if (mode == SailingSimulatorConstants.ModeMeasured) {
|
||||
noOfPaths++; // the last path is the polyline
|
||||
@@ -878,20 +944,21 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
pathDTOs[0] = this.getPolylinePathDTO(pathsAndNames.get("6#GPS Poly"), pathsAndNames.get("7#GPS Track"));
|
||||
}
|
||||
|
||||
for (Entry<String, Path> entry : pathsAndNames.entrySet()) {
|
||||
LOGGER.info("Path " + entry.getKey());
|
||||
for (Entry<PathType, Path> entry : pathsAndNames.entrySet()) {
|
||||
LOGGER.info("Path " + entry.getKey().getTxtId());
|
||||
|
||||
// NOTE: pathName convention is: sort-digit + "#" + path-name
|
||||
// pathsAndNames is TreeMap which ensures sorting
|
||||
pathDTOs[index] = new PathDTO(entry.getKey());
|
||||
// pathsAndNames is TreeMap which ensures sorting
|
||||
pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
|
||||
|
||||
// fill pathDTO with path points where speed is true wind speed
|
||||
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
|
||||
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
|
||||
wList.add(createSimulatorWindDTO(p));
|
||||
}
|
||||
|
||||
pathDTOs[index].setPoints(wList);
|
||||
pathDTOs[index].setAlgorithmTimedOut(entry.getValue().getAlgorithmTimedOut());
|
||||
pathDTOs[index].setMixedLeg(entry.getValue().getMixedLeg());
|
||||
|
||||
index--;
|
||||
}
|
||||
@@ -901,9 +968,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
rcDTO = new RaceMapDataDTO();
|
||||
rcDTO.coursePositions = new CoursePositionsDTO();
|
||||
rcDTO.coursePositions.waypointPositions = new ArrayList<>();
|
||||
Path rc = simulator.getRaceCourse();
|
||||
rcDTO.coursePositions.waypointPositions.add(rc.getPathPoints().get(0).getPosition());
|
||||
rcDTO.coursePositions.waypointPositions.add(rc.getPathPoints().get(1).getPosition());
|
||||
rcDTO.coursePositions.waypointPositions.add(course.get(0));
|
||||
rcDTO.coursePositions.waypointPositions.add(course.get(1));
|
||||
} else {
|
||||
rcDTO = null;
|
||||
}
|
||||
@@ -963,7 +1029,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
|
||||
List<TimedPositionWithSpeed> polylinePoints = gpsTrackPoints.subList(startPointIndex, endPointIndex + 1);
|
||||
|
||||
List<TimedPositionWithSpeed> turns = (new PathImpl(polylinePoints, null)).getTurns();
|
||||
List<TimedPositionWithSpeed> turns = (new PathImpl(polylinePoints, null, false /* algorithmTimedOut */, false /* mixedLeg */)).getTurns();
|
||||
// PathImpl.saveToGpxFile(new PathImpl(turns, null), "C:\\gps_path_turns_20deg_not_even_timed.gpx");
|
||||
|
||||
List<SimulatorWindDTO> points = new ArrayList<SimulatorWindDTO>();
|
||||
@@ -977,8 +1043,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
isTurn = false;
|
||||
|
||||
for (TimedPositionWithSpeed turn : turns) {
|
||||
if (turn.getPosition().getLatDeg() == point.getPosition().getLatDeg() && turn.getPosition().getLngDeg() == point.getPosition().getLngDeg()
|
||||
&& turn.getTimePoint().asMillis() == point.getTimePoint().asMillis() && turn.getSpeed().getKnots() == point.getSpeed().getKnots()
|
||||
if (turn.getPosition().getLatDeg() == point.getPosition().getLatDeg()
|
||||
&& turn.getPosition().getLngDeg() == point.getPosition().getLngDeg()
|
||||
&& turn.getTimePoint().asMillis() == point.getTimePoint().asMillis()
|
||||
&& turn.getSpeed().getKnots() == point.getSpeed().getKnots()
|
||||
&& turn.getSpeed().getBearing().getDegrees() == point.getSpeed().getBearing().getDegrees()) {
|
||||
isTurn = true;
|
||||
break;
|
||||
@@ -989,12 +1057,12 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
position = point.getPosition();
|
||||
|
||||
points.add(new SimulatorWindDTO(position.getLatDeg(), position.getLngDeg(), speedWithBearing.getKnots(),
|
||||
speedWithBearing.getBearing()
|
||||
.getDegrees(), point.getTimePoint().asMillis(), isTurn));
|
||||
speedWithBearing.getBearing().getDegrees(), point.getTimePoint().asMillis(), isTurn));
|
||||
}
|
||||
|
||||
PathDTO result = new PathDTO(POLYLINE_PATH_NAME);
|
||||
result.setPoints(points);
|
||||
result.setAlgorithmTimedOut(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1081,17 +1149,18 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
endPoint = points.get(index + 1);
|
||||
distanceMeters = startPoint.getDistance(endPoint).getMeters();
|
||||
|
||||
windAtTimePoint = useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis, gpsTrack)
|
||||
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
|
||||
windAtTimePoint = useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis,
|
||||
gpsTrack) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
|
||||
|
||||
boatBearingDeg = SimulatorServiceUtils.getInitialBearing(startPoint, endPoint);
|
||||
polarDiagram.setWind(windAtTimePoint);
|
||||
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg)).getMetersPerSecond();
|
||||
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg))
|
||||
.getMetersPerSecond();
|
||||
stepTimeMilliseconds = (long) ((distanceMeters / boatSpeedMetersPerSecond) * 1000);
|
||||
|
||||
// problem right here: boatSpeed might be 0 for very small distances
|
||||
// this is a rough fix
|
||||
if(boatSpeedMetersPerSecond == 0.0) {
|
||||
if (boatSpeedMetersPerSecond == 0.0) {
|
||||
stepTimeMilliseconds = 1000;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -25,11 +25,12 @@ public class CompactRaceMapDataDTO implements IsSerializable {
|
||||
private CoursePositionsDTO coursePositions;
|
||||
private List<SidelineDTO> courseSidelines;
|
||||
private List<CompactQuickRankDTO> quickRanks;
|
||||
private int simulationResultVersion;
|
||||
|
||||
CompactRaceMapDataDTO() {}
|
||||
|
||||
public CompactRaceMapDataDTO(Map<CompetitorDTO, List<GPSFixDTO>> boatPositions, CoursePositionsDTO coursePositions,
|
||||
List<SidelineDTO> courseSidelines, List<QuickRankDTO> quickRanks) {
|
||||
List<SidelineDTO> courseSidelines, List<QuickRankDTO> quickRanks, int simulationResultVersion) {
|
||||
this.boatPositionsByCompetitorIdAsString = new HashMap<String, List<GPSFixDTO>>();
|
||||
for (Map.Entry<CompetitorDTO, List<GPSFixDTO>> e : boatPositions.entrySet()) {
|
||||
this.boatPositionsByCompetitorIdAsString.put(e.getKey().getIdAsString(), e.getValue());
|
||||
@@ -43,6 +44,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
|
||||
}
|
||||
this.courseSidelines = courseSidelines;
|
||||
this.coursePositions = coursePositions;
|
||||
this.simulationResultVersion = simulationResultVersion;
|
||||
}
|
||||
|
||||
public RaceMapDataDTO getRaceMapDataDTO(Iterable<CompetitorDTO> competitors) {
|
||||
@@ -68,6 +70,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
|
||||
result.boatPositions.put(competitor, e.getValue());
|
||||
}
|
||||
}
|
||||
result.simulationResultVersion = simulationResultVersion;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+3
@@ -13,6 +13,9 @@ public class CoursePositionsDTO implements IsSerializable {
|
||||
public List<Position> finishMarkPositions;
|
||||
public Set<MarkDTO> marks;
|
||||
|
||||
public int totalLegsCount;
|
||||
public int currentLegNumber;
|
||||
|
||||
/**
|
||||
* <code>null</code> if the start waypoint does not have exactly two marks with valid positions; in this case,
|
||||
* {@link #startLineAdvantageousSide}, {@link #startLineAdvantageInMeters} and {@link #startLineLengthInMeters} are
|
||||
|
||||
+18
-1
@@ -7,9 +7,10 @@ import com.sap.sailing.domain.common.dto.NamedDTO;
|
||||
public class PathDTO extends NamedDTO {
|
||||
private static final long serialVersionUID = 2381814072763342186L;
|
||||
private List<SimulatorWindDTO> points;
|
||||
private boolean algorithmTimedOut;
|
||||
private boolean mixedLeg;
|
||||
|
||||
public PathDTO() {
|
||||
|
||||
}
|
||||
|
||||
public PathDTO(final String name) {
|
||||
@@ -31,5 +32,21 @@ public class PathDTO extends NamedDTO {
|
||||
|
||||
return points.get(points.size() - 1).timepoint - points.get(0).timepoint;
|
||||
}
|
||||
|
||||
public boolean getAlgorithmTimedOut() {
|
||||
return this.algorithmTimedOut;
|
||||
}
|
||||
|
||||
public void setAlgorithmTimedOut(boolean algorithmTimedOut) {
|
||||
this.algorithmTimedOut = algorithmTimedOut;
|
||||
}
|
||||
|
||||
public boolean getMixedLeg() {
|
||||
return this.mixedLeg;
|
||||
}
|
||||
|
||||
public void setMixedLeg(boolean mixedLeg) {
|
||||
this.mixedLeg = mixedLeg;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -12,4 +12,5 @@ public class RaceMapDataDTO implements IsSerializable {
|
||||
public CoursePositionsDTO coursePositions;
|
||||
public List<SidelineDTO> courseSidelines;
|
||||
public LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanks;
|
||||
public int simulationResultVersion;
|
||||
}
|
||||
+12
-1
@@ -6,6 +6,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
|
||||
public class SimulatorResultsDTO implements IsSerializable {
|
||||
|
||||
private int version;
|
||||
private Date startTime;
|
||||
private long timeStep;
|
||||
private long legDuration;
|
||||
@@ -15,6 +16,7 @@ public class SimulatorResultsDTO implements IsSerializable {
|
||||
private String notificationMessage;
|
||||
|
||||
public SimulatorResultsDTO(){
|
||||
this.version = 0;
|
||||
this.startTime = null;
|
||||
this.timeStep = 0;
|
||||
this.legDuration = 0;
|
||||
@@ -24,7 +26,8 @@ public class SimulatorResultsDTO implements IsSerializable {
|
||||
this.notificationMessage = "";
|
||||
}
|
||||
|
||||
public SimulatorResultsDTO(final Date startTime, final long timeStep, final long legDuration, final RaceMapDataDTO raceCourse, final PathDTO[] paths, final WindFieldDTO windField, final String notificationMessage) {
|
||||
public SimulatorResultsDTO(final int version, final Date startTime, final long timeStep, final long legDuration, final RaceMapDataDTO raceCourse, final PathDTO[] paths, final WindFieldDTO windField, final String notificationMessage) {
|
||||
this.version = version;
|
||||
this.startTime = startTime;
|
||||
this.timeStep = timeStep;
|
||||
this.legDuration = legDuration;
|
||||
@@ -34,6 +37,14 @@ public class SimulatorResultsDTO implements IsSerializable {
|
||||
this.notificationMessage = notificationMessage;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return this.startTime;
|
||||
}
|
||||
|
||||
+95
-32
@@ -14,6 +14,8 @@ import com.google.gwt.maps.client.base.Point;
|
||||
import com.google.gwt.maps.client.controls.ControlPosition;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.LegIdentifierImpl;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.actions.GetSimulationAction;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
@@ -40,6 +42,8 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
public static final String GET_SIMULATION_CATEGORY = "getSimulation";
|
||||
private final String textColor = "Black";
|
||||
private final String textFont = "10pt OpenSansRegular";
|
||||
private String algorithmTimedOutText = "out-of-bounds";
|
||||
private String mixedLegText = "ambiguous wind";
|
||||
private int xOffset = 0;
|
||||
private int yOffset = 0; //150;
|
||||
private double rectWidth = 20;
|
||||
@@ -52,7 +56,6 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
private SimulatorResultsDTO simulationResult;
|
||||
private PathDTO racePath;
|
||||
private int raceLeg = 0;
|
||||
private Date prevStartTime;
|
||||
private Canvas simulationLegend;
|
||||
|
||||
public RaceSimulationOverlay(MapWidget map, int zIndex, RegattaAndRaceIdentifier raceIdentifier, SailingServiceAsync sailingService, StringMessages stringMessages, AsyncActionsExecutor asyncActionsExecutor, CoordinateSystem coordinateSystem) {
|
||||
@@ -64,16 +67,28 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
this.colors = new ColorPaletteGenerator();
|
||||
}
|
||||
|
||||
public void updateLeg(int newLeg, Date newTime, boolean clearCanvas) {
|
||||
if ((newLeg != raceLeg) && (this.isVisible())) {
|
||||
public void updateLeg(int newLeg, boolean clearCanvas, int newVersion) {
|
||||
if (((newLeg != raceLeg)||((newLeg == raceLeg)&&(newVersion != (simulationResult==null ? 0 : simulationResult.getVersion())))) && (this.isVisible())) {
|
||||
raceLeg = newLeg;
|
||||
if (clearCanvas) {
|
||||
this.clearCanvas();
|
||||
}
|
||||
this.simulate(newTime);
|
||||
this.simulate(newLeg);
|
||||
}
|
||||
}
|
||||
|
||||
public LegIdentifier getLegIdentifier() {
|
||||
return new LegIdentifierImpl(raceIdentifier, String.valueOf(raceLeg));
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
if (this.simulationResult == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return this.simulationResult.getVersion();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean isVisible) {
|
||||
super.setVisible(isVisible);
|
||||
@@ -146,8 +161,12 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
Context2d ctxt = canvas.getContext2d();
|
||||
PathDTO[] paths = simulationResult.getPaths();
|
||||
boolean first = true;
|
||||
int colorIdx = paths.length - 1;
|
||||
int colorIdx = paths.length;
|
||||
for (PathDTO path : paths) {
|
||||
colorIdx--;
|
||||
if (path.getMixedLeg()) {
|
||||
continue;
|
||||
}
|
||||
List<SimulatorWindDTO> points = path.getPoints();
|
||||
ctxt.setLineWidth(3.0);
|
||||
ctxt.setGlobalAlpha(0.7);
|
||||
@@ -175,7 +194,6 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
ctxt.closePath();
|
||||
ctxt.stroke();
|
||||
}
|
||||
colorIdx--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,22 +208,57 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
txtmet = context2d.measureText("00:00:00");
|
||||
double timewidth = txtmet.getWidth();
|
||||
double txtmaxwidth = 0.0;
|
||||
txtmet = context2d.measureText(racePath.getName().split("#")[1]);
|
||||
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
|
||||
PathDTO[] paths = this.simulationResult.getPaths();
|
||||
for (PathDTO path : paths) {
|
||||
txtmet = context2d.measureText(path.getName());
|
||||
if (racePath != null) {
|
||||
txtmet = context2d.measureText(racePath.getName().split("#")[1]);
|
||||
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
|
||||
}
|
||||
//canvas.setSize(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0+"px", rectHeight*(paths.length+1)+"px");
|
||||
int canvasWidth = (int)Math.ceil(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0 + 5.0);
|
||||
int canvasHeight = (int)Math.ceil(yOffset + rectHeight*(paths.length+1));
|
||||
setCanvasSize(canvas, canvasWidth, canvasHeight);
|
||||
drawRectangleWithText(context2d, xOffset, yOffset, "rgba(255,255,255,0.8);",
|
||||
racePath.getName().split("#")[1], getFormattedTime(racePath.getPathTime()), txtmaxwidth, timewidth);
|
||||
boolean containsTimeOut = false;
|
||||
boolean containsMixedLeg = false;
|
||||
PathDTO[] paths = this.simulationResult.getPaths();
|
||||
for (PathDTO path : paths) {
|
||||
drawRectangleWithText(context2d, xOffset, yOffset + (paths.length-index) * rectHeight, this.colors.getColor(paths.length-1-index),
|
||||
path.getName().split("#")[1], getFormattedTime(path.getPathTime()), txtmaxwidth, timewidth);
|
||||
if (path.getAlgorithmTimedOut()) {
|
||||
containsTimeOut = true;
|
||||
}
|
||||
if (path.getMixedLeg()) {
|
||||
containsMixedLeg = true;
|
||||
}
|
||||
txtmet = context2d.measureText(path.getName().split("#")[1]);
|
||||
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
|
||||
}
|
||||
double newwidth = 0;
|
||||
double deltaTime = 0;
|
||||
double deltaMixedLeg = 0;
|
||||
double deltaTimeOut = 0;
|
||||
double mixedLegWidth = 0;
|
||||
if (containsMixedLeg) {
|
||||
txtmet = context2d.measureText(mixedLegText);
|
||||
mixedLegWidth = txtmet.getWidth();
|
||||
newwidth = Math.max(timewidth, mixedLegWidth);
|
||||
}
|
||||
double timeOutWidth = 0;
|
||||
if (containsTimeOut) {
|
||||
txtmet = context2d.measureText(algorithmTimedOutText);
|
||||
timeOutWidth = txtmet.getWidth();
|
||||
newwidth = Math.max(newwidth, timeOutWidth);
|
||||
}
|
||||
if (containsMixedLeg||containsTimeOut) {
|
||||
deltaTime = newwidth - timewidth;
|
||||
deltaMixedLeg = newwidth - mixedLegWidth;
|
||||
deltaTimeOut = newwidth - timeOutWidth;
|
||||
timewidth = newwidth;
|
||||
}
|
||||
//canvas.setSize(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0+"px", rectHeight*(paths.length+1)+"px");
|
||||
int canvasWidth = (int)Math.ceil(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0 + 10.0);
|
||||
int canvasHeight = (int)Math.ceil(yOffset + rectHeight*(paths.length + (racePath == null? 0 : 1)));
|
||||
setCanvasSize(canvas, canvasWidth, canvasHeight);
|
||||
if (racePath != null) {
|
||||
drawRectangleWithText(context2d, xOffset, yOffset, null,
|
||||
racePath.getName().split("#")[1], getFormattedTime(racePath.getPathTime()), txtmaxwidth, timewidth, deltaTime);
|
||||
}
|
||||
for (PathDTO path : paths) {
|
||||
String timeText = (path.getMixedLeg() ? mixedLegText : (path.getAlgorithmTimedOut() ? algorithmTimedOutText : getFormattedTime(path.getPathTime())));
|
||||
drawRectangleWithText(context2d, xOffset, yOffset + (paths.length-index-(racePath==null?1:0)) * rectHeight, this.colors.getColor(paths.length-1-index),
|
||||
path.getName().split("#")[1], timeText, txtmaxwidth, timewidth, (path.getMixedLeg()?deltaMixedLeg:(path.getAlgorithmTimedOut()?deltaTimeOut:deltaTime)));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -223,17 +276,19 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
context2d.fillRect(x, y, rectWidth, rectHeight);
|
||||
}
|
||||
|
||||
protected void drawRectangleWithText(Context2d context2d, double x, double y, String color, String text, String time, double textmaxwidth, double timewidth) {
|
||||
protected void drawRectangleWithText(Context2d context2d, double x, double y, String color, String text, String time, double textmaxwidth, double timewidth, double xdelta) {
|
||||
double offset = 3.0;
|
||||
context2d.setFont(textFont);
|
||||
drawRectangle(context2d, x, y, color);
|
||||
if (color != null) {
|
||||
drawRectangle(context2d, x, y, color);
|
||||
}
|
||||
context2d.setGlobalAlpha(0.80);
|
||||
context2d.setFillStyle("white");
|
||||
context2d.fillRect(x + rectWidth, y, 15.0 + textmaxwidth + timewidth, rectHeight);
|
||||
context2d.fillRect(x + (color==null?0:rectWidth), y, 20.0 + textmaxwidth + timewidth + (color==null?rectWidth:0), rectHeight);
|
||||
context2d.setGlobalAlpha(1.0);
|
||||
context2d.setFillStyle(textColor);
|
||||
context2d.fillText(text, x + rectWidth + 5.0, y + 12.0 + offset);
|
||||
context2d.fillText(time, x + rectWidth + textmaxwidth + 10.0, y + 12.0 + offset);
|
||||
context2d.fillText(time, x + rectWidth + textmaxwidth + xdelta + 15.0, y + 12.0 + offset);
|
||||
}
|
||||
|
||||
protected String getFormattedTime(long pathTime) {
|
||||
@@ -244,8 +299,9 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
return pathTimeStr;
|
||||
}
|
||||
|
||||
public void simulate(Date from) {
|
||||
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, raceIdentifier, from, prevStartTime);
|
||||
public void simulate(int leg) {
|
||||
LegIdentifier legIdentifier = new LegIdentifierImpl(raceIdentifier, String.valueOf(leg));
|
||||
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, legIdentifier);
|
||||
asyncActionsExecutor.execute(getSimulation, GET_SIMULATION_CATEGORY,
|
||||
new MarkedAsyncCallback<>(new AsyncCallback<SimulatorResultsDTO>() {
|
||||
@Override
|
||||
@@ -259,19 +315,26 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
public void onSuccess(SimulatorResultsDTO result) {
|
||||
// store results
|
||||
if (result != null) {
|
||||
prevStartTime = result.getStartTime();
|
||||
if (result.getPaths() != null) {
|
||||
simulationResult = result;
|
||||
PathDTO[] paths = result.getPaths();
|
||||
racePath = new PathDTO();
|
||||
List<SimulatorWindDTO> racePathPoints = new ArrayList<SimulatorWindDTO>();
|
||||
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint));
|
||||
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint + result.getLegDuration()));
|
||||
racePath.setPoints(racePathPoints);
|
||||
racePath.setName("0#Race");
|
||||
if (result.getLegDuration() > 0) {
|
||||
racePath = new PathDTO();
|
||||
List<SimulatorWindDTO> racePathPoints = new ArrayList<SimulatorWindDTO>();
|
||||
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint));
|
||||
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint + result.getLegDuration()));
|
||||
racePath.setPoints(racePathPoints);
|
||||
racePath.setName("0#Race");
|
||||
} else {
|
||||
racePath = null;
|
||||
}
|
||||
clearCanvas();
|
||||
drawPaths();
|
||||
}
|
||||
} else {
|
||||
raceLeg = 0;
|
||||
simulationResult = null;
|
||||
clearCanvas();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
+13
-1
@@ -43,6 +43,8 @@ public class PathCanvasOverlay extends WindFieldCanvasOverlay implements Named {
|
||||
private long totalTimeMilliseconds = 0;
|
||||
|
||||
private String name;
|
||||
private boolean algorithmTimedOut;
|
||||
private boolean mixedLeg;
|
||||
|
||||
private String pathColor = "Green";
|
||||
|
||||
@@ -56,9 +58,11 @@ public class PathCanvasOverlay extends WindFieldCanvasOverlay implements Named {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public PathCanvasOverlay(MapWidget map, int zIndex, String name, Timer timer, WindFieldGenParamsDTO windParams, CoordinateSystem coordinateSystem) {
|
||||
public PathCanvasOverlay(MapWidget map, int zIndex, String name, Timer timer, WindFieldGenParamsDTO windParams, boolean algorithmTimedOut, boolean mixedLeg, CoordinateSystem coordinateSystem) {
|
||||
super(map, zIndex, timer, windParams, coordinateSystem);
|
||||
this.name = name;
|
||||
this.algorithmTimedOut = algorithmTimedOut;
|
||||
this.mixedLeg = mixedLeg;
|
||||
}
|
||||
|
||||
public PathCanvasOverlay(MapWidget map, int zIndex, String name, long totalTimeMilliseconds, CoordinateSystem coordinateSystem) {
|
||||
@@ -250,6 +254,14 @@ public class PathCanvasOverlay extends WindFieldCanvasOverlay implements Named {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean getAlgorithmTimedOut() {
|
||||
return algorithmTimedOut;
|
||||
}
|
||||
|
||||
public boolean getMixedLeg() {
|
||||
return mixedLeg;
|
||||
}
|
||||
|
||||
public long getPathTime() {
|
||||
if (totalTimeIsGiven) {
|
||||
return totalTimeMilliseconds;
|
||||
|
||||
+37
-4
@@ -40,6 +40,8 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
|
||||
|
||||
private String textColor = "Black";
|
||||
private String textFont = "10pt OpenSansRegular";
|
||||
private String algorithmTimedOutText = "out-of-bounds";
|
||||
private String mixedLegText = "ambiguous wind";
|
||||
|
||||
public PathLegendCanvasOverlay(MapWidget map, int zIndex, char mode, CoordinateSystem coordinateSystem) {
|
||||
super(map, zIndex, coordinateSystem);
|
||||
@@ -82,13 +84,44 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
|
||||
txtmet = context2d.measureText("00:00:00");
|
||||
double timewidth = txtmet.getWidth();
|
||||
double txtmaxwidth = 0.0;
|
||||
boolean containsTimeOut = false;
|
||||
boolean containsMixedLeg = false;
|
||||
for (PathCanvasOverlay path : pathOverlays) {
|
||||
if (path.getAlgorithmTimedOut()) {
|
||||
containsTimeOut = true;
|
||||
}
|
||||
if (path.getMixedLeg()) {
|
||||
containsMixedLeg = true;
|
||||
}
|
||||
txtmet = context2d.measureText(path.getName());
|
||||
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
|
||||
}
|
||||
double newwidth = 0;
|
||||
double deltaTime = 0;
|
||||
double deltaMixedLeg = 0;
|
||||
double deltaTimeOut = 0;
|
||||
double mixedLegWidth = 0;
|
||||
if (containsMixedLeg) {
|
||||
txtmet = context2d.measureText(mixedLegText);
|
||||
mixedLegWidth = txtmet.getWidth();
|
||||
newwidth = Math.max(timewidth, mixedLegWidth);
|
||||
}
|
||||
double timeOutWidth = 0;
|
||||
if (containsTimeOut) {
|
||||
txtmet = context2d.measureText(algorithmTimedOutText);
|
||||
timeOutWidth = txtmet.getWidth();
|
||||
newwidth = Math.max(newwidth, timeOutWidth);
|
||||
}
|
||||
if (containsMixedLeg||containsTimeOut) {
|
||||
deltaTime = newwidth - timewidth;
|
||||
deltaMixedLeg = newwidth - mixedLegWidth;
|
||||
deltaTimeOut = newwidth - timeOutWidth;
|
||||
timewidth = newwidth;
|
||||
}
|
||||
for (PathCanvasOverlay path : pathOverlays) {
|
||||
String timeText = (path.getMixedLeg() ? mixedLegText : (path.getAlgorithmTimedOut() ? algorithmTimedOutText : getFormattedTime(path.getPathTime())));
|
||||
drawRectangleWithText(xOffset, yOffset + (pathOverlays.size()-1-index) * rectHeight, path.getPathColor(),
|
||||
path.getName(), getFormattedTime(path.getPathTime()),txtmaxwidth,timewidth);
|
||||
path.getName(), timeText, txtmaxwidth, timewidth, (path.getMixedLeg()?deltaMixedLeg:(path.getAlgorithmTimedOut()?deltaTimeOut:deltaTime)));
|
||||
index++;
|
||||
}
|
||||
//
|
||||
@@ -170,7 +203,7 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
|
||||
context2d.fillRect(x, y, rectWidth, rectHeight);
|
||||
}
|
||||
|
||||
protected void drawRectangleWithText(double x, double y, String color, String text, String time, double textmaxwidth, double timewidth) {
|
||||
protected void drawRectangleWithText(double x, double y, String color, String text, String time, double textmaxwidth, double timewidth, double xdelta) {
|
||||
|
||||
double offset = 3.0;
|
||||
|
||||
@@ -179,11 +212,11 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
|
||||
drawRectangle(x, y, color);
|
||||
context2d.setGlobalAlpha(0.80);
|
||||
context2d.setFillStyle("white");
|
||||
context2d.fillRect(x + rectWidth, y, 15.0 + textmaxwidth + timewidth, rectHeight);
|
||||
context2d.fillRect(x + rectWidth, y, 20.0 + textmaxwidth + timewidth, rectHeight);
|
||||
context2d.setGlobalAlpha(1.0);
|
||||
context2d.setFillStyle(textColor);
|
||||
context2d.fillText(text, x + rectWidth + 5.0, y + 12.0 + offset);
|
||||
context2d.fillText(time, x + rectWidth + textmaxwidth + 10.0, y + 12.0 + offset);
|
||||
context2d.fillText(time, x + rectWidth + textmaxwidth + xdelta + 15.0, y + 12.0 + offset);
|
||||
}
|
||||
|
||||
protected String getFormattedTime(long pathTime) {
|
||||
|
||||
+10
-3
@@ -18,8 +18,8 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
|
||||
private List<SimulatorWindDTO> windDTOToDraw;
|
||||
|
||||
public ReplayPathCanvasOverlay(MapWidget map, int zIndex, final String name, final Timer timer,
|
||||
WindFieldGenParamsDTO windParams, CoordinateSystem coordinateSystem) {
|
||||
super(map, zIndex, name, timer, windParams, coordinateSystem);
|
||||
WindFieldGenParamsDTO windParams, boolean algorithmTimedOut, boolean mixedLeg, CoordinateSystem coordinateSystem) {
|
||||
super(map, zIndex, name, timer, windParams, algorithmTimedOut, mixedLeg, coordinateSystem);
|
||||
this.displayWindAlongPath = false;
|
||||
windDTOToDraw = null;
|
||||
canvas.setStyleName("replayPanel");
|
||||
@@ -34,6 +34,10 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
|
||||
@Override
|
||||
public void timeChanged(final Date newTime, Date oldTime) {
|
||||
|
||||
if (windFieldDTO == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas.getContext2d().clearRect(0/* canvas.getAbsoluteLeft() */, 0/* canvas.getAbsoluteTop() */,
|
||||
canvas.getCoordinateSpaceWidth(), canvas.getCoordinateSpaceHeight());
|
||||
|
||||
@@ -50,7 +54,10 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
|
||||
|
||||
@Override
|
||||
public boolean shallStop() {
|
||||
if (!isVisible() || windDTOToDraw == null || windFieldDTO == null) {
|
||||
if (windDTOToDraw == null || windFieldDTO == null) {
|
||||
return false;
|
||||
}
|
||||
if (!isVisible()) {
|
||||
return true;
|
||||
}
|
||||
if (windDTOToDraw.size() >= (windFieldDTO.getMatrix().size()-1)) {
|
||||
|
||||
+10
-6
@@ -158,27 +158,31 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
|
||||
PathDTO currentPath = null;
|
||||
//String color = null;
|
||||
String pathName = null;
|
||||
boolean algorithmTimedOut = false;
|
||||
int noOfPaths = paths.length;
|
||||
|
||||
for (int index = 0; index < noOfPaths; ++index) {
|
||||
|
||||
currentPath = paths[index];
|
||||
pathName = currentPath.getName();
|
||||
algorithmTimedOut = currentPath.getAlgorithmTimedOut();
|
||||
//color = colorPalette.getColor(noOfPaths - 1 - index);
|
||||
|
||||
if (pathName.equals("Polyline")) {
|
||||
pathPolyline = createPathPolyline(currentPath);
|
||||
} else if (pathName.equals("GPS Poly")) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
|
||||
/* TODO Revisit for now creating a WindFieldDTO from the path */
|
||||
WindFieldDTO pathWindDTO = new WindFieldDTO();
|
||||
pathWindDTO.setMatrix(currentPath.getPoints());
|
||||
WindFieldDTO pathWindDTO = null;
|
||||
if (!currentPath.getMixedLeg()) {
|
||||
pathWindDTO = new WindFieldDTO();
|
||||
pathWindDTO.setMatrix(currentPath.getPoints());
|
||||
}
|
||||
|
||||
ReplayPathCanvasOverlay replayPathCanvasOverlay = new ReplayPathCanvasOverlay(map, SimulatorMapOverlaysZIndexes.PATH_ZINDEX,
|
||||
pathName.split("#")[1], timer, windParams, coordinateSystem);
|
||||
pathName.split("#")[1], timer, windParams, algorithmTimedOut, currentPath.getMixedLeg(), coordinateSystem);
|
||||
replayPathCanvasOverlays.add(replayPathCanvasOverlay);
|
||||
replayPathCanvasOverlay.setPathColor(colorPalette.getColor(Integer.parseInt(pathName.split("#")[0])-1));
|
||||
|
||||
@@ -205,7 +209,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
|
||||
legendCanvasOverlay.setPathOverlays(replayPathCanvasOverlays);
|
||||
|
||||
long tmpDurationTime = currentPath.getPathTime();
|
||||
if (tmpDurationTime > maxDurationTime) {
|
||||
if ((!currentPath.getMixedLeg())&&(!currentPath.getAlgorithmTimedOut())&&(tmpDurationTime > maxDurationTime)) {
|
||||
maxDurationTime = tmpDurationTime;
|
||||
}
|
||||
}
|
||||
|
||||
+56
-4
@@ -4,12 +4,64 @@
|
||||
<div id="mainContent">
|
||||
<h4 class="articleHeadline">What's New - Strategy Simulator</h4>
|
||||
<div class="innerContent">
|
||||
<h5 class="articleSubheadline">September 2014</h5>
|
||||
|
||||
<h5 class="articleSubheadline">October 2014</h5>
|
||||
<ul class="bulletList">
|
||||
<li>Point 1...
|
||||
</li>
|
||||
<li>Simulation is being integrated into the race board (see What's New in Sailing Analytics)</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">August 2014</h5>
|
||||
<ul class="bulletList">
|
||||
<li>Accuracy of optimal course calculation has been improved</li>
|
||||
<li>Streamlet motion is now calibrated to physical reality on large zoom levels of the map</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">April 2014</h5>
|
||||
<ul class="bulletList">
|
||||
<li>Wind is visualized using animated streamlets based on a swarm of particles which locally follow the wind</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">September 2013</h5>
|
||||
<ul class="bulletList">
|
||||
<li>Windbot based on RaspberryPi to construct real, spatially resolved wind vector fields from wind measurements</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">June 2013</h5>
|
||||
<ul class="bulletList">
|
||||
<li>Optimal courses shown as "Omniscient" are determined by an heuristic search algorithm greatly improving accuracy and runtime performance</li>
|
||||
<li>Sailing angles are represented with full numeric accuracy</li>
|
||||
<li>Water current is taken into account</li>
|
||||
<li>Support up- and downwind legs</li>
|
||||
<li>1-Click Simulation simplifies the user interaction</li>
|
||||
<li>Race course map for Kieler Woche and Travemuender Woche</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">March 2013</h5>
|
||||
<ul class="bulletList">
|
||||
<li>What-if simulation comparing sailed GPS-track and simulated course with changed locations of turns for
|
||||
answering questions like: would it have been advantageous to do the second turn a bit later?</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">February 2013</h5>
|
||||
<ul class="bulletList">
|
||||
<li>Strategy Simulator becomes a part of SAP's Sailing Analytics suite</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">December 2012</h5>
|
||||
<ul class="bulletList">
|
||||
<li>Polar diagram chart is available</li>
|
||||
<li>Multiple boat classes are supported based on polar diagrams in tabular format provided as CSV-files</li>
|
||||
<li>Several wind visualization approaches are supported: arrows on a grid, as well as, heatmap combined with bearing lines (either grid or integrated across race course)</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">June 2012</h5>
|
||||
<ul class="bulletList">
|
||||
<li>First upwind-only prototype of sailing simulation is available</li>
|
||||
<li>Optimal courses shown as "Omniscient" are calculated with an implementation of Dijkstra's algorithm on a rectangular spatial grid</li>
|
||||
<li>Wind is visualized by arrows which scale with wind speed</li>
|
||||
<li>Race course definition with 2 mouse clicks for start and end</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -13,4 +13,5 @@ Require-Bundle: org.hamcrest;bundle-version="1.1.0",
|
||||
com.sap.sailing.domain.test,
|
||||
com.sap.sse.common,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.tractrac.clientmodule;bundle-version="3.0.7"
|
||||
com.tractrac.clientmodule;bundle-version="3.0.7",
|
||||
com.sap.sailing.domain
|
||||
+1
-1
@@ -42,6 +42,7 @@ import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
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.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -49,7 +50,6 @@ 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.PolarDataMiner;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
+1
-1
@@ -12,8 +12,8 @@ import java.util.Random;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
|
||||
|
||||
public class IncrementalLeastSquaresTest {
|
||||
|
||||
+1
-1
@@ -7,8 +7,8 @@ import static org.junit.Assert.assertTrue;
|
||||
import org.hamcrest.number.IsCloseTo;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
|
||||
|
||||
public class IncrementalLinearRegressionOrderOneTest {
|
||||
|
||||
+3
-4
@@ -12,7 +12,6 @@ import java.text.ParseException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
@@ -27,11 +26,11 @@ import com.sap.sailing.domain.common.confidence.impl.ScalableDouble;
|
||||
import com.sap.sailing.domain.common.confidence.impl.ScalableWind;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.test.OnlineTracTracBasedTest;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tractracadapter.ReceiverType;
|
||||
import com.sap.sailing.polars.impl.PolarDataServiceImpl;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.util.kmeans.Cluster;
|
||||
@@ -117,7 +116,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
|
||||
IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException,
|
||||
CreateModelException {
|
||||
setUp("event_20110609_KielerWoch-505_Race_3");
|
||||
ManeuverBasedWindEstimationTrackImpl windTrack = new ManeuverBasedWindEstimationTrackImpl(new PolarDataServiceImpl(Executors.newFixedThreadPool(4)),
|
||||
ManeuverBasedWindEstimationTrackImpl windTrack = new ManeuverBasedWindEstimationTrackImpl(new PolarDataServiceImpl(),
|
||||
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000, /* waitForLatest */ true);
|
||||
final Map<Maneuver, Competitor> maneuvers = windTrack.getAllManeuvers(/* waitForLatest */ true);
|
||||
final int numberOfClusters = 16;
|
||||
@@ -153,7 +152,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
|
||||
}
|
||||
|
||||
private Wind getManeuverBasedAverageWind() throws NotEnoughDataHasBeenAddedException {
|
||||
ManeuverBasedWindEstimationTrackImpl windTrack = new ManeuverBasedWindEstimationTrackImpl(new PolarDataServiceImpl(Executors.newFixedThreadPool(4)),
|
||||
ManeuverBasedWindEstimationTrackImpl windTrack = new ManeuverBasedWindEstimationTrackImpl(new PolarDataServiceImpl(),
|
||||
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000, /* waitForLatest */ true);
|
||||
ScalableWind windSum = null;
|
||||
int count = 0;
|
||||
|
||||
@@ -7,9 +7,7 @@ Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-ClassPath: .
|
||||
Export-Package:
|
||||
com.sap.sailing.polars,
|
||||
com.sap.sailing.polars.data,
|
||||
com.sap.sailing.polars.factory,
|
||||
com.sap.sailing.polars.regression,
|
||||
com.sap.sailing.polars.windestimation
|
||||
Bundle-ActivationPolicy: lazy
|
||||
@@ -21,7 +19,9 @@ Require-Bundle:
|
||||
com.sap.sse.common,
|
||||
com.sap.sse,
|
||||
com.sap.sse.shared.android,
|
||||
org.apache.commons.math;bundle-version="2.1.0"
|
||||
org.apache.commons.math;bundle-version="2.1.0",
|
||||
org.eclipse.osgi
|
||||
Import-Package:
|
||||
com.sap.sailing.util,
|
||||
com.sap.sse.common
|
||||
Bundle-Activator: com.sap.sailing.polars.impl.Activator
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
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
@@ -1,16 +0,0 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.sap.sailing.polars.impl;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
|
||||
public class Activator implements BundleActivator {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Activator.class.getName());
|
||||
|
||||
private final Set<ServiceRegistration<?>> registrations = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
logger.info("Registering PolarDataService");
|
||||
registrations.add(context.registerService(PolarDataService.class, new PolarDataServiceImpl(), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
logger.info("Unregistering PolarDataService");
|
||||
for (ServiceRegistration<?> reg : registrations) {
|
||||
reg.unregister();
|
||||
}
|
||||
registrations.clear();
|
||||
}
|
||||
|
||||
}
|
||||
+33
-3
@@ -17,15 +17,18 @@ 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.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
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.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.sse.common.Util.Pair;
|
||||
import com.sap.sse.util.SmartFutureCache;
|
||||
|
||||
@@ -41,7 +44,7 @@ public class PolarDataServiceImpl implements PolarDataService {
|
||||
|
||||
private final PolarDataMiner polarDataMiner;
|
||||
|
||||
public PolarDataServiceImpl(Executor executor) {
|
||||
public PolarDataServiceImpl() {
|
||||
this.polarDataMiner = new PolarDataMiner();
|
||||
}
|
||||
|
||||
@@ -158,4 +161,31 @@ public class PolarDataServiceImpl implements PolarDataService {
|
||||
polarDataMiner.raceFinishedTracking(race);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BearingWithConfidence<Void> getManeuverAngle(BoatClass boatClass, LegType legType, Speed windSpeed)
|
||||
throws NotEnoughDataHasBeenAddedException {
|
||||
if (legType != LegType.DOWNWIND && legType != LegType.UPWIND) {
|
||||
throw new IllegalArgumentException("LegType needs to be upwind or downwind.");
|
||||
}
|
||||
if (boatClass == null || windSpeed == null) {
|
||||
throw new IllegalArgumentException("Boatclass and windspeed cannot be null.");
|
||||
}
|
||||
SpeedWithBearingWithConfidence<Void> port = getAverageSpeedWithBearing(boatClass, windSpeed, legType, Tack.PORT);
|
||||
SpeedWithBearingWithConfidence<Void> starboard = getAverageSpeedWithBearing(boatClass, windSpeed, legType,
|
||||
Tack.STARBOARD);
|
||||
double angleSumInDeg = Math.abs(port.getObject().getBearing().getDegrees())
|
||||
+ Math.abs(starboard.getObject().getBearing().getDegrees());
|
||||
Bearing bearing = new DegreeBearingImpl(angleSumInDeg);
|
||||
double confidence = (port.getConfidence() + starboard.getConfidence()) / 2;
|
||||
BearingWithConfidence<Void> bearingWithConfidence = new BearingWithConfidenceImpl<Void>(bearing, confidence,
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -14,10 +14,10 @@ import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.polars.impl.CubicEquation;
|
||||
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -48,7 +48,7 @@ public class AngleAndSpeedRegression {
|
||||
double estimatedAngle = angleRegression.getOrCreatePolynomialFunction().value(windSpeedInKnots);
|
||||
Bearing bearing = new DegreeBearingImpl(estimatedAngle);
|
||||
SpeedWithBearing speedWithBearing = new KnotSpeedWithBearingImpl(estimatedSpeed, bearing);
|
||||
return new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearing, /*FIXME*/ 0.5, null);
|
||||
return new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearing, Math.min(1, speedRegression.getNumberOfAddedPoints() / 100.0), null);
|
||||
}
|
||||
|
||||
public Set<SpeedWithBearingWithConfidence<Void>> estimateTrueWindSpeedAndAngleCandidates(Speed speedOverGround) throws NotEnoughDataHasBeenAddedException {
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
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.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.factories.GroupKeyFactory;
|
||||
|
||||
+1
-29
@@ -34,7 +34,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
|
||||
private final TrackedRace race;
|
||||
private final Competitor competitor;
|
||||
private final ClusterGroup<Speed> windSpeedClusterGroup;
|
||||
private final Set<WindSource> windSourcesToExcludeForBearing;
|
||||
private final Set<WindSource> windSourcesToExcludeForSpeed;
|
||||
private final ClusterGroup<Bearing> angleClusterGroup;
|
||||
private final BearingWithConfidence<Integer> trueWindAngle;
|
||||
@@ -48,7 +47,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
|
||||
this.competitor = competitor;
|
||||
this.windSpeedClusterGroup = windSpeedClusterGroup;
|
||||
this.angleClusterGroup = angleClusterGroup;
|
||||
this.windSourcesToExcludeForBearing = collectWindSourcesToIgnoreForBearing();
|
||||
this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed();
|
||||
this.trueWindAngle = computeTrueWindAngle();
|
||||
this.wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForSpeed);
|
||||
@@ -73,7 +71,7 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
|
||||
|
||||
private BearingWithConfidence<Integer> computeTrueWindAngle() {
|
||||
SpeedWithBearing boatSpeed = race.getTrack(competitor).getEstimatedSpeed(fix.getTimePoint());
|
||||
WindWithConfidence<Pair<Position, TimePoint>> wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForBearing);
|
||||
WindWithConfidence<Pair<Position, TimePoint>> wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint());
|
||||
|
||||
BearingWithConfidenceImpl<Integer> result = null;
|
||||
if (wind != null && boatSpeed != null) {
|
||||
@@ -105,32 +103,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
|
||||
track.getMillisecondsOverWhichToAverageSpeed()/2, /* minimumConfidence */ 0.00000001));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
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.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
|
||||
|
||||
|
||||
+1
-1
@@ -20,9 +20,9 @@ import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.polars.regression.MovingAverageBoatSpeedEstimator;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
|
||||
@@ -38,10 +38,10 @@ 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.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.impl.CubicEquation;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.datamining.components.FilterCriterion;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
|
||||
+1
-1
@@ -13,8 +13,8 @@ import com.sap.sailing.domain.common.Bearing;
|
||||
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.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
|
||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
|
||||
+4
@@ -2,6 +2,8 @@ package com.sap.sailing.polars.regression;
|
||||
|
||||
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
|
||||
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
|
||||
/**
|
||||
* Support incremental regression linear in one variable but potentially of higher order.
|
||||
*
|
||||
@@ -28,4 +30,6 @@ public interface IncrementalLeastSquares {
|
||||
*/
|
||||
public abstract PolynomialFunction getOrCreatePolynomialFunction() throws NotEnoughDataHasBeenAddedException;
|
||||
|
||||
public abstract long getNumberOfAddedPoints();
|
||||
|
||||
}
|
||||
+1
@@ -5,6 +5,7 @@ import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.mining.MovingAverageProcessorImpl;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
|
||||
+6
-1
@@ -12,8 +12,8 @@ import org.apache.commons.math.linear.RealMatrixPreservingVisitor;
|
||||
import org.apache.commons.math.linear.RealVector;
|
||||
import org.apache.commons.math.linear.SingularMatrixException;
|
||||
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
|
||||
@@ -297,4 +297,9 @@ public class IncrementalAnyOrderLeastSquaresImpl implements IncrementalLeastSqua
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNumberOfAddedPoints() {
|
||||
return numberOfPointsAdded.get();
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -35,11 +35,11 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeed;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import java.util.function.Function;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.confidence.ConfidenceBasedAverager;
|
||||
import com.sap.sailing.domain.common.confidence.HasConfidenceAndIsScalable;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
|
||||
|
||||
@@ -5,10 +5,7 @@ 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.polars.windestimation,
|
||||
com.sap.sailing.server,
|
||||
Import-Package: com.sap.sailing.server,
|
||||
com.sap.sailing.server.operationaltransformation,
|
||||
javax.ws.rs;version="1.1.1",
|
||||
javax.ws.rs.core;version="1.1.1",
|
||||
@@ -55,7 +52,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
org.apache.shiro.core;bundle-version="1.2.2",
|
||||
org.apache.shiro.web;bundle-version="1.2.2",
|
||||
org.apache.shiro.ehcache;bundle-version="1.2.3",
|
||||
org.jvnet.mimepull;bundle-version="1.9.4"
|
||||
org.jvnet.mimepull;bundle-version="1.9.4",
|
||||
com.sap.sailing.polars
|
||||
Bundle-ClassPath: .
|
||||
Web-ContextPath: /sailingserver
|
||||
Export-Package: com.sap.sailing.server.gateway,
|
||||
|
||||
+2
-2
@@ -31,9 +31,9 @@ import com.sap.sailing.domain.common.confidence.impl.ScalableDouble;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
|
||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl;
|
||||
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
|
||||
import com.sap.sailing.polars.windestimation.ScalableBearingAndScalableDouble;
|
||||
|
||||
@@ -6,9 +6,7 @@ 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,
|
||||
Import-Package: com.sap.sailing.server.gateway.deserialization,
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework;version="1.3.0",
|
||||
@@ -24,14 +22,14 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.udpconnector,
|
||||
com.sap.sailing.domain.shared.android,
|
||||
com.sap.sailing.server.gateway.serialization,
|
||||
com.sap.sailing.polars,
|
||||
com.sap.sse.common,
|
||||
com.sap.sse.operationaltransformation,
|
||||
com.sap.sse.replication,
|
||||
com.sap.sse,
|
||||
com.sap.sailing.server.gateway.serialization.shared.android,
|
||||
com.sap.sse.shared.android,
|
||||
com.sap.sse.filestorage
|
||||
com.sap.sse.filestorage,
|
||||
com.sap.sailing.simulator;bundle-version="1.0.0"
|
||||
Bundle-ClassPath: .
|
||||
Export-Package: com.sap.sailing.server,
|
||||
com.sap.sailing.server.impl;
|
||||
@@ -43,5 +41,6 @@ Export-Package: com.sap.sailing.server,
|
||||
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.operationaltransformation,
|
||||
com.sap.sailing.server.simulation
|
||||
|
||||
@@ -55,6 +55,7 @@ import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
@@ -65,8 +66,8 @@ import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.TrackerManager;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
|
||||
import com.sap.sailing.server.simulation.SimulationService;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -521,7 +522,9 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
|
||||
WindStore getWindStore();
|
||||
|
||||
PolarDataService getPolarDataService();
|
||||
|
||||
|
||||
SimulationService getSimulationService();
|
||||
|
||||
GPSFixStore getGPSFixStore();
|
||||
|
||||
RaceTracker getRaceTrackerById(Object id);
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.GPSFixMongoHandler;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMongoHandlerImpl;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMovingMongoHandlerImpl;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.server.MasterDataImportClassLoaderService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.RacingEventServiceMXBean;
|
||||
@@ -55,6 +56,8 @@ public class Activator implements BundleActivator {
|
||||
|
||||
private ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService> masterDataImportClassLoaderServiceTracker;
|
||||
|
||||
private ServiceTracker<PolarDataService, PolarDataService> polarDataServiceTracker;
|
||||
|
||||
public Activator() {
|
||||
clearPersistentCompetitors = Boolean.valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, ""+false));
|
||||
logger.log(Level.INFO, "setting "+CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME+" to "+clearPersistentCompetitors);
|
||||
@@ -77,6 +80,10 @@ public class Activator implements BundleActivator {
|
||||
context, MasterDataImportClassLoaderService.class,
|
||||
new MasterDataImportClassLoaderServiceTrackerCustomizer(context, racingEventService));
|
||||
masterDataImportClassLoaderServiceTracker.open();
|
||||
|
||||
polarDataServiceTracker = new ServiceTracker<PolarDataService, PolarDataService>(context,
|
||||
PolarDataService.class, new PolarDataServiceTrackerCustomizer(context, racingEventService));
|
||||
polarDataServiceTracker.open();
|
||||
|
||||
// register the racing service in the OSGi registry
|
||||
racingEventService.setBundleContext(context);
|
||||
@@ -164,5 +171,34 @@ public class Activator implements BundleActivator {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class PolarDataServiceTrackerCustomizer implements
|
||||
ServiceTrackerCustomizer<PolarDataService, PolarDataService> {
|
||||
|
||||
private final BundleContext context;
|
||||
private RacingEventServiceImpl racingEventService;
|
||||
|
||||
public PolarDataServiceTrackerCustomizer(BundleContext context, RacingEventServiceImpl racingEventService) {
|
||||
this.context = context;
|
||||
this.racingEventService = racingEventService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarDataService addingService(ServiceReference<PolarDataService> reference) {
|
||||
PolarDataService service = context.getService(reference);
|
||||
racingEventService.setPolarDataService(service);
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifiedService(ServiceReference<PolarDataService> reference, PolarDataService service) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedService(ServiceReference<PolarDataService> reference, PolarDataService service) {
|
||||
racingEventService.unsetPolarDataService(service);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+53
-10
@@ -127,6 +127,7 @@ import com.sap.sailing.domain.persistence.PersistenceFactory;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDB;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.MongoGPSFixStoreFactory;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
@@ -153,8 +154,6 @@ import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.factory.PolarDataServiceFactory;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.Replicator;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer;
|
||||
@@ -200,6 +199,8 @@ import com.sap.sailing.server.operationaltransformation.UpdateStartTimeReceived;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateTrackedRaceStatus;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime;
|
||||
import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclude;
|
||||
import com.sap.sailing.server.simulation.SimulationService;
|
||||
import com.sap.sailing.server.simulation.SimulationServiceFactory;
|
||||
import com.sap.sse.BuildVersion;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
||||
@@ -351,7 +352,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
private final AbstractLogEventAuthor raceLogEventAuthorForServer = new LogEventAuthorImpl(
|
||||
RacingEventService.class.getName(), 0);
|
||||
|
||||
private final PolarDataService polarDataService;
|
||||
private PolarDataService polarDataService;
|
||||
|
||||
private final SimulationService simulationService;
|
||||
|
||||
/**
|
||||
* Allow only one master data import at a time to avoid situation where multiple Imports override each other in
|
||||
@@ -504,13 +507,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
operationExecutionListeners = new ConcurrentHashMap<>();
|
||||
courseListeners = new ConcurrentHashMap<>();
|
||||
persistentRegattasForRaceIDs = new ConcurrentHashMap<>();
|
||||
final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
||||
// TODO find out how many executors we have on server side and how to manage them
|
||||
Executor polarExecutor = new ThreadPoolExecutor(/* corePoolSize */THREAD_POOL_SIZE,
|
||||
/* maximumPoolSize */THREAD_POOL_SIZE,
|
||||
final int SIMULATION_THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()/3, 1);
|
||||
Executor simulatorExecutor = new ThreadPoolExecutor(/* corePoolSize */SIMULATION_THREAD_POOL_SIZE,
|
||||
/* maximumPoolSize */SIMULATION_THREAD_POOL_SIZE,
|
||||
/* keepAliveTime */60, TimeUnit.SECONDS,
|
||||
/* workQueue */new LinkedBlockingQueue<Runnable>());
|
||||
polarDataService = PolarDataServiceFactory.createStandardPolarDataService(polarExecutor);
|
||||
// TODO: initialize smart-future-cache for simulation-results and add to simulation-service
|
||||
simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, this);
|
||||
this.raceLogReplicator = new RaceLogReplicator(this);
|
||||
this.regattaLogReplicator = new RegattaLogReplicator(this);
|
||||
this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
|
||||
@@ -559,6 +562,11 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
return polarDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationService getSimulationService() {
|
||||
return simulationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearState() throws Exception {
|
||||
for (String leaderboardGroupName : new ArrayList<>(this.leaderboardGroupsByName.keySet())) {
|
||||
@@ -1526,6 +1534,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
PolarFixCacheUpdater polarFixCacheUpdater = new PolarFixCacheUpdater(trackedRace);
|
||||
polarFixCacheUpdaters.put(trackedRace, polarFixCacheUpdater);
|
||||
trackedRace.addListener(polarFixCacheUpdater);
|
||||
|
||||
if (polarDataService != null) {
|
||||
trackedRace.setPolarDataService(polarDataService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1539,14 +1551,18 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
|
||||
@Override
|
||||
public void competitorPositionChanged(GPSFixMoving fix, Competitor item) {
|
||||
polarDataService.competitorPositionChanged(fix, item, race);
|
||||
if (polarDataService != null) {
|
||||
polarDataService.competitorPositionChanged(fix, item, race);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
||||
if (oldStatus.getStatus() == TrackedRaceStatusEnum.LOADING
|
||||
&& newStatus.getStatus() != TrackedRaceStatusEnum.LOADING) {
|
||||
polarDataService.raceFinishedLoading(race);
|
||||
if (polarDataService != null) {
|
||||
polarDataService.raceFinishedLoading(race);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3113,4 +3129,31 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
JoinedClassLoader joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders);
|
||||
return joinedClassLoader;
|
||||
}
|
||||
|
||||
public void setPolarDataService(PolarDataService service) {
|
||||
if (this.polarDataService == null) {
|
||||
polarDataService = service;
|
||||
setPolarDataServiceOnAllTrackedRaces(service);
|
||||
}
|
||||
}
|
||||
|
||||
private void setPolarDataServiceOnAllTrackedRaces(PolarDataService service) {
|
||||
Iterable<Regatta> allRegattas = getAllRegattas();
|
||||
for (Regatta regatta : allRegattas) {
|
||||
DynamicTrackedRegatta trackedRegatta = getTrackedRegatta(regatta);
|
||||
if (trackedRegatta != null) {
|
||||
Iterable<DynamicTrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
trackedRace.setPolarDataService(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unsetPolarDataService(PolarDataService service) {
|
||||
if (polarDataService == service) {
|
||||
polarDataService = null;
|
||||
setPolarDataService(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -28,6 +28,7 @@ import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
@@ -583,4 +584,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPolarDataService(PolarDataService polarDataService) {
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.server.simulation;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.SimulationResults;
|
||||
|
||||
public interface SimulationService {
|
||||
|
||||
int getSimulationResultsVersion(LegIdentifier legIdentifier);
|
||||
|
||||
SimulationResults getSimulationResults(LegIdentifier legIdentifier);
|
||||
|
||||
Map<PathType, Path> getAllPathsEvenTimed(SimulationParameters simuPars, long millisecondsStep)
|
||||
throws InterruptedException, ExecutionException;
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.sap.sailing.server.simulation;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public interface SimulationServiceFactory {
|
||||
|
||||
static SimulationServiceFactory INSTANCE = new SimulationServiceFactoryImpl();
|
||||
|
||||
SimulationService getService(Executor executor, RacingEventService racingEventService);
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.sap.sailing.server.simulation;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class SimulationServiceFactoryImpl implements SimulationServiceFactory {
|
||||
|
||||
public SimulationService getService(Executor executor, RacingEventService racingEventService) {
|
||||
return new SimulationServiceImpl(executor, racingEventService);
|
||||
}
|
||||
|
||||
}
|
||||
+472
@@ -0,0 +1,472 @@
|
||||
package com.sap.sailing.server.simulation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.LegIdentifier;
|
||||
import com.sap.sailing.domain.common.LegIdentifierImpl;
|
||||
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.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.SimulationResults;
|
||||
import com.sap.sailing.simulator.Simulator;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagramGPS;
|
||||
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulatorImpl;
|
||||
import com.sap.sailing.simulator.impl.SparsePolarDataException;
|
||||
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
|
||||
import com.sap.sailing.simulator.windfield.impl.WindFieldTrackedRaceImpl;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.util.SmartFutureCache;
|
||||
|
||||
public class SimulationServiceImpl implements SimulationService {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SimulationService.class.getName());
|
||||
|
||||
final private Executor executor;
|
||||
final private SmartFutureCache<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval> cache;
|
||||
final private RacingEventService racingEventService;
|
||||
final private ScheduledExecutorService scheduler;
|
||||
final private HashMap<String, SimulationRaceListener> raceListeners;
|
||||
final private HashMap<RaceIdentifier, LegChangeListener> legListeners;
|
||||
final private long WAIT_MILLIS = 20000; // milliseconds to wait until earliest cache-update for simulation
|
||||
|
||||
public SimulationServiceImpl(Executor executor, RacingEventService racingEventService) {
|
||||
this.executor = executor;
|
||||
this.scheduler = Executors.newScheduledThreadPool(1);
|
||||
this.racingEventService = racingEventService;
|
||||
if (racingEventService != null) {
|
||||
this.raceListeners = new HashMap<String, SimulationRaceListener>();
|
||||
this.legListeners = new HashMap<RaceIdentifier, LegChangeListener>();
|
||||
this.cache = new SmartFutureCache<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval>(
|
||||
new SmartFutureCache.AbstractCacheUpdater<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval>() {
|
||||
@Override
|
||||
public SimulationResults computeCacheUpdate(LegIdentifier key, SmartFutureCache.EmptyUpdateInterval updateInterval) throws Exception {
|
||||
logger.info("Simulation Started: \"" + key.toString() + "\"");
|
||||
SimulationResults results = computeSimulationResults(key);
|
||||
logger.info("Simulation Finished: \"" + key.toString() + "\", Results-Version: "+ (results==null?0:results.hashCode()));
|
||||
return results;
|
||||
}
|
||||
}, "SmartFutureCache.simulationService (" + racingEventService.toString() + ")");
|
||||
} else {
|
||||
this.raceListeners = null;
|
||||
this.legListeners = null;
|
||||
this.cache = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class SimulationRaceListener implements RaceListener {
|
||||
@Override
|
||||
public void raceAdded(TrackedRace trackedRace) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceRemoved(TrackedRace trackedRace) {
|
||||
RaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier();
|
||||
LegChangeListener listener = legListeners.get(raceIdentifier);
|
||||
if (listener != null) {
|
||||
trackedRace.removeListener(listener);
|
||||
}
|
||||
int legNumber = 1;
|
||||
Iterator<TrackedLeg> iterator = trackedRace.getTrackedLegs().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
LegIdentifier key = new LegIdentifierImpl((RegattaAndRaceIdentifier)raceIdentifier, ""+legNumber);
|
||||
SimulationResults entry = cache.get(key, false);
|
||||
if (entry != null) {
|
||||
cache.remove(key);
|
||||
}
|
||||
legNumber++;
|
||||
iterator.next();
|
||||
}
|
||||
legListeners.remove(raceIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
private class LegChangeListener extends AbstractRaceChangeListener {
|
||||
private final TrackedRace trackedRace;
|
||||
private LegIdentifier legIdentifier;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private boolean covered;
|
||||
|
||||
|
||||
public LegChangeListener(TrackedRace trackedRace, ScheduledExecutorService scheduler) {
|
||||
this.trackedRace = trackedRace;
|
||||
this.legIdentifier = null;
|
||||
this.scheduler = scheduler;
|
||||
this.covered = false;
|
||||
}
|
||||
|
||||
public boolean isLive() {
|
||||
return trackedRace.isLive(MillisecondsTimePoint.now());
|
||||
}
|
||||
|
||||
public void setLegIdentifier(LegIdentifier legIdentifier) {
|
||||
if (this.legIdentifier != null) {
|
||||
if (!this.legIdentifier.equals(legIdentifier)) {
|
||||
this.legIdentifier = legIdentifier;
|
||||
this.covered = false;
|
||||
}
|
||||
} else {
|
||||
this.legIdentifier = legIdentifier;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defaultAction() {
|
||||
if ((!this.covered)&&(legIdentifier!=null)) {
|
||||
this.covered = true;
|
||||
LegIdentifier tmpLegIdentifier = new LegIdentifierImpl(legIdentifier, legIdentifier.getLegName());
|
||||
scheduler.schedule(() -> triggerUpdate(tmpLegIdentifier), WAIT_MILLIS, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerUpdate(LegIdentifier legIdentifier) {
|
||||
if (this.legIdentifier.equals(legIdentifier)) {
|
||||
this.covered = false;
|
||||
}
|
||||
logger.info("Simulation Scheduled Update Triggered: \"" + legIdentifier.toString() + "\"");
|
||||
cache.triggerUpdate(legIdentifier, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void startOfRaceChanged(TimePoint oldStartOfRace, TimePoint newStartOfRace) {
|
||||
// relevant for simulation: start of leg 1 changes; requires update of leg 1
|
||||
// TODO: update leg 1
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windSourcesToExcludeChanged(Iterable<? extends WindSource> windSourcesToExclude) {
|
||||
// relevant for simulation: update all legs when wind changes overall
|
||||
// TODO: update all legs
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startOfTrackingChanged(TimePoint startOfTracking) {
|
||||
// irrelevant for simulation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endOfTrackingChanged(TimePoint endOfTracking) {
|
||||
// irrelevant for simulation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startTimeReceivedChanged(TimePoint startTimeReceived) {
|
||||
// irrelevant for simulation: should be covered by startOfRaceChanged()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markPositionChanged(GPSFix fix, Mark mark, boolean firstInTrack) {
|
||||
// relevant for simulation
|
||||
// TODO: identify influenced legs and update these legs
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windDataReceived(Wind wind, WindSource windSource) {
|
||||
// relevant for simulation: update legs influenced by wind
|
||||
// TODO: update influenced legs; "live" update current leg
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windDataRemoved(Wind wind, WindSource windSource) {
|
||||
// relevant for simulation: update legs influenced by wind
|
||||
// TODO: update influenced legs; "live" update current leg
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {
|
||||
// relevant for simulation: update legs influenced by wind
|
||||
// TODO: update influenced legs; "live" update current leg
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void competitorPositionChanged(GPSFixMoving fix, Competitor item) {
|
||||
// irrelevant for simulation: covered by wind estimation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markPassingReceived(Competitor competitor, Map<Waypoint, MarkPassing> oldMarkPassings, Iterable<MarkPassing> markPassings) {
|
||||
// relevant for simulation: update start- and end-times of legs
|
||||
// TODO: update influenced legs; "live" update current leg
|
||||
}
|
||||
|
||||
@Override
|
||||
public void speedAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {
|
||||
// irrelevant for simulation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delayToLiveChanged(long delayToLiveInMillis) {
|
||||
// irrelevant for simulation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
|
||||
// relevant for simulation: update legs influenced waypoint
|
||||
// TODO: update influenced legs; "live" update current leg
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
|
||||
// relevant for simulation: update legs influenced waypoint
|
||||
// TODO: update influenced legs; "live" update current leg
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSimulationResultsVersion(LegIdentifier legIdentifier) {
|
||||
SimulationResults result = cache.get(legIdentifier, false);
|
||||
int version = (result == null ? 0 : result.hashCode());
|
||||
logger.fine("Simulation Results-Version: " + + version);
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationResults getSimulationResults(LegIdentifier legIdentifier) {
|
||||
SimulationResults result = cache.get(legIdentifier, false);
|
||||
if (result == null) {
|
||||
logger.fine("Simulation Get: Cache Empty: \"" + legIdentifier.toString() + "\"");
|
||||
if (!raceListeners.containsKey(legIdentifier.getRegattaName())) {
|
||||
Regatta regatta = racingEventService.getRegattaByName(legIdentifier.getRegattaName());
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(regatta);
|
||||
SimulationRaceListener raceListener = new SimulationRaceListener();
|
||||
raceListeners.put(legIdentifier.getRegattaName(), raceListener);
|
||||
trackedRegatta.addRaceListener(raceListener);
|
||||
}
|
||||
if (!legListeners.containsKey(legIdentifier.getRaceIdentifier())) {
|
||||
TrackedRace trackedRace = racingEventService.getTrackedRace(legIdentifier);
|
||||
if (trackedRace != null) {
|
||||
LegChangeListener listener = new LegChangeListener(trackedRace, scheduler);
|
||||
if (listener.isLive()) {
|
||||
listener.setLegIdentifier(legIdentifier);
|
||||
}
|
||||
legListeners.put(legIdentifier.getRaceIdentifier(), listener);
|
||||
trackedRace.addListener(listener);
|
||||
}
|
||||
} else {
|
||||
LegChangeListener listener = legListeners.get(legIdentifier.getRaceIdentifier());
|
||||
if (listener.isLive()) {
|
||||
listener.setLegIdentifier(legIdentifier);
|
||||
}
|
||||
}
|
||||
logger.info("Simulation Get: Update Triggered: \"" + legIdentifier.toString() + "\"");
|
||||
cache.triggerUpdate(legIdentifier, null);
|
||||
result = cache.get(legIdentifier, true); // take first simulation result that becomes available
|
||||
}
|
||||
if (result == null) {
|
||||
logger.fine("Simulation Get: Null-Result: \"" + legIdentifier.toString() + "\"");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public SimulationResults computeSimulationResults(LegIdentifier legIdentifier) throws InterruptedException,
|
||||
ExecutionException {
|
||||
SimulationResults result = null;
|
||||
TrackedRace trackedRace = racingEventService.getTrackedRace(legIdentifier);
|
||||
if (trackedRace != null) {
|
||||
Leg leg = trackedRace.getRace().getCourse().getLegs().get(legIdentifier.getLegNumber());
|
||||
// get previous mark or start line as start-position
|
||||
Waypoint fromWaypoint = leg.getFrom();
|
||||
// get next mark as end-position
|
||||
Waypoint toWaypoint = leg.getTo();
|
||||
|
||||
TimePoint startTimePoint = null;
|
||||
TimePoint endTimePoint = null;
|
||||
MarkPassing markPassing;
|
||||
Iterator<MarkPassing> markPassingIterator = trackedRace.getMarkPassingsInOrder(fromWaypoint).iterator();
|
||||
if (markPassingIterator.hasNext()) {
|
||||
markPassing = markPassingIterator.next();
|
||||
} else {
|
||||
markPassing = null;
|
||||
}
|
||||
if (markPassing != null) {
|
||||
startTimePoint = markPassing.getTimePoint();
|
||||
}
|
||||
markPassingIterator = trackedRace.getMarkPassingsInOrder(toWaypoint).iterator();
|
||||
if (markPassingIterator.hasNext()) {
|
||||
markPassing = markPassingIterator.next();
|
||||
} else {
|
||||
markPassing = null;
|
||||
}
|
||||
if (markPassing != null) {
|
||||
endTimePoint = markPassing.getTimePoint();
|
||||
}
|
||||
long legDuration = 0;
|
||||
if ((startTimePoint != null) && (endTimePoint != null)) {
|
||||
legDuration = endTimePoint.asMillis() - startTimePoint.asMillis();
|
||||
}
|
||||
Position startPosition = null;
|
||||
Position endPosition = null;
|
||||
if (startTimePoint != null) {
|
||||
startPosition = trackedRace.getApproximatePosition(fromWaypoint, startTimePoint);
|
||||
}
|
||||
if (endTimePoint != null) {
|
||||
endPosition = trackedRace.getApproximatePosition(toWaypoint, endTimePoint);
|
||||
} else if (startTimePoint != null) {
|
||||
endPosition = trackedRace.getApproximatePosition(toWaypoint, startTimePoint);
|
||||
}
|
||||
|
||||
// determine legtype upwind/downwind/reaching
|
||||
LegType legType = null;
|
||||
try {
|
||||
legType = trackedRace.getTrackedLeg(leg).getLegType(startTimePoint);
|
||||
} catch (NoWindException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get windfield
|
||||
WindFieldGenerator windField = new WindFieldTrackedRaceImpl(trackedRace);
|
||||
Duration timeStep = new MillisecondsDurationImpl(15 * 1000);
|
||||
windField.generate(startTimePoint, null, timeStep);
|
||||
|
||||
// prepare simulation-parameters
|
||||
List<Position> course = new ArrayList<Position>();
|
||||
course.add(startPosition);
|
||||
course.add(endPosition);
|
||||
BoatClass boatClass = trackedRace.getRace().getBoatClass();
|
||||
PolarDataService polarDataService = racingEventService.getPolarDataService();
|
||||
PolarDiagram polarDiagram;
|
||||
try {
|
||||
polarDiagram = new PolarDiagramGPS(boatClass, polarDataService);
|
||||
} catch (SparsePolarDataException e) {
|
||||
polarDiagram = null;
|
||||
// TODO: raise a UI message, to inform user about missing polar data resulting in unability to simulate
|
||||
}
|
||||
double simuStepSeconds = startPosition.getDistance(endPosition).getNauticalMiles()
|
||||
/ ((PolarDiagramGPS) polarDiagram).getAvgSpeed() * 3600 / 100;
|
||||
Duration simuStep = new MillisecondsDurationImpl(Math.round(simuStepSeconds) * 1000);
|
||||
SimulationParameters simulationPars = new SimulationParametersImpl(course, polarDiagram, windField,
|
||||
simuStep, SailingSimulatorConstants.ModeEvent, true, true, legType);
|
||||
Map<PathType, Path> paths = null;
|
||||
if (polarDiagram != null) {
|
||||
paths = getAllPathsEvenTimed(simulationPars, timeStep.asMillis());
|
||||
}
|
||||
// prepare simulator-results
|
||||
result = new SimulationResults(startTimePoint.asDate(), timeStep.asMillis(), legDuration, startPosition,
|
||||
endPosition, paths, null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<PathType, Path> getAllPaths(SimulationParameters simulationParameters) throws InterruptedException,
|
||||
ExecutionException {
|
||||
|
||||
Simulator simulator = new SimulatorImpl(simulationParameters);
|
||||
Map<PathType, Path> result = new HashMap<PathType, Path>();
|
||||
|
||||
FutureTask<Path> taskOmniscient = null;
|
||||
if (simulationParameters.showOmniscient()) {
|
||||
// schedule omniscient task
|
||||
taskOmniscient = new FutureTask<Path>(() -> simulator.getPath(PathType.OMNISCIENT));
|
||||
executor.execute(taskOmniscient);
|
||||
}
|
||||
|
||||
// schedule 1-turner tasks
|
||||
FutureTask<Path> task1TurnerLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.ONE_TURNER_LEFT));
|
||||
FutureTask<Path> task1TurnerRight = new FutureTask<Path>(() -> simulator.getPath(PathType.ONE_TURNER_RIGHT));
|
||||
executor.execute(task1TurnerLeft);
|
||||
executor.execute(task1TurnerRight);
|
||||
|
||||
FutureTask<Path> taskOpportunistLeft = null;
|
||||
FutureTask<Path> taskOpportunistRight = null;
|
||||
if (simulationParameters.showOpportunist()) {
|
||||
// schedule opportunist tasks (which depend on 1-turner results)
|
||||
taskOpportunistLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.OPPORTUNIST_LEFT));
|
||||
taskOpportunistRight = new FutureTask<Path>(() -> simulator.getPath(PathType.OPPORTUNIST_RIGHT));
|
||||
executor.execute(taskOpportunistLeft);
|
||||
executor.execute(taskOpportunistRight);
|
||||
}
|
||||
|
||||
// collect 1-turner results
|
||||
result.put(PathType.ONE_TURNER_LEFT, task1TurnerLeft.get());
|
||||
result.put(PathType.ONE_TURNER_RIGHT, task1TurnerRight.get());
|
||||
|
||||
if (simulationParameters.showOpportunist()) {
|
||||
// collect opportunist results
|
||||
Path pathOpportunistLeft = taskOpportunistLeft.get();
|
||||
if (pathOpportunistLeft.getTurnCount() == 1) {
|
||||
pathOpportunistLeft = result.get(PathType.ONE_TURNER_LEFT);
|
||||
}
|
||||
result.put(PathType.OPPORTUNIST_LEFT, pathOpportunistLeft);
|
||||
Path pathOpportunistRight = taskOpportunistRight.get();
|
||||
if (pathOpportunistRight.getTurnCount() == 1) {
|
||||
pathOpportunistRight = result.get(PathType.ONE_TURNER_RIGHT);
|
||||
}
|
||||
result.put(PathType.OPPORTUNIST_RIGHT, pathOpportunistRight);
|
||||
}
|
||||
|
||||
if (simulationParameters.showOmniscient()) {
|
||||
// collect omniscient result (last, since usually slowest calculation)
|
||||
Path pathOmniscient = taskOmniscient.get();
|
||||
if (pathOmniscient.getFinalTime().after(result.get(PathType.ONE_TURNER_LEFT).getFinalTime())) {
|
||||
pathOmniscient = result.get(PathType.ONE_TURNER_LEFT);
|
||||
}
|
||||
if (pathOmniscient.getFinalTime().after(result.get(PathType.ONE_TURNER_RIGHT).getFinalTime())) {
|
||||
pathOmniscient = result.get(PathType.ONE_TURNER_RIGHT);
|
||||
}
|
||||
result.put(PathType.OMNISCIENT, pathOmniscient);
|
||||
}
|
||||
// return combined result
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<PathType, Path> getAllPathsEvenTimed(SimulationParameters simuPars, long millisecondsStep)
|
||||
throws InterruptedException, ExecutionException {
|
||||
Map<PathType, Path> allTimedPaths = new TreeMap<PathType, Path>();
|
||||
Map<PathType, Path> allPaths = this.getAllPaths(simuPars);
|
||||
for (Entry<PathType, Path> entry : allPaths.entrySet()) {
|
||||
PathType pathType = entry.getKey();
|
||||
Path pathValue = entry.getValue();
|
||||
if (pathValue != null) {
|
||||
allTimedPaths.put(pathType, pathValue.getEvenTimedPath(millisecondsStep));
|
||||
}
|
||||
}
|
||||
return allTimedPaths;
|
||||
}
|
||||
|
||||
}
|
||||
+22
-17
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.simulator.test;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -13,12 +14,14 @@ import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagram49STG;
|
||||
import com.sap.sailing.simulator.impl.RectangularGrid;
|
||||
import com.sap.sailing.simulator.impl.SailingSimulatorImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulatorImpl;
|
||||
import com.sap.sailing.simulator.impl.SparsePolarDataException;
|
||||
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
|
||||
import com.sap.sailing.simulator.windfield.WindControlParameters;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
|
||||
@@ -31,18 +34,18 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
public class SimulatorTest {
|
||||
|
||||
@Test
|
||||
public void testSailingSimulatorALL() {
|
||||
|
||||
public void testSailingSimulatorALL() throws SparsePolarDataException {
|
||||
|
||||
// race course: copacabana, rio de janeiro, brasil
|
||||
Position start = new DegreePosition(-22.975779,-43.17421);
|
||||
Position end = new DegreePosition(-22.99016,-43.156013);
|
||||
//System.out.println("race course size: "+start.getDistance(end).getKilometers());
|
||||
Position start = new DegreePosition(-22.975779, -43.17421);
|
||||
Position end = new DegreePosition(-22.99016, -43.156013);
|
||||
// System.out.println("race course size: "+start.getDistance(end).getKilometers());
|
||||
|
||||
List<Position> course = new LinkedList<Position>();
|
||||
course.add(start);
|
||||
course.add(end);
|
||||
PolarDiagram pd = new PolarDiagram49STG();//PolarDiagram49.CreateStandard49();
|
||||
|
||||
PolarDiagram pd = new PolarDiagram49STG();// PolarDiagram49.CreateStandard49();
|
||||
|
||||
RectangularGrid bd = new RectangularGrid(start, end);
|
||||
Position[][] positions = bd.generatePositions(10, 10, 0, 0);
|
||||
Bearing windBear = end.getBearingGreatCircle(start);
|
||||
@@ -54,16 +57,18 @@ public class SimulatorTest {
|
||||
Duration timeStep = new MillisecondsDurationImpl(30000);
|
||||
wf.generate(startTime, null, timeStep);
|
||||
|
||||
SimulationParameters param = new SimulationParametersImpl(course, pd, wf, SailingSimulatorConstants.ModeFreestyle, true, true);
|
||||
SailingSimulatorImpl sailingSim = new SailingSimulatorImpl(param);
|
||||
SimulationParameters param = new SimulationParametersImpl(course, pd, wf, null,
|
||||
SailingSimulatorConstants.ModeFreestyle, true, true);
|
||||
SimulatorImpl sailingSim = new SimulatorImpl(param);
|
||||
|
||||
//Map<String, Path> paths = sailingSim.getAllPathsForLeg(new SimulatorUISelectionImpl(0, 0, 0, 0));
|
||||
Map<String, Path> paths = sailingSim.getAllPaths();
|
||||
|
||||
//System.out.println("opportunistic path points: "+paths.get("2#Opportunist Left").getPathPoints().size());
|
||||
Assert.assertNotNull(paths.get("2#Opportunist Left").getPathPoints());
|
||||
//System.out.println("omnciscient path points: "+paths.get("1#Omniscient").getPathPoints().size());
|
||||
Assert.assertNotNull(paths.get("1#Omniscient").getPathPoints());
|
||||
Path pathOmniscient = sailingSim.getPath(PathType.OMNISCIENT);
|
||||
Path pathOpportunist = sailingSim.getPath(PathType.OPPORTUNIST_LEFT);
|
||||
Map<PathType, Path> paths = new HashMap<PathType, Path>();
|
||||
paths.put(PathType.OMNISCIENT, pathOmniscient);
|
||||
paths.put(PathType.OPPORTUNIST_LEFT, pathOpportunist);
|
||||
|
||||
Assert.assertNotNull(paths.get(PathType.OPPORTUNIST_LEFT).getPathPoints());
|
||||
Assert.assertNotNull(paths.get(PathType.OMNISCIENT).getPathPoints());
|
||||
}
|
||||
|
||||
}
|
||||
+23
-19
@@ -34,44 +34,48 @@ public class TreeGrowTest {
|
||||
@Test
|
||||
public void testSailingSimulatorALL() {
|
||||
|
||||
Position start = new DegreePosition(54.001917,10.82222);
|
||||
//Position end = new DegreePosition(54.023806,10.822048);
|
||||
SpeedWithBearing bearNorth = new KnotSpeedWithBearingImpl(6.0, new DegreeBearingImpl(33.0));
|
||||
Position end = bearNorth.travelTo(start, new MillisecondsTimePoint(0), new MillisecondsTimePoint(10*60*1000));
|
||||
//System.out.println(start.getDistance(end).getKilometers());
|
||||
Position start = new DegreePosition(54.001917, 10.82222);
|
||||
// Position end = new DegreePosition(54.023806,10.822048);
|
||||
SpeedWithBearing bearNorth = new KnotSpeedWithBearingImpl(6.0, new DegreeBearingImpl(33.0));
|
||||
Position end = bearNorth.travelTo(start, new MillisecondsTimePoint(0),
|
||||
new MillisecondsTimePoint(10 * 60 * 1000));
|
||||
// System.out.println(start.getDistance(end).getKilometers());
|
||||
|
||||
List<Position> course = new LinkedList<Position>();
|
||||
course.add(start);
|
||||
course.add(end);
|
||||
PolarDiagram pd = new PolarDiagram49STG();//PolarDiagram49.CreateStandard49();
|
||||
PolarDiagram pd = new PolarDiagram49STG();// PolarDiagram49.CreateStandard49();
|
||||
RectangularGrid bd = new RectangularGrid(start, end);
|
||||
Position[][] positions = bd.generatePositions(10, 10, 0, 0);
|
||||
//RectangularBoundary new_bd = new RectangularBoundary(start, end, 0.1);
|
||||
//Speed knotSpeed = new KnotSpeedImpl(8);
|
||||
WindControlParameters windParameters = new WindControlParameters(12, start.getBearingGreatCircle(end).reverse().getDegrees());
|
||||
// RectangularBoundary new_bd = new RectangularBoundary(start, end, 0.1);
|
||||
// Speed knotSpeed = new KnotSpeedImpl(8);
|
||||
WindControlParameters windParameters = new WindControlParameters(12, start.getBearingGreatCircle(end).reverse()
|
||||
.getDegrees());
|
||||
WindFieldGenerator wf = new WindFieldGeneratorOscillationImpl(bd, windParameters);
|
||||
wf.setPositionGrid(positions);
|
||||
Date startDate = new Date(0);
|
||||
TimePoint startTime = new MillisecondsTimePoint(startDate.getTime());
|
||||
Duration timeStep = new MillisecondsDurationImpl(20000);
|
||||
wf.generate(startTime, null, timeStep);
|
||||
SimulationParameters param = new SimulationParametersImpl(course, pd, wf, SailingSimulatorConstants.ModeFreestyle, true, true);
|
||||
SimulationParameters param = new SimulationParametersImpl(course, pd, wf, null,
|
||||
SailingSimulatorConstants.ModeFreestyle, true, true);
|
||||
|
||||
/*param.setProperty("Heuristic.targetTolerance[double]", 0.05);
|
||||
param.setProperty("Heuristic.timeResolution[long]", 30000.0);
|
||||
param.setProperty("Djikstra.gridv[int]", 10.0);
|
||||
param.setProperty("Djikstra.gridh[int]", 100.0);*/
|
||||
/*
|
||||
* param.setProperty("Heuristic.targetTolerance[double]", 0.05);
|
||||
* param.setProperty("Heuristic.timeResolution[long]", 30000.0); param.setProperty("Djikstra.gridv[int]", 10.0);
|
||||
* param.setProperty("Djikstra.gridh[int]", 100.0);
|
||||
*/
|
||||
|
||||
PathGeneratorTreeGrow treeGrow = new PathGeneratorTreeGrow(param);
|
||||
|
||||
Path path = treeGrow.getPath();
|
||||
|
||||
//System.out.println("tree-grow path points: "+path.getPathPoints().size());
|
||||
// System.out.println("tree-grow path points: "+path.getPathPoints().size());
|
||||
Assert.assertNotNull(path.getPathPoints());
|
||||
|
||||
//for(TimedPositionWithSpeed pos : path.getPathPoints()) {
|
||||
// System.out.println(""+pos.getPosition().getLatDeg()+", "+pos.getPosition().getLngDeg());
|
||||
//}
|
||||
|
||||
// for(TimedPositionWithSpeed pos : path.getPathPoints()) {
|
||||
// System.out.println(""+pos.getPosition().getLatDeg()+", "+pos.getPosition().getLngDeg());
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
+12
-9
@@ -41,11 +41,12 @@ public class PathGenerator1TurnerEval {
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.out.println("Collection of test methods for evaluating path segments.");
|
||||
}
|
||||
|
||||
|
||||
public void initialize() throws IOException, ClassNotFoundException {
|
||||
|
||||
this._polarDiagram = new PolarDiagramCSV(POLAR_DIAGRAM_49_STG_CSV_FILE_PATH);
|
||||
this._simulationParameters = new SimulationParametersImpl(null, this._polarDiagram, null, SailingSimulatorConstants.ModeMeasured, true, true);
|
||||
this._simulationParameters = new SimulationParametersImpl(null, this._polarDiagram, null, null,
|
||||
SailingSimulatorConstants.ModeMeasured, true, true);
|
||||
this._pathGenerator = new PathGenerator1Turner(this._simulationParameters);
|
||||
|
||||
this._windField = readWindFieldGeneratorFromExternalFile("windField.dat");
|
||||
@@ -60,8 +61,8 @@ public class PathGenerator1TurnerEval {
|
||||
int stepMax = 300;
|
||||
long timeStep = 6666;
|
||||
|
||||
TimedPositionWithSpeed result = this._pathGenerator.get1Turner(this._windField, this._polarDiagram, start, end, startTime, leftSide,
|
||||
stepMax, timeStep);
|
||||
TimedPositionWithSpeed result = this._pathGenerator.get1Turner(this._windField, this._polarDiagram, start, end,
|
||||
startTime, leftSide, stepMax, timeStep);
|
||||
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertNotNull(result.getPosition());
|
||||
@@ -85,8 +86,8 @@ public class PathGenerator1TurnerEval {
|
||||
int stepMax = 300;
|
||||
long timeStep = 1000;
|
||||
|
||||
TimedPositionWithSpeed result = this._pathGenerator.get1Turner(this._windField, this._polarDiagram, start, end, startTime, leftSide,
|
||||
stepMax, timeStep);
|
||||
TimedPositionWithSpeed result = this._pathGenerator.get1Turner(this._windField, this._polarDiagram, start, end,
|
||||
startTime, leftSide, stepMax, timeStep);
|
||||
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertNotNull(result.getPosition());
|
||||
@@ -112,7 +113,8 @@ public class PathGenerator1TurnerEval {
|
||||
int stepMax = 300;
|
||||
long timeStep = 1000;
|
||||
|
||||
TimedPositionWithSpeed result = this._pathGenerator.get1Turner(this._windField, this._polarDiagram, end, start, startTime, leftSide, stepMax, timeStep);
|
||||
TimedPositionWithSpeed result = this._pathGenerator.get1Turner(this._windField, this._polarDiagram, end, start,
|
||||
startTime, leftSide, stepMax, timeStep);
|
||||
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertNotNull(result.getPosition());
|
||||
@@ -143,7 +145,8 @@ public class PathGenerator1TurnerEval {
|
||||
file.close();
|
||||
}
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
System.err.println("[ERROR][PathGenerator1Turner][readFromExternalFile][ClassNotFoundException] " + ex.getMessage());
|
||||
System.err.println("[ERROR][PathGenerator1Turner][readFromExternalFile][ClassNotFoundException] "
|
||||
+ ex.getMessage());
|
||||
result = null;
|
||||
} catch (final IOException ex) {
|
||||
System.err.println("[ERROR][PathGenerator1Turner][readFromExternalFile][IOException] " + ex.getMessage());
|
||||
@@ -152,7 +155,7 @@ public class PathGenerator1TurnerEval {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private File getFile(String fileName) {
|
||||
return new File(RESOURCES + fileName);
|
||||
}
|
||||
|
||||
+5
-3
@@ -18,7 +18,6 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracAdapterFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.TracTracAdapterFactoryImpl;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulatorUtils;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class RaceDataAccessEval {
|
||||
@@ -26,10 +25,14 @@ public class RaceDataAccessEval {
|
||||
private static final Logger logger = Logger.getLogger(RaceDataAccessEval.class.getName());
|
||||
protected static final boolean tractracTunnel = Boolean.valueOf(System.getProperty("tractrac.tunnel", "false"));
|
||||
protected static final String tractracTunnelHost = System.getProperty("tractrac.tunnel.host", "localhost");
|
||||
@SuppressWarnings("unused")
|
||||
private static URL paramUrl;
|
||||
@SuppressWarnings("unused")
|
||||
private static URI liveUri;
|
||||
@SuppressWarnings("unused")
|
||||
private static URI storedUri;
|
||||
private static RacingEventServiceImpl service;
|
||||
@SuppressWarnings("unused")
|
||||
private static TracTracAdapterFactory tracTracAdapterFactory;
|
||||
private static RaceHandle raceHandle;
|
||||
public boolean storedend = false;
|
||||
@@ -102,8 +105,7 @@ public class RaceDataAccessEval {
|
||||
service = new RacingEventServiceImpl();
|
||||
tracTracAdapterFactory = new TracTracAdapterFactoryImpl();
|
||||
logger.info("Calling service.addTracTracRace");
|
||||
raceHandle = SimulatorUtils.loadRace(service, tracTracAdapterFactory, paramUrl, liveUri, storedUri, null, null,
|
||||
60000);
|
||||
raceHandle = null; //SimulatorUtils.loadRace(service, tracTracAdapterFactory, paramUrl, liveUri, storedUri, null, null, 60000);
|
||||
logger.info("Calling raceHandle.getRaces(): " + raceHandle);
|
||||
RaceDefinition race = raceHandle.getRace(); // wait for RaceDefinition to be completely wired in Regatta
|
||||
logger.info("Obtained race: " + race);
|
||||
|
||||
+4
-3
@@ -21,7 +21,6 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracAdapterFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.TracTracAdapterFactoryImpl;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulatorUtils;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class RacingEventPersistence {
|
||||
@@ -48,12 +47,14 @@ public class RacingEventPersistence {
|
||||
|
||||
service = new RacingEventServiceImpl();
|
||||
tracTracAdapterFactory = new TracTracAdapterFactoryImpl();
|
||||
@SuppressWarnings("unused")
|
||||
URL paramURL = new URL(paramURLStr);
|
||||
@SuppressWarnings("unused")
|
||||
URI liveURI = new URI(liveURIStr);
|
||||
@SuppressWarnings("unused")
|
||||
URI storedURI = new URI(storedURIStr);
|
||||
|
||||
raceHandle = SimulatorUtils.loadRace(service, tracTracAdapterFactory, paramURL, liveURI, storedURI, null, null,
|
||||
60000);
|
||||
//raceHandle = SimulatorUtils.loadRace(service, tracTracAdapterFactory, paramURL, liveURI, storedURI, null, null, 60000);
|
||||
|
||||
System.out.println("Done loading race.");
|
||||
|
||||
|
||||
+6
-3
@@ -13,7 +13,6 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracAdapterFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.TracTracAdapterFactoryImpl;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulatorUtils;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class TracTracReaderFromURLs implements TracTracReader {
|
||||
@@ -52,19 +51,23 @@ public class TracTracReaderFromURLs implements TracTracReader {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("null")
|
||||
public List<TrackedRace> read() throws Exception {
|
||||
System.setProperty("mongo.port", mongoPortStr);
|
||||
System.setProperty("http.proxyHost", proxyHostStr);
|
||||
System.setProperty("http.proxyPort", proxyPortStr);
|
||||
RacingEventServiceImpl service = new RacingEventServiceImpl();
|
||||
@SuppressWarnings("unused")
|
||||
final TracTracAdapterFactory tracTracAdapterFactory = new TracTracAdapterFactoryImpl();
|
||||
@SuppressWarnings("unused")
|
||||
URI liveURI = new URI(liveURIStr);
|
||||
@SuppressWarnings("unused")
|
||||
URI storedURI = new URI(storedURIStr);
|
||||
List<TrackedRace> racesList = new ArrayList<TrackedRace>();
|
||||
for (String paramURLStr : tracTracParamURLs) {
|
||||
@SuppressWarnings("unused")
|
||||
URL paramURL = new URL(paramURLStr);
|
||||
RaceHandle raceHandle = SimulatorUtils.loadRace(service, tracTracAdapterFactory, paramURL, liveURI, storedURI,
|
||||
null, null, 60000);
|
||||
RaceHandle raceHandle = null; //SimulatorUtils.loadRace(service, tracTracAdapterFactory, paramURL, liveURI, storedURI, null, null, 60000);
|
||||
String regatta = raceHandle.getRegatta().getName();
|
||||
RaceDefinition r = raceHandle.getRace();
|
||||
RegattaAndRaceIdentifier raceIdentifier = new RegattaNameAndRaceName(regatta, r.getName());
|
||||
|
||||
+6
-3
@@ -15,7 +15,6 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracAdapterFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.impl.TracTracAdapterFactoryImpl;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulatorUtils;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class TracTracWriter {
|
||||
@@ -30,19 +29,23 @@ public class TracTracWriter {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
public void write() throws Exception {
|
||||
RacingEventServiceImpl service = new RacingEventServiceImpl();
|
||||
@SuppressWarnings("unused")
|
||||
final TracTracAdapterFactory tracTracAdapterFactory = new TracTracAdapterFactoryImpl();
|
||||
System.setProperty("mongo.port", "10200");
|
||||
System.setProperty("http.proxyHost", "proxy.wdf.sap.corp");
|
||||
System.setProperty("http.proxyPort", "8080");
|
||||
@SuppressWarnings("unused")
|
||||
URI liveURI = new URI("tcp://10.18.22.156:1520");
|
||||
@SuppressWarnings("unused")
|
||||
URI storedURI = new URI("tcp://10.18.22.156:1521");
|
||||
|
||||
for (String paramURLStr : sources) {
|
||||
@SuppressWarnings("unused")
|
||||
URL paramURL = new URL(paramURLStr);
|
||||
RaceHandle raceHandle = SimulatorUtils.loadRace(service, tracTracAdapterFactory, paramURL, liveURI, storedURI,
|
||||
null, null, 60000);
|
||||
RaceHandle raceHandle = null; //SimulatorUtils.loadRace(service, tracTracAdapterFactory, paramURL, liveURI, storedURI, null, null, 60000);
|
||||
String regatta = raceHandle.getRegatta().getName();
|
||||
RaceDefinition r = raceHandle.getRace();
|
||||
List<TrackedRace> racesList = new ArrayList<TrackedRace>();
|
||||
|
||||
@@ -7,7 +7,6 @@ Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Require-Bundle: com.sap.sailing.domain.common;bundle-version="1.0.0",
|
||||
com.sap.sailing.domain;bundle-version="1.0.0",
|
||||
com.sap.sailing.server;bundle-version="1.0.0",
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sse,
|
||||
com.sap.sse.common,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
49er
|
||||
wind speed,0,6,8,10,12,14,16,20
|
||||
beat angles,45,43.4,41.8,38.9,37.5,36.8,36.3,36.9
|
||||
beat sog,0,6.435,7.678,8.129,8.448,8.679,8.712,8.734
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
49er
|
||||
wind speed,0,6,9,12,25
|
||||
beat angles,43,50.24,49.4,47.35,48.01
|
||||
beat sog,0,7.53,9.39,11.96,13.08
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
49er
|
||||
wind speed,0,6,8,10,12,14,16,20
|
||||
beat angles,45,43.4,41.8,38.9,37.5,36.8,36.3,36.9
|
||||
beat sog,0,6.435,7.678,8.129,8.448,8.679,8.712,8.734
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
49er
|
||||
wind speed,0,6,8,10,12,14,16,20
|
||||
beat angles,43,43,43,43,44,45,45.6,47
|
||||
beat sog,0,4.5,6.25,8,8.5,9,9.3,10
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
5O5
|
||||
wind speed,0,6,8,10,12,14,16,20
|
||||
beat angles,44,44,46.5,50,52,54,55,56
|
||||
beat sog,0,5,5.3,5.6,6,6.5,7,7
|
||||
|
||||
|
@@ -0,0 +1,22 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
public enum BoatDirection {
|
||||
NONE("None"),
|
||||
BEAT_LEFT("Beat Left"),
|
||||
BEAT_RIGHT("Beat Right"),
|
||||
REACH_LEFT("Reach Left"),
|
||||
REACH_RIGHT("Reach Right"),
|
||||
JIBE_LEFT("Jibe Left"),
|
||||
JIBE_RIGHT("Jibe Right");
|
||||
|
||||
private String txtId;
|
||||
|
||||
BoatDirection(String txtId) {
|
||||
this.txtId = txtId;
|
||||
}
|
||||
|
||||
public String getTxtId() {
|
||||
return txtId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,16 +3,29 @@ package com.sap.sailing.simulator;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.simulator.windfield.WindField;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public interface Path {
|
||||
|
||||
List<TimedPositionWithSpeed> getPathPoints();
|
||||
|
||||
void setPathPoints(List<TimedPositionWithSpeed> pointsList);
|
||||
|
||||
public long getMaxTurnTime();
|
||||
|
||||
public void setMaxTurnTime(long maxTurnTime);
|
||||
|
||||
void setWindField(WindField wf);
|
||||
|
||||
List<TimedPositionWithSpeed> getTurns();
|
||||
|
||||
TimePoint getFinalTime();
|
||||
|
||||
Path getEvenTimedPath(long timeStep);
|
||||
|
||||
int getTurnCount();
|
||||
|
||||
boolean getAlgorithmTimedOut();
|
||||
|
||||
boolean getMixedLeg();
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import com.sap.sailing.simulator.impl.SparsePolarDataException;
|
||||
|
||||
public interface PathGenerator {
|
||||
|
||||
void setSimulationParameters(SimulationParameters params);
|
||||
|
||||
SimulationParameters getSimulationParameters();
|
||||
|
||||
Path getPath();
|
||||
Path getPath() throws SparsePolarDataException;
|
||||
|
||||
Path getPathEvenTimed(long stepMilliseconds) throws SparsePolarDataException;
|
||||
|
||||
public boolean isTimedOut();
|
||||
|
||||
Path getPathEvenTimed(long stepMilliseconds);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
public enum PathType {
|
||||
OMNISCIENT("1#Omniscient"),
|
||||
OPPORTUNIST_LEFT("2#Opportunist Left"),
|
||||
OPPORTUNIST_RIGHT("3#Opportunist Right"),
|
||||
ONE_TURNER_LEFT("4#1-Turner Left"),
|
||||
ONE_TURNER_RIGHT("5#1-Turner Right");
|
||||
|
||||
private String txtId;
|
||||
|
||||
PathType(String txtId) {
|
||||
this.txtId = txtId;
|
||||
}
|
||||
|
||||
public String getTxtId() {
|
||||
return txtId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
public enum PointOfSail {
|
||||
TACKING("Tacking"),
|
||||
JIBING("Jibing"),
|
||||
REACHING("Reaching");
|
||||
|
||||
private String txtId;
|
||||
|
||||
PointOfSail(String txtId) {
|
||||
this.txtId = txtId;
|
||||
}
|
||||
|
||||
public String getTxtId() {
|
||||
return txtId;
|
||||
}
|
||||
|
||||
}
|
||||
Loaded 100 of 136 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user