mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-08 05:11:04 +00:00
Merge branch 'origin/simulator_maps_v3'
This commit is contained in:
commit
11ec71c0a3
31 files changed
+819
-2155
No files matched your search
+7
-8
@@ -55,6 +55,7 @@ import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternDisplayManager;
|
||||
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternNotFoundException;
|
||||
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternSetting;
|
||||
import com.sap.sailing.simulator.BoatClassProperties;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SailingSimulator;
|
||||
@@ -62,11 +63,11 @@ import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
import com.sap.sailing.simulator.impl.ConfigurationManager;
|
||||
import com.sap.sailing.simulator.impl.CurvedGrid;
|
||||
import com.sap.sailing.simulator.impl.PathGenerator1Turner;
|
||||
import com.sap.sailing.simulator.impl.PathImpl;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagramCSV;
|
||||
import com.sap.sailing.simulator.impl.ReadingConfigurationFileStatus;
|
||||
import com.sap.sailing.simulator.impl.RectangularBoundary;
|
||||
import com.sap.sailing.simulator.impl.SailingSimulatorImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
|
||||
import com.sap.sailing.simulator.impl.TimedPositionImpl;
|
||||
@@ -185,9 +186,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
course.add(nw);
|
||||
course.add(se);
|
||||
|
||||
RectangularBoundary bd = new RectangularBoundary(nw, se, 0.1);
|
||||
// List<Position> lattice = bd.extractLattice(params.getxRes(),
|
||||
// params.getyRes());
|
||||
Grid bd = new CurvedGrid(nw, se);
|
||||
|
||||
controlParameters.resetBlastRandomStream = params.isKeepState();
|
||||
retreiveWindControlParameters(pattern);
|
||||
@@ -201,7 +200,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
throw new WindPatternNotFoundException("Please select a valid wind pattern.");
|
||||
}
|
||||
|
||||
Position[][] grid = bd.extractGrid(params.getxRes(), params.getyRes(), params.getBorderY(), params.getBorderX());
|
||||
Position[][] grid = bd.generatePositions(params.getxRes(), params.getyRes(), params.getBorderY(), params.getBorderX());
|
||||
wf.setPositionGrid(grid);
|
||||
|
||||
TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime());
|
||||
@@ -549,9 +548,9 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
|
||||
SailingSimulator sailingSimulator = new SailingSimulatorImpl(simulationParameters);
|
||||
Path gpsWind = sailingSimulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
|
||||
|
||||
RectangularBoundary rectangularBoundry = new RectangularBoundary(oldMovedPosition, newMovedPosition, 0.1);
|
||||
this.controlParameters.baseWindBearing += rectangularBoundry.getSouth().getDegrees();
|
||||
WindFieldGeneratorMeasured windFieldGenerator = new WindFieldGeneratorMeasured(rectangularBoundry, this.controlParameters);
|
||||
Grid grid = new CurvedGrid(oldMovedPosition, newMovedPosition);
|
||||
this.controlParameters.baseWindBearing += grid.getSouth().getDegrees();
|
||||
WindFieldGeneratorMeasured windFieldGenerator = new WindFieldGeneratorMeasured(grid, this.controlParameters);
|
||||
windFieldGenerator.setGPSWind(gpsWind);
|
||||
|
||||
TimePoint startTime = new MillisecondsTimePoint(requestData.oldMovedPointTimePoint);
|
||||
|
||||
+4
-4
@@ -6,8 +6,8 @@ import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.impl.RectangularBoundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.impl.RectangularGrid;
|
||||
|
||||
public class RectangularBoundaryTest {
|
||||
|
||||
@@ -16,8 +16,8 @@ public class RectangularBoundaryTest {
|
||||
Position p1 = new DegreePosition(25.661333, -90.752563);
|
||||
Position p2 = new DegreePosition(24.522137, -90.774536);
|
||||
|
||||
Boundary b = new RectangularBoundary(p1, p2, 0.1);
|
||||
Position[][] grid = b.extractGrid(20,20,0,0);
|
||||
Grid b = new RectangularGrid(p1, p2);
|
||||
Position[][] grid = b.generatePositions(20,20,0,0);
|
||||
assertEquals("Number of lattice points",400,grid.length*grid[0].length);
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -20,7 +20,7 @@ import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagram49STG;
|
||||
import com.sap.sailing.simulator.impl.RectangularBoundary;
|
||||
import com.sap.sailing.simulator.impl.RectangularGrid;
|
||||
import com.sap.sailing.simulator.impl.SailingSimulatorImpl;
|
||||
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
|
||||
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
|
||||
@@ -43,8 +43,8 @@ public class SimulatorTest {
|
||||
course.add(end);
|
||||
PolarDiagram pd = new PolarDiagram49STG();//PolarDiagram49.CreateStandard49();
|
||||
|
||||
RectangularBoundary bd = new RectangularBoundary(start, end, 0.1);
|
||||
Position[][] positions = bd.extractGrid(10, 10, 0, 0);
|
||||
RectangularGrid bd = new RectangularGrid(start, end);
|
||||
Position[][] positions = bd.generatePositions(10, 10, 0, 0);
|
||||
Bearing windBear = end.getBearingGreatCircle(start);
|
||||
WindControlParameters windParameters = new WindControlParameters(12.0, windBear.getDegrees());
|
||||
WindFieldGenerator wf = new WindFieldGeneratorBlastImpl(bd, windParameters);
|
||||
|
||||
+5
-5
@@ -20,9 +20,9 @@ import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.impl.PathGeneratorTreeGrowWind3;
|
||||
import com.sap.sailing.simulator.impl.PathGeneratorTreeGrowWind;
|
||||
import com.sap.sailing.simulator.impl.PolarDiagram49STG;
|
||||
import com.sap.sailing.simulator.impl.RectangularBoundary;
|
||||
import com.sap.sailing.simulator.impl.RectangularGrid;
|
||||
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
|
||||
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
|
||||
import com.sap.sailing.simulator.windfield.WindControlParameters;
|
||||
@@ -44,8 +44,8 @@ public class TreeGrowTest {
|
||||
course.add(start);
|
||||
course.add(end);
|
||||
PolarDiagram pd = new PolarDiagram49STG();//PolarDiagram49.CreateStandard49();
|
||||
RectangularBoundary bd = new RectangularBoundary(start, end, 0.1);
|
||||
Position[][] positions = bd.extractGrid(10, 10, 0, 0);
|
||||
RectangularGrid bd = new RectangularGrid(start, end);
|
||||
Position[][] positions = bd.generatePositions(10, 10, 0, 0);
|
||||
//RectangularBoundary new_bd = new RectangularBoundary(start, end, 0.1);
|
||||
//Speed knotSpeed = new KnotSpeedImpl(8);
|
||||
WindControlParameters windParameters = new WindControlParameters(12, start.getBearingGreatCircle(end).reverse().getDegrees());
|
||||
@@ -62,7 +62,7 @@ public class TreeGrowTest {
|
||||
param.setProperty("Djikstra.gridv[int]", 10.0);
|
||||
param.setProperty("Djikstra.gridh[int]", 100.0);*/
|
||||
|
||||
PathGeneratorTreeGrowWind3 treeGrow = new PathGeneratorTreeGrowWind3(param);
|
||||
PathGeneratorTreeGrowWind treeGrow = new PathGeneratorTreeGrowWind(param);
|
||||
|
||||
Path path = treeGrow.getPath();
|
||||
|
||||
|
||||
+8
-8
@@ -23,7 +23,7 @@ import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsDurationImpl;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.simulator.impl.RectangularBoundary;
|
||||
import com.sap.sailing.simulator.impl.RectangularGrid;
|
||||
import com.sap.sailing.simulator.impl.TimedPositionWithSpeedImpl;
|
||||
import com.sap.sailing.simulator.windfield.WindControlParameters;
|
||||
import com.sap.sailing.simulator.windfield.impl.WindFieldGeneratorBlastImpl;
|
||||
@@ -51,11 +51,11 @@ public class WindFieldGeneratorTest {
|
||||
course.add(end);
|
||||
|
||||
WindControlParameters windParameters = new WindControlParameters(3, 180);
|
||||
RectangularBoundary bd = new RectangularBoundary(start, end, 0.1);
|
||||
RectangularGrid bd = new RectangularGrid(start, end);
|
||||
WindFieldGeneratorImpl wf = new WindFieldGeneratorBlastImpl(bd, windParameters);
|
||||
int hSteps = 10;
|
||||
int vSteps = 5;
|
||||
Position[][] positions = bd.extractGrid(hSteps, vSteps, 0, 0);
|
||||
Position[][] positions = bd.generatePositions(hSteps, vSteps, 0, 0);
|
||||
assert (positions.length*positions[0].length == hSteps * vSteps);
|
||||
int index = 0;
|
||||
for (int i = 0; i < positions.length; ++i) {
|
||||
@@ -63,7 +63,7 @@ public class WindFieldGeneratorTest {
|
||||
logger.info("P" + ++index + ":" + positions[i][j]);
|
||||
}
|
||||
}
|
||||
wf.setPositionGrid(bd.extractGrid(hSteps, vSteps, 0, 0));
|
||||
wf.setPositionGrid(bd.generatePositions(hSteps, vSteps, 0, 0));
|
||||
Position[][] positionGrid = wf.getPositionGrid();
|
||||
assertNotNull("Position Grid is not null", positionGrid);
|
||||
assertEquals("Position Grid Number of Rows", vSteps, positionGrid.length);
|
||||
@@ -91,13 +91,13 @@ public class WindFieldGeneratorTest {
|
||||
windParameters.frequency = 0.375;
|
||||
windParameters.amplitude = 20.0;
|
||||
|
||||
RectangularBoundary bd = new RectangularBoundary(start, end, 0.1);
|
||||
RectangularGrid bd = new RectangularGrid(start, end);
|
||||
WindFieldGeneratorOscillationImpl wf = new WindFieldGeneratorOscillationImpl(bd, windParameters);
|
||||
|
||||
int hSteps = 30;
|
||||
int vSteps = 15;
|
||||
|
||||
wf.setPositionGrid(bd.extractGrid(hSteps, vSteps, 0, 0));
|
||||
wf.setPositionGrid(bd.generatePositions(hSteps, vSteps, 0, 0));
|
||||
Position[][] positionGrid = wf.getPositionGrid();
|
||||
TimePoint startTime = new MillisecondsTimePoint(0);
|
||||
Duration timeStep = new MillisecondsDurationImpl(30 * 1000);
|
||||
@@ -235,12 +235,12 @@ public class WindFieldGeneratorTest {
|
||||
windParameters.blastWindSpeed = 0.0;
|
||||
windParameters.blastWindSpeedVar = 0.0;
|
||||
|
||||
RectangularBoundary bd = new RectangularBoundary(start, end, 0.1);
|
||||
RectangularGrid bd = new RectangularGrid(start, end);
|
||||
WindFieldGeneratorCombined wf = new WindFieldGeneratorCombined(bd, windParameters);
|
||||
int hSteps = 30;
|
||||
int vSteps = 15;
|
||||
|
||||
wf.setPositionGrid(bd.extractGrid(hSteps, vSteps, 0, 0));
|
||||
wf.setPositionGrid(bd.generatePositions(hSteps, vSteps, 0, 0));
|
||||
Position[][] positionGrid = wf.getPositionGrid();
|
||||
TimePoint startTime = new MillisecondsTimePoint(0);
|
||||
Duration timeStep = new MillisecondsDurationImpl(30 * 1000);
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
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.impl.DegreeBearingImpl;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public interface Boundary extends Serializable {
|
||||
|
||||
static Bearing TRUENORTH = new DegreeBearingImpl(0);
|
||||
static Bearing TRUESOUTH = new DegreeBearingImpl(180);
|
||||
static Bearing TRUEEAST = new DegreeBearingImpl(90);
|
||||
static Bearing TRUEWEST = new DegreeBearingImpl(270);
|
||||
|
||||
double getTolerance();
|
||||
|
||||
Map<String, Position> getCorners();
|
||||
|
||||
boolean isWithinBoundaries(Position P);
|
||||
|
||||
//List<Position> extractLattice(int hPoints, int vPoints);
|
||||
Position[][] extractGrid(int hPoints, int vPoints, int borderY, int borderX);
|
||||
//List<Position> extractLattice(Distance hStep, Distance vstep);
|
||||
public Util.Pair<Integer,Integer> getGridIndex(Position x);
|
||||
|
||||
public int getResY();
|
||||
public int getResX();
|
||||
public int getBorderY();
|
||||
public int getBorderX();
|
||||
|
||||
Bearing getNorth();
|
||||
Bearing getSouth();
|
||||
Bearing getEast();
|
||||
Bearing getWest();
|
||||
|
||||
Distance getHeight();
|
||||
Distance getWidth();
|
||||
|
||||
Map<String,Double> getRelativeCoordinates(Position p);
|
||||
Position getRelativePoint(double x, double y);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.sap.sailing.simulator;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
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.impl.DegreeBearingImpl;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
* The Grid interface defines access to a set of GPS-positions which form a lattice of supporting positions for
|
||||
* representing a vectorfield or performing optimization.
|
||||
*
|
||||
* @author Christopher Ronnewinkel (D036654)
|
||||
*
|
||||
*/
|
||||
public interface Grid extends Serializable {
|
||||
|
||||
static Bearing relativeNorth = new DegreeBearingImpl(0);
|
||||
static Bearing relativeSouth = new DegreeBearingImpl(180);
|
||||
static Bearing relativeEast = new DegreeBearingImpl(90);
|
||||
static Bearing relativeWest = new DegreeBearingImpl(270);
|
||||
|
||||
Map<String, Position> getCorners();
|
||||
|
||||
boolean inBounds(Position P);
|
||||
|
||||
Position[][] generatePositions(int hPoints, int vPoints, int borderY, int borderX);
|
||||
|
||||
public Util.Pair<Integer, Integer> getIndex(Position x);
|
||||
|
||||
public int getResY();
|
||||
|
||||
public int getResX();
|
||||
|
||||
public int getBorderY();
|
||||
|
||||
public int getBorderX();
|
||||
|
||||
Bearing getNorth();
|
||||
|
||||
Bearing getSouth();
|
||||
|
||||
Bearing getEast();
|
||||
|
||||
Bearing getWest();
|
||||
|
||||
Distance getHeight();
|
||||
|
||||
Distance getWidth();
|
||||
|
||||
}
|
||||
+1
-1
@@ -18,7 +18,7 @@ public interface SimulationParameters {
|
||||
|
||||
WindFieldGenerator getWindField();
|
||||
|
||||
Boundary getBoundaries();
|
||||
Grid getGrid();
|
||||
|
||||
Map<String,Double> getSettings();
|
||||
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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.simulator.Grid;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
* Implements the {@link Grid} interface by providing a grid of GPS-positions based on great circles and the
|
||||
* corresponding index-calculation to associate an arbitrary GPS-position with the closest grid-GPS-position.
|
||||
*
|
||||
* Since the grid is constructed in spherical coordinates, we call it the curved grid. It stays perfectly symmetric no
|
||||
* matter along which bearing to North it is aligned with.
|
||||
*
|
||||
* @author Christopher Ronnewinkel (D036654)
|
||||
*
|
||||
*/
|
||||
public class CurvedGrid implements Grid {
|
||||
|
||||
private static final long serialVersionUID = 3598121983120213464L;
|
||||
private Position rcStart; // start position of race course
|
||||
private Position rcEnd; // end position of race course
|
||||
private int vPoints; // number of vertical steps
|
||||
private int hPoints; // number of horizontal steps
|
||||
private int borderY;
|
||||
private int borderX;
|
||||
|
||||
private Position gridNorthWest;
|
||||
private Position gridSouthEast;
|
||||
private Position gridSouthWest;
|
||||
private Position gridNorthEast;
|
||||
|
||||
private Bearing gridNorth;
|
||||
private Bearing gridSouth;
|
||||
private Bearing gridEast;
|
||||
private Bearing gridWest;
|
||||
|
||||
private Distance gridWidth;
|
||||
private double xscale = 1.5;
|
||||
private Distance gridHeight;
|
||||
|
||||
public CurvedGrid(Position p1, Position p2) {
|
||||
|
||||
rcStart = p1;
|
||||
rcEnd = p2;
|
||||
|
||||
gridNorth = p1.getBearingGreatCircle(p2);
|
||||
gridSouth = gridNorth.reverse();
|
||||
gridEast = gridNorth.add(relativeEast);
|
||||
gridWest = gridNorth.add(relativeWest);
|
||||
|
||||
gridHeight = p1.getDistance(p2);
|
||||
gridWidth = gridHeight.scale(2);
|
||||
|
||||
gridNorthWest = p2.translateGreatCircle(gridWest, gridHeight);
|
||||
gridNorthEast = p2.translateGreatCircle(gridEast, gridHeight);
|
||||
|
||||
gridSouthWest = p1.translateGreatCircle(gridWest, gridHeight);
|
||||
gridSouthEast = p1.translateGreatCircle(gridEast, gridHeight);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Position> getCorners() {
|
||||
|
||||
Map<String, Position> map = new HashMap<String, Position>();
|
||||
map.put("NorthWest", gridNorthWest);
|
||||
map.put("SouthWest", gridSouthWest);
|
||||
map.put("SouthEast", gridSouthEast);
|
||||
map.put("NorthEast", gridNorthEast);
|
||||
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inBounds(Position p) {
|
||||
|
||||
Position northProjection = p.projectToLineThrough(gridNorthWest, getEast());
|
||||
Position southProjection = p.projectToLineThrough(gridSouthWest, getEast());
|
||||
Position westProjection = p.projectToLineThrough(gridNorthWest, getNorth());
|
||||
Position eastProjection = p.projectToLineThrough(gridNorthEast, getNorth());
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position[][] generatePositions(int hPoints, int vPoints, int borderY, int borderX) {
|
||||
|
||||
this.vPoints = vPoints;
|
||||
this.hPoints = hPoints;
|
||||
|
||||
this.borderY = borderY;
|
||||
this.borderX = borderX;
|
||||
|
||||
Distance vStep = gridHeight.scale(1.0 / (vPoints - 1));
|
||||
Distance hStep = gridHeight.scale(xscale / (hPoints - 1));
|
||||
|
||||
Position[][] grid = new Position[vPoints + 2 * borderY][hPoints + 2 * borderX];
|
||||
Position pv;
|
||||
for (int i = -borderY; i < (vPoints + borderY); i++) {
|
||||
|
||||
if (i == 0) {
|
||||
pv = rcStart;
|
||||
} else if (i == vPoints - 1) {
|
||||
pv = rcEnd;
|
||||
} else {
|
||||
pv = rcStart.translateGreatCircle(gridNorth, vStep.scale(i));
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
// left side
|
||||
while (j < (hPoints + 2 * borderX) / 2) {
|
||||
grid[i + borderY][j] = pv.translateGreatCircle(gridWest,
|
||||
hStep.scale((hPoints + 2 * borderX - 1) / 2. - j));
|
||||
j++;
|
||||
}
|
||||
|
||||
// middle
|
||||
if ((hPoints + 2 * borderX) % 2 == 1) {
|
||||
grid[i + borderY][j] = pv;
|
||||
j++;
|
||||
}
|
||||
|
||||
// right side
|
||||
while (j < (hPoints + 2 * borderX)) {
|
||||
grid[i + borderY][j] = pv.translateGreatCircle(gridEast,
|
||||
hStep.scale(j - (hPoints + 2 * borderX - 1) / 2.));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
public Util.Pair<Integer, Integer> getIndex(Position x) {
|
||||
|
||||
double vFlt = 0;
|
||||
double hFlt = 0;
|
||||
|
||||
if (!x.equals(rcStart)) {
|
||||
Position h = x.projectToLineThrough(rcStart, gridNorth);
|
||||
vFlt = vPoints * rcStart.getDistance(h).getMeters() / gridHeight.getMeters();
|
||||
int sign = +1;
|
||||
if (Math.abs(h.getBearingGreatCircle(x).getDifferenceTo(gridWest).getDegrees()) < 90.0) {
|
||||
sign = -1;
|
||||
}
|
||||
hFlt = sign * (hPoints - 1) * x.getDistance(h).getMeters() / gridHeight.getMeters() / xscale;
|
||||
}
|
||||
|
||||
int vIdx = Math.min(Math.max(-this.borderY, (int) Math.round(vFlt) + this.borderY), vPoints - 1 + this.borderY);
|
||||
int hIdx = Math.min(Math.max(-this.borderX, (int) Math.round((hPoints - 1) / 2. + hFlt)), hPoints - 1 + this.borderX);
|
||||
|
||||
return new Util.Pair<Integer, Integer>(vIdx, hIdx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResY() {
|
||||
return this.vPoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResX() {
|
||||
return this.hPoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBorderY() {
|
||||
return this.borderY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBorderX() {
|
||||
return this.borderX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getNorth() {
|
||||
return gridNorth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getSouth() {
|
||||
return gridSouth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getEast() {
|
||||
return gridEast;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bearing getWest() {
|
||||
return gridWest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWidth() {
|
||||
return gridWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getHeight() {
|
||||
return gridHeight;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -25,14 +25,14 @@ public class PathCandidate implements Comparable<PathCandidate> {
|
||||
// sort descending by length, width, height
|
||||
public int compareTo(PathCandidate other) {
|
||||
if (this.path.length() == other.path.length()) {
|
||||
if (this.vrt == other.vrt) {
|
||||
if (this.trn == other.trn) {
|
||||
if (Math.abs(this.hrz) == Math.abs(other.hrz)) {
|
||||
return 0;
|
||||
} else {
|
||||
return (Math.abs(this.hrz) < Math.abs(other.hrz) ? -1 : +1);
|
||||
}
|
||||
} else {
|
||||
return (this.vrt > other.vrt ? -1 : +1);
|
||||
return (this.trn < other.trn ? -1 : +1);
|
||||
}
|
||||
} else {
|
||||
return (this.path.length() < other.path.length() ? -1 : +1);
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@ import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
@@ -26,7 +26,7 @@ public class PathGenerator1TurnerLeftDirect extends PathGeneratorBase {
|
||||
public Path getPath() {
|
||||
|
||||
// retrieve simulation parameters
|
||||
Boundary boundary = new RectangularBoundary(this.parameters.getCourse().get(0), this.parameters
|
||||
Grid boundary = new RectangularGrid(this.parameters.getCourse().get(0), this.parameters
|
||||
.getCourse().get(1));// simulationParameters.getBoundaries();
|
||||
WindFieldGenerator windField = this.parameters.getWindField();
|
||||
PolarDiagram polarDiagram = this.parameters.getBoatPolarDiagram();
|
||||
@@ -102,7 +102,7 @@ public class PathGenerator1TurnerLeftDirect extends PathGeneratorBase {
|
||||
// System.out.println("out of time");
|
||||
break;
|
||||
}
|
||||
if (!boundary.isWithinBoundaries(currentPosition)) {
|
||||
if (!boundary.inBounds(currentPosition)) {
|
||||
// outOfBounds = true;
|
||||
// System.out.println("out of bounds");
|
||||
break;
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@ import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
@@ -26,7 +26,7 @@ public class PathGenerator1TurnerRightDirect extends PathGeneratorBase {
|
||||
public Path getPath() {
|
||||
|
||||
// retrieve simulation parameters
|
||||
Boundary boundary = new RectangularBoundary(this.parameters.getCourse().get(0), this.parameters
|
||||
Grid boundary = new RectangularGrid(this.parameters.getCourse().get(0), this.parameters
|
||||
.getCourse().get(1));// simulationParameters.getBoundaries();
|
||||
WindFieldGenerator windField = this.parameters.getWindField();
|
||||
PolarDiagram polarDiagram = this.parameters.getBoatPolarDiagram();
|
||||
@@ -102,7 +102,7 @@ public class PathGenerator1TurnerRightDirect extends PathGeneratorBase {
|
||||
// System.out.println("out of time");
|
||||
break;
|
||||
}
|
||||
if (!boundary.isWithinBoundaries(currentPosition)) {
|
||||
if (!boundary.inBounds(currentPosition)) {
|
||||
// outOfBounds = true;
|
||||
// System.out.println("out of bounds");
|
||||
break;
|
||||
|
||||
+3
-3
@@ -14,7 +14,7 @@ import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
@@ -34,7 +34,7 @@ public class PathGeneratorDijkstra extends PathGeneratorBase {
|
||||
public Path getPath() {
|
||||
|
||||
// retrieve simulation parameters
|
||||
Boundary boundary = new RectangularBoundary(this.parameters.getCourse().get(0), this.parameters
|
||||
Grid boundary = new RectangularGrid(this.parameters.getCourse().get(0), this.parameters
|
||||
.getCourse().get(1));// simulationParameters.getBoundaries();
|
||||
WindFieldGenerator windField = this.parameters.getWindField();
|
||||
PolarDiagram polarDiagram = this.parameters.getBoatPolarDiagram();
|
||||
@@ -49,7 +49,7 @@ public class PathGeneratorDijkstra extends PathGeneratorBase {
|
||||
int gridv = this.parameters.getProperty("Djikstra.gridv[int]").intValue(); // number of vertical grid steps
|
||||
int gridh = this.parameters.getProperty("Djikstra.gridh[int]").intValue(); // number of horizontal grid
|
||||
// steps
|
||||
Position[][] sailGrid = boundary.extractGrid(gridh, gridv, 0, 0);
|
||||
Position[][] sailGrid = boundary.generatePositions(gridh, gridv, 0, 0);
|
||||
|
||||
// create adjacency graph including start and end
|
||||
Map<Position, List<Position>> graph = new HashMap<Position, List<Position>>();
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
@@ -130,7 +130,7 @@ public class PathGeneratorDynProgForward extends PathGeneratorBase {
|
||||
public Path getPath() {
|
||||
|
||||
// retrieve simulation parameters
|
||||
Boundary boundary = new RectangularBoundary(this.parameters.getCourse().get(0), this.parameters
|
||||
Grid boundary = new RectangularGrid(this.parameters.getCourse().get(0), this.parameters
|
||||
.getCourse().get(1));// simulationParameters.getBoundaries();
|
||||
WindFieldGenerator windField = this.parameters.getWindField();
|
||||
PolarDiagram polarDiagram = this.parameters.getBoatPolarDiagram();
|
||||
@@ -162,7 +162,7 @@ public class PathGeneratorDynProgForward extends PathGeneratorBase {
|
||||
}
|
||||
|
||||
// generate grid positions using sgridh and sgridv
|
||||
Position[][] sailGrid = boundary.extractGrid(spatialGridsizeHorizontal, spatialGridsizeVertical, 0, 0);
|
||||
Position[][] sailGrid = boundary.generatePositions(spatialGridsizeHorizontal, spatialGridsizeVertical, 0, 0);
|
||||
|
||||
// optimization grid indexes:
|
||||
// vertical steps: 0, ..., v-1
|
||||
|
||||
-421
@@ -1,421 +0,0 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
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.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
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.WindFieldGenerator;
|
||||
|
||||
public class PathGeneratorTreeGrowTarget extends PathGeneratorBase {
|
||||
|
||||
private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
|
||||
int maxLeft;
|
||||
int maxRight;
|
||||
boolean startLeft;
|
||||
|
||||
public PathGeneratorTreeGrowTarget(SimulationParameters params) {
|
||||
this.parameters = params;
|
||||
}
|
||||
|
||||
public void setEvaluationParameters(int maxLeftVal, int maxRightVal, boolean startLeftVal) {
|
||||
this.maxLeft = maxLeftVal;
|
||||
this.maxRight = maxRightVal;
|
||||
this.startLeft = startLeftVal;
|
||||
}
|
||||
|
||||
class PathCand implements Comparable<PathCand> {
|
||||
public PathCand(TimedPosition pos, double vrt, double hrz, String path) {
|
||||
this.pos = pos;
|
||||
this.vrt = vrt;
|
||||
this.hrz = hrz;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
TimedPosition pos;
|
||||
double vrt;
|
||||
double hrz;
|
||||
String path;
|
||||
|
||||
/*@Override
|
||||
// sort ascending by horizontal distance
|
||||
public int compareTo(PathCand other) {
|
||||
if (Math.abs(this.hrz) == Math.abs(other.hrz))
|
||||
return 0;
|
||||
return (Math.abs(this.hrz) < Math.abs(other.hrz) ? -1 : +1);
|
||||
}*/
|
||||
@Override
|
||||
// sort descending by height
|
||||
public int compareTo(PathCand other) {
|
||||
if (this.vrt == other.vrt) {
|
||||
if (Math.abs(this.hrz) == Math.abs(other.hrz)) {
|
||||
return 0;
|
||||
} else {
|
||||
return (Math.abs(this.hrz) < Math.abs(other.hrz) ? -1 : +1);
|
||||
}
|
||||
} else {
|
||||
return (this.vrt > other.vrt ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// generate step
|
||||
TimedPosition getStep(TimedPosition pos, long timeStep, long turnLoss, char prevDirection, char nextDirection) {
|
||||
|
||||
double offDeg = 5.0;
|
||||
WindFieldGenerator wf = this.parameters.getWindField();
|
||||
TimePoint curTime = pos.getTimePoint();
|
||||
Position curPosition = pos.getPosition();
|
||||
Wind posWind = wf.getWind(new TimedPositionWithSpeedImpl(curTime, curPosition, null));
|
||||
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
pd.setWind(posWind);
|
||||
|
||||
// get beat-angle left and right
|
||||
Bearing travelBearing = null;
|
||||
Bearing tmpBearing = null;
|
||||
if (nextDirection == 'L') {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[0];
|
||||
} else if (nextDirection == 'R') {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[1];
|
||||
} else if (nextDirection == 'M') {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[0];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(+offDeg));
|
||||
} else if (nextDirection == 'S') {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[1];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(-offDeg));
|
||||
}
|
||||
|
||||
// determine beat-speed left and right
|
||||
SpeedWithBearing travelSpeed = pd.getSpeedAtBearing(travelBearing);
|
||||
|
||||
TimePoint travelTime;
|
||||
TimePoint nextTime = new MillisecondsTimePoint(curTime.asMillis()+timeStep);
|
||||
char prevBaseDirection = prevDirection;
|
||||
if (prevBaseDirection == 'M') {
|
||||
prevBaseDirection = 'L';
|
||||
}
|
||||
if (prevBaseDirection == 'S') {
|
||||
prevBaseDirection = 'R';
|
||||
}
|
||||
char nextBaseDirection = nextDirection;
|
||||
if (nextBaseDirection == 'M') {
|
||||
nextBaseDirection = 'L';
|
||||
}
|
||||
if (nextBaseDirection == 'S') {
|
||||
nextBaseDirection = 'R';
|
||||
}
|
||||
boolean sameBaseDirection = (nextBaseDirection == prevBaseDirection)||(prevBaseDirection == '0');
|
||||
if (sameBaseDirection) {
|
||||
travelTime = nextTime;
|
||||
} else {
|
||||
travelTime = new MillisecondsTimePoint(nextTime.asMillis() - turnLoss);
|
||||
}
|
||||
|
||||
return new TimedPositionImpl(nextTime, travelSpeed.travelTo(curPosition, curTime, travelTime));
|
||||
}
|
||||
|
||||
PathCand getPathCand(PathCand path, char nextDirection, long timeStep, long turnLoss, Position posStart, Bearing bearVrt, double tgtHeight) {
|
||||
|
||||
// calculate next path position (taking turn-loss into account)
|
||||
TimedPosition pathPos = this.getStep(path.pos, timeStep, turnLoss, path.path.charAt(path.path.length()-1), nextDirection);
|
||||
|
||||
// calculate height-position with reference to race course
|
||||
Position posHeight = pathPos.getPosition().projectToLineThrough(posStart, bearVrt);
|
||||
|
||||
// calculate vertical distance as distance of height-position to start
|
||||
double vrtDist = Math.round(posHeight.getDistance(posStart).getMeters()*100.0)/100.0;
|
||||
/*if (vrtDist > tgtHeight) {
|
||||
// scale last step so that vrtDist ~ tgtHeight
|
||||
Position prevPos = path.pos.getPosition();
|
||||
TimePoint prevTime = path.pos.getTimePoint();
|
||||
double heightFrac = (tgtHeight - path.vrt) / (vrtDist - path.vrt);
|
||||
Position newPos = prevPos.translateGreatCircle(prevPos.getBearingGreatCircle(pathPos.getPosition()), prevPos.getDistance(pathPos.getPosition()).scale(heightFrac));
|
||||
TimePoint newTime = new MillisecondsTimePoint(Math.round(prevTime.asMillis() + (pathPos.getTimePoint().asMillis()-prevTime.asMillis())*heightFrac));
|
||||
pathPos = new TimedPositionImpl(newTime, newPos);
|
||||
posHeight = pathPos.getPosition().projectToLineThrough(posStart, bearVrt);
|
||||
}*/
|
||||
|
||||
// calculate horizontal side: left or right in reference to race course
|
||||
double posSide = 1;
|
||||
double posBear = posStart.getBearingGreatCircle(pathPos.getPosition()).getDegrees();
|
||||
if ((posBear < 0.0)||(posBear > 180.0)) {
|
||||
posSide = -1;
|
||||
} else if ((posBear == 0.0)||(posBear == 180.0)) {
|
||||
posSide = 0;
|
||||
}
|
||||
// calculate horizontal distance as distance of height-position to current position
|
||||
double hrzDist = Math.round(posSide*posHeight.getDistance(pathPos.getPosition()).getMeters()*100.0)/100.0;
|
||||
|
||||
//System.out.println(""+hrzDist+", "+vrtDist+", "+pathPos.getPosition().getLatDeg()+", "+pathPos.getPosition().getLngDeg()+", "+posHeight.getLatDeg()+", "+posHeight.getLngDeg());
|
||||
|
||||
// extend path-string by step-direction
|
||||
String pathStr = path.path + nextDirection;
|
||||
|
||||
return (new PathCand(pathPos, vrtDist, hrzDist, pathStr));
|
||||
}
|
||||
|
||||
// generate path candidates based on beat angles
|
||||
List<PathCand> getPathCandsBeat(PathCand path, long timeStep, long turnLoss, Position posStart, Bearing bearVrt, double tgtHeight) {
|
||||
|
||||
List<PathCand> result = new ArrayList<PathCand>();
|
||||
PathCand newPathCand;
|
||||
|
||||
// step left
|
||||
newPathCand = getPathCand(path, 'L', timeStep, turnLoss, posStart, bearVrt, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
|
||||
// step wide left
|
||||
newPathCand = getPathCand(path, 'M', timeStep, turnLoss, posStart, bearVrt, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
|
||||
// step right
|
||||
newPathCand = getPathCand(path, 'R', timeStep, turnLoss, posStart, bearVrt, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
|
||||
// step wide right
|
||||
newPathCand = getPathCand(path, 'S', timeStep, turnLoss, posStart, bearVrt, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
WindFieldGenerator wf = this.parameters.getWindField();
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
Position startPos = this.parameters.getCourse().get(0);
|
||||
Position endPos = this.parameters.getCourse().get(1);
|
||||
TimePoint startTime = wf.getStartTime();// new MillisecondsTimePoint(0);
|
||||
List<TimedPositionWithSpeed> path = new ArrayList<TimedPositionWithSpeed>();
|
||||
|
||||
Position currentPosition = startPos;
|
||||
TimePoint currentTime = startTime;
|
||||
|
||||
Distance distStartEnd = startPos.getDistance(endPos);
|
||||
double distStartEndMeters = distStartEnd.getMeters();
|
||||
|
||||
long timeStep = wf.getTimeStep().asMillis()/3;
|
||||
logger.info("Time step :" + timeStep);
|
||||
long turnLoss = pd.getTurnLoss(); // 4000; // time lost when doing a turn
|
||||
|
||||
Wind wndStart = wf.getWind(new TimedPositionWithSpeedImpl(startTime, startPos, null));
|
||||
logger.fine("wndStart speed:" + wndStart.getKnots() + " angle:" + wndStart.getBearing().getDegrees());
|
||||
pd.setWind(wndStart);
|
||||
Bearing bearVrt = startPos.getBearingGreatCircle(endPos);
|
||||
//Bearing bearHrz = bearVrt.add(new DegreeBearingImpl(90.0));
|
||||
Position middlePos = startPos.translateGreatCircle(bearVrt, distStartEnd.scale(0.5));
|
||||
|
||||
System.out.println("start : "+startPos.getLatDeg()+", "+startPos.getLngDeg());
|
||||
System.out.println("middle: "+middlePos.getLatDeg()+", "+middlePos.getLngDeg());
|
||||
System.out.println("end : "+endPos.getLatDeg()+", "+endPos.getLngDeg());
|
||||
|
||||
// initialize list of paths
|
||||
PathCand initPath = new PathCand(new TimedPositionImpl(currentTime, currentPosition), 0.0, 0.0, "0");
|
||||
String initPathStr = "0";
|
||||
//String initPathStr = "0RRRRRRRRRRRRRRRLLL";
|
||||
//String initPathStr = "0RRRRRRRRRRRRRRRRRR";
|
||||
//PathCand initPath = new PathCand(new TimedPositionImpl(currentTime, currentPosition), 0.0, 0.0, ); //"0RRRRRRRRRRRRRRR");
|
||||
if (initPathStr.length()>1) {
|
||||
//char prevDirection = '0';
|
||||
char nextDirection = '0';
|
||||
for(int idx=1; idx<initPathStr.length(); idx++) {
|
||||
nextDirection = initPathStr.charAt(idx);
|
||||
//TimedPosition newPosition = this.getStep(initPath.pos, timeStep, turnLoss, prevDirection, nextDirection);
|
||||
//initPath.pos = newPosition;
|
||||
PathCand newPathCand = getPathCand(initPath, nextDirection, timeStep, turnLoss, startPos, bearVrt, distStartEndMeters);
|
||||
initPath = newPathCand;
|
||||
//prevDirection = nextDirection;
|
||||
}
|
||||
}
|
||||
List<PathCand> allPaths = new ArrayList<PathCand>();
|
||||
List<PathCand> trgPaths = new ArrayList<PathCand>();
|
||||
allPaths.add(initPath);
|
||||
|
||||
|
||||
TimedPosition tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, '0', 'L');
|
||||
double tstDist1 = startPos.getDistance(tstPosition.getPosition()).getMeters();
|
||||
tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, '0', 'R');
|
||||
double tstDist2 = startPos.getDistance(tstPosition.getPosition()).getMeters();
|
||||
|
||||
double hrzBinSize = (tstDist1 + tstDist2)/3; // horizontal bin size in meters
|
||||
System.out.println("Horizontal Bin Size: "+hrzBinSize);
|
||||
|
||||
double oobFact = 0.75; // out-of-bounds factor
|
||||
//int hrzLeft = (int)Math.round(Math.floor( -distStartEndMeters / 2.0 / hrzBinSize / oobFact ));
|
||||
//int hrzRight = (int)Math.round(Math.floor( distStartEndMeters / 2.0 / hrzBinSize / oobFact ));
|
||||
|
||||
boolean reachedEnd = false;
|
||||
int addSteps = 0;
|
||||
int finalSteps = 0; // maximum number of additional steps after first target-path found
|
||||
//for(int count=0; count<10; count++) {
|
||||
while ((!reachedEnd)||(addSteps<finalSteps)) {
|
||||
|
||||
if (reachedEnd) {
|
||||
addSteps++;
|
||||
}
|
||||
|
||||
// generate new paths
|
||||
double hrzMin = 0;
|
||||
double hrzMax = 0;
|
||||
List<PathCand> newPathCands;
|
||||
List<PathCand> newPaths = new ArrayList<PathCand>();
|
||||
for(PathCand curPath : allPaths) {
|
||||
|
||||
if ((curPath.vrt > distStartEndMeters)) {
|
||||
continue;
|
||||
} else {
|
||||
newPathCands = this.getPathCandsBeat(curPath, timeStep, turnLoss, startPos, bearVrt, distStartEndMeters);
|
||||
}
|
||||
|
||||
for(PathCand newPath : newPathCands) {
|
||||
|
||||
newPaths.add(newPath);
|
||||
if (newPath.hrz < hrzMin) {
|
||||
hrzMin = newPath.hrz;
|
||||
}
|
||||
if (newPath.hrz > hrzMax) {
|
||||
hrzMax = newPath.hrz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int hrzLeft = (int)Math.round(Math.floor( (hrzMin + hrzBinSize/2.0) / hrzBinSize ));
|
||||
int hrzRight = (int)Math.round(Math.floor( (hrzMax + hrzBinSize/2.0) / hrzBinSize ));
|
||||
//System.out.println("hrzLeft: "+hrzLeft+", hrzRight: "+hrzRight);
|
||||
|
||||
// build map of best path per hrz-bin
|
||||
int countPath = 0;
|
||||
int mapSize = hrzRight-hrzLeft+1;
|
||||
//System.out.println("MapSize: "+mapSize);
|
||||
|
||||
int[] binIdx = new int[mapSize]; // TODO: init with zero?
|
||||
double[] binVal = new double[mapSize]; // TODO: init with zero?
|
||||
for(int curIdx=0; curIdx<newPaths.size(); curIdx++) {
|
||||
PathCand curPath = newPaths.get(curIdx);
|
||||
|
||||
// check whether path is *outside* regatta-area
|
||||
double distFromMiddleMeters = middlePos.getDistance(curPath.pos.getPosition()).getMeters();
|
||||
if (distFromMiddleMeters > oobFact*distStartEndMeters) {
|
||||
continue; // ignore curPath
|
||||
}
|
||||
|
||||
// increase path-counter
|
||||
countPath++;
|
||||
|
||||
// determine map-key
|
||||
int curKey = (int)Math.round(Math.floor( (curPath.hrz + hrzBinSize/2.0) / hrzBinSize )) - hrzLeft;
|
||||
|
||||
/*String allR = "0" + (new String(new char[curPath.path.length()-1]).replace('\0', 'R'));
|
||||
if (curPath.path.equals(allR)) {
|
||||
System.out.println(""+curPath.path+": "+curPath.hrz+", "+curPath.vrt+", "+curPath.pos.getPosition().getLatDeg()+", "+curPath.pos.getPosition().getLngDeg());
|
||||
}*/
|
||||
|
||||
// check whether curPath is better then the ones looked at
|
||||
if ((curKey>=0)&&(curKey < mapSize)) {
|
||||
if (curPath.vrt > binVal[curKey]) {
|
||||
binVal[curKey] = curPath.vrt;
|
||||
binIdx[curKey] = curIdx+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if there are still paths inside regatta-area
|
||||
if (countPath > 0) {
|
||||
// take best from each horizontal-bin and check if target is reached
|
||||
allPaths = new ArrayList<PathCand>();
|
||||
for (int curKey = 0; curKey < mapSize; curKey++) {
|
||||
|
||||
if (binIdx[curKey] > 0) {
|
||||
PathCand curPath = newPaths.get(binIdx[curKey] - 1);
|
||||
allPaths.add(curPath);
|
||||
|
||||
// debug output
|
||||
/*if ((Math.abs(curKey + hrzLeft) <= 3)) {
|
||||
System.out.println("" + curPath.path + ": " + (curKey + hrzLeft) + ", vrt:" + curPath.vrt + ", hrz:" + curPath.hrz + ", bin:" + (Math.floor((curPath.hrz + hrzBinSize / 2.0) / hrzBinSize)));
|
||||
}*/
|
||||
|
||||
// terminate path-search if paths close enough to target are found
|
||||
if ((curPath.vrt > distStartEndMeters)) {
|
||||
if ((Math.abs(curKey + hrzLeft) <= 2)) {
|
||||
reachedEnd = true;
|
||||
trgPaths.add(curPath); // add path to list of target-paths
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// terminate path-search as no path inside regatta-area are left
|
||||
reachedEnd = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if no target-paths were found, return empty path
|
||||
if (trgPaths.size() == 0) {
|
||||
//trgPaths = allPaths; // TODO: only for testing; remove lateron
|
||||
return new PathImpl(path, wf); // return empty path
|
||||
}
|
||||
|
||||
// sort target-paths ascending by distance-to-target
|
||||
Collections.sort(trgPaths);
|
||||
|
||||
// debug output
|
||||
for(PathCand curPath : trgPaths) {
|
||||
System.out.print(""+curPath.path+": "+curPath.pos.getTimePoint().asMillis()+", "+curPath.pos.getPosition().getLatDeg()+", "+curPath.pos.getPosition().getLngDeg()+", ");
|
||||
System.out.println(" height:"+curPath.vrt+" of "+startPos.getDistance(endPos).getMeters()+", dist:"+curPath.hrz+" ~ "+curPath.pos.getPosition().getDistance(endPos));
|
||||
}
|
||||
|
||||
//
|
||||
// fill gwt-path
|
||||
//
|
||||
|
||||
// generate intermediate steps
|
||||
PathCand bstPath = trgPaths.get(0); // target-path ending closest to target
|
||||
TimedPositionWithSpeed curPosition = null;
|
||||
char nextDirection = '0';
|
||||
char prevDirection = '0';
|
||||
for(int step=0; step<(bstPath.path.length()-1); step++) {
|
||||
|
||||
nextDirection = bstPath.path.charAt(step);
|
||||
|
||||
if (nextDirection == '0') {
|
||||
|
||||
curPosition = new TimedPositionWithSpeedImpl(startTime, startPos, null);
|
||||
path.add(curPosition);
|
||||
|
||||
} else {
|
||||
|
||||
TimedPosition newPosition = this.getStep(curPosition, timeStep, turnLoss, prevDirection, nextDirection);
|
||||
curPosition = new TimedPositionWithSpeedImpl(newPosition.getTimePoint(), newPosition.getPosition(), null);
|
||||
path.add(curPosition);
|
||||
|
||||
}
|
||||
|
||||
prevDirection = nextDirection;
|
||||
}
|
||||
|
||||
// add final position (rescaled before to end on height of target)
|
||||
path.add(new TimedPositionWithSpeedImpl(bstPath.pos.getTimePoint(), bstPath.pos.getPosition(), null));
|
||||
|
||||
return new PathImpl(path, wf);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+420
-164
@@ -1,7 +1,11 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -27,57 +31,62 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
private boolean debugMsgOn = false;
|
||||
|
||||
double oobFact = 0.75; // out-of-bounds factor
|
||||
int maxTurns = 0;
|
||||
boolean upwindLeg = false;
|
||||
String initPathStr = "0";
|
||||
PathCandidate bestCand = null;
|
||||
long usedTimeStep = 0;
|
||||
boolean gridStore = false;
|
||||
ArrayList<List<PathCandidate>> gridPositions = null;
|
||||
ArrayList<List<PathCandidate>> isocPositions = null;
|
||||
String gridFile = null;
|
||||
|
||||
public PathGeneratorTreeGrowWind(SimulationParameters params) {
|
||||
this.parameters = params;
|
||||
}
|
||||
|
||||
public void setEvaluationParameters(String startDirection, int maxTurns) {
|
||||
public void setEvaluationParameters(String startDirection, int maxTurns, String gridFile) {
|
||||
if (startDirection != null) {
|
||||
this.initPathStr = "0" + startDirection;
|
||||
} else {
|
||||
this.initPathStr = "0";
|
||||
}
|
||||
this.maxTurns = maxTurns;
|
||||
this.gridFile = gridFile;
|
||||
if (this.gridFile != null) {
|
||||
this.gridStore = true;
|
||||
this.gridPositions = new ArrayList<List<PathCandidate>>();
|
||||
this.isocPositions = new ArrayList<List<PathCandidate>>();
|
||||
} else {
|
||||
this.gridStore = false;
|
||||
this.gridPositions = null;
|
||||
this.isocPositions = null;
|
||||
}
|
||||
}
|
||||
|
||||
class PathCandidate implements Comparable<PathCandidate> {
|
||||
public PathCandidate(TimedPosition pos, double vrt, double hrz, int trn, String path) {
|
||||
this.pos = pos;
|
||||
this.vrt = vrt;
|
||||
this.hrz = hrz;
|
||||
this.trn = trn;
|
||||
this.path = path;
|
||||
class SortPathCandsAbsHorizontally implements Comparator<PathCandidate> {
|
||||
|
||||
@Override
|
||||
public int compare(PathCandidate p1, PathCandidate p2) {
|
||||
if (Math.abs(p1.hrz) == Math.abs(p2.hrz)) {
|
||||
return 0;
|
||||
} else {
|
||||
return (Math.abs(p1.hrz) < Math.abs(p2.hrz) ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
TimedPosition pos;
|
||||
double vrt;
|
||||
double hrz;
|
||||
int trn;
|
||||
String path;
|
||||
}
|
||||
|
||||
class SortPathCandsHorizontally implements Comparator<PathCandidate> {
|
||||
|
||||
/*@Override
|
||||
// sort ascending by horizontal distance
|
||||
public int compareTo(PathCand other) {
|
||||
if (Math.abs(this.hrz) == Math.abs(other.hrz))
|
||||
return 0;
|
||||
return (Math.abs(this.hrz) < Math.abs(other.hrz) ? -1 : +1);
|
||||
}*/
|
||||
@Override
|
||||
// sort descending by height
|
||||
public int compareTo(PathCandidate other) {
|
||||
if (this.vrt == other.vrt) {
|
||||
if (Math.abs(this.hrz) == Math.abs(other.hrz)) {
|
||||
return 0;
|
||||
} else {
|
||||
return (Math.abs(this.hrz) < Math.abs(other.hrz) ? -1 : +1);
|
||||
}
|
||||
public int compare(PathCandidate p1, PathCandidate p2) {
|
||||
if (p1.hrz == p2.hrz) {
|
||||
return 0;
|
||||
} else {
|
||||
return (this.vrt > other.vrt ? -1 : +1);
|
||||
}
|
||||
return (p1.hrz < p2.hrz ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -86,36 +95,57 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
PathCandidate getBestCand() {
|
||||
return this.bestCand;
|
||||
}
|
||||
|
||||
long getUsedTimeStep() {
|
||||
return this.usedTimeStep;
|
||||
}
|
||||
|
||||
|
||||
// generate step in one of the possible directions
|
||||
// default: L - left, R - right
|
||||
// extended: M - wide left, S - wide right
|
||||
Util.Pair<TimedPosition,Wind> getStep(TimedPosition pos, long timeStep, long turnLoss, boolean sameBaseDirection, char nextDirection) {
|
||||
TimedPosition getStep(TimedPosition pos, long timeStep, long turnLoss, boolean sameBaseDirection, char nextDirection) {
|
||||
|
||||
double offDeg = 5.0;
|
||||
double offDeg = 3.0;
|
||||
WindFieldGenerator wf = this.parameters.getWindField();
|
||||
TimePoint curTime = pos.getTimePoint();
|
||||
Position curPosition = pos.getPosition();
|
||||
Wind posWind = wf.getWind(new TimedPositionWithSpeedImpl(curTime, curPosition, null));
|
||||
Wind posWind = wf.getWind(new TimedPositionImpl(curTime, curPosition));
|
||||
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
pd.setWind(posWind);
|
||||
Wind appWind = new WindImpl(posWind.getPosition(), posWind.getTimePoint(), pd.getWind());;
|
||||
|
||||
// get beat-angle left and right
|
||||
Bearing travelBearing = null;
|
||||
Bearing tmpBearing = null;
|
||||
if (nextDirection == 'L') {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[0];
|
||||
if (this.upwindLeg) {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[0];
|
||||
} else {
|
||||
travelBearing = pd.optimalDirectionsDownwind()[0];
|
||||
}
|
||||
} else if (nextDirection == 'R') {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[1];
|
||||
if (this.upwindLeg) {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[1];
|
||||
} else {
|
||||
travelBearing = pd.optimalDirectionsDownwind()[1];
|
||||
}
|
||||
} else if (nextDirection == 'M') {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[0];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(+offDeg));
|
||||
if (this.upwindLeg) {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[0];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(-offDeg));
|
||||
} else {
|
||||
tmpBearing = pd.optimalDirectionsDownwind()[0];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(-offDeg));
|
||||
}
|
||||
} else if (nextDirection == 'S') {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[1];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(-offDeg));
|
||||
if (this.upwindLeg) {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[1];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(+offDeg));
|
||||
} else {
|
||||
tmpBearing = pd.optimalDirectionsDownwind()[1];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(+offDeg));
|
||||
}
|
||||
}
|
||||
|
||||
// determine beat-speed left and right
|
||||
@@ -129,7 +159,8 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
travelTime = new MillisecondsTimePoint(nextTime.asMillis() - turnLoss);
|
||||
}
|
||||
|
||||
return new Util.Pair<TimedPosition,Wind>(new TimedPositionImpl(nextTime, travelSpeed.travelTo(curPosition, curTime, travelTime)), appWind);
|
||||
Position nextPosition = travelSpeed.travelTo(curPosition, curTime, travelTime);
|
||||
return new TimedPositionImpl(nextTime, nextPosition);
|
||||
}
|
||||
|
||||
// use base direction to distinguish direction changes that do or don't require a turn
|
||||
@@ -167,20 +198,29 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
}
|
||||
|
||||
// calculate next path position (taking turn-loss into account)
|
||||
Util.Pair<TimedPosition,Wind> nextStep = this.getStep(path.pos, timeStep, turnLoss, sameBaseDirection, nextDirection);
|
||||
TimedPosition pathPos = nextStep.getA();
|
||||
Wind posWind = nextStep.getB();
|
||||
TimedPosition pathPos = this.getStep(path.pos, timeStep, turnLoss, sameBaseDirection, nextDirection);
|
||||
|
||||
// determine apparent wind at next path position & time
|
||||
Wind posWind = this.parameters.getWindField().getWind(pathPos);
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
pd.setWind(posWind);
|
||||
Wind appWind = new WindImpl(posWind.getPosition(), posWind.getTimePoint(), pd.getWind());
|
||||
|
||||
// calculate height-position with reference to race course
|
||||
Position posHeight = pathPos.getPosition().projectToLineThrough(posEnd, posWind.getBearing());
|
||||
Bearing bearVrt = posStart.getBearingGreatCircle(posEnd);
|
||||
Position posHeightTrgt = pathPos.getPosition().projectToLineThrough(posStart, bearVrt);
|
||||
//Position posHeightWind = pathPos.getPosition().projectToLineThrough(posRef, posWind.getBearing());
|
||||
// calculate height-position with reference to apparent wind
|
||||
Position posHeight = pathPos.getPosition().projectToLineThrough(posEnd, appWind.getBearing());
|
||||
|
||||
// calculate vertical distance as distance of height-position to start
|
||||
//double vrtDist = tgtHeight - Math.round(posHeight.getDistance(posEnd).getMeters()*100.0)/100.0;
|
||||
double vrtDist = Math.round(posHeight.getDistance(posStart).getMeters()*100.0)/100.0;
|
||||
// calculate vertical distance as distance of height-position to end
|
||||
Bearing bearHeight = posEnd.getBearingGreatCircle(posHeight);
|
||||
double bearHeightSide = appWind.getBearing().getDifferenceTo(bearHeight).getDegrees();
|
||||
double vrtSide = (this.upwindLeg ? -1.0 : +1.0);
|
||||
if (Math.abs(bearHeightSide) > 170.0) {
|
||||
vrtSide = (this.upwindLeg ? +1.0 : -1.0);
|
||||
}
|
||||
double vrtDist = vrtSide*Math.round(posHeight.getDistance(posEnd).getMeters()*1000.0)/1000.0;
|
||||
|
||||
//
|
||||
// TODO: scale last step to exactly reach height of posEnd, and adjust time correspondingly
|
||||
//
|
||||
/*if (vrtDist > tgtHeight) {
|
||||
// scale last step so that vrtDist ~ tgtHeight
|
||||
Position prevPos = path.pos.getPosition();
|
||||
@@ -194,23 +234,23 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
|
||||
// calculate horizontal side: left or right in reference to race course
|
||||
double posSide = 1;
|
||||
//double posBear = posWind.getBearing().getDegrees() - posEnd.getBearingGreatCircle(pathPos.getPosition()).getDegrees();
|
||||
double posBear = posStart.getBearingGreatCircle(pathPos.getPosition()).getDegrees();
|
||||
if ((posBear < 0.0)||(posBear > 180.0)) {
|
||||
Bearing posBear = posStart.getBearingGreatCircle(pathPos.getPosition());
|
||||
Bearing bearVrt = posStart.getBearingGreatCircle(posEnd);
|
||||
double posBearDiff = bearVrt.getDifferenceTo(posBear).getDegrees();
|
||||
if ((posBearDiff < 0.0)||(posBearDiff > 180.0)) {
|
||||
posSide = -1;
|
||||
} else if ((posBear == 0.0)||(posBear == 180.0)) {
|
||||
} else if ((posBearDiff == 0.0)||(posBearDiff == 180.0)) {
|
||||
posSide = 0;
|
||||
}
|
||||
// calculate horizontal distance as distance of height-position to current position
|
||||
//double hrzDist = Math.round(posSide*posHeight.getDistance(pathPos.getPosition()).getMeters()*100.0)/100.0;
|
||||
double hrzDist = Math.round(posSide*posHeightTrgt.getDistance(pathPos.getPosition()).getMeters()*100.0)/100.0;
|
||||
|
||||
//System.out.println(""+hrzDist+", "+vrtDist+", "+pathPos.getPosition().getLatDeg()+", "+pathPos.getPosition().getLngDeg()+", "+posHeight.getLatDeg()+", "+posHeight.getLngDeg());
|
||||
Position posHeightTrgt = pathPos.getPosition().projectToLineThrough(posStart, bearVrt);
|
||||
double hrzDist = Math.round(posSide*posHeightTrgt.getDistance(pathPos.getPosition()).getMeters()*1000.0)/1000.0;
|
||||
|
||||
// extend path-string by step-direction
|
||||
String pathStr = path.path + nextDirection;
|
||||
char nextBaseDirection = this.getBaseDirection(nextDirection);
|
||||
|
||||
return (new PathCandidate(pathPos, vrtDist, hrzDist, turnCount, pathStr));
|
||||
return (new PathCandidate(pathPos, vrtDist, hrzDist, turnCount, pathStr, nextBaseDirection, appWind));
|
||||
}
|
||||
|
||||
|
||||
@@ -256,13 +296,200 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
return result;
|
||||
}
|
||||
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> generateCandidate(List<PathCandidate> oldPaths, long timeStep, long turnLoss, Position posStart, Position posMiddle, Position posEnd, double tgtHeight) {
|
||||
|
||||
List<PathCandidate> newPathCands;
|
||||
List<PathCandidate> leftPaths = new ArrayList<PathCandidate>();
|
||||
List<PathCandidate> rightPaths = new ArrayList<PathCandidate>();
|
||||
for(PathCandidate curPath : oldPaths) {
|
||||
|
||||
newPathCands = this.getPathCandsBeatWind(curPath, timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
for (PathCandidate curNewPath : newPathCands) {
|
||||
// check whether path is *outside* regatta-area
|
||||
double distFromMiddleMeters = posMiddle.getDistance(curPath.pos.getPosition()).getMeters();
|
||||
if (distFromMiddleMeters > oobFact * tgtHeight) {
|
||||
continue; // ignore curPath
|
||||
}
|
||||
|
||||
if (curNewPath.sid == 'L') {
|
||||
leftPaths.add(curNewPath);
|
||||
} else if (curNewPath.sid == 'R') {
|
||||
rightPaths.add(curNewPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> newPaths = new Util.Pair<List<PathCandidate>,List<PathCandidate>>(leftPaths, rightPaths);
|
||||
return newPaths;
|
||||
}
|
||||
|
||||
|
||||
List<PathCandidate> filterCandidates(List<PathCandidate> allCands, double hrzBinWidth) {
|
||||
|
||||
boolean[] filterMap = new boolean[allCands.size()];
|
||||
|
||||
// sort candidates by horizontal distance
|
||||
Comparator<PathCandidate> sortHorizontal = new SortPathCandsHorizontally();
|
||||
Collections.sort(allCands, sortHorizontal);
|
||||
|
||||
// start scan with index 0
|
||||
int idxL = 0;
|
||||
int idxR = 0;
|
||||
|
||||
// for each candidate, check the neighborhoods and identify bad candidates
|
||||
for(int idx = 0; idx < allCands.size(); idx++) {
|
||||
|
||||
// current horizontal distance
|
||||
double hrzDist = allCands.get(idx).hrz;
|
||||
|
||||
// align left index
|
||||
while(Math.abs(hrzDist - allCands.get(idxL).hrz) > hrzBinWidth) {
|
||||
idxL++;
|
||||
}
|
||||
|
||||
// align right index
|
||||
boolean finished = false;
|
||||
while(!finished && (idxR < (allCands.size()-1))) {
|
||||
if (Math.abs(hrzDist - allCands.get(idxR+1).hrz) <= hrzBinWidth) {
|
||||
idxR++;
|
||||
} else {
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
// search maximum height
|
||||
// in neighborhood idxL, ..., idxR
|
||||
|
||||
// init max for search
|
||||
int vrtIdx = idxL;
|
||||
double vrtMax = allCands.get(vrtIdx).vrt;
|
||||
filterMap[vrtIdx] = false;
|
||||
|
||||
// evaluate remainder of neighborhood
|
||||
if (idxL < idxR) {
|
||||
for(int jdx = (idxL+1); jdx <= idxR; jdx++) {
|
||||
if (allCands.get(jdx).vrt > vrtMax) {
|
||||
// reset previous max candidate
|
||||
filterMap[vrtIdx] = true;
|
||||
// keep max height
|
||||
vrtMax = allCands.get(jdx).vrt;
|
||||
// keep max index
|
||||
vrtIdx = jdx;
|
||||
// set current max candidate
|
||||
filterMap[vrtIdx] = false;
|
||||
} else {
|
||||
filterMap[jdx] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // endfor each candidate
|
||||
|
||||
// collect all good candidates (i.e. filterMap == false)
|
||||
List<PathCandidate> filterCands = new ArrayList<PathCandidate>();
|
||||
for(int idx=0; idx < allCands.size(); idx++) {
|
||||
if (!filterMap[idx]) {
|
||||
filterCands.add(allCands.get(idx));
|
||||
}
|
||||
}
|
||||
|
||||
// return remaining good candidates
|
||||
return filterCands;
|
||||
}
|
||||
|
||||
|
||||
List<PathCandidate> filterIsochrone(List<PathCandidate> allCands, double hrzBinWidth) {
|
||||
|
||||
boolean[] filterMap = new boolean[allCands.size()];
|
||||
for(int idx = 0; idx < allCands.size(); idx++) {
|
||||
filterMap[idx] = true;
|
||||
}
|
||||
|
||||
// sort candidates by horizontal distance
|
||||
Comparator<PathCandidate> sortHorizontal = new SortPathCandsHorizontally();
|
||||
Collections.sort(allCands, sortHorizontal);
|
||||
|
||||
// start scan with index 0
|
||||
int idxL = 0;
|
||||
int idxR = 0;
|
||||
|
||||
// for each candidate, check the neighborhoods and identify bad candidates
|
||||
for(int idx = 0; idx < allCands.size(); idx++) {
|
||||
|
||||
// current horizontal distance
|
||||
double hrzDist = allCands.get(idx).hrz;
|
||||
|
||||
// align left index
|
||||
while(Math.abs(hrzDist - allCands.get(idxL).hrz) > hrzBinWidth) {
|
||||
idxL++;
|
||||
}
|
||||
|
||||
// align right index
|
||||
boolean finished = false;
|
||||
while(!finished && (idxR < (allCands.size()-1))) {
|
||||
if (Math.abs(hrzDist - allCands.get(idxR+1).hrz) <= hrzBinWidth) {
|
||||
idxR++;
|
||||
} else {
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
// search maximum height
|
||||
// in neighborhood idxL, ..., idxR
|
||||
|
||||
// init max for search
|
||||
ArrayList<Integer> vrtIdx = new ArrayList<Integer>();
|
||||
vrtIdx.add(idxL);
|
||||
double vrtMax = allCands.get(idxL).vrt;
|
||||
|
||||
// evaluate remainder of neighborhood
|
||||
if (idxL < idxR) {
|
||||
for(int jdx = (idxL+1); jdx <= idxR; jdx++) {
|
||||
if (allCands.get(jdx).vrt > vrtMax) {
|
||||
// keep max height
|
||||
vrtMax = allCands.get(jdx).vrt;
|
||||
// keep max index
|
||||
vrtIdx = new ArrayList<Integer>();
|
||||
vrtIdx.add(jdx);
|
||||
} else if (allCands.get(jdx).vrt == vrtMax) {
|
||||
// add further max indexes
|
||||
vrtIdx.add(jdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Integer jdx : vrtIdx) {
|
||||
filterMap[jdx] = false;
|
||||
}
|
||||
|
||||
} // endfor each candidate
|
||||
|
||||
// collect all good candidates (i.e. filterMap == false)
|
||||
List<PathCandidate> filterCands = new ArrayList<PathCandidate>();
|
||||
for(int idx=0; idx < allCands.size(); idx++) {
|
||||
if (!filterMap[idx]) {
|
||||
filterCands.add(allCands.get(idx));
|
||||
}
|
||||
}
|
||||
|
||||
// return remaining good candidates
|
||||
return filterCands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
WindFieldGenerator wf = this.parameters.getWindField();
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
|
||||
Position startPos = this.parameters.getCourse().get(0);
|
||||
Position endPos = this.parameters.getCourse().get(1);
|
||||
|
||||
// test downwind: exchange start and end
|
||||
//Position startPos = this.parameters.getCourse().get(1);
|
||||
//Position endPos = this.parameters.getCourse().get(0);
|
||||
|
||||
TimePoint startTime = wf.getStartTime();// new MillisecondsTimePoint(0);
|
||||
List<TimedPositionWithSpeed> path = new ArrayList<TimedPositionWithSpeed>();
|
||||
|
||||
@@ -272,25 +499,42 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
Distance distStartEnd = startPos.getDistance(endPos);
|
||||
double distStartEndMeters = distStartEnd.getMeters();
|
||||
|
||||
long timeStep = wf.getTimeStep().asMillis()/3;
|
||||
logger.info("Time step :" + timeStep);
|
||||
long turnLoss = pd.getTurnLoss(); // 4000; // time lost when doing a turn
|
||||
|
||||
Wind wndStart = wf.getWind(new TimedPositionWithSpeedImpl(startTime, startPos, null));
|
||||
logger.fine("wndStart speed:" + wndStart.getKnots() + " angle:" + wndStart.getBearing().getDegrees());
|
||||
pd.setWind(wndStart);
|
||||
Bearing bearVrt = startPos.getBearingGreatCircle(endPos);
|
||||
//Bearing bearHrz = bearVrt.add(new DegreeBearingImpl(90.0));
|
||||
Position middlePos = startPos.translateGreatCircle(bearVrt, distStartEnd.scale(0.5));
|
||||
|
||||
|
||||
Bearing bearRCWind = wndStart.getBearing().getDifferenceTo(bearVrt);
|
||||
String legType = "downwind";
|
||||
this.upwindLeg = false;
|
||||
|
||||
if ((Math.abs(bearRCWind.getDegrees()) > 90.0)&&(Math.abs(bearRCWind.getDegrees()) < 270.0)) {
|
||||
legType = "upwind";
|
||||
this.upwindLeg = true;
|
||||
}
|
||||
|
||||
if (debugMsgOn) {
|
||||
System.out.println("start : "+startPos.getLatDeg()+", "+startPos.getLngDeg());
|
||||
System.out.println("middle: "+middlePos.getLatDeg()+", "+middlePos.getLngDeg());
|
||||
System.out.println("end : "+endPos.getLatDeg()+", "+endPos.getLngDeg());
|
||||
}
|
||||
logger.info("Leg Direction: "+legType);
|
||||
|
||||
long timeStep = wf.getTimeStep().asMillis()/2;
|
||||
if (!this.upwindLeg) {
|
||||
timeStep = timeStep / 2;
|
||||
}
|
||||
this.usedTimeStep = timeStep;
|
||||
logger.info("Time step :" + timeStep);
|
||||
long turnLoss = pd.getTurnLoss(); // 4000; // time lost when doing a turn
|
||||
if (!this.upwindLeg) {
|
||||
turnLoss = turnLoss / 2;
|
||||
}
|
||||
|
||||
// calculate initial position according to initPathStr
|
||||
PathCandidate initPath = new PathCandidate(new TimedPositionImpl(currentTime, currentPosition), 0.0, 0.0, 0, "0");
|
||||
PathCandidate initPath = new PathCandidate(new TimedPositionImpl(currentTime, currentPosition), 0.0, 0.0, 0, "0", '0', wndStart);
|
||||
if (initPathStr.length()>1) {
|
||||
char nextDirection = '0';
|
||||
for(int idx=1; idx<initPathStr.length(); idx++) {
|
||||
@@ -304,17 +548,17 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
allPaths.add(initPath);
|
||||
|
||||
|
||||
TimedPosition tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, true, 'L').getA();
|
||||
TimedPosition tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, true, 'L');
|
||||
double tstDist1 = startPos.getDistance(tstPosition.getPosition()).getMeters();
|
||||
tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, true, 'R').getA();
|
||||
tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, true, 'R');
|
||||
double tstDist2 = startPos.getDistance(tstPosition.getPosition()).getMeters();
|
||||
|
||||
double hrzBinSize = (tstDist1 + tstDist2)/4; // horizontal bin size in meters
|
||||
double hrzBinSize = (tstDist1 + tstDist2)/6.0; // horizontal bin size in meters
|
||||
if (debugMsgOn) {
|
||||
System.out.println("Horizontal Bin Size: "+hrzBinSize);
|
||||
}
|
||||
|
||||
double oobFact = 0.75; // out-of-bounds factor
|
||||
//double oobFact = 0.75; // out-of-bounds factor
|
||||
boolean reachedEnd = false;
|
||||
int addSteps = 0;
|
||||
int finalSteps = 0; // maximum number of additional steps after first target-path found
|
||||
@@ -325,109 +569,123 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
addSteps++;
|
||||
}
|
||||
|
||||
// generate new paths
|
||||
double hrzMin = 0;
|
||||
double hrzMax = 0;
|
||||
List<PathCandidate> newPathCands;
|
||||
List<PathCandidate> newPaths = new ArrayList<PathCandidate>();
|
||||
for(PathCandidate curPath : allPaths) {
|
||||
// generate new candidates (inside regatta-area)
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> newPaths = this.generateCandidate(allPaths, timeStep, turnLoss, startPos, middlePos, endPos, distStartEndMeters);
|
||||
|
||||
if ((curPath.vrt > distStartEndMeters)) {
|
||||
continue;
|
||||
} else {
|
||||
//newPathCands = this.getPathCandsBeat(curPath, timeStep, turnLoss, startPos, bearVrt, distStartEndMeters);
|
||||
newPathCands = this.getPathCandsBeatWind(curPath, timeStep, turnLoss, startPos, endPos, distStartEndMeters);
|
||||
|
||||
// select good candidates
|
||||
List<PathCandidate> leftPaths = this.filterCandidates(newPaths.getA(), hrzBinSize/2.0);
|
||||
List<PathCandidate> rightPaths = this.filterCandidates(newPaths.getB(), hrzBinSize/2.0);
|
||||
|
||||
List<PathCandidate> nextPaths = new ArrayList<PathCandidate> ();
|
||||
nextPaths.addAll(leftPaths);
|
||||
nextPaths.addAll(rightPaths);
|
||||
|
||||
allPaths = nextPaths;
|
||||
|
||||
if (this.gridStore) {
|
||||
|
||||
/*ArrayList<TimedPosition> isoChrone = new ArrayList<TimedPosition>();
|
||||
for(PathCand curCand : allPaths) {
|
||||
isoChrone.add(curCand.pos);
|
||||
}
|
||||
this.gridPositions.add(isoChrone);*/
|
||||
|
||||
for(PathCandidate newPath : newPathCands) {
|
||||
this.gridPositions.add(allPaths);
|
||||
|
||||
List<PathCandidate> isocPaths = this.filterIsochrone(allPaths, hrzBinSize);
|
||||
this.isocPositions.add(isocPaths);
|
||||
|
||||
newPaths.add(newPath);
|
||||
if (newPath.hrz < hrzMin) {
|
||||
hrzMin = newPath.hrz;
|
||||
}
|
||||
if (newPath.hrz > hrzMax) {
|
||||
hrzMax = newPath.hrz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int hrzLeft = (int)Math.round(Math.floor( (hrzMin + hrzBinSize/2.0) / hrzBinSize ));
|
||||
int hrzRight = (int)Math.round(Math.floor( (hrzMax + hrzBinSize/2.0) / hrzBinSize ));
|
||||
//System.out.println("hrzLeft: "+hrzLeft+", hrzRight: "+hrzRight);
|
||||
// check if there are still paths in the regatta-area
|
||||
if (allPaths.size() > 0) {
|
||||
|
||||
// build map of best path per hrz-bin
|
||||
int countPath = 0;
|
||||
int mapSize = hrzRight-hrzLeft+1;
|
||||
//System.out.println("MapSize: "+mapSize);
|
||||
|
||||
int[] binIdx = new int[mapSize]; // TODO: init with zero?
|
||||
double[] binVal = new double[mapSize];
|
||||
// TODO: init of binVal
|
||||
/*for(int idx = 0; idx < mapSize; idx++) {
|
||||
binVal[idx] = 2*distStartEndMeters;
|
||||
}*/
|
||||
for(int curIdx=0; curIdx<newPaths.size(); curIdx++) {
|
||||
PathCandidate curPath = newPaths.get(curIdx);
|
||||
//if (curPath.vrt > 3900) {
|
||||
if (debugMsgOn) {
|
||||
System.out.println(""+curPath.path+": "+curPath.hrz+", "+curPath.vrt+", "+curPath.pos.getPosition().getLatDeg()+", "+curPath.pos.getPosition().getLngDeg());
|
||||
}
|
||||
//}
|
||||
|
||||
// check whether path is *outside* regatta-area
|
||||
double distFromMiddleMeters = middlePos.getDistance(curPath.pos.getPosition()).getMeters();
|
||||
if (distFromMiddleMeters > oobFact*distStartEndMeters) {
|
||||
continue; // ignore curPath
|
||||
}
|
||||
|
||||
// increase path-counter
|
||||
countPath++;
|
||||
|
||||
// determine map-key
|
||||
int curKey = (int)Math.round(Math.floor( (curPath.hrz + hrzBinSize/2.0) / hrzBinSize )) - hrzLeft;
|
||||
|
||||
/*String allR = "0" + (new String(new char[curPath.path.length()-1]).replace('\0', 'R'));
|
||||
if (curPath.path.equals(allR)) {
|
||||
System.out.println(""+curPath.path+": "+curPath.hrz+", "+curPath.vrt+", "+curPath.pos.getPosition().getLatDeg()+", "+curPath.pos.getPosition().getLngDeg());
|
||||
}*/
|
||||
|
||||
// check whether curPath is better then the ones looked at
|
||||
if ((curKey>=0)&&(curKey < mapSize)) {
|
||||
if (curPath.vrt > binVal[curKey]) {
|
||||
binVal[curKey] = curPath.vrt;
|
||||
binIdx[curKey] = curIdx+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if there are still paths inside regatta-area
|
||||
if (countPath > 0) {
|
||||
// take best from each horizontal-bin and check if target is reached
|
||||
allPaths = new ArrayList<PathCandidate>();
|
||||
for (int curKey = 0; curKey < mapSize; curKey++) {
|
||||
|
||||
if (binIdx[curKey] > 0) {
|
||||
PathCandidate curPath = newPaths.get(binIdx[curKey] - 1);
|
||||
allPaths.add(curPath);
|
||||
|
||||
// debug output
|
||||
/*if ((Math.abs(curKey + hrzLeft) <= 10)) {
|
||||
System.out.println("" + curPath.path + ": " + (curKey + hrzLeft) + ", vrt:" + curPath.vrt + ", hrz:" + curPath.hrz + ", bin:" + (Math.floor((curPath.hrz + hrzBinSize / 2.0) / hrzBinSize)));
|
||||
}*/
|
||||
|
||||
// terminate path-search if paths close enough to target are found
|
||||
if ((curPath.vrt > distStartEndMeters)) {
|
||||
if ((Math.abs(curKey + hrzLeft) <= 3)) {
|
||||
reachedEnd = true;
|
||||
trgPaths.add(curPath); // add path to list of target-paths
|
||||
}
|
||||
for(PathCandidate curPath : allPaths) {
|
||||
// terminate path-search if paths are found that are close enough to target
|
||||
//if ((curPath.vrt > distStartEndMeters)) {
|
||||
if ((curPath.vrt > 0.0)) {
|
||||
//logger.info("\ntPath: " + curPath.path + "\n Time: " + (Math.round((curPath.pos.getTimePoint().asMillis()-startTime.asMillis())/1000.0/60.0*10.0)/10.0)+", Height: "+curPath.vrt+" of "+(Math.round(startPos.getDistance(endPos).getMeters()*100.0)/100.0)+", Dist: "+curPath.hrz+"m ~ "+(Math.round(curPath.pos.getPosition().getDistance(endPos).getMeters()*100.0)/100.0)+"m");
|
||||
int curBin = (int)Math.round(Math.floor( (curPath.hrz + hrzBinSize/2.0) / hrzBinSize ));
|
||||
if ((Math.abs(curBin) <= 2)) {
|
||||
reachedEnd = true;
|
||||
trgPaths.add(curPath); // add path to list of target-paths
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// terminate path-search as no path inside regatta-area are left
|
||||
reachedEnd = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.gridStore) {
|
||||
|
||||
double distResolution = distStartEndMeters*0.01;
|
||||
BufferedWriter outputCSV;
|
||||
try {
|
||||
outputCSV = new BufferedWriter(new FileWriter(this.gridFile+"-grid.csv"));
|
||||
outputCSV.write("step; lat; lng; time; side; path; vrt\n");
|
||||
outputCSV.write("0; "+startPos.getLatDeg()+"; "+startPos.getLngDeg()+"; "+(startTime.asMillis()/1000)+"; 0; 0; "+(-distStartEndMeters)+"\n");
|
||||
outputCSV.write("0; "+endPos.getLatDeg()+"; "+endPos.getLngDeg()+"; "+(startTime.asMillis()/1000)+"; 0; 0; 0\n");
|
||||
int stepCount = 0;
|
||||
for(List<PathCandidate> isoChrone : this.gridPositions) {
|
||||
stepCount++;
|
||||
PathCandidate prevPos = null;
|
||||
for(PathCandidate isoPos : isoChrone) {
|
||||
|
||||
if (prevPos != null) {
|
||||
if (prevPos.pos.getPosition().getDistance(isoPos.pos.getPosition()).getMeters() < distResolution) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
String outStr = ""+stepCount+"; "+isoPos.pos.getPosition().getLatDeg()+"; "+isoPos.pos.getPosition().getLngDeg()+"; "+(isoPos.pos.getTimePoint().asMillis()/1000)+"; "+isoPos.sid;
|
||||
outStr += "; "+isoPos.path+"; "+isoPos.vrt;
|
||||
outStr += "\n";
|
||||
outputCSV.write(outStr);
|
||||
|
||||
prevPos = isoPos;
|
||||
}
|
||||
}
|
||||
outputCSV.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
outputCSV = new BufferedWriter(new FileWriter(this.gridFile+"-isoc.csv"));
|
||||
outputCSV.write("step; lat; lng; time; side; path; vrt\n");
|
||||
outputCSV.write("0; "+startPos.getLatDeg()+"; "+startPos.getLngDeg()+"; "+(startTime.asMillis()/1000)+"; 0; 0; "+(-distStartEndMeters)+"\n");
|
||||
outputCSV.write("0; "+endPos.getLatDeg()+"; "+endPos.getLngDeg()+"; "+(startTime.asMillis()/1000)+"; 0; 0; 0\n");
|
||||
int stepCount = 0;
|
||||
for(List<PathCandidate> isoChrone : this.isocPositions) {
|
||||
stepCount++;
|
||||
PathCandidate prevPos = null;
|
||||
for(PathCandidate isoPos : isoChrone) {
|
||||
|
||||
if (prevPos != null) {
|
||||
if (prevPos.pos.getPosition().getDistance(isoPos.pos.getPosition()).getMeters() < distResolution) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
String outStr = ""+stepCount+"; "+isoPos.pos.getPosition().getLatDeg()+"; "+isoPos.pos.getPosition().getLngDeg()+"; "+(isoPos.pos.getTimePoint().asMillis()/1000)+"; "+isoPos.sid;
|
||||
outStr += "; "+isoPos.path+"; "+isoPos.vrt;
|
||||
outStr += "\n";
|
||||
outputCSV.write(outStr);
|
||||
|
||||
prevPos = isoPos;
|
||||
}
|
||||
}
|
||||
outputCSV.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -443,13 +701,11 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
Collections.sort(trgPaths);
|
||||
|
||||
// debug output
|
||||
//if (debugMsgOn) {
|
||||
for(PathCandidate curPath : trgPaths) {
|
||||
logger.info("\nPath: " + curPath.path + "\n Time: " + (Math.round((curPath.pos.getTimePoint().asMillis()-startTime.asMillis())/1000.0/60.0*10.0)/10.0)+", Height: "+curPath.vrt+" of "+(Math.round(startPos.getDistance(endPos).getMeters()*100.0)/100.0)+", Dist: "+curPath.hrz+"m ~ "+(Math.round(curPath.pos.getPosition().getDistance(endPos).getMeters()*100.0)/100.0)+"m");
|
||||
//System.out.print(""+curPath.path+": "+curPath.pos.getTimePoint().asMillis()+", "+curPath.pos.getPosition().getLatDeg()+", "+curPath.pos.getPosition().getLngDeg()+", ");
|
||||
//System.out.println(" height:"+curPath.vrt+" of "+startPos.getDistance(endPos).getMeters()+", dist:"+curPath.hrz+" ~ "+curPath.pos.getPosition().getDistance(endPos));
|
||||
}
|
||||
//}
|
||||
|
||||
//
|
||||
// fill gwt-path
|
||||
@@ -472,7 +728,7 @@ public class PathGeneratorTreeGrowWind extends PathGeneratorBase {
|
||||
} else {
|
||||
|
||||
boolean sameBaseDirection = this.isSameDirection(prevDirection, nextDirection);
|
||||
TimedPosition newPosition = this.getStep(curPosition, timeStep, turnLoss, sameBaseDirection, nextDirection).getA();
|
||||
TimedPosition newPosition = this.getStep(curPosition, timeStep, turnLoss, sameBaseDirection, nextDirection);
|
||||
curPosition = new TimedPositionWithSpeedImpl(newPosition.getTimePoint(), newPosition.getPosition(), null);
|
||||
path.add(curPosition);
|
||||
|
||||
|
||||
-566
@@ -1,566 +0,0 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
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.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
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.WindFieldGenerator;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class PathGeneratorTreeGrowWind2 extends PathGeneratorBase {
|
||||
|
||||
private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
private boolean debugMsgOn = false;
|
||||
|
||||
double oobFact = 0.75; // out-of-bounds factor
|
||||
int maxTurns = 0;
|
||||
String initPathStr = "0";
|
||||
PathCandidate bestCand = null;
|
||||
boolean gridStore = false;
|
||||
ArrayList<List<PathCandidate>> gridPositions = null;
|
||||
String gridFile = null;
|
||||
|
||||
public PathGeneratorTreeGrowWind2(SimulationParameters params) {
|
||||
this.parameters = params;
|
||||
}
|
||||
|
||||
public void setEvaluationParameters(String startDirection, int maxTurns, String gridFile) {
|
||||
if (startDirection != null) {
|
||||
this.initPathStr = "0" + startDirection;
|
||||
} else {
|
||||
this.initPathStr = "0";
|
||||
}
|
||||
this.maxTurns = maxTurns;
|
||||
this.gridFile = gridFile;
|
||||
if (this.gridFile != null) {
|
||||
this.gridStore = true;
|
||||
this.gridPositions = new ArrayList<List<PathCandidate>>();
|
||||
} else {
|
||||
this.gridStore = false;
|
||||
this.gridPositions = null;
|
||||
}
|
||||
}
|
||||
|
||||
class SortPathCandsAbsHorizontally implements Comparator<PathCandidate> {
|
||||
|
||||
@Override
|
||||
public int compare(PathCandidate p1, PathCandidate p2) {
|
||||
if (Math.abs(p1.hrz) == Math.abs(p2.hrz)) {
|
||||
return 0;
|
||||
} else {
|
||||
return (Math.abs(p1.hrz) < Math.abs(p2.hrz) ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SortPathCandsHorizontally implements Comparator<PathCandidate> {
|
||||
|
||||
@Override
|
||||
public int compare(PathCandidate p1, PathCandidate p2) {
|
||||
if (p1.hrz == p2.hrz) {
|
||||
return 0;
|
||||
} else {
|
||||
return (p1.hrz < p2.hrz ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// getter for evaluating best path cand propoerties further
|
||||
PathCandidate getBestCand() {
|
||||
return this.bestCand;
|
||||
}
|
||||
|
||||
|
||||
// generate step in one of the possible directions
|
||||
// default: L - left, R - right
|
||||
// extended: M - wide left, S - wide right
|
||||
Util.Pair<TimedPosition,Wind> getStep(TimedPosition pos, long timeStep, long turnLoss, boolean sameBaseDirection, char nextDirection) {
|
||||
|
||||
double offDeg = 3.0;
|
||||
WindFieldGenerator wf = this.parameters.getWindField();
|
||||
TimePoint curTime = pos.getTimePoint();
|
||||
Position curPosition = pos.getPosition();
|
||||
Wind posWind = wf.getWind(new TimedPositionWithSpeedImpl(curTime, curPosition, null));
|
||||
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
pd.setWind(posWind);
|
||||
Wind appWind = new WindImpl(posWind.getPosition(), posWind.getTimePoint(), pd.getWind());;
|
||||
|
||||
// get beat-angle left and right
|
||||
Bearing travelBearing = null;
|
||||
Bearing tmpBearing = null;
|
||||
if (nextDirection == 'L') {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[0];
|
||||
} else if (nextDirection == 'R') {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[1];
|
||||
} else if (nextDirection == 'M') {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[0];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(-offDeg));
|
||||
} else if (nextDirection == 'S') {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[1];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(+offDeg));
|
||||
}
|
||||
|
||||
// determine beat-speed left and right
|
||||
SpeedWithBearing travelSpeed = pd.getSpeedAtBearing(travelBearing);
|
||||
|
||||
TimePoint travelTime;
|
||||
TimePoint nextTime = new MillisecondsTimePoint(curTime.asMillis()+timeStep);
|
||||
if (sameBaseDirection) {
|
||||
travelTime = nextTime;
|
||||
} else {
|
||||
travelTime = new MillisecondsTimePoint(nextTime.asMillis() - turnLoss);
|
||||
}
|
||||
|
||||
return new Util.Pair<TimedPosition,Wind>(new TimedPositionImpl(nextTime, travelSpeed.travelTo(curPosition, curTime, travelTime)), appWind);
|
||||
}
|
||||
|
||||
// use base direction to distinguish direction changes that do or don't require a turn
|
||||
char getBaseDirection(char direction) {
|
||||
char baseDirection = direction;
|
||||
|
||||
if (direction == 'M') {
|
||||
baseDirection = 'L';
|
||||
}
|
||||
if (direction == 'S') {
|
||||
baseDirection = 'R';
|
||||
}
|
||||
|
||||
return baseDirection;
|
||||
}
|
||||
|
||||
// check whether nextDirection is same base direction as previous direction, i.e. no turn
|
||||
boolean isSameDirection(char prevDirection, char nextDirection) {
|
||||
|
||||
char prevBaseDirection = this.getBaseDirection(prevDirection);
|
||||
char nextBaseDirection = this.getBaseDirection(nextDirection);
|
||||
|
||||
return ((nextBaseDirection == prevBaseDirection)||(prevBaseDirection == '0'));
|
||||
}
|
||||
|
||||
// get path candidate measuring height towards (local, current-apparent) wind
|
||||
PathCandidate getPathCandWind(PathCandidate path, char nextDirection, long timeStep, long turnLoss, Position posStart, Position posEnd, double tgtHeight) {
|
||||
|
||||
char prevDirection = path.path.charAt(path.path.length()-1);
|
||||
boolean sameBaseDirection = this.isSameDirection(prevDirection, nextDirection);
|
||||
|
||||
int turnCount = path.trn;
|
||||
if (!sameBaseDirection) {
|
||||
turnCount++;
|
||||
}
|
||||
|
||||
// calculate next path position (taking turn-loss into account)
|
||||
Util.Pair<TimedPosition,Wind> nextStep = this.getStep(path.pos, timeStep, turnLoss, sameBaseDirection, nextDirection);
|
||||
TimedPosition pathPos = nextStep.getA();
|
||||
Wind posWind = nextStep.getB();
|
||||
|
||||
// calculate height-position with reference to race course
|
||||
Position posHeight = pathPos.getPosition().projectToLineThrough(posEnd, posWind.getBearing());
|
||||
Bearing bearVrt = posStart.getBearingGreatCircle(posEnd);
|
||||
Position posHeightTrgt = pathPos.getPosition().projectToLineThrough(posStart, bearVrt);
|
||||
//Position posHeightWind = pathPos.getPosition().projectToLineThrough(posRef, posWind.getBearing());
|
||||
|
||||
// calculate vertical distance as distance of height-position to start
|
||||
//double vrtDist = Math.round(posHeightTrgt.getDistance(posStart).getMeters()*100.0)/100.0;
|
||||
double vrtDist = Math.round(posHeight.getDistance(posStart).getMeters()*100.0)/100.0;
|
||||
|
||||
/*if (vrtDist > tgtHeight) {
|
||||
// scale last step so that vrtDist ~ tgtHeight
|
||||
Position prevPos = path.pos.getPosition();
|
||||
TimePoint prevTime = path.pos.getTimePoint();
|
||||
double heightFrac = (tgtHeight - path.vrt) / (vrtDist - path.vrt);
|
||||
Position newPos = prevPos.translateGreatCircle(prevPos.getBearingGreatCircle(pathPos.getPosition()), prevPos.getDistance(pathPos.getPosition()).scale(heightFrac));
|
||||
TimePoint newTime = new MillisecondsTimePoint(Math.round(prevTime.asMillis() + (pathPos.getTimePoint().asMillis()-prevTime.asMillis())*heightFrac));
|
||||
pathPos = new TimedPositionImpl(newTime, newPos);
|
||||
posHeight = pathPos.getPosition().projectToLineThrough(posStart, bearVrt);
|
||||
}*/
|
||||
|
||||
// calculate horizontal side: left or right in reference to race course
|
||||
double posSide = 1;
|
||||
//double posBear = posWind.getBearing().getDegrees() - posEnd.getBearingGreatCircle(pathPos.getPosition()).getDegrees();
|
||||
Bearing posBear = posStart.getBearingGreatCircle(pathPos.getPosition());
|
||||
double posBearDiff = bearVrt.getDifferenceTo(posBear).getDegrees();
|
||||
if ((posBearDiff < 0.0)||(posBearDiff > 180.0)) {
|
||||
posSide = -1;
|
||||
} else if ((posBearDiff == 0.0)||(posBearDiff == 180.0)) {
|
||||
posSide = 0;
|
||||
}
|
||||
|
||||
// calculate horizontal distance as distance of height-position to current position
|
||||
//double hrzDist = Math.round(posSide*posHeight.getDistance(pathPos.getPosition()).getMeters()*100.0)/100.0;
|
||||
double hrzDist = Math.round(posSide*posHeightTrgt.getDistance(pathPos.getPosition()).getMeters()*100.0)/100.0;
|
||||
|
||||
//System.out.println(""+hrzDist+", "+vrtDist+", "+pathPos.getPosition().getLatDeg()+", "+pathPos.getPosition().getLngDeg()+", "+posHeight.getLatDeg()+", "+posHeight.getLngDeg());
|
||||
|
||||
// extend path-string by step-direction
|
||||
String pathStr = path.path + nextDirection;
|
||||
char nextBaseDirection = this.getBaseDirection(nextDirection);
|
||||
|
||||
return (new PathCandidate(pathPos, vrtDist, hrzDist, turnCount, pathStr, nextBaseDirection, posWind));
|
||||
}
|
||||
|
||||
|
||||
// generate path candidates based on beat angles
|
||||
List<PathCandidate> getPathCandsBeatWind(PathCandidate path, long timeStep, long turnLoss, Position posStart, Position posEnd, double tgtHeight) {
|
||||
|
||||
List<PathCandidate> result = new ArrayList<PathCandidate>();
|
||||
PathCandidate newPathCand;
|
||||
|
||||
if (this.maxTurns > 0) {
|
||||
|
||||
char prevDirection = path.path.charAt(path.path.length()-1);
|
||||
if ((path.trn < this.maxTurns)||(this.isSameDirection(prevDirection, 'L'))) {
|
||||
newPathCand = getPathCandWind(path, 'L', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
}
|
||||
|
||||
if ((path.trn < this.maxTurns)||(this.isSameDirection(prevDirection, 'R'))) {
|
||||
newPathCand = getPathCandWind(path, 'R', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// step left
|
||||
newPathCand = getPathCandWind(path, 'L', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
|
||||
// step wide left
|
||||
//newPathCand = getPathCandWind(path, 'M', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
//result.add(newPathCand);
|
||||
|
||||
// step right
|
||||
newPathCand = getPathCandWind(path, 'R', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
|
||||
// step wide right
|
||||
//newPathCand = getPathCandWind(path, 'S', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
//result.add(newPathCand);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> generateCandidate(List<PathCandidate> oldPaths, long timeStep, long turnLoss, Position posStart, Position posMiddle, Position posEnd, double tgtHeight) {
|
||||
|
||||
List<PathCandidate> newPathCands;
|
||||
List<PathCandidate> leftPaths = new ArrayList<PathCandidate>();
|
||||
List<PathCandidate> rightPaths = new ArrayList<PathCandidate>();
|
||||
for(PathCandidate curPath : oldPaths) {
|
||||
|
||||
newPathCands = this.getPathCandsBeatWind(curPath, timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
for (PathCandidate curNewPath : newPathCands) {
|
||||
// check whether path is *outside* regatta-area
|
||||
double distFromMiddleMeters = posMiddle.getDistance(curPath.pos.getPosition()).getMeters();
|
||||
if (distFromMiddleMeters > oobFact * tgtHeight) {
|
||||
continue; // ignore curPath
|
||||
}
|
||||
|
||||
if (curNewPath.sid == 'L') {
|
||||
leftPaths.add(curNewPath);
|
||||
} else if (curNewPath.sid == 'R') {
|
||||
rightPaths.add(curNewPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> newPaths = new Util.Pair<List<PathCandidate>,List<PathCandidate>>(leftPaths, rightPaths);
|
||||
return newPaths;
|
||||
}
|
||||
|
||||
|
||||
List<PathCandidate> filterCandidates(List<PathCandidate> allCands, double hrzBinWidth) {
|
||||
|
||||
boolean[] filterMap = new boolean[allCands.size()];
|
||||
|
||||
// sort candidates by horizontal distance
|
||||
Comparator<PathCandidate> sortHorizontal = new SortPathCandsHorizontally();
|
||||
Collections.sort(allCands, sortHorizontal);
|
||||
|
||||
// start scan with index 0
|
||||
int idxL = 0;
|
||||
int idxR = 0;
|
||||
|
||||
// for each candidate, check the neighborhoos and identify bad candidates
|
||||
for(int idx = 0; idx < allCands.size(); idx++) {
|
||||
|
||||
// current horizontal distance
|
||||
double hrzDist = allCands.get(idx).hrz;
|
||||
|
||||
// align left index
|
||||
while(Math.abs(hrzDist - allCands.get(idxL).hrz) > hrzBinWidth) {
|
||||
idxL++;
|
||||
}
|
||||
|
||||
// align right index
|
||||
boolean finished = false;
|
||||
while(!finished && (idxR < (allCands.size()-1))) {
|
||||
if (Math.abs(hrzDist - allCands.get(idxR+1).hrz) <= hrzBinWidth) {
|
||||
idxR++;
|
||||
} else {
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
// search maximum height
|
||||
// in neighborhood idxL, ..., idxR
|
||||
|
||||
// init max for search
|
||||
int vrtIdx = idxL;
|
||||
double vrtMax = allCands.get(vrtIdx).vrt;
|
||||
filterMap[vrtIdx] = false;
|
||||
|
||||
// evaluate remainder of neighborhood
|
||||
if (idxL < idxR) {
|
||||
for(int jdx = (idxL+1); jdx <= idxR; jdx++) {
|
||||
if (allCands.get(jdx).vrt > vrtMax) {
|
||||
// reset previous max candidate
|
||||
filterMap[vrtIdx] = true;
|
||||
// keep max height
|
||||
vrtMax = allCands.get(jdx).vrt;
|
||||
// keep max index
|
||||
vrtIdx = jdx;
|
||||
// set current max candidate
|
||||
filterMap[vrtIdx] = false;
|
||||
} else {
|
||||
filterMap[jdx] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // endfor each candidate
|
||||
|
||||
// collect all good candidates (i.e. filterMap == false)
|
||||
List<PathCandidate> filterCands = new ArrayList<PathCandidate>();
|
||||
for(int idx=0; idx < allCands.size(); idx++) {
|
||||
if (!filterMap[idx]) {
|
||||
filterCands.add(allCands.get(idx));
|
||||
}
|
||||
}
|
||||
|
||||
// return remaining good candidates
|
||||
return filterCands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
WindFieldGenerator wf = this.parameters.getWindField();
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
Position startPos = this.parameters.getCourse().get(0);
|
||||
Position endPos = this.parameters.getCourse().get(1);
|
||||
TimePoint startTime = wf.getStartTime();// new MillisecondsTimePoint(0);
|
||||
List<TimedPositionWithSpeed> path = new ArrayList<TimedPositionWithSpeed>();
|
||||
|
||||
Position currentPosition = startPos;
|
||||
TimePoint currentTime = startTime;
|
||||
|
||||
Distance distStartEnd = startPos.getDistance(endPos);
|
||||
double distStartEndMeters = distStartEnd.getMeters();
|
||||
|
||||
long timeStep = wf.getTimeStep().asMillis()/3;
|
||||
logger.info("Time step :" + timeStep);
|
||||
long turnLoss = pd.getTurnLoss(); // 4000; // time lost when doing a turn
|
||||
|
||||
Wind wndStart = wf.getWind(new TimedPositionWithSpeedImpl(startTime, startPos, null));
|
||||
logger.fine("wndStart speed:" + wndStart.getKnots() + " angle:" + wndStart.getBearing().getDegrees());
|
||||
pd.setWind(wndStart);
|
||||
Bearing bearVrt = startPos.getBearingGreatCircle(endPos);
|
||||
//Bearing bearHrz = bearVrt.add(new DegreeBearingImpl(90.0));
|
||||
Position middlePos = startPos.translateGreatCircle(bearVrt, distStartEnd.scale(0.5));
|
||||
|
||||
if (debugMsgOn) {
|
||||
System.out.println("start : "+startPos.getLatDeg()+", "+startPos.getLngDeg());
|
||||
System.out.println("middle: "+middlePos.getLatDeg()+", "+middlePos.getLngDeg());
|
||||
System.out.println("end : "+endPos.getLatDeg()+", "+endPos.getLngDeg());
|
||||
}
|
||||
|
||||
// calculate initial position according to initPathStr
|
||||
PathCandidate initPath = new PathCandidate(new TimedPositionImpl(currentTime, currentPosition), 0.0, 0.0, 0, "0", '0', wndStart);
|
||||
if (initPathStr.length()>1) {
|
||||
char nextDirection = '0';
|
||||
for(int idx=1; idx<initPathStr.length(); idx++) {
|
||||
nextDirection = initPathStr.charAt(idx);
|
||||
PathCandidate newPathCand = getPathCandWind(initPath, nextDirection, timeStep, turnLoss, startPos, endPos, distStartEndMeters);
|
||||
initPath = newPathCand;
|
||||
}
|
||||
}
|
||||
List<PathCandidate> allPaths = new ArrayList<PathCandidate>();
|
||||
List<PathCandidate> trgPaths = new ArrayList<PathCandidate>();
|
||||
allPaths.add(initPath);
|
||||
|
||||
|
||||
TimedPosition tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, true, 'L').getA();
|
||||
double tstDist1 = startPos.getDistance(tstPosition.getPosition()).getMeters();
|
||||
tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, true, 'R').getA();
|
||||
double tstDist2 = startPos.getDistance(tstPosition.getPosition()).getMeters();
|
||||
|
||||
double hrzBinSize = (tstDist1 + tstDist2)/2.0; // horizontal bin size in meters
|
||||
if (debugMsgOn) {
|
||||
System.out.println("Horizontal Bin Size: "+hrzBinSize);
|
||||
}
|
||||
|
||||
//double oobFact = 0.75; // out-of-bounds factor
|
||||
boolean reachedEnd = false;
|
||||
int addSteps = 0;
|
||||
int finalSteps = 0; // maximum number of additional steps after first target-path found
|
||||
|
||||
while ((!reachedEnd)||(addSteps<finalSteps)) {
|
||||
|
||||
if (reachedEnd) {
|
||||
addSteps++;
|
||||
}
|
||||
|
||||
// generate new candidates (inside regatta-area)
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> newPaths = this.generateCandidate(allPaths, timeStep, turnLoss, startPos, middlePos, endPos, distStartEndMeters);
|
||||
|
||||
|
||||
// select good candidates
|
||||
List<PathCandidate> leftPaths = this.filterCandidates(newPaths.getA(), hrzBinSize/2.0);
|
||||
List<PathCandidate> rightPaths = this.filterCandidates(newPaths.getB(), hrzBinSize/2.0);
|
||||
|
||||
List<PathCandidate> nextPaths = new ArrayList<PathCandidate> ();
|
||||
nextPaths.addAll(leftPaths);
|
||||
nextPaths.addAll(rightPaths);
|
||||
|
||||
allPaths = nextPaths;
|
||||
|
||||
if (this.gridStore) {
|
||||
|
||||
/*ArrayList<TimedPosition> isoChrone = new ArrayList<TimedPosition>();
|
||||
for(PathCand curCand : allPaths) {
|
||||
isoChrone.add(curCand.pos);
|
||||
}
|
||||
this.gridPositions.add(isoChrone);*/
|
||||
|
||||
this.gridPositions.add(allPaths);
|
||||
|
||||
}
|
||||
|
||||
// check if there are still paths in the regatta-area
|
||||
if (allPaths.size() > 0) {
|
||||
|
||||
for(PathCandidate curPath : allPaths) {
|
||||
// terminate path-search if paths are found that are close enough to target
|
||||
if ((curPath.vrt > distStartEndMeters)) {
|
||||
int curBin = (int)Math.round(Math.floor( (curPath.hrz + hrzBinSize/2.0) / hrzBinSize ));
|
||||
if ((Math.abs(curBin) <= 2)) {
|
||||
reachedEnd = true;
|
||||
trgPaths.add(curPath); // add path to list of target-paths
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// terminate path-search as no path inside regatta-area are left
|
||||
reachedEnd = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.gridStore) {
|
||||
|
||||
BufferedWriter outputCSV;
|
||||
try {
|
||||
outputCSV = new BufferedWriter(new FileWriter(this.gridFile));
|
||||
outputCSV.write("step; lat; lng; time; side\n");
|
||||
int stepCount = 0;
|
||||
for(List<PathCandidate> isoChrone : this.gridPositions) {
|
||||
stepCount++;
|
||||
for(PathCandidate isoPos : isoChrone) {
|
||||
|
||||
outputCSV.write(""+stepCount+"; "+isoPos.pos.getPosition().getLatDeg()+"; "+isoPos.pos.getPosition().getLngDeg()+"; "+(isoPos.pos.getTimePoint().asMillis()/1000)+"; "+isoPos.sid+"\n");
|
||||
|
||||
}
|
||||
}
|
||||
outputCSV.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// if no target-paths were found, return empty path
|
||||
if (trgPaths.size() == 0) {
|
||||
//trgPaths = allPaths; // TODO: only for testing; remove lateron
|
||||
TimedPositionWithSpeed curPosition = new TimedPositionWithSpeedImpl(startTime, startPos, null);
|
||||
path.add(curPosition);
|
||||
return new PathImpl(path, wf); // return empty path
|
||||
}
|
||||
|
||||
// sort target-paths ascending by distance-to-target
|
||||
Collections.sort(trgPaths);
|
||||
|
||||
// debug output
|
||||
//if (debugMsgOn) {
|
||||
for(PathCandidate curPath : trgPaths) {
|
||||
logger.info("\nPath: " + curPath.path + "\n Time: " + (Math.round((curPath.pos.getTimePoint().asMillis()-startTime.asMillis())/1000.0/60.0*10.0)/10.0)+", Height: "+curPath.vrt+" of "+(Math.round(startPos.getDistance(endPos).getMeters()*100.0)/100.0)+", Dist: "+curPath.hrz+"m ~ "+(Math.round(curPath.pos.getPosition().getDistance(endPos).getMeters()*100.0)/100.0)+"m");
|
||||
//System.out.print(""+curPath.path+": "+curPath.pos.getTimePoint().asMillis()+", "+curPath.pos.getPosition().getLatDeg()+", "+curPath.pos.getPosition().getLngDeg()+", ");
|
||||
//System.out.println(" height:"+curPath.vrt+" of "+startPos.getDistance(endPos).getMeters()+", dist:"+curPath.hrz+" ~ "+curPath.pos.getPosition().getDistance(endPos));
|
||||
}
|
||||
//}
|
||||
|
||||
//
|
||||
// fill gwt-path
|
||||
//
|
||||
|
||||
// generate intermediate steps
|
||||
bestCand = trgPaths.get(0); // target-path ending closest to target
|
||||
TimedPositionWithSpeed curPosition = null;
|
||||
char nextDirection = '0';
|
||||
char prevDirection = '0';
|
||||
for(int step=0; step<(bestCand.path.length()-1); step++) {
|
||||
|
||||
nextDirection = bestCand.path.charAt(step);
|
||||
|
||||
if (nextDirection == '0') {
|
||||
|
||||
curPosition = new TimedPositionWithSpeedImpl(startTime, startPos, null);
|
||||
path.add(curPosition);
|
||||
|
||||
} else {
|
||||
|
||||
boolean sameBaseDirection = this.isSameDirection(prevDirection, nextDirection);
|
||||
TimedPosition newPosition = this.getStep(curPosition, timeStep, turnLoss, sameBaseDirection, nextDirection).getA();
|
||||
curPosition = new TimedPositionWithSpeedImpl(newPosition.getTimePoint(), newPosition.getPosition(), null);
|
||||
path.add(curPosition);
|
||||
|
||||
}
|
||||
|
||||
prevDirection = nextDirection;
|
||||
}
|
||||
|
||||
// add final position (rescaled before to end on height of target)
|
||||
path.add(new TimedPositionWithSpeedImpl(bestCand.pos.getTimePoint(), bestCand.pos.getPosition(), null));
|
||||
|
||||
return new PathImpl(path, wf);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-751
@@ -1,751 +0,0 @@
|
||||
package com.sap.sailing.simulator.impl;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
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.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
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.WindFieldGenerator;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class PathGeneratorTreeGrowWind3 extends PathGeneratorBase {
|
||||
|
||||
private static Logger logger = Logger.getLogger("com.sap.sailing");
|
||||
private boolean debugMsgOn = false;
|
||||
|
||||
double oobFact = 0.75; // out-of-bounds factor
|
||||
int maxTurns = 0;
|
||||
boolean upwindLeg = false;
|
||||
String initPathStr = "0";
|
||||
PathCandidate bestCand = null;
|
||||
long usedTimeStep = 0;
|
||||
boolean gridStore = false;
|
||||
ArrayList<List<PathCandidate>> gridPositions = null;
|
||||
ArrayList<List<PathCandidate>> isocPositions = null;
|
||||
String gridFile = null;
|
||||
|
||||
public PathGeneratorTreeGrowWind3(SimulationParameters params) {
|
||||
this.parameters = params;
|
||||
}
|
||||
|
||||
public void setEvaluationParameters(String startDirection, int maxTurns, String gridFile) {
|
||||
if (startDirection != null) {
|
||||
this.initPathStr = "0" + startDirection;
|
||||
} else {
|
||||
this.initPathStr = "0";
|
||||
}
|
||||
this.maxTurns = maxTurns;
|
||||
this.gridFile = gridFile;
|
||||
if (this.gridFile != null) {
|
||||
this.gridStore = true;
|
||||
this.gridPositions = new ArrayList<List<PathCandidate>>();
|
||||
this.isocPositions = new ArrayList<List<PathCandidate>>();
|
||||
} else {
|
||||
this.gridStore = false;
|
||||
this.gridPositions = null;
|
||||
this.isocPositions = null;
|
||||
}
|
||||
}
|
||||
|
||||
class SortPathCandsAbsHorizontally implements Comparator<PathCandidate> {
|
||||
|
||||
@Override
|
||||
public int compare(PathCandidate p1, PathCandidate p2) {
|
||||
if (Math.abs(p1.hrz) == Math.abs(p2.hrz)) {
|
||||
return 0;
|
||||
} else {
|
||||
return (Math.abs(p1.hrz) < Math.abs(p2.hrz) ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SortPathCandsHorizontally implements Comparator<PathCandidate> {
|
||||
|
||||
@Override
|
||||
public int compare(PathCandidate p1, PathCandidate p2) {
|
||||
if (p1.hrz == p2.hrz) {
|
||||
return 0;
|
||||
} else {
|
||||
return (p1.hrz < p2.hrz ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// getter for evaluating best path cand propoerties further
|
||||
PathCandidate getBestCand() {
|
||||
return this.bestCand;
|
||||
}
|
||||
|
||||
long getUsedTimeStep() {
|
||||
return this.usedTimeStep;
|
||||
}
|
||||
|
||||
|
||||
// generate step in one of the possible directions
|
||||
// default: L - left, R - right
|
||||
// extended: M - wide left, S - wide right
|
||||
Util.Pair<TimedPosition,Wind> getStep(TimedPosition pos, long timeStep, long turnLoss, boolean sameBaseDirection, char nextDirection) {
|
||||
|
||||
double offDeg = 3.0;
|
||||
WindFieldGenerator wf = this.parameters.getWindField();
|
||||
TimePoint curTime = pos.getTimePoint();
|
||||
Position curPosition = pos.getPosition();
|
||||
Wind posWind = wf.getWind(new TimedPositionWithSpeedImpl(curTime, curPosition, null));
|
||||
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
pd.setWind(posWind);
|
||||
Wind appWind = new WindImpl(posWind.getPosition(), posWind.getTimePoint(), pd.getWind());;
|
||||
|
||||
// get beat-angle left and right
|
||||
Bearing travelBearing = null;
|
||||
Bearing tmpBearing = null;
|
||||
if (nextDirection == 'L') {
|
||||
if (this.upwindLeg) {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[0];
|
||||
} else {
|
||||
travelBearing = pd.optimalDirectionsDownwind()[0];
|
||||
}
|
||||
} else if (nextDirection == 'R') {
|
||||
if (this.upwindLeg) {
|
||||
travelBearing = pd.optimalDirectionsUpwind()[1];
|
||||
} else {
|
||||
travelBearing = pd.optimalDirectionsDownwind()[1];
|
||||
}
|
||||
} else if (nextDirection == 'M') {
|
||||
if (this.upwindLeg) {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[0];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(-offDeg));
|
||||
} else {
|
||||
tmpBearing = pd.optimalDirectionsDownwind()[0];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(-offDeg));
|
||||
}
|
||||
} else if (nextDirection == 'S') {
|
||||
if (this.upwindLeg) {
|
||||
tmpBearing = pd.optimalDirectionsUpwind()[1];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(+offDeg));
|
||||
} else {
|
||||
tmpBearing = pd.optimalDirectionsDownwind()[1];
|
||||
travelBearing = tmpBearing.add(new DegreeBearingImpl(+offDeg));
|
||||
}
|
||||
}
|
||||
|
||||
// determine beat-speed left and right
|
||||
SpeedWithBearing travelSpeed = pd.getSpeedAtBearing(travelBearing);
|
||||
|
||||
TimePoint travelTime;
|
||||
TimePoint nextTime = new MillisecondsTimePoint(curTime.asMillis()+timeStep);
|
||||
if (sameBaseDirection) {
|
||||
travelTime = nextTime;
|
||||
} else {
|
||||
travelTime = new MillisecondsTimePoint(nextTime.asMillis() - turnLoss);
|
||||
}
|
||||
|
||||
return new Util.Pair<TimedPosition,Wind>(new TimedPositionImpl(nextTime, travelSpeed.travelTo(curPosition, curTime, travelTime)), appWind);
|
||||
}
|
||||
|
||||
// use base direction to distinguish direction changes that do or don't require a turn
|
||||
char getBaseDirection(char direction) {
|
||||
char baseDirection = direction;
|
||||
|
||||
if (direction == 'M') {
|
||||
baseDirection = 'L';
|
||||
}
|
||||
if (direction == 'S') {
|
||||
baseDirection = 'R';
|
||||
}
|
||||
|
||||
return baseDirection;
|
||||
}
|
||||
|
||||
// check whether nextDirection is same base direction as previous direction, i.e. no turn
|
||||
boolean isSameDirection(char prevDirection, char nextDirection) {
|
||||
|
||||
char prevBaseDirection = this.getBaseDirection(prevDirection);
|
||||
char nextBaseDirection = this.getBaseDirection(nextDirection);
|
||||
|
||||
return ((nextBaseDirection == prevBaseDirection)||(prevBaseDirection == '0'));
|
||||
}
|
||||
|
||||
// get path candidate measuring height towards (local, current-apparent) wind
|
||||
PathCandidate getPathCandWind(PathCandidate path, char nextDirection, long timeStep, long turnLoss, Position posStart, Position posEnd, double tgtHeight) {
|
||||
|
||||
char prevDirection = path.path.charAt(path.path.length()-1);
|
||||
boolean sameBaseDirection = this.isSameDirection(prevDirection, nextDirection);
|
||||
|
||||
int turnCount = path.trn;
|
||||
if (!sameBaseDirection) {
|
||||
turnCount++;
|
||||
}
|
||||
|
||||
// calculate next path position (taking turn-loss into account)
|
||||
Util.Pair<TimedPosition,Wind> nextStep = this.getStep(path.pos, timeStep, turnLoss, sameBaseDirection, nextDirection);
|
||||
TimedPosition pathPos = nextStep.getA();
|
||||
Wind posWind = nextStep.getB();
|
||||
|
||||
// calculate height-position with reference to race course
|
||||
Position posHeight = pathPos.getPosition().projectToLineThrough(posEnd, posWind.getBearing());
|
||||
Bearing bearVrt = posStart.getBearingGreatCircle(posEnd);
|
||||
Position posHeightTrgt = pathPos.getPosition().projectToLineThrough(posStart, bearVrt);
|
||||
|
||||
// calculate vertical distance as distance of height-position to start
|
||||
//double vrtDist = Math.round(posHeightTrgt.getDistance(posStart).getMeters()*100.0)/100.0;
|
||||
|
||||
Bearing bearHeight = posEnd.getBearingGreatCircle(posHeight);
|
||||
double bearHeightSide = posWind.getBearing().getDifferenceTo(bearHeight).getDegrees();
|
||||
/*if (Math.abs(bearHeightSide) > 5.0) {
|
||||
System.out.println("bearHeightSide: "+bearHeightSide);
|
||||
}*/
|
||||
double vrtSide = (this.upwindLeg ? -1.0 : +1.0);
|
||||
if (Math.abs(bearHeightSide) > 170.0) {
|
||||
vrtSide = (this.upwindLeg ? +1.0 : -1.0);
|
||||
}
|
||||
double vrtDist = vrtSide*Math.round(posHeight.getDistance(posEnd).getMeters()*100.0)/100.0;
|
||||
|
||||
/*if (vrtDist > tgtHeight) {
|
||||
// scale last step so that vrtDist ~ tgtHeight
|
||||
Position prevPos = path.pos.getPosition();
|
||||
TimePoint prevTime = path.pos.getTimePoint();
|
||||
double heightFrac = (tgtHeight - path.vrt) / (vrtDist - path.vrt);
|
||||
Position newPos = prevPos.translateGreatCircle(prevPos.getBearingGreatCircle(pathPos.getPosition()), prevPos.getDistance(pathPos.getPosition()).scale(heightFrac));
|
||||
TimePoint newTime = new MillisecondsTimePoint(Math.round(prevTime.asMillis() + (pathPos.getTimePoint().asMillis()-prevTime.asMillis())*heightFrac));
|
||||
pathPos = new TimedPositionImpl(newTime, newPos);
|
||||
posHeight = pathPos.getPosition().projectToLineThrough(posStart, bearVrt);
|
||||
}*/
|
||||
|
||||
// calculate horizontal side: left or right in reference to race course
|
||||
double posSide = 1;
|
||||
//double posBear = posWind.getBearing().getDegrees() - posEnd.getBearingGreatCircle(pathPos.getPosition()).getDegrees();
|
||||
Bearing posBear = posStart.getBearingGreatCircle(pathPos.getPosition());
|
||||
double posBearDiff = bearVrt.getDifferenceTo(posBear).getDegrees();
|
||||
if ((posBearDiff < 0.0)||(posBearDiff > 180.0)) {
|
||||
posSide = -1;
|
||||
} else if ((posBearDiff == 0.0)||(posBearDiff == 180.0)) {
|
||||
posSide = 0;
|
||||
}
|
||||
// calculate horizontal distance as distance of height-position to current position
|
||||
//double hrzDist = Math.round(posSide*posHeight.getDistance(pathPos.getPosition()).getMeters()*100.0)/100.0;
|
||||
double hrzDist = Math.round(posSide*posHeightTrgt.getDistance(pathPos.getPosition()).getMeters()*100.0)/100.0;
|
||||
|
||||
//System.out.println(""+hrzDist+", "+vrtDist+", "+pathPos.getPosition().getLatDeg()+", "+pathPos.getPosition().getLngDeg()+", "+posHeight.getLatDeg()+", "+posHeight.getLngDeg());
|
||||
|
||||
// extend path-string by step-direction
|
||||
String pathStr = path.path + nextDirection;
|
||||
char nextBaseDirection = this.getBaseDirection(nextDirection);
|
||||
|
||||
return (new PathCandidate(pathPos, vrtDist, hrzDist, turnCount, pathStr, nextBaseDirection, posWind));
|
||||
}
|
||||
|
||||
|
||||
// generate path candidates based on beat angles
|
||||
List<PathCandidate> getPathCandsBeatWind(PathCandidate path, long timeStep, long turnLoss, Position posStart, Position posEnd, double tgtHeight) {
|
||||
|
||||
List<PathCandidate> result = new ArrayList<PathCandidate>();
|
||||
PathCandidate newPathCand;
|
||||
|
||||
if (this.maxTurns > 0) {
|
||||
|
||||
char prevDirection = path.path.charAt(path.path.length()-1);
|
||||
if ((path.trn < this.maxTurns)||(this.isSameDirection(prevDirection, 'L'))) {
|
||||
newPathCand = getPathCandWind(path, 'L', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
}
|
||||
|
||||
if ((path.trn < this.maxTurns)||(this.isSameDirection(prevDirection, 'R'))) {
|
||||
newPathCand = getPathCandWind(path, 'R', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// step left
|
||||
newPathCand = getPathCandWind(path, 'L', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
|
||||
// step wide left
|
||||
//newPathCand = getPathCandWind(path, 'M', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
//result.add(newPathCand);
|
||||
|
||||
// step right
|
||||
newPathCand = getPathCandWind(path, 'R', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
result.add(newPathCand);
|
||||
|
||||
// step wide right
|
||||
//newPathCand = getPathCandWind(path, 'S', timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
//result.add(newPathCand);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> generateCandidate(List<PathCandidate> oldPaths, long timeStep, long turnLoss, Position posStart, Position posMiddle, Position posEnd, double tgtHeight) {
|
||||
|
||||
List<PathCandidate> newPathCands;
|
||||
List<PathCandidate> leftPaths = new ArrayList<PathCandidate>();
|
||||
List<PathCandidate> rightPaths = new ArrayList<PathCandidate>();
|
||||
for(PathCandidate curPath : oldPaths) {
|
||||
|
||||
newPathCands = this.getPathCandsBeatWind(curPath, timeStep, turnLoss, posStart, posEnd, tgtHeight);
|
||||
for (PathCandidate curNewPath : newPathCands) {
|
||||
// check whether path is *outside* regatta-area
|
||||
double distFromMiddleMeters = posMiddle.getDistance(curPath.pos.getPosition()).getMeters();
|
||||
if (distFromMiddleMeters > oobFact * tgtHeight) {
|
||||
continue; // ignore curPath
|
||||
}
|
||||
|
||||
if (curNewPath.sid == 'L') {
|
||||
leftPaths.add(curNewPath);
|
||||
} else if (curNewPath.sid == 'R') {
|
||||
rightPaths.add(curNewPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> newPaths = new Util.Pair<List<PathCandidate>,List<PathCandidate>>(leftPaths, rightPaths);
|
||||
return newPaths;
|
||||
}
|
||||
|
||||
|
||||
List<PathCandidate> filterCandidates(List<PathCandidate> allCands, double hrzBinWidth) {
|
||||
|
||||
boolean[] filterMap = new boolean[allCands.size()];
|
||||
|
||||
// sort candidates by horizontal distance
|
||||
Comparator<PathCandidate> sortHorizontal = new SortPathCandsHorizontally();
|
||||
Collections.sort(allCands, sortHorizontal);
|
||||
|
||||
// start scan with index 0
|
||||
int idxL = 0;
|
||||
int idxR = 0;
|
||||
|
||||
// for each candidate, check the neighborhoods and identify bad candidates
|
||||
for(int idx = 0; idx < allCands.size(); idx++) {
|
||||
|
||||
// current horizontal distance
|
||||
double hrzDist = allCands.get(idx).hrz;
|
||||
|
||||
// align left index
|
||||
while(Math.abs(hrzDist - allCands.get(idxL).hrz) > hrzBinWidth) {
|
||||
idxL++;
|
||||
}
|
||||
|
||||
// align right index
|
||||
boolean finished = false;
|
||||
while(!finished && (idxR < (allCands.size()-1))) {
|
||||
if (Math.abs(hrzDist - allCands.get(idxR+1).hrz) <= hrzBinWidth) {
|
||||
idxR++;
|
||||
} else {
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
// search maximum height
|
||||
// in neighborhood idxL, ..., idxR
|
||||
|
||||
// init max for search
|
||||
int vrtIdx = idxL;
|
||||
double vrtMax = allCands.get(vrtIdx).vrt;
|
||||
filterMap[vrtIdx] = false;
|
||||
|
||||
// evaluate remainder of neighborhood
|
||||
if (idxL < idxR) {
|
||||
for(int jdx = (idxL+1); jdx <= idxR; jdx++) {
|
||||
if (allCands.get(jdx).vrt > vrtMax) {
|
||||
// reset previous max candidate
|
||||
filterMap[vrtIdx] = true;
|
||||
// keep max height
|
||||
vrtMax = allCands.get(jdx).vrt;
|
||||
// keep max index
|
||||
vrtIdx = jdx;
|
||||
// set current max candidate
|
||||
filterMap[vrtIdx] = false;
|
||||
} else {
|
||||
filterMap[jdx] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // endfor each candidate
|
||||
|
||||
// collect all good candidates (i.e. filterMap == false)
|
||||
List<PathCandidate> filterCands = new ArrayList<PathCandidate>();
|
||||
for(int idx=0; idx < allCands.size(); idx++) {
|
||||
if (!filterMap[idx]) {
|
||||
filterCands.add(allCands.get(idx));
|
||||
}
|
||||
}
|
||||
|
||||
// return remaining good candidates
|
||||
return filterCands;
|
||||
}
|
||||
|
||||
|
||||
List<PathCandidate> filterIsochrone(List<PathCandidate> allCands, double hrzBinWidth) {
|
||||
|
||||
boolean[] filterMap = new boolean[allCands.size()];
|
||||
for(int idx = 0; idx < allCands.size(); idx++) {
|
||||
filterMap[idx] = true;
|
||||
}
|
||||
|
||||
// sort candidates by horizontal distance
|
||||
Comparator<PathCandidate> sortHorizontal = new SortPathCandsHorizontally();
|
||||
Collections.sort(allCands, sortHorizontal);
|
||||
|
||||
// start scan with index 0
|
||||
int idxL = 0;
|
||||
int idxR = 0;
|
||||
|
||||
// for each candidate, check the neighborhoods and identify bad candidates
|
||||
for(int idx = 0; idx < allCands.size(); idx++) {
|
||||
|
||||
// current horizontal distance
|
||||
double hrzDist = allCands.get(idx).hrz;
|
||||
|
||||
// align left index
|
||||
while(Math.abs(hrzDist - allCands.get(idxL).hrz) > hrzBinWidth) {
|
||||
idxL++;
|
||||
}
|
||||
|
||||
// align right index
|
||||
boolean finished = false;
|
||||
while(!finished && (idxR < (allCands.size()-1))) {
|
||||
if (Math.abs(hrzDist - allCands.get(idxR+1).hrz) <= hrzBinWidth) {
|
||||
idxR++;
|
||||
} else {
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
// search maximum height
|
||||
// in neighborhood idxL, ..., idxR
|
||||
|
||||
// init max for search
|
||||
ArrayList<Integer> vrtIdx = new ArrayList<Integer>();
|
||||
vrtIdx.add(idxL);
|
||||
double vrtMax = allCands.get(idxL).vrt;
|
||||
|
||||
// evaluate remainder of neighborhood
|
||||
if (idxL < idxR) {
|
||||
for(int jdx = (idxL+1); jdx <= idxR; jdx++) {
|
||||
if (allCands.get(jdx).vrt > vrtMax) {
|
||||
// keep max height
|
||||
vrtMax = allCands.get(jdx).vrt;
|
||||
// keep max index
|
||||
vrtIdx = new ArrayList<Integer>();
|
||||
vrtIdx.add(jdx);
|
||||
} else if (allCands.get(jdx).vrt == vrtMax) {
|
||||
// add further max indexes
|
||||
vrtIdx.add(jdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Integer jdx : vrtIdx) {
|
||||
filterMap[jdx] = false;
|
||||
}
|
||||
|
||||
} // endfor each candidate
|
||||
|
||||
// collect all good candidates (i.e. filterMap == false)
|
||||
List<PathCandidate> filterCands = new ArrayList<PathCandidate>();
|
||||
for(int idx=0; idx < allCands.size(); idx++) {
|
||||
if (!filterMap[idx]) {
|
||||
filterCands.add(allCands.get(idx));
|
||||
}
|
||||
}
|
||||
|
||||
// return remaining good candidates
|
||||
return filterCands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
WindFieldGenerator wf = this.parameters.getWindField();
|
||||
PolarDiagram pd = this.parameters.getBoatPolarDiagram();
|
||||
|
||||
Position startPos = this.parameters.getCourse().get(0);
|
||||
Position endPos = this.parameters.getCourse().get(1);
|
||||
|
||||
// test downwind: exchange start and end
|
||||
//Position startPos = this.parameters.getCourse().get(1);
|
||||
//Position endPos = this.parameters.getCourse().get(0);
|
||||
|
||||
TimePoint startTime = wf.getStartTime();// new MillisecondsTimePoint(0);
|
||||
List<TimedPositionWithSpeed> path = new ArrayList<TimedPositionWithSpeed>();
|
||||
|
||||
Position currentPosition = startPos;
|
||||
TimePoint currentTime = startTime;
|
||||
|
||||
Distance distStartEnd = startPos.getDistance(endPos);
|
||||
double distStartEndMeters = distStartEnd.getMeters();
|
||||
|
||||
Wind wndStart = wf.getWind(new TimedPositionWithSpeedImpl(startTime, startPos, null));
|
||||
logger.fine("wndStart speed:" + wndStart.getKnots() + " angle:" + wndStart.getBearing().getDegrees());
|
||||
pd.setWind(wndStart);
|
||||
Bearing bearVrt = startPos.getBearingGreatCircle(endPos);
|
||||
//Bearing bearHrz = bearVrt.add(new DegreeBearingImpl(90.0));
|
||||
Position middlePos = startPos.translateGreatCircle(bearVrt, distStartEnd.scale(0.5));
|
||||
|
||||
Bearing bearRCWind = wndStart.getBearing().getDifferenceTo(bearVrt);
|
||||
String legType = "downwind";
|
||||
this.upwindLeg = false;
|
||||
|
||||
if ((Math.abs(bearRCWind.getDegrees()) > 90.0)&&(Math.abs(bearRCWind.getDegrees()) < 270.0)) {
|
||||
legType = "upwind";
|
||||
this.upwindLeg = true;
|
||||
}
|
||||
|
||||
if (debugMsgOn) {
|
||||
System.out.println("start : "+startPos.getLatDeg()+", "+startPos.getLngDeg());
|
||||
System.out.println("middle: "+middlePos.getLatDeg()+", "+middlePos.getLngDeg());
|
||||
System.out.println("end : "+endPos.getLatDeg()+", "+endPos.getLngDeg());
|
||||
}
|
||||
logger.info("Leg Direction: "+legType);
|
||||
|
||||
long timeStep = wf.getTimeStep().asMillis()/2;
|
||||
if (!this.upwindLeg) {
|
||||
timeStep = timeStep / 2;
|
||||
}
|
||||
this.usedTimeStep = timeStep;
|
||||
logger.info("Time step :" + timeStep);
|
||||
long turnLoss = pd.getTurnLoss(); // 4000; // time lost when doing a turn
|
||||
if (!this.upwindLeg) {
|
||||
turnLoss = turnLoss / 2;
|
||||
}
|
||||
|
||||
// calculate initial position according to initPathStr
|
||||
PathCandidate initPath = new PathCandidate(new TimedPositionImpl(currentTime, currentPosition), 0.0, 0.0, 0, "0", '0', wndStart);
|
||||
if (initPathStr.length()>1) {
|
||||
char nextDirection = '0';
|
||||
for(int idx=1; idx<initPathStr.length(); idx++) {
|
||||
nextDirection = initPathStr.charAt(idx);
|
||||
PathCandidate newPathCand = getPathCandWind(initPath, nextDirection, timeStep, turnLoss, startPos, endPos, distStartEndMeters);
|
||||
initPath = newPathCand;
|
||||
}
|
||||
}
|
||||
List<PathCandidate> allPaths = new ArrayList<PathCandidate>();
|
||||
List<PathCandidate> trgPaths = new ArrayList<PathCandidate>();
|
||||
allPaths.add(initPath);
|
||||
|
||||
|
||||
TimedPosition tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, true, 'L').getA();
|
||||
double tstDist1 = startPos.getDistance(tstPosition.getPosition()).getMeters();
|
||||
tstPosition = this.getStep(new TimedPositionImpl(startTime, startPos), timeStep, turnLoss, true, 'R').getA();
|
||||
double tstDist2 = startPos.getDistance(tstPosition.getPosition()).getMeters();
|
||||
|
||||
double hrzBinSize = (tstDist1 + tstDist2)/3.0; // horizontal bin size in meters
|
||||
if (debugMsgOn) {
|
||||
System.out.println("Horizontal Bin Size: "+hrzBinSize);
|
||||
}
|
||||
|
||||
//double oobFact = 0.75; // out-of-bounds factor
|
||||
boolean reachedEnd = false;
|
||||
int addSteps = 0;
|
||||
int finalSteps = 0; // maximum number of additional steps after first target-path found
|
||||
|
||||
while ((!reachedEnd)||(addSteps<finalSteps)) {
|
||||
|
||||
if (reachedEnd) {
|
||||
addSteps++;
|
||||
}
|
||||
|
||||
// generate new candidates (inside regatta-area)
|
||||
Util.Pair<List<PathCandidate>,List<PathCandidate>> newPaths = this.generateCandidate(allPaths, timeStep, turnLoss, startPos, middlePos, endPos, distStartEndMeters);
|
||||
|
||||
|
||||
// select good candidates
|
||||
List<PathCandidate> leftPaths = this.filterCandidates(newPaths.getA(), hrzBinSize/2.0);
|
||||
List<PathCandidate> rightPaths = this.filterCandidates(newPaths.getB(), hrzBinSize/2.0);
|
||||
|
||||
List<PathCandidate> nextPaths = new ArrayList<PathCandidate> ();
|
||||
nextPaths.addAll(leftPaths);
|
||||
nextPaths.addAll(rightPaths);
|
||||
|
||||
allPaths = nextPaths;
|
||||
|
||||
if (this.gridStore) {
|
||||
|
||||
/*ArrayList<TimedPosition> isoChrone = new ArrayList<TimedPosition>();
|
||||
for(PathCand curCand : allPaths) {
|
||||
isoChrone.add(curCand.pos);
|
||||
}
|
||||
this.gridPositions.add(isoChrone);*/
|
||||
|
||||
this.gridPositions.add(allPaths);
|
||||
|
||||
List<PathCandidate> isocPaths = this.filterIsochrone(allPaths, hrzBinSize);
|
||||
this.isocPositions.add(isocPaths);
|
||||
|
||||
}
|
||||
|
||||
// check if there are still paths in the regatta-area
|
||||
if (allPaths.size() > 0) {
|
||||
|
||||
for(PathCandidate curPath : allPaths) {
|
||||
// terminate path-search if paths are found that are close enough to target
|
||||
//if ((curPath.vrt > distStartEndMeters)) {
|
||||
if ((curPath.vrt > 0.0)) {
|
||||
//logger.info("\ntPath: " + curPath.path + "\n Time: " + (Math.round((curPath.pos.getTimePoint().asMillis()-startTime.asMillis())/1000.0/60.0*10.0)/10.0)+", Height: "+curPath.vrt+" of "+(Math.round(startPos.getDistance(endPos).getMeters()*100.0)/100.0)+", Dist: "+curPath.hrz+"m ~ "+(Math.round(curPath.pos.getPosition().getDistance(endPos).getMeters()*100.0)/100.0)+"m");
|
||||
int curBin = (int)Math.round(Math.floor( (curPath.hrz + hrzBinSize/2.0) / hrzBinSize ));
|
||||
if ((Math.abs(curBin) <= 1)) {
|
||||
reachedEnd = true;
|
||||
trgPaths.add(curPath); // add path to list of target-paths
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// terminate path-search as no path inside regatta-area are left
|
||||
reachedEnd = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.gridStore) {
|
||||
|
||||
double distResolution = distStartEndMeters*0.01;
|
||||
BufferedWriter outputCSV;
|
||||
try {
|
||||
outputCSV = new BufferedWriter(new FileWriter(this.gridFile+"-grid.csv"));
|
||||
outputCSV.write("step; lat; lng; time; side; path; vrt\n");
|
||||
outputCSV.write("0; "+startPos.getLatDeg()+"; "+startPos.getLngDeg()+"; "+(startTime.asMillis()/1000)+"; 0; 0; "+(-distStartEndMeters)+"\n");
|
||||
outputCSV.write("0; "+endPos.getLatDeg()+"; "+endPos.getLngDeg()+"; "+(startTime.asMillis()/1000)+"; 0; 0; 0\n");
|
||||
int stepCount = 0;
|
||||
for(List<PathCandidate> isoChrone : this.gridPositions) {
|
||||
stepCount++;
|
||||
PathCandidate prevPos = null;
|
||||
for(PathCandidate isoPos : isoChrone) {
|
||||
|
||||
if (prevPos != null) {
|
||||
if (prevPos.pos.getPosition().getDistance(isoPos.pos.getPosition()).getMeters() < distResolution) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
String outStr = ""+stepCount+"; "+isoPos.pos.getPosition().getLatDeg()+"; "+isoPos.pos.getPosition().getLngDeg()+"; "+(isoPos.pos.getTimePoint().asMillis()/1000)+"; "+isoPos.sid;
|
||||
outStr += "; "+isoPos.path+"; "+isoPos.vrt;
|
||||
outStr += "\n";
|
||||
outputCSV.write(outStr);
|
||||
|
||||
prevPos = isoPos;
|
||||
}
|
||||
}
|
||||
outputCSV.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
outputCSV = new BufferedWriter(new FileWriter(this.gridFile+"-isoc.csv"));
|
||||
outputCSV.write("step; lat; lng; time; side; path; vrt\n");
|
||||
outputCSV.write("0; "+startPos.getLatDeg()+"; "+startPos.getLngDeg()+"; "+(startTime.asMillis()/1000)+"; 0; 0; "+(-distStartEndMeters)+"\n");
|
||||
outputCSV.write("0; "+endPos.getLatDeg()+"; "+endPos.getLngDeg()+"; "+(startTime.asMillis()/1000)+"; 0; 0; 0\n");
|
||||
int stepCount = 0;
|
||||
for(List<PathCandidate> isoChrone : this.isocPositions) {
|
||||
stepCount++;
|
||||
PathCandidate prevPos = null;
|
||||
for(PathCandidate isoPos : isoChrone) {
|
||||
|
||||
if (prevPos != null) {
|
||||
if (prevPos.pos.getPosition().getDistance(isoPos.pos.getPosition()).getMeters() < distResolution) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
String outStr = ""+stepCount+"; "+isoPos.pos.getPosition().getLatDeg()+"; "+isoPos.pos.getPosition().getLngDeg()+"; "+(isoPos.pos.getTimePoint().asMillis()/1000)+"; "+isoPos.sid;
|
||||
outStr += "; "+isoPos.path+"; "+isoPos.vrt;
|
||||
outStr += "\n";
|
||||
outputCSV.write(outStr);
|
||||
|
||||
prevPos = isoPos;
|
||||
}
|
||||
}
|
||||
outputCSV.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// if no target-paths were found, return empty path
|
||||
if (trgPaths.size() == 0) {
|
||||
//trgPaths = allPaths; // TODO: only for testing; remove lateron
|
||||
TimedPositionWithSpeed curPosition = new TimedPositionWithSpeedImpl(startTime, startPos, null);
|
||||
path.add(curPosition);
|
||||
return new PathImpl(path, wf); // return empty path
|
||||
}
|
||||
|
||||
// sort target-paths ascending by distance-to-target
|
||||
Collections.sort(trgPaths);
|
||||
|
||||
// debug output
|
||||
//if (debugMsgOn) {
|
||||
for(PathCandidate curPath : trgPaths) {
|
||||
logger.info("\nPath: " + curPath.path + "\n Time: " + (Math.round((curPath.pos.getTimePoint().asMillis()-startTime.asMillis())/1000.0/60.0*10.0)/10.0)+", Height: "+curPath.vrt+" of "+(Math.round(startPos.getDistance(endPos).getMeters()*100.0)/100.0)+", Dist: "+curPath.hrz+"m ~ "+(Math.round(curPath.pos.getPosition().getDistance(endPos).getMeters()*100.0)/100.0)+"m");
|
||||
//System.out.print(""+curPath.path+": "+curPath.pos.getTimePoint().asMillis()+", "+curPath.pos.getPosition().getLatDeg()+", "+curPath.pos.getPosition().getLngDeg()+", ");
|
||||
//System.out.println(" height:"+curPath.vrt+" of "+startPos.getDistance(endPos).getMeters()+", dist:"+curPath.hrz+" ~ "+curPath.pos.getPosition().getDistance(endPos));
|
||||
}
|
||||
//}
|
||||
|
||||
//
|
||||
// fill gwt-path
|
||||
//
|
||||
|
||||
// generate intermediate steps
|
||||
bestCand = trgPaths.get(0); // target-path ending closest to target
|
||||
TimedPositionWithSpeed curPosition = null;
|
||||
char nextDirection = '0';
|
||||
char prevDirection = '0';
|
||||
for(int step=0; step<(bestCand.path.length()-1); step++) {
|
||||
|
||||
nextDirection = bestCand.path.charAt(step);
|
||||
|
||||
if (nextDirection == '0') {
|
||||
|
||||
curPosition = new TimedPositionWithSpeedImpl(startTime, startPos, null);
|
||||
path.add(curPosition);
|
||||
|
||||
} else {
|
||||
|
||||
boolean sameBaseDirection = this.isSameDirection(prevDirection, nextDirection);
|
||||
TimedPosition newPosition = this.getStep(curPosition, timeStep, turnLoss, sameBaseDirection, nextDirection).getA();
|
||||
curPosition = new TimedPositionWithSpeedImpl(newPosition.getTimePoint(), newPosition.getPosition(), null);
|
||||
path.add(curPosition);
|
||||
|
||||
}
|
||||
|
||||
prevDirection = nextDirection;
|
||||
}
|
||||
|
||||
// add final position (rescaled before to end on height of target)
|
||||
path.add(new TimedPositionWithSpeedImpl(bestCand.pos.getTimePoint(), bestCand.pos.getPosition(), null));
|
||||
|
||||
return new PathImpl(path, wf);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+50
-127
@@ -7,10 +7,23 @@ 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.impl.DegreePosition;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class RectangularBoundary implements Boundary {
|
||||
/**
|
||||
* Implements the {@link Grid} interface by providing a grid of GPS-positions based on the plane approximation of the
|
||||
* earth and the corresponding index-calculation to associate an arbitrary GPS-position with the closest
|
||||
* grid-GPS-position.
|
||||
*
|
||||
* Since the grid has rectangular shape in the plane approximation, we call it rectangular grid. The plane approximation
|
||||
* allows for a simple index calculation based on CPU-light operations. If not aligned with North the grid gets slightly
|
||||
* distorted leading to asymmetries which may influence the accuracy of path calculations or optimizations.
|
||||
* Still, for typical race course diameters of up to 5 nautical miles, it is a very good and fast approximation.
|
||||
*
|
||||
* @author Christopher Ronnewinkel (D036654)
|
||||
*
|
||||
*/
|
||||
public class RectangularGrid implements Grid {
|
||||
|
||||
private static final long serialVersionUID = 3598121983120213464L;
|
||||
private Position rcStart; // start position of race course
|
||||
@@ -24,7 +37,7 @@ public class RectangularBoundary implements Boundary {
|
||||
private int borderX;
|
||||
|
||||
private Position northWest;
|
||||
//private Position southEast;
|
||||
// private Position southEast;
|
||||
private Position southWest;
|
||||
private Position northEast;
|
||||
|
||||
@@ -43,20 +56,17 @@ public class RectangularBoundary implements Boundary {
|
||||
|
||||
double tolerance;
|
||||
|
||||
public RectangularBoundary(Position p1, Position p2, double tlr) {
|
||||
|
||||
// System.out.println("Start:"+p1);
|
||||
// System.out.println("End :"+p2);
|
||||
public RectangularGrid(Position p1, Position p2) {
|
||||
|
||||
rcStart = p1;
|
||||
rcEnd = p2;
|
||||
|
||||
tolerance = tlr;
|
||||
tolerance = 0.1;
|
||||
|
||||
north = p1.getBearingGreatCircle(p2);
|
||||
south = north.reverse();
|
||||
east = north.add(TRUEEAST);
|
||||
west = north.add(TRUEWEST);
|
||||
east = north.add(relativeEast);
|
||||
west = north.add(relativeWest);
|
||||
|
||||
appHeight = p1.getDistance(p2);
|
||||
appWidth = appHeight.scale(2);
|
||||
@@ -65,40 +75,21 @@ public class RectangularBoundary implements Boundary {
|
||||
appNorthWest = p2.translateGreatCircle(west, appHeight);
|
||||
appNorthEast = p2.translateGreatCircle(east, appHeight);
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
// diag1 = diag1.reverse();
|
||||
// southEast = appSouthEast.translateGreatCircle(diag1, diag.scale(tolerance));
|
||||
Bearing diag2 = appSouthWest.getBearingGreatCircle(appNorthEast);
|
||||
northEast = appNorthEast.translateGreatCircle(diag2, diag.scale(tolerance));
|
||||
diag2 = diag2.reverse();
|
||||
southWest = appSouthWest.translateGreatCircle(diag2, diag.scale(tolerance));
|
||||
}
|
||||
|
||||
public RectangularBoundary(Position p1, Position p2) {
|
||||
|
||||
this(p1, p2, 0.1);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Position> getCorners() {
|
||||
|
||||
@@ -113,7 +104,7 @@ public class RectangularBoundary implements Boundary {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWithinBoundaries(Position p) {
|
||||
public boolean inBounds(Position p) {
|
||||
|
||||
Position northProjection = p.projectToLineThrough(northWest, getEast());
|
||||
Position southProjection = p.projectToLineThrough(southWest, getEast());
|
||||
@@ -131,14 +122,14 @@ public class RectangularBoundary implements Boundary {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position[][] extractGrid(int hPoints, int vPoints, int borderY, int borderX) {
|
||||
public Position[][] generatePositions(int hPoints, int vPoints, int borderY, int borderX) {
|
||||
|
||||
this.vPoints = vPoints;
|
||||
this.hPoints = hPoints;
|
||||
|
||||
this.borderY = borderY;
|
||||
this.borderX = borderX;
|
||||
|
||||
|
||||
double xscale = 1.5;
|
||||
|
||||
double alat = (rcEnd.getLatDeg() + rcStart.getLatDeg()) / 2.;
|
||||
@@ -170,11 +161,9 @@ public class RectangularBoundary implements Boundary {
|
||||
nHor[0] = nscHor[0];
|
||||
nHor[1] = nscHor[1] / lngScale;
|
||||
|
||||
// System.out.println("LngScale:"+lngScale+", Diff.Vrt:"+dVrt);
|
||||
Position[][] grid = new Position[vPoints+2*borderY][hPoints+2*borderX];
|
||||
Position[][] grid = new Position[vPoints + 2 * borderY][hPoints + 2 * borderX];
|
||||
Position pv;
|
||||
for (int i = -borderY; i < (vPoints+borderY); i++) {
|
||||
// System.out.print("nrow "+i+": ");
|
||||
for (int i = -borderY; i < (vPoints + borderY); i++) {
|
||||
|
||||
if (i == 0) {
|
||||
pv = rcStart;
|
||||
@@ -187,41 +176,32 @@ public class RectangularBoundary implements Boundary {
|
||||
|
||||
int j = 0;
|
||||
// left side
|
||||
while (j < (hPoints+2*borderX) / 2) {
|
||||
grid[i+borderY][j] = new DegreePosition(pv.getLatDeg() - ((hPoints + 2*borderX - 1) / 2. - j) / (hPoints - 1) * nHor[0]
|
||||
* xscale * lscVrt, pv.getLngDeg() - ((hPoints + 2*borderX - 1) / 2. - j) / (hPoints - 1) * nHor[1] * xscale
|
||||
* lscVrt);
|
||||
// System.out.print(""+grid[i][j]+"("+((hPoints-1)/2.-j)+"), ");
|
||||
while (j < (hPoints + 2 * borderX) / 2) {
|
||||
grid[i + borderY][j] = new DegreePosition(pv.getLatDeg() - ((hPoints + 2 * borderX - 1) / 2. - j)
|
||||
/ (hPoints - 1) * nHor[0] * xscale * lscVrt, pv.getLngDeg()
|
||||
- ((hPoints + 2 * borderX - 1) / 2. - j) / (hPoints - 1) * nHor[1] * xscale * lscVrt);
|
||||
j++;
|
||||
}
|
||||
|
||||
// middle
|
||||
if ((hPoints+2*borderX) % 2 == 1) {
|
||||
grid[i+borderY][j] = pv;
|
||||
// System.out.print(""+grid[i][j]+", ");
|
||||
if ((hPoints + 2 * borderX) % 2 == 1) {
|
||||
grid[i + borderY][j] = pv;
|
||||
j++;
|
||||
}
|
||||
|
||||
// right side
|
||||
while (j < (hPoints+2*borderX)) {
|
||||
grid[i+borderY][j] = new DegreePosition(pv.getLatDeg() + (j - (hPoints + 2*borderX - 1) / 2.) / (hPoints - 1) * nHor[0]
|
||||
* xscale * lscVrt, pv.getLngDeg() + (j - (hPoints + 2*borderX - 1) / 2.) / (hPoints - 1) * nHor[1] * xscale
|
||||
* lscVrt);
|
||||
// System.out.print(""+grid[i][j]+"("+(j-(hPoints-1)/2.)+"), ");
|
||||
while (j < (hPoints + 2 * borderX)) {
|
||||
grid[i + borderY][j] = new DegreePosition(pv.getLatDeg() + (j - (hPoints + 2 * borderX - 1) / 2.)
|
||||
/ (hPoints - 1) * nHor[0] * xscale * lscVrt, pv.getLngDeg()
|
||||
+ (j - (hPoints + 2 * borderX - 1) / 2.) / (hPoints - 1) * nHor[1] * xscale * lscVrt);
|
||||
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 Util.Pair<Integer, Integer> getGridIndex(Position x) {
|
||||
public Util.Pair<Integer, Integer> getIndex(Position x) {
|
||||
|
||||
double[] scX = new double[2];
|
||||
scX[0] = x.getLatDeg() - rcStart.getLatDeg();
|
||||
@@ -229,64 +209,35 @@ public class RectangularBoundary implements Boundary {
|
||||
|
||||
double sPrd = scX[0] * nvHor[0] + scX[1] * nvHor[1];
|
||||
|
||||
int vIdx = Math.min(Math.max(-this.borderY, (int) Math.round(scX[0] * nvVrt[0] + scX[1] * nvVrt[1])), vPoints - 1 + this.borderY);
|
||||
int hIdx = Math.min(Math.max(-this.borderX, (int) Math.round(sPrd + (hPoints - 1) / 2.)), hPoints - 1 + this.borderX);
|
||||
int vIdx = Math.min(Math.max(-this.borderY, (int) Math.round(scX[0] * nvVrt[0] + scX[1] * nvVrt[1])), vPoints
|
||||
- 1 + this.borderY);
|
||||
int hIdx = Math.min(Math.max(-this.borderX, (int) Math.round(sPrd + (hPoints - 1) / 2.)), hPoints - 1
|
||||
+ this.borderX);
|
||||
|
||||
// System.out.println("getGridIndex: "+vIdx+","+hIdx+"("+vPoints+","+hPoints+")");
|
||||
return new Util.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 int getResY() {
|
||||
return this.vPoints;
|
||||
return this.vPoints;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getResX() {
|
||||
return this.hPoints;
|
||||
return this.hPoints;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getBorderY() {
|
||||
return this.borderY;
|
||||
return this.borderY;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getBorderX() {
|
||||
return this.borderX;
|
||||
return this.borderX;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bearing getNorth() {
|
||||
return north;
|
||||
@@ -317,32 +268,4 @@ public class RectangularBoundary implements Boundary {
|
||||
return appHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Double> getRelativeCoordinates(Position p) {
|
||||
if (!isWithinBoundaries(p))
|
||||
return null;
|
||||
|
||||
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());
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRelativePoint(double x, double y) {
|
||||
|
||||
Position point = appSouthWest;
|
||||
point = point.translateGreatCircle(getEast(), getWidth().scale(x));
|
||||
point = point.translateGreatCircle(getNorth(), getHeight().scale(y));
|
||||
return point;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTolerance() {
|
||||
return tolerance;
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -12,7 +12,7 @@ import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.RaceProperties;
|
||||
import com.sap.sailing.simulator.SailingSimulator;
|
||||
@@ -79,7 +79,7 @@ public class SailingSimulatorImpl implements SailingSimulator {
|
||||
LOGGER.info("showOpportunist: "+this.simulationParameters.showOpportunist());
|
||||
|
||||
if (gridArea != null) {
|
||||
Boundary bd = new RectangularBoundary(gridArea[0], gridArea[1], 0.1);
|
||||
Grid bd = new CurvedGrid(gridArea[0], gridArea[1]);
|
||||
|
||||
// set base wind bearing
|
||||
wf.getWindParameters().baseWindBearing += bd.getSouth().getDegrees();
|
||||
@@ -103,7 +103,7 @@ public class SailingSimulatorImpl implements SailingSimulator {
|
||||
}
|
||||
|
||||
wf.setBoundary(bd);
|
||||
Position[][] positionGrid = bd.extractGrid(gridRes[0], gridRes[1], gridRes[2], gridRes[3]);
|
||||
Position[][] positionGrid = bd.generatePositions(gridRes[0], gridRes[1], gridRes[2], gridRes[3]);
|
||||
wf.setPositionGrid(positionGrid);
|
||||
wf.generate(wf.getStartTime(), wf.getEndTime(), wf.getTimeStep());
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class SailingSimulatorImpl implements SailingSimulator {
|
||||
//
|
||||
|
||||
// get instance of heuristic searcher
|
||||
PathGeneratorTreeGrowWind3 genTreeGrow = new PathGeneratorTreeGrowWind3(this.simulationParameters);
|
||||
PathGeneratorTreeGrowWind genTreeGrow = new PathGeneratorTreeGrowWind(this.simulationParameters);
|
||||
|
||||
// search best left-starting 1-turner
|
||||
genTreeGrow.setEvaluationParameters("L", 1, null);
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.PolarDiagram;
|
||||
import com.sap.sailing.simulator.SimulationParameters;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
|
||||
@@ -64,8 +64,8 @@ public class SimulationParametersImpl implements SimulationParameters {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boundary getBoundaries() {
|
||||
return windField.getBoundaries();
|
||||
public Grid getGrid() {
|
||||
return windField.getGrid();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -373,7 +373,7 @@ public class SimulatorUtils {
|
||||
Map<String, Path> paths = new HashMap<String, Path>();
|
||||
|
||||
// get instance of heuristic searcher
|
||||
PathGeneratorTreeGrowWind3 genTreeGrow = new PathGeneratorTreeGrowWind3(parameters);
|
||||
PathGeneratorTreeGrowWind genTreeGrow = new PathGeneratorTreeGrowWind(parameters);
|
||||
|
||||
// search best left-starting 1-turner
|
||||
genTreeGrow.setEvaluationParameters("L", 1, null);
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package com.sap.sailing.simulator.windfield;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
|
||||
@@ -11,7 +11,7 @@ public interface WindField extends Serializable {
|
||||
|
||||
public Wind getWind(TimedPosition coordinates);
|
||||
|
||||
public Boundary getBoundaries();
|
||||
public Grid getGrid();
|
||||
|
||||
public Path getLine(TimedPosition seed, boolean forward);
|
||||
|
||||
|
||||
+2
-2
@@ -7,13 +7,13 @@ import java.io.Serializable;
|
||||
import com.sap.sailing.domain.common.Duration;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
|
||||
public interface WindFieldGenerator extends WindField, Serializable {
|
||||
|
||||
public WindControlParameters getWindParameters();
|
||||
|
||||
public void setBoundary(Boundary boundary);
|
||||
public void setBoundary(Grid boundary);
|
||||
|
||||
public void setPositionGrid(Position[][] positions);
|
||||
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
package com.sap.sailing.simulator.windfield;
|
||||
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.windfield.impl.WindFieldGeneratorFactoryImpl;
|
||||
|
||||
public interface WindFieldGeneratorFactory {
|
||||
|
||||
static WindFieldGeneratorFactory INSTANCE = new WindFieldGeneratorFactoryImpl();
|
||||
|
||||
public WindFieldGenerator createWindFieldGenerator(String patternName, Boundary boundary,
|
||||
public WindFieldGenerator createWindFieldGenerator(String patternName, Grid boundary,
|
||||
WindControlParameters windParameters);
|
||||
}
|
||||
+5
-7
@@ -14,7 +14,7 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.windfield.WindControlParameters;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
|
||||
@@ -32,7 +32,7 @@ public class WindFieldGeneratorBlastImpl extends WindFieldGeneratorImpl implemen
|
||||
private double blastSizeProbability = 70;
|
||||
private double blastEdgeProbability = 30;
|
||||
private double blastBearingMean = 0;
|
||||
private double blastBearingVar = 8;
|
||||
private double blastBearingVar = 6;
|
||||
private double defaultWindSpeed = 0;
|
||||
private double defaultWindBearing = 0;
|
||||
private SpeedWithBearing defaultSpeedWithBearing;
|
||||
@@ -44,7 +44,7 @@ public class WindFieldGeneratorBlastImpl extends WindFieldGeneratorImpl implemen
|
||||
|
||||
private static Logger logger = Logger.getLogger(WindFieldGeneratorBlastImpl.class.getName());
|
||||
|
||||
public WindFieldGeneratorBlastImpl(Boundary boundary, WindControlParameters windParameters) {
|
||||
public WindFieldGeneratorBlastImpl(Grid boundary, WindControlParameters windParameters) {
|
||||
super(boundary, windParameters);
|
||||
}
|
||||
|
||||
@@ -164,8 +164,7 @@ public class WindFieldGeneratorBlastImpl extends WindFieldGeneratorImpl implemen
|
||||
//System.out.println("blast speed mean: "+bSpeedMean+" var: "+bSpeedVar);
|
||||
//return NormalGen.nextDouble(new LFSR113("BlastSpeedStream"), bSpeedMean, bSpeedVar);
|
||||
RandomStream speedStream = windParameters.getBlastRandomStreamManager().getRandomStream(BlastRandomSeedManagerImpl.BlastStream.SPEED.name());
|
||||
return NormalGen.nextDouble(speedStream, bSpeedMean, bSpeedVar);
|
||||
|
||||
return Math.max(0.5*bSpeedMean, Math.min(1.5*bSpeedMean, NormalGen.nextDouble(speedStream, bSpeedMean, bSpeedVar)));
|
||||
}
|
||||
|
||||
private int getBlastSize() {
|
||||
@@ -177,8 +176,7 @@ public class WindFieldGeneratorBlastImpl extends WindFieldGeneratorImpl implemen
|
||||
private double getBlastAngle() {
|
||||
//return NormalGen.nextDouble(new LFSR113("BlastAngleStream"), blastBearingMean, blastBearingVar);
|
||||
RandomStream bearingStream = windParameters.getBlastRandomStreamManager().getRandomStream(BlastRandomSeedManagerImpl.BlastStream.BEARING.name());
|
||||
return NormalGen.nextDouble(bearingStream, blastBearingMean, blastBearingVar);
|
||||
|
||||
return Math.max(-1.5*blastBearingVar, Math.min(1.5*blastBearingVar, NormalGen.nextDouble(bearingStream, blastBearingMean, blastBearingVar)));
|
||||
}
|
||||
|
||||
private SpeedWithBearing getSpeedWithBearing(TimedPosition timedPosition) {
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@ import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.windfield.WindControlParameters;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
|
||||
@@ -18,14 +18,14 @@ public class WindFieldGeneratorCombined extends WindFieldGeneratorImpl implement
|
||||
private WindFieldGeneratorBlastImpl blastGen;
|
||||
private WindFieldGeneratorOscillationImpl oscillationGen;
|
||||
|
||||
public WindFieldGeneratorCombined(Boundary boundary, WindControlParameters windParameters) {
|
||||
public WindFieldGeneratorCombined(Grid boundary, WindControlParameters windParameters) {
|
||||
super(boundary, windParameters);
|
||||
blastGen = new WindFieldGeneratorBlastImpl(boundary, windParameters);
|
||||
oscillationGen = new WindFieldGeneratorOscillationImpl(boundary, windParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoundary(Boundary boundary) {
|
||||
public void setBoundary(Grid boundary) {
|
||||
|
||||
super.setBoundary(boundary);
|
||||
blastGen.setBoundary(boundary);
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.simulator.windfield.impl;
|
||||
|
||||
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.windfield.WindControlParameters;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGeneratorFactory;
|
||||
@@ -9,7 +9,7 @@ import com.sap.sailing.simulator.windfield.WindFieldGeneratorFactory;
|
||||
public class WindFieldGeneratorFactoryImpl implements WindFieldGeneratorFactory {
|
||||
|
||||
@Override
|
||||
public WindFieldGenerator createWindFieldGenerator(String patternName, Boundary boundary,
|
||||
public WindFieldGenerator createWindFieldGenerator(String patternName, Grid boundary,
|
||||
WindControlParameters windParameters) {
|
||||
if (patternName.equals("BLASTS")) {
|
||||
return new WindFieldGeneratorBlastImpl(boundary, windParameters);
|
||||
|
||||
+7
-7
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
@@ -27,7 +27,7 @@ import com.sap.sse.common.Util;
|
||||
public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
|
||||
private static final long serialVersionUID = -6366698648104363491L;
|
||||
protected Boundary boundary;
|
||||
protected Grid boundary;
|
||||
protected WindControlParameters windParameters;
|
||||
protected Position[][] positions;
|
||||
|
||||
@@ -46,7 +46,7 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
|
||||
private static Logger logger = Logger.getLogger("com.sap.sailing.windfield");
|
||||
|
||||
public WindFieldGeneratorImpl(Boundary boundary, WindControlParameters windParameters) {
|
||||
public WindFieldGeneratorImpl(Grid boundary, WindControlParameters windParameters) {
|
||||
this.boundary = boundary;
|
||||
this.windParameters = windParameters;
|
||||
this.positions = null;
|
||||
@@ -58,7 +58,7 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoundary(Boundary boundary) {
|
||||
public void setBoundary(Grid boundary) {
|
||||
this.boundary = boundary;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boundary getBoundaries() {
|
||||
public Grid getGrid() {
|
||||
return boundary;
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
LinkedList<TimedPositionWithSpeed> path = new LinkedList<TimedPositionWithSpeed>();
|
||||
path.add(new TimedPositionWithSpeedImpl(currentTime, currentPosition, null));
|
||||
|
||||
while(boundary.isWithinBoundaries(currentPosition)) {
|
||||
while(boundary.inBounds(currentPosition)) {
|
||||
Wind currentWind = this.getWind(new TimedPositionImpl(startTime, currentPosition));
|
||||
TimePoint middleTime = currentTime.plus(timeStep/2);
|
||||
Position middlePosition;
|
||||
@@ -138,7 +138,7 @@ public abstract class WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
}
|
||||
|
||||
public Util.Pair<Integer, Integer> getPositionIndex(Position p) {
|
||||
Util.Pair<Integer, Integer> gIdx = boundary.getGridIndex(p);
|
||||
Util.Pair<Integer, Integer> gIdx = boundary.getIndex(p);
|
||||
if ((gIdx.getA() != null) && (gIdx.getB() != null)) {
|
||||
return gIdx;
|
||||
} else {
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.Path;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.TimedPositionWithSpeed;
|
||||
@@ -30,7 +30,7 @@ public class WindFieldGeneratorMeasured extends WindFieldGeneratorImpl implement
|
||||
// super();
|
||||
// }
|
||||
|
||||
public WindFieldGeneratorMeasured(Boundary boundary, WindControlParameters windParameters) {
|
||||
public WindFieldGeneratorMeasured(Grid boundary, WindControlParameters windParameters) {
|
||||
super(boundary, windParameters);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.simulator.Boundary;
|
||||
import com.sap.sailing.simulator.Grid;
|
||||
import com.sap.sailing.simulator.TimedPosition;
|
||||
import com.sap.sailing.simulator.windfield.WindControlParameters;
|
||||
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
|
||||
@@ -32,7 +32,7 @@ public class WindFieldGeneratorOscillationImpl extends WindFieldGeneratorImpl im
|
||||
|
||||
private static Logger logger = Logger.getLogger(WindFieldGeneratorOscillationImpl.class.getName());
|
||||
|
||||
public WindFieldGeneratorOscillationImpl(Boundary boundary, WindControlParameters windParameters) {
|
||||
public WindFieldGeneratorOscillationImpl(Grid boundary, WindControlParameters windParameters) {
|
||||
super(boundary, windParameters);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user