implemented extendet optimumDirectionUpwind and optimumDirectionDownwind

functions for the nonconstant target direction case
This commit is contained in:
Alexandru Dimofte committed 2012-07-29 17:21:23 +03:00
1 parent bad1dbaaf1
commit 49b4ed2011
2 files changed
+171 -67

No files matched your search

@@ -120,6 +120,17 @@ public class PolarDiagram49Test {
}
fw.write(xLine + "\n");
fw.write(yLine + "\n");
polarDiagram.setTargetDirection(new DegreeBearingImpl(10.0));
xLine = "";
yLine = "";
for (Bearing b : polarDiagram.optimalDirectionsUpwind()) {
xLine += "," + polarDiagram.getSpeedAtBearing(b).getKnots() * Math.cos(Math.PI/2 - b.getRadians());
yLine += "," + polarDiagram.getSpeedAtBearing(b).getKnots() * Math.sin(Math.PI/2 - b.getRadians());
}
fw.write(xLine + "\n");
fw.write(yLine + "\n");
}
fw.close();
@@ -8,6 +8,7 @@ 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;
@@ -20,7 +21,12 @@ import com.sap.sailing.domain.common.impl.RadianBearingImpl;
public class PolarDiagram49 implements PolarDiagram {
private SpeedWithBearing wind;
//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);
private NavigableMap<Speed, NavigableMap<Bearing, Speed>> speedTable;
private NavigableMap<Speed, Bearing> beatAngles;
@@ -28,8 +34,7 @@ public class PolarDiagram49 implements PolarDiagram {
private NavigableMap<Speed, Speed> beatSOG;
private NavigableMap<Speed, Speed> gybeSOG;
//private static boolean initialized = false;
//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;
@@ -178,9 +183,20 @@ public class PolarDiagram49 implements PolarDiagram {
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) {
@@ -279,73 +295,150 @@ public class PolarDiagram49 implements PolarDiagram {
@Override
public Bearing[] optimalDirectionsUpwind() {
Bearing windBearing = wind.getBearing().reverse();
Bearing floorBeatAngle;
if (beatAngles.floorEntry(wind) == null) {
floorBeatAngle = beatAngles.ceilingEntry(wind).getValue();
} else {
floorBeatAngle = beatAngles.floorEntry(wind).getValue();
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) };
}
Bearing ceilingBeatAngle;
if (beatAngles.ceilingEntry(wind) == null) {
ceilingBeatAngle = beatAngles.floorEntry(wind).getValue();
} else {
ceilingBeatAngle = beatAngles.ceilingEntry(wind).getValue();
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 };
}
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());
}
Bearing estBeatAngleRight = new RadianBearingImpl(+beatAngle);
Bearing estBeatAngleLeft = new RadianBearingImpl(-beatAngle);
return new Bearing[] {
// windBearing.add(estBeatAngle),
// windBearing.add(estBeatAngle.getDifferenceTo(windBearing))
windBearing.add(estBeatAngleLeft), windBearing.add(estBeatAngleRight) };
}
@Override
public Bearing[] optimalDirectionsDownwind() {
// TODO
Bearing windBearing = wind.getBearing().reverse();
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 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 };
}
Bearing estGybeAngle = new RadianBearingImpl(gybeAngle);
return new Bearing[] { windBearing.add(estGybeAngle),
windBearing.add(estGybeAngle.getDifferenceTo(windBearing)) };
}
//a Bearing Comparator useful in the creation of sorted sets of Bearing
public static Comparator<Bearing> bearingComparator = new Comparator<Bearing>() {
@Override
@@ -381,6 +474,8 @@ public class PolarDiagram49 implements PolarDiagram {
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) {
@@ -389,13 +484,13 @@ public class PolarDiagram49 implements PolarDiagram {
Set<Bearing> extraBearings = new HashSet<Bearing>();
for (Speed s : speedTable.keySet()) {
setWind(new KnotSpeedWithBearingImpl(s.getKnots(), new DegreeBearingImpl(180)));
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(180)));
setWind(new KnotSpeedWithBearingImpl(s.getKnots(), new DegreeBearingImpl(135)));
NavigableMap<Bearing, Speed> currentTable = new TreeMap<Bearing, Speed>(bearingComparator);
table.put(s, currentTable);
@@ -412,14 +507,12 @@ public class PolarDiagram49 implements PolarDiagram {
@Override
public Bearing getTargetDirection() {
// TODO Auto-generated method stub
return null;
return targetDirection;
}
@Override
public void setTargetDirection(Bearing newTargetDirection) {
// TODO Auto-generated method stub
targetDirection = newTargetDirection;
}
}