check for zero-speed due to missing wind or polar data; extend get-even-timed-path for the case of two cornerpoints per step; scale turning step of finish-phase 1-turner to layline; fix plausibility check;

This commit is contained in:
Christopher Ronnewinkel (D036654)
2015-04-29 09:36:00 +02:00
parent 4c97142b8d
commit 3e69f05216
14 changed files with 123 additions and 96 deletions
@@ -403,7 +403,7 @@ import com.sap.sailing.simulator.PolarDiagram;
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.SparsePolarDataException;
import com.sap.sailing.simulator.impl.SparseSimulationDataException;
import com.sap.sailing.xrr.schema.RegattaResults;
import com.sap.sailing.xrr.structureimport.SeriesParameters;
import com.sap.sailing.xrr.structureimport.StructureImporter;
@@ -1434,7 +1434,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
PolarDiagram polarDiagram;
try {
polarDiagram = new PolarDiagramGPS(boatClass, polarData);
} catch (SparsePolarDataException e) {
} catch (SparseSimulationDataException e) {
polarDiagram = null;
// TODO: raise a UI message, to inform user about missing polar data resulting in unability to simulate
}
@@ -49,7 +49,7 @@ 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.impl.SparseSimulationDataException;
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
import com.sap.sailing.simulator.windfield.impl.WindFieldTrackedRaceImpl;
@@ -391,7 +391,7 @@ public class SimulationServiceImpl implements SimulationService {
PolarDiagram polarDiagram;
try {
polarDiagram = new PolarDiagramGPS(boatClass, polarDataService);
} catch (SparsePolarDataException e) {
} catch (SparseSimulationDataException e) {
polarDiagram = null;
// TODO: raise a UI message, to inform user about missing polar data resulting in unability to simulate
}
@@ -441,19 +441,21 @@ public class SimulationServiceImpl implements SimulationService {
}
// collect 1-turner results
result.put(PathType.ONE_TURNER_LEFT, task1TurnerLeft.get());
result.put(PathType.ONE_TURNER_RIGHT, task1TurnerRight.get());
Path path1TurnerLeft = task1TurnerLeft.get();
result.put(PathType.ONE_TURNER_LEFT, path1TurnerLeft);
Path path1TurnerRight = task1TurnerRight.get();
result.put(PathType.ONE_TURNER_RIGHT, path1TurnerRight);
if (simulationParameters.showOpportunist()) {
// collect opportunist results
Path pathOpportunistLeft = taskOpportunistLeft.get();
if (pathOpportunistLeft.getTurnCount() == 1) {
pathOpportunistLeft = result.get(PathType.ONE_TURNER_LEFT);
if (!path1TurnerLeft.getAlgorithmTimedOut() && (pathOpportunistLeft.getTurnCount() == 1)) {
pathOpportunistLeft = path1TurnerLeft;
}
result.put(PathType.OPPORTUNIST_LEFT, pathOpportunistLeft);
Path pathOpportunistRight = taskOpportunistRight.get();
if (pathOpportunistRight.getTurnCount() == 1) {
pathOpportunistRight = result.get(PathType.ONE_TURNER_RIGHT);
if (!path1TurnerRight.getAlgorithmTimedOut() && (pathOpportunistRight.getTurnCount() == 1)) {
pathOpportunistRight = path1TurnerRight;
}
result.put(PathType.OPPORTUNIST_RIGHT, pathOpportunistRight);
}
@@ -461,11 +463,11 @@ public class SimulationServiceImpl implements SimulationService {
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 (!path1TurnerLeft.getAlgorithmTimedOut() && (pathOmniscient.getFinalTime().after(path1TurnerLeft.getFinalTime()))) {
pathOmniscient = path1TurnerLeft;
}
if (pathOmniscient.getFinalTime().after(result.get(PathType.ONE_TURNER_RIGHT).getFinalTime())) {
pathOmniscient = result.get(PathType.ONE_TURNER_RIGHT);
if (!path1TurnerRight.getAlgorithmTimedOut() && (pathOmniscient.getFinalTime().after(path1TurnerRight.getFinalTime()))) {
pathOmniscient = path1TurnerRight;
}
result.put(PathType.OMNISCIENT, pathOmniscient);
}
@@ -21,7 +21,7 @@ import com.sap.sailing.simulator.impl.PolarDiagram49STG;
import com.sap.sailing.simulator.impl.RectangularGrid;
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.impl.SparseSimulationDataException;
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
import com.sap.sailing.simulator.windfield.WindControlParameters;
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
@@ -34,7 +34,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
public class SimulatorTest {
@Test
public void testSailingSimulatorALL() throws SparsePolarDataException {
public void testSailingSimulatorALL() throws SparseSimulationDataException {
// race course: copacabana, rio de janeiro, brasil
Position start = new DegreePosition(-22.975779, -43.17421);
@@ -1,6 +1,6 @@
package com.sap.sailing.simulator;
import com.sap.sailing.simulator.impl.SparsePolarDataException;
import com.sap.sailing.simulator.impl.SparseSimulationDataException;
public interface PathGenerator {
@@ -8,9 +8,9 @@ public interface PathGenerator {
SimulationParameters getSimulationParameters();
Path getPath() throws SparsePolarDataException;
Path getPath() throws SparseSimulationDataException;
Path getPathEvenTimed(long stepMilliseconds) throws SparsePolarDataException;
Path getPathEvenTimed(long stepMilliseconds) throws SparseSimulationDataException;
public boolean isTimedOut();
@@ -2,7 +2,7 @@ package com.sap.sailing.simulator;
import java.util.List;
import com.sap.sailing.simulator.impl.SparsePolarDataException;
import com.sap.sailing.simulator.impl.SparseSimulationDataException;
public interface Simulator {
@@ -11,7 +11,7 @@ public interface Simulator {
SimulationParameters getSimulationParameters();
Path getPath(PathType pathType) throws SparsePolarDataException;
Path getPath(PathType pathType) throws SparseSimulationDataException;
Path getRaceCourse();
@@ -92,7 +92,6 @@ public class PathGenerator1Turner360 extends PathGeneratorBase {
long turnloss = polarDiagram.getTurnLoss(); // 4000;
Distance courseLength = posStart.getDistance(posEnd);
Bearing bearStart2End = posStart.getBearingGreatCircle(posEnd);
Position currentPosition = posStart;
TimePoint currentTime = startTime;
TimePoint nextTime;
@@ -109,7 +108,6 @@ public class PathGenerator1Turner360 extends PathGeneratorBase {
} else {
stepMax = this.evalStepMax;
}
double[] reachTime = new double[stepMax];
boolean targetFound;
long timeStep;
if (this.evalTimeStep == 0) {
@@ -118,11 +116,10 @@ public class PathGenerator1Turner360 extends PathGeneratorBase {
timeStep = this.evalTimeStep;
}
Bearing direction;
Bearing layline;
double newDistance;
double minimumDistance = courseLength.getMeters();
//double overallMinimumDistance = courseLength.getMeters();
//int stepOfOverallMinimumDistance = stepMax;
LinkedList<TimedPositionWithSpeed> path = null;
LinkedList<TimedPositionWithSpeed> allminpath = null;
TimePoint minimumTime = startTime.plus(24*60*60*1000);
@@ -130,7 +127,6 @@ public class PathGenerator1Turner360 extends PathGeneratorBase {
currentPosition = posStart;
currentTime = startTime;
reachTime[step] = courseLength.getMeters();
targetFound = false;
minimumDistance = courseLength.getMeters();
path = new LinkedList<TimedPositionWithSpeed>();
@@ -159,19 +155,24 @@ public class PathGenerator1Turner360 extends PathGeneratorBase {
if (pointOfSail == PointOfSail.TACKING) {
if (leftSide) {
direction = polarDiagram.optimalDirectionsUpwind()[0];
layline = polarDiagram.optimalDirectionsUpwind()[1].reverse();
} else {
direction = polarDiagram.optimalDirectionsUpwind()[1];
layline = polarDiagram.optimalDirectionsUpwind()[0].reverse();
}
prevPointOfSail = pointOfSail;
} else if (pointOfSail == PointOfSail.JIBING) {
if (leftSide) {
direction = polarDiagram.optimalDirectionsDownwind()[1];
layline = polarDiagram.optimalDirectionsDownwind()[0].reverse();
} else {
direction = polarDiagram.optimalDirectionsDownwind()[0];
layline = polarDiagram.optimalDirectionsDownwind()[1].reverse();
}
prevPointOfSail = pointOfSail;
} else {
direction = bearTarget;
direction = bearTarget;
layline = null;
}
SpeedWithBearing currSpeed;
if ((pointOfSail != PointOfSail.REACHING) || !polarDiagram.hasCurrent()) {
@@ -181,6 +182,19 @@ public class PathGenerator1Turner360 extends PathGeneratorBase {
}
nextTime = new MillisecondsTimePoint(currentTime.asMillis() + timeStep);
Position nextPosition = currSpeed.travelTo(currentPosition, currentTime, nextTime);
// scale step at layline
if (layline != null) {
Bearing nextBearTarget = nextPosition.getBearingGreatCircle(posEnd);
Util.Pair<PointOfSail, BoatDirection> nextPointOfSailAndReachingSide = polarDiagram.getPointOfSail(nextBearTarget);
PointOfSail nextPointOfSail = nextPointOfSailAndReachingSide.getA();
if (nextPointOfSail != pointOfSail) {
Position tmpPosition = nextPosition.projectToLineThrough(posEnd, layline);
long scaledTimeStep = Math.round(timeStep*currentPosition.getDistance(tmpPosition).getMeters() / currentPosition.getDistance(nextPosition).getMeters());
nextTime = new MillisecondsTimePoint(currentTime.asMillis() + scaledTimeStep);
nextPosition = currSpeed.travelTo(currentPosition, currentTime, nextTime);
}
}
newDistance = nextPosition.getDistance(posEnd).getMeters();
if (newDistance < minimumDistance) {
minimumDistance = newDistance;
@@ -190,14 +204,12 @@ public class PathGenerator1Turner360 extends PathGeneratorBase {
currentTime = nextTime;
}
if (currentPosition.getDistance(posEnd).getMeters() < reachingTolerance * courseLength.getMeters()) {
reachTime[step] = minimumDistance;
targetFound = true;
if (posStart.getDistance(currentPosition).getMeters() > posStart.getDistance(posEnd).getMeters()) {
targetFound = true;
}
}
//if (minimumDistance < overallMinimumDistance) {
if (targetFound&&(currentTime.before(minimumTime))) {
//overallMinimumDistance = minimumDistance;
minimumTime = currentTime;
//stepOfOverallMinimumDistance = step;
allminpath = path;
}
stepLeft++;
@@ -251,18 +263,12 @@ public class PathGenerator1Turner360 extends PathGeneratorBase {
currentTime = nextTime;
}
if (currentPosition.getDistance(posEnd).getMeters() < reachingTolerance * courseLength.getMeters()) {
Bearing bearPath2End = currentPosition.getBearingGreatCircle(posEnd);
double bearDiff = bearPath2End.getDegrees() - bearStart2End.getDegrees();
reachTime[step] = minimumDistance * Math.signum(bearDiff);
if (posStart.getDistance(currentPosition).getMeters() > posStart.getDistance(posEnd).getMeters()) {
targetFound = true;
}
}
//if (minimumDistance < overallMinimumDistance) {
if (targetFound&&(currentTime.before(minimumTime))) {
//overallMinimumDistance = minimumDistance;
minimumTime = currentTime;
//stepOfOverallMinimumDistance = step;
allminpath = new LinkedList<TimedPositionWithSpeed>(path);
}
stepRight++;
@@ -34,7 +34,7 @@ public class PathGeneratorBase implements PathGenerator {
}
@Override
public Path getPath() throws SparsePolarDataException {
public Path getPath() throws SparseSimulationDataException {
return null;
}
@@ -51,7 +51,7 @@ public class PathGeneratorBase implements PathGenerator {
}
@Override
public Path getPathEvenTimed(long stepMilliseconds) throws SparsePolarDataException {
public Path getPathEvenTimed(long stepMilliseconds) throws SparseSimulationDataException {
Path path = this.getPath();
@@ -60,7 +60,7 @@ public class PathGeneratorOpportunistEuclidian360 extends PathGeneratorBase {
@Override
public Path getPath() {
public Path getPath() throws SparseSimulationDataException {
this.algorithmStartTime = MillisecondsTimePoint.now();
WindFieldGenerator wf = parameters.getWindField();
@@ -79,7 +79,7 @@ public class PathGeneratorOpportunistEuclidian360 extends PathGeneratorBase {
BoatDirection prevDirection = BoatDirection.NONE;
long turnLoss = polarDiagram.getTurnLoss(); // time lost when doing a turn
double fracFinishPhase = 0.075;
double fracFinishPhase = 0.05;
TimePoint travelTimeLeft;
TimePoint travelTimeRight;
@@ -167,7 +167,15 @@ public class PathGeneratorOpportunistEuclidian360 extends PathGeneratorBase {
}
// get boat speed at current position
SpeedWithBearing boatSpeedLeft = polarDiagram.getSpeedAtBearing(bearLeft);
if (boatSpeedLeft.getKnots() == 0) {
logger.severe("Travel Speed for NextDirection '" + "L" + "' is ZERO. This must NOT happen.");
throw new SparseSimulationDataException();
}
SpeedWithBearing boatSpeedRight = polarDiagram.getSpeedAtBearing(bearRight);
if (boatSpeedRight.getKnots() == 0) {
logger.severe("Travel Speed for NextDirection '" + "R" + "' is ZERO. This must NOT happen.");
throw new SparseSimulationDataException();
}
logger.finest("left boat speed:" + boatSpeedLeft.getKnots() + " angle:" + boatSpeedLeft.getBearing().getDegrees()
+ " right boat speed:" + boatSpeedRight.getKnots() + " angle:" + boatSpeedRight.getBearing().getDegrees());
@@ -183,7 +191,7 @@ public class PathGeneratorOpportunistEuclidian360 extends PathGeneratorBase {
travelTimeRight = new MillisecondsTimePoint(nextTimeVal);
}
// get next boat positions by travelling left and right
// get next boat positions by traveling left and right
Position nextBoatPositionLeft = boatSpeedLeft.travelTo(currentPosition, currentTime, travelTimeLeft);
Position nextBoatPositionRight = boatSpeedRight.travelTo(currentPosition, currentTime, travelTimeRight);
// calculate distance to target left and right
@@ -267,7 +275,11 @@ public class PathGeneratorOpportunistEuclidian360 extends PathGeneratorBase {
} else {
boatSpeedTarget = polarDiagram.getSpeedAtBearing(bearTarget);
}
// get next boat positions by travelling left and right
if ((boatSpeedTarget.getKnots() == 0)&&(!polarDiagram.hasCurrent())) {
logger.severe("Travel Speed for NextDirection '" + (reachingSide==BoatDirection.REACH_LEFT?"D":"E") + "' is ZERO. This must NOT happen.");
throw new SparseSimulationDataException();
}
// get next boat positions by traveling reach
Position nextBoatPositionReach = boatSpeedTarget.travelTo(currentPosition, currentTime, travelTimeReach);
path.add(new TimedPositionWithSpeedImpl(nextTime, nextBoatPositionReach, currentWind));
currentPosition = nextBoatPositionReach;
@@ -288,11 +300,6 @@ public class PathGeneratorOpportunistEuclidian360 extends PathGeneratorBase {
currentHeight = startPos.getDistance(endPos).getMeters() - posHeight.getDistance(startPos).getMeters();
}
// remove last position, if already too close to target for finish-phase
if (currentHeight < startPos.getDistance(endPos).getMeters()*fracFinishPhase/2) {
path.remove(path.size()-1);
}
if (!this.isTimedOut()) {
//
// FinishPhase: get 1-turners to finalize course
@@ -310,11 +317,11 @@ public class PathGeneratorOpportunistEuclidian360 extends PathGeneratorBase {
long finishTimeStep = Math.max(500, timeStep / 10);
int finishStepsLeft = (int) Math.round(1.5*(path.get(path.size()-1).getTimePoint().asMillis() - path.get(0).getTimePoint().asMillis()) / (1-fracFinishPhase) * fracFinishPhase / finishTimeStep);
generator1Turner.setEvaluationParameters(true, currentPosition, endPos, leftTurningTime, finishTimeStep, finishStepsLeft, 0.05, this.upwindLeg);
generator1Turner.setEvaluationParameters(true, currentPosition, endPos, leftTurningTime, finishTimeStep, finishStepsLeft, 0.2, this.upwindLeg);
Path leftPath = generator1Turner.getPath();
int finishStepsRight = (int) Math.round(1.5*(path.get(path.size()-1).getTimePoint().asMillis() - path.get(0).getTimePoint().asMillis()) / (1-fracFinishPhase) * fracFinishPhase / finishTimeStep);
generator1Turner.setEvaluationParameters(false, currentPosition, endPos, rightTurningTime, finishTimeStep, finishStepsRight, 0.05, this.upwindLeg);
generator1Turner.setEvaluationParameters(false, currentPosition, endPos, rightTurningTime, finishTimeStep, finishStepsRight, 0.2, this.upwindLeg);
Path rightPath = generator1Turner.getPath();
if ((leftPath.getPathPoints() != null) && (rightPath.getPathPoints() != null)) {
@@ -109,7 +109,7 @@ public class PathGeneratorTreeGrow360 extends PathGeneratorBase {
// default: L - left, R - right
// extended: M - wide left, S - wide right
TimedPosition getStep(TimedPosition pos, Wind posWind, Position posEnd, long timeStep, long turnLoss, boolean sameBaseDirection,
char nextDirection) throws SparsePolarDataException {
char nextDirection) throws SparseSimulationDataException {
TimePoint curTime = pos.getTimePoint();
Position curPosition = pos.getPosition();
@@ -152,9 +152,14 @@ public class PathGeneratorTreeGrow360 extends PathGeneratorBase {
if (travelSpeed == null) {
logger.severe("Travel Speed for NextDirection '" + nextDirection + "' is NULL. This must NOT happen.");
}
throw new SparsePolarDataException();
throw new SparseSimulationDataException();
}
if ((travelSpeed.getKnots() == 0)&&(!polarDiagram.hasCurrent())) {
logger.severe("Travel Speed for NextDirection '" + nextDirection + "' is ZERO. This must NOT happen.");
throw new SparseSimulationDataException();
}
TimePoint travelTime;
TimePoint nextTime = new MillisecondsTimePoint(curTime.asMillis() + timeStep);
if (sameBaseDirection) {
@@ -201,7 +206,7 @@ public class PathGeneratorTreeGrow360 extends PathGeneratorBase {
// get path candidate measuring height towards (local, current-apparent) wind
PathCandidate getPathCandWind(PathCandidate path, char nextDirection, long timeStep, long turnLoss,
Position posStart, Position posEnd, double tgtHeight) throws SparsePolarDataException {
Position posStart, Position posEnd, double tgtHeight) throws SparseSimulationDataException {
char prevDirection = path.path.charAt(path.path.length() - 1);
boolean sameBaseDirection = this.isSameDirection(prevDirection, nextDirection);
@@ -267,7 +272,7 @@ public class PathGeneratorTreeGrow360 extends PathGeneratorBase {
// generate path candidates based on bearing to target
List<PathCandidate> getPathCandsBeatWind(PathCandidate path, long timeStep, long turnLoss, Position posStart,
Position posEnd, double tgtHeight) throws SparsePolarDataException {
Position posEnd, double tgtHeight) throws SparseSimulationDataException {
// determine bearing of target
Bearing bearTarget = path.pos.getPosition().getBearingGreatCircle(posEnd);
@@ -399,7 +404,7 @@ public class PathGeneratorTreeGrow360 extends PathGeneratorBase {
}
Util.Pair<List<PathCandidate>, List<PathCandidate>> generateCandidate(List<PathCandidate> oldPaths, long timeStep,
long turnLoss, Position posStart, Position posMiddle, Position posEnd, double tgtHeight) throws SparsePolarDataException {
long turnLoss, Position posStart, Position posMiddle, Position posEnd, double tgtHeight) throws SparseSimulationDataException {
List<PathCandidate> newPathCands;
List<PathCandidate> leftPaths = new ArrayList<PathCandidate>();
@@ -585,7 +590,7 @@ public class PathGeneratorTreeGrow360 extends PathGeneratorBase {
}
@Override
public Path getPath() throws SparsePolarDataException {
public Path getPath() throws SparseSimulationDataException {
this.algorithmStartTime = MillisecondsTimePoint.now();
WindFieldGenerator wf = this.parameters.getWindField();
@@ -140,9 +140,6 @@ public class PathImpl implements Path, Serializable {
TimedPositionWithSpeed p1 = this.pathPoints.get(idx - 1);
TimedPositionWithSpeed p2 = this.pathPoints.get(idx);
Distance dist = p1.getPosition().getDistance(p2.getPosition());
// long nextTime = (double)nextTimePoint.asMillis();
// System.out.println(""+(nextTimePoint.asMillis() -
// p1.getTimePoint().asMillis())+" - "+(p2.getTimePoint().asMillis() - p1.getTimePoint().asMillis()));
double scale1 = nextTimePoint.asMillis() - p1.getTimePoint().asMillis();
double scale2 = p2.getTimePoint().asMillis() - p1.getTimePoint().asMillis();
Position nextPosition = p1.getPosition().translateGreatCircle(
@@ -168,32 +165,42 @@ public class PathImpl implements Path, Serializable {
double scaleDist = 0.01 * nextPoint.getPosition().getDistance(prevPoint.getPosition())
.getMeters();
// evaluate collected points to potentially find turn/corner
double maxDist = 0;
TimedPositionWithSpeed maxPoint = null;
// evaluate collected points to potentially find turn/corner (up to two)
double prevSide = 0;
int maxCnt = 0;
ArrayList<TimedPositionWithSpeed> maxPoint = new ArrayList<TimedPositionWithSpeed>();
maxPoint.add(path.get(0));
ArrayList<Double> maxDist = new ArrayList<Double>();
maxDist.add(new Double(0));
Bearing nextBear = prevPoint.getPosition().getBearingGreatCircle(nextPoint.getPosition());
for (int jdx = 0; jdx < points.size(); jdx++) {
Position pcur = points.get(jdx).getPosition();
Position ptmp = pcur.projectToLineThrough(prevPoint.getPosition(), nextBear);
double lineDist = ptmp.getDistance(pcur).getMeters();
if (lineDist > maxDist) {
maxPoint = points.get(jdx);
maxDist = lineDist;
double side = Math.signum(nextBear.getDifferenceTo(prevPoint.getPosition().getBearingGreatCircle(pcur)).getDegrees());
boolean sideChange = (prevSide != 0)&&(side != prevSide);
double lineDist = Math.round(ptmp.getDistance(pcur).getMeters()*1000.0)/1000.0;
if (sideChange) {
maxCnt++;
maxDist.add(new Double(0));
maxPoint.add(path.get(0));
}
if (lineDist > maxDist.get(maxCnt)) {
maxPoint.set(maxCnt, points.get(jdx));
maxDist.set(maxCnt, lineDist);
}
prevSide = side;
}
if (maxDist > scaleDist) {
// add intermediate corner point
SpeedWithBearing maxWind = null;
if (this.windField != null) {
maxWind = this.windField.getWind(new TimedPositionImpl(maxPoint.getTimePoint(), maxPoint
.getPosition()));
maxPoint = new TimedPositionWithSpeedImpl(maxPoint.getTimePoint(), maxPoint.getPosition(),
maxWind);
for(int cnt=0; cnt<=maxCnt; cnt++) {
if (maxDist.get(cnt) > scaleDist) {
// add intermediate corner point
SpeedWithBearing maxWind = null;
if (this.windField != null) {
maxWind = this.windField.getWind(new TimedPositionImpl(maxPoint.get(cnt).getTimePoint(), maxPoint.get(cnt).getPosition()));
maxPoint.set(cnt, new TimedPositionWithSpeedImpl(maxPoint.get(cnt).getTimePoint(), maxPoint.get(cnt).getPosition(), maxWind));
}
path.add(maxPoint.get(cnt));
}
path.add(maxPoint);
}
// add next even timed point
@@ -25,7 +25,7 @@ public class PolarDiagramGPS extends PolarDiagramBase {
private final PolarDataService polarData;
private double avgSpeed;
public PolarDiagramGPS(BoatClass boatClass, PolarDataService polarData) throws SparsePolarDataException {
public PolarDiagramGPS(BoatClass boatClass, PolarDataService polarData) throws SparseSimulationDataException {
this.boatClass = boatClass;
this.polarData = polarData;
@@ -102,7 +102,7 @@ public class PolarDiagramGPS extends PolarDiagramBase {
}
if ((beatAngles.size() <= 1)||(beatSpeed.size() <= 1)||(jibeAngles.size() <= 1)||(jibeSpeed.size() <= 1)) {
throw new SparsePolarDataException();
throw new SparseSimulationDataException();
}
NavigableMap<Speed, NavigableMap<Bearing, Speed>> mapSpeedTable = new TreeMap<Speed, NavigableMap<Bearing, Speed>>();
@@ -40,7 +40,7 @@ public class SimulatorImpl implements Simulator {
}
@Override
public Path getPath(PathType pathType) throws SparsePolarDataException {
public Path getPath(PathType pathType) throws SparseSimulationDataException {
PathGeneratorTreeGrow360 genTreeGrow;
PathGeneratorOpportunistEuclidian360 genOpportunistic;
Path path = null;
@@ -1,15 +0,0 @@
package com.sap.sailing.simulator.impl;
public class SparsePolarDataException extends Exception {
private static final long serialVersionUID = 4134116458606258315L;
public SparsePolarDataException() {
super("Not enough polar data to represent beat/jibe angles/speeds for simulation.");
}
public SparsePolarDataException(String string) {
super(string);
}
}
@@ -0,0 +1,15 @@
package com.sap.sailing.simulator.impl;
public class SparseSimulationDataException extends Exception {
private static final long serialVersionUID = 4134116458606258315L;
public SparseSimulationDataException() {
super("Not enough simulation data available (sparse wind data or sparse polar data for beat/jibe angles/speeds).");
}
public SparseSimulationDataException(String string) {
super(string);
}
}