Merged annotation toggle and DNF features with heading visualisation.

main
cbt24 9 years ago
parent cfbb27513d
commit 1524ed5a0e

@ -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<BoatInRace> 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<Boolean>() {
public void changed(ObservableValue<? extends Boolean> 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<Boolean>() {
public void changed(ObservableValue<? extends Boolean> ov,
Boolean old_val, Boolean new_val) {
raceMap.toggleAnno();
raceMap.update();
}
});
}

@ -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;
}

@ -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();

@ -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());

@ -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,19 +186,37 @@ 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;
}
}
/**
@ -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()));
}
}
}

@ -69,9 +69,18 @@
<items>
<AnchorPane fx:id="canvasBase" prefHeight="581.0" prefWidth="537.0">
<children>
<Label fx:id="timer" layoutX="45.0" layoutY="146.0" text="0:0" AnchorPane.bottomAnchor="0.0"
AnchorPane.rightAnchor="0.0"/>
<Label fx:id="FPS" layoutX="-20.0" layoutY="153.0" text="FPS: 0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="-0.0" />
<Label fx:id="FPS" text="FPS: 0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" />
<Label fx:id="timer" layoutX="45.0" layoutY="146.0" text="0:0" AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0" />
<TitledPane fx:id="userControl" animated="false" text="User Control" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<CheckBox fx:id="showFPS" mnemonicParsing="false" selected="true" text="Show FPS" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
<CheckBox fx:id="showAnno" mnemonicParsing="false" selected="true" text="Show Annotations" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="25.0" />
</children>
</AnchorPane>
</content>
</TitledPane>
</children>
</AnchorPane>
<AnchorPane layoutX="450.0" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="200.0"

Loading…
Cancel
Save