@ -2,7 +2,9 @@ package visualiser.model;
import javafx.scene.paint.Color ;
import javafx.scene.paint.Color ;
import javafx.scene.paint.LinearGradient ;
import javafx.scene.paint.Paint ;
import javafx.scene.paint.Paint ;
import javafx.scene.text.Font ;
import javafx.scene.transform.Rotate ;
import javafx.scene.transform.Rotate ;
import network.Messages.Enums.BoatStatusEnum ;
import network.Messages.Enums.BoatStatusEnum ;
import shared.dataInput.RaceDataSource ;
import shared.dataInput.RaceDataSource ;
@ -10,6 +12,8 @@ import shared.enums.RoundingType;
import shared.model.* ;
import shared.model.* ;
import java.util.ArrayList ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Comparator ;
import java.util.List ;
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 .
* Draws a circle with a given diameter , centred on a given graph coordinate .
* @param center The center coordinate of the circle .
* @param center The center coordinate of the circle .
* @param diameter The diameter 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.
//The graphCoordinates are for the center of the point, so we offset them to get the corner coordinate.
gc . fillOval (
gc . fillOval (
@ -148,6 +158,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
center . getY ( ) - ( diameter / 2 ) ,
center . getY ( ) - ( diameter / 2 ) ,
diameter , diameter ) ;
diameter , diameter ) ;
gc . restore ( ) ;
}
}
/ * *
/ * *
@ -156,20 +167,16 @@ public class ResizableRaceCanvas extends ResizableCanvas {
* @param graphCoordinateA Starting Point of the line in GraphCoordinate .
* @param graphCoordinateA Starting Point of the line in GraphCoordinate .
* @param graphCoordinateB End Point of the line in GraphCoordinate .
* @param graphCoordinateB End Point of the line in GraphCoordinate .
* @param paint Colour the line is to coloured .
* @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 . setStroke ( paint ) ;
gc . setFill ( paint ) ;
gc . setFill ( paint ) ;
gc . setLineWidth ( lineWidth ) ;
double endPointDiameter = 6 ;
//Draw first end-point.
drawCircle ( graphCoordinateA , endPointDiameter ) ;
//Draw second end-point.
drawCircle ( graphCoordinateB , endPointDiameter ) ;
//Draw line between them.
//Draw line between them.
gc . strokeLine (
gc . strokeLine (
@ -178,26 +185,12 @@ public class ResizableRaceCanvas extends ResizableCanvas {
graphCoordinateB . getX ( ) ,
graphCoordinateB . getX ( ) ,
graphCoordinateB . getY ( ) ) ;
graphCoordinateB . getY ( ) ) ;
}
gc . restore ( ) ;
/ * *
* 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 ;
//Draw the point.
drawCircle ( graphCoordinate , pointDiameter ) ;
}
}
/ * *
/ * *
* Display given name and speed of boat at a graph coordinate
* 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 coordinate coordinate the text appears
* @param timeToNextMark The time until the boat reaches the next mark .
* @param timeToNextMark The time until the boat reaches the next mark .
* @param timeSinceLastMark The time since the boat passed the last 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.
//The text to draw. Built during the function.
String text = "" ;
String text = "" ;
@ -254,8 +249,16 @@ public class ResizableRaceCanvas extends ResizableCanvas {
yCoord + = 30 ;
yCoord + = 30 ;
}
}
gc . save ( ) ;
gc . setStroke ( textPaint ) ;
gc . setFill ( textPaint ) ;
gc . setFont ( new Font ( gc . getFont ( ) . getName ( ) , fontSize ) ) ;
//Draw text.
//Draw text.
gc . fillText ( text , xCoord , yCoord ) ;
gc . fillText ( text , xCoord , yCoord ) ;
gc . restore ( ) ;
}
}
@ -271,7 +274,9 @@ public class ResizableRaceCanvas extends ResizableCanvas {
boat . getCurrentSpeed ( ) ,
boat . getCurrentSpeed ( ) ,
this . map . convertGPS ( boat . getPosition ( ) ) ,
this . map . convertGPS ( boat . getPosition ( ) ) ,
boat . getTimeToNextMarkFormatted ( this . visualiserRace . getVisualiserRaceState ( ) . getRaceClock ( ) . getCurrentTime ( ) ) ,
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 ( ) {
private void drawBoats ( ) {
for ( VisualiserBoat boat : new ArrayList < > ( visualiserRace . getVisualiserRaceState ( ) . getBoats ( ) ) ) {
List < VisualiserBoat > boats = new ArrayList < > ( visualiserRace . getVisualiserRaceState ( ) . getBoats ( ) ) ;
//Sort to ensure we draw boats in consistent order.
boats . sort ( Comparator . comparingInt ( Boat : : getSourceID ) ) ;
//Draw the boat.
//Current draw order:
drawBoat ( boat ) ;
// 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.
//Only draw wake if they are currently racing.
if ( boat . getStatus ( ) = = BoatStatusEnum . RACING ) {
if ( boat . getStatus ( ) = = BoatStatusEnum . RACING ) {
drawWake ( boat ) ;
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 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 ) ) {
if ( ( boat . getStatus ( ) ! = BoatStatusEnum . RACING ) & & ( boat . getStatus ( ) = = BoatStatusEnum . FINISHED ) ) {
boat . setTimeAtLastMark ( visualiserRace . getVisualiserRaceState ( ) . getRaceClock ( ) . getCurrentTime ( ) ) ;
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.
//The above shape is essentially a triangle 12px wide, and 24px long.
gc . save ( ) ;
//Draw the boat.
//Draw the boat.
gc . setFill ( boat . getColor ( ) ) ;
gc . setFill ( boat . getColor ( ) ) ;
gc . save ( ) ;
rotate ( boat . getBearing ( ) . degrees ( ) , pos . getX ( ) , pos . getY ( ) ) ;
rotate ( boat . getBearing ( ) . degrees ( ) , pos . getX ( ) , pos . getY ( ) ) ;
gc . fillPolygon ( x , y , 3 ) ;
gc . fillPolygon ( x , y , x . length ) ;
gc . restore ( ) ;
gc . restore ( ) ;
@ -372,12 +401,14 @@ public class ResizableRaceCanvas extends ResizableCanvas {
//The above shape is essentially a triangle 24px wide, and 48 long.
//The above shape is essentially a triangle 24px wide, and 48 long.
gc . save ( ) ;
//Draw the boat.
//Draw the boat.
gc . setFill ( Color . BLACK ) ;
gc . setFill ( Color . BLACK ) ;
gc . save ( ) ;
rotate ( boat . getBearing ( ) . degrees ( ) , pos . getX ( ) , pos . getY ( ) ) ;
rotate ( boat . getBearing ( ) . degrees ( ) , pos . getX ( ) , pos . getY ( ) ) ;
gc . fillPolygon ( x , y , 3 ) ;
gc . fillPolygon ( x , y , x . length ) ;
gc . restore ( ) ;
gc . restore ( ) ;
}
}
@ -393,8 +424,15 @@ public class ResizableRaceCanvas extends ResizableCanvas {
GraphCoordinate wakeFrom = this . map . convertGPS ( boat . getPosition ( ) ) ;
GraphCoordinate wakeFrom = this . map . convertGPS ( boat . getPosition ( ) ) ;
GraphCoordinate wakeTo = this . map . convertGPS ( boat . getWake ( ) ) ;
GraphCoordinate wakeTo = this . map . convertGPS ( boat . getWake ( ) ) ;
//Draw.
double lineWidth = 4 ;
drawLine ( wakeFrom , wakeTo , boat . getColor ( ) ) ;
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.
//Calculate screen position.
GraphCoordinate mark1 = this . map . convertGPS ( mark . getPosition ( ) ) ;
GraphCoordinate mark1 = this . map . convertGPS ( mark . getPosition ( ) ) ;
double diameter = 10 ;
//Draw.
//Draw.
drawPoint ( mark1 , Color . LIMEGREEN ) ;
draw Circle( mark1 , diameter , Color . DARK GREEN) ;
}
}
@ -459,6 +499,8 @@ public class ResizableRaceCanvas extends ResizableCanvas {
* /
* /
private void drawBoundary ( ) {
private void drawBoundary ( ) {
gc . save ( ) ;
//Prepare to draw.
//Prepare to draw.
gc . setLineWidth ( 1 ) ;
gc . setLineWidth ( 1 ) ;
gc . setFill ( Color . AQUA ) ;
gc . setFill ( Color . AQUA ) ;
@ -481,6 +523,8 @@ public class ResizableRaceCanvas extends ResizableCanvas {
//Draw the boundary.
//Draw the boundary.
gc . fillPolygon ( xpoints , ypoints , xpoints . length ) ;
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 . setGPSTopLeft ( visualiserRace . getVisualiserRaceState ( ) . getRaceDataSource ( ) . getMapTopLeft ( ) ) ;
this . map . setGPSBotRight ( visualiserRace . getVisualiserRaceState ( ) . getRaceDataSource ( ) . getMapBottomRight ( ) ) ;
this . map . setGPSBotRight ( visualiserRace . getVisualiserRaceState ( ) . getRaceDataSource ( ) . getMapBottomRight ( ) ) ;
gc . setLineWidth ( 2 ) ;
clear ( ) ;
clear ( ) ;
@ -601,6 +644,8 @@ public class ResizableRaceCanvas extends ResizableCanvas {
GraphCoordinate c1 = this . map . convertGPS ( controlPoint ) ;
GraphCoordinate c1 = this . map . convertGPS ( controlPoint ) ;
GraphCoordinate c2 = this . map . convertGPS ( controlPoint2 ) ;
GraphCoordinate c2 = this . map . convertGPS ( controlPoint2 ) ;
gc . save ( ) ;
gc . setLineWidth ( 2 ) ;
gc . setLineWidth ( 2 ) ;
gc . setStroke ( Color . MEDIUMAQUAMARINE ) ;
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 . bezierCurveTo ( c1 . getX ( ) , c1 . getY ( ) , c2 . getX ( ) , c2 . getY ( ) , curvePointEnd . getX ( ) , curvePointEnd . getY ( ) ) ;
gc . stroke ( ) ;
gc . stroke ( ) ;
gc . closePath ( ) ;
gc . closePath ( ) ;
gc . save ( ) ;
//gc.save();
gc . restore ( ) ;
return pointToEndCurve ;
return pointToEndCurve ;
} else { //last leg so no curve
} else { //last leg so no curve
GraphCoordinate startPath = this . map . convertGPS ( legStartPoint ) ;
GraphCoordinate startPath = this . map . convertGPS ( legStartPoint ) ;
GraphCoordinate endPath = this . map . convertGPS ( legs . get ( index ) . getEndCompoundMark ( ) . getAverageGPSCoordinate ( ) ) ;
GraphCoordinate endPath = this . map . convertGPS ( legs . get ( index ) . getEndCompoundMark ( ) . getAverageGPSCoordinate ( ) ) ;
gc . save ( ) ;
gc . beginPath ( ) ;
gc . beginPath ( ) ;
gc . moveTo ( startPath . getX ( ) , startPath . getY ( ) ) ;
gc . moveTo ( startPath . getX ( ) , startPath . getY ( ) ) ;
gc . lineTo ( endPath . getX ( ) , endPath . getY ( ) ) ;
gc . lineTo ( endPath . getX ( ) , endPath . getY ( ) ) ;
gc . stroke ( ) ;
gc . stroke ( ) ;
gc . closePath ( ) ;
gc . closePath ( ) ;
gc . save ( ) ;
//gc.save();
drawArrowHead ( legStartPoint , legs . get ( index ) . getEndCompoundMark ( ) . getAverageGPSCoordinate ( ) ) ;
drawArrowHead ( legStartPoint , legs . get ( index ) . getEndCompoundMark ( ) . getAverageGPSCoordinate ( ) ) ;
gc . restore ( ) ;
return null ;
return null ;
}
}
}
}
@ -661,17 +712,43 @@ public class ResizableRaceCanvas extends ResizableCanvas {
//Check that track points are enabled.
//Check that track points are enabled.
if ( this . annoPath ) {
if ( this . annoPath ) {
//Apply the boat color.
List < TrackPoint > trackPoints = new ArrayList < > ( boat . getTrack ( ) ) ;
gc . setFill ( boat . getColor ( ) ) ;
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.
gc . restore ( ) ;
GraphCoordinate scaledCoordinate = this . map . convertGPS ( point . getCoordinate ( ) ) ;
//Draw a circle for the trackpoint.
gc . fillOval ( scaledCoordinate . getX ( ) , scaledCoordinate . getY ( ) , point . getDiameter ( ) , point . getDiameter ( ) ) ;
}
}
}
}