mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-19 18:50:03 +00:00
Merge branch 'simulator_merge_from_master' of ssh://git.wdf.sap.corp:29418/SAPSail/sapsailingcapture into simulator_merge_from_master
Conflicts: java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PolarDiagram49.java
This commit is contained in:
commit
9504ddabba
16 files changed
+2243
-1822
No files matched your search
@@ -0,0 +1,13 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PathGenerator {
|
||||
|
||||
void setSimulationParameters(SimulationParameters params);
|
||||
SimulationParameters getSimulationParameters();
|
||||
|
||||
Path getPath();
|
||||
List<TimedPositionWithSpeed> getPathEvenTimed(long millisecondsStep);
|
||||
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
|
||||
@@ -8,7 +8,6 @@ public interface SailingSimulator {
|
||||
void setSimulationParameters(SimulationParameters params);
|
||||
SimulationParameters getSimulationParameters();
|
||||
|
||||
Path getOptimumPath();
|
||||
Map<String, Path> getAllPaths();
|
||||
Map<String, List<TimedPositionWithSpeed>> getAllPathsEvenTimed(long millisecondsStep);
|
||||
|
||||
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathGenerator;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
import com.sap.sailing.simulator.WindFieldGenerator;
|
||||
|
||||
public class PathGenerator1Turner implements PathGenerator {
|
||||
|
||||
class result1Turn {
|
||||
public result1Turn(Path[] p, char s, int n) {
|
||||
paths = p;
|
||||
side = s;
|
||||
middle = n;
|
||||
}
|
||||
|
||||
Path[] paths;
|
||||
char side;
|
||||
int middle;
|
||||
}
|
||||
|
||||
// private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
private SimulationParameters simulationParameters;
|
||||
private boolean leftSide;
|
||||
private result1Turn result;
|
||||
|
||||
public PathGenerator1Turner(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSimulationParameters(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationParameters getSimulationParameters() {
|
||||
return simulationParameters;
|
||||
}
|
||||
|
||||
public void setEvaluationParameters(boolean leftSideVal) {
|
||||
this.leftSide = leftSideVal;
|
||||
}
|
||||
|
||||
public int getMiddle() {
|
||||
return this.result.middle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
WindFieldGenerator windField = simulationParameters.getWindField();
|
||||
PolarDiagram polarDiagram = simulationParameters.getBoatPolarDiagram();
|
||||
Position start = simulationParameters.getCourse().get(0);
|
||||
Position end = simulationParameters.getCourse().get(1);
|
||||
TimePoint startTime = windField.getStartTime();// new MillisecondsTimePoint(0);
|
||||
|
||||
long turnloss = polarDiagram.getTurnLoss(); // 4000;
|
||||
|
||||
Distance courseLength = start.getDistance(end);
|
||||
Bearing bearStart2End = start.getBearingGreatCircle(end);
|
||||
Position currentPosition = start;
|
||||
TimePoint currentTime = startTime;
|
||||
TimePoint nextTime;
|
||||
|
||||
double reachingTolerance = 0.03;
|
||||
int stepMax = 800;
|
||||
double[] reachTime = new double[stepMax];
|
||||
boolean targetFound;
|
||||
long timeStep = windField.getTimeStep().asMillis() / 5;
|
||||
Bearing direction;
|
||||
|
||||
double newDistance;
|
||||
double minimumDistance = courseLength.getMeters();
|
||||
double overallMinimumDistance = courseLength.getMeters();
|
||||
int stepOfOverallMinimumDistance = stepMax;
|
||||
LinkedList<TimedPositionWithSpeed> path = null;
|
||||
// LinkedList<TimedPositionWithSpeed> prevpath = null;
|
||||
// LinkedList<TimedPositionWithSpeed> xpath1 = null;
|
||||
// LinkedList<TimedPositionWithSpeed> xpath2 = null;
|
||||
|
||||
LinkedList<TimedPositionWithSpeed> allminpath = null;
|
||||
|
||||
for (int step = 0; step < stepMax; step++) {
|
||||
|
||||
currentPosition = start;
|
||||
currentTime = startTime;
|
||||
reachTime[step] = courseLength.getMeters();
|
||||
targetFound = false;
|
||||
minimumDistance = courseLength.getMeters();
|
||||
path = new LinkedList<TimedPositionWithSpeed>();
|
||||
path.addLast(new TimedPositionWithSpeedImpl(currentTime, currentPosition, null));
|
||||
|
||||
int stepLeft = 0;
|
||||
while ((stepLeft < step) && (!targetFound)) {
|
||||
|
||||
SpeedWithBearing currentWind = windField.getWind(new TimedPositionImpl(currentTime, currentPosition));
|
||||
polarDiagram.setWind(currentWind);
|
||||
if (leftSide) {
|
||||
direction = polarDiagram.optimalDirectionsUpwind()[0];
|
||||
} else {
|
||||
direction = polarDiagram.optimalDirectionsUpwind()[1];
|
||||
}
|
||||
SpeedWithBearing currSpeed = polarDiagram.getSpeedAtBearing(direction);
|
||||
nextTime = new MillisecondsTimePoint(currentTime.asMillis() + timeStep);
|
||||
Position nextPosition = currSpeed.travelTo(currentPosition, currentTime, nextTime);
|
||||
newDistance = nextPosition.getDistance(end).getMeters();
|
||||
if (newDistance < minimumDistance) {
|
||||
minimumDistance = newDistance;
|
||||
}
|
||||
currentPosition = nextPosition;
|
||||
currentTime = nextTime;
|
||||
path.addLast(new TimedPositionWithSpeedImpl(currentTime, currentPosition, null));
|
||||
|
||||
if (currentPosition.getDistance(end).getMeters() < reachingTolerance * courseLength.getMeters()) {
|
||||
reachTime[step] = minimumDistance;
|
||||
targetFound = true;
|
||||
if (minimumDistance < overallMinimumDistance) {
|
||||
overallMinimumDistance = minimumDistance;
|
||||
stepOfOverallMinimumDistance = step;
|
||||
allminpath = path;
|
||||
}
|
||||
}
|
||||
stepLeft++;
|
||||
}
|
||||
|
||||
currentTime = new MillisecondsTimePoint(currentTime.asMillis() + turnloss);
|
||||
|
||||
int stepRight = 0;
|
||||
while ((stepRight < (stepMax - step)) && (!targetFound)) {
|
||||
|
||||
SpeedWithBearing currentWind = windField.getWind(new TimedPositionImpl(currentTime, currentPosition));
|
||||
polarDiagram.setWind(currentWind);
|
||||
if (leftSide) {
|
||||
direction = polarDiagram.optimalDirectionsUpwind()[1];
|
||||
} else {
|
||||
direction = polarDiagram.optimalDirectionsUpwind()[0];
|
||||
}
|
||||
SpeedWithBearing currSpeed = polarDiagram.getSpeedAtBearing(direction);
|
||||
nextTime = new MillisecondsTimePoint(currentTime.asMillis() + timeStep);
|
||||
Position nextPosition = currSpeed.travelTo(currentPosition, currentTime, nextTime);
|
||||
newDistance = nextPosition.getDistance(end).getMeters();
|
||||
if (newDistance < minimumDistance) {
|
||||
minimumDistance = newDistance;
|
||||
}
|
||||
currentPosition = nextPosition;
|
||||
currentTime = nextTime;
|
||||
path.addLast(new TimedPositionWithSpeedImpl(currentTime, currentPosition, null)); // currSpeed));
|
||||
|
||||
if (currentPosition.getDistance(end).getMeters() < reachingTolerance * courseLength.getMeters()) {
|
||||
// System.out.println(""+s+":"+path.size()+" dist:"+mindist);
|
||||
Bearing bearPath2End = currentPosition.getBearingGreatCircle(end);
|
||||
double bearDiff = bearPath2End.getDegrees() - bearStart2End.getDegrees();
|
||||
// System.out.println(""+s+": "+mindist+" bearDiff: "+bearDiff);
|
||||
reachTime[step] = minimumDistance * Math.signum(bearDiff);
|
||||
/*if ((prevpath != null) && (Math.signum(reachTime[step]) != Math.signum(reachTime[step - 1]))) {
|
||||
xpath1 = path;
|
||||
xpath2 = prevpath;
|
||||
}
|
||||
prevpath = path;*/
|
||||
if (start.getDistance(currentPosition).getMeters() > start.getDistance(end).getMeters()) {
|
||||
targetFound = true;
|
||||
}
|
||||
if (minimumDistance < overallMinimumDistance) {
|
||||
overallMinimumDistance = minimumDistance;
|
||||
stepOfOverallMinimumDistance = step;
|
||||
allminpath = new LinkedList<TimedPositionWithSpeed>(path);
|
||||
}
|
||||
}
|
||||
stepRight++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* for (int i=0; i<reachTime.length; i++) { System.out.println(""+i+": "+reachTime[i]); }
|
||||
*/
|
||||
|
||||
// PathImpl[] paths = new PathImpl[2];
|
||||
// paths[0] = new PathImpl(xpath1,windField);
|
||||
// paths[1] = new PathImpl(xpath2, windField);
|
||||
PathImpl[] paths = new PathImpl[1];
|
||||
paths[0] = new PathImpl(allminpath, windField);
|
||||
char side;
|
||||
if (leftSide) {
|
||||
side = 'L';
|
||||
} else {
|
||||
side = 'R';
|
||||
}
|
||||
this.result = new result1Turn(paths, side, stepOfOverallMinimumDistance);
|
||||
|
||||
return result.paths[0];
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TimedPositionWithSpeed> getPathEvenTimed(long millisecondsStep) {
|
||||
|
||||
Path path = this.getPath();
|
||||
return path.getEvenTimedPoints(millisecondsStep);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathGenerator;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
import com.sap.sailing.simulator.WindFieldGenerator;
|
||||
|
||||
public class PathGenerator1TurnerLeftDirect implements PathGenerator {
|
||||
|
||||
// private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
SimulationParameters simulationParameters;
|
||||
|
||||
public PathGenerator1TurnerLeftDirect(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSimulationParameters(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationParameters getSimulationParameters() {
|
||||
return simulationParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
// retrieve simulation parameters
|
||||
Boundary boundary = new RectangularBoundary(simulationParameters.getCourse().get(0), simulationParameters
|
||||
.getCourse().get(1));// simulationParameters.getBoundaries();
|
||||
WindFieldGenerator windField = simulationParameters.getWindField();
|
||||
PolarDiagram polarDiagram = simulationParameters.getBoatPolarDiagram();
|
||||
Position start = simulationParameters.getCourse().get(0);
|
||||
Position end = simulationParameters.getCourse().get(1);
|
||||
TimePoint startTime = windField.getStartTime();// new MillisecondsTimePoint(0);
|
||||
|
||||
Distance courseLength = start.getDistance(end);
|
||||
|
||||
// the solution path
|
||||
LinkedList<TimedPositionWithSpeed> lst = null;
|
||||
// the minimal one-turn time
|
||||
|
||||
Long timeResolution = 120000L;
|
||||
boolean turned = true;
|
||||
// boolean outOfBounds = false;
|
||||
Long minTurn = Long.MAX_VALUE;
|
||||
int turningStep = 0;
|
||||
|
||||
while (turned) {
|
||||
LinkedList<TimedPositionWithSpeed> tempLst = new LinkedList<TimedPositionWithSpeed>();
|
||||
Position currentPosition = start;
|
||||
TimePoint currentTime = startTime;
|
||||
turned = false;
|
||||
// outOfBounds = false;
|
||||
turningStep++;
|
||||
int currentStep = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
SpeedWithBearing currWind = windField.getWind(new TimedPositionImpl(currentTime, currentPosition));
|
||||
polarDiagram.setWind(currWind);
|
||||
TimePoint nextTime = new MillisecondsTimePoint(currentTime.asMillis() + timeResolution);
|
||||
tempLst.add(new TimedPositionWithSpeedImpl(currentTime, currentPosition, currWind));
|
||||
|
||||
if (currentStep >= turningStep) {
|
||||
turned = true;
|
||||
nextTime = new MillisecondsTimePoint(nextTime.asMillis() + polarDiagram.getTurnLoss());
|
||||
}
|
||||
|
||||
if (!turned) {
|
||||
Bearing direction = polarDiagram.optimalDirectionsUpwind()[0];
|
||||
// for(Bearing b: polarDiagram.optimalDirectionsUpwind())
|
||||
// if(polarDiagram.getWindSide(b) == PolarDiagram.WindSide.LEFT)
|
||||
// direction = b;
|
||||
SpeedWithBearing currSpeed = polarDiagram.getSpeedAtBearing(direction);
|
||||
currentPosition = currSpeed.travelTo(currentPosition, currentTime, nextTime);
|
||||
}
|
||||
if (turned) {
|
||||
Bearing direction1 = currentPosition.getBearingGreatCircle(end);
|
||||
Bearing direction2 = polarDiagram.optimalDirectionsUpwind()[1];
|
||||
// for(Bearing b: polarDiagram.optimalDirectionsUpwind())
|
||||
// if(polarDiagram.getWindSide(b) == PolarDiagram.WindSide.RIGHT)
|
||||
// direction2 = b;
|
||||
SpeedWithBearing currSpeed1 = polarDiagram.getSpeedAtBearing(direction1);
|
||||
SpeedWithBearing currSpeed2 = polarDiagram.getSpeedAtBearing(direction2);
|
||||
Position nextPosition1 = currSpeed1.travelTo(currentPosition, currentTime, nextTime);
|
||||
Position nextPosition2 = currSpeed2.travelTo(currentPosition, currentTime, nextTime);
|
||||
// nextPosition2.
|
||||
if (nextPosition1.getDistance(end).compareTo(nextPosition2.getDistance(end)) < 0
|
||||
&& Math.abs(direction1.getDifferenceTo(direction2).getDegrees()) < 45.0)
|
||||
currentPosition = nextPosition1;
|
||||
else
|
||||
currentPosition = nextPosition2;
|
||||
}
|
||||
|
||||
currentStep++;
|
||||
// System.out.println(currentStep + "/" + turningStep + "/" + turned);
|
||||
currentTime = nextTime;
|
||||
|
||||
if (currentTime.asMillis() > minTurn) {
|
||||
// System.out.println("out of time");
|
||||
break;
|
||||
}
|
||||
if (!boundary.isWithinBoundaries(currentPosition)) {
|
||||
// outOfBounds = true;
|
||||
// System.out.println("out of bounds");
|
||||
break;
|
||||
}
|
||||
if (currentPosition.getDistance(end).compareTo(courseLength.scale(0.005)) < 0) {
|
||||
minTurn = currentTime.asMillis();
|
||||
lst = new LinkedList<TimedPositionWithSpeed>(tempLst);
|
||||
Bearing directionToEnd = currentPosition.getBearingGreatCircle(end);
|
||||
SpeedWithBearing crtWind = windField.getWind(new TimedPositionImpl(currentTime, currentPosition));
|
||||
polarDiagram.setWind(crtWind);
|
||||
Speed speedToEnd = polarDiagram.getSpeedAtBearing(directionToEnd);
|
||||
Distance distanceToEnd = currentPosition.getDistance(end);
|
||||
Long timeToEnd = (long) (1000.0 * distanceToEnd.getMeters() / speedToEnd.getMetersPerSecond());
|
||||
TimePoint endTime = new MillisecondsTimePoint(currentTime.asMillis() + timeToEnd);
|
||||
lst.addLast(new TimedPositionWithSpeedImpl(endTime, end, crtWind));
|
||||
// System.out.println("end reached!!!");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (lst != null) {
|
||||
// lst.addLast(new TimedPositionWithSpeedImpl(new
|
||||
// MillisecondsTimePoint(lst.getLast().getTimePoint().asMillis() + timeResolution), end,
|
||||
// lst.getLast().getSpeed()));
|
||||
return new PathImpl(lst, windField);
|
||||
} else
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TimedPositionWithSpeed> getPathEvenTimed(long millisecondsStep) {
|
||||
|
||||
Path path = this.getPath();
|
||||
return path.getEvenTimedPoints(millisecondsStep);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathGenerator;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
import com.sap.sailing.simulator.WindFieldGenerator;
|
||||
|
||||
public class PathGenerator1TurnerRightDirect implements PathGenerator {
|
||||
|
||||
// private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
SimulationParameters simulationParameters;
|
||||
|
||||
public PathGenerator1TurnerRightDirect(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSimulationParameters(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationParameters getSimulationParameters() {
|
||||
return simulationParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
// retrieve simulation parameters
|
||||
Boundary boundary = new RectangularBoundary(simulationParameters.getCourse().get(0), simulationParameters
|
||||
.getCourse().get(1));// simulationParameters.getBoundaries();
|
||||
WindFieldGenerator windField = simulationParameters.getWindField();
|
||||
PolarDiagram polarDiagram = simulationParameters.getBoatPolarDiagram();
|
||||
Position start = simulationParameters.getCourse().get(0);
|
||||
Position end = simulationParameters.getCourse().get(1);
|
||||
TimePoint startTime = windField.getStartTime();// new MillisecondsTimePoint(0);
|
||||
|
||||
Distance courseLength = start.getDistance(end);
|
||||
|
||||
// the solution path
|
||||
LinkedList<TimedPositionWithSpeed> lst = null;
|
||||
// the minimal one-turn time
|
||||
|
||||
Long timeResolution = 120000L;
|
||||
boolean turned = true;
|
||||
// boolean outOfBounds = false;
|
||||
Long minTurn = Long.MAX_VALUE;
|
||||
int turningStep = 0;
|
||||
|
||||
while (turned) {
|
||||
LinkedList<TimedPositionWithSpeed> tempLst = new LinkedList<TimedPositionWithSpeed>();
|
||||
Position currentPosition = start;
|
||||
TimePoint currentTime = startTime;
|
||||
turned = false;
|
||||
// outOfBounds = false;
|
||||
turningStep++;
|
||||
int currentStep = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
SpeedWithBearing currWind = windField.getWind(new TimedPositionImpl(currentTime, currentPosition));
|
||||
polarDiagram.setWind(currWind);
|
||||
TimePoint nextTime = new MillisecondsTimePoint(currentTime.asMillis() + timeResolution);
|
||||
tempLst.add(new TimedPositionWithSpeedImpl(currentTime, currentPosition, currWind));
|
||||
|
||||
if (currentStep >= turningStep) {
|
||||
turned = true;
|
||||
nextTime = new MillisecondsTimePoint(nextTime.asMillis() + polarDiagram.getTurnLoss());
|
||||
}
|
||||
|
||||
if (!turned) {
|
||||
Bearing direction = polarDiagram.optimalDirectionsUpwind()[1];
|
||||
// for(Bearing b: polarDiagram.optimalDirectionsUpwind())
|
||||
// if(polarDiagram.getWindSide(b) == PolarDiagram.WindSide.LEFT)
|
||||
// direction = b;
|
||||
SpeedWithBearing currSpeed = polarDiagram.getSpeedAtBearing(direction);
|
||||
currentPosition = currSpeed.travelTo(currentPosition, currentTime, nextTime);
|
||||
}
|
||||
if (turned) {
|
||||
Bearing direction1 = currentPosition.getBearingGreatCircle(end);
|
||||
Bearing direction2 = polarDiagram.optimalDirectionsUpwind()[0];
|
||||
// for(Bearing b: polarDiagram.optimalDirectionsUpwind())
|
||||
// if(polarDiagram.getWindSide(b) == PolarDiagram.WindSide.RIGHT)
|
||||
// direction2 = b;
|
||||
SpeedWithBearing currSpeed1 = polarDiagram.getSpeedAtBearing(direction1);
|
||||
SpeedWithBearing currSpeed2 = polarDiagram.getSpeedAtBearing(direction2);
|
||||
Position nextPosition1 = currSpeed1.travelTo(currentPosition, currentTime, nextTime);
|
||||
Position nextPosition2 = currSpeed2.travelTo(currentPosition, currentTime, nextTime);
|
||||
// nextPosition2.
|
||||
if (nextPosition1.getDistance(end).compareTo(nextPosition2.getDistance(end)) < 0
|
||||
&& Math.abs(direction1.getDifferenceTo(direction2).getDegrees()) < 45.0)
|
||||
currentPosition = nextPosition1;
|
||||
else
|
||||
currentPosition = nextPosition2;
|
||||
}
|
||||
|
||||
currentStep++;
|
||||
// System.out.println(currentStep + "/" + turningStep + "/" + turned);
|
||||
currentTime = nextTime;
|
||||
|
||||
if (currentTime.asMillis() > minTurn) {
|
||||
// System.out.println("out of time");
|
||||
break;
|
||||
}
|
||||
if (!boundary.isWithinBoundaries(currentPosition)) {
|
||||
// outOfBounds = true;
|
||||
// System.out.println("out of bounds");
|
||||
break;
|
||||
}
|
||||
if (currentPosition.getDistance(end).compareTo(courseLength.scale(0.005)) < 0) {
|
||||
minTurn = currentTime.asMillis();
|
||||
lst = new LinkedList<TimedPositionWithSpeed>(tempLst);
|
||||
Bearing directionToEnd = currentPosition.getBearingGreatCircle(end);
|
||||
SpeedWithBearing crtWind = windField.getWind(new TimedPositionImpl(currentTime, currentPosition));
|
||||
polarDiagram.setWind(crtWind);
|
||||
Speed speedToEnd = polarDiagram.getSpeedAtBearing(directionToEnd);
|
||||
Distance distanceToEnd = currentPosition.getDistance(end);
|
||||
Long timeToEnd = (long) (1000.0 * distanceToEnd.getMeters() / speedToEnd.getMetersPerSecond());
|
||||
TimePoint endTime = new MillisecondsTimePoint(currentTime.asMillis() + timeToEnd);
|
||||
lst.addLast(new TimedPositionWithSpeedImpl(endTime, end, crtWind));
|
||||
// System.out.println("end reached!!!");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (lst != null) {
|
||||
// lst.addLast(new TimedPositionWithSpeedImpl(new
|
||||
// MillisecondsTimePoint(lst.getLast().getTimePoint().asMillis() + timeResolution), end,
|
||||
// lst.getLast().getSpeed()));
|
||||
return new PathImpl(lst, windField);
|
||||
} else
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TimedPositionWithSpeed> getPathEvenTimed(long millisecondsStep) {
|
||||
|
||||
Path path = this.getPath();
|
||||
return path.getEvenTimedPoints(millisecondsStep);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathGenerator;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
import com.sap.sailing.simulator.WindFieldGenerator;
|
||||
|
||||
public class PathGeneratorDijkstra implements PathGenerator {
|
||||
|
||||
// private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
SimulationParameters simulationParameters;
|
||||
|
||||
public PathGeneratorDijkstra(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSimulationParameters(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationParameters getSimulationParameters() {
|
||||
return simulationParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
// retrieve simulation parameters
|
||||
Boundary boundary = new RectangularBoundary(simulationParameters.getCourse().get(0), simulationParameters
|
||||
.getCourse().get(1));// simulationParameters.getBoundaries();
|
||||
WindFieldGenerator windField = simulationParameters.getWindField();
|
||||
PolarDiagram polarDiagram = simulationParameters.getBoatPolarDiagram();
|
||||
Position start = simulationParameters.getCourse().get(0);
|
||||
Position end = simulationParameters.getCourse().get(1);
|
||||
TimePoint startTime = windField.getStartTime();// new MillisecondsTimePoint(0);
|
||||
|
||||
// the solution path
|
||||
LinkedList<TimedPositionWithSpeed> lst = new LinkedList<TimedPositionWithSpeed>();
|
||||
|
||||
// initiate grid
|
||||
int gridv = simulationParameters.getProperty("Djikstra.gridv[int]").intValue(); // number of vertical grid steps
|
||||
int gridh = simulationParameters.getProperty("Djikstra.gridh[int]").intValue(); // number of horizontal grid
|
||||
// steps
|
||||
Position[][] sailGrid = boundary.extractGrid(gridh, gridv);
|
||||
|
||||
// create adjacency graph including start and end
|
||||
Map<Position, List<Position>> graph = new HashMap<Position, List<Position>>();
|
||||
graph.put(start, Arrays.asList(sailGrid[1]));
|
||||
for (int i = 1; i < gridv - 2; i++) {
|
||||
for (Position p : sailGrid[i]) {
|
||||
graph.put(p, Arrays.asList(sailGrid[i + 1]));
|
||||
}
|
||||
}
|
||||
for (Position p : sailGrid[gridv - 2]) {
|
||||
graph.put(p, Arrays.asList(end));
|
||||
}
|
||||
|
||||
/*
|
||||
* //create backwards adjacency graph, required to reconstruct the optimal path Map<Position, List<Position>>
|
||||
* backGraph = new HashMap<Position, List<Position>>(); backGraph.put(end, Arrays.asList(sailGrid[gridv-2]));
|
||||
* for(int i = gridv-2; i > 1; i--) { for(Position p: sailGrid[i]) { backGraph.put(p,
|
||||
* Arrays.asList(sailGrid[i-1])); } } for(Position p : sailGrid[1]) { backGraph.put(p, Arrays.asList(start)); }
|
||||
*/
|
||||
|
||||
// create tentative distance matrix
|
||||
// additional to tentative distances, the matrix also contains the root of each position
|
||||
// that can be </null> if unavailable
|
||||
Map<Position, Pair<Long, Position>> tentativeDistances = new HashMap<Position, Pair<Long, Position>>();
|
||||
for (Position p : graph.keySet()) {
|
||||
tentativeDistances.put(p, new Pair<Long, Position>(Long.MAX_VALUE, null));
|
||||
}
|
||||
tentativeDistances.put(start, new Pair<Long, Position>(startTime.asMillis(), null));
|
||||
tentativeDistances.put(end, new Pair<Long, Position>(Long.MAX_VALUE, null));
|
||||
|
||||
// create set of unvisited nodes
|
||||
List<Position> unvisited = new ArrayList<Position>(graph.keySet());
|
||||
unvisited.add(end);
|
||||
|
||||
// set the initial node as current
|
||||
Position currentPosition = start;
|
||||
TimePoint currentTime = startTime;
|
||||
// Bearing previousBearing = null;
|
||||
|
||||
// search loop
|
||||
// ends when the end is visited
|
||||
while (currentPosition != end) {
|
||||
// set the polar diagram to the wind at the current position and time
|
||||
TimedPosition currentTimedPosition = new TimedPositionImpl(currentTime, currentPosition);
|
||||
SpeedWithBearing currentWind = windField.getWind(currentTimedPosition);
|
||||
polarDiagram.setWind(currentWind);
|
||||
|
||||
// compute the tentative distance to all the unvisited neighbours of the current node
|
||||
// and replace it in the matrix if is smaller than the previous one
|
||||
List<Position> unvisitedNeighbours = new LinkedList<Position>(graph.get(currentPosition));
|
||||
unvisitedNeighbours.retainAll(unvisited);
|
||||
for (Position p : unvisitedNeighbours) {
|
||||
Bearing bearingToP = currentPosition.getBearingGreatCircle(p);
|
||||
Distance distanceToP = currentPosition.getDistance(p);
|
||||
Speed speedToP = polarDiagram.getSpeedAtBearing(bearingToP);
|
||||
// multiplied by 1000 to have milliseconds
|
||||
Long timeToP = (long) (1000 * (distanceToP.getMeters() / speedToP.getMetersPerSecond()));
|
||||
/*
|
||||
* if (previousBearing != null) { Bearing windBearingFrom = currentWind.getBearing().reverse(); if(
|
||||
* (PolarDiagram49.bearingComparator.compare(bearingToP, windBearingFrom) > 0) &&
|
||||
* (PolarDiagram49.bearingComparator.compare(previousBearing, windBearingFrom) < 0) ) timeToP = timeToP
|
||||
* + 4000; if( (PolarDiagram49.bearingComparator.compare(bearingToP, windBearingFrom) < 0) &&
|
||||
* (PolarDiagram49.bearingComparator.compare(previousBearing, windBearingFrom) > 0) ) timeToP = timeToP
|
||||
* + 4000; }
|
||||
*/
|
||||
|
||||
Long tentativeDistanceToP = currentTime.asMillis() + timeToP;
|
||||
if (tentativeDistanceToP < tentativeDistances.get(p).getA()) {
|
||||
tentativeDistances.put(p, new Pair<Long, Position>(tentativeDistanceToP, currentPosition));
|
||||
}
|
||||
}
|
||||
|
||||
// mark current node as visited
|
||||
unvisited.remove(currentPosition);
|
||||
|
||||
// select the unvisited node with the smallest tentative distance
|
||||
// and set it as current
|
||||
Long minTentativeDistance = Long.MAX_VALUE;
|
||||
for (Position p : unvisited) {
|
||||
if (tentativeDistances.get(p).getA() < minTentativeDistance) {
|
||||
currentPosition = p;
|
||||
minTentativeDistance = tentativeDistances.get(p).getA();
|
||||
// previousBearing = tentativeDistances.get(p).getB().getBearingGreatCircle(currentPosition);
|
||||
currentTime = new MillisecondsTimePoint(minTentativeDistance);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// I need to add the end point to the distances matrix
|
||||
// tentativeDistances.put(end,currentTime.asMillis());
|
||||
|
||||
// at this point currentPosition = end
|
||||
// currentTime = total duration of the course
|
||||
|
||||
// reconstruct the optimal path by going from start to end
|
||||
/*
|
||||
* while(currentPosition != start) { TimedPositionWithSpeed currentTimedPositionWithSpeed = new
|
||||
* TimedPositionWithSpeedImpl(currentTime, currentPosition, null ); lst.addFirst(currentTimedPositionWithSpeed);
|
||||
* System.out.println(boundary.getGridIndex(currentTimedPositionWithSpeed.getPosition())); List<Position>
|
||||
* currentPredecessors = backGraph.get(currentPosition); Long minTime = Long.MAX_VALUE; for(Position p :
|
||||
* currentPredecessors) { if(tentativeDistances.get(p) < minTime) { minTime = tentativeDistances.get(p);
|
||||
* currentPosition = p; currentTime = new MillisecondsTimePoint(minTime); } } } //I need to add the first point
|
||||
* to the path lst.addFirst(new TimedPositionWithSpeedImpl(startTime, start, null));
|
||||
*/
|
||||
while (currentPosition != null) {
|
||||
currentTime = new MillisecondsTimePoint(tentativeDistances.get(currentPosition).getA());
|
||||
SpeedWithBearing windAtPoint = windField.getWind(new TimedPositionImpl(currentTime, currentPosition));
|
||||
TimedPositionWithSpeed current = new TimedPositionWithSpeedImpl(currentTime, currentPosition, windAtPoint);
|
||||
lst.addFirst(current);
|
||||
currentPosition = tentativeDistances.get(currentPosition).getB();
|
||||
}
|
||||
|
||||
return new PathImpl(lst, windField);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TimedPositionWithSpeed> getPathEvenTimed(long millisecondsStep) {
|
||||
|
||||
Path path = this.getPath();
|
||||
return path.getEvenTimedPoints(millisecondsStep);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+372
@@ -0,0 +1,372 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathGenerator;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
import com.sap.sailing.simulator.WindField;
|
||||
import com.sap.sailing.simulator.WindFieldGenerator;
|
||||
|
||||
public class PathGeneratorDynProgForward implements PathGenerator {
|
||||
|
||||
// private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
SimulationParameters simulationParameters;
|
||||
|
||||
public PathGeneratorDynProgForward(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSimulationParameters(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationParameters getSimulationParameters() {
|
||||
return simulationParameters;
|
||||
}
|
||||
|
||||
//
|
||||
// dynamic programming approach with forward iteration along start-end line
|
||||
//
|
||||
|
||||
// find minimum duration in alternate steps from h1=hidx to the calling h2
|
||||
private DPDuration findMinDur(ArrayList<DPDuration> alldur) {
|
||||
DPDuration mindur = alldur.get(0);
|
||||
for (int i = 0; i < alldur.size(); i++) {
|
||||
if (alldur.get(i).duration < mindur.duration) {
|
||||
mindur = alldur.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
return mindur;
|
||||
}
|
||||
|
||||
// calculate duration of step from position p1 to position p2 at time curtime from side of wind side1
|
||||
private DPDuration calcDuration(TimePoint curtime, int side1, Position p1, Position p2, WindField windField,
|
||||
PolarDiagram polarDiagram) {
|
||||
|
||||
// set turnloss to be approximately 4sec (until polardiagram has getTurnloss() method)
|
||||
long turnloss = polarDiagram.getTurnLoss(); // 4000;
|
||||
|
||||
// System.out.println("p1: "+p1+" p2:"+p2);
|
||||
|
||||
// take wind of starting position p1 at current time
|
||||
TimedPosition currentTimedPosition = new TimedPositionImpl(curtime, p1);
|
||||
SpeedWithBearing currentWind = windField.getWind(currentTimedPosition);
|
||||
// alternate approach: take wind of target position p2 at current time
|
||||
// TimedPosition windTimedPosition = new TimedPositionImpl(curtime, p2);
|
||||
// SpeedWithBearing currentWind = windField.getWind(windTimedPosition);
|
||||
|
||||
// System.out.println("wind: "+currentWind.getKnots()+", "+currentWind.getBearing().getDegrees()+"°");
|
||||
|
||||
// set polar diagram to current wind
|
||||
polarDiagram.setWind(currentWind);
|
||||
|
||||
// calculate bearing, distance and speed from p1 to p2
|
||||
Bearing bearingToP = p1.getBearingGreatCircle(p2);
|
||||
Distance distanceToP = p1.getDistance(p2);
|
||||
Speed speedToP = polarDiagram.getSpeedAtBearing(bearingToP);
|
||||
// System.out.println("p1 to p2: angle: "+bearingToP.getDegrees()+"° dist: "+distanceToP.getMeters()+"m speed: "+speedToP.getMetersPerSecond()+"m/s");
|
||||
|
||||
// add time delta for sailing from p1 to p2 to current time
|
||||
double deltat;
|
||||
if (speedToP.getMetersPerSecond() <= 0.1) {
|
||||
deltat = 86400; // set a high value for small times
|
||||
} else {
|
||||
deltat = (distanceToP.getMeters() / speedToP.getMetersPerSecond());
|
||||
}
|
||||
long timeToP = curtime.asMillis() + (long) (deltat) * 1000;
|
||||
// System.out.println("time: "+deltat/60.+"min");
|
||||
|
||||
// identify turn based on change of sign of relative bearing of p1 to p2 towards the wind
|
||||
Bearing relativeBearing = currentWind.getBearing().reverse().getDifferenceTo(bearingToP);
|
||||
int side2;
|
||||
if (relativeBearing.getDegrees() == 0) {
|
||||
side2 = 0;
|
||||
} else {
|
||||
side2 = (int) Math.signum(relativeBearing.getDegrees());
|
||||
}
|
||||
if ((side1 != 0) && (side2 != 0) && (side1 == -side2)) {
|
||||
timeToP = timeToP + turnloss;
|
||||
}
|
||||
|
||||
// return arrival time at p2 and wind side at p2 as durP instance
|
||||
DPDuration durToP = new DPDuration(timeToP, side2, 0, 0);
|
||||
|
||||
return durToP;
|
||||
}
|
||||
|
||||
// duration parameters: duration in millis, side of the wind, referencing horizontal grid column hidx,
|
||||
// and path index pidx (pidx currently unused, maybe used for structuring in groups of equivalent time, see
|
||||
// prototype R-script)
|
||||
class DPDuration {
|
||||
public DPDuration(long dur, int sid, int h, int p) {
|
||||
duration = dur;
|
||||
side = sid;
|
||||
hidx = h;
|
||||
pidx = p;
|
||||
}
|
||||
|
||||
long duration;
|
||||
int side;
|
||||
int hidx;
|
||||
int pidx;
|
||||
}
|
||||
|
||||
// location parameters: horizontal grid index idx, duration dur to reach this point (within path)
|
||||
class DPLocation {
|
||||
public DPLocation(int i, long d) {
|
||||
idx = i;
|
||||
dur = d;
|
||||
}
|
||||
|
||||
int idx;
|
||||
long dur;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
// retrieve simulation parameters
|
||||
Boundary boundary = new RectangularBoundary(simulationParameters.getCourse().get(0), simulationParameters
|
||||
.getCourse().get(1));// simulationParameters.getBoundaries();
|
||||
WindFieldGenerator windField = simulationParameters.getWindField();
|
||||
PolarDiagram polarDiagram = simulationParameters.getBoatPolarDiagram();
|
||||
// Position start = simulationParameters.getCourse().get(0);
|
||||
// Position end = simulationParameters.getCourse().get(1);
|
||||
TimePoint startTime = windField.getStartTime();
|
||||
|
||||
// the optimal path
|
||||
LinkedList<TimedPositionWithSpeed> optPath = new LinkedList<TimedPositionWithSpeed>();
|
||||
|
||||
// initiate grid: since performance is good, make it somewhat larger than what we do with dijkstra
|
||||
int spatialGridsizeVertical = 15; // 21; //(int) Math.round(1.5 *
|
||||
// simulationParameters.getProperty("Djikstra.gridv[int]").intValue()); // number
|
||||
// of
|
||||
// vertical
|
||||
// grid
|
||||
// steps
|
||||
// Formula: sgridh ~ xscale*sgridv/tan(beatangle*pi/180)
|
||||
int spatialGridsizeHorizontal = 121; // (25-1)*5; //(41-1)*5; //(int) Math.round(2 *
|
||||
// simulationParameters.getProperty("Djikstra.gridh[int]").intValue()); // number
|
||||
// of
|
||||
// horizontal
|
||||
// grid
|
||||
// steps
|
||||
|
||||
// make horizontal grid size uneven, to have an index for the middle line
|
||||
if (spatialGridsizeHorizontal % 2 == 0) {
|
||||
spatialGridsizeHorizontal++;
|
||||
}
|
||||
|
||||
// generate grid positions using sgridh and sgridv
|
||||
Position[][] sailGrid = boundary.extractGrid(spatialGridsizeHorizontal, spatialGridsizeVertical);
|
||||
|
||||
// optimization grid indexes:
|
||||
// vertical steps: 0, ..., v-1
|
||||
// horizontal steps: -gridh, ..., 0, ..., +gridh
|
||||
int optimizationGridsizeVertical = spatialGridsizeVertical;
|
||||
int optimizationGridsizeHorizontal = spatialGridsizeHorizontal / 2;
|
||||
|
||||
ArrayList<DPDuration> alldur;
|
||||
ArrayList<ArrayList<Vector<DPLocation>>> paths = new ArrayList<ArrayList<Vector<DPLocation>>>();
|
||||
ArrayList<DPDuration> duras = new ArrayList<DPDuration>();
|
||||
|
||||
// in each vertical step, paths having the same minimum duration are kept
|
||||
double mintol = 1.0; // threshold of closeness to realy minimum duration for keeping paths
|
||||
int maxeqpaths = 2; // maximum nmber of equal paths to keep [currently set to low values, to save Java heap
|
||||
// memory]
|
||||
|
||||
// loop over vertical steps
|
||||
for (int idxv = 0; idxv < (optimizationGridsizeVertical - 1); idxv++) {
|
||||
|
||||
// System.out.println(" vstep: "+idxv);
|
||||
|
||||
ArrayList<ArrayList<Vector<DPLocation>>> pathsnew = new ArrayList<ArrayList<Vector<DPLocation>>>();
|
||||
ArrayList<DPDuration> durasnew = new ArrayList<DPDuration>();
|
||||
|
||||
// get start boundary correct
|
||||
int range1;
|
||||
if (idxv == 0) {
|
||||
range1 = 0;
|
||||
} else {
|
||||
range1 = optimizationGridsizeHorizontal;
|
||||
}
|
||||
|
||||
// get end boundary correct
|
||||
int range2;
|
||||
if (idxv == (optimizationGridsizeVertical - 2)) {
|
||||
range2 = 0;
|
||||
} else {
|
||||
range2 = optimizationGridsizeHorizontal;
|
||||
}
|
||||
|
||||
// target loop: idxh2
|
||||
for (int idxh2 = -range2; idxh2 <= range2; idxh2++) {
|
||||
|
||||
alldur = new ArrayList<DPDuration>();
|
||||
|
||||
if (idxv > 0) { // if not at start of the grid
|
||||
|
||||
// origin loop: idxh1
|
||||
for (int idxh1 = -range1; idxh1 <= range1; idxh1++) {
|
||||
|
||||
// calculate the time to go from [idxv,idxh1] to [idxv+1,idxh2]
|
||||
DPDuration durationh1h2 = calcDuration(new MillisecondsTimePoint(
|
||||
duras.get(idxh1 + range1).duration), duras.get(idxh1 + range1).side,
|
||||
sailGrid[idxv][idxh1 + optimizationGridsizeHorizontal], sailGrid[idxv + 1][idxh2
|
||||
+ optimizationGridsizeHorizontal], windField, polarDiagram);
|
||||
|
||||
// *forbidden* angles
|
||||
if (durationh1h2.duration < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// remember durations of current vertical step in alldur
|
||||
durationh1h2.hidx = idxh1 + range1;
|
||||
alldur.add(durationh1h2);
|
||||
|
||||
} // horizontal origin loop: idxh1
|
||||
|
||||
if (idxv != (optimizationGridsizeVertical - 2)) { // if not at end of the grid
|
||||
|
||||
// find minimum duration in alldur
|
||||
DPDuration mindur = findMinDur(alldur);
|
||||
|
||||
// remember minimum duration for reaching [idxv,idxh2]
|
||||
DPDuration tdur = new DPDuration(mindur.duration, mindur.side, idxh2
|
||||
+ optimizationGridsizeHorizontal, 0);
|
||||
durasnew.add(tdur);
|
||||
|
||||
// keep all (see mintol, maxeqpaths) paths with minimum duration for reaching [idxv,idxh2]
|
||||
int k = 0;
|
||||
for (int j = 0; j < alldur.size(); j++) {
|
||||
|
||||
if ((alldur.get(j).duration <= mintol * mindur.duration) && (k < maxeqpaths)) {
|
||||
ArrayList<Vector<DPLocation>> npaths;
|
||||
if ((pathsnew.size() > 0)
|
||||
&& (pathsnew.size() == (idxh2 + optimizationGridsizeHorizontal + 1))) {
|
||||
npaths = pathsnew.get(idxh2 + optimizationGridsizeHorizontal);
|
||||
} else {
|
||||
npaths = new ArrayList<Vector<DPLocation>>();
|
||||
pathsnew.add(npaths);
|
||||
}
|
||||
ArrayList<Vector<DPLocation>> tpaths = paths.get(alldur.get(j).hidx);
|
||||
for (int i = 0; i < tpaths.size(); i++) {
|
||||
Vector<DPLocation> tpath;
|
||||
tpath = new Vector<DPLocation>(tpaths.get(i)); // (Vector<DPLocation>)
|
||||
// (tpaths.get(i)).clone();
|
||||
tpath.add(new DPLocation(idxh2, mindur.duration));
|
||||
npaths.add(tpath);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// find minimum in alldur
|
||||
DPDuration mindur = findMinDur(alldur);
|
||||
|
||||
// remember minimum duration for reaching [idxv,idxh2]
|
||||
DPDuration tdur = new DPDuration(mindur.duration, mindur.side, 0, 0);
|
||||
durasnew.add(tdur);
|
||||
|
||||
// keep all (see mintol, maxeqpaths) paths with minimum duration for reaching [idxv,idxh2]
|
||||
int k = 0;
|
||||
for (int j = 0; j < alldur.size(); j++) {
|
||||
|
||||
if ((alldur.get(j).duration <= mintol * mindur.duration) && (k < maxeqpaths)) {
|
||||
ArrayList<Vector<DPLocation>> npaths;
|
||||
if ((pathsnew.size() > 0) && (pathsnew.size() == (idxh2 + range2 + 1))) {
|
||||
npaths = pathsnew.get(idxh2 + range2);
|
||||
} else {
|
||||
npaths = new ArrayList<Vector<DPLocation>>();
|
||||
pathsnew.add(npaths);
|
||||
}
|
||||
ArrayList<Vector<DPLocation>> tpaths = paths.get(alldur.get(j).hidx);
|
||||
for (int i = 0; i < tpaths.size(); i++) {
|
||||
Vector<DPLocation> tpath;
|
||||
tpath = new Vector<DPLocation>(tpaths.get(i)); // (Vector<DPLocation>)
|
||||
// (tpaths.get(i)).clone();
|
||||
tpath.add(new DPLocation(0, mindur.duration));
|
||||
npaths.add(tpath);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} else { // start of grid
|
||||
|
||||
Vector<DPLocation> tpath = new Vector<DPLocation>();
|
||||
tpath.add(new DPLocation(0, startTime.asMillis()));
|
||||
ArrayList<Vector<DPLocation>> tpaths = new ArrayList<Vector<DPLocation>>();
|
||||
tpaths.add(tpath);
|
||||
pathsnew.add(tpaths);
|
||||
DPDuration tdur = calcDuration(startTime, 0, sailGrid[0][optimizationGridsizeHorizontal],
|
||||
sailGrid[1][idxh2 + optimizationGridsizeHorizontal], windField, polarDiagram);
|
||||
tdur.hidx = idxh2 + optimizationGridsizeHorizontal;
|
||||
durasnew.add(tdur);
|
||||
tpath.add(new DPLocation(idxh2, tdur.duration));
|
||||
}
|
||||
|
||||
} // horizontal target loop: idxh2
|
||||
|
||||
paths = pathsnew;
|
||||
duras = durasnew;
|
||||
|
||||
/*
|
||||
* if (idxv == (gridv-2)) { System.out.print(" optimal path:"); for(int i=0; i<1;i++) {//paths.size();
|
||||
* i++) { //System.out.print(""+duras.get(i).duration+" - "); for(int j=0; j<1;j++) {//paths.get(i).size();
|
||||
* j++) { int kmax = paths.get(i).get(j).size();
|
||||
* System.out.print(""+((paths.get(i).get(j).get(kmax-1).dur-paths
|
||||
* .get(i).get(j).get(0).dur)/1000./60.)+"min: "); for(int k=0;k<kmax; k++) {
|
||||
* System.out.print(" "+paths.get(i).get(j).get(k).idx); } System.out.println(); } } }
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
// generate timed position path
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
// for(int j=0; j<paths.get(i).size(); j++) {
|
||||
for (int j = 0; j < 1; j++) { // restrict to first path
|
||||
for (int k = 0; k < paths.get(i).get(j).size(); k++) {
|
||||
Position p = sailGrid[k][paths.get(i).get(j).get(k).idx + optimizationGridsizeHorizontal];
|
||||
TimePoint t = new MillisecondsTimePoint(paths.get(i).get(j).get(k).dur);
|
||||
// System.out.println("deltaT: "+(t.asMillis()-startTime.asMillis())/1000.);
|
||||
optPath.add(new TimedPositionWithSpeedImpl(t, p, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new PathImpl(optPath, windField);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TimedPositionWithSpeed> getPathEvenTimed(long millisecondsStep) {
|
||||
|
||||
Path path = this.getPath();
|
||||
return path.getEvenTimedPoints(millisecondsStep);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PathGenerator;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
import com.sap.sailing.simulator.WindFieldGenerator;
|
||||
|
||||
public class PathGeneratorOpportunistEuclidian implements PathGenerator {
|
||||
|
||||
private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
SimulationParameters simulationParameters;
|
||||
int maxLeft;
|
||||
int maxRight;
|
||||
boolean startLeft;
|
||||
|
||||
public PathGeneratorOpportunistEuclidian(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSimulationParameters(SimulationParameters params) {
|
||||
simulationParameters = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulationParameters getSimulationParameters() {
|
||||
return simulationParameters;
|
||||
}
|
||||
|
||||
public void setEvaluationParameters(int maxLeftVal, int maxRightVal, boolean startLeftVal) {
|
||||
this.maxLeft = maxLeftVal;
|
||||
this.maxRight = maxRightVal;
|
||||
this.startLeft = startLeftVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
WindFieldGenerator wf = simulationParameters.getWindField();
|
||||
PolarDiagram pd = simulationParameters.getBoatPolarDiagram();
|
||||
Position start = simulationParameters.getCourse().get(0);
|
||||
Position end = simulationParameters.getCourse().get(1);
|
||||
TimePoint startTime = wf.getStartTime();// new MillisecondsTimePoint(0);
|
||||
List<TimedPositionWithSpeed> lst = new ArrayList<TimedPositionWithSpeed>();
|
||||
|
||||
Position currentPosition = start;
|
||||
TimePoint currentTime = startTime;
|
||||
|
||||
int stepsLeft = 0;
|
||||
int stepsRight = 0;
|
||||
boolean allLeft = true;
|
||||
boolean allRight = true;
|
||||
|
||||
int prevDirection = -1;
|
||||
long turnloss = pd.getTurnLoss(); // 4000; // time lost when doing a turn
|
||||
long windpred = 1000; // time used to predict wind, i.e. hypothetical sailors prediction
|
||||
|
||||
TimePoint leftTime;
|
||||
TimePoint rightTime;
|
||||
|
||||
Wind wndStart = wf.getWind(new TimedPositionWithSpeedImpl(startTime, start, null));
|
||||
logger.fine("wndStart speed:" + wndStart.getKnots() + " angle:" + wndStart.getBearing().getDegrees());
|
||||
pd.setWind(wndStart);
|
||||
Bearing bearStart = currentPosition.getBearingGreatCircle(end);
|
||||
SpeedWithBearing spdStart = pd.getSpeedAtBearing(bearStart);
|
||||
lst.add(new TimedPositionWithSpeedImpl(startTime, start, spdStart));
|
||||
long timeStep = wf.getTimeStep().asMillis();
|
||||
logger.info("Time step :" + timeStep);
|
||||
// while there is more than 5% of the total distance to the finish
|
||||
|
||||
SpeedWithBearing slft = null;
|
||||
SpeedWithBearing srght = null;
|
||||
while (currentPosition.getDistance(end).compareTo(start.getDistance(end).scale(0.05)) > 0) {
|
||||
|
||||
// TimePoint nextTime = new MillisecondsTimePoint(currentTime.asMillis() + 30000);
|
||||
|
||||
long nextTimeVal = currentTime.asMillis() + timeStep;// + 30000;
|
||||
TimePoint nextTime = new MillisecondsTimePoint(nextTimeVal);
|
||||
|
||||
Wind cWind = wf.getWind(new TimedPositionWithSpeedImpl(currentTime, currentPosition, null));
|
||||
logger.fine("cWind speed:" + cWind.getKnots() + " angle:" + cWind.getBearing().getDegrees());
|
||||
// System.out.println("Start WindBear: " + (cWind.getBearing().getDegrees() - bearStart.getDegrees()));
|
||||
pd.setWind(cWind);
|
||||
|
||||
// get wind of direction
|
||||
Bearing wLft = pd.optimalDirectionsUpwind()[0];
|
||||
Bearing wRght = pd.optimalDirectionsUpwind()[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());
|
||||
|
||||
TimePoint wTime = new MillisecondsTimePoint(currentTime.asMillis() + windpred);
|
||||
// Position pWDirect = sWDirect.travelTo(currentPosition, currentTime, wTime);
|
||||
Position pWLft = sWLft.travelTo(currentPosition, currentTime, wTime);
|
||||
Position pWRght = sWRght.travelTo(currentPosition, currentTime, wTime);
|
||||
|
||||
logger.fine("current Pos:" + currentPosition.getLatDeg() + "," + currentPosition.getLngDeg());
|
||||
logger.fine("left Pos:" + pWLft.getLatDeg() + "," + pWLft.getLngDeg());
|
||||
logger.fine("right Pos:" + pWRght.getLatDeg() + "," + pWRght.getLngDeg());
|
||||
|
||||
// calculate next step
|
||||
// Wind dWind = wf.getWind(new TimedPositionWithSpeedImpl(currentTime, pWDirect, null));
|
||||
// logger.fine("dWind speed:" + dWind.getKnots() + " angle:" + dWind.getBearing().getDegrees());
|
||||
// pd.setWind(dWind);
|
||||
// Bearing direct = currentPosition.getBearingGreatCircle(end);
|
||||
// SpeedWithBearing sdirect = pd.getSpeedAtBearing(direct);
|
||||
|
||||
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);
|
||||
Bearing lft = pd.optimalDirectionsUpwind()[0];
|
||||
slft = pd.getSpeedAtBearing(lft);
|
||||
|
||||
Wind rWind = wf.getWind(new TimedPositionWithSpeedImpl(currentTime, pWRght, null));
|
||||
logger.fine("rWind speed:" + rWind.getKnots() + " angle:" + rWind.getBearing().getDegrees());
|
||||
// System.out.println("Right WindBear: " + (rWind.getBearing().getDegrees() - bearStart.getDegrees()));
|
||||
pd.setWind(rWind);
|
||||
Bearing rght = pd.optimalDirectionsUpwind()[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());
|
||||
|
||||
/*
|
||||
* if (prevDirection == 0) { directTime = new MillisecondsTimePoint(nextTimeVal); leftTime = new
|
||||
* MillisecondsTimePoint(nextTimeVal - turnloss); rightTime = new MillisecondsTimePoint(nextTimeVal -
|
||||
* turnloss); } else
|
||||
*/
|
||||
if (prevDirection == 1) {
|
||||
leftTime = new MillisecondsTimePoint(nextTimeVal);
|
||||
rightTime = new MillisecondsTimePoint(nextTimeVal - turnloss);
|
||||
} else if (prevDirection == 2) {
|
||||
leftTime = new MillisecondsTimePoint(nextTimeVal - turnloss);
|
||||
rightTime = new MillisecondsTimePoint(nextTimeVal);
|
||||
} else {
|
||||
leftTime = new MillisecondsTimePoint(nextTimeVal);
|
||||
rightTime = new MillisecondsTimePoint(nextTimeVal);
|
||||
}
|
||||
|
||||
// Position pdirect = sdirect.travelTo(currentPosition, currentTime, directTime);
|
||||
Position plft = slft.travelTo(currentPosition, currentTime, leftTime);
|
||||
Position prght = srght.travelTo(currentPosition, currentTime, rightTime);
|
||||
|
||||
// System.out.println("RelBearLeft : " + (slft.getBearing().getDegrees() - bearStart.getDegrees()));
|
||||
// System.out.println("RelBearRight: " + (srght.getBearing().getDegrees() - bearStart.getDegrees()));
|
||||
|
||||
// Distance ddirect = pdirect.getDistance(end);
|
||||
Distance dlft = plft.getDistance(end);
|
||||
Distance drght = prght.getDistance(end);
|
||||
|
||||
double lDistCM = Math.round(dlft.getMeters() * 1000.) / 1000.;
|
||||
double rDistCM = Math.round(drght.getMeters() * 1000.) / 1000.;
|
||||
|
||||
/*
|
||||
* if (ddirect.compareTo(dlft) <= 0 && ddirect.compareTo(drght) <= 0) { lst.add(new
|
||||
* TimedPositionWithSpeedImpl(nextTime, pdirect, sdirect)); currentPosition = pdirect; prevDirection = 0; }
|
||||
*/
|
||||
|
||||
if (prevDirection == -1) {
|
||||
|
||||
if (startLeft) {
|
||||
lst.add(new TimedPositionWithSpeedImpl(nextTime, plft, slft));
|
||||
currentPosition = plft;
|
||||
if (prevDirection == 2) {
|
||||
allLeft = false;
|
||||
} else {
|
||||
stepsLeft++;
|
||||
}
|
||||
prevDirection = 1;
|
||||
} else {
|
||||
lst.add(new TimedPositionWithSpeedImpl(nextTime, prght, srght));
|
||||
currentPosition = prght;
|
||||
if (prevDirection == 1) {
|
||||
allRight = false;
|
||||
} else {
|
||||
stepsRight++;
|
||||
}
|
||||
prevDirection = 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
// System.out.println("Distance Left - Right: "+lDistCM+" - "+ rDistCM);
|
||||
if (((lDistCM <= rDistCM) && (!allLeft || (stepsLeft < maxLeft)))
|
||||
|| (allRight && (stepsRight >= maxRight))) {
|
||||
lst.add(new TimedPositionWithSpeedImpl(nextTime, plft, slft));
|
||||
currentPosition = plft;
|
||||
if (prevDirection == 2) {
|
||||
allLeft = false;
|
||||
} else {
|
||||
stepsLeft++;
|
||||
}
|
||||
prevDirection = 1;
|
||||
} else {
|
||||
// if (((drght.compareTo(dlft) < 0)&&(stepsRight < maxRight))||(stepsLeft >= maxLeft)) {
|
||||
lst.add(new TimedPositionWithSpeedImpl(nextTime, prght, srght));
|
||||
currentPosition = prght;
|
||||
if (prevDirection == 1) {
|
||||
allRight = false;
|
||||
} else {
|
||||
stepsRight++;
|
||||
}
|
||||
prevDirection = 2;
|
||||
}
|
||||
}
|
||||
|
||||
currentTime = nextTime;
|
||||
|
||||
}
|
||||
|
||||
// approach end
|
||||
double bearingToEnd;
|
||||
SpeedWithBearing bearingBoat;
|
||||
if (prevDirection == 1) {
|
||||
bearingToEnd = currentPosition.getBearingGreatCircle(end).getDegrees()
|
||||
- pd.optimalDirectionsUpwind()[1].getDegrees();
|
||||
bearingBoat = slft;
|
||||
} else {
|
||||
bearingToEnd = pd.optimalDirectionsUpwind()[0].getDegrees()
|
||||
- currentPosition.getBearingGreatCircle(end).getDegrees();
|
||||
bearingBoat = srght;
|
||||
}
|
||||
bearingToEnd = (bearingToEnd + 360 + 180) % 360 - 180;
|
||||
// System.out.println("b2End:" + bearingToEnd);
|
||||
double bearingToEndSign = Math.signum(bearingToEnd);
|
||||
Position tackPosition = currentPosition;
|
||||
Position tackPositionNew = currentPosition;
|
||||
TimePoint tackTime = currentTime;
|
||||
TimePoint tackTimeNext = currentTime;
|
||||
long searchTime = 500;
|
||||
while (Math.signum(bearingToEnd) == bearingToEndSign) {
|
||||
tackTime = tackTimeNext;
|
||||
tackPosition = tackPositionNew;
|
||||
if (bearingToEnd < 0) {
|
||||
tackTimeNext = new MillisecondsTimePoint(tackTime.asMillis() + searchTime);
|
||||
tackPositionNew = bearingBoat.travelTo(tackPosition, tackTime, tackTimeNext);
|
||||
} else {
|
||||
tackTimeNext = new MillisecondsTimePoint(tackTime.asMillis() - searchTime);
|
||||
tackPositionNew = bearingBoat.travelTo(tackPosition, tackTime, tackTimeNext);
|
||||
}
|
||||
if (prevDirection == 1) {
|
||||
bearingToEnd = tackPositionNew.getBearingGreatCircle(end).getDegrees()
|
||||
- pd.optimalDirectionsUpwind()[1].getDegrees();
|
||||
// System.out.println("bEnd :" + tackPosition.getBearingGreatCircle(end).getDegrees());
|
||||
// System.out.println("bBoat:" + pd.optimalDirectionsUpwind()[1].getDegrees());
|
||||
} else {
|
||||
bearingToEnd = pd.optimalDirectionsUpwind()[0].getDegrees()
|
||||
- tackPositionNew.getBearingGreatCircle(end).getDegrees();
|
||||
// System.out.println("bEnd :" + tackPosition.getBearingGreatCircle(end).getDegrees());
|
||||
// System.out.println("bBoat:" + pd.optimalDirectionsUpwind()[0].getDegrees());
|
||||
}
|
||||
bearingToEnd = (bearingToEnd + 360 + 180) % 360 - 180;
|
||||
// System.out.println("b2End:" + bearingToEnd);
|
||||
}
|
||||
|
||||
// scan more detailed between tackPosition and tackPositionNew
|
||||
boolean endIteration = false;
|
||||
while ((Math.abs(bearingToEnd) > 0.1) && (!endIteration)) {
|
||||
TimePoint tackTimeMid = new MillisecondsTimePoint((tackTime.asMillis() + tackTimeNext.asMillis()) / 2);
|
||||
if (tackTimeMid.asMillis() == tackTime.asMillis()) {
|
||||
endIteration = true;
|
||||
}
|
||||
Position tackPositionMid = bearingBoat.travelTo(tackPosition, tackTime, tackTimeMid);
|
||||
if (prevDirection == 1) {
|
||||
bearingToEnd = tackPositionMid.getBearingGreatCircle(end).getDegrees()
|
||||
- pd.optimalDirectionsUpwind()[1].getDegrees();
|
||||
// System.out.println("bEnd :" + tackPositionMid.getBearingGreatCircle(end).getDegrees());
|
||||
// System.out.println("bBoat:" + pd.optimalDirectionsUpwind()[1].getDegrees());
|
||||
} else {
|
||||
bearingToEnd = pd.optimalDirectionsUpwind()[0].getDegrees()
|
||||
- tackPositionMid.getBearingGreatCircle(end).getDegrees();
|
||||
// System.out.println("bEnd :" + tackPositionMid.getBearingGreatCircle(end).getDegrees());
|
||||
// System.out.println("bBoat:" + pd.optimalDirectionsUpwind()[0].getDegrees());
|
||||
}
|
||||
bearingToEnd = (bearingToEnd + 360 + 180) % 360 - 180;
|
||||
// System.out.println("fine b2End:" + bearingToEnd);
|
||||
if (Math.signum(bearingToEnd) == bearingToEndSign) {
|
||||
tackPosition = tackPositionMid;
|
||||
tackTime = tackTimeMid;
|
||||
} else {
|
||||
tackPositionNew = tackPositionMid;
|
||||
tackTimeNext = tackTimeMid;
|
||||
}
|
||||
}
|
||||
|
||||
TimePoint tackTimeOpt = new MillisecondsTimePoint((tackTime.asMillis() + tackTimeNext.asMillis()) / 2);
|
||||
Position tackPositionOpt = bearingBoat.travelTo(tackPosition, tackTime, tackTimeOpt);
|
||||
|
||||
// System.out.println("tack time:"+tackPosition.)
|
||||
lst.remove(lst.size() - 1);
|
||||
lst.add(new TimedPositionWithSpeedImpl(tackTimeOpt, tackPositionOpt, null));
|
||||
|
||||
currentPosition = tackPosition;
|
||||
currentTime = tackTime;
|
||||
|
||||
Wind wndEnd = wf.getWind(new TimedPositionWithSpeedImpl(currentTime, currentPosition, null));
|
||||
// System.out.println("wndEnd speed:" + wndEnd.getKnots() + " angle:" + wndEnd.getBearing().getDegrees());
|
||||
pd.setWind(wndEnd);
|
||||
Bearing bearEnd = currentPosition.getBearingGreatCircle(end);
|
||||
// System.out.println("bearEnd angle:" + bearEnd.getDegrees());
|
||||
SpeedWithBearing spdEnd = pd.getSpeedAtBearing(bearEnd);
|
||||
|
||||
long nextTimeVal = currentTime.asMillis()
|
||||
+ Math.round(currentPosition.getDistance(end).getMeters() / spdEnd.getMetersPerSecond()) * 1000;// 30000;
|
||||
// System.out.println("time:" + currentTime.asMillis() + " " + currentPosition.getDistance(end).getMeters()
|
||||
// + " speed:" + spdEnd.getMetersPerSecond());
|
||||
// System.out.println("next:" + nextTimeVal);
|
||||
TimePoint nextTime = new MillisecondsTimePoint(nextTimeVal + turnloss);
|
||||
|
||||
lst.add(new TimedPositionWithSpeedImpl(nextTime, end, null));
|
||||
|
||||
return new PathImpl(lst, wf);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TimedPositionWithSpeed> getPathEvenTimed(long millisecondsStep) {
|
||||
|
||||
Path path = this.getPath();
|
||||
return path.getEvenTimedPoints(millisecondsStep);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-559
@@ -1,559 +0,0 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.RadianBearingImpl;
|
||||
|
||||
public class PolarDiagram49 implements PolarDiagram {
|
||||
|
||||
// the current speed and direction of the wind
|
||||
private SpeedWithBearing wind = new KnotSpeedWithBearingImpl(6,
|
||||
new DegreeBearingImpl(180));
|
||||
|
||||
// the preferred direction of movement
|
||||
// is used by optimalDirectionsUpwind() and optimialDirectionsDownwind()
|
||||
private Bearing targetDirection = new DegreeBearingImpl(0);
|
||||
|
||||
protected NavigableMap<Speed, NavigableMap<Bearing, Speed>> speedTable;
|
||||
protected NavigableMap<Speed, Bearing> beatAngles;
|
||||
protected NavigableMap<Speed, Bearing> gybeAngles;
|
||||
protected NavigableMap<Speed, Speed> beatSOG;
|
||||
protected NavigableMap<Speed, Speed> gybeSOG;
|
||||
|
||||
// this constructor creates an instance with a hard-coded set of values
|
||||
public PolarDiagram49() {
|
||||
speedTable = new TreeMap<Speed, NavigableMap<Bearing, Speed>>();
|
||||
NavigableMap<Bearing, Speed> tableRow;
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagram49.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(52), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(60), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(75), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(90), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(110), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(120), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(135), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(150), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(180), Speed.NULL);
|
||||
speedTable.put(Speed.NULL, tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagram49.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(52), new KnotSpeedImpl(6.57));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(7.01));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(7.36));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(7.31));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(6.73));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(6.39));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(5.58));
|
||||
tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(4.62));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(2.5));
|
||||
speedTable.put(new KnotSpeedImpl(6), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagram49.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(52), new KnotSpeedImpl(7.78));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(8.13));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(8.38));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(8.31));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(8.04));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(7.79));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(7));
|
||||
tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(5.85));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(3));
|
||||
speedTable.put(new KnotSpeedImpl(8), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagram49.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(52), new KnotSpeedImpl(8.34));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(8.66));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(9.01));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(8.95));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(8.87));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(8.64));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(8.02));
|
||||
tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(6.97));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(4));
|
||||
speedTable.put(new KnotSpeedImpl(10), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagram49.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(52), new KnotSpeedImpl(8.64));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(8.95));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(9.39));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(9.5));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(9.54));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(9.3));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(8.71));
|
||||
tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(7.86));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(5));
|
||||
speedTable.put(new KnotSpeedImpl(12), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagram49.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(52), new KnotSpeedImpl(8.84));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(9.15));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(9.62));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(9.98));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(10.08));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(9.95));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(9.29));
|
||||
tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(8.57));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(6));
|
||||
speedTable.put(new KnotSpeedImpl(14), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagram49.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(52), new KnotSpeedImpl(8.95));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(9.28));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(9.8));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(10.28));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(10.44));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(10.72));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(9.88));
|
||||
tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(9.13));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(7));
|
||||
speedTable.put(new KnotSpeedImpl(16), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagram49.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(52), new KnotSpeedImpl(8.91));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(9.34));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(10.01));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(10.67));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(11.17));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(11.81));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(11.47));
|
||||
tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(10.26));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(7.5));
|
||||
speedTable.put(new KnotSpeedImpl(20), tableRow);
|
||||
|
||||
beatAngles = new TreeMap<Speed, Bearing>();
|
||||
beatAngles.put(new KnotSpeedImpl(0), new DegreeBearingImpl(45));
|
||||
beatAngles.put(new KnotSpeedImpl(6), new DegreeBearingImpl(43.4));
|
||||
beatAngles.put(new KnotSpeedImpl(8), new DegreeBearingImpl(41.8));
|
||||
beatAngles.put(new KnotSpeedImpl(10), new DegreeBearingImpl(38.9));
|
||||
beatAngles.put(new KnotSpeedImpl(12), new DegreeBearingImpl(37.5));
|
||||
beatAngles.put(new KnotSpeedImpl(14), new DegreeBearingImpl(36.8));
|
||||
beatAngles.put(new KnotSpeedImpl(16), new DegreeBearingImpl(36.3));
|
||||
beatAngles.put(new KnotSpeedImpl(20), new DegreeBearingImpl(36.9));
|
||||
|
||||
double beatScale = 1.1;
|
||||
beatSOG = new TreeMap<Speed, Speed>();
|
||||
beatSOG.put(new KnotSpeedImpl(0), new KnotSpeedImpl(0));
|
||||
beatSOG.put(new KnotSpeedImpl(6), new KnotSpeedImpl(5.85 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(8), new KnotSpeedImpl(6.98 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(10), new KnotSpeedImpl(7.39 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(12), new KnotSpeedImpl(7.68 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(14), new KnotSpeedImpl(7.89 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(16), new KnotSpeedImpl(7.92 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(20), new KnotSpeedImpl(7.94 * beatScale));
|
||||
|
||||
gybeAngles = new TreeMap<Speed, Bearing>();
|
||||
gybeAngles.put(new KnotSpeedImpl(0), new DegreeBearingImpl(120));
|
||||
gybeAngles.put(new KnotSpeedImpl(6), new DegreeBearingImpl(140));
|
||||
gybeAngles.put(new KnotSpeedImpl(8), new DegreeBearingImpl(142.6));
|
||||
gybeAngles.put(new KnotSpeedImpl(10), new DegreeBearingImpl(148.4));
|
||||
gybeAngles.put(new KnotSpeedImpl(12), new DegreeBearingImpl(154.4));
|
||||
gybeAngles.put(new KnotSpeedImpl(14), new DegreeBearingImpl(162.5));
|
||||
gybeAngles.put(new KnotSpeedImpl(16), new DegreeBearingImpl(169.6));
|
||||
gybeAngles.put(new KnotSpeedImpl(20), new DegreeBearingImpl(172.3));
|
||||
|
||||
gybeSOG = new TreeMap<Speed, Speed>();
|
||||
gybeSOG.put(new KnotSpeedImpl(0), new KnotSpeedImpl(0));
|
||||
gybeSOG.put(new KnotSpeedImpl(6), new KnotSpeedImpl(5.22));
|
||||
gybeSOG.put(new KnotSpeedImpl(8), new KnotSpeedImpl(6.38));
|
||||
gybeSOG.put(new KnotSpeedImpl(10), new KnotSpeedImpl(7.09));
|
||||
gybeSOG.put(new KnotSpeedImpl(12), new KnotSpeedImpl(7.6));
|
||||
gybeSOG.put(new KnotSpeedImpl(14), new KnotSpeedImpl(7.97));
|
||||
gybeSOG.put(new KnotSpeedImpl(16), new KnotSpeedImpl(8.39));
|
||||
gybeSOG.put(new KnotSpeedImpl(20), new KnotSpeedImpl(9.38));
|
||||
|
||||
for (Speed s : speedTable.keySet()) {
|
||||
|
||||
if (beatAngles.containsKey(s)
|
||||
&& !speedTable.get(s).containsKey(beatAngles.get(s)))
|
||||
speedTable.get(s).put(beatAngles.get(s), beatSOG.get(s));
|
||||
|
||||
if (gybeAngles.containsKey(s)
|
||||
&& !speedTable.get(s).containsKey(gybeAngles.get(s)))
|
||||
speedTable.get(s).put(gybeAngles.get(s), gybeSOG.get(s));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// a constructor that allows a generic set of parameters
|
||||
public PolarDiagram49(
|
||||
NavigableMap<Speed, NavigableMap<Bearing, Speed>> speeds,
|
||||
NavigableMap<Speed, Bearing> beats,
|
||||
NavigableMap<Speed, Bearing> gybes,
|
||||
NavigableMap<Speed, Speed> beatSOGs,
|
||||
NavigableMap<Speed, Speed> gybeSOGs) {
|
||||
|
||||
wind = new KnotSpeedWithBearingImpl(0, new DegreeBearingImpl(180));
|
||||
|
||||
speedTable = speeds;
|
||||
beatAngles = beats;
|
||||
gybeAngles = gybes;
|
||||
beatSOG = beatSOGs;
|
||||
gybeSOG = gybeSOGs;
|
||||
|
||||
for (Speed s : speedTable.keySet()) {
|
||||
|
||||
if (beatAngles.containsKey(s)
|
||||
&& !speedTable.get(s).containsKey(beatAngles.get(s)))
|
||||
speedTable.get(s).put(beatAngles.get(s), beatSOG.get(s));
|
||||
|
||||
if (gybeAngles.containsKey(s)
|
||||
&& !speedTable.get(s).containsKey(gybeAngles.get(s)))
|
||||
speedTable.get(s).put(gybeAngles.get(s), gybeSOG.get(s));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getWind() {
|
||||
return wind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWind(SpeedWithBearing newWind) {
|
||||
wind = newWind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedAtBearing(Bearing bearing) {
|
||||
|
||||
Bearing relativeBearing = wind.getBearing().reverse()
|
||||
.getDifferenceTo(bearing);
|
||||
if (relativeBearing.getDegrees() < 0)
|
||||
relativeBearing = relativeBearing
|
||||
.getDifferenceTo(new DegreeBearingImpl(0));
|
||||
|
||||
Speed floorWind = speedTable.floorKey(wind);
|
||||
Speed ceilingWind = speedTable.ceilingKey(wind);
|
||||
|
||||
if (ceilingWind == null) {
|
||||
ceilingWind = floorWind;
|
||||
}
|
||||
if (floorWind == null) {
|
||||
floorWind = ceilingWind;
|
||||
}
|
||||
|
||||
NavigableMap<Bearing, Speed> floorSpeeds = speedTable.get(floorWind);
|
||||
NavigableMap<Bearing, Speed> ceilingSpeeds = speedTable
|
||||
.get(ceilingWind);
|
||||
|
||||
// Taylor estimations of order 1
|
||||
Speed floorSpeed1 = floorSpeeds.floorEntry(relativeBearing).getValue();
|
||||
Speed floorSpeed2 = floorSpeeds.ceilingEntry(relativeBearing)
|
||||
.getValue();
|
||||
Bearing floorBearing1 = floorSpeeds.floorKey(relativeBearing);
|
||||
Bearing floorBearing2 = floorSpeeds.ceilingKey(relativeBearing);
|
||||
double floorSpeed;
|
||||
if (floorSpeed1.equals(floorSpeed2)) {
|
||||
floorSpeed = floorSpeed1.getKnots();
|
||||
} else {
|
||||
floorSpeed = floorSpeed1.getKnots()
|
||||
+ (relativeBearing.getRadians() - floorBearing1
|
||||
.getRadians())
|
||||
* (floorSpeed2.getKnots() - floorSpeed1.getKnots())
|
||||
/ (floorBearing2.getRadians() - floorBearing1.getRadians());
|
||||
}
|
||||
|
||||
Speed ceilingSpeed1 = ceilingSpeeds.floorEntry(relativeBearing)
|
||||
.getValue();
|
||||
Speed ceilingSpeed2 = ceilingSpeeds.ceilingEntry(relativeBearing)
|
||||
.getValue();
|
||||
Bearing ceilingBearing1 = ceilingSpeeds.floorKey(relativeBearing);
|
||||
Bearing ceilingBearing2 = ceilingSpeeds.ceilingKey(relativeBearing);
|
||||
double ceilingSpeed;
|
||||
if (ceilingSpeed1.equals(ceilingSpeed2)) {
|
||||
ceilingSpeed = ceilingSpeed1.getKnots();
|
||||
} else {
|
||||
ceilingSpeed = ceilingSpeed1.getKnots()
|
||||
+ (relativeBearing.getRadians() - ceilingBearing1
|
||||
.getRadians())
|
||||
* (ceilingSpeed2.getKnots() - ceilingSpeed1.getKnots())
|
||||
/ (ceilingBearing2.getRadians() - ceilingBearing1
|
||||
.getRadians());
|
||||
}
|
||||
|
||||
double speed;
|
||||
if (floorWind.equals(ceilingWind)) {
|
||||
speed = floorSpeed;
|
||||
} else {
|
||||
speed = floorSpeed + (wind.getKnots() - floorWind.getKnots())
|
||||
* (ceilingSpeed - floorSpeed)
|
||||
/ (ceilingWind.getKnots() - floorWind.getKnots());
|
||||
}
|
||||
if ((Math.abs(relativeBearing.getDegrees()) < 20)
|
||||
|| (Math.abs(relativeBearing.getDegrees()) > 330)) {
|
||||
speed = 0.1;
|
||||
}
|
||||
|
||||
return new KnotSpeedWithBearingImpl(speed, bearing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing[] optimalDirectionsUpwind() {
|
||||
Bearing windBearing = wind.getBearing().reverse();
|
||||
Bearing estBeatAngleRight = null;
|
||||
Bearing estBeatAngleLeft = null;
|
||||
if (targetDirection.equals(new DegreeBearingImpl(0))) {
|
||||
Bearing floorBeatAngle;
|
||||
if (beatAngles.floorEntry(wind) == null) {
|
||||
floorBeatAngle = beatAngles.ceilingEntry(wind).getValue();
|
||||
} else {
|
||||
floorBeatAngle = beatAngles.floorEntry(wind).getValue();
|
||||
}
|
||||
Bearing ceilingBeatAngle;
|
||||
if (beatAngles.ceilingEntry(wind) == null) {
|
||||
ceilingBeatAngle = beatAngles.floorEntry(wind).getValue();
|
||||
} else {
|
||||
ceilingBeatAngle = beatAngles.ceilingEntry(wind).getValue();
|
||||
}
|
||||
if (floorBeatAngle == null)
|
||||
floorBeatAngle = new DegreeBearingImpl(0);
|
||||
if (ceilingBeatAngle == null)
|
||||
ceilingBeatAngle = new DegreeBearingImpl(0);
|
||||
|
||||
Speed floorSpeed = beatAngles.floorKey(wind);
|
||||
if (floorSpeed == null) {
|
||||
floorSpeed = beatAngles.ceilingKey(wind);
|
||||
}
|
||||
Speed ceilingSpeed = beatAngles.ceilingKey(wind);
|
||||
if (beatAngles.ceilingKey(wind) == null) {
|
||||
ceilingSpeed = beatAngles.floorKey(wind);
|
||||
}
|
||||
double beatAngle;
|
||||
if (floorSpeed.equals(ceilingSpeed)) {
|
||||
beatAngle = floorBeatAngle.getRadians();
|
||||
} else {
|
||||
beatAngle = floorBeatAngle.getRadians()
|
||||
+ (wind.getKnots() - floorSpeed.getKnots())
|
||||
* (ceilingBeatAngle.getRadians() - floorBeatAngle
|
||||
.getRadians())
|
||||
/ (ceilingSpeed.getKnots() - floorSpeed.getKnots());
|
||||
}
|
||||
estBeatAngleRight = new RadianBearingImpl(+beatAngle);
|
||||
estBeatAngleLeft = new RadianBearingImpl(-beatAngle);
|
||||
return new Bearing[] {
|
||||
// windBearing.add(estBeatAngle),
|
||||
// windBearing.add(estBeatAngle.getDifferenceTo(windBearing))
|
||||
windBearing.add(estBeatAngleLeft),
|
||||
windBearing.add(estBeatAngleRight) };
|
||||
} else {
|
||||
Set<Bearing> allKeys = new TreeSet<Bearing>(bearingComparator);
|
||||
for (Double b = 0.0; b < 360.0; b += 5.0)
|
||||
allKeys.add(new DegreeBearingImpl(b));
|
||||
Bearing _targetDirection = targetDirection;
|
||||
setTargetDirection(new DegreeBearingImpl(0.0));
|
||||
allKeys.addAll(Arrays.asList(optimalDirectionsUpwind()));
|
||||
allKeys.addAll(Arrays.asList(optimalDirectionsDownwind()));
|
||||
setTargetDirection(_targetDirection);
|
||||
Double maxSpeedRight = 0.0;
|
||||
Double maxSpeedLeft = 0.0;
|
||||
for (Bearing b : allKeys) {
|
||||
if (b.getDifferenceTo(getWind().getBearing()).getDegrees() > 0) {
|
||||
if (getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection())
|
||||
.getRadians()) > maxSpeedRight) {
|
||||
maxSpeedRight = getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(
|
||||
getTargetDirection()).getRadians());
|
||||
estBeatAngleRight = b;
|
||||
}
|
||||
} else if (getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection())
|
||||
.getRadians()) > maxSpeedLeft) {
|
||||
maxSpeedLeft = getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection())
|
||||
.getRadians());
|
||||
estBeatAngleLeft = b;
|
||||
}
|
||||
}
|
||||
return new Bearing[] {
|
||||
// windBearing.add(estBeatAngle),
|
||||
// windBearing.add(estBeatAngle.getDifferenceTo(windBearing))
|
||||
estBeatAngleLeft, estBeatAngleRight };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing[] optimalDirectionsDownwind() {
|
||||
|
||||
Bearing windBearing = wind.getBearing().reverse();
|
||||
Bearing estGybeAngleRight = null;
|
||||
Bearing estGybeAngleLeft = null;
|
||||
if (getTargetDirection().equals(new DegreeBearingImpl(0))) {
|
||||
windBearing = wind.getBearing().reverse();
|
||||
estGybeAngleRight = null;
|
||||
estGybeAngleLeft = null;
|
||||
Bearing floorGybeAngle = gybeAngles.floorEntry(wind).getValue();
|
||||
Bearing ceilingGybeAngle = gybeAngles.ceilingEntry(wind).getValue();
|
||||
if (floorGybeAngle == null)
|
||||
floorGybeAngle = new DegreeBearingImpl(0);
|
||||
if (ceilingGybeAngle == null)
|
||||
ceilingGybeAngle = new DegreeBearingImpl(0);
|
||||
Speed floorSpeed = gybeAngles.floorKey(wind);
|
||||
Speed ceilingSpeed = gybeAngles.ceilingKey(wind);
|
||||
double gybeAngle;
|
||||
if (floorSpeed.equals(ceilingSpeed)) {
|
||||
gybeAngle = floorGybeAngle.getRadians();
|
||||
} else {
|
||||
gybeAngle = floorGybeAngle.getRadians()
|
||||
+ (wind.getKnots() - floorSpeed.getKnots())
|
||||
* (ceilingGybeAngle.getRadians() - floorGybeAngle
|
||||
.getRadians())
|
||||
/ (ceilingSpeed.getKnots() - floorSpeed.getKnots());
|
||||
}
|
||||
// Bearing estGybeAngle = new RadianBearingImpl(gybeAngle);
|
||||
estGybeAngleRight = new RadianBearingImpl(+gybeAngle);
|
||||
estGybeAngleLeft = new RadianBearingImpl(-gybeAngle);
|
||||
return new Bearing[] { windBearing.add(estGybeAngleRight),
|
||||
windBearing.add(estGybeAngleLeft) };
|
||||
} else {
|
||||
|
||||
Set<Bearing> allKeys = new TreeSet<Bearing>(bearingComparator);
|
||||
for (Double b = 0.0; b < 360.0; b += 5.0)
|
||||
allKeys.add(new DegreeBearingImpl(b));
|
||||
Bearing _targetDirection = targetDirection;
|
||||
setTargetDirection(new DegreeBearingImpl(0.0));
|
||||
allKeys.addAll(Arrays.asList(optimalDirectionsUpwind()));
|
||||
allKeys.addAll(Arrays.asList(optimalDirectionsDownwind()));
|
||||
setTargetDirection(_targetDirection);
|
||||
Double maxSpeedRight = 0.0;
|
||||
Double maxSpeedLeft = 0.0;
|
||||
for (Bearing b : allKeys) {
|
||||
if (b.getDifferenceTo(getWind().getBearing()).getDegrees() > 0) {
|
||||
if (getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(
|
||||
getTargetDirection().reverse())
|
||||
.getRadians()) > maxSpeedRight) {
|
||||
maxSpeedRight = getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(
|
||||
getTargetDirection().reverse())
|
||||
.getRadians());
|
||||
estGybeAngleRight = b;
|
||||
}
|
||||
} else if (getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(
|
||||
getTargetDirection().reverse()).getRadians()) > maxSpeedLeft) {
|
||||
maxSpeedLeft = getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(
|
||||
getTargetDirection().reverse())
|
||||
.getRadians());
|
||||
estGybeAngleLeft = b;
|
||||
}
|
||||
}
|
||||
return new Bearing[] {
|
||||
// windBearing.add(estBeatAngle),
|
||||
// windBearing.add(estBeatAngle.getDifferenceTo(windBearing))
|
||||
estGybeAngleLeft, estGybeAngleRight };
|
||||
}
|
||||
}
|
||||
|
||||
// a Bearing Comparator useful in the creation of sorted sets of Bearing
|
||||
public static Comparator<Bearing> bearingComparator = new Comparator<Bearing>() {
|
||||
|
||||
@Override
|
||||
public int compare(Bearing o1, Bearing o2) {
|
||||
Double d1 = o1.getDegrees();
|
||||
if (d1 < 0)
|
||||
d1 = 360 + d1;
|
||||
Double d2 = o2.getDegrees();
|
||||
if (d2 < 0)
|
||||
d2 = 360 + d2;
|
||||
return d1.compareTo(d2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@Override
|
||||
public long getTurnLoss() {
|
||||
// TODO Auto-generated method stub
|
||||
return 4000;
|
||||
}
|
||||
|
||||
// TO BE REVIEWED
|
||||
// not sure I use the right terms and conventions
|
||||
@Override
|
||||
public WindSide getWindSide(Bearing bearing) {
|
||||
WindSide windSide = null;
|
||||
if (bearingComparator.compare(bearing, wind.getBearing().reverse()) > 0)
|
||||
windSide = WindSide.LEFT;
|
||||
if (bearingComparator.compare(bearing, wind.getBearing().reverse()) < 0)
|
||||
windSide = WindSide.RIGHT;
|
||||
if (bearing.equals(wind.getBearing()))
|
||||
windSide = WindSide.OPPOSING;
|
||||
if (bearing.equals(wind.getBearing().reverse()))
|
||||
windSide = WindSide.FACING;
|
||||
|
||||
return windSide;
|
||||
}
|
||||
|
||||
// returns a table of Bearing-Speed pairs with a bearingStep granularity
|
||||
// for all Speeds in speedTable
|
||||
@Override
|
||||
public NavigableMap<Speed, NavigableMap<Bearing, Speed>> polarDiagramPlot(
|
||||
Double bearingStep) {
|
||||
|
||||
NavigableMap<Speed, NavigableMap<Bearing, Speed>> table = new TreeMap<Speed, NavigableMap<Bearing, Speed>>();
|
||||
Set<Bearing> extraBearings = new HashSet<Bearing>();
|
||||
|
||||
for (Speed s : speedTable.keySet()) {
|
||||
setWind(new KnotSpeedWithBearingImpl(s.getKnots(),
|
||||
new DegreeBearingImpl(135)));
|
||||
extraBearings.addAll(Arrays.asList(optimalDirectionsUpwind()));
|
||||
extraBearings.addAll(Arrays.asList(optimalDirectionsDownwind()));
|
||||
}
|
||||
|
||||
for (Speed s : speedTable.keySet()) {
|
||||
setWind(new KnotSpeedWithBearingImpl(s.getKnots(),
|
||||
new DegreeBearingImpl(135)));
|
||||
NavigableMap<Bearing, Speed> currentTable = new TreeMap<Bearing, Speed>(
|
||||
bearingComparator);
|
||||
table.put(s, currentTable);
|
||||
|
||||
for (Double b = 0.0; b < 360.0; b += bearingStep) {
|
||||
Bearing bearing = new DegreeBearingImpl(b);
|
||||
currentTable.put(bearing, getSpeedAtBearing(bearing));
|
||||
}
|
||||
for (Bearing extraBearing : extraBearings)
|
||||
currentTable.put(extraBearing, getSpeedAtBearing(extraBearing));
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getTargetDirection() {
|
||||
return targetDirection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetDirection(Bearing newTargetDirection) {
|
||||
targetDirection = newTargetDirection;
|
||||
}
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.NavigableMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
|
||||
public class PolarDiagram505 extends PolarDiagramBase {
|
||||
|
||||
// this constructor creates an instance with a hard-coded set of values
|
||||
public PolarDiagram505() {
|
||||
speedTable = new TreeMap<Speed, NavigableMap<Bearing, Speed>>();
|
||||
NavigableMap<Bearing, Speed> tableRow;
|
||||
|
||||
double cutAngle = 35.0;
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagramBase.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(cutAngle), new KnotSpeedImpl(1));
|
||||
tableRow.put(new DegreeBearingImpl(60), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(75), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(90), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(110), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(120), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(135), Speed.NULL);
|
||||
// tableRow.put(new DegreeBearingImpl(150), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(180), Speed.NULL);
|
||||
speedTable.put(Speed.NULL, tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagramBase.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(cutAngle), new KnotSpeedImpl(1));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(5.09));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(5.17));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(5.25));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(5.15));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(5.1));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(5.03));
|
||||
// tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(4.62));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(2.5));
|
||||
speedTable.put(new KnotSpeedImpl(6), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagramBase.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(cutAngle), new KnotSpeedImpl(1));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(5.38));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(5.47));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(5.57));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(6.01));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(6.23));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(6.57));
|
||||
// tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(5.85));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(3.35));
|
||||
speedTable.put(new KnotSpeedImpl(8), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagramBase.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(cutAngle), new KnotSpeedImpl(1));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(5.67));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(5.77));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(5.88));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(6.94));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(7.47));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(8.26));
|
||||
// tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(6.97));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(4.25));
|
||||
speedTable.put(new KnotSpeedImpl(10), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagramBase.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(cutAngle), new KnotSpeedImpl(1));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(6.06));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(6.18));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(6.30));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(7.86));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(8.64));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(9.81));
|
||||
// tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(7.86));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(5));
|
||||
speedTable.put(new KnotSpeedImpl(12), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagramBase.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(cutAngle), new KnotSpeedImpl(1));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(6.55));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(6.69));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(6.83));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(8.71));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(9.66));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(11.07));
|
||||
// tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(8.57));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(5.75));
|
||||
speedTable.put(new KnotSpeedImpl(14), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagramBase.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(cutAngle), new KnotSpeedImpl(1));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(7.05));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(7.20));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(7.35));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(9.50));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(10.58));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(12.19));
|
||||
// tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(9.13));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(6.5));
|
||||
speedTable.put(new KnotSpeedImpl(16), tableRow);
|
||||
|
||||
tableRow = new TreeMap<Bearing, Speed>(PolarDiagramBase.bearingComparator);
|
||||
tableRow.put(new DegreeBearingImpl(0), Speed.NULL);
|
||||
tableRow.put(new DegreeBearingImpl(cutAngle), new KnotSpeedImpl(1));
|
||||
tableRow.put(new DegreeBearingImpl(60), new KnotSpeedImpl(7.04));
|
||||
tableRow.put(new DegreeBearingImpl(75), new KnotSpeedImpl(7.20));
|
||||
tableRow.put(new DegreeBearingImpl(90), new KnotSpeedImpl(7.35));
|
||||
tableRow.put(new DegreeBearingImpl(110), new KnotSpeedImpl(9.90));
|
||||
tableRow.put(new DegreeBearingImpl(120), new KnotSpeedImpl(11.18));
|
||||
tableRow.put(new DegreeBearingImpl(135), new KnotSpeedImpl(13.09));
|
||||
// tableRow.put(new DegreeBearingImpl(150), new KnotSpeedImpl(10.26));
|
||||
tableRow.put(new DegreeBearingImpl(180), new KnotSpeedImpl(7.5));
|
||||
speedTable.put(new KnotSpeedImpl(20), tableRow);
|
||||
|
||||
NavigableMap<Speed, Bearing> beatAngles = new TreeMap<Speed, Bearing>();
|
||||
beatAngles.put(new KnotSpeedImpl(0), new DegreeBearingImpl(44.0));
|
||||
beatAngles.put(new KnotSpeedImpl(6), new DegreeBearingImpl(44.0));
|
||||
beatAngles.put(new KnotSpeedImpl(8), new DegreeBearingImpl(46.5));
|
||||
beatAngles.put(new KnotSpeedImpl(10), new DegreeBearingImpl(50.0));
|
||||
beatAngles.put(new KnotSpeedImpl(12), new DegreeBearingImpl(52.0));
|
||||
beatAngles.put(new KnotSpeedImpl(14), new DegreeBearingImpl(54.0));
|
||||
beatAngles.put(new KnotSpeedImpl(16), new DegreeBearingImpl(55.0));
|
||||
beatAngles.put(new KnotSpeedImpl(20), new DegreeBearingImpl(56.0));
|
||||
|
||||
double beatScale = 1.0;
|
||||
NavigableMap<Speed, Speed> beatSOG = new TreeMap<Speed, Speed>();
|
||||
beatSOG.put(new KnotSpeedImpl(0), new KnotSpeedImpl(0));
|
||||
beatSOG.put(new KnotSpeedImpl(6), new KnotSpeedImpl(5.00 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(8), new KnotSpeedImpl(5.30 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(10), new KnotSpeedImpl(5.60 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(12), new KnotSpeedImpl(6.00 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(14), new KnotSpeedImpl(6.50 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(16), new KnotSpeedImpl(7.00 * beatScale));
|
||||
beatSOG.put(new KnotSpeedImpl(20), new KnotSpeedImpl(7.00 * beatScale));
|
||||
|
||||
NavigableMap<Speed, Bearing> gybeAngles = new TreeMap<Speed, Bearing>();
|
||||
gybeAngles.put(new KnotSpeedImpl(0), new DegreeBearingImpl(141.0));
|
||||
gybeAngles.put(new KnotSpeedImpl(6), new DegreeBearingImpl(141.0));
|
||||
gybeAngles.put(new KnotSpeedImpl(8), new DegreeBearingImpl(141.0));
|
||||
gybeAngles.put(new KnotSpeedImpl(10), new DegreeBearingImpl(139.5));
|
||||
gybeAngles.put(new KnotSpeedImpl(12), new DegreeBearingImpl(137.5));
|
||||
gybeAngles.put(new KnotSpeedImpl(14), new DegreeBearingImpl(139.5));
|
||||
gybeAngles.put(new KnotSpeedImpl(16), new DegreeBearingImpl(142.5));
|
||||
gybeAngles.put(new KnotSpeedImpl(20), new DegreeBearingImpl(150.0));
|
||||
|
||||
NavigableMap<Speed, Speed> gybeSOG = new TreeMap<Speed, Speed>();
|
||||
gybeSOG.put(new KnotSpeedImpl(0), new KnotSpeedImpl(0));
|
||||
gybeSOG.put(new KnotSpeedImpl(6), new KnotSpeedImpl(5.00));
|
||||
gybeSOG.put(new KnotSpeedImpl(8), new KnotSpeedImpl(6.70));
|
||||
gybeSOG.put(new KnotSpeedImpl(10), new KnotSpeedImpl(8.50));
|
||||
gybeSOG.put(new KnotSpeedImpl(12), new KnotSpeedImpl(10.00));
|
||||
gybeSOG.put(new KnotSpeedImpl(14), new KnotSpeedImpl(11.50));
|
||||
gybeSOG.put(new KnotSpeedImpl(16), new KnotSpeedImpl(13.00));
|
||||
gybeSOG.put(new KnotSpeedImpl(20), new KnotSpeedImpl(15.00));
|
||||
|
||||
for (Speed s : speedTable.keySet()) {
|
||||
|
||||
if (beatAngles.containsKey(s) && !speedTable.get(s).containsKey(beatAngles.get(s)))
|
||||
speedTable.get(s).put(beatAngles.get(s), beatSOG.get(s));
|
||||
|
||||
if (gybeAngles.containsKey(s) && !speedTable.get(s).containsKey(gybeAngles.get(s)))
|
||||
speedTable.get(s).put(gybeAngles.get(s), gybeSOG.get(s));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.RadianBearingImpl;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
|
||||
public class PolarDiagramBase implements PolarDiagram {
|
||||
|
||||
// the current speed and direction of the wind
|
||||
protected SpeedWithBearing wind = new KnotSpeedWithBearingImpl(6, new DegreeBearingImpl(180));
|
||||
|
||||
// the preferred direction of movement
|
||||
// is used by optimalDirectionsUpwind() and optimialDirectionsDownwind()
|
||||
protected Bearing targetDirection = new DegreeBearingImpl(0);
|
||||
|
||||
protected NavigableMap<Speed, NavigableMap<Bearing, Speed>> speedTable;
|
||||
protected NavigableMap<Speed, Bearing> beatAngles;
|
||||
protected NavigableMap<Speed, Bearing> gybeAngles;
|
||||
protected NavigableMap<Speed, Speed> beatSOG;
|
||||
protected NavigableMap<Speed, Speed> gybeSOG;
|
||||
|
||||
// this constructor creates an instance with a hard-coded set of values
|
||||
public PolarDiagramBase() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// a constructor that allows a generic set of parameters
|
||||
public PolarDiagramBase(NavigableMap<Speed, NavigableMap<Bearing, Speed>> speeds,
|
||||
NavigableMap<Speed, Bearing> beats, NavigableMap<Speed, Bearing> gybes,
|
||||
NavigableMap<Speed, Speed> beatSOGs, NavigableMap<Speed, Speed> gybeSOGs) {
|
||||
|
||||
wind = new KnotSpeedWithBearingImpl(0, new DegreeBearingImpl(180));
|
||||
|
||||
speedTable = speeds;
|
||||
beatAngles = beats;
|
||||
gybeAngles = gybes;
|
||||
beatSOG = beatSOGs;
|
||||
gybeSOG = gybeSOGs;
|
||||
|
||||
for (Speed s : speedTable.keySet()) {
|
||||
|
||||
if (beatAngles.containsKey(s) && !speedTable.get(s).containsKey(beatAngles.get(s)))
|
||||
speedTable.get(s).put(beatAngles.get(s), beatSOG.get(s));
|
||||
|
||||
if (gybeAngles.containsKey(s) && !speedTable.get(s).containsKey(gybeAngles.get(s)))
|
||||
speedTable.get(s).put(gybeAngles.get(s), gybeSOG.get(s));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getWind() {
|
||||
return wind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWind(SpeedWithBearing newWind) {
|
||||
wind = newWind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedAtBearing(Bearing bearing) {
|
||||
|
||||
Bearing relativeBearing = wind.getBearing().reverse().getDifferenceTo(bearing);
|
||||
if (relativeBearing.getDegrees() < 0)
|
||||
relativeBearing = relativeBearing.getDifferenceTo(new DegreeBearingImpl(0));
|
||||
|
||||
Speed floorWind = speedTable.floorKey(wind);
|
||||
Speed ceilingWind = speedTable.ceilingKey(wind);
|
||||
|
||||
if (ceilingWind == null) {
|
||||
ceilingWind = floorWind;
|
||||
}
|
||||
if (floorWind == null) {
|
||||
floorWind = ceilingWind;
|
||||
}
|
||||
|
||||
NavigableMap<Bearing, Speed> floorSpeeds = speedTable.get(floorWind);
|
||||
NavigableMap<Bearing, Speed> ceilingSpeeds = speedTable.get(ceilingWind);
|
||||
|
||||
// Taylor estimations of order 1
|
||||
Speed floorSpeed1 = floorSpeeds.floorEntry(relativeBearing).getValue();
|
||||
Speed floorSpeed2 = floorSpeeds.ceilingEntry(relativeBearing).getValue();
|
||||
Bearing floorBearing1 = floorSpeeds.floorKey(relativeBearing);
|
||||
Bearing floorBearing2 = floorSpeeds.ceilingKey(relativeBearing);
|
||||
double floorSpeed;
|
||||
if (floorSpeed1.equals(floorSpeed2)) {
|
||||
floorSpeed = floorSpeed1.getKnots();
|
||||
} else {
|
||||
floorSpeed = floorSpeed1.getKnots() + (relativeBearing.getRadians() - floorBearing1.getRadians())
|
||||
* (floorSpeed2.getKnots() - floorSpeed1.getKnots())
|
||||
/ (floorBearing2.getRadians() - floorBearing1.getRadians());
|
||||
}
|
||||
|
||||
Speed ceilingSpeed1 = ceilingSpeeds.floorEntry(relativeBearing).getValue();
|
||||
Speed ceilingSpeed2 = ceilingSpeeds.ceilingEntry(relativeBearing).getValue();
|
||||
Bearing ceilingBearing1 = ceilingSpeeds.floorKey(relativeBearing);
|
||||
Bearing ceilingBearing2 = ceilingSpeeds.ceilingKey(relativeBearing);
|
||||
double ceilingSpeed;
|
||||
if (ceilingSpeed1.equals(ceilingSpeed2)) {
|
||||
ceilingSpeed = ceilingSpeed1.getKnots();
|
||||
} else {
|
||||
ceilingSpeed = ceilingSpeed1.getKnots() + (relativeBearing.getRadians() - ceilingBearing1.getRadians())
|
||||
* (ceilingSpeed2.getKnots() - ceilingSpeed1.getKnots())
|
||||
/ (ceilingBearing2.getRadians() - ceilingBearing1.getRadians());
|
||||
}
|
||||
|
||||
double speed;
|
||||
if (floorWind.equals(ceilingWind)) {
|
||||
speed = floorSpeed;
|
||||
} else {
|
||||
speed = floorSpeed + (wind.getKnots() - floorWind.getKnots()) * (ceilingSpeed - floorSpeed)
|
||||
/ (ceilingWind.getKnots() - floorWind.getKnots());
|
||||
}
|
||||
if ((Math.abs(relativeBearing.getDegrees()) < 20) || (Math.abs(relativeBearing.getDegrees()) > 330)) {
|
||||
speed = 0.1;
|
||||
}
|
||||
|
||||
return new KnotSpeedWithBearingImpl(speed, bearing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing[] optimalDirectionsUpwind() {
|
||||
Bearing windBearing = wind.getBearing().reverse();
|
||||
Bearing estBeatAngleRight = null;
|
||||
Bearing estBeatAngleLeft = null;
|
||||
if (targetDirection.equals(new DegreeBearingImpl(0))) {
|
||||
Bearing floorBeatAngle;
|
||||
if (beatAngles.floorEntry(wind) == null) {
|
||||
floorBeatAngle = beatAngles.ceilingEntry(wind).getValue();
|
||||
} else {
|
||||
floorBeatAngle = beatAngles.floorEntry(wind).getValue();
|
||||
}
|
||||
Bearing ceilingBeatAngle;
|
||||
if (beatAngles.ceilingEntry(wind) == null) {
|
||||
ceilingBeatAngle = beatAngles.floorEntry(wind).getValue();
|
||||
} else {
|
||||
ceilingBeatAngle = beatAngles.ceilingEntry(wind).getValue();
|
||||
}
|
||||
if (floorBeatAngle == null)
|
||||
floorBeatAngle = new DegreeBearingImpl(0);
|
||||
if (ceilingBeatAngle == null)
|
||||
ceilingBeatAngle = new DegreeBearingImpl(0);
|
||||
|
||||
Speed floorSpeed = beatAngles.floorKey(wind);
|
||||
if (floorSpeed == null) {
|
||||
floorSpeed = beatAngles.ceilingKey(wind);
|
||||
}
|
||||
Speed ceilingSpeed = beatAngles.ceilingKey(wind);
|
||||
if (beatAngles.ceilingKey(wind) == null) {
|
||||
ceilingSpeed = beatAngles.floorKey(wind);
|
||||
}
|
||||
double beatAngle;
|
||||
if (floorSpeed.equals(ceilingSpeed)) {
|
||||
beatAngle = floorBeatAngle.getRadians();
|
||||
} else {
|
||||
beatAngle = floorBeatAngle.getRadians() + (wind.getKnots() - floorSpeed.getKnots())
|
||||
* (ceilingBeatAngle.getRadians() - floorBeatAngle.getRadians())
|
||||
/ (ceilingSpeed.getKnots() - floorSpeed.getKnots());
|
||||
}
|
||||
estBeatAngleRight = new RadianBearingImpl(+beatAngle);
|
||||
estBeatAngleLeft = new RadianBearingImpl(-beatAngle);
|
||||
return new Bearing[] {
|
||||
// windBearing.add(estBeatAngle),
|
||||
// windBearing.add(estBeatAngle.getDifferenceTo(windBearing))
|
||||
windBearing.add(estBeatAngleLeft), windBearing.add(estBeatAngleRight) };
|
||||
} else {
|
||||
Set<Bearing> allKeys = new TreeSet<Bearing>(bearingComparator);
|
||||
for (Double b = 0.0; b < 360.0; b += 5.0)
|
||||
allKeys.add(new DegreeBearingImpl(b));
|
||||
Bearing _targetDirection = targetDirection;
|
||||
setTargetDirection(new DegreeBearingImpl(0.0));
|
||||
allKeys.addAll(Arrays.asList(optimalDirectionsUpwind()));
|
||||
allKeys.addAll(Arrays.asList(optimalDirectionsDownwind()));
|
||||
setTargetDirection(_targetDirection);
|
||||
Double maxSpeedRight = 0.0;
|
||||
Double maxSpeedLeft = 0.0;
|
||||
for (Bearing b : allKeys) {
|
||||
if (b.getDifferenceTo(getWind().getBearing()).getDegrees() > 0) {
|
||||
if (getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection()).getRadians()) > maxSpeedRight) {
|
||||
maxSpeedRight = getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection()).getRadians());
|
||||
estBeatAngleRight = b;
|
||||
}
|
||||
} else if (getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection()).getRadians()) > maxSpeedLeft) {
|
||||
maxSpeedLeft = getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection()).getRadians());
|
||||
estBeatAngleLeft = b;
|
||||
}
|
||||
}
|
||||
return new Bearing[] {
|
||||
// windBearing.add(estBeatAngle),
|
||||
// windBearing.add(estBeatAngle.getDifferenceTo(windBearing))
|
||||
estBeatAngleLeft, estBeatAngleRight };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing[] optimalDirectionsDownwind() {
|
||||
|
||||
Bearing windBearing = wind.getBearing().reverse();
|
||||
Bearing estGybeAngleRight = null;
|
||||
Bearing estGybeAngleLeft = null;
|
||||
if (getTargetDirection().equals(new DegreeBearingImpl(0))) {
|
||||
windBearing = wind.getBearing().reverse();
|
||||
estGybeAngleRight = null;
|
||||
estGybeAngleLeft = null;
|
||||
Bearing floorGybeAngle = gybeAngles.floorEntry(wind).getValue();
|
||||
Bearing ceilingGybeAngle = gybeAngles.ceilingEntry(wind).getValue();
|
||||
if (floorGybeAngle == null)
|
||||
floorGybeAngle = new DegreeBearingImpl(0);
|
||||
if (ceilingGybeAngle == null)
|
||||
ceilingGybeAngle = new DegreeBearingImpl(0);
|
||||
Speed floorSpeed = gybeAngles.floorKey(wind);
|
||||
Speed ceilingSpeed = gybeAngles.ceilingKey(wind);
|
||||
double gybeAngle;
|
||||
if (floorSpeed.equals(ceilingSpeed)) {
|
||||
gybeAngle = floorGybeAngle.getRadians();
|
||||
} else {
|
||||
gybeAngle = floorGybeAngle.getRadians() + (wind.getKnots() - floorSpeed.getKnots())
|
||||
* (ceilingGybeAngle.getRadians() - floorGybeAngle.getRadians())
|
||||
/ (ceilingSpeed.getKnots() - floorSpeed.getKnots());
|
||||
}
|
||||
// Bearing estGybeAngle = new RadianBearingImpl(gybeAngle);
|
||||
estGybeAngleRight = new RadianBearingImpl(+gybeAngle);
|
||||
estGybeAngleLeft = new RadianBearingImpl(-gybeAngle);
|
||||
return new Bearing[] { windBearing.add(estGybeAngleRight), windBearing.add(estGybeAngleLeft) };
|
||||
} else {
|
||||
|
||||
Set<Bearing> allKeys = new TreeSet<Bearing>(bearingComparator);
|
||||
for (Double b = 0.0; b < 360.0; b += 5.0)
|
||||
allKeys.add(new DegreeBearingImpl(b));
|
||||
Bearing _targetDirection = targetDirection;
|
||||
setTargetDirection(new DegreeBearingImpl(0.0));
|
||||
allKeys.addAll(Arrays.asList(optimalDirectionsUpwind()));
|
||||
allKeys.addAll(Arrays.asList(optimalDirectionsDownwind()));
|
||||
setTargetDirection(_targetDirection);
|
||||
Double maxSpeedRight = 0.0;
|
||||
Double maxSpeedLeft = 0.0;
|
||||
for (Bearing b : allKeys) {
|
||||
if (b.getDifferenceTo(getWind().getBearing()).getDegrees() > 0) {
|
||||
if (getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection().reverse()).getRadians()) > maxSpeedRight) {
|
||||
maxSpeedRight = getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection().reverse()).getRadians());
|
||||
estGybeAngleRight = b;
|
||||
}
|
||||
} else if (getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection().reverse()).getRadians()) > maxSpeedLeft) {
|
||||
maxSpeedLeft = getSpeedAtBearing(b).getKnots()
|
||||
* Math.cos(b.getDifferenceTo(getTargetDirection().reverse()).getRadians());
|
||||
estGybeAngleLeft = b;
|
||||
}
|
||||
}
|
||||
return new Bearing[] {
|
||||
// windBearing.add(estBeatAngle),
|
||||
// windBearing.add(estBeatAngle.getDifferenceTo(windBearing))
|
||||
estGybeAngleLeft, estGybeAngleRight };
|
||||
}
|
||||
}
|
||||
|
||||
// a Bearing Comparator useful in the creation of sorted sets of Bearing
|
||||
public static Comparator<Bearing> bearingComparator = new Comparator<Bearing>() {
|
||||
|
||||
@Override
|
||||
public int compare(Bearing o1, Bearing o2) {
|
||||
Double d1 = o1.getDegrees();
|
||||
if (d1 < 0)
|
||||
d1 = 360 + d1;
|
||||
Double d2 = o2.getDegrees();
|
||||
if (d2 < 0)
|
||||
d2 = 360 + d2;
|
||||
return d1.compareTo(d2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@Override
|
||||
public long getTurnLoss() {
|
||||
// TODO Auto-generated method stub
|
||||
return 4000;
|
||||
}
|
||||
|
||||
// TO BE REVIEWED
|
||||
// not sure I use the right terms and conventions
|
||||
@Override
|
||||
public WindSide getWindSide(Bearing bearing) {
|
||||
WindSide windSide = null;
|
||||
if (bearingComparator.compare(bearing, wind.getBearing().reverse()) > 0)
|
||||
windSide = WindSide.LEFT;
|
||||
if (bearingComparator.compare(bearing, wind.getBearing().reverse()) < 0)
|
||||
windSide = WindSide.RIGHT;
|
||||
if (bearing.equals(wind.getBearing()))
|
||||
windSide = WindSide.OPPOSING;
|
||||
if (bearing.equals(wind.getBearing().reverse()))
|
||||
windSide = WindSide.FACING;
|
||||
|
||||
return windSide;
|
||||
}
|
||||
|
||||
// returns a table of Bearing-Speed pairs with a bearingStep granularity
|
||||
// for all Speeds in speedTable
|
||||
@Override
|
||||
public NavigableMap<Speed, NavigableMap<Bearing, Speed>> polarDiagramPlot(Double bearingStep) {
|
||||
|
||||
NavigableMap<Speed, NavigableMap<Bearing, Speed>> table = new TreeMap<Speed, NavigableMap<Bearing, Speed>>();
|
||||
Set<Bearing> extraBearings = new HashSet<Bearing>();
|
||||
|
||||
for (Speed s : speedTable.keySet()) {
|
||||
setWind(new KnotSpeedWithBearingImpl(s.getKnots(), new DegreeBearingImpl(135)));
|
||||
extraBearings.addAll(Arrays.asList(optimalDirectionsUpwind()));
|
||||
extraBearings.addAll(Arrays.asList(optimalDirectionsDownwind()));
|
||||
}
|
||||
|
||||
for (Speed s : speedTable.keySet()) {
|
||||
setWind(new KnotSpeedWithBearingImpl(s.getKnots(), new DegreeBearingImpl(135)));
|
||||
NavigableMap<Bearing, Speed> currentTable = new TreeMap<Bearing, Speed>(bearingComparator);
|
||||
table.put(s, currentTable);
|
||||
|
||||
for (Double b = 0.0; b < 360.0; b += bearingStep) {
|
||||
Bearing bearing = new DegreeBearingImpl(b);
|
||||
currentTable.put(bearing, getSpeedAtBearing(bearing));
|
||||
}
|
||||
for (Bearing extraBearing : extraBearings)
|
||||
currentTable.put(extraBearing, getSpeedAtBearing(extraBearing));
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getTargetDirection() {
|
||||
return targetDirection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetDirection(Bearing newTargetDirection) {
|
||||
targetDirection = newTargetDirection;
|
||||
}
|
||||
|
||||
}
|
||||
+65
-65
@@ -1,6 +1,5 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
@@ -12,78 +11,79 @@ import com.sap.sailing.simulator.PolarDiagram;
|
||||
|
||||
public class PolarDiagramImpl implements PolarDiagram {
|
||||
|
||||
private SpeedWithBearing wind;
|
||||
private Bearing northWest;
|
||||
private Bearing northEast;
|
||||
private Bearing southEast;
|
||||
private Bearing southWest;
|
||||
|
||||
public PolarDiagramImpl(double windSpeed) {
|
||||
|
||||
setWind(new KilometersPerHourSpeedWithBearingImpl(windSpeed, new DegreeBearingImpl(0)));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getWind() {
|
||||
return wind;
|
||||
}
|
||||
private SpeedWithBearing wind;
|
||||
private Bearing northWest;
|
||||
private Bearing northEast;
|
||||
private Bearing southEast;
|
||||
private Bearing southWest;
|
||||
|
||||
@Override
|
||||
public void setWind(SpeedWithBearing newWind) {
|
||||
wind = newWind;
|
||||
northWest = wind.getBearing().add(new DegreeBearingImpl(330));
|
||||
northEast = wind.getBearing().add(new DegreeBearingImpl(30));
|
||||
southWest = wind.getBearing().add(new DegreeBearingImpl(210));
|
||||
southEast = wind.getBearing().add(new DegreeBearingImpl(150));
|
||||
}
|
||||
public PolarDiagramImpl(double windSpeed) {
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedAtBearing(Bearing bearing) {
|
||||
if (bearing.equals(northEast) || bearing.equals(northWest)) return new KilometersPerHourSpeedWithBearingImpl(wind.getKilometersPerHour(), bearing);
|
||||
if (bearing.equals(southEast) || bearing.equals(southWest)) return new KilometersPerHourSpeedWithBearingImpl(0.7*wind.getKilometersPerHour(), bearing);
|
||||
return new KilometersPerHourSpeedWithBearingImpl(0.5*wind.getKilometersPerHour(), bearing);
|
||||
}
|
||||
setWind(new KilometersPerHourSpeedWithBearingImpl(windSpeed, new DegreeBearingImpl(0)));
|
||||
|
||||
@Override
|
||||
public Bearing[] optimalDirectionsUpwind() {
|
||||
return new Bearing[] {northWest, northEast};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing[] optimalDirectionsDownwind() {
|
||||
return new Bearing[] {southEast, southWest};
|
||||
}
|
||||
@Override
|
||||
public SpeedWithBearing getWind() {
|
||||
return wind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTurnLoss() {
|
||||
// TODO Auto-generated method stub
|
||||
return 4000;
|
||||
}
|
||||
@Override
|
||||
public void setWind(SpeedWithBearing newWind) {
|
||||
wind = newWind;
|
||||
northWest = wind.getBearing().add(new DegreeBearingImpl(330));
|
||||
northEast = wind.getBearing().add(new DegreeBearingImpl(30));
|
||||
southWest = wind.getBearing().add(new DegreeBearingImpl(210));
|
||||
southEast = wind.getBearing().add(new DegreeBearingImpl(150));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindSide getWindSide(Bearing bearing) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedAtBearing(Bearing bearing) {
|
||||
if (bearing.equals(northEast) || bearing.equals(northWest))
|
||||
return new KilometersPerHourSpeedWithBearingImpl(wind.getKilometersPerHour(), bearing);
|
||||
if (bearing.equals(southEast) || bearing.equals(southWest))
|
||||
return new KilometersPerHourSpeedWithBearingImpl(0.7 * wind.getKilometersPerHour(), bearing);
|
||||
return new KilometersPerHourSpeedWithBearingImpl(0.5 * wind.getKilometersPerHour(), bearing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableMap<Speed, NavigableMap<Bearing, Speed>> polarDiagramPlot(
|
||||
Double bearingStep) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Bearing[] optimalDirectionsUpwind() {
|
||||
return new Bearing[] { northWest, northEast };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getTargetDirection() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Bearing[] optimalDirectionsDownwind() {
|
||||
return new Bearing[] { southEast, southWest };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetDirection(Bearing newTargetDirection) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
@Override
|
||||
public long getTurnLoss() {
|
||||
// TODO Auto-generated method stub
|
||||
return 4000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindSide getWindSide(Bearing bearing) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableMap<Speed, NavigableMap<Bearing, Speed>> polarDiagramPlot(Double bearingStep) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getTargetDirection() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetDirection(Bearing newTargetDirection) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+98
-121
@@ -12,7 +12,7 @@ import com.sap.sailing.simulator.Boundary;
|
||||
|
||||
public class RectangularBoundary implements Boundary {
|
||||
|
||||
private Position rcStart; // start position of race course
|
||||
private Position rcStart; // start position of race course
|
||||
private Position rcEnd; // end position of race course
|
||||
private double lngScale; // scale of distances longitude : latitude
|
||||
private double[] nvVrt; // vertical normal vector with suitable length
|
||||
@@ -21,7 +21,7 @@ public class RectangularBoundary implements Boundary {
|
||||
private int hPoints; // number of horizontal steps
|
||||
|
||||
private Position northWest;
|
||||
private Position southEast;
|
||||
//private Position southEast;
|
||||
private Position southWest;
|
||||
private Position northEast;
|
||||
|
||||
@@ -30,7 +30,6 @@ public class RectangularBoundary implements Boundary {
|
||||
private Position appSouthWest;
|
||||
private Position appNorthEast;
|
||||
|
||||
|
||||
private Bearing north;
|
||||
private Bearing south;
|
||||
private Bearing east;
|
||||
@@ -43,8 +42,8 @@ public class RectangularBoundary implements Boundary {
|
||||
|
||||
public RectangularBoundary(Position p1, Position p2, double tlr) {
|
||||
|
||||
//System.out.println("Start:"+p1);
|
||||
//System.out.println("End :"+p2);
|
||||
// System.out.println("Start:"+p1);
|
||||
// System.out.println("End :"+p2);
|
||||
|
||||
rcStart = p1;
|
||||
rcEnd = p2;
|
||||
@@ -65,26 +64,26 @@ public class RectangularBoundary implements Boundary {
|
||||
|
||||
// the following test shows, that numerics appear to be instable:
|
||||
// translating appNorthEast 2xEast should be appNorthWest, but numerically its NOT
|
||||
//Position tstNorthEast = appNorthWest.translateGreatCircle(east, appHeight).translateGreatCircle(east, appHeight);
|
||||
//appSouthEast = appNorthEast.translateGreatCircle(south, appHeight);
|
||||
//appSouthWest = appNorthWest.translateGreatCircle(south, appHeight);
|
||||
// Position tstNorthEast = appNorthWest.translateGreatCircle(east, appHeight).translateGreatCircle(east,
|
||||
// appHeight);
|
||||
// appSouthEast = appNorthEast.translateGreatCircle(south, appHeight);
|
||||
// appSouthWest = appNorthWest.translateGreatCircle(south, appHeight);
|
||||
|
||||
appSouthWest = p1.translateGreatCircle(west, appHeight);
|
||||
appSouthEast = p1.translateGreatCircle(east, appHeight);
|
||||
|
||||
//System.out.println("southWest:"+appSouthWest);
|
||||
//System.out.println("southEast:"+appSouthEast);
|
||||
//System.out.println("northWest:"+appNorthWest);
|
||||
//System.out.println("northEast:"+appNorthEast);
|
||||
//System.out.println("testnEast:"+tstNorthEast);
|
||||
|
||||
// System.out.println("southWest:"+appSouthWest);
|
||||
// System.out.println("southEast:"+appSouthEast);
|
||||
// System.out.println("northWest:"+appNorthWest);
|
||||
// System.out.println("northEast:"+appNorthEast);
|
||||
// System.out.println("testnEast:"+tstNorthEast);
|
||||
|
||||
Distance diag = appNorthWest.getDistance(appSouthEast);
|
||||
|
||||
Bearing diag1 = appSouthEast.getBearingGreatCircle(appNorthWest);
|
||||
northWest = appNorthWest.translateGreatCircle(diag1, diag.scale(tolerance));
|
||||
diag1 = diag1.reverse();
|
||||
southEast = appSouthEast.translateGreatCircle(diag1, diag.scale(tolerance));
|
||||
//southEast = appSouthEast.translateGreatCircle(diag1, diag.scale(tolerance));
|
||||
Bearing diag2 = appSouthWest.getBearingGreatCircle(appNorthEast);
|
||||
northEast = appNorthEast.translateGreatCircle(diag2, diag.scale(tolerance));
|
||||
diag2 = diag2.reverse();
|
||||
@@ -121,11 +120,10 @@ public class RectangularBoundary implements Boundary {
|
||||
Distance northSouth = northProjection.getDistance(southProjection);
|
||||
Distance eastWest = eastProjection.getDistance(westProjection);
|
||||
|
||||
return
|
||||
( northSouth.compareTo(p.getDistance(northProjection)) >= 0 )
|
||||
&& ( northSouth.compareTo(p.getDistance(southProjection)) >= 0 )
|
||||
&& ( eastWest.compareTo(p.getDistance(eastProjection)) >= 0 )
|
||||
&& ( eastWest.compareTo(p.getDistance(westProjection)) >=0 );
|
||||
return (northSouth.compareTo(p.getDistance(northProjection)) >= 0)
|
||||
&& (northSouth.compareTo(p.getDistance(southProjection)) >= 0)
|
||||
&& (eastWest.compareTo(p.getDistance(eastProjection)) >= 0)
|
||||
&& (eastWest.compareTo(p.getDistance(westProjection)) >= 0);
|
||||
|
||||
}
|
||||
|
||||
@@ -136,9 +134,9 @@ public class RectangularBoundary implements Boundary {
|
||||
this.hPoints = hPoints;
|
||||
|
||||
double xscale = 1.5;
|
||||
|
||||
double alat = (rcEnd.getLatDeg() + rcStart.getLatDeg())/2.;
|
||||
lngScale = Math.cos(alat*Math.PI/180.);
|
||||
|
||||
double alat = (rcEnd.getLatDeg() + rcStart.getLatDeg()) / 2.;
|
||||
lngScale = Math.cos(alat * Math.PI / 180.);
|
||||
|
||||
double[] dVrt = new double[2];
|
||||
dVrt[0] = rcEnd.getLatDeg() - rcStart.getLatDeg();
|
||||
@@ -146,143 +144,121 @@ public class RectangularBoundary implements Boundary {
|
||||
|
||||
double[] dscVrt = new double[2];
|
||||
dscVrt[0] = dVrt[0];
|
||||
dscVrt[1] = dVrt[1]*lngScale;
|
||||
dscVrt[1] = dVrt[1] * lngScale;
|
||||
|
||||
double lscVrt = Math.sqrt(dscVrt[0]*dscVrt[0] + dscVrt[1]*dscVrt[1]);
|
||||
double lscVrt = Math.sqrt(dscVrt[0] * dscVrt[0] + dscVrt[1] * dscVrt[1]);
|
||||
|
||||
nvVrt = new double[2];
|
||||
nvVrt[0] = dscVrt[0]/lscVrt/lscVrt*(vPoints-1);
|
||||
nvVrt[1] = dscVrt[1]/lscVrt/lscVrt*(vPoints-1);
|
||||
nvVrt[0] = dscVrt[0] / lscVrt / lscVrt * (vPoints - 1);
|
||||
nvVrt[1] = dscVrt[1] / lscVrt / lscVrt * (vPoints - 1);
|
||||
|
||||
double[] nscHor = new double[2];
|
||||
nscHor[0] = -dscVrt[1]/lscVrt;
|
||||
nscHor[1] = dscVrt[0]/lscVrt;
|
||||
nscHor[0] = -dscVrt[1] / lscVrt;
|
||||
nscHor[1] = dscVrt[0] / lscVrt;
|
||||
|
||||
nvHor = new double[2];
|
||||
nvHor[0] = nscHor[0]/xscale/lscVrt*(hPoints-1);
|
||||
nvHor[1] = nscHor[1]/xscale/lscVrt*(hPoints-1);
|
||||
nvHor[0] = nscHor[0] / xscale / lscVrt * (hPoints - 1);
|
||||
nvHor[1] = nscHor[1] / xscale / lscVrt * (hPoints - 1);
|
||||
|
||||
double[] nHor = new double[2];
|
||||
nHor[0] = nscHor[0];
|
||||
nHor[1] = nscHor[1]/lngScale;
|
||||
nHor[1] = nscHor[1] / lngScale;
|
||||
|
||||
//System.out.println("LngScale:"+lngScale+", Diff.Vrt:"+dVrt);
|
||||
Position[][] grid = new Position[vPoints][hPoints];
|
||||
// System.out.println("LngScale:"+lngScale+", Diff.Vrt:"+dVrt);
|
||||
Position[][] grid = new Position[vPoints][hPoints];
|
||||
Position pv;
|
||||
for (int i = 0; i < vPoints; i++) {
|
||||
//System.out.print("nrow "+i+": ");
|
||||
// System.out.print("nrow "+i+": ");
|
||||
|
||||
if (i == 0) {
|
||||
pv = rcStart;
|
||||
} else if (i == vPoints-1) {
|
||||
} else if (i == vPoints - 1) {
|
||||
pv = rcEnd;
|
||||
} else {
|
||||
pv = new DegreePosition(rcStart.getLatDeg() + i/(vPoints-1.0)*dVrt[0],rcStart.getLngDeg() + i/(vPoints-1.0)*dVrt[1]);
|
||||
pv = new DegreePosition(rcStart.getLatDeg() + i / (vPoints - 1.0) * dVrt[0], rcStart.getLngDeg() + i
|
||||
/ (vPoints - 1.0) * dVrt[1]);
|
||||
}
|
||||
|
||||
int j=0;
|
||||
int j = 0;
|
||||
// left side
|
||||
while (j < hPoints/2) {
|
||||
grid[i][j] = new DegreePosition(pv.getLatDeg() - ((hPoints-1)/2.-j)/(hPoints-1)*nHor[0]*xscale*lscVrt, pv.getLngDeg() - ((hPoints-1)/2.-j)/(hPoints-1)*nHor[1]*xscale*lscVrt);
|
||||
//System.out.print(""+grid[i][j]+"("+((hPoints-1)/2.-j)+"), ");
|
||||
while (j < hPoints / 2) {
|
||||
grid[i][j] = new DegreePosition(pv.getLatDeg() - ((hPoints - 1) / 2. - j) / (hPoints - 1) * nHor[0]
|
||||
* xscale * lscVrt, pv.getLngDeg() - ((hPoints - 1) / 2. - j) / (hPoints - 1) * nHor[1] * xscale
|
||||
* lscVrt);
|
||||
// System.out.print(""+grid[i][j]+"("+((hPoints-1)/2.-j)+"), ");
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
// middle
|
||||
if (hPoints%2 == 1) {
|
||||
if (hPoints % 2 == 1) {
|
||||
grid[i][j] = pv;
|
||||
//System.out.print(""+grid[i][j]+", ");
|
||||
// System.out.print(""+grid[i][j]+", ");
|
||||
j++;
|
||||
}
|
||||
|
||||
// right side
|
||||
while (j < hPoints) {
|
||||
grid[i][j] = new DegreePosition(pv.getLatDeg() + (j-(hPoints-1)/2.)/(hPoints-1)*nHor[0]*xscale*lscVrt, pv.getLngDeg() + (j-(hPoints-1)/2.)/(hPoints-1)*nHor[1]*xscale*lscVrt);
|
||||
//System.out.print(""+grid[i][j]+"("+(j-(hPoints-1)/2.)+"), ");
|
||||
grid[i][j] = new DegreePosition(pv.getLatDeg() + (j - (hPoints - 1) / 2.) / (hPoints - 1) * nHor[0]
|
||||
* xscale * lscVrt, pv.getLngDeg() + (j - (hPoints - 1) / 2.) / (hPoints - 1) * nHor[1] * xscale
|
||||
* lscVrt);
|
||||
// System.out.print(""+grid[i][j]+"("+(j-(hPoints-1)/2.)+"), ");
|
||||
j++;
|
||||
}
|
||||
//System.out.println();
|
||||
}
|
||||
// System.out.println();
|
||||
}
|
||||
|
||||
/*System.out.println("Grid Index Test:");
|
||||
for (int i =0; i<vPoints; i++) {
|
||||
for (int j=0; j<hPoints; j++) {
|
||||
System.out.print(""+this.getGridIndex(grid[i][j])+", ");
|
||||
}
|
||||
System.out.println();
|
||||
}*/
|
||||
/*
|
||||
* System.out.println("Grid Index Test:"); for (int i =0; i<vPoints; i++) { for (int j=0; j<hPoints; j++) {
|
||||
* System.out.print(""+this.getGridIndex(grid[i][j])+", "); } System.out.println(); }
|
||||
*/
|
||||
return grid;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Pair<Integer,Integer> getGridIndex(Position x) {
|
||||
public Pair<Integer, Integer> getGridIndex(Position x) {
|
||||
|
||||
double[] scX = new double[2];
|
||||
scX[0] = x.getLatDeg()-rcStart.getLatDeg();
|
||||
scX[1] = (x.getLngDeg()-rcStart.getLngDeg())*lngScale;
|
||||
scX[0] = x.getLatDeg() - rcStart.getLatDeg();
|
||||
scX[1] = (x.getLngDeg() - rcStart.getLngDeg()) * lngScale;
|
||||
|
||||
double sPrd = scX[0]*nvHor[0]+scX[1]*nvHor[1];
|
||||
double sPrd = scX[0] * nvHor[0] + scX[1] * nvHor[1];
|
||||
|
||||
int vIdx = Math.min(Math.max(0, (int) Math.round(scX[0]*nvVrt[0]+scX[1]*nvVrt[1])), vPoints-1);
|
||||
int hIdx = Math.min(Math.max(0, (int) Math.round(sPrd+(hPoints-1)/2.)), hPoints-1);
|
||||
int vIdx = Math.min(Math.max(0, (int) Math.round(scX[0] * nvVrt[0] + scX[1] * nvVrt[1])), vPoints - 1);
|
||||
int hIdx = Math.min(Math.max(0, (int) Math.round(sPrd + (hPoints - 1) / 2.)), hPoints - 1);
|
||||
|
||||
//System.out.println("getGridIndex: "+vIdx+","+hIdx+"("+vPoints+","+hPoints+")");
|
||||
return new Pair<Integer, Integer>(vIdx,hIdx);
|
||||
// System.out.println("getGridIndex: "+vIdx+","+hIdx+"("+vPoints+","+hPoints+")");
|
||||
return new Pair<Integer, Integer>(vIdx, hIdx);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* @Override
|
||||
public List<Position> extractLattice(int hPoints, int vPoints) {
|
||||
|
||||
Position[][] grid = extractGrid(hPoints, vPoints);
|
||||
List<Position> lst = new ArrayList<Position>();
|
||||
for(Position[] line : grid) {
|
||||
for(Position p : line) {
|
||||
lst.add(p);
|
||||
}
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
@Override
|
||||
//may not return a rectangular lattice!
|
||||
public List<Position> extractLattice(Distance hStep, Distance vStep) {
|
||||
|
||||
Position startPoint = appSouthWest;
|
||||
|
||||
Bearing vBearing = getNorth();
|
||||
Bearing hBearing = getEast();
|
||||
boolean hMode = true;
|
||||
|
||||
List<Position> lst = new ArrayList<Position>();
|
||||
|
||||
Position current = startPoint;
|
||||
lst.add(current);
|
||||
Position next;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (hMode) next = current.translateGreatCircle(hBearing, hStep);
|
||||
else next = current.translateGreatCircle(vBearing, vStep);
|
||||
|
||||
if (isWithinBoundaries(next)) {
|
||||
current = next;
|
||||
lst.add(current);
|
||||
if (!hMode) {
|
||||
hMode = true;
|
||||
hBearing = hBearing.reverse();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(hMode) hMode = false;
|
||||
else break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return lst;
|
||||
}
|
||||
/*
|
||||
* @Override public List<Position> extractLattice(int hPoints, int vPoints) {
|
||||
*
|
||||
* Position[][] grid = extractGrid(hPoints, vPoints); List<Position> lst = new ArrayList<Position>(); for(Position[]
|
||||
* line : grid) { for(Position p : line) { lst.add(p); } } return lst; }
|
||||
*
|
||||
* @Override //may not return a rectangular lattice! public List<Position> extractLattice(Distance hStep, Distance
|
||||
* vStep) {
|
||||
*
|
||||
* Position startPoint = appSouthWest;
|
||||
*
|
||||
* Bearing vBearing = getNorth(); Bearing hBearing = getEast(); boolean hMode = true;
|
||||
*
|
||||
* List<Position> lst = new ArrayList<Position>();
|
||||
*
|
||||
* Position current = startPoint; lst.add(current); Position next;
|
||||
*
|
||||
* while (true) {
|
||||
*
|
||||
* if (hMode) next = current.translateGreatCircle(hBearing, hStep); else next =
|
||||
* current.translateGreatCircle(vBearing, vStep);
|
||||
*
|
||||
* if (isWithinBoundaries(next)) { current = next; lst.add(current); if (!hMode) { hMode = true; hBearing =
|
||||
* hBearing.reverse(); } } else { if(hMode) hMode = false; else break; }
|
||||
*
|
||||
* }
|
||||
*
|
||||
* return lst; }
|
||||
*/
|
||||
|
||||
@Override
|
||||
@@ -317,14 +293,15 @@ public class RectangularBoundary implements Boundary {
|
||||
|
||||
@Override
|
||||
public Map<String, Double> getRelativeCoordinates(Position p) {
|
||||
if (!isWithinBoundaries(p)) return null;
|
||||
if (!isWithinBoundaries(p))
|
||||
return null;
|
||||
|
||||
Map<String,Double> map = new HashMap<String,Double>();
|
||||
Map<String, Double> map = new HashMap<String, Double>();
|
||||
Position px = p.projectToLineThrough(appSouthWest, getEast());
|
||||
Position py = p.projectToLineThrough(appSouthWest, getNorth());
|
||||
|
||||
map.put("X", px.getDistance(appSouthWest).getMeters()/getWidth().getMeters());
|
||||
map.put("Y", py.getDistance(appSouthWest).getMeters()/getHeight().getMeters());
|
||||
map.put("X", px.getDistance(appSouthWest).getMeters() / getWidth().getMeters());
|
||||
map.put("Y", py.getDistance(appSouthWest).getMeters() / getHeight().getMeters());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
+66
-1037
File diff suppressed because it is too large.
Load diff
+25
-38
@@ -1,9 +1,7 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.KilometersPerHourSpeedWithBearingImpl;
|
||||
@@ -25,7 +23,7 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
protected WindControlParameters windParameters;
|
||||
protected Position[][] positions;
|
||||
protected Map<Pair<Integer, Integer>, Position> indexPositionMap;
|
||||
|
||||
|
||||
protected Map<TimePoint, SpeedWithBearing[][]> timeSpeedWithBearingMap;
|
||||
|
||||
protected TimePoint startTime;
|
||||
@@ -34,28 +32,18 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
* TimePoint which constitutes one unit of time
|
||||
*/
|
||||
protected TimePoint timeStep;
|
||||
|
||||
private class LatLngComparator implements Comparator<Position> {
|
||||
|
||||
@Override
|
||||
public int compare(Position p1, Position p2) {
|
||||
|
||||
if (p1.getLatDeg() < p2.getLatDeg()) {
|
||||
return -1;
|
||||
} else if (p1.getLatDeg() == p2.getLngDeg()) {
|
||||
if (p1.getLngDeg() < p2.getLngDeg()) {
|
||||
return -1;
|
||||
} else if (p1.getLngDeg() == p2.getLngDeg()) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* private class LatLngComparator implements Comparator<Position> {
|
||||
*
|
||||
* @Override public int compare(Position p1, Position p2) {
|
||||
*
|
||||
* if (p1.getLatDeg() < p2.getLatDeg()) { return -1; } else if (p1.getLatDeg() == p2.getLngDeg()) { if
|
||||
* (p1.getLngDeg() < p2.getLngDeg()) { return -1; } else if (p1.getLngDeg() == p2.getLngDeg()) { return 0; } else {
|
||||
* return 1; } } else { return 1; } }
|
||||
*
|
||||
* }
|
||||
*/
|
||||
|
||||
public WindFieldGeneratorImpl(Boundary boundary, WindControlParameters windParameters) {
|
||||
this.boundary = boundary;
|
||||
@@ -97,11 +85,11 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
}
|
||||
for (int i = 0; i < positions.length; ++i) {
|
||||
for (int j = 0; j < positions[0].length; ++j) {
|
||||
Pair<Integer,Integer> index = new Pair<Integer, Integer>(i, j);
|
||||
Pair<Integer, Integer> index = new Pair<Integer, Integer>(i, j);
|
||||
indexPositionMap.put(index, positions[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Position getPosition(int i, int j) {
|
||||
@@ -109,46 +97,45 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
return indexPositionMap.get(indexKey);
|
||||
|
||||
}
|
||||
|
||||
public Pair<Integer,Integer> getPositionIndex(Position p) {
|
||||
Pair<Integer,Integer> gIdx = boundary.getGridIndex(p);
|
||||
if ((gIdx.getA()!=null)&&(gIdx.getB()!=null)) {
|
||||
|
||||
public Pair<Integer, Integer> getPositionIndex(Position p) {
|
||||
Pair<Integer, Integer> gIdx = boundary.getGridIndex(p);
|
||||
if ((gIdx.getA() != null) && (gIdx.getB() != null)) {
|
||||
return gIdx;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param t
|
||||
* @return time units relative to the startTime where each unit is timeStep long
|
||||
*/
|
||||
public int getTimeIndex(TimePoint t) {
|
||||
return (int) ((t.asMillis()-startTime.asMillis())/timeStep.asMillis());
|
||||
return (int) ((t.asMillis() - startTime.asMillis()) / timeStep.asMillis());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void generate(TimePoint start, TimePoint end, TimePoint step) {
|
||||
this.startTime = start;
|
||||
this.endTime = end;
|
||||
this.timeStep = step;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TimePoint getStartTime() {
|
||||
return this.startTime;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TimePoint getTimeStep() {
|
||||
return this.timeStep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public TimePoint getEndTime() {
|
||||
return this.endTime;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user