mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -24,7 +24,6 @@ public class App extends Application {
|
|||||||
primaryStage.setOnCloseRequest(e -> {
|
primaryStage.setOnCloseRequest(e -> {
|
||||||
StreamParser.appClose();
|
StreamParser.appClose();
|
||||||
StreamReceiver.noMoreBytes();
|
StreamReceiver.noMoreBytes();
|
||||||
System.out.println("[CLIENT] Exiting program");
|
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -65,8 +64,8 @@ public class App extends Application {
|
|||||||
//Change the StreamReceiver in this else block to change the default data source.
|
//Change the StreamReceiver in this else block to change the default data source.
|
||||||
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("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream");
|
// sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream");
|
||||||
|
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
||||||
}
|
}
|
||||||
|
|
||||||
sr.start();
|
sr.start();
|
||||||
|
|||||||
@@ -45,17 +45,12 @@ public class CanvasController {
|
|||||||
private Group group;
|
private Group group;
|
||||||
private GraphicsContext gc;
|
private GraphicsContext gc;
|
||||||
private ImageView mapImage;
|
private ImageView mapImage;
|
||||||
|
|
||||||
private final int MARK_SIZE = 10;
|
|
||||||
private final int BUFFER_SIZE = 50;
|
private final int BUFFER_SIZE = 50;
|
||||||
private final int PANEL_WIDTH = 1260; // it should be 1280 but, minors 40 to cancel the bias.
|
private final int PANEL_WIDTH = 1260; // it should be 1280 but, minors 40 to cancel the bias.
|
||||||
private final int PANEL_HEIGHT = 960;
|
private final int PANEL_HEIGHT = 960;
|
||||||
private final int CANVAS_WIDTH = 720;
|
private final int CANVAS_WIDTH = 720;
|
||||||
private final int CANVAS_HEIGHT = 720;
|
private final int CANVAS_HEIGHT = 720;
|
||||||
private final int LHS_BUFFER = BUFFER_SIZE;
|
|
||||||
private final int RHS_BUFFER = BUFFER_SIZE;
|
|
||||||
private final int TOP_BUFFER = BUFFER_SIZE;
|
|
||||||
private final int BOT_BUFFER = TOP_BUFFER;
|
|
||||||
private boolean horizontalInversion = false;
|
private boolean horizontalInversion = false;
|
||||||
|
|
||||||
private double distanceScaleFactor;
|
private double distanceScaleFactor;
|
||||||
@@ -113,13 +108,14 @@ public class CanvasController {
|
|||||||
gc.setGlobalAlpha(0.5);
|
gc.setGlobalAlpha(0.5);
|
||||||
fitMarksToCanvas();
|
fitMarksToCanvas();
|
||||||
drawGoogleMap();
|
drawGoogleMap();
|
||||||
|
|
||||||
|
|
||||||
// TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml
|
// TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml
|
||||||
initializeBoats();
|
initializeBoats();
|
||||||
initializeMarks();
|
initializeMarks();
|
||||||
timer = new AnimationTimer() {
|
timer = new AnimationTimer() {
|
||||||
|
|
||||||
|
private int UPDATE_FPM_PERIOD = 50; // update FPM label every 50 frames
|
||||||
|
private int updateFPMCounter = 100;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(long now) {
|
public void handle(long now) {
|
||||||
|
|
||||||
@@ -135,11 +131,12 @@ public class CanvasController {
|
|||||||
elapsedNanos = now - oldFrameTime ;
|
elapsedNanos = now - oldFrameTime ;
|
||||||
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
|
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
|
||||||
frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
|
frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
|
||||||
drawFps(frameRate.intValue());
|
if (updateFPMCounter++ > UPDATE_FPM_PERIOD) {
|
||||||
|
updateFPMCounter = 0;
|
||||||
|
drawFps(frameRate.intValue());
|
||||||
|
}
|
||||||
|
raceViewController.updateSparkLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 1/05/17 cir27 - Make the RaceObjects update on the actual delay.
|
|
||||||
elapsedNanos = 1000 / 60;
|
|
||||||
updateGroups();
|
updateGroups();
|
||||||
if (StreamParser.isRaceFinished()) {
|
if (StreamParser.isRaceFinished()) {
|
||||||
this.stop();
|
this.stop();
|
||||||
@@ -348,17 +345,14 @@ public class CanvasController {
|
|||||||
|
|
||||||
private void drawFps(int fps){
|
private void drawFps(int fps){
|
||||||
if (raceViewController.isDisplayFps()){
|
if (raceViewController.isDisplayFps()){
|
||||||
gc.clearRect(5,5,50,20);
|
gc.clearRect(5, 5, 60, 30);
|
||||||
gc.setFill(Color.SKYBLUE);
|
gc.setFont(new Font(16));
|
||||||
gc.fillRect(4,4,51,21);
|
gc.setLineWidth(4);
|
||||||
gc.setFill(Color.BLACK);
|
gc.setGlobalAlpha(0.75);
|
||||||
gc.setFont(new Font(14));
|
|
||||||
gc.setLineWidth(3);
|
|
||||||
gc.fillText(fps + " FPS", 5, 20);
|
gc.fillText(fps + " FPS", 5, 20);
|
||||||
|
gc.setGlobalAlpha(0.5);
|
||||||
} else {
|
} else {
|
||||||
gc.clearRect(5,5,50,20);
|
gc.clearRect(5,5,60,30);
|
||||||
gc.setFill(Color.SKYBLUE);
|
|
||||||
gc.fillRect(4,4,51,21);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,24 +408,24 @@ public class CanvasController {
|
|||||||
|
|
||||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
||||||
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint));
|
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint));
|
||||||
referencePointX = LHS_BUFFER + distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
|
referencePointX = BUFFER_SIZE + distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
|
||||||
|
|
||||||
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, maxLatPoint));
|
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, maxLatPoint));
|
||||||
referencePointY = CANVAS_HEIGHT - (TOP_BUFFER + BOT_BUFFER);
|
referencePointY = CANVAS_HEIGHT - (BUFFER_SIZE + BUFFER_SIZE);
|
||||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint);
|
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint);
|
||||||
referencePointY = referencePointY / 2;
|
referencePointY = referencePointY / 2;
|
||||||
referencePointY += TOP_BUFFER;
|
referencePointY += BUFFER_SIZE;
|
||||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint);
|
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint);
|
||||||
} else {
|
} else {
|
||||||
referencePointY = CANVAS_HEIGHT - BOT_BUFFER;
|
referencePointY = CANVAS_HEIGHT - BUFFER_SIZE;
|
||||||
|
|
||||||
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint));
|
referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint));
|
||||||
referencePointX = LHS_BUFFER;
|
referencePointX = BUFFER_SIZE;
|
||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
|
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
|
||||||
referencePointX += ((CANVAS_WIDTH - (LHS_BUFFER + RHS_BUFFER)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
referencePointX += ((CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
||||||
}
|
}
|
||||||
if(horizontalInversion) {
|
if(horizontalInversion) {
|
||||||
referencePointX = CANVAS_WIDTH - RHS_BUFFER - (referencePointX - LHS_BUFFER);
|
referencePointX = CANVAS_WIDTH - BUFFER_SIZE - (referencePointX - BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,10 +446,10 @@ public class CanvasController {
|
|||||||
horiAngle = horiAngle - (Math.PI / 2);
|
horiAngle = horiAngle - (Math.PI / 2);
|
||||||
double horiDistance = Math.cos(horiAngle) * Mark.calculateDistance(minLonPoint, maxLonPoint);
|
double horiDistance = Math.cos(horiAngle) * Mark.calculateDistance(minLonPoint, maxLonPoint);
|
||||||
|
|
||||||
double vertScale = (CANVAS_HEIGHT - (TOP_BUFFER + BOT_BUFFER)) / vertDistance;
|
double vertScale = (CANVAS_HEIGHT - (BUFFER_SIZE + BUFFER_SIZE)) / vertDistance;
|
||||||
|
|
||||||
if ((horiDistance * vertScale) > (CANVAS_WIDTH - (RHS_BUFFER + LHS_BUFFER))) {
|
if ((horiDistance * vertScale) > (CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE))) {
|
||||||
distanceScaleFactor = (CANVAS_WIDTH - (RHS_BUFFER + LHS_BUFFER)) / horiDistance;
|
distanceScaleFactor = (CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE)) / horiDistance;
|
||||||
scaleDirection = ScaleDirection.HORIZONTAL;
|
scaleDirection = ScaleDirection.HORIZONTAL;
|
||||||
} else {
|
} else {
|
||||||
distanceScaleFactor = vertScale;
|
distanceScaleFactor = vertScale;
|
||||||
@@ -493,7 +487,7 @@ public class CanvasController {
|
|||||||
yAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
yAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
}
|
}
|
||||||
if(horizontalInversion) {
|
if(horizontalInversion) {
|
||||||
xAxisLocation = CANVAS_WIDTH - RHS_BUFFER - (xAxisLocation - LHS_BUFFER);
|
xAxisLocation = CANVAS_WIDTH - BUFFER_SIZE - (xAxisLocation - BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
return new Point2D(xAxisLocation, yAxisLocation);
|
return new Point2D(xAxisLocation, yAxisLocation);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.geometry.Side;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.chart.LineChart;
|
||||||
|
import javafx.scene.chart.NumberAxis;
|
||||||
|
import javafx.scene.chart.XYChart;
|
||||||
|
import javafx.scene.chart.XYChart.Series;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
@@ -30,12 +35,19 @@ import seng302.models.stream.StreamParser;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
* Created by ptg19 on 29/03/17.
|
* Created by ptg19 on 29/03/17.
|
||||||
*/
|
*/
|
||||||
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
|
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private LineChart raceSparkLine;
|
||||||
|
@FXML
|
||||||
|
private NumberAxis sparklineYAxis;
|
||||||
@FXML
|
@FXML
|
||||||
private VBox positionVbox;
|
private VBox positionVbox;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -59,7 +71,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private boolean displayFps;
|
private boolean displayFps;
|
||||||
private Timeline timerTimeline;
|
private Timeline timerTimeline;
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
|
private static HashMap<Integer, Series<String, Double>> sparkLineData = new HashMap<>();
|
||||||
|
private static ArrayList<Yacht> racingBoats = new ArrayList<>();
|
||||||
private ImportantAnnotationsState importantAnnotations;
|
private ImportantAnnotationsState importantAnnotations;
|
||||||
private Yacht selectedBoat;
|
private Yacht selectedBoat;
|
||||||
|
|
||||||
@@ -67,6 +80,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
// Load a default important annotation state
|
// Load a default important annotation state
|
||||||
importantAnnotations = new ImportantAnnotationsState();
|
importantAnnotations = new ImportantAnnotationsState();
|
||||||
|
|
||||||
|
//Formatting the y axis of the sparkline
|
||||||
|
raceSparkLine.getYAxis().setRotate(180);
|
||||||
|
raceSparkLine.getYAxis().setTickLabelRotation(180);
|
||||||
|
raceSparkLine.getYAxis().setTranslateX(15);
|
||||||
|
raceSparkLine.getYAxis().setAutoRanging(false);
|
||||||
|
|
||||||
|
startingBoats = new ArrayList<>(StreamParser.getBoats().values());
|
||||||
|
|
||||||
includedCanvasController.setup(this);
|
includedCanvasController.setup(this);
|
||||||
includedCanvasController.initializeCanvas();
|
includedCanvasController.initializeCanvas();
|
||||||
initializeUpdateTimer();
|
initializeUpdateTimer();
|
||||||
@@ -74,14 +95,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
initialiseAnnotationSlider();
|
initialiseAnnotationSlider();
|
||||||
initialiseBoatSelectionComboBox();
|
initialiseBoatSelectionComboBox();
|
||||||
includedCanvasController.timer.start();
|
includedCanvasController.timer.start();
|
||||||
|
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
||||||
selectAnnotationBtn.setOnAction(event -> {
|
|
||||||
loadSelectAnnotationView();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The important annotations have been changed, update this view
|
* The important annotations have been changed, update this view
|
||||||
|
*
|
||||||
* @param importantAnnotationsState The current state of the selected annotations
|
* @param importantAnnotationsState The current state of the selected annotations
|
||||||
*/
|
*/
|
||||||
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
|
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
|
||||||
@@ -89,6 +109,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
|
setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the "select annotations" view in a new window
|
* Loads the "select annotations" view in a new window
|
||||||
*/
|
*/
|
||||||
@@ -126,6 +147,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
(observable, oldValue, newValue) -> displayFps = !displayFps);
|
(observable, oldValue, newValue) -> displayFps = !displayFps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initialiseAnnotationSlider() {
|
private void initialiseAnnotationSlider() {
|
||||||
annotationSlider.setLabelFormatter(new StringConverter<Double>() {
|
annotationSlider.setLabelFormatter(new StringConverter<Double>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -166,6 +188,79 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to add any new boats into the race that may have started late or not have had data received yet
|
||||||
|
*/
|
||||||
|
void updateSparkLine(){
|
||||||
|
// Collect the racing boats that aren't already in the chart
|
||||||
|
ArrayList<Yacht> sparkLineCandidates = startingBoats.stream().filter(yacht -> !sparkLineData.containsKey(yacht.getSourceID())
|
||||||
|
&& yacht.getPosition() != null & yacht.getPosition() != "-").collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
|
||||||
|
// Obtain the qualifying boats to set the max on the Y axis
|
||||||
|
racingBoats = startingBoats.stream().filter(yacht ->
|
||||||
|
yacht.getPosition() != null & yacht.getPosition() != "-").collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
sparklineYAxis.setUpperBound(racingBoats.size() + 1);
|
||||||
|
|
||||||
|
// Create a new data series for new boats
|
||||||
|
sparkLineCandidates.stream().filter(yacht -> yacht.getPosition() != null).forEach(yacht -> {
|
||||||
|
Series<String, Double> yachtData = new Series<>();
|
||||||
|
yachtData.setName(yacht.getBoatName());
|
||||||
|
yachtData.getData().add(new XYChart.Data<>(Integer.toString(yacht.getLegNumber()), 1 + racingBoats.size() - Double.parseDouble(yacht.getPosition())));
|
||||||
|
sparkLineData.put(yacht.getSourceID(), yachtData);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lambda function to sort the series in order of leg (later legs shown more to the right)
|
||||||
|
List<XYChart.Series<String, Double>> positions = new ArrayList<>(sparkLineData.values());
|
||||||
|
Collections.sort(positions, (o1, o2) -> {
|
||||||
|
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
|
||||||
|
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
|
||||||
|
if (leg2 < leg1){
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Adds the new data series to the sparkline (and set the colour of the series)
|
||||||
|
raceSparkLine.setCreateSymbols(false);
|
||||||
|
positions.stream().filter(spark -> !raceSparkLine.getData().contains(spark)).forEach(spark -> {
|
||||||
|
raceSparkLine.getData().add(spark);
|
||||||
|
spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the yachts sparkline of the desired boat and using the new leg number
|
||||||
|
* @param yacht The yacht to be updated on the sparkline
|
||||||
|
* @param legNumber the leg number that the position will be assigned to
|
||||||
|
*/
|
||||||
|
public static void updateYachtPositionSparkline(Yacht yacht, Integer legNumber){
|
||||||
|
XYChart.Series<String, Double> positionData = sparkLineData.get(yacht.getSourceID());
|
||||||
|
positionData.getData().add(new XYChart.Data<>(Integer.toString(legNumber), 1 + racingBoats.size() - Double.parseDouble(yacht.getPosition())));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the rgb string of the boats colour to use for the chart via css
|
||||||
|
* @param boatName boat passed in to get the boats colour
|
||||||
|
* @return the colour as an rgb string
|
||||||
|
*/
|
||||||
|
private String getBoatColorAsRGB(String boatName){
|
||||||
|
Color color = Color.WHITE;
|
||||||
|
for (Yacht yacht: startingBoats){
|
||||||
|
if (Objects.equals(yacht.getBoatName(), boatName)){
|
||||||
|
color = yacht.getColour();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return String.format( "#%02X%02X%02X",
|
||||||
|
(int)( color.getRed() * 255 ),
|
||||||
|
(int)( color.getGreen() * 255 ),
|
||||||
|
(int)( color.getBlue() * 255 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initalises a timer which updates elements of the RaceView such as wind direction, boat
|
* Initalises a timer which updates elements of the RaceView such as wind direction, boat
|
||||||
* orderings etc.. which are dependent on the info from the stream parser constantly.
|
* orderings etc.. which are dependent on the info from the stream parser constantly.
|
||||||
@@ -182,7 +277,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
updateWindDirection();
|
updateWindDirection();
|
||||||
updateOrder();
|
updateOrder();
|
||||||
updateBoatSelectionComboBox();
|
updateBoatSelectionComboBox();
|
||||||
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -233,21 +327,42 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
positionVbox.getChildren().removeAll();
|
positionVbox.getChildren().removeAll();
|
||||||
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
|
|
||||||
for (Yacht boat : StreamParser.getBoatsPos().values()) {
|
// list of racing boat id
|
||||||
if (boat.getBoatStatus() == 3) { // 3 is finish status
|
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
|
||||||
Text textToAdd = new Text(boat.getPosition() + ". " +
|
.getParticipants();
|
||||||
boat.getShortName() + " (Finished)");
|
ArrayList<Integer> participantIDs = new ArrayList<>();
|
||||||
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
for (Participant p : participants) {
|
||||||
positionVbox.getChildren().add(textToAdd);
|
participantIDs.add(p.getsourceID());
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
if (StreamParser.isRaceStarted()) {
|
||||||
Text textToAdd = new Text(boat.getPosition() + ". " +
|
for (Yacht boat : StreamParser.getBoatsPos().values()) {
|
||||||
boat.getShortName() + " ");
|
if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing
|
||||||
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
if (boat.getBoatStatus() == 3) { // 3 is finish status
|
||||||
textToAdd.setStyle("");
|
Text textToAdd = new Text(boat.getPosition() + ". " +
|
||||||
positionVbox.getChildren().add(textToAdd);
|
boat.getShortName() + " (Finished)");
|
||||||
|
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
||||||
|
positionVbox.getChildren().add(textToAdd);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Text textToAdd = new Text(boat.getPosition() + ". " +
|
||||||
|
boat.getShortName() + " ");
|
||||||
|
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
||||||
|
textToAdd.setStyle("");
|
||||||
|
positionVbox.getChildren().add(textToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Yacht boat : StreamParser.getBoats().values()) {
|
||||||
|
if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing
|
||||||
|
Text textToAdd = new Text(boat.getPosition() + ". " +
|
||||||
|
boat.getShortName() + " ");
|
||||||
|
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
||||||
|
textToAdd.setStyle("");
|
||||||
|
positionVbox.getChildren().add(textToAdd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,12 +437,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isDisplayFps() {
|
boolean isDisplayFps() {
|
||||||
return displayFps;
|
return displayFps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the important annotations for a specific BoatGroup
|
* Display the important annotations for a specific BoatGroup
|
||||||
|
*
|
||||||
* @param bg The boat group to set the annotations for
|
* @param bg The boat group to set the annotations for
|
||||||
*/
|
*/
|
||||||
private void setBoatGroupImportantAnnotations(BoatGroup bg) {
|
private void setBoatGroupImportantAnnotations(BoatGroup bg) {
|
||||||
@@ -427,4 +543,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
Stage getStage() {
|
Stage getStage() {
|
||||||
return stage;
|
return stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for when the boat attempts to add data to the sparkline (first checks if the sparkline contains info on it)
|
||||||
|
* @param yachtId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean sparkLineStatus(Integer yachtId) {
|
||||||
|
return sparkLineData.containsKey(yachtId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package seng302.controllers;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
@@ -11,7 +12,6 @@ import javafx.collections.ObservableList;
|
|||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.Parent;
|
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.TableColumn;
|
import javafx.scene.control.TableColumn;
|
||||||
@@ -23,8 +23,10 @@ import javafx.scene.layout.Pane;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
import seng302.models.stream.StreamParser;
|
import seng302.models.stream.StreamParser;
|
||||||
|
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
|
||||||
|
|
||||||
public class StartScreenController implements Initializable {
|
public class StartScreenController implements Initializable {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private GridPane gridPane;
|
private GridPane gridPane;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -48,19 +50,18 @@ public class StartScreenController implements Initializable {
|
|||||||
|
|
||||||
private boolean switchedToRaceView = false;
|
private boolean switchedToRaceView = false;
|
||||||
|
|
||||||
private void setContentPane(String jfxUrl){
|
private void setContentPane(String jfxUrl) {
|
||||||
try{
|
try {
|
||||||
// get the main controller anchor pane (MainView.fxml)
|
// get the main controller anchor pane (MainView.fxml)
|
||||||
AnchorPane contentPane = (AnchorPane) gridPane.getParent();
|
AnchorPane contentPane = (AnchorPane) gridPane.getParent();
|
||||||
contentPane.getChildren().removeAll();
|
contentPane.getChildren().removeAll();
|
||||||
contentPane.getChildren().clear();
|
contentPane.getChildren().clear();
|
||||||
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
|
contentPane.getChildren()
|
||||||
}
|
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
|
||||||
catch(javafx.fxml.LoadException e){
|
} catch (javafx.fxml.LoadException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
} catch (IOException e) {
|
||||||
catch(IOException e){
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +73,8 @@ public class StartScreenController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Running a timer to update the livestream status on welcome screen. Update interval is 1 second.
|
* Running a timer to update the livestream status on welcome screen. Update interval is 1
|
||||||
|
* second.
|
||||||
*/
|
*/
|
||||||
public void startStream() {
|
public void startStream() {
|
||||||
if (StreamParser.isStreamStatus()) {
|
if (StreamParser.isStreamStatus()) {
|
||||||
@@ -102,8 +104,10 @@ public class StartScreenController implements Initializable {
|
|||||||
updateTeamList();
|
updateTeamList();
|
||||||
timeTillLive.setTextFill(Color.RED);
|
timeTillLive.setTextFill(Color.RED);
|
||||||
switchToRaceViewButton.setDisable(false);
|
switchToRaceViewButton.setDisable(false);
|
||||||
String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60);
|
String timerMinute = Long
|
||||||
String timerSecond = Long.toString(StreamParser.getTimeSinceStart() % 60);
|
.toString(StreamParser.getTimeSinceStart() / 60);
|
||||||
|
String timerSecond = Long
|
||||||
|
.toString(StreamParser.getTimeSinceStart() % 60);
|
||||||
if (timerSecond.length() == 1) {
|
if (timerSecond.length() == 1) {
|
||||||
timerSecond = "0" + timerSecond;
|
timerSecond = "0" + timerSecond;
|
||||||
}
|
}
|
||||||
@@ -114,8 +118,10 @@ public class StartScreenController implements Initializable {
|
|||||||
updateTeamList();
|
updateTeamList();
|
||||||
timeTillLive.setTextFill(Color.BLACK);
|
timeTillLive.setTextFill(Color.BLACK);
|
||||||
switchToRaceViewButton.setDisable(false);
|
switchToRaceViewButton.setDisable(false);
|
||||||
String timerMinute = Long.toString(-1 * StreamParser.getTimeSinceStart() / 60);
|
String timerMinute = Long
|
||||||
String timerSecond = Long.toString(-1 * StreamParser.getTimeSinceStart() % 60);
|
.toString(-1 * StreamParser.getTimeSinceStart() / 60);
|
||||||
|
String timerSecond = Long
|
||||||
|
.toString(-1 * StreamParser.getTimeSinceStart() % 60);
|
||||||
if (timerSecond.length() == 1) {
|
if (timerSecond.length() == 1) {
|
||||||
timerSecond = "0" + timerSecond;
|
timerSecond = "0" + timerSecond;
|
||||||
}
|
}
|
||||||
@@ -143,19 +149,40 @@ public class StartScreenController implements Initializable {
|
|||||||
teamList.setItems(data);
|
teamList.setItems(data);
|
||||||
|
|
||||||
boatNameCol.setCellValueFactory(
|
boatNameCol.setCellValueFactory(
|
||||||
new PropertyValueFactory<>("boatName")
|
new PropertyValueFactory<>("boatName")
|
||||||
);
|
);
|
||||||
shortNameCol.setCellValueFactory(
|
shortNameCol.setCellValueFactory(
|
||||||
new PropertyValueFactory<>("shortName")
|
new PropertyValueFactory<>("shortName")
|
||||||
);
|
);
|
||||||
countryCol.setCellValueFactory(
|
countryCol.setCellValueFactory(
|
||||||
new PropertyValueFactory<>("country")
|
new PropertyValueFactory<>("country")
|
||||||
);
|
);
|
||||||
posCol.setCellValueFactory(
|
posCol.setCellValueFactory(
|
||||||
new PropertyValueFactory<>("position")
|
new PropertyValueFactory<>("position")
|
||||||
);
|
);
|
||||||
|
|
||||||
data.addAll(StreamParser.getBoatsPos().values());
|
// check if the boat is racing
|
||||||
|
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
|
||||||
|
.getParticipants();
|
||||||
|
ArrayList<Integer> participantIDs = new ArrayList<>();
|
||||||
|
for (Participant p : participants) {
|
||||||
|
participantIDs.add(p.getsourceID());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add boats to the start screen list
|
||||||
|
if (StreamParser.isRaceStarted()) { // if race is started, use StreamParser.getBoatsPos()
|
||||||
|
for (Yacht boat : StreamParser.getBoatsPos().values()) {
|
||||||
|
if (participantIDs.contains(boat.getSourceID())) {
|
||||||
|
data.add(boat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // else use StreamParser.getBoats()
|
||||||
|
for (Yacht boat : StreamParser.getBoats().values()) {
|
||||||
|
if (participantIDs.contains(boat.getSourceID())) {
|
||||||
|
data.add(boat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
teamList.refresh();
|
teamList.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
package seng302.models;
|
package seng302.models;
|
||||||
|
|
||||||
import javafx.event.EventHandler;
|
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.scene.CacheHint;
|
import javafx.scene.CacheHint;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
import javafx.scene.input.MouseDragEvent;
|
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import javafx.scene.shape.Line;
|
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;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package seng302.models;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by ryan_ on 16/03/2017.
|
* Enum for randomly generating colours.
|
||||||
*/
|
*/
|
||||||
public enum Colors {
|
public enum Colors {
|
||||||
RED, PERU, SEAGREEN, GREEN, BLUE, PURPLE;
|
RED, PERU, SEAGREEN, GREEN, BLUE, PURPLE;
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ public class Event {
|
|||||||
if (this.isFinishingEvent) {
|
if (this.isFinishingEvent) {
|
||||||
return (this.getTimeString() + ", " + this.getBoat().getBoatName() + " finished the race");
|
return (this.getTimeString() + ", " + this.getBoat().getBoatName() + " finished the race");
|
||||||
}
|
}
|
||||||
// System.out.println(this.getDistanceBetweenMarks());
|
|
||||||
return (this.getTimeString() + ", " + this.getBoat().getBoatName() + " passed " + this.mark1.getName() + " going heading " + this.getBoatHeading() + "°");
|
return (this.getTimeString() + ", " + this.getBoat().getBoatName() + " passed " + this.mark1.getName() + " going heading " + this.getBoatHeading() + "°");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
import seng302.models.mark.SingleMark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the leg of a race.
|
|
||||||
*/
|
|
||||||
public class Leg {
|
|
||||||
private int heading;
|
|
||||||
private int distance;
|
|
||||||
private boolean isFinishingLeg;
|
|
||||||
private SingleMark startingSingleMark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new leg
|
|
||||||
*
|
|
||||||
* @param heading, the magnetic heading of this leg
|
|
||||||
* @param distance, the total distance of this leg in meters
|
|
||||||
* @param singleMark, the singleMark this leg starts on
|
|
||||||
*/
|
|
||||||
public Leg(int heading, int distance, SingleMark singleMark) {
|
|
||||||
this.heading = heading;
|
|
||||||
this.distance = distance;
|
|
||||||
this.startingSingleMark = singleMark;
|
|
||||||
this.isFinishingLeg = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new leg
|
|
||||||
*
|
|
||||||
* @param heading, the magnetic heading of this leg
|
|
||||||
* @param distance, the total distance of this leg in meters
|
|
||||||
* @param markerName, the name of the marker this leg starts on
|
|
||||||
*/
|
|
||||||
public Leg(int heading, int distance, String markerName) {
|
|
||||||
this.heading = heading;
|
|
||||||
this.distance = distance;
|
|
||||||
this.startingSingleMark = new SingleMark(markerName);
|
|
||||||
this.isFinishingLeg = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the heading of this leg
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public int getHeading() {
|
|
||||||
return this.heading;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the heading for this leg
|
|
||||||
* @param heading
|
|
||||||
*/
|
|
||||||
public void setHeading(int heading) {
|
|
||||||
this.heading = heading;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the total distance of this leg in meters
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public int getDistance() {
|
|
||||||
return this.distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the distance of this leg in meters
|
|
||||||
* @param distance
|
|
||||||
*/
|
|
||||||
public void setDistance(int distance) {
|
|
||||||
this.distance = distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the marker this leg started on
|
|
||||||
* @return SingleMark
|
|
||||||
*/
|
|
||||||
public SingleMark getMarker() {
|
|
||||||
return this.startingSingleMark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the singleMark this leg starts on
|
|
||||||
* @param singleMark
|
|
||||||
*/
|
|
||||||
public void setMarker(SingleMark singleMark) {
|
|
||||||
this.startingSingleMark = singleMark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the marker this leg started on
|
|
||||||
* @return String
|
|
||||||
*/
|
|
||||||
public String getMarkerLabel() {
|
|
||||||
return this.startingSingleMark.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify whether or not the race finishes on this leg
|
|
||||||
*
|
|
||||||
* @param isFinishingLeg whether or not the race finishes on this leg
|
|
||||||
*/
|
|
||||||
public void setFinishingLeg(boolean isFinishingLeg) {
|
|
||||||
this.isFinishingLeg = isFinishingLeg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not the race finishes after this leg
|
|
||||||
* @return true if this the race finishes after this leg
|
|
||||||
*/
|
|
||||||
public boolean getIsFinishingLeg() {
|
|
||||||
return this.isFinishingLeg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
import javafx.animation.Timeline;
|
|
||||||
import javafx.beans.property.DoubleProperty;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by zyt10 on 17/03/17.
|
|
||||||
* this class is literally just to associate a timeline with a DoubleProperty x and y
|
|
||||||
*/
|
|
||||||
public class TimelineInfo {
|
|
||||||
private Timeline timeline;
|
|
||||||
private DoubleProperty x;
|
|
||||||
private DoubleProperty y;
|
|
||||||
|
|
||||||
public TimelineInfo(Timeline timeline, DoubleProperty x, DoubleProperty y) {
|
|
||||||
this.timeline = timeline;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Timeline getTimeline() {
|
|
||||||
return timeline;
|
|
||||||
}
|
|
||||||
public DoubleProperty getX() {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
public DoubleProperty getY() {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package seng302.models;
|
package seng302.models;
|
||||||
|
|
||||||
|
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
import seng302.controllers.RaceViewController;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -9,9 +11,10 @@ import java.text.SimpleDateFormat;
|
|||||||
* Yacht class for the racing boat.
|
* Yacht class for the racing boat.
|
||||||
*
|
*
|
||||||
* Class created to store more variables (eg. boat statuses) compared to the XMLParser boat class,
|
* Class created to store more variables (eg. boat statuses) compared to the XMLParser boat class,
|
||||||
* also done outside Boat class because some old variables are not used anymore.
|
* also done outside Boat class because some old variables are not used anymore.
|
||||||
*/
|
*/
|
||||||
public class Yacht {
|
public class Yacht {
|
||||||
|
|
||||||
// Used in boat group
|
// Used in boat group
|
||||||
private Color colour;
|
private Color colour;
|
||||||
private double velocity;
|
private double velocity;
|
||||||
@@ -33,21 +36,22 @@ public class Yacht {
|
|||||||
// Mark rounding
|
// Mark rounding
|
||||||
private Long markRoundingTime;
|
private Long markRoundingTime;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used in EventTest and RaceTest.
|
* Used in EventTest and RaceTest.
|
||||||
*
|
*
|
||||||
* @param boatName Create a yacht object with name.
|
* @param boatName Create a yacht object with name.
|
||||||
*/
|
*/
|
||||||
public Yacht (String boatName) {
|
public Yacht(String boatName) {
|
||||||
this.boatName = boatName;
|
this.boatName = boatName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used in BoatGroupTest.
|
* Used in BoatGroupTest.
|
||||||
*
|
*
|
||||||
* @param boatName The name of the team sailing the boat
|
* @param boatName The name of the team sailing the boat
|
||||||
* @param boatVelocity The speed of the boat in meters/second
|
* @param boatVelocity The speed of the boat in meters/second
|
||||||
* @param shortName A shorter version of the teams name
|
* @param shortName A shorter version of the teams name
|
||||||
*/
|
*/
|
||||||
public Yacht(String boatName, double boatVelocity, String shortName, int id) {
|
public Yacht(String boatName, double boatVelocity, String shortName, int id) {
|
||||||
this.boatName = boatName;
|
this.boatName = boatName;
|
||||||
@@ -56,30 +60,37 @@ public class Yacht {
|
|||||||
this.sourceID = id;
|
this.sourceID = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Yacht(String boatType, Integer sourceID, String hullID, String shortName, String boatName, String country) {
|
public Yacht(String boatType, Integer sourceID, String hullID, String shortName,
|
||||||
|
String boatName, String country) {
|
||||||
this.boatType = boatType;
|
this.boatType = boatType;
|
||||||
this.sourceID = sourceID;
|
this.sourceID = sourceID;
|
||||||
this.hullID = hullID;
|
this.hullID = hullID;
|
||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
this.boatName = boatName;
|
this.boatName = boatName;
|
||||||
this.country = country;
|
this.country = country;
|
||||||
|
this.position = "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBoatType() {
|
public String getBoatType() {
|
||||||
return boatType;
|
return boatType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getSourceID() {
|
public Integer getSourceID() {
|
||||||
return sourceID;
|
return sourceID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHullID() {
|
public String getHullID() {
|
||||||
return hullID;
|
return hullID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getShortName() {
|
public String getShortName() {
|
||||||
return shortName;
|
return shortName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBoatName() {
|
public String getBoatName() {
|
||||||
return boatName;
|
return boatName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCountry() {
|
public String getCountry() {
|
||||||
return country;
|
return country;
|
||||||
}
|
}
|
||||||
@@ -97,6 +108,9 @@ public class Yacht {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setLegNumber(Integer legNumber) {
|
public void setLegNumber(Integer legNumber) {
|
||||||
|
if (colour != null && position != "-" && legNumber != this.legNumber&& RaceViewController.sparkLineStatus(sourceID)) {
|
||||||
|
RaceViewController.updateYachtPositionSparkline(this, legNumber);
|
||||||
|
}
|
||||||
this.legNumber = legNumber;
|
this.legNumber = legNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ public abstract class Mark {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mark instance by passing its name and type
|
* Create a mark instance by passing its name and type
|
||||||
|
*
|
||||||
* @param name the name of the mark
|
* @param name the name of the mark
|
||||||
* @param markType the type of mark. either GATE_MARK or SINGLE_MARK.
|
* @param markType the type of mark. either GATE_MARK or SINGLE_MARK.
|
||||||
*/
|
*/
|
||||||
public Mark (String name, MarkType markType, int id) {
|
public Mark(String name, MarkType markType, int id) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.markType = markType;
|
this.markType = markType;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@@ -47,20 +48,24 @@ public abstract class Mark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the heading in radians from geographical location with latitude1, longitude 1 to geographical
|
* Calculate the heading in radians from geographical location with latitude1, longitude 1 to
|
||||||
* latitude2, longitude 2
|
* geographical latitude2, longitude 2
|
||||||
|
*
|
||||||
* @param longitude1 Longitude of first point in degrees
|
* @param longitude1 Longitude of first point in degrees
|
||||||
* @param longitude2 Longitude of second point in degrees
|
* @param longitude2 Longitude of second point in degrees
|
||||||
* @param latitude1 Latitude of first point in degrees
|
* @param latitude1 Latitude of first point in degrees
|
||||||
* @param latitude2 Latitude of first point in degrees
|
* @param latitude2 Latitude of first point in degrees
|
||||||
* @return Heading in radians
|
* @return Heading in radians
|
||||||
*/
|
*/
|
||||||
public static double calculateHeadingRad (Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
|
public static double calculateHeadingRad(Double latitude1, Double longitude1, Double latitude2,
|
||||||
|
Double longitude2) {
|
||||||
latitude1 = Math.toRadians(latitude1);
|
latitude1 = Math.toRadians(latitude1);
|
||||||
latitude2 = Math.toRadians(latitude2);
|
latitude2 = Math.toRadians(latitude2);
|
||||||
Double longDiff= Math.toRadians(longitude2-longitude1);
|
Double longDiff = Math.toRadians(longitude2 - longitude1);
|
||||||
Double y = Math.sin(longDiff)*Math.cos(latitude2);
|
Double y = Math.sin(longDiff) * Math.cos(latitude2);
|
||||||
Double x = Math.cos(latitude1)*Math.sin(latitude2)-Math.sin(latitude1)*Math.cos(latitude2)*Math.cos(longDiff);
|
Double x =
|
||||||
|
Math.cos(latitude1) * Math.sin(latitude2) - Math.sin(latitude1) * Math.cos(latitude2)
|
||||||
|
* Math.cos(longDiff);
|
||||||
return Math.atan2(y, x);
|
return Math.atan2(y, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,33 +85,35 @@ public abstract class Mark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the distance in meters from geographical location with latitude1, longitude 1 to geographical
|
* Calculate the distance in meters from geographical location with latitude1, longitude 1 to
|
||||||
* latitude2, longitude 2
|
* geographical latitude2, longitude 2
|
||||||
*
|
*
|
||||||
* @param longitude1 Longitude of first point in degrees
|
* @param longitude1 Longitude of first point in degrees
|
||||||
* @param longitude2 Longitude of second point in degrees
|
* @param longitude2 Longitude of second point in degrees
|
||||||
* @param latitude1 Latitude of first point in degrees
|
* @param latitude1 Latitude of first point in degrees
|
||||||
* @param latitude2 Latitude of first point in degrees
|
* @param latitude2 Latitude of first point in degrees
|
||||||
* @return Distance in meters
|
* @return Distance in meters
|
||||||
*/
|
*/
|
||||||
public static Double calculateDistance (Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
|
public static Double calculateDistance(Double latitude1, Double longitude1, Double latitude2,
|
||||||
|
Double longitude2) {
|
||||||
Double theta = longitude1 - longitude2;
|
Double theta = longitude1 - longitude2;
|
||||||
Double dist = Math.sin(Math.toRadians(latitude1)) * Math.sin(Math.toRadians(latitude2)) +
|
Double dist = Math.sin(Math.toRadians(latitude1)) * Math.sin(Math.toRadians(latitude2)) +
|
||||||
Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(latitude2)) *
|
Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(latitude2)) *
|
||||||
Math.cos(Math.toRadians(theta));
|
Math.cos(Math.toRadians(theta));
|
||||||
dist = Math.acos(dist);
|
dist = Math.acos(dist);
|
||||||
dist = Math.toDegrees(dist);
|
dist = Math.toDegrees(dist);
|
||||||
dist = dist * 60 * 1.1508; //nautical mile (distance between two degrees) * (degrees in a minute)
|
dist = dist * 60
|
||||||
|
* 1.1508; //nautical mile (distance between two degrees) * (degrees in a minute)
|
||||||
dist = dist * 1609.344; //ratio of miles to metres
|
dist = dist * 1609.344; //ratio of miles to metres
|
||||||
return dist;
|
return dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MarkType getMarkType() {
|
public MarkType getMarkType() {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import javafx.scene.shape.Circle;
|
|||||||
import javafx.scene.shape.Line;
|
import javafx.scene.shape.Line;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by CJIRWIN on 26/04/2017.
|
* Grouping of javaFX objects needed to represent a Mark on screen.
|
||||||
*/
|
*/
|
||||||
public class MarkGroup extends Group {
|
public class MarkGroup extends Group {
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ package seng302.models.mark;
|
|||||||
* Created by Haoming Yin (hyi25) on 17/3/17.
|
* Created by Haoming Yin (hyi25) on 17/3/17.
|
||||||
*/
|
*/
|
||||||
public enum MarkType {
|
public enum MarkType {
|
||||||
SINGLE_MARK, OPEN_GATE, CLOSED_GATE
|
SINGLE_MARK, OPEN_GATE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@@ -31,69 +32,65 @@ import seng302.models.stream.packets.StreamPacket;
|
|||||||
* that are threadsafe so the visualiser can always access the latest speed and position available
|
* that are threadsafe so the visualiser can always access the latest speed and position available
|
||||||
* Created by kre39 on 23/04/17.
|
* Created by kre39 on 23/04/17.
|
||||||
*/
|
*/
|
||||||
public class StreamParser extends Thread{
|
public class StreamParser extends Thread {
|
||||||
|
|
||||||
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> markPositions = new ConcurrentHashMap<>();
|
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> markPositions = new ConcurrentHashMap<>();
|
||||||
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatPositions = new ConcurrentHashMap<>();
|
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatPositions = new ConcurrentHashMap<>();
|
||||||
private String threadName;
|
private String threadName;
|
||||||
private Thread t;
|
private Thread t;
|
||||||
private static boolean newRaceXmlReceived = false;
|
private static boolean newRaceXmlReceived = false;
|
||||||
private static boolean raceStarted = false;
|
private static boolean raceStarted = false;
|
||||||
private static XMLParser xmlObject;
|
private static XMLParser xmlObject;
|
||||||
private static boolean raceFinished = false;
|
private static boolean raceFinished = false;
|
||||||
private static boolean streamStatus = false;
|
private static boolean streamStatus = false;
|
||||||
private static long timeSinceStart = -1;
|
private static long timeSinceStart = -1;
|
||||||
private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>();
|
private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>();
|
||||||
private static Map<Long, Yacht> boatsPos = new ConcurrentSkipListMap<>();
|
private static Map<Long, Yacht> boatsPos = new ConcurrentSkipListMap<>();
|
||||||
private static double windDirection = 0;
|
private static double windDirection = 0;
|
||||||
private static Long currentTimeLong;
|
private static Long currentTimeLong;
|
||||||
private static String currentTimeString;
|
private static String currentTimeString;
|
||||||
private static boolean appRunning;
|
private static boolean appRunning;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to initialise the thread name and stream parser object so a thread can be executed
|
* Used to initialise the thread name and stream parser object so a thread can be executed
|
||||||
*
|
*
|
||||||
* @param threadName name of the thread
|
* @param threadName name of the thread
|
||||||
*/
|
*/
|
||||||
public StreamParser(String threadName){
|
public StreamParser(String threadName) {
|
||||||
this.threadName = threadName;
|
this.threadName = threadName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to within threading so when the stream parser thread runs, it will keep looking for a packet to
|
* Used to within threading so when the stream parser thread runs, it will keep looking for a
|
||||||
* process until it is unable to find anymore packets
|
* packet to process until it is unable to find anymore packets
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public void run(){
|
public void run() {
|
||||||
appRunning = true;
|
appRunning = true;
|
||||||
try {
|
try {
|
||||||
System.out.println("[CLIENT] Start of stream");
|
streamStatus = true;
|
||||||
streamStatus = true;
|
xmlObject = new XMLParser();
|
||||||
xmlObject = new XMLParser();
|
while (StreamReceiver.packetBuffer == null || StreamReceiver.packetBuffer.size() < 1) {
|
||||||
while (StreamReceiver.packetBuffer == null || StreamReceiver.packetBuffer.size() < 1) {
|
Thread.sleep(1);
|
||||||
Thread.sleep(1);
|
}
|
||||||
}
|
while (appRunning) {
|
||||||
while (appRunning){
|
StreamPacket packet = StreamReceiver.packetBuffer.take();
|
||||||
StreamPacket packet = StreamReceiver.packetBuffer.take();
|
parsePacket(packet);
|
||||||
parsePacket(packet);
|
Thread.sleep(1);
|
||||||
Thread.sleep(1);
|
while (StreamReceiver.packetBuffer.peek() == null) {
|
||||||
while (StreamReceiver.packetBuffer.peek() == null) {
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception e) {
|
||||||
} catch (Exception e){
|
e.printStackTrace();
|
||||||
e.printStackTrace();
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to start the stream parser thread when multithreading
|
* Used to start the stream parser thread when multithreading
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public void start () {
|
public void start() {
|
||||||
System.out.println("[CLIENT] Starting " + threadName );
|
|
||||||
if (t == null) {
|
if (t == null) {
|
||||||
t = new Thread (this, threadName);
|
t = new Thread(this, threadName);
|
||||||
t.start ();
|
t.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,55 +100,53 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet the packet to be looked at and processed
|
* @param packet the packet to be looked at and processed
|
||||||
*/
|
*/
|
||||||
private static void parsePacket(StreamPacket packet) {
|
private static void parsePacket(StreamPacket packet) {
|
||||||
try{
|
try {
|
||||||
switch (packet.getType()){
|
switch (packet.getType()) {
|
||||||
case HEARTBEAT:
|
case HEARTBEAT:
|
||||||
extractHeartBeat(packet);
|
extractHeartBeat(packet);
|
||||||
break;
|
break;
|
||||||
case RACE_STATUS:
|
case RACE_STATUS:
|
||||||
extractRaceStatus(packet);
|
extractRaceStatus(packet);
|
||||||
break;
|
break;
|
||||||
case DISPLAY_TEXT_MESSAGE:
|
case DISPLAY_TEXT_MESSAGE:
|
||||||
extractDisplayMessage(packet);
|
extractDisplayMessage(packet);
|
||||||
break;
|
break;
|
||||||
case XML_MESSAGE:
|
case XML_MESSAGE:
|
||||||
newRaceXmlReceived = true;
|
newRaceXmlReceived = true;
|
||||||
extractXmlMessage(packet);
|
extractXmlMessage(packet);
|
||||||
break;
|
break;
|
||||||
case RACE_START_STATUS:
|
case RACE_START_STATUS:
|
||||||
extractRaceStartStatus(packet);
|
extractRaceStartStatus(packet);
|
||||||
break;
|
break;
|
||||||
case YACHT_EVENT_CODE:
|
case YACHT_EVENT_CODE:
|
||||||
extractYachtEventCode(packet);
|
extractYachtEventCode(packet);
|
||||||
break;
|
break;
|
||||||
case YACHT_ACTION_CODE:
|
case YACHT_ACTION_CODE:
|
||||||
extractYachtActionCode(packet);
|
extractYachtActionCode(packet);
|
||||||
break;
|
break;
|
||||||
case CHATTER_TEXT:
|
case CHATTER_TEXT:
|
||||||
extractChatterText(packet);
|
extractChatterText(packet);
|
||||||
break;
|
break;
|
||||||
case BOAT_LOCATION:
|
case BOAT_LOCATION:
|
||||||
extractBoatLocation(packet);
|
extractBoatLocation(packet);
|
||||||
break;
|
break;
|
||||||
case MARK_ROUNDING:
|
case MARK_ROUNDING:
|
||||||
extractMarkRounding(packet);
|
extractMarkRounding(packet);
|
||||||
break;
|
break;
|
||||||
case COURSE_WIND:
|
case COURSE_WIND:
|
||||||
extractCourseWind(packet);
|
extractCourseWind(packet);
|
||||||
break;
|
break;
|
||||||
case AVG_WIND:
|
case AVG_WIND:
|
||||||
extractAvgWind(packet);
|
extractAvgWind(packet);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
//System.out.println(packet.getType().toString());
|
}
|
||||||
}
|
} catch (NullPointerException e) {
|
||||||
}
|
System.out.println("Error parsing packet");
|
||||||
catch (NullPointerException e){
|
}
|
||||||
System.out.println("Error parsing packet");
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the seq num used in the heartbeat packet
|
* Extracts the seq num used in the heartbeat packet
|
||||||
@@ -179,42 +174,41 @@ public class StreamParser extends Thread{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the useful race status data from race status type packets. This method will also print to the
|
* Extracts the useful race status data from race status type packets. This method will also
|
||||||
* console the current state of the race (if it has started/finished or is about to start), along side
|
* print to the console the current state of the race (if it has started/finished or is about to
|
||||||
* this it'll also display the amount of time since the race has started or time till it starts
|
* start), along side this it'll also display the amount of time since the race has started or
|
||||||
|
* time till it starts
|
||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
*/
|
*/
|
||||||
private static void extractRaceStatus(StreamPacket packet){
|
private static void extractRaceStatus(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long currentTime = bytesToLong(Arrays.copyOfRange(payload,1,7));
|
long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long raceId = bytesToLong(Arrays.copyOfRange(payload,7,11));
|
long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11));
|
||||||
int raceStatus = payload[11];
|
int raceStatus = payload[11];
|
||||||
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18));
|
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload, 12, 18));
|
||||||
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
|
long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20));
|
||||||
long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22));
|
long windSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22));
|
||||||
|
|
||||||
currentTimeLong = currentTime;
|
currentTimeLong = currentTime;
|
||||||
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
||||||
if (xmlObject.getRegattaXML() != null) {
|
if (xmlObject.getRegattaXML() != null) {
|
||||||
format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString()));
|
format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString()));
|
||||||
currentTimeString = format.format((new Date (currentTime)).getTime());
|
currentTimeString = format.format((new Date(currentTime)).getTime());
|
||||||
}
|
}
|
||||||
long timeTillStart = ((new Date (expectedStartTime)).getTime() - (new Date (currentTime)).getTime())/1000;
|
long timeTillStart =
|
||||||
|
((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
|
||||||
|
|
||||||
if (timeTillStart > 0) {
|
if (timeTillStart > 0) {
|
||||||
timeSinceStart = timeTillStart;
|
timeSinceStart = timeTillStart;
|
||||||
//System.out.println("Time till start: " + timeTillStart + " Seconds");
|
|
||||||
} else {
|
} else {
|
||||||
if (raceStatus == 4 || raceStatus == 8){
|
if (raceStatus == 4 || raceStatus == 8) {
|
||||||
raceFinished = true;
|
raceFinished = true;
|
||||||
raceStarted = false;
|
raceStarted = false;
|
||||||
System.out.println("[CLIENT] Race has finished");
|
} else if (!raceStarted) {
|
||||||
} else if (!raceStarted){
|
|
||||||
raceStarted = true;
|
raceStarted = true;
|
||||||
raceFinished = false;
|
raceFinished = false;
|
||||||
System.out.println("[CLIENT] Race has started");
|
|
||||||
}
|
}
|
||||||
timeSinceStart = timeTillStart;
|
timeSinceStart = timeTillStart;
|
||||||
}
|
}
|
||||||
@@ -225,18 +219,20 @@ public class StreamParser extends Thread{
|
|||||||
int noBoats = payload[22];
|
int noBoats = payload[22];
|
||||||
int raceType = payload[23];
|
int raceType = payload[23];
|
||||||
boatsPos = new TreeMap<>();
|
boatsPos = new TreeMap<>();
|
||||||
for (int i = 0; i < noBoats; i++){
|
for (int i = 0; i < noBoats; i++) {
|
||||||
long boatStatusSourceID = bytesToLong(Arrays.copyOfRange(payload,24 + (i * 20),28+ (i * 20)));
|
long boatStatusSourceID = bytesToLong(
|
||||||
|
Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20)));
|
||||||
Yacht boat = boats.get((int) boatStatusSourceID);
|
Yacht boat = boats.get((int) boatStatusSourceID);
|
||||||
boat.setBoatStatus((int)payload[28 + (i * 20)]);
|
boat.setBoatStatus((int) payload[28 + (i * 20)]);
|
||||||
boat.setLegNumber((int)payload[29 + (i * 20)]);
|
boat.setLegNumber((int) payload[29 + (i * 20)]);
|
||||||
boat.setPenaltiesAwarded((int)payload[30 + (i * 20)]);
|
boat.setPenaltiesAwarded((int) payload[30 + (i * 20)]);
|
||||||
boat.setPenaltiesServed((int)payload[31 + (i * 20)]);
|
boat.setPenaltiesServed((int) payload[31 + (i * 20)]);
|
||||||
Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,32 + (i * 20),38+ (i * 20)));
|
Long estTimeAtNextMark = bytesToLong(
|
||||||
|
Arrays.copyOfRange(payload, 32 + (i * 20), 38 + (i * 20)));
|
||||||
boat.setEstimateTimeAtNextMark(estTimeAtNextMark);
|
boat.setEstimateTimeAtNextMark(estTimeAtNextMark);
|
||||||
Long estTimeAtFinish = bytesToLong(Arrays.copyOfRange(payload,38 + (i * 20),44+ (i * 20)));
|
Long estTimeAtFinish = bytesToLong(
|
||||||
|
Arrays.copyOfRange(payload, 38 + (i * 20), 44 + (i * 20)));
|
||||||
boat.setEstimateTimeAtFinish(estTimeAtFinish);
|
boat.setEstimateTimeAtFinish(estTimeAtFinish);
|
||||||
boatsPos.put(estTimeAtFinish, boat);
|
|
||||||
// String boatStatus = "SourceID: " + boatStatusSourceID;
|
// String boatStatus = "SourceID: " + boatStatusSourceID;
|
||||||
// boatStatus += "\nBoat Status: " + (int)payload[28 + (i * 20)];
|
// boatStatus += "\nBoat Status: " + (int)payload[28 + (i * 20)];
|
||||||
// boatStatus += "\nLegNumber: " + (int)payload[29 + (i * 20)];
|
// boatStatus += "\nLegNumber: " + (int)payload[29 + (i * 20)];
|
||||||
@@ -264,15 +260,16 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
*/
|
*/
|
||||||
private static void extractDisplayMessage(StreamPacket packet){
|
private static void extractDisplayMessage(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int numOfLines = payload[3];
|
int numOfLines = payload[3];
|
||||||
int totalLen = 0;
|
int totalLen = 0;
|
||||||
for (int i = 0; i < numOfLines; i++){
|
for (int i = 0; i < numOfLines; i++) {
|
||||||
int lineNum = payload[4 + totalLen];
|
int lineNum = payload[4 + totalLen];
|
||||||
int textLength = payload[5 + totalLen];
|
int textLength = payload[5 + totalLen];
|
||||||
byte[] messageTextBytes = Arrays.copyOfRange(payload,6 + totalLen,6 + textLength + totalLen);
|
byte[] messageTextBytes = Arrays
|
||||||
|
.copyOfRange(payload, 6 + totalLen, 6 + textLength + totalLen);
|
||||||
String messageText = new String(messageTextBytes);
|
String messageText = new String(messageTextBytes);
|
||||||
totalLen += 2 + textLength;
|
totalLen += 2 + textLength;
|
||||||
}
|
}
|
||||||
@@ -283,13 +280,14 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
*/
|
*/
|
||||||
private static void extractXmlMessage(StreamPacket packet){
|
private static void extractXmlMessage(StreamPacket packet) {
|
||||||
|
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
|
|
||||||
int messageType = payload[9];
|
int messageType = payload[9];
|
||||||
long messageLength = bytesToLong(Arrays.copyOfRange(payload,12,14));
|
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
|
||||||
String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messageLength)))).trim();
|
String xmlMessage = new String(
|
||||||
|
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
|
||||||
|
|
||||||
//Create XML document Object
|
//Create XML document Object
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
@@ -318,12 +316,12 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
*/
|
*/
|
||||||
private static void extractRaceStartStatus(StreamPacket packet){
|
private static void extractRaceStartStatus(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long raceStartTime = bytesToLong(Arrays.copyOfRange(payload,9,15));
|
long raceStartTime = bytesToLong(Arrays.copyOfRange(payload, 9, 15));
|
||||||
long raceId = bytesToLong(Arrays.copyOfRange(payload,15,19));
|
long raceId = bytesToLong(Arrays.copyOfRange(payload, 15, 19));
|
||||||
int notificationType = payload[19];
|
int notificationType = payload[19];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,28 +331,28 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
*/
|
*/
|
||||||
private static void extractYachtEventCode(StreamPacket packet){
|
private static void extractYachtEventCode(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long raceId = bytesToLong(Arrays.copyOfRange(payload,9,13));
|
long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
||||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload,13,17));
|
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
||||||
long incidentId = bytesToLong(Arrays.copyOfRange(payload,17,21));
|
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21));
|
||||||
int eventId = payload[21];
|
int eventId = payload[21];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a yacht action occurs this will parse the parse the byte array to retrieve the necessary info,
|
* When a yacht action occurs this will parse the parse the byte array to retrieve the necessary
|
||||||
* currently unused
|
* info, currently unused
|
||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
*/
|
*/
|
||||||
private static void extractYachtActionCode(StreamPacket packet){
|
private static void extractYachtActionCode(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload,9,13));
|
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
||||||
long incidentId = bytesToLong(Arrays.copyOfRange(payload,13,17));
|
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
||||||
int eventId = payload[17];
|
int eventId = payload[17];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,51 +361,54 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
*/
|
*/
|
||||||
private static void extractChatterText(StreamPacket packet){
|
private static void extractChatterText(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int messageType = payload[1];
|
int messageType = payload[1];
|
||||||
int length = payload[2];
|
int length = payload[2];
|
||||||
String message = new String(Arrays.copyOfRange(payload,3,3 + length));
|
String message = new String(Arrays.copyOfRange(payload, 3, 3 + length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to breakdown the boatlocation packets so the boat coordinates, id and groundspeed are all used
|
* Used to breakdown the boatlocation packets so the boat coordinates, id and groundspeed are
|
||||||
* All the other extra data is still being read and translated however is unused.
|
* all used All the other extra data is still being read and translated however is unused.
|
||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
*/
|
*/
|
||||||
private static void extractBoatLocation(StreamPacket packet){
|
private static void extractBoatLocation(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
|
|
||||||
int deviceType = (int)payload[15];
|
int deviceType = (int) payload[15];
|
||||||
long timeValid = bytesToLong(Arrays.copyOfRange(payload,1,7));
|
long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long seq = bytesToLong(Arrays.copyOfRange(payload,11,15));
|
long seq = bytesToLong(Arrays.copyOfRange(payload, 11, 15));
|
||||||
long boatId = bytesToLong(Arrays.copyOfRange(payload,7,11));
|
long boatId = bytesToLong(Arrays.copyOfRange(payload, 7, 11));
|
||||||
long rawLat = bytesToLong(Arrays.copyOfRange(payload,16,20));
|
long rawLat = bytesToLong(Arrays.copyOfRange(payload, 16, 20));
|
||||||
long rawLon = bytesToLong(Arrays.copyOfRange(payload,20,24));
|
long rawLon = bytesToLong(Arrays.copyOfRange(payload, 20, 24));
|
||||||
//Converts the double to a usable lat/lon
|
//Converts the double to a usable lat/lon
|
||||||
double lat = ((180d * (double)rawLat)/Math.pow(2,31));
|
double lat = ((180d * (double) rawLat) / Math.pow(2, 31));
|
||||||
double lon = ((180d *(double)rawLon)/Math.pow(2,31));
|
double lon = ((180d * (double) rawLon) / Math.pow(2, 31));
|
||||||
long heading = bytesToLong(Arrays.copyOfRange(payload,28,30));
|
long heading = bytesToLong(Arrays.copyOfRange(payload, 28, 30));
|
||||||
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload,38,40))/1000.0;
|
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0;
|
||||||
|
|
||||||
//type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat
|
//type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat
|
||||||
if (deviceType == 1){
|
if (deviceType == 1) {
|
||||||
BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed);
|
BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon,
|
||||||
|
heading, groundSpeed);
|
||||||
|
|
||||||
//add a new priority que to the boatPositions HashMap
|
//add a new priority que to the boatPositions HashMap
|
||||||
if (!boatPositions.containsKey(boatId)){
|
if (!boatPositions.containsKey(boatId)) {
|
||||||
boatPositions.put(boatId, new PriorityBlockingQueue<>(256, new Comparator<BoatPositionPacket>() {
|
boatPositions.put(boatId,
|
||||||
@Override
|
new PriorityBlockingQueue<>(256, new Comparator<BoatPositionPacket>() {
|
||||||
public int compare(BoatPositionPacket p1, BoatPositionPacket p2) {
|
@Override
|
||||||
return (int) (p1.getTimeValid() - p2.getTimeValid());
|
public int compare(BoatPositionPacket p1, BoatPositionPacket p2) {
|
||||||
}
|
return (int) (p1.getTimeValid() - p2.getTimeValid());
|
||||||
}));
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
boatPositions.get(boatId).put(boatPacket);
|
boatPositions.get(boatId).put(boatPacket);
|
||||||
} else if (deviceType == 3){
|
} else if (deviceType == 3) {
|
||||||
BoatPositionPacket markPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed);
|
BoatPositionPacket markPacket = new BoatPositionPacket(boatId, timeValid, lat, lon,
|
||||||
|
heading, groundSpeed);
|
||||||
|
|
||||||
//add a new priority que to the boatPositions HashMap
|
//add a new priority que to the boatPositions HashMap
|
||||||
if (!markPositions.containsKey(boatId)) {
|
if (!markPositions.containsKey(boatId)) {
|
||||||
@@ -428,19 +429,19 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet The packet containing the payload
|
* @param packet The packet containing the payload
|
||||||
*/
|
*/
|
||||||
private static void extractMarkRounding(StreamPacket packet){
|
private static void extractMarkRounding(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long raceId = bytesToLong(Arrays.copyOfRange(payload,9,13));
|
long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
||||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload,13,17));
|
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
||||||
int boatStatus = payload[17];
|
int boatStatus = payload[17];
|
||||||
int roundingSide = payload[18];
|
int roundingSide = payload[18];
|
||||||
int markType = payload[19];
|
int markType = payload[19];
|
||||||
int markId = payload[20];
|
int markId = payload[20];
|
||||||
|
|
||||||
// assign mark rounding time to boat
|
// assign mark rounding time to boat
|
||||||
boats.get((int)subjectId).setMarkRoundingTime(timeStamp);
|
boats.get((int) subjectId).setMarkRoundingTime(timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -448,21 +449,29 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet The packet containing the payload
|
* @param packet The packet containing the payload
|
||||||
*/
|
*/
|
||||||
private static void extractCourseWind(StreamPacket packet){
|
private static void extractCourseWind(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int selectedWindId = payload[1];
|
int selectedWindId = payload[1];
|
||||||
int loopCount = payload[2];
|
int loopCount = payload[2];
|
||||||
ArrayList<String> windInfo = new ArrayList<>();
|
ArrayList<String> windInfo = new ArrayList<>();
|
||||||
for (int i = 0; i < loopCount; i++){
|
for (int i = 0; i < loopCount; i++) {
|
||||||
String wind = "WindId: " + payload[3 + (20 * i)];
|
String wind = "WindId: " + payload[3 + (20 * i)];
|
||||||
wind += "\nTime: " + bytesToLong(Arrays.copyOfRange(payload,4 + (20 * i),10 + (20 * i)));
|
wind +=
|
||||||
wind += "\nRaceId: " + bytesToLong(Arrays.copyOfRange(payload,10 + (20 * i),14 + (20 * i)));
|
"\nTime: " + bytesToLong(Arrays.copyOfRange(payload, 4 + (20 * i), 10 + (20 * i)));
|
||||||
wind += "\nWindDirection: " + bytesToLong(Arrays.copyOfRange(payload,14 + (20 * i),16 + (20 * i)));
|
wind += "\nRaceId: " + bytesToLong(
|
||||||
wind += "\nWindSpeed: " + bytesToLong(Arrays.copyOfRange(payload,16 + (20 * i),18 + (20 * i)));
|
Arrays.copyOfRange(payload, 10 + (20 * i), 14 + (20 * i)));
|
||||||
wind += "\nBestUpWindAngle: " + bytesToLong(Arrays.copyOfRange(payload,18 + (20 * i),20 + (20 * i)));
|
wind += "\nWindDirection: " + bytesToLong(
|
||||||
wind += "\nBestDownWindAngle: " + bytesToLong(Arrays.copyOfRange(payload,20 + (20 * i),22 + (20 * i)));
|
Arrays.copyOfRange(payload, 14 + (20 * i), 16 + (20 * i)));
|
||||||
wind += "\nFlags: " + String.format("%8s", Integer.toBinaryString(payload[22 + (20 * i)] & 0xFF)).replace(' ', '0');
|
wind += "\nWindSpeed: " + bytesToLong(
|
||||||
|
Arrays.copyOfRange(payload, 16 + (20 * i), 18 + (20 * i)));
|
||||||
|
wind += "\nBestUpWindAngle: " + bytesToLong(
|
||||||
|
Arrays.copyOfRange(payload, 18 + (20 * i), 20 + (20 * i)));
|
||||||
|
wind += "\nBestDownWindAngle: " + bytesToLong(
|
||||||
|
Arrays.copyOfRange(payload, 20 + (20 * i), 22 + (20 * i)));
|
||||||
|
wind += "\nFlags: " + String
|
||||||
|
.format("%8s", Integer.toBinaryString(payload[22 + (20 * i)] & 0xFF))
|
||||||
|
.replace(' ', '0');
|
||||||
windInfo.add(wind);
|
windInfo.add(wind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,18 +481,18 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @param packet The packet containing the paylaod
|
* @param packet The packet containing the paylaod
|
||||||
*/
|
*/
|
||||||
private static void extractAvgWind(StreamPacket packet){
|
private static void extractAvgWind(StreamPacket packet) {
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long rawPeriod = bytesToLong(Arrays.copyOfRange(payload,7,9));
|
long rawPeriod = bytesToLong(Arrays.copyOfRange(payload, 7, 9));
|
||||||
long rawSamplePeriod = bytesToLong(Arrays.copyOfRange(payload,9,11));
|
long rawSamplePeriod = bytesToLong(Arrays.copyOfRange(payload, 9, 11));
|
||||||
long period2 = bytesToLong(Arrays.copyOfRange(payload,11,13));
|
long period2 = bytesToLong(Arrays.copyOfRange(payload, 11, 13));
|
||||||
long speed2 = bytesToLong(Arrays.copyOfRange(payload,13,15));
|
long speed2 = bytesToLong(Arrays.copyOfRange(payload, 13, 15));
|
||||||
long period3 = bytesToLong(Arrays.copyOfRange(payload,15,17));
|
long period3 = bytesToLong(Arrays.copyOfRange(payload, 15, 17));
|
||||||
long speed3 = bytesToLong(Arrays.copyOfRange(payload,17,19));
|
long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19));
|
||||||
long period4 = bytesToLong(Arrays.copyOfRange(payload,19,21));
|
long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21));
|
||||||
long speed4 = bytesToLong(Arrays.copyOfRange(payload,21,23));
|
long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -492,11 +501,11 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @return a positive long if there is less than 7 bytes -1 otherwise
|
* @return a positive long if there is less than 7 bytes -1 otherwise
|
||||||
*/
|
*/
|
||||||
private static long bytesToLong(byte[] bytes){
|
private static long bytesToLong(byte[] bytes) {
|
||||||
long partialLong = 0;
|
long partialLong = 0;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (byte b: bytes){
|
for (byte b : bytes) {
|
||||||
if (index > 6){
|
if (index > 6) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
partialLong = partialLong | (b & 0xFFL) << (index * 8);
|
partialLong = partialLong | (b & 0xFFL) << (index * 8);
|
||||||
@@ -596,9 +605,8 @@ public class StreamParser extends Thread{
|
|||||||
return currentTimeLong;
|
return currentTimeLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void appClose(){
|
public static void appClose() {
|
||||||
appRunning = false;
|
appRunning = false;
|
||||||
System.out.println("[CLIENT] Shutting down stream parser");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -607,8 +615,8 @@ public class StreamParser extends Thread{
|
|||||||
*
|
*
|
||||||
* @return the status of if new xml has been received
|
* @return the status of if new xml has been received
|
||||||
*/
|
*/
|
||||||
public static boolean isNewRaceXmlReceived(){
|
public static boolean isNewRaceXmlReceived() {
|
||||||
if (newRaceXmlReceived){
|
if (newRaceXmlReceived) {
|
||||||
newRaceXmlReceived = false;
|
newRaceXmlReceived = false;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ public class StreamReceiver extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void start () {
|
public void start () {
|
||||||
System.out.println("[CLIENT] Starting " + threadName );
|
|
||||||
if (t == null) {
|
if (t == null) {
|
||||||
t = new Thread (this, threadName);
|
t = new Thread (this, threadName);
|
||||||
t.start ();
|
t.start ();
|
||||||
@@ -155,6 +154,5 @@ public class StreamReceiver extends Thread {
|
|||||||
|
|
||||||
public static void noMoreBytes(){
|
public static void noMoreBytes(){
|
||||||
moreBytes = false;
|
moreBytes = false;
|
||||||
System.out.println("[CLIENT] Shutting down stream receiver");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
Thread runner = new Thread(this, threadName);
|
Thread runner = new Thread(this, threadName);
|
||||||
runner.setDaemon(true);
|
runner.setDaemon(true);
|
||||||
|
|
||||||
serverLog("Spawning Server", 0);
|
|
||||||
|
|
||||||
raceSimulator = new Simulator(BOAT_LOCATION_PERIOD);
|
raceSimulator = new Simulator(BOAT_LOCATION_PERIOD);
|
||||||
raceSimulator.addObserver(this);
|
raceSimulator.addObserver(this);
|
||||||
// run race simulator, so it can send boats' static location.
|
// run race simulator, so it can send boats' static location.
|
||||||
@@ -136,7 +134,6 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
* Starts an instance of the race simulator
|
* Starts an instance of the race simulator
|
||||||
*/
|
*/
|
||||||
private void startRaceSim(){
|
private void startRaceSim(){
|
||||||
serverLog("Starting Running Race Simulator", 0);
|
|
||||||
// set race started to true, so the simulator will start moving boats
|
// set race started to true, so the simulator will start moving boats
|
||||||
raceSimulator.setRaceStarted(true);
|
raceSimulator.setRaceStarted(true);
|
||||||
}
|
}
|
||||||
@@ -144,8 +141,7 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
/**
|
/**
|
||||||
* Starts sending heartbeat messages to the client
|
* Starts sending heartbeat messages to the client
|
||||||
*/
|
*/
|
||||||
private void startSendingHeartbeats(){
|
private void startSendingHeartbeats() {
|
||||||
serverLog("Sending Heartbeats", 0);
|
|
||||||
Timer t = new Timer();
|
Timer t = new Timer();
|
||||||
|
|
||||||
t.schedule(new TimerTask() {
|
t.schedule(new TimerTask() {
|
||||||
@@ -156,7 +152,7 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
try {
|
try {
|
||||||
server.send(heartbeat);
|
server.send(heartbeat);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.print("");
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0, HEARTBEAT_PERIOD);
|
}, 0, HEARTBEAT_PERIOD);
|
||||||
@@ -176,14 +172,13 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
if (startTime < System.currentTimeMillis() && !raceStarted){
|
if (startTime < System.currentTimeMillis() && !raceStarted){
|
||||||
startRaceSim();
|
startRaceSim();
|
||||||
raceStarted = true;
|
raceStarted = true;
|
||||||
serverLog("Race Started", 0);
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
server.send(raceStartStatusMessage);
|
server.send(raceStartStatusMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.print("");
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0, RACE_START_STATUS_PERIOD);
|
}, 0, RACE_START_STATUS_PERIOD);
|
||||||
@@ -193,7 +188,6 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
* Start sending race start status messages until race starts
|
* Start sending race start status messages until race starts
|
||||||
*/
|
*/
|
||||||
private void startSendingRaceStatusMessages(){
|
private void startSendingRaceStatusMessages(){
|
||||||
serverLog("Sending race status messages", 0);
|
|
||||||
Timer t = new Timer();
|
Timer t = new Timer();
|
||||||
t.schedule(new TimerTask() {
|
t.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
@@ -201,9 +195,8 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
Message raceStatusMessage = getRaceStatusMessage();
|
Message raceStatusMessage = getRaceStatusMessage();
|
||||||
try {
|
try {
|
||||||
server.send(raceStatusMessage);
|
server.send(raceStatusMessage);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.print("");
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0, RACE_STATUS_PERIOD);
|
}, 0, RACE_STATUS_PERIOD);
|
||||||
@@ -220,17 +213,12 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
|
|
||||||
if (raceData != null){
|
if (raceData != null){
|
||||||
server.send(raceData);
|
server.send(raceData);
|
||||||
serverLog("Sending race data", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boatData != null){
|
if (boatData != null){
|
||||||
server.send(boatData);
|
server.send(boatData);
|
||||||
serverLog("Sending boat data", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regatta != null){
|
if (regatta != null){
|
||||||
server.send(regatta);
|
server.send(regatta);
|
||||||
serverLog("Sending regatta data", 0);
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
serverLog("Couldn't send an XML Message: " + e.getMessage(), 0);
|
serverLog("Couldn't send an XML Message: " + e.getMessage(), 0);
|
||||||
@@ -249,7 +237,6 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
Message raceData = getXmlMessage("/server_config/courseLimits.xml", XMLMessageSubType.RACE);
|
Message raceData = getXmlMessage("/server_config/courseLimits.xml", XMLMessageSubType.RACE);
|
||||||
if (raceData != null) {
|
if (raceData != null) {
|
||||||
server.send(raceData);
|
server.send(raceData);
|
||||||
serverLog("Sending race data", 0);
|
|
||||||
}
|
}
|
||||||
}catch (IOException e) {
|
}catch (IOException e) {
|
||||||
serverLog("Couldn't send an XML Message: " + e.getMessage(), 0);
|
serverLog("Couldn't send an XML Message: " + e.getMessage(), 0);
|
||||||
@@ -345,7 +332,7 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.print("");
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0, BOAT_LOCATION_PERIOD);
|
}, 0, BOAT_LOCATION_PERIOD);
|
||||||
@@ -372,7 +359,6 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
numOfBoatsFinished ++;
|
numOfBoatsFinished ++;
|
||||||
if (!boatsFinished.get(boat.getSourceID())) {
|
if (!boatsFinished.get(boat.getSourceID())) {
|
||||||
boatsFinished.put(boat.getSourceID(), true);
|
boatsFinished.put(boat.getSourceID(), true);
|
||||||
serverLog("Boat " + boat.getSourceID() + " finished the race", 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message m = new BoatLocationMessage(boat.getSourceID(), 1, boat.getLat(),
|
Message m = new BoatLocationMessage(boat.getSourceID(), 1, boat.getLat(),
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ class StreamingServerSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void start(){
|
void start(){
|
||||||
ServerThread.serverLog("Listening For Connections",0);
|
|
||||||
try {
|
try {
|
||||||
client = socket.accept();
|
client = socket.accept();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -39,7 +38,6 @@ class StreamingServerSocket {
|
|||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
isServerStarted = true;
|
isServerStarted = true;
|
||||||
ServerThread.serverLog("client connected from " + client.socket().getInetAddress(),0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ public class Simulator extends Observable implements Runnable {
|
|||||||
numOfFinishedBoats += moveBoat(boat, lapse);
|
numOfFinishedBoats += moveBoat(boat, lapse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//System.out.println(boats.get(0));
|
|
||||||
|
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers(boats);
|
notifyObservers(boats);
|
||||||
@@ -68,8 +67,6 @@ public class Simulator extends Observable implements Runnable {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("[SERVER] Race simulator has been terminated");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -181,4 +181,8 @@ Remove scroll bars
|
|||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart{
|
||||||
|
-fx-background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import java.lang.*?>
|
<?import java.lang.*?>
|
||||||
|
<?import javafx.scene.chart.*?>
|
||||||
<?import javafx.scene.control.*?>
|
<?import javafx.scene.control.*?>
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.scene.shape.*?>
|
<?import javafx.scene.shape.*?>
|
||||||
@@ -50,6 +51,14 @@
|
|||||||
<Button fx:id="selectAnnotationBtn" layoutX="35.0" layoutY="578.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="170.0" styleClass="blue-ui-btn" text="Select Annotations" textFill="WHITE" />
|
<Button fx:id="selectAnnotationBtn" layoutX="35.0" layoutY="578.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="170.0" styleClass="blue-ui-btn" text="Select Annotations" textFill="WHITE" />
|
||||||
<Text fill="WHITE" layoutX="11.0" layoutY="649.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Boat Selection" />
|
<Text fill="WHITE" layoutX="11.0" layoutY="649.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Boat Selection" />
|
||||||
<ComboBox fx:id="boatSelectionComboBox" layoutX="37.0" layoutY="664.0" prefHeight="25.0" prefWidth="170.0" promptText="Select Boat" styleClass="combo-box-base" />
|
<ComboBox fx:id="boatSelectionComboBox" layoutX="37.0" layoutY="664.0" prefHeight="25.0" prefWidth="170.0" promptText="Select Boat" styleClass="combo-box-base" />
|
||||||
|
<LineChart fx:id="raceSparkLine" layoutX="-15.0" layoutY="719.0" legendVisible="false" prefHeight="277.0" prefWidth="260.0" title="Boat Positions">
|
||||||
|
<xAxis>
|
||||||
|
<CategoryAxis label="Leg Number" side="BOTTOM" styleClass="spark-line-xaxis" />
|
||||||
|
</xAxis>
|
||||||
|
<yAxis>
|
||||||
|
<NumberAxis fx:id="sparklineYAxis" minorTickCount="1" minorTickLength="1.0" side="LEFT" styleClass="spark-line-yaxis" tickLabelGap="1.0" tickUnit="1.0" upperBound="7.0" />
|
||||||
|
</yAxis>
|
||||||
|
</LineChart>
|
||||||
</children>
|
</children>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
<AnchorPane fx:id="contentAnchorPane" maxHeight="960.0" maxWidth="1280.0" prefHeight="960.0" prefWidth="1280.0" style="-fx-background-color: skyblue;" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2147483647" GridPane.valignment="TOP">
|
<AnchorPane fx:id="contentAnchorPane" maxHeight="960.0" maxWidth="1280.0" prefHeight="960.0" prefWidth="1280.0" style="-fx-background-color: skyblue;" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2147483647" GridPane.valignment="TOP">
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
package seng302;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import seng302.models.Leg;
|
|
||||||
import seng302.models.mark.SingleMark;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit test for the Leg class.
|
|
||||||
*/
|
|
||||||
public class LegTest {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creation of the leg by specifying a string
|
|
||||||
* for the marker label
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testLegCreationUsingMarkerLabel() {
|
|
||||||
Leg leg = new Leg(010, 100, "SingleMark");
|
|
||||||
|
|
||||||
assertEquals(leg.getHeading(), 010);
|
|
||||||
assertEquals(leg.getDistance(), 100);
|
|
||||||
assertEquals(leg.getMarkerLabel(), "SingleMark");
|
|
||||||
assertEquals(leg.getIsFinishingLeg(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creation of the leg by providing a
|
|
||||||
* SingleMark object
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testLegCreation() {
|
|
||||||
Leg leg = new Leg(010, 100, new SingleMark("SingleMark"));
|
|
||||||
|
|
||||||
assertEquals(leg.getHeading(), 010);
|
|
||||||
assertEquals(leg.getDistance(), 100);
|
|
||||||
assertEquals(leg.getMarkerLabel(), "SingleMark");
|
|
||||||
assertEquals(leg.getIsFinishingLeg(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test changing whether or not a
|
|
||||||
* leg is the finishing leg
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSetFinishLeg() {
|
|
||||||
Leg leg = new Leg(010, 100, "SingleMark");
|
|
||||||
|
|
||||||
leg.setFinishingLeg(true);
|
|
||||||
assertEquals(leg.getIsFinishingLeg(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -99,7 +99,7 @@ public class StreamReceiverTest {
|
|||||||
byte[] emptyArray = {};
|
byte[] emptyArray = {};
|
||||||
assert bytesToLong.invoke(streamReceiver, emptyArray).equals(0L);
|
assert bytesToLong.invoke(streamReceiver, emptyArray).equals(0L);
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
System.out.println("");
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user