mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-17 01:31:01 +00:00
implemented extendet optimumDirectionUpwind and optimumDirectionDownwind
functions for the nonconstant target direction case
This commit is contained in:
1 parent
bad1dbaaf1
commit
49b4ed2011
2 files changed
+171
-67
No files matched your search
+11
@@ -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();
|
||||
|
||||
+160
-67
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user