From 62752c142a3842a3518ee271b0a7702457284ece Mon Sep 17 00:00:00 2001 From: hba56 Date: Mon, 7 Aug 2017 12:47:55 +1200 Subject: [PATCH 1/4] building blocks for drawing the race line around the course #story[1087] --- racevisionGame/src/main/java/shared/model/Race.java | 7 +++++++ .../java/visualiser/model/ResizableRaceCanvas.java | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/racevisionGame/src/main/java/shared/model/Race.java b/racevisionGame/src/main/java/shared/model/Race.java index 415e9f77..8b327fb4 100644 --- a/racevisionGame/src/main/java/shared/model/Race.java +++ b/racevisionGame/src/main/java/shared/model/Race.java @@ -323,6 +323,13 @@ public abstract class Race implements Runnable { return lastFps; } + /** + * Returns the legs of this race + * @return list of legs + */ + public List getLegs() { + return legs; + } /** * Increments the FPS counter, and adds timePeriod milliseconds to our FPS reset timer. diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index 7664f854..386468c8 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -1,6 +1,7 @@ package visualiser.model; +import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.image.Image; import javafx.scene.paint.Color; @@ -9,6 +10,7 @@ import javafx.scene.transform.Rotate; import network.Messages.Enums.BoatStatusEnum; import shared.dataInput.RaceDataSource; import shared.model.GPSCoordinate; +import shared.model.Leg; import shared.model.Mark; import shared.model.RaceClock; @@ -516,6 +518,17 @@ public class ResizableRaceCanvas extends ResizableCanvas { } + /** + * draws a transparent line around the course that shows the paths boats must travel + */ + public void drawRaceLine(){ + List legs = this.visualiserRace.getLegs(); + + for (Leg leg: legs) { + //todo calculate and draw line around this leg + } + + } /** * Draws the race boundary image onto the canvas. From ef3f468b19e9caaa8de5ce17bc541e86d560ba3e Mon Sep 17 00:00:00 2001 From: hba56 Date: Tue, 8 Aug 2017 00:02:07 +1200 Subject: [PATCH 2/4] arrows displayed for each leg #story[1101] --- .../visualiser/model/ResizableRaceCanvas.java | 72 ++++++++++++++++--- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index 386468c8..10ff60ec 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -1,7 +1,6 @@ package visualiser.model; -import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.image.Image; import javafx.scene.paint.Color; @@ -9,12 +8,8 @@ import javafx.scene.paint.Paint; import javafx.scene.transform.Rotate; import network.Messages.Enums.BoatStatusEnum; import shared.dataInput.RaceDataSource; -import shared.model.GPSCoordinate; -import shared.model.Leg; -import shared.model.Mark; -import shared.model.RaceClock; +import shared.model.*; -import java.time.Duration; import java.util.List; /** @@ -513,6 +508,9 @@ public class ResizableRaceCanvas extends ResizableCanvas { //Marks. drawMarks(); + //Guiding Line + drawRaceLine(); + //Wind arrow. This rotates the wind arrow node. displayWindArrow(this.visualiserRace.getWindDirection().degrees()); @@ -523,11 +521,67 @@ public class ResizableRaceCanvas extends ResizableCanvas { */ public void drawRaceLine(){ List legs = this.visualiserRace.getLegs(); - - for (Leg leg: legs) { - //todo calculate and draw line around this leg + for (int i = 0; i < legs.size() -1; i++) { + drawLineRounding(legs.get(i)); } + } + + private void drawLineRounding(Leg leg){ + //finds the direction of the leg as a bearing + GPSCoordinate startDirectionLinePoint = leg.getStartCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate endDirectionLinePoint = leg.getEndCompoundMark().getAverageGPSCoordinate(); + Bearing bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint); + + //use the direction line to find a point parallel to it by the mark + GPSCoordinate pointToStartCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, + 150, Azimuth.fromDegrees(bearingOfDirectionLine.degrees()+90)); + + //use the direction line to find a point to curve too + GPSCoordinate pointToEndCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, + 150, Azimuth.fromDegrees(bearingOfDirectionLine.degrees())); + + //use the curve points to find the two control points for the bezier curve + Bearing bearingOfCurveLine = GPSCoordinate.calculateBearing(pointToStartCurve, pointToEndCurve); + GPSCoordinate controlPoint1 = GPSCoordinate.calculateNewPosition(pointToStartCurve, + 150, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+ 50)); + + //change all gps into graph coordinate + GraphCoordinate startPath = this.map.convertGPS(startDirectionLinePoint); + GraphCoordinate curvePoint = this.map.convertGPS(pointToStartCurve); + GraphCoordinate curvePointEnd = this.map.convertGPS(pointToEndCurve); + GraphCoordinate c1 = this.map.convertGPS(controlPoint1); + + gc.setStroke(Color.RED); + gc.setLineWidth(1); + + gc.beginPath(); + gc.moveTo(startPath.getX(), startPath.getY()); + gc.lineTo(curvePoint.getX(), curvePoint.getY()); + gc.bezierCurveTo(c1.getX(), c1.getY(), c1.getX(), c1.getY(), curvePointEnd.getX(), curvePointEnd.getY()); + gc.stroke(); + gc.closePath(); + gc.save(); + + drawArrowHead(controlPoint1, pointToEndCurve); + } + + private void drawArrowHead(GPSCoordinate start, GPSCoordinate end){ + + GraphCoordinate lineStart = this.map.convertGPS(start); + GraphCoordinate lineEnd = this.map.convertGPS(end); + + double arrowAngle = Math.toRadians(45.0); + double arrowLength = 10.0; + double dx = lineStart.getX() - lineEnd.getX(); + double dy = lineStart.getY() - lineEnd.getY(); + double angle = Math.atan2(dy, dx); + double x1 = Math.cos(angle + arrowAngle) * arrowLength + lineEnd.getX(); + double y1 = Math.sin(angle + arrowAngle) * arrowLength + lineEnd.getY(); + double x2 = Math.cos(angle - arrowAngle) * arrowLength + lineEnd.getX(); + double y2 = Math.sin(angle - arrowAngle) * arrowLength + lineEnd.getY(); + gc.strokeLine(lineEnd.getX(), lineEnd.getY(), x1, y1); + gc.strokeLine(lineEnd.getX(), lineEnd.getY(), x2, y2); } /** From 22722286ef40602e231b0fda5d4c11500bbce4c0 Mon Sep 17 00:00:00 2001 From: hba56 Date: Tue, 8 Aug 2017 14:47:11 +1200 Subject: [PATCH 3/4] all paths now join up #story[1087] --- .../visualiser/model/ResizableRaceCanvas.java | 109 ++++++++++++------ 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index 10ff60ec..2263de91 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -521,48 +521,87 @@ public class ResizableRaceCanvas extends ResizableCanvas { */ public void drawRaceLine(){ List legs = this.visualiserRace.getLegs(); + GPSCoordinate legStartPoint = legs.get(0).getStartCompoundMark().getAverageGPSCoordinate(); + GPSCoordinate nextStartPoint; for (int i = 0; i < legs.size() -1; i++) { - drawLineRounding(legs.get(i)); + nextStartPoint = drawLineRounding(legs, i, legStartPoint); + legStartPoint = nextStartPoint; } } - private void drawLineRounding(Leg leg){ - //finds the direction of the leg as a bearing - GPSCoordinate startDirectionLinePoint = leg.getStartCompoundMark().getAverageGPSCoordinate(); - GPSCoordinate endDirectionLinePoint = leg.getEndCompoundMark().getAverageGPSCoordinate(); - Bearing bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint); - - //use the direction line to find a point parallel to it by the mark - GPSCoordinate pointToStartCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, - 150, Azimuth.fromDegrees(bearingOfDirectionLine.degrees()+90)); - - //use the direction line to find a point to curve too - GPSCoordinate pointToEndCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, - 150, Azimuth.fromDegrees(bearingOfDirectionLine.degrees())); - - //use the curve points to find the two control points for the bezier curve - Bearing bearingOfCurveLine = GPSCoordinate.calculateBearing(pointToStartCurve, pointToEndCurve); - GPSCoordinate controlPoint1 = GPSCoordinate.calculateNewPosition(pointToStartCurve, - 150, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+ 50)); - - //change all gps into graph coordinate - GraphCoordinate startPath = this.map.convertGPS(startDirectionLinePoint); - GraphCoordinate curvePoint = this.map.convertGPS(pointToStartCurve); - GraphCoordinate curvePointEnd = this.map.convertGPS(pointToEndCurve); - GraphCoordinate c1 = this.map.convertGPS(controlPoint1); + /** + * Draws a line around a course that shows where boats need to go. This method + * draws the line leg by leg + * @param legs the legs of a race + * @param index the index of the current leg to use + * @return the end point of the current leg that has been drawn + */ + private GPSCoordinate drawLineRounding(List legs, int index, GPSCoordinate legStartPoint){ + GPSCoordinate startDirectionLinePoint; + GPSCoordinate endDirectionLinePoint; + Bearing bearingOfDirectionLine; + + GPSCoordinate startNextDirectionLinePoint; + GPSCoordinate endNextDirectionLinePoint; + Bearing bearingOfNextDirectionLine; + + //finds the direction of the current leg as a bearing + startDirectionLinePoint = legStartPoint; + endDirectionLinePoint = legs.get(index).getEndCompoundMark().getMark1Position(); + bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint); + + //finds the direction of the next leg as a bearing + if (index < legs.size() -2){ // not last leg + startNextDirectionLinePoint = legs.get(index + 1).getStartCompoundMark().getMark1Position(); + endNextDirectionLinePoint = legs.get(index + 1).getEndCompoundMark().getMark1Position(); + bearingOfNextDirectionLine = GPSCoordinate.calculateBearing(startNextDirectionLinePoint, endNextDirectionLinePoint); + + //use the direction line to find a point parallel to it by the mark + GPSCoordinate pointToStartCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, + 150, Azimuth.fromDegrees(bearingOfDirectionLine.degrees()+90)); + + //use the direction line to find a point to curve too + GPSCoordinate pointToEndCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, + 150, Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees()+90)); + + //use the curve points to find the two control points for the bezier curve + Bearing bearingOfCurveLine = GPSCoordinate.calculateBearing(pointToStartCurve, pointToEndCurve); + GPSCoordinate controlPoint = GPSCoordinate.calculateNewPosition(pointToStartCurve, + 75, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+ 50)); + + //change all gps into graph coordinate + GraphCoordinate startPath = this.map.convertGPS(startDirectionLinePoint); + GraphCoordinate curvePoint = this.map.convertGPS(pointToStartCurve); + GraphCoordinate curvePointEnd = this.map.convertGPS(pointToEndCurve); + GraphCoordinate c1 = this.map.convertGPS(controlPoint); + + gc.setStroke(Color.RED); + gc.setLineWidth(1); + + gc.beginPath(); + gc.moveTo(startPath.getX(), startPath.getY()); + gc.lineTo(curvePoint.getX(), curvePoint.getY()); + gc.bezierCurveTo(c1.getX(), c1.getY(), c1.getX(), c1.getY(), curvePointEnd.getX(), curvePointEnd.getY()); + gc.stroke(); + gc.closePath(); + gc.save(); - gc.setStroke(Color.RED); - gc.setLineWidth(1); + drawArrowHead(controlPoint, pointToEndCurve); - gc.beginPath(); - gc.moveTo(startPath.getX(), startPath.getY()); - gc.lineTo(curvePoint.getX(), curvePoint.getY()); - gc.bezierCurveTo(c1.getX(), c1.getY(), c1.getX(), c1.getY(), curvePointEnd.getX(), curvePointEnd.getY()); - gc.stroke(); - gc.closePath(); - gc.save(); + return pointToEndCurve; + }else{//last leg so no curve + GraphCoordinate startPath = this.map.convertGPS(legStartPoint); + GraphCoordinate endPath = this.map.convertGPS(legs.get(index).getEndCompoundMark().getAverageGPSCoordinate()); - drawArrowHead(controlPoint1, pointToEndCurve); + gc.beginPath(); + gc.moveTo(startPath.getX(), startPath.getY()); + gc.lineTo(endPath.getX(), endPath.getY()); + gc.stroke(); + gc.closePath(); + gc.save(); + drawArrowHead(legStartPoint, legs.get(index).getEndCompoundMark().getAverageGPSCoordinate()); + return null; + } } private void drawArrowHead(GPSCoordinate start, GPSCoordinate end){ From bb75806781f46618deaf0c3ce4b4469db6efbc51 Mon Sep 17 00:00:00 2001 From: hba56 Date: Tue, 8 Aug 2017 23:23:46 +1200 Subject: [PATCH 4/4] Cleaned up line to be in a shippable shape #story[1101] --- .../visualiser/model/ResizableRaceCanvas.java | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index 2263de91..379f99e5 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -3,8 +3,7 @@ package visualiser.model; import javafx.scene.Node; import javafx.scene.image.Image; -import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; +import javafx.scene.paint.*; import javafx.scene.transform.Rotate; import network.Messages.Enums.BoatStatusEnum; import shared.dataInput.RaceDataSource; @@ -502,15 +501,15 @@ public class ResizableRaceCanvas extends ResizableCanvas { //Race boundary. drawBoundary(); + //Guiding Line + drawRaceLine(); + //Boats. drawBoats(); //Marks. drawMarks(); - //Guiding Line - drawRaceLine(); - //Wind arrow. This rotates the wind arrow node. displayWindArrow(this.visualiserRace.getWindDirection().degrees()); @@ -558,36 +557,49 @@ public class ResizableRaceCanvas extends ResizableCanvas { //use the direction line to find a point parallel to it by the mark GPSCoordinate pointToStartCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, - 150, Azimuth.fromDegrees(bearingOfDirectionLine.degrees()+90)); + 100, Azimuth.fromDegrees(bearingOfDirectionLine.degrees()+90)); //use the direction line to find a point to curve too GPSCoordinate pointToEndCurve = GPSCoordinate.calculateNewPosition(endDirectionLinePoint, - 150, Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees()+90)); + 100, Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees()+90)); //use the curve points to find the two control points for the bezier curve + GPSCoordinate controlPoint; + GPSCoordinate controlPoint2; Bearing bearingOfCurveLine = GPSCoordinate.calculateBearing(pointToStartCurve, pointToEndCurve); - GPSCoordinate controlPoint = GPSCoordinate.calculateNewPosition(pointToStartCurve, - 75, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+ 50)); + if ((bearingOfDirectionLine.degrees() - bearingOfNextDirectionLine.degrees() +360)%360< 145){ + //small turn + controlPoint = GPSCoordinate.calculateNewPosition(pointToStartCurve, + 50, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+45)); + controlPoint2 = controlPoint; + }else{ + //large turn + controlPoint = GPSCoordinate.calculateNewPosition(pointToStartCurve, + 150, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+90)); + controlPoint2 = GPSCoordinate.calculateNewPosition(pointToEndCurve, + 150, Azimuth.fromDegrees(bearingOfCurveLine.degrees()+90)); + } + //change all gps into graph coordinate GraphCoordinate startPath = this.map.convertGPS(startDirectionLinePoint); GraphCoordinate curvePoint = this.map.convertGPS(pointToStartCurve); GraphCoordinate curvePointEnd = this.map.convertGPS(pointToEndCurve); GraphCoordinate c1 = this.map.convertGPS(controlPoint); + GraphCoordinate c2 = this.map.convertGPS(controlPoint2); - gc.setStroke(Color.RED); - gc.setLineWidth(1); + gc.setLineWidth(2); + gc.setStroke(Color.MEDIUMAQUAMARINE); gc.beginPath(); gc.moveTo(startPath.getX(), startPath.getY()); gc.lineTo(curvePoint.getX(), curvePoint.getY()); - gc.bezierCurveTo(c1.getX(), c1.getY(), c1.getX(), c1.getY(), curvePointEnd.getX(), curvePointEnd.getY()); + drawArrowHead(startDirectionLinePoint, pointToStartCurve); + gc.bezierCurveTo(c1.getX(), c1.getY(), c2.getX(), c2.getY(), curvePointEnd.getX(), curvePointEnd.getY()); gc.stroke(); gc.closePath(); gc.save(); - drawArrowHead(controlPoint, pointToEndCurve); - return pointToEndCurve; }else{//last leg so no curve GraphCoordinate startPath = this.map.convertGPS(legStartPoint);