Merge branch 'master' of https://eng-git.canterbury.ac.nz/seng302-2017/team-7 into changeStartingPositions2
This commit is contained in:
@@ -32,7 +32,8 @@ public class App extends Application {
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
this.primaryStage = primaryStage;
|
||||
|
||||
primaryStage.minHeightProperty().setValue(600);
|
||||
primaryStage.minWidthProperty().setValue(780);
|
||||
//load the first container
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader();
|
||||
|
||||
@@ -21,12 +21,14 @@ public class Constants {
|
||||
public static final GPSCoordinate finishLineMarker1 = new GPSCoordinate(32.317379, -64.839291);
|
||||
public static final GPSCoordinate finishLineMarker2 = new GPSCoordinate(32.317257, -64.836260);
|
||||
|
||||
public static final double wakeScale = 10;
|
||||
|
||||
public static final BoatInRace[] OFFICIAL_AC35_COMPETITORS = new BoatInRace[]
|
||||
{new BoatInRace("Oracle Team USA", 30.0, Color.BLUEVIOLET, "Oracle"),
|
||||
new BoatInRace("Land Rover BAR", 23.0, Color.BLACK, "BAR"),
|
||||
new BoatInRace("SoftBank Team Japan", 27.0, Color.RED, "JAP"),
|
||||
new BoatInRace("Groupama Team France", 25.0, Color.ORANGE, "FRN"),
|
||||
new BoatInRace("Artemis Racing", 22.5, Color.DARKOLIVEGREEN, "ART"),
|
||||
new BoatInRace("Land Rover BAR", 23.0, Color.BLACK, "BGR"),
|
||||
new BoatInRace("SoftBank Team Japan", 27.0, Color.RED, "JPN"),
|
||||
new BoatInRace("Groupama Team France", 25.0, Color.ORANGE, "FRA"),
|
||||
new BoatInRace("Artemis Racing", 22.5, Color.DARKOLIVEGREEN, "SWE"),
|
||||
new BoatInRace("Emirates Team New Zealand", 62, Color.LIMEGREEN, "ETNZ")};
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.util.Callback;
|
||||
@@ -34,7 +35,7 @@ import java.util.ResourceBundle;
|
||||
*/
|
||||
public class RaceController extends Controller{
|
||||
@FXML
|
||||
AnchorPane canvasBase;
|
||||
GridPane canvasBase;
|
||||
|
||||
ResizableRaceCanvas raceMap;
|
||||
|
||||
@@ -55,7 +56,6 @@ public class RaceController extends Controller{
|
||||
@FXML
|
||||
Label FPS;
|
||||
|
||||
|
||||
@FXML
|
||||
TableView<BoatInRace> boatInfoTable;
|
||||
@FXML
|
||||
@@ -76,7 +76,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.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,15 +122,38 @@ public class RaceController extends Controller{
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
|
||||
//listener for fps
|
||||
/*Tooltip tp = new Tooltip("");
|
||||
tp.install(timer, tp);*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
/*timer.setOnMouseEntered(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent e) {
|
||||
tp.show(timer, timer.getLayoutX()+timer.getWidth()+10, timer.getLayoutY()+timer.getHeight()-10);
|
||||
}
|
||||
});
|
||||
timer.setOnMouseExited(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent e) {
|
||||
tp.hide();
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes and runs the race, based on the user's chosen scale factor
|
||||
* Currently uses an example racecourse
|
||||
*
|
||||
* @param scaleFactor
|
||||
* @param scaleFactor scale value of race
|
||||
*/
|
||||
private void startRace(int scaleFactor) {
|
||||
RaceXMLReader raceXMLReader = null;
|
||||
@@ -145,12 +168,18 @@ public class RaceController extends Controller{
|
||||
}
|
||||
BoatInRace[] boats = new BoatInRace[raceXMLReader.getBoats().size()];
|
||||
boats = raceXMLReader.getBoats().toArray(boats);
|
||||
|
||||
raceMap = new ResizableRaceCanvas();
|
||||
//BoatInRace[] boats = generateAC35Competitors();
|
||||
double lat1 = raceXMLReader.getMapTopLeft().getLatitude();
|
||||
double long1 = raceXMLReader.getMapTopLeft().getLongitude();
|
||||
double lat2 = raceXMLReader.getMapBottomRight().getLatitude();
|
||||
double long2 = raceXMLReader.getMapBottomRight().getLongitude();
|
||||
raceMap = new ResizableRaceCanvas(lat1, long1, lat2, long2);
|
||||
raceMap.setMouseTransparent(true);
|
||||
raceMap.widthProperty().bind(canvasBase.widthProperty());
|
||||
raceMap.heightProperty().bind(canvasBase.heightProperty());
|
||||
raceMap.setBoats(boats);
|
||||
raceMap.setRaceBoundaries(raceXMLReader.getBoundary());
|
||||
raceMap.drawBoats();
|
||||
raceMap.drawRaceMap();
|
||||
raceMap.setVisible(true);
|
||||
|
||||
@@ -161,9 +190,7 @@ public class RaceController extends Controller{
|
||||
ArrayList<Leg> legs = raceXMLReader.getLegs();
|
||||
ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, this, scaleFactor);
|
||||
|
||||
new Thread((race)).start();
|
||||
|
||||
//listener for fps
|
||||
showFPS.setVisible(true);
|
||||
showFPS.selectedProperty().addListener(new ChangeListener<Boolean>() {
|
||||
public void changed(ObservableValue<? extends Boolean> ov,
|
||||
Boolean old_val, Boolean new_val) {
|
||||
@@ -179,12 +206,15 @@ public class RaceController extends Controller{
|
||||
showAnno.selectedProperty().addListener(new ChangeListener<Boolean>() {
|
||||
public void changed(ObservableValue<? extends Boolean> ov,
|
||||
Boolean old_val, Boolean new_val) {
|
||||
raceMap.toggleAnno();
|
||||
raceMap.drawRaceMap();
|
||||
raceMap.toggleAnno();
|
||||
raceMap.update();
|
||||
}
|
||||
});
|
||||
|
||||
new Thread((race)).start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the value for the race clock label
|
||||
* @param time time that the label will be updated to
|
||||
@@ -199,5 +229,4 @@ public class RaceController extends Controller{
|
||||
*/
|
||||
public void setFrames(String fps) { FPS.setText((fps)); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
this.velocityProp = new SimpleStringProperty(String.valueOf(Math.round(velocity)));
|
||||
this.abbrev = abbrev;
|
||||
this.name = new SimpleStringProperty(name);
|
||||
}
|
||||
@@ -48,6 +48,14 @@ 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;
|
||||
this.velocityProp.setValue(String.valueOf(Math.round(velocity)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Print method prints the name of the boat
|
||||
|
||||
@@ -4,8 +4,10 @@ import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.geotools.referencing.GeodeticCalculator;
|
||||
import seng302.Constants;
|
||||
import seng302.GPSCoordinate;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
/**
|
||||
* Boat in the Race extends Boat.
|
||||
@@ -21,6 +23,7 @@ public class BoatInRace extends Boat {
|
||||
private Color colour;
|
||||
private boolean finished = false;
|
||||
private StringProperty currentLegName;
|
||||
private boolean started = false;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
@@ -76,6 +79,25 @@ 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();
|
||||
|
||||
GeodeticCalculator calc = new GeodeticCalculator();
|
||||
calc.setStartingGeographicPoint(
|
||||
new Point2D.Double(getCurrentPosition().getLongitude(), getCurrentPosition().getLatitude())
|
||||
);
|
||||
calc.setDirection(reverseHeading, distance);
|
||||
Point2D endpoint = calc.getDestinationGeographicPoint();
|
||||
return new GPSCoordinate(endpoint.getY(), endpoint.getX());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Scaled velocity of the boat
|
||||
*/
|
||||
@@ -203,4 +225,11 @@ public class BoatInRace extends Boat {
|
||||
this.finished = bool;
|
||||
}
|
||||
|
||||
public boolean isStarted() {
|
||||
return started;
|
||||
}
|
||||
|
||||
public void setStarted(boolean started) {
|
||||
this.started = started;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import seng302.GPSCoordinate;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Parent class for races
|
||||
@@ -30,8 +31,8 @@ public abstract class Race implements Runnable {
|
||||
protected int scaleFactor;
|
||||
|
||||
private int SLEEP_TIME = 100; //time in milliseconds to pause in a paced loop
|
||||
protected int PRERACE_TIME = 10000;//Integer.MAX_VALUE; //time in milliseconds to pause during pre-race
|
||||
private boolean timerEnabled = true;
|
||||
protected int PRERACE_TIME = 5000; //time in milliseconds to pause during pre-race
|
||||
private boolean timerEnabled = true; //boolean to determine if timer is ran
|
||||
|
||||
/**
|
||||
* Initailiser for Race
|
||||
@@ -105,6 +106,21 @@ public abstract class Race implements Runnable {
|
||||
timerEnabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the state in waiting for the race starts.
|
||||
*/
|
||||
private void preRace() {
|
||||
//show the boats participating.
|
||||
System.out.println("Boats Participating:");
|
||||
System.out.println("====================");
|
||||
for (int i = 0; i < startingBoats.size(); i++) {
|
||||
if (startingBoats.get(i) != null) {
|
||||
System.out.println(i + 1 + ". " + startingBoats.get(i).toString() + ", Speed: "
|
||||
+ Math.round(startingBoats.get(i).getVelocity()) + "kn");
|
||||
startingBoats.get(i).setCurrentLeg(legs.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Countdown timer until race starts. Use PRERACE_TIME to set countdown duration.
|
||||
@@ -120,15 +136,18 @@ public abstract class Race implements Runnable {
|
||||
long timeLoopEnded;
|
||||
|
||||
while (currentTime <= startTime) {
|
||||
//if (controller != null) controller.updateMap(startingBoats);
|
||||
timeLeft = startTime - currentTime;
|
||||
currentTimeInSeconds = timeLeft / 1000;
|
||||
minutes = currentTimeInSeconds / 60;
|
||||
remainingSeconds = currentTimeInSeconds % 60;
|
||||
hours = minutes / 60;
|
||||
minutes = minutes % 60;
|
||||
if (controller != null) {
|
||||
updateTime(String.format("Time until race starts: %02d:%02d:%02d", hours, minutes, remainingSeconds));
|
||||
if (timeLeft == 0 && controller != null) {
|
||||
updateTime("Race is starting...");
|
||||
} else {
|
||||
currentTimeInSeconds = timeLeft / 1000;
|
||||
minutes = currentTimeInSeconds / 60;
|
||||
remainingSeconds = currentTimeInSeconds % 60;
|
||||
hours = minutes / 60;
|
||||
minutes = minutes % 60;
|
||||
if (controller != null) {
|
||||
updateTime(String.format("Race clock: -%02d:%02d:%02d", hours, minutes, remainingSeconds));
|
||||
}
|
||||
}
|
||||
try {
|
||||
timeLoopEnded = System.currentTimeMillis();
|
||||
@@ -150,7 +169,7 @@ public abstract class Race implements Runnable {
|
||||
long remainingSeconds;
|
||||
long hours;
|
||||
|
||||
currentTimeInSeconds = (totalTimeElapsed / 1000) * scaleFactor;
|
||||
currentTimeInSeconds = (totalTimeElapsed * scaleFactor)/ 1000;
|
||||
minutes = currentTimeInSeconds / 60;
|
||||
remainingSeconds = currentTimeInSeconds % 60;
|
||||
hours = minutes / 60;
|
||||
@@ -174,6 +193,11 @@ public abstract class Race implements Runnable {
|
||||
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.
|
||||
@@ -182,11 +206,15 @@ public abstract class Race implements Runnable {
|
||||
|
||||
System.setProperty("javafx.animation.fullspeed", "true");
|
||||
|
||||
for (BoatInRace boat: startingBoats){
|
||||
boat.setStarted(true);
|
||||
}
|
||||
|
||||
new AnimationTimer() {
|
||||
|
||||
long timeRaceStarted = System.currentTimeMillis();
|
||||
int fps = 0;
|
||||
long timeCurrent = System.currentTimeMillis();
|
||||
long timeRaceStarted = System.currentTimeMillis(); //start time of loop
|
||||
int fps = 0; //init fps value
|
||||
long timeCurrent = System.currentTimeMillis(); //current time
|
||||
|
||||
@Override
|
||||
public void handle(long arg0) {
|
||||
@@ -208,6 +236,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){
|
||||
@@ -236,21 +269,28 @@ public abstract class Race implements Runnable {
|
||||
*/
|
||||
protected void checkPosition(BoatInRace boat, long timeElapsed) {
|
||||
if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()){
|
||||
// updateController();
|
||||
//boat has passed onto new leg
|
||||
if (boat.getCurrentLeg().getName().equals("Finish")) {
|
||||
//boat has finished
|
||||
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());
|
||||
//Move boat on to next leg
|
||||
Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1);
|
||||
|
||||
boat.setCurrentLeg(nextLeg);
|
||||
//Add overshoot distance into the distance travelled for the next leg
|
||||
boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg());
|
||||
}
|
||||
FXCollections.sort(startingBoats, (a,b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber());
|
||||
//Update the boat display table in the GUI to reflect the leg change
|
||||
FXCollections.sort(startingBoats, (a, b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,9 +312,9 @@ public abstract class Race implements Runnable {
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is a function that generates the Race and populates the events list.
|
||||
* Is automatically called by the initialiser function, so that simulateRace() does not return an empty race.
|
||||
* @see Race#simulateRace()
|
||||
* Updates the boat's gps coordinates depending on time elapsed
|
||||
* @param boat
|
||||
* @param millisecondsElapsed
|
||||
*/
|
||||
protected abstract void updatePosition(BoatInRace boat, int millisecondsElapsed);
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package seng302.Model;
|
||||
|
||||
|
||||
import com.sun.corba.se.impl.orbutil.graph.Graph;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.paint.Color;
|
||||
@@ -17,6 +19,7 @@ import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* This creates a JavaFX Canvas that is fills it's parent.
|
||||
@@ -27,7 +30,10 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
private GraphicsContext gc;
|
||||
private RaceMap map;
|
||||
private BoatInRace[] boats;
|
||||
private RaceController controller;
|
||||
private boolean raceAnno = true;
|
||||
private ArrayList<GPSCoordinate> raceBoundaries;
|
||||
double[] xpoints = {}, ypoints = {};
|
||||
|
||||
/**
|
||||
* Sets the boats that are to be displayed in this race.
|
||||
@@ -38,8 +44,8 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
this.boats = boats;
|
||||
}
|
||||
|
||||
|
||||
public ResizableRaceCanvas(RaceMap map) {
|
||||
super();
|
||||
this.map = map;
|
||||
gc = this.getGraphicsContext2D();
|
||||
// Redraw canvas when size changes.
|
||||
@@ -52,6 +58,12 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
*/
|
||||
public ResizableRaceCanvas() {
|
||||
this(null);
|
||||
setMap(new RaceMap(32.278, -64.863, 32.320989, -64.821, (int) getWidth(), (int) getHeight()));
|
||||
}
|
||||
|
||||
public ResizableRaceCanvas(double lat1, double long1, double lat2, double long2){
|
||||
this(null);
|
||||
setMap(new RaceMap(lat1, long1, lat2, long2, (int) getWidth(), (int) getHeight()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,9 +83,24 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
* @see Color
|
||||
* @see Paint
|
||||
*/
|
||||
public void displayMark(GraphCoordinate graphCoordinate, Paint paint) {
|
||||
public void displayMark(GraphCoordinate graphCoordinate, Paint paint){
|
||||
double d = 25;
|
||||
gc.setFill(paint);
|
||||
gc.fillOval(graphCoordinate.getX(), graphCoordinate.getY(), 25, 25);
|
||||
gc.fillOval(graphCoordinate.getX() - (d/2), graphCoordinate.getY() - (d/2), d, d);
|
||||
}
|
||||
|
||||
public void displayBoat(BoatInRace boat, double angle) {
|
||||
GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition());
|
||||
Paint paint = boat.getColour();
|
||||
|
||||
double[] x = {pos.getX() - 6, pos.getX(), pos.getX() + 6};
|
||||
double[] y = {pos.getY() + 12, pos.getY() - 12, pos.getY() + 12};
|
||||
gc.setFill(paint);
|
||||
|
||||
gc.save();
|
||||
rotate(angle, pos.getX(), pos.getY());
|
||||
gc.fillPolygon(x, y, 3);
|
||||
gc.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,7 +112,7 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
* @see Color
|
||||
* @see Paint
|
||||
*/
|
||||
public void displayLine(GraphCoordinate graphCoordinateA, GraphCoordinate graphCoordinateB, Paint paint) {
|
||||
private void displayLine(GraphCoordinate graphCoordinateA, GraphCoordinate graphCoordinateB, Paint paint) {
|
||||
gc.setStroke(paint);
|
||||
gc.setFill(paint);
|
||||
gc.fillOval(graphCoordinateA.getX() - 3, graphCoordinateA.getY() - 3, 6, 6);
|
||||
@@ -101,23 +128,24 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
* @see Paint
|
||||
* @see Color
|
||||
*/
|
||||
public void displayPoint(GraphCoordinate graphCoordinate, Paint paint) {
|
||||
private void displayPoint(GraphCoordinate graphCoordinate, Paint paint) {
|
||||
gc.setFill(paint);
|
||||
gc.fillOval(graphCoordinate.getX(), graphCoordinate.getY(), 10, 10);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays an arrow on the Canvas
|
||||
* @param coordinate Coordinate that the arrow is to be displayed at.
|
||||
* @param angle Angle that the arrow is to be facing in degrees 0 degrees = North (Up).
|
||||
* @see GraphCoordinate
|
||||
*/
|
||||
public void displayArrow(GraphCoordinate coordinate, int angle) {
|
||||
private void displayArrow(GraphCoordinate coordinate, int angle) {
|
||||
gc.save();
|
||||
rotate(angle, coordinate.getX(),coordinate.getY());
|
||||
rotate(angle, coordinate.getX(), coordinate.getY());
|
||||
gc.setFill(Color.BLACK);
|
||||
gc.fillPolygon(new double[]{coordinate.getX()-12, coordinate.getX()-6, coordinate.getX(), coordinate.getX()-4, coordinate.getX()-4, coordinate.getX()-8, coordinate.getX()-8},
|
||||
new double[]{coordinate.getY()-5, coordinate.getY()-20, coordinate.getY()-5, coordinate.getY()-5, coordinate.getY()+20, coordinate.getY()+20, coordinate.getY()-5},
|
||||
gc.fillPolygon(new double[]{coordinate.getX() - 12, coordinate.getX() - 6, coordinate.getX(), coordinate.getX() - 4, coordinate.getX() - 4, coordinate.getX() - 8, coordinate.getX() - 8},
|
||||
new double[]{coordinate.getY() - 5, coordinate.getY() - 20, coordinate.getY() - 5, coordinate.getY() - 5, coordinate.getY() + 20, coordinate.getY() + 20, coordinate.getY() - 5},
|
||||
7);
|
||||
gc.restore();
|
||||
}
|
||||
@@ -139,8 +167,8 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
* @param speed speed of the boat
|
||||
* @param coordinate coordinate the text appears
|
||||
*/
|
||||
public void displayText(String name, double speed, GraphCoordinate coordinate){
|
||||
String text = String.format("%s, %2$.2f knots", name, speed);
|
||||
private void displayText(String name, double speed, GraphCoordinate coordinate){
|
||||
String text = String.format("%s, %2$.2fkn", name, speed);
|
||||
//System.out.println(text.length()*7);
|
||||
long xCoord = coordinate.getX()+20;
|
||||
long yCoord = coordinate.getY();
|
||||
@@ -153,6 +181,23 @@ 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();
|
||||
}
|
||||
|
||||
public void drawBoundaries(){
|
||||
if (this.raceBoundaries == null){
|
||||
return;
|
||||
}
|
||||
gc.setFill(Color.AQUA);
|
||||
setRaceBoundCoordinates();
|
||||
gc.fillPolygon(xpoints, ypoints, xpoints.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the Race Map
|
||||
*/
|
||||
@@ -163,13 +208,15 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
|
||||
gc.clearRect(0, 0, width, height);
|
||||
//System.out.println("Race Map Canvas Width: "+ width + ", Height:" + height);
|
||||
this.map = new RaceMap(32.278, -64.863, 32.320989, -64.821, (int) width, (int) height);
|
||||
if (map == null) {
|
||||
return;
|
||||
return;//TODO this should return a exception in the future
|
||||
}
|
||||
this.map.setHeight((int)height);
|
||||
this.map.setWidth((int)width);
|
||||
|
||||
//finish line
|
||||
gc.setLineWidth(2);
|
||||
drawBoundaries();
|
||||
GraphCoordinate finishLineCoord1 = this.map.convertGPS(Constants.finishLineMarker1);
|
||||
GraphCoordinate finishLineCoord2 = this.map.convertGPS(Constants.finishLineMarker2);
|
||||
displayLine(finishLineCoord1, finishLineCoord2, Color.DARKRED);
|
||||
@@ -188,20 +235,10 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
|
||||
displayLine(startline1, startline2, Color.GREEN);
|
||||
|
||||
updateBoats();
|
||||
|
||||
if (boats != null) {
|
||||
for (BoatInRace boat : boats) {
|
||||
if (boat != null) {
|
||||
// System.out.print("Drawing Boat At: " + boat.getCurrentPosition());
|
||||
displayPoint(this.map.convertGPS(boat.getCurrentPosition()), boat.getColour());
|
||||
if (raceAnno){
|
||||
displayText(boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition()));}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//display wind direction arrow - specify origin point and angle
|
||||
displayArrow(new GraphCoordinate(500, 20), 100);
|
||||
//display wind direction arrow - specify origin point and angle - angle now set to random angle
|
||||
displayArrow(new GraphCoordinate((int)getWidth()-40, 40), 150);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +265,48 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws boats while race in progress, when leg heading is set.
|
||||
*/
|
||||
public void updateBoats() {
|
||||
if (boats != null) {
|
||||
for (BoatInRace boat : boats) {
|
||||
boolean finished = boat.getCurrentLeg().getName().equals("Finish") || boat.getCurrentLeg().getName().equals("DNF");
|
||||
boolean isStart = boat.isStarted();
|
||||
if (!finished && isStart) {
|
||||
displayBoat(boat, boat.calculateHeading());
|
||||
GraphCoordinate wakeFrom = this.map.convertGPS(boat.getCurrentPosition());
|
||||
GraphCoordinate wakeTo = this.map.convertGPS(boat.getWake());
|
||||
displayLine(wakeFrom, wakeTo, boat.getColour());
|
||||
} else if (!isStart){
|
||||
displayBoat(boat, boat.calculateHeading());
|
||||
} else {
|
||||
displayBoat(boat, 0);
|
||||
}
|
||||
|
||||
if (raceAnno) displayText(boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setRaceBoundaries(ArrayList<GPSCoordinate> boundaries) {
|
||||
this.raceBoundaries = new ArrayList<>();
|
||||
for (GPSCoordinate bound: boundaries){
|
||||
raceBoundaries.add(bound);
|
||||
}
|
||||
setRaceBoundCoordinates();
|
||||
}
|
||||
|
||||
public void setRaceBoundCoordinates(){
|
||||
xpoints = new double[this.raceBoundaries.size()];
|
||||
ypoints = new double[this.raceBoundaries.size()];
|
||||
for (int i = 0; i < raceBoundaries.size(); i++){
|
||||
GraphCoordinate coord = map.convertGPS(raceBoundaries.get(i));
|
||||
xpoints[i] = coord.getX();
|
||||
ypoints[i] = coord.getY();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Canvas to resizable.
|
||||
*
|
||||
@@ -260,4 +339,17 @@ 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);
|
||||
if (raceAnno) displayText(boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,16 @@ public class RaceMap {
|
||||
* @see GraphCoordinate
|
||||
*/
|
||||
public GraphCoordinate convertGPS(double lat, double lon) {
|
||||
int difference = Math.abs(width - height);
|
||||
int size = width;
|
||||
if (width > height){
|
||||
size = height;
|
||||
return new GraphCoordinate((int) ((size * (lon - x1) / (x2 - x1)) + difference/2), (int) (size - (size * (lat - y1) / (y2 - y1))));
|
||||
}else{
|
||||
return new GraphCoordinate((int) (size * (lon - x1) / (x2 - x1)), (int) ((size - (size * (lat - y1) / (y2 - y1))) + difference/2));
|
||||
}
|
||||
|
||||
return new GraphCoordinate((int) (width * (lon - x1) / (x2 - x1)), (int) (height - (height * (lat - y1) / (y2 - y1))));
|
||||
//return new GraphCoordinate((int) (width * (lon - x1) / (x2 - x1)), (int) (height - (height * (lat - y1) / (y2 - y1))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,4 +58,12 @@ public class RaceMap {
|
||||
public GraphCoordinate convertGPS(GPSCoordinate coordinate) {
|
||||
return convertGPS(coordinate.getLatitude(), coordinate.getLongitude());
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ public class RaceXMLReader extends XMLReader{
|
||||
private Color[] colors = {Color.BLUEVIOLET, Color.BLACK, Color.RED, Color.ORANGE, Color.DARKOLIVEGREEN, Color.LIMEGREEN};//TODO make this established in xml or come up with a better system.
|
||||
private ArrayList<Leg> legs = new ArrayList<>();
|
||||
private GPSCoordinate mark, startPt1, startPt2, finishPt1, finishPt2, leewardPt1, leewardPt2, windwardPt1, windwardPt2;
|
||||
private GPSCoordinate mapTopLeft, mapBottomRight;
|
||||
private ArrayList<GPSCoordinate> boundary = new ArrayList<>();
|
||||
private static double COORDINATEPADDING = 0.0005;
|
||||
|
||||
|
||||
public RaceXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException {
|
||||
@@ -36,8 +38,8 @@ public class RaceXMLReader extends XMLReader{
|
||||
|
||||
private void read(){
|
||||
readCourse();
|
||||
readBoats();
|
||||
readLegs();
|
||||
readBoats();
|
||||
}
|
||||
|
||||
public void readBoats(){
|
||||
@@ -51,6 +53,9 @@ public class RaceXMLReader extends XMLReader{
|
||||
//System.out.println(String.format("%s, %s, %s",name, abbrev, velo));
|
||||
BoatInRace boat = new BoatInRace(name, velo, colors[i], abbrev);
|
||||
boat.setCurrentPosition(startPt1);
|
||||
if (legs.size() > 0){
|
||||
boat.setCurrentLeg(legs.get(0));
|
||||
}
|
||||
boats.add(boat);
|
||||
}
|
||||
}
|
||||
@@ -74,9 +79,61 @@ public class RaceXMLReader extends XMLReader{
|
||||
NodeList nCourse = doc.getElementsByTagName("course");
|
||||
|
||||
NodeList nBounds = ((Element)nCourse.item(0)).getElementsByTagName("boundaries");
|
||||
nBounds = ((Element) nBounds.item(0)).getElementsByTagName("coordinate");
|
||||
int maxLatitudeIndex = 0;
|
||||
double maxLatitude = -Double.MIN_VALUE;
|
||||
int maxLongitudeIndex = 0;
|
||||
double maxLongitude = -180;
|
||||
int minLatitudeIndex = 0;
|
||||
double minLatitude = Double.MAX_VALUE;
|
||||
int minLongitudeIndex = 0;
|
||||
double minLongitude = Double.MAX_VALUE;
|
||||
for (int i = 0; i < nBounds.getLength(); i++){
|
||||
boundary.add(getCoordinates(nBounds, i));
|
||||
boundary.add(getCoordinates((Element) nBounds.item(i)));
|
||||
if (boundary.get(i).getLatitude() > maxLatitude){
|
||||
maxLatitudeIndex = i;
|
||||
maxLatitude = boundary.get(i).getLatitude();
|
||||
}
|
||||
if (boundary.get(i).getLatitude() < minLatitude){
|
||||
minLatitudeIndex = i;
|
||||
minLatitude = boundary.get(i).getLatitude();
|
||||
}
|
||||
if (boundary.get(i).getLongitude() > maxLongitude){
|
||||
maxLongitudeIndex = i;
|
||||
maxLongitude = boundary.get(i).getLongitude();
|
||||
}
|
||||
if (boundary.get(i).getLongitude() < minLongitude){
|
||||
minLongitudeIndex = i;
|
||||
minLongitude = boundary.get(i).getLongitude();
|
||||
}
|
||||
}
|
||||
/*System.out.println(nBounds.getLength());
|
||||
System.out.println(maxLatitude);
|
||||
System.out.println(minLatitude);
|
||||
System.out.println(maxLongitude);
|
||||
System.out.println(minLongitude);*/
|
||||
|
||||
double difference = 0;//this will hold the largest difference so we can make the map square.
|
||||
double latitudeDiff = Math.abs(Math.abs(boundary.get(maxLatitudeIndex).getLatitude()) - Math.abs(boundary.get(minLatitudeIndex).getLatitude()));
|
||||
double longitudeDiff = Math.abs(Math.abs(boundary.get(maxLongitudeIndex).getLongitude()) - Math.abs(boundary.get(minLongitudeIndex).getLongitude()));
|
||||
if (latitudeDiff >= longitudeDiff){
|
||||
difference = latitudeDiff - longitudeDiff;
|
||||
maxLongitude += difference/2;
|
||||
minLongitude -= difference/2;
|
||||
}else{
|
||||
difference = longitudeDiff - latitudeDiff;
|
||||
maxLatitude += difference/2;
|
||||
minLatitude -= difference/2;
|
||||
}
|
||||
maxLatitude += COORDINATEPADDING;
|
||||
minLatitude -= COORDINATEPADDING;
|
||||
maxLongitude += COORDINATEPADDING;
|
||||
minLongitude -= COORDINATEPADDING;
|
||||
//now create map boundaries
|
||||
//top left canvas point is min logitude, max latitude
|
||||
//bottom right of canvas point is min longitude, max latitude.
|
||||
mapTopLeft = new GPSCoordinate(minLatitude, minLongitude);
|
||||
mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude);
|
||||
|
||||
NodeList nMarks = ((Element)nCourse.item(0)).getElementsByTagName("marker");
|
||||
startPt1 = getCoordinates(nMarks, 0);
|
||||
@@ -190,4 +247,12 @@ public class RaceXMLReader extends XMLReader{
|
||||
public ArrayList<GPSCoordinate> getBoundary() {
|
||||
return boundary;
|
||||
}
|
||||
|
||||
public GPSCoordinate getMapTopLeft() {
|
||||
return mapTopLeft;
|
||||
}
|
||||
|
||||
public GPSCoordinate getMapBottomRight() {
|
||||
return mapBottomRight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,31 +9,31 @@
|
||||
<boat>
|
||||
<name>Land Rover BAR</name>
|
||||
<speed>50</speed>
|
||||
<abbr>BAR</abbr>
|
||||
<abbr>GBR</abbr>
|
||||
<colour>BLACK</colour>
|
||||
</boat>
|
||||
<boat>
|
||||
<name>SoftBank Team Japan</name>
|
||||
<speed>40</speed>
|
||||
<abbr>JAP</abbr>
|
||||
<abbr>JPN</abbr>
|
||||
<colour>RED</colour>
|
||||
</boat>
|
||||
<boat>
|
||||
<name>Groupama Team France</name>
|
||||
<speed>35</speed>
|
||||
<abbr>FRN</abbr>
|
||||
<abbr>FRA</abbr>
|
||||
<colour>ORANGE</colour>
|
||||
</boat>
|
||||
<boat>
|
||||
<name>Artemis Racing</name>
|
||||
<speed>44</speed>
|
||||
<abbr>ART</abbr>
|
||||
<abbr>SWE</abbr>
|
||||
<colour>DARKOLIVEGREEN</colour>
|
||||
</boat>
|
||||
<boat>
|
||||
<name>Emirates Team New Zealand</name>
|
||||
<speed>62</speed>
|
||||
<abbr>ENZ</abbr>
|
||||
<abbr>NZL</abbr>
|
||||
<colour>LIMEGREEN</colour>
|
||||
</boat>
|
||||
</boats>
|
||||
@@ -169,12 +169,48 @@
|
||||
<course>
|
||||
<boundaries>
|
||||
<coordinate>
|
||||
<latitude>32.278</latitude>
|
||||
<longitude>-64.863</longitude>
|
||||
<latitude>32.313922</latitude>
|
||||
<longitude>-64.837168</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.30989</latitude>
|
||||
<longitude>-64.821</longitude>
|
||||
<latitude>32.317403</latitude>
|
||||
<longitude>-64.838627</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.317911</latitude>
|
||||
<longitude>-64.836996</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.317548</latitude>
|
||||
<longitude>-64.835022</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.304273</latitude>
|
||||
<longitude>-64.822834</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.279097</latitude>
|
||||
<longitude>-64.841545</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.279604</latitude>
|
||||
<longitude>-64.849871</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.289545</latitude>
|
||||
<longitude>-64.854162</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.290198</latitude>
|
||||
<longitude>-64.858711</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.297164</latitude>
|
||||
<longitude>-64.856394</longitude>
|
||||
</coordinate>
|
||||
<coordinate>
|
||||
<latitude>32.296148</latitude>
|
||||
<longitude>-64.849184</longitude>
|
||||
</coordinate>
|
||||
</boundaries>
|
||||
<marker>
|
||||
|
||||
@@ -61,22 +61,40 @@
|
||||
</GridPane>
|
||||
<SplitPane fx:id="ongoingRacePane" dividerPositions="0.7" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<items>
|
||||
<AnchorPane fx:id="canvasBase" prefHeight="581.0" prefWidth="537.0">
|
||||
<children>
|
||||
<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>
|
||||
<GridPane fx:id="canvasBase">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Pane prefHeight="200.0" prefWidth="400.0" GridPane.halignment="LEFT" GridPane.valignment="TOP">
|
||||
<children>
|
||||
<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="77.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 Annotation" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="30.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</TitledPane>
|
||||
</children>
|
||||
</Pane>
|
||||
<Label fx:id="timer" layoutX="45.0" layoutY="146.0" text="0:0" AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0" GridPane.halignment="RIGHT" GridPane.valignment="BOTTOM">
|
||||
<font>
|
||||
<Font name="System Bold" size="15.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label fx:id="FPS" text="FPS: 0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
|
||||
<font>
|
||||
<Font name="System Bold" size="15.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</GridPane>
|
||||
<AnchorPane layoutX="450.0" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="200.0" GridPane.columnIndex="1">
|
||||
<children>
|
||||
<TableView fx:id="boatInfoTable" layoutX="-2.0" prefHeight="600.0" prefWidth="264.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="-2.0" AnchorPane.rightAnchor="-62.0" AnchorPane.topAnchor="0.0">
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package seng302.Model;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import seng302.GPSCoordinate;
|
||||
|
||||
@@ -113,4 +115,43 @@ public class BoatInRaceTest {
|
||||
assertFalse(testBoat.isFinished());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getWakeAtProperHeading() throws Exception {
|
||||
BoatInRace boat = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt");
|
||||
|
||||
// Construct leg of 0 degrees
|
||||
GPSCoordinate startPoint = new GPSCoordinate(0, 0);
|
||||
GPSCoordinate endPoint = new GPSCoordinate(50, 0);
|
||||
Leg leg0deg = new Leg("Start", startPoint, endPoint, 0);
|
||||
boat.setCurrentLeg(leg0deg);
|
||||
boat.setCurrentPosition(new GPSCoordinate(0,0));
|
||||
|
||||
assertEquals(0, boat.calculateHeading(), 1e-8);
|
||||
|
||||
// Construct leg from wake - heading should be 180 degrees
|
||||
Leg leg180deg = new Leg("Start", startPoint, boat.getWake(), 0);
|
||||
boat.setCurrentLeg(leg180deg);
|
||||
|
||||
assertEquals(180, boat.calculateHeading(), 1e-8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWakeProportionalToVelocity() throws Exception {
|
||||
BoatInRace boat = new BoatInRace("Test", 10, Color.ALICEBLUE, "tt");
|
||||
|
||||
// Construct leg of 0 degrees at 0 N
|
||||
GPSCoordinate startPoint = new GPSCoordinate(0, 0);
|
||||
GPSCoordinate endPoint = new GPSCoordinate(50, 0);
|
||||
Leg leg0deg = new Leg("Start", startPoint, endPoint, 0);
|
||||
boat.setCurrentLeg(leg0deg);
|
||||
boat.setCurrentPosition(new GPSCoordinate(0,0));
|
||||
|
||||
// Get latitude of endpoint of wake at 10 kn (longitude is 0)
|
||||
double endpointAt10Kn = boat.getWake().getLatitude();
|
||||
|
||||
// Latitude of endpoint at 20 kn should be twice endpoint at 10 kn
|
||||
boat.setVelocity(20);
|
||||
assertEquals(2*endpointAt10Kn, boat.getWake().getLatitude(), 1e-8);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user