Calculation of upwind downwind leg given a boat, wind and next mark now works. created GeometryUtils class

Can accurately calculate if a boat is going upwind or downward using a line function for the wind vector from the gate and the boat position from the gate.

Requires knowledge of the next mark which requires the boat to have passed a mark. This could be fixed by extracting the leg number from the race status packet and mapping these to gates in an initalisation step

tags: #story[956]
This commit is contained in:
William Muir
2017-05-24 14:57:22 +12:00
parent 89464e033e
commit 1cac7cc189
7 changed files with 200 additions and 30 deletions
+1
View File
@@ -67,6 +67,7 @@ public class App extends Application {
else { else {
// sr = new StreamReceiver("localhost", 4949, "RaceStream"); // sr = new StreamReceiver("localhost", 4949, "RaceStream");
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
// sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream");
} }
sr.start(); sr.start();
+63
View File
@@ -0,0 +1,63 @@
package seng302;
import javafx.geometry.Point2D;
/**
* A Class for performing geometric calculations on the canvas
* Created by wmu16 on 24/05/17.
*/
public final class GeometryUtils {
/**
* Performs the line function on two points of a line and a test point to test which side of the line that point is
* on. If the return value is
* return 1, then the point is on one side of the line,
* return -1 then the point is on the other side of the line
* return 0 then the point is exactly on the line.
* @param linePoint1 One point of the line
* @param linePoint2 Second point of the line
* @param testPoint The point to test with this line
* @return A return value indicating which side of the line the point is on
*/
public static Integer lineFunction(Point2D linePoint1, Point2D linePoint2, Point2D testPoint) {
Double x = testPoint.getX();
Double y = testPoint.getY();
Double x1 = linePoint1.getX();
Double y1 = linePoint1.getY();
Double x2 = linePoint2.getX();
Double y2 = linePoint2.getY();
Double result = (x - x1)*(y2 - y1) - (y - y1)*(x2 - x1); //Line function
if (result > 0) {
return 1;
}
else if (result < 0) {
return -1;
}
else {
return 0;
}
}
/**
* Given a point and a vector (angle and vector length) Will create a new point, that vector away from the origin
* point
* @param originPoint The point with which to use as the base for our vector addition
* @param angleInDeg (DEGREES) The angle at which our new point is being created (in degrees!)
* @param vectorLength The length out on this angle from the origin point to create the new point
* @return a Point2D
*/
public static Point2D makeArbitraryVectorPoint(Point2D originPoint, Double angleInDeg, Double vectorLength) {
Double endPointX = originPoint.getX() + vectorLength * Math.cos(Math.toRadians(angleInDeg));
Double endPointY = originPoint.getY() + vectorLength * Math.sin(Math.toRadians(angleInDeg));
return new Point2D(endPointX, endPointY);
}
}
@@ -435,7 +435,7 @@ public class CanvasController {
return findScaledXY (unscaled.getLatitude(), unscaled.getLongitude()); return findScaledXY (unscaled.getLatitude(), unscaled.getLongitude());
} }
private Point2D findScaledXY (double unscaledLat, double unscaledLon) { public Point2D findScaledXY (double unscaledLat, double unscaledLon) {
double distanceFromReference; double distanceFromReference;
double angleFromReference; double angleFromReference;
int xAxisLocation = (int) referencePointX; int xAxisLocation = (int) referencePointX;
@@ -468,4 +468,8 @@ public class CanvasController {
List<BoatGroup> getBoatGroups() { List<BoatGroup> getBoatGroups() {
return boatGroups; return boatGroups;
} }
List<MarkGroup> getMarkGroups() {
return markGroups;
}
} }
@@ -26,6 +26,9 @@ import seng302.controllers.annotations.ImportantAnnotationController;
import seng302.controllers.annotations.ImportantAnnotationDelegate; import seng302.controllers.annotations.ImportantAnnotationDelegate;
import seng302.controllers.annotations.ImportantAnnotationsState; import seng302.controllers.annotations.ImportantAnnotationsState;
import seng302.models.*; import seng302.models.*;
import seng302.models.mark.GateMark;
import seng302.models.mark.Mark;
import seng302.models.mark.MarkGroup;
import seng302.models.stream.StreamParser; import seng302.models.stream.StreamParser;
import java.io.IOException; import java.io.IOException;
@@ -185,14 +188,29 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
for (Yacht yacht : StreamParser.getBoatsPos().values()) { for (Yacht yacht : StreamParser.getBoatsPos().values()) {
if (yacht.getLastMarkRounded() != null) {
System.out.println("\n\nboat: " + yacht.getBoatName());
System.out.println("last Mark: " + yacht.getLastMarkRounded().getName());
}
if (yacht.getNextMark() != null){ if (yacht.getNextMark() != null){
System.out.println("next Mark: " + yacht.getNextMark().getName()); System.out.println("next Mark: " + yacht.getNextMark().getName());
for (BoatGroup bg : includedCanvasController.getBoatGroups()) { for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
bg.calculateLegDirection();
Boolean isUpwindLeg = null;
// Can only calc leg direction if there is a next mark and it is a gate mark
Mark nextMark = bg.getBoat().getNextMark();
if (!(nextMark == null || !(nextMark instanceof GateMark))) {
isUpwindLeg = bg.isUpwindLeg(includedCanvasController);
}
for (MarkGroup mg : includedCanvasController.getMarkGroups()) {
if (mg.getMainMark().equals(nextMark)) {
}
}
if (isUpwindLeg != null) {
if (isUpwindLeg) {
}
}
} }
} }
+39 -24
View File
@@ -12,7 +12,11 @@ import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon; import javafx.scene.shape.Polygon;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
import seng302.GeometryUtils;
import seng302.controllers.CanvasController;
import seng302.models.mark.GateMark;
import seng302.models.mark.Mark; import seng302.models.mark.Mark;
import seng302.models.mark.SingleMark;
import seng302.models.stream.StreamParser; import seng302.models.stream.StreamParser;
import java.text.DateFormat; import java.text.DateFormat;
@@ -364,33 +368,44 @@ public class BoatGroup extends Group {
} }
public void calculateLegDirection() { /**
Mark lastMark = boat.getLastMarkRounded(); * This function works out if a boat is going upwind or down wind. It looks at the boats current position, the next
* gates position and the current wind
* If bot the wind vector from the next gate and the boat from the next gate lay on the same side, then the boat is
* going up wind, if they are on different sides of the gate, then the boat is going downwind
* @param canvasController
*/
public Boolean isUpwindLeg(CanvasController canvasController) {
Mark nextMark = boat.getNextMark(); Mark nextMark = boat.getNextMark();
if (lastMark == null || nextMark == null) {
return; Double windAngle = StreamParser.getWindDirection();
GateMark thisGateMark = (GateMark) nextMark;
SingleMark nextMark1 = thisGateMark.getSingleMark1();
SingleMark nextMark2 = thisGateMark.getSingleMark2();
Point2D nextMarkPoint1 = canvasController.findScaledXY(nextMark1.getLatitude(), nextMark1.getLongitude());
Point2D nextMarkPoint2 = canvasController.findScaledXY(nextMark2.getLatitude(), nextMark2.getLongitude());
Point2D boatCurrentPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
Point2D windTestPoint = GeometryUtils.makeArbitraryVectorPoint(nextMarkPoint1, windAngle, 10d);
Integer boatLineFuncResult = GeometryUtils.lineFunction(nextMarkPoint1, nextMarkPoint2, boatCurrentPoint);
Integer windLineFuncResult = GeometryUtils.lineFunction(nextMarkPoint1, nextMarkPoint2, windTestPoint);
/*
If both the wind vector from the gate and the boat from the gate are on the same side of that gate, then the
boat is travelling into the wind. thus upwind. Otherwise if they are on different sides, then the boat is going
with the wind.
*/
System.out.println("Boat Line func result: " + boatLineFuncResult);
System.out.println("Wind Line func result: " + windLineFuncResult);
if (boatLineFuncResult == windLineFuncResult) {
return true;
} else {
return false;
} }
Double windDirection = StreamParser.getWindDirection();
Double arbitraryDistance = 10d;
Point2D lastMarkMidPoint = new Point2D(lastMark.getLatitude(), lastMark.getLongitude());
Point2D nextMarkMidPoint = new Point2D(nextMark.getLatitude(), nextMark.getLongitude());
Double windDirX = lastMarkMidPoint.getX() + (lastMarkMidPoint.getX() + arbitraryDistance -lastMarkMidPoint.getX())*Math.cos(windDirection) - (lastMarkMidPoint.getY() + arbitraryDistance -lastMarkMidPoint.getY())*Math.sin(windDirection);
Double windDirY = lastMarkMidPoint.getY() + (lastMarkMidPoint.getX() + arbitraryDistance -lastMarkMidPoint.getX())*Math.sin(windDirection) + (lastMarkMidPoint.getY() + arbitraryDistance -lastMarkMidPoint.getY())*Math.cos(windDirection);
Point2D windDirPoint = new Point2D(windDirX, windDirY);
Double angle = lastMarkMidPoint.angle(nextMarkMidPoint, windDirPoint);
if (angle <= 90) {
System.out.println(lastMark.getName() + " is downwind");
System.out.println(nextMark.getName() + " is upwind");
}
// if (lastMarkMidPoint.angle(nextMarkMidPoint, windDirPoint) <= 90) {
// boat.getNextMark().s
// }
} }
@@ -161,4 +161,8 @@ public class MarkGroup extends Group {
idArray[i++] = mark.getId(); idArray[i++] = mark.getId();
return idArray; return idArray;
} }
public Mark getMainMark() {
return mainMark;
}
} }
+65
View File
@@ -0,0 +1,65 @@
package seng302;
import javafx.geometry.Point2D;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test Class for the GeometryUtils class
* Created by wmu16 on 24/05/17.
*/
public class TestGeoUtils {
//Line in x = y
private Point2D linePoint1 = new Point2D(0, 0);
private Point2D linePoint2 = new Point2D(1, 1);
//Point below x = y
private Point2D arbitraryPoint1 = new Point2D(1, 0);
//Point above x = y
private Point2D arbitraryPoint2 = new Point2D(0, 1);
//Point on x = y
private Point2D arbitraryPoint3 = new Point2D(2, 2);
@Before
public void setUp() throws Exception {
}
@Test
public void testLineFunction() {
Integer lineFunctionResult1 = GeometryUtils.lineFunction(linePoint1, linePoint2, arbitraryPoint1);
Integer lineFunctionResult2 = GeometryUtils.lineFunction(linePoint1, linePoint2, arbitraryPoint2);
Integer lineFunctionResult3 = GeometryUtils.lineFunction(linePoint1, linePoint2, arbitraryPoint3);
//Point1 and Point2 are on opposite sides
assertEquals(Math.abs(lineFunctionResult1), Math.abs(lineFunctionResult2));
assertNotEquals(lineFunctionResult1, lineFunctionResult2);
//Point3 is on the line
assertEquals((long) lineFunctionResult3, 0L);
}
@Test
public void testMakeArbitraryVectorPoint() {
//Make a point (1,0) from point (0,0)
Point2D newPoint = GeometryUtils.makeArbitraryVectorPoint(linePoint1, 0d, 1d);
Point2D expected = new Point2D(1,0);
assertEquals(expected.getX(), newPoint.getX(), 1E-6);
assertEquals(expected.getY(), newPoint.getY(), 1E-6);
newPoint = GeometryUtils.makeArbitraryVectorPoint(linePoint1, 90d, 1d);
expected = new Point2D(0, 1);
assertEquals(expected.getX(), newPoint.getX(), 1E-6);
assertEquals(expected.getY(), newPoint.getY(), 1E-6);
}
}