diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 20c01788..a3d5f49f 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -24,7 +24,6 @@ public class App extends Application { primaryStage.setOnCloseRequest(e -> { StreamParser.appClose(); StreamReceiver.noMoreBytes(); - System.out.println("[CLIENT] Exiting program"); 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. else{ // 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("livedata.americascup.com", 4941, "RaceStream"); } sr.start(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 3452e89c..d3b3722f 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -34,6 +34,12 @@ import seng302.models.stream.packets.BoatPositionPacket; import seng302.server.simulator.GeoUtility; import seng302.server.simulator.mark.Position; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.PriorityBlockingQueue; + /** * Created by ptg19 on 15/03/17. * Modified by Haoming Yin (hyi25) on 20/3/2017. @@ -49,16 +55,11 @@ public class CanvasController { private GraphicsContext gc; private ImageView mapImage; - private final int MARK_SIZE = 10; - 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_HEIGHT = 960; - private final int CANVAS_WIDTH = 720; + 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_HEIGHT = 960; + private final int CANVAS_WIDTH = 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 double distanceScaleFactor; @@ -122,6 +123,9 @@ public class CanvasController { initializeMarks(); timer = new AnimationTimer() { + private int UPDATE_FPM_PERIOD = 50; // update FPM label every 50 frames + private int updateFPMCounter = 100; + @Override public void handle(long now) { @@ -134,14 +138,15 @@ public class CanvasController { } long elapsedNanos; if (arrayFilled) { - elapsedNanos = now - oldFrameTime; - long elapsedNanosPerFrame = elapsedNanos / frameTimes.length; - frameRate = 1_000_000_000.0 / elapsedNanosPerFrame; - drawFps(frameRate.intValue()); + elapsedNanos = now - oldFrameTime ; + long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ; + frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ; + 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(); if (StreamParser.isRaceFinished()) { this.stop(); @@ -388,19 +393,16 @@ public class CanvasController { } - private void drawFps(int fps) { - if (raceViewController.isDisplayFps()) { - gc.clearRect(5, 5, 50, 20); - gc.setFill(Color.SKYBLUE); - gc.fillRect(4, 4, 51, 21); - gc.setFill(Color.BLACK); - gc.setFont(new Font(14)); - gc.setLineWidth(3); + private void drawFps(int fps){ + if (raceViewController.isDisplayFps()){ + gc.clearRect(5, 5, 60, 30); + gc.setFont(new Font(16)); + gc.setLineWidth(4); + gc.setGlobalAlpha(0.75); gc.fillText(fps + " FPS", 5, 20); + gc.setGlobalAlpha(0.5); } else { - gc.clearRect(5, 5, 50, 20); - gc.setFill(Color.SKYBLUE); - gc.fillRect(4, 4, 51, 21); + gc.clearRect(5,5,60,30); } } @@ -463,29 +465,24 @@ public class CanvasController { if (scaleDirection == ScaleDirection.HORIZONTAL) { 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)); - referencePointY = CANVAS_HEIGHT - (TOP_BUFFER + BOT_BUFFER); - referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * Mark - .calculateDistance(referencePoint, maxLatPoint); - referencePointY = referencePointY / 2; - referencePointY += TOP_BUFFER; - referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * Mark - .calculateDistance(referencePoint, maxLatPoint); + referencePointY = CANVAS_HEIGHT - (BUFFER_SIZE + BUFFER_SIZE); + referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint); + referencePointY = referencePointY / 2; + referencePointY += BUFFER_SIZE; + referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint); } else { - referencePointY = CANVAS_HEIGHT - BOT_BUFFER; + referencePointY = CANVAS_HEIGHT - BUFFER_SIZE; referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint)); - referencePointX = LHS_BUFFER; - referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark - .calculateDistance(referencePoint, minLonPoint); - referencePointX += ((CANVAS_WIDTH - (LHS_BUFFER + RHS_BUFFER)) - (minLonToMaxLon - * distanceScaleFactor)) / 2; + referencePointX = BUFFER_SIZE; + referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint); + referencePointX += ((CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE)) - (minLonToMaxLon * distanceScaleFactor)) / 2; } - if (horizontalInversion) { - referencePointX = CANVAS_WIDTH - RHS_BUFFER - (referencePointX - LHS_BUFFER); + if(horizontalInversion) { + referencePointX = CANVAS_WIDTH - BUFFER_SIZE - (referencePointX - BUFFER_SIZE); } } @@ -509,10 +506,10 @@ public class CanvasController { 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))) { - distanceScaleFactor = (CANVAS_WIDTH - (RHS_BUFFER + LHS_BUFFER)) / horiDistance; + if ((horiDistance * vertScale) > (CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE))) { + distanceScaleFactor = (CANVAS_WIDTH - (BUFFER_SIZE + BUFFER_SIZE)) / horiDistance; scaleDirection = ScaleDirection.HORIZONTAL; } else { distanceScaleFactor = vertScale; @@ -561,8 +558,8 @@ public class CanvasController { yAxisLocation += (int) Math .round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); } - if (horizontalInversion) { - xAxisLocation = CANVAS_WIDTH - RHS_BUFFER - (xAxisLocation - LHS_BUFFER); + if(horizontalInversion) { + xAxisLocation = CANVAS_WIDTH - BUFFER_SIZE - (xAxisLocation - BUFFER_SIZE); } return new Point2D(xAxisLocation, yAxisLocation); } diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 43c04a9b..03b51cfa 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -6,7 +6,12 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; +import javafx.geometry.Side; 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.CheckBox; import javafx.scene.control.ComboBox; @@ -30,12 +35,19 @@ import seng302.models.stream.StreamParser; import java.io.IOException; import java.util.*; +import seng302.models.stream.XMLParser.RaceXMLObject.Participant; +import java.util.stream.Collectors; /** + * * Created by ptg19 on 29/03/17. */ public class RaceViewController extends Thread implements ImportantAnnotationDelegate { + @FXML + private LineChart raceSparkLine; + @FXML + private NumberAxis sparklineYAxis; @FXML private VBox positionVbox; @FXML @@ -59,7 +71,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel private boolean displayFps; private Timeline timerTimeline; private Stage stage; - + private static HashMap> sparkLineData = new HashMap<>(); + private static ArrayList racingBoats = new ArrayList<>(); private ImportantAnnotationsState importantAnnotations; private Yacht selectedBoat; @@ -67,6 +80,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // Load a default important annotation state 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.initializeCanvas(); initializeUpdateTimer(); @@ -74,14 +95,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel initialiseAnnotationSlider(); initialiseBoatSelectionComboBox(); includedCanvasController.timer.start(); - - selectAnnotationBtn.setOnAction(event -> { - loadSelectAnnotationView(); - }); + selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView()); } + /** * The important annotations have been changed, update this view + * * @param importantAnnotationsState The current state of the selected annotations */ public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) { @@ -89,6 +109,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations } + /** * 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); } + private void initialiseAnnotationSlider() { annotationSlider.setLabelFormatter(new StringConverter() { @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 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 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> 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 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 * 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(); updateOrder(); updateBoatSelectionComboBox(); - }) ); @@ -233,21 +327,42 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel positionVbox.getChildren().removeAll(); positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); - for (Yacht boat : StreamParser.getBoatsPos().values()) { - if (boat.getBoatStatus() == 3) { // 3 is finish status - Text textToAdd = new Text(boat.getPosition() + ". " + - boat.getShortName() + " (Finished)"); - textToAdd.setFill(Paint.valueOf("#d3d3d3")); - positionVbox.getChildren().add(textToAdd); + // list of racing boat id + ArrayList participants = StreamParser.getXmlObject().getRaceXML() + .getParticipants(); + ArrayList participantIDs = new ArrayList<>(); + for (Participant p : participants) { + participantIDs.add(p.getsourceID()); + } - } else { - Text textToAdd = new Text(boat.getPosition() + ". " + - boat.getShortName() + " "); - textToAdd.setFill(Paint.valueOf("#d3d3d3")); - textToAdd.setStyle(""); - positionVbox.getChildren().add(textToAdd); + if (StreamParser.isRaceStarted()) { + for (Yacht boat : StreamParser.getBoatsPos().values()) { + if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing + if (boat.getBoatStatus() == 3) { // 3 is finish status + Text textToAdd = new Text(boat.getPosition() + ". " + + 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; } /** * Display the important annotations for a specific BoatGroup + * * @param bg The boat group to set the annotations for */ private void setBoatGroupImportantAnnotations(BoatGroup bg) { @@ -427,4 +543,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Stage getStage() { 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); + } } \ No newline at end of file diff --git a/src/main/java/seng302/controllers/StartScreenController.java b/src/main/java/seng302/controllers/StartScreenController.java index 770a52a6..3e9d27bd 100644 --- a/src/main/java/seng302/controllers/StartScreenController.java +++ b/src/main/java/seng302/controllers/StartScreenController.java @@ -2,6 +2,7 @@ package seng302.controllers; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; import java.util.ResourceBundle; import java.util.Timer; import java.util.TimerTask; @@ -22,6 +23,7 @@ import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import seng302.models.Yacht; import seng302.models.stream.StreamParser; +import seng302.models.stream.XMLParser.RaceXMLObject.Participant; public class StartScreenController implements Initializable { @@ -162,7 +164,28 @@ public class StartScreenController implements Initializable { new PropertyValueFactory<>("position") ); - data.addAll(StreamParser.getBoatsPos().values()); + // check if the boat is racing + ArrayList participants = StreamParser.getXmlObject().getRaceXML() + .getParticipants(); + ArrayList 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(); } } diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 3e97df5e..b50cd155 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -1,13 +1,9 @@ package seng302.models; -import javafx.event.EventHandler; import javafx.geometry.Point2D; import javafx.scene.CacheHint; import javafx.scene.Group; -import javafx.scene.input.MouseDragEvent; -import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import javafx.scene.text.Text; diff --git a/src/main/java/seng302/models/Colors.java b/src/main/java/seng302/models/Colors.java index 8d1b9c25..0078e505 100644 --- a/src/main/java/seng302/models/Colors.java +++ b/src/main/java/seng302/models/Colors.java @@ -3,7 +3,7 @@ package seng302.models; import javafx.scene.paint.Color; /** - * Created by ryan_ on 16/03/2017. + * Enum for randomly generating colours. */ public enum Colors { RED, PERU, SEAGREEN, GREEN, BLUE, PURPLE; diff --git a/src/main/java/seng302/models/Event.java b/src/main/java/seng302/models/Event.java index 80f688c7..325afdf0 100644 --- a/src/main/java/seng302/models/Event.java +++ b/src/main/java/seng302/models/Event.java @@ -92,7 +92,6 @@ public class Event { if (this.isFinishingEvent) { 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() + "°"); } diff --git a/src/main/java/seng302/models/Leg.java b/src/main/java/seng302/models/Leg.java deleted file mode 100644 index 8f21a6ea..00000000 --- a/src/main/java/seng302/models/Leg.java +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/src/main/java/seng302/models/TimelineInfo.java b/src/main/java/seng302/models/TimelineInfo.java deleted file mode 100644 index 867ce67b..00000000 --- a/src/main/java/seng302/models/TimelineInfo.java +++ /dev/null @@ -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; - } -} diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 8ae5d76c..c5bdcbb7 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -1,6 +1,8 @@ package seng302.models; + import javafx.scene.paint.Color; +import seng302.controllers.RaceViewController; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -9,9 +11,10 @@ import java.text.SimpleDateFormat; * Yacht class for the racing boat. * * 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 { + // Used in boat group private Color colour; private double velocity; @@ -33,21 +36,22 @@ public class Yacht { // Mark rounding private Long markRoundingTime; + /** * Used in EventTest and RaceTest. * * @param boatName Create a yacht object with name. */ - public Yacht (String boatName) { + public Yacht(String boatName) { this.boatName = boatName; } /** * 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 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) { this.boatName = boatName; @@ -56,30 +60,37 @@ public class Yacht { 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.sourceID = sourceID; this.hullID = hullID; this.shortName = shortName; this.boatName = boatName; this.country = country; + this.position = "-"; } public String getBoatType() { return boatType; } + public Integer getSourceID() { return sourceID; } + public String getHullID() { return hullID; } + public String getShortName() { return shortName; } + public String getBoatName() { return boatName; } + public String getCountry() { return country; } @@ -97,6 +108,9 @@ public class Yacht { } public void setLegNumber(Integer legNumber) { + if (colour != null && position != "-" && legNumber != this.legNumber&& RaceViewController.sparkLineStatus(sourceID)) { + RaceViewController.updateYachtPositionSparkline(this, legNumber); + } this.legNumber = legNumber; } diff --git a/src/main/java/seng302/models/mark/Mark.java b/src/main/java/seng302/models/mark/Mark.java index 1ca1f608..acb61ea1 100644 --- a/src/main/java/seng302/models/mark/Mark.java +++ b/src/main/java/seng302/models/mark/Mark.java @@ -14,10 +14,11 @@ public abstract class Mark { /** * Create a mark instance by passing its name and type + * * @param name the name of the 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.markType = markType; 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 - * latitude2, longitude 2 + * Calculate the heading in radians from geographical location with latitude1, longitude 1 to + * geographical latitude2, longitude 2 + * * @param longitude1 Longitude of first 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 * @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); latitude2 = Math.toRadians(latitude2); - Double longDiff= Math.toRadians(longitude2-longitude1); - 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 longDiff = Math.toRadians(longitude2 - longitude1); + 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); 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 - * latitude2, longitude 2 + * Calculate the distance in meters from geographical location with latitude1, longitude 1 to + * geographical latitude2, longitude 2 * * @param longitude1 Longitude of first 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 * @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 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(theta)); + Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(latitude2)) * + Math.cos(Math.toRadians(theta)); dist = Math.acos(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 return dist; } - + public String getName() { return name; } public void setName(String name) { - this.name = name; + this.name = name; } public MarkType getMarkType() { diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index c87ae174..661f45de 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -9,7 +9,7 @@ import javafx.scene.shape.Circle; 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 { diff --git a/src/main/java/seng302/models/mark/MarkType.java b/src/main/java/seng302/models/mark/MarkType.java index 4ac6a9e3..92b3c93b 100644 --- a/src/main/java/seng302/models/mark/MarkType.java +++ b/src/main/java/seng302/models/mark/MarkType.java @@ -5,5 +5,5 @@ package seng302.models.mark; * Created by Haoming Yin (hyi25) on 17/3/17. */ public enum MarkType { - SINGLE_MARK, OPEN_GATE, CLOSED_GATE + SINGLE_MARK, OPEN_GATE } diff --git a/src/main/java/seng302/models/stream/StreamParser.java b/src/main/java/seng302/models/stream/StreamParser.java index 0aefef9e..a5d7ed09 100644 --- a/src/main/java/seng302/models/stream/StreamParser.java +++ b/src/main/java/seng302/models/stream/StreamParser.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.Map; import java.util.TimeZone; 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 * Created by kre39 on 23/04/17. */ -public class StreamParser extends Thread{ +public class StreamParser extends Thread { - public static ConcurrentHashMap> markPositions = new ConcurrentHashMap<>(); - public static ConcurrentHashMap> boatPositions = new ConcurrentHashMap<>(); - private String threadName; - private Thread t; - private static boolean newRaceXmlReceived = false; - private static boolean raceStarted = false; - private static XMLParser xmlObject; - private static boolean raceFinished = false; - private static boolean streamStatus = false; - private static long timeSinceStart = -1; - private static Map boats = new ConcurrentHashMap<>(); - private static Map boatsPos = new ConcurrentSkipListMap<>(); - private static double windDirection = 0; - private static Long currentTimeLong; - private static String currentTimeString; - private static boolean appRunning; + public static ConcurrentHashMap> markPositions = new ConcurrentHashMap<>(); + public static ConcurrentHashMap> boatPositions = new ConcurrentHashMap<>(); + private String threadName; + private Thread t; + private static boolean newRaceXmlReceived = false; + private static boolean raceStarted = false; + private static XMLParser xmlObject; + private static boolean raceFinished = false; + private static boolean streamStatus = false; + private static long timeSinceStart = -1; + private static Map boats = new ConcurrentHashMap<>(); + private static Map boatsPos = new ConcurrentSkipListMap<>(); + private static double windDirection = 0; + private static Long currentTimeLong; + private static String currentTimeString; + private static boolean appRunning; /** * Used to initialise the thread name and stream parser object so a thread can be executed * * @param threadName name of the thread */ - public StreamParser(String threadName){ - this.threadName = threadName; - } + public StreamParser(String threadName) { + this.threadName = threadName; + } /** - * Used to within threading so when the stream parser thread runs, it will keep looking for a packet to - * process until it is unable to find anymore packets - * + * Used to within threading so when the stream parser thread runs, it will keep looking for a + * packet to process until it is unable to find anymore packets */ - public void run(){ + public void run() { appRunning = true; - try { - System.out.println("[CLIENT] Start of stream"); - streamStatus = true; - xmlObject = new XMLParser(); - while (StreamReceiver.packetBuffer == null || StreamReceiver.packetBuffer.size() < 1) { - Thread.sleep(1); - } - while (appRunning){ - StreamPacket packet = StreamReceiver.packetBuffer.take(); - parsePacket(packet); - Thread.sleep(1); - while (StreamReceiver.packetBuffer.peek() == null) { - } - } - } catch (Exception e){ - e.printStackTrace(); - } - } + try { + streamStatus = true; + xmlObject = new XMLParser(); + while (StreamReceiver.packetBuffer == null || StreamReceiver.packetBuffer.size() < 1) { + Thread.sleep(1); + } + while (appRunning) { + StreamPacket packet = StreamReceiver.packetBuffer.take(); + parsePacket(packet); + Thread.sleep(1); + while (StreamReceiver.packetBuffer.peek() == null) { + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } /** * Used to start the stream parser thread when multithreading - * */ - public void start () { - System.out.println("[CLIENT] Starting " + threadName ); + public void start() { if (t == null) { - t = new Thread (this, threadName); - t.start (); + t = new Thread(this, threadName); + t.start(); } } @@ -103,55 +100,53 @@ public class StreamParser extends Thread{ * * @param packet the packet to be looked at and processed */ - private static void parsePacket(StreamPacket packet) { - try{ - switch (packet.getType()){ - case HEARTBEAT: - extractHeartBeat(packet); - break; - case RACE_STATUS: - extractRaceStatus(packet); - break; - case DISPLAY_TEXT_MESSAGE: - extractDisplayMessage(packet); - break; - case XML_MESSAGE: - newRaceXmlReceived = true; - extractXmlMessage(packet); - break; - case RACE_START_STATUS: - extractRaceStartStatus(packet); - break; - case YACHT_EVENT_CODE: - extractYachtEventCode(packet); - break; - case YACHT_ACTION_CODE: - extractYachtActionCode(packet); - break; - case CHATTER_TEXT: - extractChatterText(packet); - break; - case BOAT_LOCATION: - extractBoatLocation(packet); - break; - case MARK_ROUNDING: - extractMarkRounding(packet); - break; - case COURSE_WIND: - extractCourseWind(packet); - break; - case AVG_WIND: - extractAvgWind(packet); - break; - default: - break; - //System.out.println(packet.getType().toString()); - } - } - catch (NullPointerException e){ - System.out.println("Error parsing packet"); - } - } + private static void parsePacket(StreamPacket packet) { + try { + switch (packet.getType()) { + case HEARTBEAT: + extractHeartBeat(packet); + break; + case RACE_STATUS: + extractRaceStatus(packet); + break; + case DISPLAY_TEXT_MESSAGE: + extractDisplayMessage(packet); + break; + case XML_MESSAGE: + newRaceXmlReceived = true; + extractXmlMessage(packet); + break; + case RACE_START_STATUS: + extractRaceStartStatus(packet); + break; + case YACHT_EVENT_CODE: + extractYachtEventCode(packet); + break; + case YACHT_ACTION_CODE: + extractYachtActionCode(packet); + break; + case CHATTER_TEXT: + extractChatterText(packet); + break; + case BOAT_LOCATION: + extractBoatLocation(packet); + break; + case MARK_ROUNDING: + extractMarkRounding(packet); + break; + case COURSE_WIND: + extractCourseWind(packet); + break; + case AVG_WIND: + extractAvgWind(packet); + break; + default: + break; + } + } catch (NullPointerException e) { + System.out.println("Error parsing 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 - * console the current state of the race (if it has started/finished or is about to start), along side - * this it'll also display the amount of time since the race has started or time till it starts + * Extracts the useful race status data from race status type packets. This method will also + * print to the console the current state of the race (if it has started/finished or is about to + * 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 */ - private static void extractRaceStatus(StreamPacket packet){ + private static void extractRaceStatus(StreamPacket packet) { byte[] payload = packet.getPayload(); int messageVersionNo = payload[0]; - long currentTime = bytesToLong(Arrays.copyOfRange(payload,1,7)); - long raceId = bytesToLong(Arrays.copyOfRange(payload,7,11)); + long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); + long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11)); int raceStatus = payload[11]; - long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18)); - long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); - long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22)); + long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload, 12, 18)); + long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20)); + long windSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22)); currentTimeLong = currentTime; DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); if (xmlObject.getRegattaXML() != null) { 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) { timeSinceStart = timeTillStart; - //System.out.println("Time till start: " + timeTillStart + " Seconds"); } else { - if (raceStatus == 4 || raceStatus == 8){ + if (raceStatus == 4 || raceStatus == 8) { raceFinished = true; raceStarted = false; - System.out.println("[CLIENT] Race has finished"); - } else if (!raceStarted){ + } else if (!raceStarted) { raceStarted = true; raceFinished = false; - System.out.println("[CLIENT] Race has started"); } timeSinceStart = timeTillStart; } @@ -225,18 +219,20 @@ public class StreamParser extends Thread{ int noBoats = payload[22]; int raceType = payload[23]; boatsPos = new TreeMap<>(); - for (int i = 0; i < noBoats; i++){ - long boatStatusSourceID = bytesToLong(Arrays.copyOfRange(payload,24 + (i * 20),28+ (i * 20))); + for (int i = 0; i < noBoats; i++) { + long boatStatusSourceID = bytesToLong( + Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20))); Yacht boat = boats.get((int) boatStatusSourceID); - boat.setBoatStatus((int)payload[28 + (i * 20)]); - boat.setLegNumber((int)payload[29 + (i * 20)]); - boat.setPenaltiesAwarded((int)payload[30 + (i * 20)]); - boat.setPenaltiesServed((int)payload[31 + (i * 20)]); - Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,32 + (i * 20),38+ (i * 20))); + boat.setBoatStatus((int) payload[28 + (i * 20)]); + boat.setLegNumber((int) payload[29 + (i * 20)]); + boat.setPenaltiesAwarded((int) payload[30 + (i * 20)]); + boat.setPenaltiesServed((int) payload[31 + (i * 20)]); + Long estTimeAtNextMark = bytesToLong( + Arrays.copyOfRange(payload, 32 + (i * 20), 38 + (i * 20))); 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); - boatsPos.put(estTimeAtFinish, boat); // String boatStatus = "SourceID: " + boatStatusSourceID; // boatStatus += "\nBoat Status: " + (int)payload[28 + (i * 20)]; // boatStatus += "\nLegNumber: " + (int)payload[29 + (i * 20)]; @@ -260,15 +256,16 @@ public class StreamParser extends Thread{ * * @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(); int messageVersionNo = payload[0]; int numOfLines = payload[3]; int totalLen = 0; - for (int i = 0; i < numOfLines; i++){ + for (int i = 0; i < numOfLines; i++) { int lineNum = payload[4 + 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); totalLen += 2 + textLength; } @@ -279,13 +276,14 @@ public class StreamParser extends Thread{ * * @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(); int messageType = payload[9]; - long messageLength = bytesToLong(Arrays.copyOfRange(payload,12,14)); - String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messageLength)))).trim(); + long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14)); + String xmlMessage = new String( + (Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim(); //Create XML document Object DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -314,12 +312,12 @@ public class StreamParser extends Thread{ * * @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(); int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7)); - long raceStartTime = bytesToLong(Arrays.copyOfRange(payload,9,15)); - long raceId = bytesToLong(Arrays.copyOfRange(payload,15,19)); + long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); + long raceStartTime = bytesToLong(Arrays.copyOfRange(payload, 9, 15)); + long raceId = bytesToLong(Arrays.copyOfRange(payload, 15, 19)); int notificationType = payload[19]; } @@ -329,28 +327,28 @@ public class StreamParser extends Thread{ * * @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(); int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7)); - long raceId = bytesToLong(Arrays.copyOfRange(payload,9,13)); - long subjectId = bytesToLong(Arrays.copyOfRange(payload,13,17)); - long incidentId = bytesToLong(Arrays.copyOfRange(payload,17,21)); + long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); + long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); + long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); + long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21)); int eventId = payload[21]; } /** - * When a yacht action occurs this will parse the parse the byte array to retrieve the necessary info, - * currently unused + * When a yacht action occurs this will parse the parse the byte array to retrieve the necessary + * info, currently unused * * @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(); int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7)); - long subjectId = bytesToLong(Arrays.copyOfRange(payload,9,13)); - long incidentId = bytesToLong(Arrays.copyOfRange(payload,13,17)); + long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); + long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); + long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); int eventId = payload[17]; } @@ -359,51 +357,54 @@ public class StreamParser extends Thread{ * * @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(); int messageVersionNo = payload[0]; int messageType = payload[1]; 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 - * All the other extra data is still being read and translated however is unused. + * Used to breakdown the boatlocation packets so the boat coordinates, id and groundspeed are + * 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 */ - private static void extractBoatLocation(StreamPacket packet){ + private static void extractBoatLocation(StreamPacket packet) { byte[] payload = packet.getPayload(); - int deviceType = (int)payload[15]; - long timeValid = bytesToLong(Arrays.copyOfRange(payload,1,7)); - long seq = bytesToLong(Arrays.copyOfRange(payload,11,15)); - long boatId = bytesToLong(Arrays.copyOfRange(payload,7,11)); - long rawLat = bytesToLong(Arrays.copyOfRange(payload,16,20)); - long rawLon = bytesToLong(Arrays.copyOfRange(payload,20,24)); + int deviceType = (int) payload[15]; + long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); + long seq = bytesToLong(Arrays.copyOfRange(payload, 11, 15)); + long boatId = bytesToLong(Arrays.copyOfRange(payload, 7, 11)); + long rawLat = bytesToLong(Arrays.copyOfRange(payload, 16, 20)); + long rawLon = bytesToLong(Arrays.copyOfRange(payload, 20, 24)); //Converts the double to a usable lat/lon - double lat = ((180d * (double)rawLat)/Math.pow(2,31)); - double lon = ((180d *(double)rawLon)/Math.pow(2,31)); - long heading = bytesToLong(Arrays.copyOfRange(payload,28,30)); - double groundSpeed = bytesToLong(Arrays.copyOfRange(payload,38,40))/1000.0; + double lat = ((180d * (double) rawLat) / Math.pow(2, 31)); + double lon = ((180d * (double) rawLon) / Math.pow(2, 31)); + long heading = bytesToLong(Arrays.copyOfRange(payload, 28, 30)); + 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 - if (deviceType == 1){ - BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed); + if (deviceType == 1) { + BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, + heading, groundSpeed); //add a new priority que to the boatPositions HashMap - if (!boatPositions.containsKey(boatId)){ - boatPositions.put(boatId, new PriorityBlockingQueue<>(256, new Comparator() { - @Override - public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { - return (int) (p1.getTimeValid() - p2.getTimeValid()); - } - })); + if (!boatPositions.containsKey(boatId)) { + boatPositions.put(boatId, + new PriorityBlockingQueue<>(256, new Comparator() { + @Override + public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { + return (int) (p1.getTimeValid() - p2.getTimeValid()); + } + })); } boatPositions.get(boatId).put(boatPacket); - } else if (deviceType == 3){ - BoatPositionPacket markPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed); + } else if (deviceType == 3) { + BoatPositionPacket markPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, + heading, groundSpeed); //add a new priority que to the boatPositions HashMap if (!markPositions.containsKey(boatId)) { @@ -424,19 +425,19 @@ public class StreamParser extends Thread{ * * @param packet The packet containing the payload */ - private static void extractMarkRounding(StreamPacket packet){ + private static void extractMarkRounding(StreamPacket packet) { byte[] payload = packet.getPayload(); int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7)); - long raceId = bytesToLong(Arrays.copyOfRange(payload,9,13)); - long subjectId = bytesToLong(Arrays.copyOfRange(payload,13,17)); + long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); + long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); + long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); int boatStatus = payload[17]; int roundingSide = payload[18]; int markType = payload[19]; int markId = payload[20]; // assign mark rounding time to boat - boats.get((int)subjectId).setMarkRoundingTime(timeStamp); + boats.get((int) subjectId).setMarkRoundingTime(timeStamp); } /** @@ -444,21 +445,29 @@ public class StreamParser extends Thread{ * * @param packet The packet containing the payload */ - private static void extractCourseWind(StreamPacket packet){ + private static void extractCourseWind(StreamPacket packet) { byte[] payload = packet.getPayload(); int messageVersionNo = payload[0]; int selectedWindId = payload[1]; int loopCount = payload[2]; ArrayList windInfo = new ArrayList<>(); - for (int i = 0; i < loopCount; i++){ + for (int i = 0; i < loopCount; i++) { String wind = "WindId: " + payload[3 + (20 * i)]; - wind += "\nTime: " + bytesToLong(Arrays.copyOfRange(payload,4 + (20 * i),10 + (20 * i))); - wind += "\nRaceId: " + bytesToLong(Arrays.copyOfRange(payload,10 + (20 * i),14 + (20 * i))); - wind += "\nWindDirection: " + bytesToLong(Arrays.copyOfRange(payload,14 + (20 * i),16 + (20 * i))); - 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'); + wind += + "\nTime: " + bytesToLong(Arrays.copyOfRange(payload, 4 + (20 * i), 10 + (20 * i))); + wind += "\nRaceId: " + bytesToLong( + Arrays.copyOfRange(payload, 10 + (20 * i), 14 + (20 * i))); + wind += "\nWindDirection: " + bytesToLong( + Arrays.copyOfRange(payload, 14 + (20 * i), 16 + (20 * i))); + 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); } } @@ -468,18 +477,18 @@ public class StreamParser extends Thread{ * * @param packet The packet containing the paylaod */ - private static void extractAvgWind(StreamPacket packet){ + private static void extractAvgWind(StreamPacket packet) { byte[] payload = packet.getPayload(); int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload,1,7)); - long rawPeriod = bytesToLong(Arrays.copyOfRange(payload,7,9)); - long rawSamplePeriod = bytesToLong(Arrays.copyOfRange(payload,9,11)); - long period2 = bytesToLong(Arrays.copyOfRange(payload,11,13)); - long speed2 = bytesToLong(Arrays.copyOfRange(payload,13,15)); - long period3 = bytesToLong(Arrays.copyOfRange(payload,15,17)); - long speed3 = bytesToLong(Arrays.copyOfRange(payload,17,19)); - long period4 = bytesToLong(Arrays.copyOfRange(payload,19,21)); - long speed4 = bytesToLong(Arrays.copyOfRange(payload,21,23)); + long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); + long rawPeriod = bytesToLong(Arrays.copyOfRange(payload, 7, 9)); + long rawSamplePeriod = bytesToLong(Arrays.copyOfRange(payload, 9, 11)); + long period2 = bytesToLong(Arrays.copyOfRange(payload, 11, 13)); + long speed2 = bytesToLong(Arrays.copyOfRange(payload, 13, 15)); + long period3 = bytesToLong(Arrays.copyOfRange(payload, 15, 17)); + long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19)); + long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21)); + long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23)); } /** @@ -488,11 +497,11 @@ public class StreamParser extends Thread{ * * @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; int index = 0; - for (byte b: bytes){ - if (index > 6){ + for (byte b : bytes) { + if (index > 6) { return -1; } partialLong = partialLong | (b & 0xFFL) << (index * 8); @@ -592,9 +601,8 @@ public class StreamParser extends Thread{ return currentTimeLong; } - public static void appClose(){ + public static void appClose() { appRunning = false; - System.out.println("[CLIENT] Shutting down stream parser"); } /** @@ -603,8 +611,8 @@ public class StreamParser extends Thread{ * * @return the status of if new xml has been received */ - public static boolean isNewRaceXmlReceived(){ - if (newRaceXmlReceived){ + public static boolean isNewRaceXmlReceived() { + if (newRaceXmlReceived) { newRaceXmlReceived = false; return true; } else { diff --git a/src/main/java/seng302/models/stream/StreamReceiver.java b/src/main/java/seng302/models/stream/StreamReceiver.java index b3303806..b1ddb996 100644 --- a/src/main/java/seng302/models/stream/StreamReceiver.java +++ b/src/main/java/seng302/models/stream/StreamReceiver.java @@ -44,7 +44,6 @@ public class StreamReceiver extends Thread { } public void start () { - System.out.println("[CLIENT] Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); @@ -155,6 +154,5 @@ public class StreamReceiver extends Thread { public static void noMoreBytes(){ moreBytes = false; - System.out.println("[CLIENT] Shutting down stream receiver"); } } diff --git a/src/main/java/seng302/server/ServerThread.java b/src/main/java/seng302/server/ServerThread.java index 094845ab..98038ea2 100644 --- a/src/main/java/seng302/server/ServerThread.java +++ b/src/main/java/seng302/server/ServerThread.java @@ -29,8 +29,6 @@ public class ServerThread implements Runnable, Observer { Thread runner = new Thread(this, threadName); runner.setDaemon(true); - serverLog("Spawning Server", 0); - raceSimulator = new Simulator(BOAT_LOCATION_PERIOD); raceSimulator.addObserver(this); // run race simulator, so it can send boats' static location. @@ -134,7 +132,6 @@ public class ServerThread implements Runnable, Observer { * Starts an instance of the race simulator */ private void startRaceSim(){ - serverLog("Starting Running Race Simulator", 0); // set race started to true, so the simulator will start moving boats raceSimulator.setRaceStarted(true); } @@ -142,8 +139,7 @@ public class ServerThread implements Runnable, Observer { /** * Starts sending heartbeat messages to the client */ - private void startSendingHeartbeats(){ - serverLog("Sending Heartbeats", 0); + private void startSendingHeartbeats() { Timer t = new Timer(); t.schedule(new TimerTask() { @@ -154,7 +150,7 @@ public class ServerThread implements Runnable, Observer { try { server.send(heartbeat); } catch (IOException e) { - System.out.print(""); + e.printStackTrace(); } } }, 0, HEARTBEAT_PERIOD); @@ -174,14 +170,13 @@ public class ServerThread implements Runnable, Observer { if (startTime < System.currentTimeMillis() && !raceStarted){ startRaceSim(); raceStarted = true; - serverLog("Race Started", 0); } else{ server.send(raceStartStatusMessage); } } catch (IOException e) { - System.out.print(""); + e.printStackTrace(); } } }, 0, RACE_START_STATUS_PERIOD); @@ -191,7 +186,6 @@ public class ServerThread implements Runnable, Observer { * Start sending race start status messages until race starts */ private void startSendingRaceStatusMessages(){ - serverLog("Sending race status messages", 0); Timer t = new Timer(); t.schedule(new TimerTask() { @Override @@ -199,9 +193,8 @@ public class ServerThread implements Runnable, Observer { Message raceStatusMessage = getRaceStatusMessage(); try { server.send(raceStatusMessage); - } catch (IOException e) { - System.out.print(""); + e.printStackTrace(); } } }, 0, RACE_STATUS_PERIOD); @@ -218,17 +211,12 @@ public class ServerThread implements Runnable, Observer { if (raceData != null){ server.send(raceData); - serverLog("Sending race data", 0); } - if (boatData != null){ server.send(boatData); - serverLog("Sending boat data", 0); } - if (regatta != null){ server.send(regatta); - serverLog("Sending regatta data", 0); } } catch (IOException e) { serverLog("Couldn't send an XML Message: " + e.getMessage(), 0); @@ -247,7 +235,6 @@ public class ServerThread implements Runnable, Observer { Message raceData = getXmlMessage("/server_config/courseLimits.xml", XMLMessageSubType.RACE); if (raceData != null) { server.send(raceData); - serverLog("Sending race data", 0); } }catch (IOException e) { serverLog("Couldn't send an XML Message: " + e.getMessage(), 0); @@ -295,7 +282,7 @@ public class ServerThread implements Runnable, Observer { } } catch (IOException e) { - System.out.print(""); + e.printStackTrace(); } } }, 0, BOAT_LOCATION_PERIOD); @@ -322,7 +309,6 @@ public class ServerThread implements Runnable, Observer { numOfBoatsFinished ++; if (!boatsFinished.get(boat.getSourceID())) { boatsFinished.put(boat.getSourceID(), true); - serverLog("Boat " + boat.getSourceID() + " finished the race", 1); } } Message m = new BoatLocationMessage(boat.getSourceID(), 1, boat.getLat(), diff --git a/src/main/java/seng302/server/StreamingServerSocket.java b/src/main/java/seng302/server/StreamingServerSocket.java index dc249ea4..35297f9f 100644 --- a/src/main/java/seng302/server/StreamingServerSocket.java +++ b/src/main/java/seng302/server/StreamingServerSocket.java @@ -28,7 +28,6 @@ class StreamingServerSocket { } void start(){ - ServerThread.serverLog("Listening For Connections",0); try { client = socket.accept(); } catch (IOException e) { @@ -39,7 +38,6 @@ class StreamingServerSocket { } else{ isServerStarted = true; - ServerThread.serverLog("client connected from " + client.socket().getInetAddress(),0); } } diff --git a/src/main/java/seng302/server/simulator/Simulator.java b/src/main/java/seng302/server/simulator/Simulator.java index 72d2717a..514ecc25 100644 --- a/src/main/java/seng302/server/simulator/Simulator.java +++ b/src/main/java/seng302/server/simulator/Simulator.java @@ -54,7 +54,6 @@ public class Simulator extends Observable implements Runnable { numOfFinishedBoats += moveBoat(boat, lapse); } } - //System.out.println(boats.get(0)); setChanged(); notifyObservers(boats); @@ -65,8 +64,6 @@ public class Simulator extends Observable implements Runnable { e.printStackTrace(); } } - - System.out.println("[SERVER] Race simulator has been terminated"); } /** diff --git a/src/main/resources/css/master.css b/src/main/resources/css/master.css index 8223fc00..bef93923 100644 --- a/src/main/resources/css/master.css +++ b/src/main/resources/css/master.css @@ -181,4 +181,8 @@ Remove scroll bars -fx-background-radius: 0; -fx-background-insets: 0; -fx-padding: 0; -} \ No newline at end of file +} + +.chart{ + -fx-background-color: #ffffff; +} diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index f43099a1..b225ec98 100644 --- a/src/main/resources/views/RaceView.fxml +++ b/src/main/resources/views/RaceView.fxml @@ -1,6 +1,7 @@ + @@ -50,6 +51,14 @@