mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
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:
@@ -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();
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user