mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-22 13:45:42 +00:00
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:
+2
-2
@@ -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
|
||||
}
|
||||
|
||||
+14
-12
@@ -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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -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();
|
||||
|
||||
|
||||
+23
-17
@@ -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++;
|
||||
|
||||
+2
-2
@@ -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();
|
||||
|
||||
|
||||
+18
-11
@@ -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)) {
|
||||
|
||||
+11
-6
@@ -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
|
||||
|
||||
+2
-2
@@ -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>>();
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
-15
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user