diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index 57c864b5..1c17b540 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -2,7 +2,9 @@ package visualiser.model; import javafx.scene.paint.Color; +import javafx.scene.paint.LinearGradient; import javafx.scene.paint.Paint; +import javafx.scene.text.Font; import javafx.scene.transform.Rotate; import network.Messages.Enums.BoatStatusEnum; import shared.dataInput.RaceDataSource; @@ -10,6 +12,8 @@ import shared.enums.RoundingType; import shared.model.*; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.List; /** @@ -139,8 +143,14 @@ public class ResizableRaceCanvas extends ResizableCanvas { * Draws a circle with a given diameter, centred on a given graph coordinate. * @param center The center coordinate of the circle. * @param diameter The diameter of the circle. + * @param paint The paint to use for the circle. */ - private void drawCircle(GraphCoordinate center, double diameter) { + private void drawCircle(GraphCoordinate center, double diameter, Paint paint) { + + gc.save(); + + gc.setFill(paint); + gc.setStroke(paint); //The graphCoordinates are for the center of the point, so we offset them to get the corner coordinate. gc.fillOval( @@ -148,6 +158,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { center.getY() - (diameter / 2), diameter, diameter ); + gc.restore(); } /** @@ -156,20 +167,16 @@ public class ResizableRaceCanvas extends ResizableCanvas { * @param graphCoordinateA Starting Point of the line in GraphCoordinate. * @param graphCoordinateB End Point of the line in GraphCoordinate. * @param paint Colour the line is to coloured. + * @param lineWidth The width of the line. */ - private void drawLine(GraphCoordinate graphCoordinateA, GraphCoordinate graphCoordinateB, Paint paint) { + private void drawLine(GraphCoordinate graphCoordinateA, GraphCoordinate graphCoordinateB, Paint paint, double lineWidth) { + + gc.save(); gc.setStroke(paint); gc.setFill(paint); - - double endPointDiameter = 6; - - //Draw first end-point. - drawCircle(graphCoordinateA, endPointDiameter); - - //Draw second end-point. - drawCircle(graphCoordinateB, endPointDiameter); + gc.setLineWidth(lineWidth); //Draw line between them. gc.strokeLine( @@ -178,26 +185,12 @@ public class ResizableRaceCanvas extends ResizableCanvas { graphCoordinateB.getX(), graphCoordinateB.getY() ); - } - - /** - * Display a point on the Canvas. It has a diameter of 10 pixels. - * - * @param graphCoordinate Coordinate that the point is to be displayed at. - * @param paint Paint to use for the point. - */ - private void drawPoint(GraphCoordinate graphCoordinate, Paint paint) { - - //Set paint. - gc.setFill(paint); - - double pointDiameter = 10; + gc.restore(); - //Draw the point. - drawCircle(graphCoordinate, pointDiameter); } + /** * Display given name and speed of boat at a graph coordinate * @@ -207,8 +200,10 @@ public class ResizableRaceCanvas extends ResizableCanvas { * @param coordinate coordinate the text appears * @param timeToNextMark The time until the boat reaches the next mark. * @param timeSinceLastMark The time since the boat passed the last mark. + * @param textPaint The color of the text. + * @param fontSize The size of the font. */ - private void drawText(String name, String abbrev, double speed, GraphCoordinate coordinate, String timeToNextMark, String timeSinceLastMark) { + private void drawText(String name, String abbrev, double speed, GraphCoordinate coordinate, String timeToNextMark, String timeSinceLastMark, Paint textPaint, double fontSize) { //The text to draw. Built during the function. String text = ""; @@ -254,8 +249,16 @@ public class ResizableRaceCanvas extends ResizableCanvas { yCoord += 30; } + gc.save(); + + gc.setStroke(textPaint); + gc.setFill(textPaint); + gc.setFont(new Font(gc.getFont().getName(), fontSize)); + //Draw text. gc.fillText(text, xCoord, yCoord); + + gc.restore(); } @@ -271,7 +274,9 @@ public class ResizableRaceCanvas extends ResizableCanvas { boat.getCurrentSpeed(), this.map.convertGPS(boat.getPosition()), boat.getTimeToNextMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()), - boat.getTimeSinceLastMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()) ); + boat.getTimeSinceLastMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()), + Color.BLACK, + 20 ); } @@ -283,29 +288,51 @@ public class ResizableRaceCanvas extends ResizableCanvas { */ private void drawBoats() { - for (VisualiserBoat boat : new ArrayList<>(visualiserRace.getVisualiserRaceState().getBoats())) { + List boats = new ArrayList<>(visualiserRace.getVisualiserRaceState().getBoats()); + //Sort to ensure we draw boats in consistent order. + boats.sort(Comparator.comparingInt(Boat::getSourceID)); - //Draw the boat. - drawBoat(boat); + //Current draw order: + // track points + // wake + // boat + // text + //Track points. + for (VisualiserBoat boat : boats) { + drawTrack(boat); + } + + //Wake. + for (VisualiserBoat boat : boats) { //Only draw wake if they are currently racing. if (boat.getStatus() == BoatStatusEnum.RACING) { drawWake(boat); } + } + + //Boat. + for (VisualiserBoat boat : boats) { + drawBoat(boat); + } + + //Text. + for (VisualiserBoat boat : boats) { + drawBoatText(boat); + } + + +/* //If the race hasn't started, we set the time since last mark to the current time, to ensure we don't start counting until the race actually starts. if ((boat.getStatus() != BoatStatusEnum.RACING) && (boat.getStatus() == BoatStatusEnum.FINISHED)) { boat.setTimeAtLastMark(visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()); } +*/ - //Draw boat label. - drawBoatText(boat); - //Draw track. - drawTrack(boat); - } } @@ -338,12 +365,14 @@ public class ResizableRaceCanvas extends ResizableCanvas { //The above shape is essentially a triangle 12px wide, and 24px long. + + gc.save(); + //Draw the boat. gc.setFill(boat.getColor()); - gc.save(); rotate(boat.getBearing().degrees(), pos.getX(), pos.getY()); - gc.fillPolygon(x, y, 3); + gc.fillPolygon(x, y, x.length); gc.restore(); @@ -372,12 +401,14 @@ public class ResizableRaceCanvas extends ResizableCanvas { //The above shape is essentially a triangle 24px wide, and 48 long. + + gc.save(); + //Draw the boat. gc.setFill(Color.BLACK); - gc.save(); rotate(boat.getBearing().degrees(), pos.getX(), pos.getY()); - gc.fillPolygon(x, y, 3); + gc.fillPolygon(x, y, x.length); gc.restore(); } @@ -393,8 +424,15 @@ public class ResizableRaceCanvas extends ResizableCanvas { GraphCoordinate wakeFrom = this.map.convertGPS(boat.getPosition()); GraphCoordinate wakeTo = this.map.convertGPS(boat.getWake()); - //Draw. - drawLine(wakeFrom, wakeTo, boat.getColor()); + double lineWidth = 4; + double endPointDiameter = 12; + + //Line. + drawLine(wakeFrom, wakeTo, Color.DARKBLUE, lineWidth); + + //Draw end-point. + //drawCircle(wakeTo, endPointDiameter, Color.BLACK); + } @@ -420,8 +458,10 @@ public class ResizableRaceCanvas extends ResizableCanvas { //Calculate screen position. GraphCoordinate mark1 = this.map.convertGPS(mark.getPosition()); + double diameter = 10; + //Draw. - drawPoint(mark1, Color.LIMEGREEN); + drawCircle(mark1, diameter, Color.DARKGREEN); } @@ -459,6 +499,8 @@ public class ResizableRaceCanvas extends ResizableCanvas { */ private void drawBoundary() { + gc.save(); + //Prepare to draw. gc.setLineWidth(1); gc.setFill(Color.AQUA); @@ -481,6 +523,8 @@ public class ResizableRaceCanvas extends ResizableCanvas { //Draw the boundary. gc.fillPolygon(xpoints, ypoints, xpoints.length); + gc.restore(); + } /** @@ -493,7 +537,6 @@ public class ResizableRaceCanvas extends ResizableCanvas { this.map.setGPSTopLeft(visualiserRace.getVisualiserRaceState().getRaceDataSource().getMapTopLeft()); this.map.setGPSBotRight(visualiserRace.getVisualiserRaceState().getRaceDataSource().getMapBottomRight()); - gc.setLineWidth(2); clear(); @@ -601,6 +644,8 @@ public class ResizableRaceCanvas extends ResizableCanvas { GraphCoordinate c1 = this.map.convertGPS(controlPoint); GraphCoordinate c2 = this.map.convertGPS(controlPoint2); + gc.save(); + gc.setLineWidth(2); gc.setStroke(Color.MEDIUMAQUAMARINE); @@ -611,20 +656,26 @@ public class ResizableRaceCanvas extends ResizableCanvas { gc.bezierCurveTo(c1.getX(), c1.getY(), c2.getX(), c2.getY(), curvePointEnd.getX(), curvePointEnd.getY()); gc.stroke(); gc.closePath(); - gc.save(); + //gc.save(); + gc.restore(); return pointToEndCurve; }else{//last leg so no curve GraphCoordinate startPath = this.map.convertGPS(legStartPoint); GraphCoordinate endPath = this.map.convertGPS(legs.get(index).getEndCompoundMark().getAverageGPSCoordinate()); + gc.save(); + gc.beginPath(); gc.moveTo(startPath.getX(), startPath.getY()); gc.lineTo(endPath.getX(), endPath.getY()); gc.stroke(); gc.closePath(); - gc.save(); + //gc.save(); drawArrowHead(legStartPoint, legs.get(index).getEndCompoundMark().getAverageGPSCoordinate()); + + gc.restore(); + return null; } } @@ -661,17 +712,43 @@ public class ResizableRaceCanvas extends ResizableCanvas { //Check that track points are enabled. if (this.annoPath) { - //Apply the boat color. - gc.setFill(boat.getColor()); + List trackPoints = new ArrayList<>(boat.getTrack()); + + if (trackPoints.size() > 2 ) { + + gc.save(); + + gc.setLineWidth(3); + + + //Draw a line between each adjacent pair of track points. + for (int i = 0; i < trackPoints.size() - 1; i++) { + + //Convert the GPSCoordinate to a screen coordinate. + GraphCoordinate scaledCoordinate1 = this.map.convertGPS(trackPoints.get(i).getCoordinate()); + GraphCoordinate scaledCoordinate2 = this.map.convertGPS(trackPoints.get(i + 1).getCoordinate()); + + double alpha = trackPoints.get(i).getAlpha(); + Paint fadedPaint = new Color( + boat.getColor().getRed(), + boat.getColor().getGreen(), + boat.getColor().getBlue(), + alpha ); + + //Apply the faded boat color. + gc.setFill(fadedPaint); + gc.setStroke(fadedPaint); + + gc.strokeLine( + scaledCoordinate1.getX(), + scaledCoordinate1.getY(), + scaledCoordinate2.getX(), + scaledCoordinate2.getY() ); + } - //Draw each TrackPoint. - for (TrackPoint point : new ArrayList<>(boat.getTrack())) { - //Convert the GPSCoordinate to a screen coordinate. - GraphCoordinate scaledCoordinate = this.map.convertGPS(point.getCoordinate()); + gc.restore(); - //Draw a circle for the trackpoint. - gc.fillOval(scaledCoordinate.getX(), scaledCoordinate.getY(), point.getDiameter(), point.getDiameter()); } } diff --git a/racevisionGame/src/main/java/visualiser/model/TrackPoint.java b/racevisionGame/src/main/java/visualiser/model/TrackPoint.java index 4e0c76c0..f3378a43 100644 --- a/racevisionGame/src/main/java/visualiser/model/TrackPoint.java +++ b/racevisionGame/src/main/java/visualiser/model/TrackPoint.java @@ -34,11 +34,6 @@ public class TrackPoint { */ private final double minAlpha; - /** - * The diameter to draw the track point with. - */ - private final double diameter; - /** * Creates a new track point with fixed GPS coordinates and time, to reach minimum opacity on expiry. @@ -53,7 +48,6 @@ public class TrackPoint { this.expiry = expiry; this.minAlpha = 0.1; - this.diameter = 5d; } @@ -97,12 +91,4 @@ public class TrackPoint { return timeAdded; } - - /** - * Returns the diameter to draw the track point with. - * @return The diameter to draw the track point with. - */ - public double getDiameter() { - return diameter; - } } diff --git a/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java b/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java index a02706a6..6cbfdaa3 100644 --- a/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java +++ b/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java @@ -36,12 +36,12 @@ public class VisualiserBoat extends Boat { /** * The minimum period of time, in milliseconds, between the creation of each track point. */ - private static final long trackPointTimeInterval = 5000; + private static final long trackPointTimeInterval = 1000; /** * The number of track points that should be created before fully diminishing the alpha of a given track point. */ - private static final int trackPointLimit = 10; + private static final int trackPointLimit = 50; /** @@ -53,7 +53,7 @@ public class VisualiserBoat extends Boat { /** * Scalar used to scale the boat's wake. */ - private static final double wakeScale = 5; + private static final double wakeScale = 25; /** * If true then this boat has been allocated to the client. diff --git a/racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java b/racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java index 3315cbfa..77db4f7c 100644 --- a/racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java +++ b/racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java @@ -224,11 +224,7 @@ public class VisualiserRaceState extends RaceState { Leg startingLeg = getLegs().get(0); for (VisualiserBoat boat : boats) { - boat.setCurrentLeg(startingLeg); - boat.setTimeAtLastMark(getRaceClock().getCurrentTime()); - boat.setPosition(new GPSCoordinate(0, 0)); - } } diff --git a/racevisionGame/src/main/resources/css/dayMode.css b/racevisionGame/src/main/resources/css/dayMode.css index d0f62fb7..aa14c68b 100644 --- a/racevisionGame/src/main/resources/css/dayMode.css +++ b/racevisionGame/src/main/resources/css/dayMode.css @@ -52,4 +52,6 @@ -fx-background-color: -fx-mark-highlight-color, rgb(255, 255, 255); } - +#arrowImage { + -fx-image: url("/visualiser/images/arrow.png"); +}