mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-13 22:15:26 +00:00
add smart-future-cache and move simulation-service to server-plugin;
This commit is contained in:
1 parent
4dc35e059a
commit
32ae97ec48
26 files changed
+606
-327
No files matched your search
+6
-5
@@ -3,10 +3,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.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.sailing.simulator.LegIdentifier;
|
||||
import com.sap.sse.gwt.client.async.AsyncAction;
|
||||
|
||||
/**
|
||||
@@ -18,19 +19,19 @@ import com.sap.sse.gwt.client.async.AsyncAction;
|
||||
*/
|
||||
public class GetSimulationAction implements AsyncAction<SimulatorResultsDTO> {
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final RegattaAndRaceIdentifier raceIdentifier;
|
||||
private final LegIdentifier legIdentifier;
|
||||
private final Date from;
|
||||
private final Date prevStartTime;
|
||||
|
||||
public GetSimulationAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
|
||||
public GetSimulationAction(SailingServiceAsync sailingService, LegIdentifier legIdentifier, Date from, Date prevStartTime) {
|
||||
this.sailingService = sailingService;
|
||||
this.raceIdentifier = raceIdentifier;
|
||||
this.legIdentifier = legIdentifier;
|
||||
this.from = from;
|
||||
this.prevStartTime = prevStartTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(AsyncCallback<SimulatorResultsDTO> callback) {
|
||||
sailingService.getSimulatorResults(raceIdentifier, from, prevStartTime, callback);
|
||||
sailingService.getSimulatorResults(legIdentifier, from, prevStartTime, callback);
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -84,6 +84,7 @@ import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.VenueDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||
import com.sap.sailing.simulator.LegIdentifier;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -140,7 +141,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
|
||||
Boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime);
|
||||
SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier, Date from, Date prevStartTime);
|
||||
|
||||
CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString,
|
||||
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate) throws NoWindException;
|
||||
|
||||
+2
-1
@@ -74,6 +74,7 @@ import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.VenueDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||
import com.sap.sailing.simulator.LegIdentifier;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.search.KeywordQuery;
|
||||
import com.sap.sse.gwt.client.BuildVersionRetriever;
|
||||
@@ -188,7 +189,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, Date from, Date prevStartTime, AsyncCallback<SimulatorResultsDTO> callback);
|
||||
|
||||
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind, AsyncCallback<Void> callback);
|
||||
|
||||
|
||||
+32
-98
@@ -388,11 +388,13 @@ 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.LegIdentifier;
|
||||
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.SimulationService;
|
||||
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.SimulationParametersImpl;
|
||||
@@ -1493,107 +1495,39 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
};
|
||||
|
||||
@Override
|
||||
public SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
|
||||
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
|
||||
public SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier, Date from, Date prevStartTime) {
|
||||
// get simulation-results from smart-future-cached simulation-service
|
||||
SimulationService simulationService = getService().getSimulationService();
|
||||
SimulationResults simulationResults = simulationService.getSimulationResults(legIdentifier);
|
||||
// prepare simulator-results-dto
|
||||
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();
|
||||
}
|
||||
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);
|
||||
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<Position>();
|
||||
course.add(startPosition);
|
||||
course.add(endPosition);
|
||||
BoatClass boatClass = trackedRace.getRace().getBoatClass();
|
||||
PolarDataService polarData = getService().getPolarDataService();
|
||||
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
|
||||
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);
|
||||
|
||||
// for upwind/downwind, run simulation with start-time, start-position, end-position and windfield
|
||||
SimulationService simulationService = getService().getSimulationService();
|
||||
Map<PathType, Path> paths = null;
|
||||
if (legType != LegType.REACHING) {
|
||||
paths = simulationService.getAllPaths(simulationPars);
|
||||
}
|
||||
|
||||
// prepare simulator-results-dto
|
||||
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);
|
||||
index--;
|
||||
}
|
||||
RaceMapDataDTO rcDTO;
|
||||
rcDTO = new RaceMapDataDTO();
|
||||
rcDTO.coursePositions = new CoursePositionsDTO();
|
||||
rcDTO.coursePositions.waypointPositions = new ArrayList<PositionDTO>();
|
||||
PositionDTO posDTO;
|
||||
posDTO = SimulatorServiceUtils.toPositionDTO(startPosition);
|
||||
rcDTO.coursePositions.waypointPositions.add(posDTO);
|
||||
posDTO = SimulatorServiceUtils.toPositionDTO(endPosition);
|
||||
rcDTO.coursePositions.waypointPositions.add(posDTO);
|
||||
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<PositionDTO>();
|
||||
PositionDTO posDTO;
|
||||
posDTO = SimulatorServiceUtils.toPositionDTO(simulationResults.getStartPosition());
|
||||
rcDTO.coursePositions.waypointPositions.add(posDTO);
|
||||
posDTO = SimulatorServiceUtils.toPositionDTO(simulationResults.getEndPosition());
|
||||
rcDTO.coursePositions.waypointPositions.add(posDTO);
|
||||
result = new SimulatorResultsDTO(simulationResults.getStartTime(), simulationResults.getTimeStep(),
|
||||
simulationResults.getLegDuration(), rcDTO, pathDTOs, null, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -26,6 +26,8 @@ import com.sap.sailing.gwt.ui.shared.SimulatorWindDTO;
|
||||
import com.sap.sailing.gwt.ui.simulator.racemap.FullCanvasOverlay;
|
||||
import com.sap.sailing.gwt.ui.simulator.util.ColorPalette;
|
||||
import com.sap.sailing.gwt.ui.simulator.util.ColorPaletteGenerator;
|
||||
import com.sap.sailing.simulator.LegIdentifier;
|
||||
import com.sap.sailing.simulator.impl.LegIdentifierImpl;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
|
||||
|
||||
@@ -70,7 +72,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
if (clearCanvas) {
|
||||
this.clearCanvas();
|
||||
}
|
||||
this.simulate(newTime);
|
||||
this.simulate(newTime, newLeg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,8 +249,9 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
|
||||
return pathTimeStr;
|
||||
}
|
||||
|
||||
public void simulate(Date from) {
|
||||
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, raceIdentifier, from, prevStartTime);
|
||||
public void simulate(Date from, int leg) {
|
||||
LegIdentifier legIdentifier = new LegIdentifierImpl(raceIdentifier, String.valueOf(leg));
|
||||
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, legIdentifier, from, prevStartTime);
|
||||
asyncActionsExecutor.execute(getSimulation, GET_SIMULATION_CATEGORY,
|
||||
new MarkedAsyncCallback<>(new AsyncCallback<SimulatorResultsDTO>() {
|
||||
@Override
|
||||
|
||||
@@ -9,8 +9,6 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package: com.sap.sailing.polars,
|
||||
com.sap.sailing.polars.factory,
|
||||
com.sap.sailing.server.gateway.deserialization,
|
||||
com.sap.sailing.simulator,
|
||||
com.sap.sailing.simulator.impl,
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework;version="1.3.0",
|
||||
@@ -33,7 +31,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
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;
|
||||
@@ -45,5 +44,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
|
||||
|
||||
@@ -64,7 +64,7 @@ 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.simulator.SimulationService;
|
||||
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;
|
||||
|
||||
+3
-3
@@ -191,8 +191,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.simulator.SimulationService;
|
||||
import com.sap.sailing.simulator.SimulationServiceFactory;
|
||||
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;
|
||||
@@ -505,7 +505,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
||||
/* 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);
|
||||
simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, this);
|
||||
this.raceLogReplicator = new RaceLogReplicator(this);
|
||||
this.regattaLogReplicator = new RegattaLogReplicator(this);
|
||||
this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.sap.sailing.server.simulation;
|
||||
|
||||
import com.sap.sailing.simulator.LegIdentifier;
|
||||
import com.sap.sailing.simulator.SimulationResults;
|
||||
|
||||
|
||||
public interface SimulationService {
|
||||
|
||||
SimulationResults getSimulationResults(LegIdentifier legIdentifier);
|
||||
|
||||
}
|
||||
+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);
|
||||
}
|
||||
|
||||
}
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
package com.sap.sailing.server.simulation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
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.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.simulator.LegIdentifier;
|
||||
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.impl.MaximumTurnTimes;
|
||||
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.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
import com.sap.sse.util.SmartFutureCache;
|
||||
import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
|
||||
|
||||
public class SimulationServiceImpl implements SimulationService {
|
||||
|
||||
final private Executor executor;
|
||||
final private SmartFutureCache<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval> cache;
|
||||
final private RacingEventService racingEventService;
|
||||
|
||||
public SimulationServiceImpl(Executor executor, RacingEventService racingEventService) {
|
||||
this.executor = executor;
|
||||
this.cache = new SmartFutureCache<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval>(
|
||||
new SmartFutureCache.AbstractCacheUpdater<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval>() {
|
||||
@Override
|
||||
public SimulationResults computeCacheUpdate(LegIdentifier key, EmptyUpdateInterval updateInterval)
|
||||
throws Exception {
|
||||
return computeSimulationResults(key);
|
||||
}
|
||||
}, "SmartFutureCache.simulationService (" + racingEventService.toString() + ")");
|
||||
this.racingEventService = racingEventService;
|
||||
}
|
||||
|
||||
private class Listener extends AbstractRaceChangeListener {
|
||||
private final LegIdentifier legIdentifier;
|
||||
|
||||
public Listener(LegIdentifier legIdentifier) {
|
||||
this.legIdentifier = legIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defaultAction() {
|
||||
cache.triggerUpdate(legIdentifier, null);
|
||||
}
|
||||
|
||||
// simulation is not influenced by live-delay
|
||||
@Override
|
||||
public void delayToLiveChanged(long delayToLiveInMillis) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationResults getSimulationResults(LegIdentifier legIdentifier) {
|
||||
SimulationResults result = cache.get(legIdentifier, false);
|
||||
if (result == null) {
|
||||
TrackedRace trackedRace = racingEventService.getTrackedRace(legIdentifier);
|
||||
trackedRace.addListener(new Listener(legIdentifier));
|
||||
cache.triggerUpdate(legIdentifier, null);
|
||||
result = cache.get(legIdentifier, false); // take first simulation result that becomes available
|
||||
}
|
||||
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;
|
||||
markPassing = trackedRace.getMarkPassingsInOrder(fromWaypoint).iterator().next();
|
||||
if (markPassing != null) {
|
||||
startTimePoint = markPassing.getTimePoint();
|
||||
}
|
||||
markPassing = trackedRace.getMarkPassingsInOrder(toWaypoint).iterator().next();
|
||||
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) {
|
||||
// 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<Position>();
|
||||
course.add(startPosition);
|
||||
course.add(endPosition);
|
||||
BoatClass boatClass = trackedRace.getRace().getBoatClass();
|
||||
PolarDataService polarDataService = racingEventService.getPolarDataService();
|
||||
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarDataService);
|
||||
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);
|
||||
Map<PathType, Path> paths = null;
|
||||
if (legType != LegType.REACHING) {
|
||||
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 simuPars) throws InterruptedException,
|
||||
ExecutionException {
|
||||
|
||||
SailingSimulator simulator = new SailingSimulatorImpl(simuPars);
|
||||
Map<PathType, Path> result = new HashMap<PathType, Path>();
|
||||
// schedule omniscient task
|
||||
FutureTask<Path> taskOmniscient = new FutureTask<Path>(() -> simulator.getPath(PathType.OMNISCIENT, null));
|
||||
executor.execute(taskOmniscient);
|
||||
|
||||
// schedule 1-turner tasks
|
||||
FutureTask<Path> task1TurnerLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.ONE_TURNER_LEFT, null));
|
||||
FutureTask<Path> task1TurnerRight = new FutureTask<Path>(() -> simulator.getPath(PathType.ONE_TURNER_RIGHT, null));
|
||||
executor.execute(task1TurnerLeft);
|
||||
executor.execute(task1TurnerRight);
|
||||
|
||||
// collect 1-turner results
|
||||
result.put(PathType.ONE_TURNER_LEFT, task1TurnerLeft.get());
|
||||
result.put(PathType.ONE_TURNER_RIGHT, task1TurnerRight.get());
|
||||
|
||||
// maximum turn times
|
||||
MaximumTurnTimes maxTurnTimes = new MaximumTurnTimes(task1TurnerLeft.get().getMaxTurnTime(), task1TurnerRight
|
||||
.get().getMaxTurnTime());
|
||||
|
||||
// schedule opportunist tasks (which depend on 1-turner results)
|
||||
FutureTask<Path> taskOpportunistLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.OPPORTUNIST_LEFT, maxTurnTimes));
|
||||
FutureTask<Path> taskOpportunistRight = new FutureTask<Path>(() -> simulator.getPath(PathType.OPPORTUNIST_RIGHT, maxTurnTimes));
|
||||
executor.execute(taskOpportunistLeft);
|
||||
executor.execute(taskOpportunistRight);
|
||||
|
||||
// collect opportunist results
|
||||
result.put(PathType.OPPORTUNIST_LEFT, taskOpportunistLeft.get());
|
||||
result.put(PathType.OPPORTUNIST_RIGHT, taskOpportunistRight.get());
|
||||
|
||||
// collect omniscient result (last, since usually slowest calculation)
|
||||
result.put(PathType.OMNISCIENT, taskOmniscient.get());
|
||||
|
||||
// return combined result
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<PathType, Path> getAllPathsEvenTimed(SimulationParameters simuPars, long millisecondsStep)
|
||||
throws InterruptedException, ExecutionException {
|
||||
Map<PathType, Path> allTimedPaths = new HashMap<PathType, Path>();
|
||||
Map<PathType, Path> allPaths = this.getAllPaths(simuPars);
|
||||
for (Entry<PathType, Path> entry : allPaths.entrySet()) {
|
||||
PathType pathType = entry.getKey();
|
||||
Path pathValue = entry.getValue();
|
||||
allTimedPaths.put(pathType, pathValue.getEvenTimedPath(millisecondsStep));
|
||||
}
|
||||
return allTimedPaths;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
|
||||
public interface LegIdentifier extends RegattaAndRaceIdentifier {
|
||||
String getLegName();
|
||||
int getLegNumber();
|
||||
}
|
||||
@@ -9,6 +9,10 @@ public interface Path {
|
||||
List<TimedPositionWithSpeed> getPathPoints();
|
||||
|
||||
void setPathPoints(List<TimedPositionWithSpeed> pointsList);
|
||||
|
||||
public long getMaxTurnTime();
|
||||
|
||||
public void setMaxTurnTime(long maxTurnTime);
|
||||
|
||||
void setWindField(WindField wf);
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.sap.sailing.simulator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.simulator.impl.MaximumTurnTimes;
|
||||
|
||||
|
||||
public interface SailingSimulator {
|
||||
|
||||
@@ -12,7 +14,7 @@ public interface SailingSimulator {
|
||||
|
||||
Path getLegGPSTrack(SimulatorUISelection selection);
|
||||
|
||||
Path getPath(PathType pathType);
|
||||
Path getPath(PathType pathType, MaximumTurnTimes maxTurnTimes);
|
||||
|
||||
Map<String, Path> getAllPaths();
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
|
||||
public class SimulationResults {
|
||||
|
||||
private Date startTime;
|
||||
private long timeStep;
|
||||
private long legDuration;
|
||||
private Position startPosition;
|
||||
private Position endPosition;
|
||||
private Map<PathType, Path> paths;
|
||||
private String notificationMessage;
|
||||
|
||||
public SimulationResults(){
|
||||
this.startTime = null;
|
||||
this.timeStep = 0;
|
||||
this.legDuration = 0;
|
||||
this.paths = null;
|
||||
this.notificationMessage = "";
|
||||
}
|
||||
|
||||
public SimulationResults(final Date startTime, final long timeStep, final long legDuration, final Position startPosition, final Position endPosition, final Map<PathType, Path> paths, final String notificationMessage) {
|
||||
this.startTime = startTime;
|
||||
this.timeStep = timeStep;
|
||||
this.legDuration = legDuration;
|
||||
this.startPosition = startPosition;
|
||||
this.endPosition = endPosition;
|
||||
this.paths = paths;
|
||||
this.notificationMessage = notificationMessage;
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return this.startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Date startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public long getTimeStep() {
|
||||
return this.timeStep;
|
||||
}
|
||||
|
||||
public void setTimeStep(long timeStep) {
|
||||
this.timeStep = timeStep;
|
||||
}
|
||||
|
||||
public long getLegDuration() {
|
||||
return this.legDuration;
|
||||
}
|
||||
|
||||
public void setLegDuration(long legDuration) {
|
||||
this.legDuration = legDuration;
|
||||
}
|
||||
|
||||
public Position getStartPosition() {
|
||||
return this.startPosition;
|
||||
}
|
||||
|
||||
public void setStartPosition(Position startPosition) {
|
||||
this.startPosition = startPosition;
|
||||
}
|
||||
|
||||
public Position getEndPosition() {
|
||||
return this.endPosition;
|
||||
}
|
||||
|
||||
public void setEndPosition(Position endPosition) {
|
||||
this.endPosition = endPosition;
|
||||
}
|
||||
|
||||
public Map<PathType, Path> getPaths() {
|
||||
return this.paths;
|
||||
}
|
||||
|
||||
public void setPaths(final Map<PathType, Path> paths) {
|
||||
this.paths = paths;
|
||||
}
|
||||
|
||||
public String getNotificationMessage() {
|
||||
return this.notificationMessage;
|
||||
}
|
||||
|
||||
public void setNotificationMessage(final String notificationMessage) {
|
||||
this.notificationMessage = notificationMessage;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public interface SimulationService {
|
||||
|
||||
Map<PathType, Path> getAllPaths(SimulationParameters simuPars);
|
||||
|
||||
Map<PathType, Path> getAllPathsEvenTimed(SimulationParameters simuPars, long millisecondsStep);
|
||||
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.simulator.impl.SimulationServiceFactoryImpl;
|
||||
|
||||
public interface SimulationServiceFactory {
|
||||
|
||||
static SimulationServiceFactory INSTANCE = new SimulationServiceFactoryImpl();
|
||||
|
||||
SimulationService getService(Executor executor);
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.simulator.LegIdentifier;
|
||||
|
||||
|
||||
|
||||
public class LegIdentifierImpl extends RegattaNameAndRaceName implements LegIdentifier {
|
||||
private static final long serialVersionUID = 3599904513673776450L;
|
||||
private String legName;
|
||||
|
||||
public LegIdentifierImpl(RegattaAndRaceIdentifier raceIdentifier, String legName) {
|
||||
super(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName());
|
||||
this.legName = legName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegName() {
|
||||
return legName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLegNumber() {
|
||||
return Integer.parseInt(legName);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
public class MaximumTurnTimes {
|
||||
public long left;
|
||||
public long right;
|
||||
|
||||
public MaximumTurnTimes(long left, long right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
}
|
||||
+54
-51
@@ -24,8 +24,7 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
int turns;
|
||||
int maxLeft;
|
||||
int maxRight;
|
||||
long maxLeftTime;
|
||||
long maxRightTime;
|
||||
MaximumTurnTimes maxTurnTimes;
|
||||
boolean startLeft;
|
||||
boolean upwindLeg = false;
|
||||
|
||||
@@ -33,35 +32,34 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
public void setEvaluationParameters(int maxLeftVal, int maxRightVal, boolean startLeftVal) {
|
||||
this.maxLeft = maxLeftVal;
|
||||
this.maxRight = maxRightVal;
|
||||
this.startLeft = startLeftVal;
|
||||
public void setEvaluationParameters(int maxLeft, int maxRight, boolean startLeft) {
|
||||
this.maxLeft = maxLeft;
|
||||
this.maxRight = maxRight;
|
||||
this.startLeft = startLeft;
|
||||
}
|
||||
|
||||
public void setEvaluationParameters(long maxLeftTime, long maxRightTime, boolean startLeftVal) {
|
||||
this.maxLeftTime = maxLeftTime;
|
||||
this.maxRightTime = maxRightTime;
|
||||
this.startLeft = startLeftVal;
|
||||
public void setEvaluationParameters(MaximumTurnTimes maxTurnTimes, boolean startLeft) {
|
||||
this.maxTurnTimes = maxTurnTimes;
|
||||
this.startLeft = startLeft;
|
||||
}
|
||||
|
||||
public int getTurns() {
|
||||
return turns;
|
||||
return turns;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
WindFieldGenerator wf = simulationParameters.getWindField();
|
||||
PolarDiagram pd = simulationParameters.getBoatPolarDiagram();
|
||||
|
||||
|
||||
Position start = simulationParameters.getCourse().get(0);
|
||||
Position end = simulationParameters.getCourse().get(1);
|
||||
|
||||
|
||||
// test downwind: exchange start and end
|
||||
//Position start = simulationParameters.getCourse().get(1);
|
||||
//Position end = simulationParameters.getCourse().get(0);
|
||||
|
||||
// Position start = simulationParameters.getCourse().get(1);
|
||||
// Position end = simulationParameters.getCourse().get(0);
|
||||
|
||||
TimePoint startTime = wf.getStartTime();// new MillisecondsTimePoint(0);
|
||||
List<TimedPositionWithSpeed> path = new ArrayList<TimedPositionWithSpeed>();
|
||||
|
||||
@@ -86,34 +84,34 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
logger.fine("wndStart speed:" + wndStart.getKnots() + " angle:" + wndStart.getBearing().getDegrees());
|
||||
pd.setWind(wndStart);
|
||||
Bearing bearStart = currentPosition.getBearingGreatCircle(end);
|
||||
//SpeedWithBearing spdStart = pd.getSpeedAtBearing(bearStart);
|
||||
// SpeedWithBearing spdStart = pd.getSpeedAtBearing(bearStart);
|
||||
path.add(new TimedPositionWithSpeedImpl(startTime, start, wndStart));
|
||||
|
||||
long timeStep = wf.getTimeStep().asMillis()/2;
|
||||
|
||||
long timeStep = wf.getTimeStep().asMillis() / 2;
|
||||
logger.info("Time step :" + timeStep);
|
||||
// while there is more than 5% of the total distance to the finish
|
||||
|
||||
Bearing bearRCWind = wndStart.getBearing().getDifferenceTo(bearStart);
|
||||
String legType = "downwind";
|
||||
this.upwindLeg = false;
|
||||
|
||||
if ((Math.abs(bearRCWind.getDegrees()) > 90.0)&&(Math.abs(bearRCWind.getDegrees()) < 270.0)) {
|
||||
legType = "upwind";
|
||||
|
||||
if ((Math.abs(bearRCWind.getDegrees()) > 90.0) && (Math.abs(bearRCWind.getDegrees()) < 270.0)) {
|
||||
legType = "upwind";
|
||||
this.upwindLeg = true;
|
||||
}
|
||||
|
||||
|
||||
int timeStepScale = 1;
|
||||
if (!this.upwindLeg) {
|
||||
timeStepScale = 2;
|
||||
timeStep = timeStep / timeStepScale;
|
||||
turnloss = turnloss / timeStepScale;
|
||||
turnloss = turnloss / timeStepScale;
|
||||
}
|
||||
|
||||
if ((maxLeftTime > 0)||(maxRightTime > 0)) {
|
||||
this.maxLeft = (int)Math.floor((double)maxLeftTime / (double)timeStep);
|
||||
this.maxRight = (int)Math.floor((double)maxRightTime / (double)timeStep);
|
||||
if ((maxTurnTimes.left > 0) || (maxTurnTimes.right > 0)) {
|
||||
this.maxLeft = (int) Math.floor((double) maxTurnTimes.left / (double) timeStep);
|
||||
this.maxRight = (int) Math.floor((double) maxTurnTimes.right / (double) timeStep);
|
||||
}
|
||||
logger.info("Leg Direction: "+legType);
|
||||
logger.info("Leg Direction: " + legType);
|
||||
|
||||
//
|
||||
// StrategicPhase: start & intermediate course until close to target
|
||||
@@ -121,7 +119,9 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
turns = 0;
|
||||
SpeedWithBearing slft = null;
|
||||
SpeedWithBearing srght = null;
|
||||
while ((currentHeight > 0)&&(currentPosition.getDistance(end).compareTo(start.getDistance(end).scale(fracFinishPhase)) > 0)&&(path.size()<500)) {
|
||||
while ((currentHeight > 0)
|
||||
&& (currentPosition.getDistance(end).compareTo(start.getDistance(end).scale(fracFinishPhase)) > 0)
|
||||
&& (path.size() < 500)) {
|
||||
|
||||
// TimePoint nextTime = new MillisecondsTimePoint(currentTime.asMillis() + 30000);
|
||||
|
||||
@@ -137,19 +137,19 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
Bearing wLft;
|
||||
Bearing wRght;
|
||||
if (this.upwindLeg) {
|
||||
wLft = pd.optimalDirectionsUpwind()[0];
|
||||
wRght = pd.optimalDirectionsUpwind()[1];
|
||||
wLft = pd.optimalDirectionsUpwind()[0];
|
||||
wRght = pd.optimalDirectionsUpwind()[1];
|
||||
} else {
|
||||
wLft = pd.optimalDirectionsDownwind()[0];
|
||||
wRght = pd.optimalDirectionsDownwind()[1];
|
||||
wLft = pd.optimalDirectionsDownwind()[0];
|
||||
wRght = pd.optimalDirectionsDownwind()[1];
|
||||
}
|
||||
// Bearing wDirect = currentPosition.getBearingGreatCircle(end);
|
||||
|
||||
// SpeedWithBearing sWDirect = pd.getSpeedAtBearing(wDirect);
|
||||
SpeedWithBearing sWLft = pd.getSpeedAtBearing(wLft);
|
||||
SpeedWithBearing sWRght = pd.getSpeedAtBearing(wRght);
|
||||
logger.fine("left boat speed:" + sWLft.getKnots() + " angle:" + sWLft.getBearing().getDegrees() + " right boat speed:"
|
||||
+ sWRght.getKnots() + " angle:" + sWRght.getBearing().getDegrees());
|
||||
logger.fine("left boat speed:" + sWLft.getKnots() + " angle:" + sWLft.getBearing().getDegrees()
|
||||
+ " right boat speed:" + sWRght.getKnots() + " angle:" + sWRght.getBearing().getDegrees());
|
||||
|
||||
TimePoint wTime = new MillisecondsTimePoint(currentTime.asMillis() + windpred);
|
||||
// Position pWDirect = sWDirect.travelTo(currentPosition, currentTime, wTime);
|
||||
@@ -170,12 +170,12 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
Wind lWind = wf.getWind(new TimedPositionWithSpeedImpl(currentTime, pWLft, null));
|
||||
logger.fine("lWind speed:" + lWind.getKnots() + " angle:" + lWind.getBearing().getDegrees());
|
||||
// System.out.println("Left WindBear: " + (lWind.getBearing().getDegrees() - bearStart.getDegrees()));
|
||||
pd.setWind(lWind);
|
||||
pd.setWind(lWind);
|
||||
Bearing lft;
|
||||
if (this.upwindLeg) {
|
||||
lft = pd.optimalDirectionsUpwind()[0];
|
||||
lft = pd.optimalDirectionsUpwind()[0];
|
||||
} else {
|
||||
lft = pd.optimalDirectionsDownwind()[0];
|
||||
lft = pd.optimalDirectionsDownwind()[0];
|
||||
}
|
||||
slft = pd.getSpeedAtBearing(lft);
|
||||
|
||||
@@ -185,17 +185,17 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
pd.setWind(rWind);
|
||||
Bearing rght;
|
||||
if (this.upwindLeg) {
|
||||
rght = pd.optimalDirectionsUpwind()[1];
|
||||
rght = pd.optimalDirectionsUpwind()[1];
|
||||
} else {
|
||||
rght = pd.optimalDirectionsDownwind()[1];
|
||||
rght = pd.optimalDirectionsDownwind()[1];
|
||||
}
|
||||
srght = pd.getSpeedAtBearing(rght);
|
||||
|
||||
// System.out.println("Bearings : " + (lft.getDegrees() - bearStart.getDegrees()) + " "
|
||||
// + (rght.getDegrees() - bearStart.getDegrees()));
|
||||
|
||||
logger.fine("left boat speed:" + slft.getKnots() + " angle:" + slft.getBearing().getDegrees() + " right boat speed:"
|
||||
+ srght.getKnots() + " angle:" + srght.getBearing().getDegrees());
|
||||
logger.fine("left boat speed:" + slft.getKnots() + " angle:" + slft.getBearing().getDegrees()
|
||||
+ " right boat speed:" + srght.getKnots() + " angle:" + srght.getBearing().getDegrees());
|
||||
|
||||
/*
|
||||
* if (prevDirection == 0) { directTime = new MillisecondsTimePoint(nextTimeVal); leftTime = new
|
||||
@@ -235,7 +235,7 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
if (prevDirection == -1) {
|
||||
|
||||
if (startLeft) {
|
||||
allRight = false;
|
||||
allRight = false;
|
||||
path.add(new TimedPositionWithSpeedImpl(nextTime, plft, lWind));
|
||||
currentPosition = plft;
|
||||
if (prevDirection == 2) {
|
||||
@@ -246,7 +246,7 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
}
|
||||
prevDirection = 1;
|
||||
} else {
|
||||
allLeft = false;
|
||||
allLeft = false;
|
||||
path.add(new TimedPositionWithSpeedImpl(nextTime, prght, rWind));
|
||||
currentPosition = prght;
|
||||
if (prevDirection == 1) {
|
||||
@@ -260,7 +260,8 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
|
||||
} else {
|
||||
// System.out.println("Distance Left - Right: "+lDistCM+" - "+ rDistCM);
|
||||
if (((lDistCM <= rDistCM) && (!allLeft || (stepsLeft < maxLeft))) || (allRight && (stepsRight >= maxRight))) {
|
||||
if (((lDistCM <= rDistCM) && (!allLeft || (stepsLeft < maxLeft)))
|
||||
|| (allRight && (stepsRight >= maxRight))) {
|
||||
path.add(new TimedPositionWithSpeedImpl(nextTime, plft, lWind));
|
||||
currentPosition = plft;
|
||||
if (prevDirection == 2) {
|
||||
@@ -287,7 +288,7 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
currentTime = nextTime;
|
||||
Position posHeight = currentPosition.projectToLineThrough(start, bearStart);
|
||||
currentHeight = start.getDistance(end).getMeters() - posHeight.getDistance(start).getMeters();
|
||||
//System.out.println("Height to Target: "+height);
|
||||
// System.out.println("Height to Target: "+height);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -304,15 +305,17 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
|
||||
rightGoingTime = currentTime;
|
||||
}
|
||||
|
||||
gen1Turner.setEvaluationParameters(true, currentPosition, end, leftGoingTime, timeStep / (5 * 3), 100, 0.1, this.upwindLeg);
|
||||
gen1Turner.setEvaluationParameters(true, currentPosition, end, leftGoingTime, timeStep / (5 * 3), 100, 0.1,
|
||||
this.upwindLeg);
|
||||
Path leftPath = gen1Turner.getPath();
|
||||
|
||||
gen1Turner.setEvaluationParameters(false, currentPosition, end, rightGoingTime, timeStep / (5 * 3), 100, 0.1, this.upwindLeg);
|
||||
gen1Turner.setEvaluationParameters(false, currentPosition, end, rightGoingTime, timeStep / (5 * 3), 100, 0.1,
|
||||
this.upwindLeg);
|
||||
Path rightPath = gen1Turner.getPath();
|
||||
|
||||
if ((leftPath.getPathPoints() != null) && (rightPath.getPathPoints() != null)) {
|
||||
if (leftPath.getPathPoints().get(leftPath.getPathPoints().size() - 1).getTimePoint().asMillis() <= rightPath.getPathPoints()
|
||||
.get(rightPath.getPathPoints().size() - 1).getTimePoint().asMillis()) {
|
||||
if (leftPath.getPathPoints().get(leftPath.getPathPoints().size() - 1).getTimePoint().asMillis() <= rightPath
|
||||
.getPathPoints().get(rightPath.getPathPoints().size() - 1).getTimePoint().asMillis()) {
|
||||
path.addAll(leftPath.getPathPoints());
|
||||
} else {
|
||||
path.addAll(rightPath.getPathPoints());
|
||||
|
||||
+10
-2
@@ -739,8 +739,16 @@ public class PathGeneratorTreeGrow extends PathGeneratorBase {
|
||||
// add final position (rescaled before to end on height of target)
|
||||
path.add(new TimedPositionWithSpeedImpl(bestCand.pos.getTimePoint(), bestCand.pos.getPosition(), null));
|
||||
|
||||
return new PathImpl(path, wf);
|
||||
|
||||
// maximum turn time for one-turner simulation, otherwise zero
|
||||
long maxTurnTime = 0;
|
||||
if (this.maxTurns == 1) {
|
||||
int turnMiddle = 1000;
|
||||
if (bestCand != null) {
|
||||
turnMiddle = bestCand.getIndexOfTurnRL();
|
||||
maxTurnTime = turnMiddle * this.usedTimeStep;
|
||||
}
|
||||
}
|
||||
return new PathImpl(path, wf, maxTurnTime);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,15 +27,21 @@ public class PathImpl implements Path, Serializable {
|
||||
private static final long serialVersionUID = -6354445155884413937L;
|
||||
private List<TimedPositionWithSpeed> pathPoints;
|
||||
private WindField windField;
|
||||
private long maxTurnTime;
|
||||
|
||||
private static final double TRESHOLD_DEGREES = 25.0;
|
||||
private static final double THRESHOLD_DISTANCE_METERS = 15.0;
|
||||
|
||||
public PathImpl(List<TimedPositionWithSpeed> pointsList, WindField wf) {
|
||||
|
||||
this.pathPoints = pointsList;
|
||||
this.windField = wf;
|
||||
this.maxTurnTime = 0;
|
||||
}
|
||||
|
||||
public PathImpl(List<TimedPositionWithSpeed> pointsList, WindField wf, long maxTurnTime) {
|
||||
this.pathPoints = pointsList;
|
||||
this.windField = wf;
|
||||
this.maxTurnTime = maxTurnTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,6 +54,16 @@ public class PathImpl implements Path, Serializable {
|
||||
this.pathPoints = pointsList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxTurnTime() {
|
||||
return this.maxTurnTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxTurnTime(long maxTurnTime) {
|
||||
this.maxTurnTime = maxTurnTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getEvenTimedPath(long timestep) {
|
||||
return new PathImpl(this.getEvenTimedPathAsList(timestep), this.windField);
|
||||
|
||||
+38
-9
@@ -65,9 +65,38 @@ public class SailingSimulatorImpl implements SailingSimulator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(PathType pathType) {
|
||||
// TODO: de-scramble implementation of getAllPaths() to focus on just one path fpr multi-threaded execution
|
||||
return null;
|
||||
public Path getPath(PathType pathType, MaximumTurnTimes maxTurnTimes) {
|
||||
PathGeneratorTreeGrow genTreeGrow;
|
||||
PathGeneratorOpportunistEuclidian genOpportunistic;
|
||||
Path path = null;
|
||||
switch (pathType) {
|
||||
case OMNISCIENT:
|
||||
genTreeGrow = new PathGeneratorTreeGrow(this.simulationParameters); // instantiate heuristic searcher
|
||||
genTreeGrow.setEvaluationParameters(null, 0, null); // allow for arbitrary many turns
|
||||
path = genTreeGrow.getPath();
|
||||
|
||||
case ONE_TURNER_LEFT:
|
||||
genTreeGrow = new PathGeneratorTreeGrow(this.simulationParameters); // instantiate heuristic searcher
|
||||
genTreeGrow.setEvaluationParameters("L", 1, null); // start left and limit to one turn
|
||||
path = genTreeGrow.getPath();
|
||||
|
||||
case ONE_TURNER_RIGHT:
|
||||
genTreeGrow = new PathGeneratorTreeGrow(this.simulationParameters); // instantiate heuristic searcher
|
||||
genTreeGrow.setEvaluationParameters("R", 1, null); // start right and limit to one turn
|
||||
path = genTreeGrow.getPath();
|
||||
|
||||
case OPPORTUNIST_LEFT:
|
||||
genOpportunistic = new PathGeneratorOpportunistEuclidian(this.simulationParameters);
|
||||
genOpportunistic.setEvaluationParameters(maxTurnTimes, true);
|
||||
path = genOpportunistic.getPath();
|
||||
|
||||
case OPPORTUNIST_RIGHT:
|
||||
genOpportunistic = new PathGeneratorOpportunistEuclidian(this.simulationParameters);
|
||||
genOpportunistic.setEvaluationParameters(maxTurnTimes, false);
|
||||
path = genOpportunistic.getPath();
|
||||
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,16 +151,17 @@ public class SailingSimulatorImpl implements SailingSimulator {
|
||||
// get instance of heuristic searcher
|
||||
PathGeneratorTreeGrow genTreeGrow = new PathGeneratorTreeGrow(this.simulationParameters);
|
||||
|
||||
MaximumTurnTimes maxTurnTimes = new MaximumTurnTimes(1000000000, 1000000000);
|
||||
|
||||
// search best left-starting 1-turner
|
||||
genTreeGrow.setEvaluationParameters("L", 1, null);
|
||||
Path leftPath = genTreeGrow.getPath();
|
||||
PathCandidate leftBestCand = genTreeGrow.getBestCand();
|
||||
int left1TurnMiddle = 1000;
|
||||
long left1TurnMidtime = 1000000000;
|
||||
long left1TurnTimestep = genTreeGrow.getUsedTimeStep();
|
||||
if (leftBestCand != null) {
|
||||
left1TurnMiddle = leftBestCand.getIndexOfTurnLR();
|
||||
left1TurnMidtime = left1TurnMiddle * left1TurnTimestep;
|
||||
maxTurnTimes.left = left1TurnMiddle * left1TurnTimestep;
|
||||
}
|
||||
|
||||
// search best right-starting 1-turner
|
||||
@@ -139,11 +169,10 @@ public class SailingSimulatorImpl implements SailingSimulator {
|
||||
Path rightPath = genTreeGrow.getPath();
|
||||
PathCandidate rightBestCand = genTreeGrow.getBestCand();
|
||||
int right1TurnMiddle = 1000;
|
||||
long right1TurnMidtime = 1000000000;
|
||||
long right1TurnTimestep = genTreeGrow.getUsedTimeStep();
|
||||
if (rightBestCand != null) {
|
||||
right1TurnMiddle = rightBestCand.getIndexOfTurnRL();
|
||||
right1TurnMidtime = right1TurnMiddle * right1TurnTimestep;
|
||||
maxTurnTimes.right = right1TurnMiddle * right1TurnTimestep;
|
||||
}
|
||||
|
||||
Path optPath = null;
|
||||
@@ -162,14 +191,14 @@ public class SailingSimulatorImpl implements SailingSimulator {
|
||||
// PathGeneratorOpportunistVMG genOpportunistic = new PathGeneratorOpportunistVMG(simulationParameters);
|
||||
|
||||
// left-starting opportunist
|
||||
genOpportunistic.setEvaluationParameters(left1TurnMidtime, right1TurnMidtime, true);
|
||||
genOpportunistic.setEvaluationParameters(maxTurnTimes, true);
|
||||
oppPathL = genOpportunistic.getPath();
|
||||
if (genOpportunistic.getTurns() == 1) {
|
||||
oppPathL = leftPath;
|
||||
}
|
||||
|
||||
// right-starting opportunist
|
||||
genOpportunistic.setEvaluationParameters(left1TurnMidtime, right1TurnMidtime, false);
|
||||
genOpportunistic.setEvaluationParameters(maxTurnTimes, false);
|
||||
oppPathR = genOpportunistic.getPath();
|
||||
if (genOpportunistic.getTurns() == 1) {
|
||||
oppPathR = rightPath;
|
||||
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.sap.sailing.simulator.SimulationService;
|
||||
import com.sap.sailing.simulator.SimulationServiceFactory;
|
||||
|
||||
public class SimulationServiceFactoryImpl implements SimulationServiceFactory {
|
||||
|
||||
public SimulationService getService(Executor executor) {
|
||||
return new SimulationServiceImpl(executor);
|
||||
}
|
||||
|
||||
}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathType;
|
||||
import com.sap.sailing.simulator.SailingSimulator;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.SimulationService;
|
||||
|
||||
public class SimulationServiceImpl implements SimulationService {
|
||||
|
||||
private Executor executor;
|
||||
private SailingSimulator simulator;
|
||||
|
||||
public SimulationServiceImpl(Executor executor) {
|
||||
this.executor = executor;
|
||||
// TODO: add smart-future-cache for simulation
|
||||
}
|
||||
|
||||
public Map<PathType, Path> getAllPaths(SimulationParameters simuPars) {
|
||||
|
||||
// TODO: check smart-future-cache
|
||||
|
||||
this.simulator = new SailingSimulatorImpl(simuPars);
|
||||
Map<PathType, Path> result = new HashMap<PathType, Path>();
|
||||
// schedule omniscient task
|
||||
FutureTask<Path> 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);
|
||||
|
||||
// collect 1-turner results
|
||||
try {
|
||||
result.put(PathType.ONE_TURNER_LEFT, task1TurnerLeft.get());
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
result.put(PathType.ONE_TURNER_RIGHT, task1TurnerRight.get());
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// schedule opportunist tasks (which depend on 1-turner results)
|
||||
FutureTask<Path> taskOpportunistLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.OPPORTUNIST_LEFT));
|
||||
FutureTask<Path> taskOpportunistRight = new FutureTask<Path>(
|
||||
() -> simulator.getPath(PathType.OPPORTUNIST_RIGHT));
|
||||
executor.execute(taskOpportunistLeft);
|
||||
executor.execute(taskOpportunistRight);
|
||||
|
||||
// collect opportunist results
|
||||
try {
|
||||
result.put(PathType.OPPORTUNIST_LEFT, taskOpportunistLeft.get());
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
result.put(PathType.OPPORTUNIST_RIGHT, taskOpportunistRight.get());
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// collect omniscient result (last, since usually slowest calculation)
|
||||
try {
|
||||
result.put(PathType.OMNISCIENT, taskOmniscient.get());
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// TODO: update smart-future-cache
|
||||
|
||||
// return combined result
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PathType, Path> getAllPathsEvenTimed(SimulationParameters simuPars, long millisecondsStep) {
|
||||
Map<PathType, Path> allTimedPaths = new HashMap<PathType, Path>();
|
||||
Map<PathType, Path> allPaths = this.getAllPaths(simuPars);
|
||||
for (Entry<PathType, Path> entry : allPaths.entrySet()) {
|
||||
PathType pathType = entry.getKey();
|
||||
Path pathValue = entry.getValue();
|
||||
allTimedPaths.put(pathType, pathValue.getEvenTimedPath(millisecondsStep));
|
||||
}
|
||||
return allTimedPaths;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user