From 1524ed5a0e0831e519e64b77a4bb39c4a7770fd1 Mon Sep 17 00:00:00 2001 From: cbt24 Date: Wed, 29 Mar 2017 13:27:41 +1300 Subject: [PATCH] Merged annotation toggle and DNF features with heading visualisation. --- .../seng302/Controllers/RaceController.java | 37 ++++++++++++++---- src/main/java/seng302/Model/Boat.java | 6 ++- src/main/java/seng302/Model/BoatInRace.java | 6 +++ src/main/java/seng302/Model/Race.java | 19 ++++++++++ .../seng302/Model/ResizableRaceCanvas.java | 38 +++++++++++++++++-- src/main/resources/scenes/racepane.fxml | 15 ++++++-- 6 files changed, 105 insertions(+), 16 deletions(-) diff --git a/src/main/java/seng302/Controllers/RaceController.java b/src/main/java/seng302/Controllers/RaceController.java index f44d0e7e..e83146a8 100644 --- a/src/main/java/seng302/Controllers/RaceController.java +++ b/src/main/java/seng302/Controllers/RaceController.java @@ -2,15 +2,12 @@ package seng302.Controllers; import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.fxml.FXML; -import javafx.scene.control.Label; -import javafx.scene.control.SplitPane; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; -import javafx.scene.control.TitledPane; +import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; @@ -39,6 +36,11 @@ public class RaceController extends Controller { @FXML SplitPane ongoingRacePane; + @FXML + CheckBox showFPS; + + @FXML + CheckBox showAnno; @FXML Label timer; @@ -67,8 +69,7 @@ public class RaceController extends Controller { public void updateMap(ObservableList boats) { BoatInRace[] boatInRaces = new BoatInRace[boats.size()]; raceMap.setBoats(boats.toArray(boatInRaces)); - raceMap.drawRaceMap(); - raceMap.updateBoats(); + raceMap.update(); } /** @@ -114,7 +115,17 @@ public class RaceController extends Controller { @Override public void initialize(URL location, ResourceBundle resources) { - + //listener for fps + showFPS.selectedProperty().addListener(new ChangeListener() { + public void changed(ObservableValue ov, + Boolean old_val, Boolean new_val) { + if (showFPS.isSelected()){ + FPS.setVisible(true); + } else { + FPS.setVisible(false); + } + } + }); } /** @@ -126,6 +137,7 @@ public class RaceController extends Controller { private void startRace(int scaleFactor) { BoatInRace[] boats = generateAC35Competitors(); raceMap = new ResizableRaceCanvas(); + raceMap.setMouseTransparent(true); raceMap.widthProperty().bind(canvasBase.widthProperty()); raceMap.heightProperty().bind(canvasBase.heightProperty()); raceMap.setBoats(boats); @@ -142,6 +154,15 @@ public class RaceController extends Controller { new Thread((race)).start(); + + //listener for annotation + showAnno.selectedProperty().addListener(new ChangeListener() { + public void changed(ObservableValue ov, + Boolean old_val, Boolean new_val) { + raceMap.toggleAnno(); + raceMap.update(); + } + }); } diff --git a/src/main/java/seng302/Model/Boat.java b/src/main/java/seng302/Model/Boat.java index 1b1801fc..222e1a68 100644 --- a/src/main/java/seng302/Model/Boat.java +++ b/src/main/java/seng302/Model/Boat.java @@ -21,7 +21,7 @@ public class Boat { */ public Boat(String name, double velocity, String abbrev) { this.velocity = velocity; - this.velocityProp = new SimpleStringProperty(String.valueOf(velocity* 1.94384)); + this.velocityProp = new SimpleStringProperty(String.valueOf(Math.round(velocity))); this.abbrev = abbrev; this.name = new SimpleStringProperty(name); } @@ -48,6 +48,10 @@ public class Boat { return velocity; } + /** + * Sets the speed of the boat in knots. + * @param velocity speed in knots + */ public void setVelocity(double velocity) { this.velocity = velocity; } diff --git a/src/main/java/seng302/Model/BoatInRace.java b/src/main/java/seng302/Model/BoatInRace.java index 01b410ae..72906939 100644 --- a/src/main/java/seng302/Model/BoatInRace.java +++ b/src/main/java/seng302/Model/BoatInRace.java @@ -75,6 +75,12 @@ public class BoatInRace extends Boat { return calculateHeading(azimuth); } + /** + * Returns the position of the end of the boat's wake, which is 180 degrees + * from the boat's heading, and whose length is proportional to the boat's + * speed. + * @return GPSCoordinate of wake endpoint. + */ public GPSCoordinate getWake() { double reverseHeading = calculateHeading() - 180; double distance = Constants.wakeScale * getVelocity(); diff --git a/src/main/java/seng302/Model/Race.java b/src/main/java/seng302/Model/Race.java index 340b7e35..5ab877d7 100644 --- a/src/main/java/seng302/Model/Race.java +++ b/src/main/java/seng302/Model/Race.java @@ -8,6 +8,7 @@ import javafx.collections.ObservableList; import seng302.Controllers.RaceController; import java.util.ArrayList; +import java.util.Random; /** * Parent class for races @@ -164,10 +165,19 @@ public abstract class Race implements Runnable { Platform.runLater(() -> {controller.setTimer(time);}); } + /** + * Update the calculated fps to the fps label + * @param fps The new calculated fps value + */ private void updateFPS(int fps) { Platform.runLater(() -> {controller.setFrames("FPS: " + fps);}); } + private boolean doNotFinish() { + Random rand = new Random(); + return rand.nextInt(100) < 1; + } + /** * Starts the Race Simulation, playing the race start to finish with the timescale. * This prints the boats participating, the order that the events occur in time order, and the respective information of the events. @@ -203,6 +213,11 @@ public abstract class Race implements Runnable { if (controller != null) controller.updateMap(startingBoats); if (timerEnabled) updateTime(calcTimer()); + } else { + //Exit animation timer + updateTime(calcTimer()); + updateFPS(0); //race ended so fps = 0 + stop(); //exit animation timer } fps++; if ((System.currentTimeMillis()-timeCurrent) > 1000){ @@ -240,6 +255,10 @@ public abstract class Race implements Runnable { boatsFinished++; boat.setFinished(true); boat.setTimeFinished(timeElapsed); + } else if(doNotFinish()) { + boatsFinished++; + boat.setFinished(true); + boat.setCurrentLeg(new Leg("DNF",-1)); } else { //Calculate how much the boat overshot the marker by boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance()); diff --git a/src/main/java/seng302/Model/ResizableRaceCanvas.java b/src/main/java/seng302/Model/ResizableRaceCanvas.java index cc55458a..4764dee7 100644 --- a/src/main/java/seng302/Model/ResizableRaceCanvas.java +++ b/src/main/java/seng302/Model/ResizableRaceCanvas.java @@ -19,6 +19,7 @@ public class ResizableRaceCanvas extends Canvas { private GraphicsContext gc; private RaceMap map; private BoatInRace[] boats; + private boolean raceAnno = true; /** * Sets the boats that are to be displayed in this race. @@ -141,6 +142,14 @@ public class ResizableRaceCanvas extends Canvas { gc.fillText(text, xCoord, yCoord); } + /** + * Draws race map with up to date data. + */ + public void update() { + this.drawRaceMap(); + this.updateBoats(); + } + /** * Draws the Race Map */ @@ -177,21 +186,39 @@ public class ResizableRaceCanvas extends Canvas { displayArrow(new GraphCoordinate(500, 20), 100); } + /** + * Draws boats while race in progress, when leg heading is set. + */ public void updateBoats() { if (boats != null) { for (BoatInRace boat : boats) { - if (boat != null && !boat.getCurrentLeg().getName().equals("Finish")) { + boolean finished = boat.getCurrentLeg().getName().equals("Finish") || boat.getCurrentLeg().getName().equals("DNF"); + if (!finished) { displayBoat(boat, boat.calculateHeading()); GraphCoordinate wakeFrom = this.map.convertGPS(boat.getCurrentPosition()); GraphCoordinate wakeTo = this.map.convertGPS(boat.getWake()); displayLine(wakeFrom, wakeTo, boat.getColour()); } - else displayBoat(boat, 0); - displayText(boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition())); + else { + displayBoat(boat, 0); + } + + if (raceAnno) displayText(boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition())); } } } + /** + * Toggle the raceAnno value + */ + public void toggleAnno(){ + if (raceAnno){ + raceAnno = false; + } else { + raceAnno = true; + } + } + /** * Set the Canvas to resizable. * @@ -224,12 +251,15 @@ public class ResizableRaceCanvas extends Canvas { return getHeight(); } + /** + * Draws boats during race setup, when leg heading is not set. + */ public void drawBoats() { if (boats != null) { for (BoatInRace boat : boats) { if (boat != null) { displayBoat(boat, 0); - displayText(boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition())); + if (raceAnno) displayText(boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition())); } } } diff --git a/src/main/resources/scenes/racepane.fxml b/src/main/resources/scenes/racepane.fxml index 2840e5a1..620b0e81 100644 --- a/src/main/resources/scenes/racepane.fxml +++ b/src/main/resources/scenes/racepane.fxml @@ -69,9 +69,18 @@ -