Refactored Boat class to better fit the MVC model by moving all GUI parts to BoatPolygon. Changed the way animation works so that it will work with a constantly updated set of lats and lons.

TODO - Change Mark class to no longer store XY pixel data.
TODO - Add in a timer force updates boat position if a packet has not been recieved for a while.

#story30b #story30c #implement #refactor
This commit is contained in:
Calum
2017-04-24 23:06:30 +12:00
parent b5129c5c80
commit 46037b5aea
8 changed files with 392 additions and 234 deletions
@@ -3,6 +3,7 @@ package seng302.controllers;
import javafx.animation.*; import javafx.animation.*;
import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.geometry.Point2D;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.canvas.Canvas; import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext; import javafx.scene.canvas.GraphicsContext;
@@ -11,6 +12,8 @@ import javafx.scene.paint.Color;
import javafx.scene.text.Font; import javafx.scene.text.Font;
import javafx.util.Pair; import javafx.util.Pair;
import seng302.models.Boat; import seng302.models.Boat;
import seng302.models.BoatPolygon;
import seng302.models.Colors;
import seng302.models.mark.GateMark; import seng302.models.mark.GateMark;
import seng302.models.mark.Mark; import seng302.models.mark.Mark;
import seng302.models.mark.MarkType; import seng302.models.mark.MarkType;
@@ -32,14 +35,17 @@ public class CanvasController {
private ResizableCanvas canvas; private ResizableCanvas canvas;
private Group group; private Group group;
private GraphicsContext gc; private GraphicsContext gc;
private List<BoatPolygon> boatPolygons = new ArrayList<>();
private final int MARK_SIZE = 10; private final int MARK_SIZE = 10;
private final int BUFFER_SIZE = 25; private final int BUFFER_SIZE = 25;
private final int CANVAS_SIZE = 1000; private final int CANVAS_WIDTH = 1000;
private final int CANVAS_HEIGHT = 1000;
private final int LHS_BUFFER = BUFFER_SIZE; private final int LHS_BUFFER = BUFFER_SIZE;
private final int RHS_BUFFER = BUFFER_SIZE + MARK_SIZE / 2; private final int RHS_BUFFER = BUFFER_SIZE + MARK_SIZE / 2;
private final int TOP_BUFFER = BUFFER_SIZE; private final int TOP_BUFFER = BUFFER_SIZE;
private final int BOT_BUFFER = TOP_BUFFER + MARK_SIZE / 2; private final int BOT_BUFFER = TOP_BUFFER + MARK_SIZE / 2;
private final int FRAME_RATE = 60;
private double distanceScaleFactor; private double distanceScaleFactor;
private ScaleDirection scaleDirection; private ScaleDirection scaleDirection;
@@ -49,6 +55,9 @@ public class CanvasController {
private Mark maxLonPoint; private Mark maxLonPoint;
private int referencePointX; private int referencePointX;
private int referencePointY; private int referencePointY;
private double metersToPixels;
public AnimationTimer timer;
private enum ScaleDirection { private enum ScaleDirection {
HORIZONTAL, HORIZONTAL,
@@ -67,70 +76,119 @@ public class CanvasController {
canvasPane.getChildren().add(canvas); canvasPane.getChildren().add(canvas);
canvasPane.getChildren().add(group); canvasPane.getChildren().add(group);
// Bind canvas size to stack pane size. // Bind canvas size to stack pane size.
canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_SIZE)); canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH));
canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_SIZE)); canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT));
group.minWidth(CANVAS_SIZE); group.minWidth(CANVAS_WIDTH);
group.minHeight(CANVAS_SIZE); group.minHeight(CANVAS_HEIGHT);
// canvas.widthProperty().bind(canvasPane.widthProperty());
// canvas.heightProperty().bind(canvasPane.heightProperty());
// group.minWidth(canvas.getWidth());
// group.minHeight(canvas.getHeight());
} }
public void initializeCanvas (){
public void setUpBoats(){
gc = canvas.getGraphicsContext2D(); gc = canvas.getGraphicsContext2D();
gc.save(); gc.save();
gc.setFill(Color.SKYBLUE); gc.setFill(Color.SKYBLUE);
gc.fillRect(0,0, CANVAS_SIZE,CANVAS_SIZE); gc.fillRect(0,0, CANVAS_WIDTH, CANVAS_HEIGHT);
gc.restore(); gc.restore();
drawCourse(); drawCourse();
for (Mark m : raceViewController.getRace().getCourse())
{
System.out.println("MARK NAME - " + m.getName());
System.out.println("X LOCATION - " + m.getX());
System.out.println("Y LOCATION - " + m.getY());
}
drawBoats(); drawBoats();
drawFps(12); // drawFps(12);
// overriding the handle so that it can clean canvas and redraw boats and course marks // // overriding the handle so that it can clean canvas and redraw boats and course marks
AnimationTimer timer = new AnimationTimer() { // AnimationTimer timer = new AnimationTimer() {
private long lastUpdate = 0; // private long lastUpdate = 0;
private long lastFpsUpdate = 0; // private long lastFpsUpdate = 0;
private int lastFpsCount = 0; // private int lastFpsCount = 0;
private int fpsCount = 0; // private int fpsCount = 0;
boolean done = true; // boolean done = true;
//
// @Override
// public void handle(long now) {
// if (true){ //if statement for limiting refresh rate if needed
//// gc.clearRect(0, 0, canvas.getWidth(),canvas.getHeight());
//// gc.setFill(Color.SKYBLUE);
//// gc.fillRect(0,0,canvas.getWidth(),canvas.getHeight());
//
//
// // If race has started, draw the boats and play the timeline
// if (raceViewController.getRace().getRaceTime() > 1) {
// raceViewController.playTimelines();
// }
// // Race has not started, pause the timelines
// else {
// raceViewController.pauseTimelines();
// }
// lastUpdate = now;
// fpsCount ++;
// if (now - lastFpsUpdate >= 1000000000){
// lastFpsCount = fpsCount;
// fpsCount = 0;
// lastFpsUpdate = now;
// }
// }
// }
// };
// timer.start();
//try {
// Thread.sleep(10000);
//}catch (Exception e) {
// e.printStackTrace();
//}
timer = new AnimationTimer() {
private int countdown = 60;
private int[] currentRaceMarker = {1, 1, 1, 1, 1, 1};
List<Mark> marks = raceViewController.getRace().getCourse();
@Override @Override
public void handle(long now) { public void handle(long now) {
if (true){ //if statement for limiting refresh rate if needed boolean raceFinished = true;
// gc.clearRect(0, 0, canvas.getWidth(),canvas.getHeight()); boolean descending;
// gc.setFill(Color.SKYBLUE); int boatIndex = 0;
// gc.fillRect(0,0,canvas.getWidth(),canvas.getHeight()); Mark nextMark;
if (countdown == 0) {
for (BoatPolygon bp : boatPolygons) {
// If race has started, draw the boats and play the timeline if (currentRaceMarker[boatIndex] < marks.size()) {
if (raceViewController.getRace().getRaceTime() > 1){ if (currentRaceMarker[boatIndex] == 6) {
raceViewController.playTimelines(); int debugLine = 4;
} }
// Race has not started, pause the timelines double xb4 = bp.getLayoutX();
else { double yb4 = bp.getLayoutY();
raceViewController.pauseTimelines(); nextMark = marks.get(currentRaceMarker[boatIndex]);
if (nextMark.getY() > bp.getLayoutY())
descending = true;
else
descending = false;
bp.updatePosition(1000 / 60);
if (descending && nextMark.getY() < bp.getLayoutY()) {
currentRaceMarker[boatIndex]++;
bp.setDestination(
marks.get(currentRaceMarker[boatIndex]).getX(), marks.get(currentRaceMarker[boatIndex]).getY()
);
} else if (!descending && nextMark.getY() > bp.getLayoutY()) {
currentRaceMarker[boatIndex]++;
bp.setDestination(
marks.get(currentRaceMarker[boatIndex]).getX(), marks.get(currentRaceMarker[boatIndex]).getY()
);
} }
lastUpdate = now; double xnew = bp.getLayoutX();
fpsCount ++; double ynew = bp.getLayoutY();
if (now - lastFpsUpdate >= 1000000000){ double dx = xnew - xb4;
lastFpsCount = fpsCount; double dy = ynew -yb4;
fpsCount = 0; raceFinished = false;
lastFpsUpdate = now; boatIndex++;
} }
} }
if (raceFinished) {
System.out.println("DONZEO LADS");
this.stop();
}
} else {
countdown--;
}
} }
}; };
timer.start(); for (Mark m : raceViewController.getRace().getCourse())
System.out.println(m.getName());
//timer.start();
} }
class ResizableCanvas extends Canvas { class ResizableCanvas extends Canvas {
@@ -179,16 +237,22 @@ public class CanvasController {
*/ */
private void drawBoats() { private void drawBoats() {
// Map<Boat, TimelineInfo> timelineInfos = raceViewController.getTimelineInfos(); // Map<Boat, TimelineInfo> timelineInfos = raceViewController.getTimelineInfos();
ArrayList<Boat> boats = raceViewController.getStartingBoats(); List<Boat> boats = raceViewController.getStartingBoats();
Double startingX = (double) raceViewController.getRace().getCourse().get(0).getX(); List<Mark> marks = raceViewController.getRace().getCourse();
Double startingY = (double) raceViewController.getRace().getCourse().get(0).getY(); Double startingX = (double) marks.get(0).getX();
Double startingY = (double) marks.get(0).getY();
Double firstMarkX = (double) marks.get(1).getX();
Double firstMarkY = (double) marks.get(1).getY();
for (Boat boat : boats) { for (Boat boat : boats) {
boat.moveBoatTo(startingX, startingY); BoatPolygon bp = new BoatPolygon(boat, Colors.getColor());
group.getChildren().add(boat.getWake()); bp.moveBoatTo(startingX, startingY);
group.getChildren().add(boat.getBoatObject()); bp.setDestination(firstMarkX, firstMarkY);
group.getChildren().add(boat.getTeamNameObject()); group.getChildren().add(bp.getWake());
group.getChildren().add(boat.getVelocityObject()); group.getChildren().add(bp);
group.getChildren().add(bp.getTeamNameObject());
group.getChildren().add(bp.getVelocityObject());
boatPolygons.add(bp);
// drawBoat(boat.getLongitude(), boat.getLatitude(), boat.getColor(), boat.getShortName(), boat.getSpeedInKnots(), boat.getHeading()); // drawBoat(boat.getLongitude(), boat.getLatitude(), boat.getColor(), boat.getShortName(), boat.getSpeedInKnots(), boat.getHeading());
} }
} }
@@ -248,11 +312,11 @@ public class CanvasController {
Color color = Color.BLUE; Color color = Color.BLUE;
if (gateMark.getName().equals("Start")){ if (gateMark.getName().equals("Start")){
color = Color.RED; color = Color.GREEN;
} }
if (gateMark.getName().equals("Finish")){ if (gateMark.getName().equals("Finish")){
color = Color.GREEN; color = Color.RED;
} }
drawSingleMark(gateMark.getSingleMark1(), color); drawSingleMark(gateMark.getSingleMark1(), color);
@@ -282,14 +346,16 @@ public class CanvasController {
double minLonToMaxLon = scaleRaceExtremities(); double minLonToMaxLon = scaleRaceExtremities();
calculateReferencePointLocation(minLonToMaxLon); calculateReferencePointLocation(minLonToMaxLon);
givePointsXY(); givePointsXY();
findMetersToPixels();
} }
/** /**
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the marker with the leftmost * Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the marker with the leftmost
* marker, rightmost marker, southern most marker and northern most marker respectively. * marker, rightmost marker, southern most marker and northern most marker respectively.
*/ */
private void findMinMaxPoint() { private void findMinMaxPoint() {
ArrayList<Mark> sortedPoints = new ArrayList<>(); List<Mark> sortedPoints = new ArrayList<>();
for (Mark mark : raceViewController.getRace().getCourse()) for (Mark mark : raceViewController.getRace().getCourse())
{ {
if (mark.getMarkType() == MarkType.SINGLE_MARK) if (mark.getMarkType() == MarkType.SINGLE_MARK)
@@ -348,9 +414,6 @@ public class CanvasController {
} }
referencePoint.setX(referencePointX); referencePoint.setX(referencePointX);
referencePoint.setY(referencePointY); referencePoint.setY(referencePointY);
System.out.println("REF POINT = " + referencePoint.getName());
System.out.println(referencePointX);
System.out.println(referencePointY);
} }
/** /**
@@ -387,41 +450,44 @@ public class CanvasController {
* are scaled according to the distanceScaleFactor variable. * are scaled according to the distanceScaleFactor variable.
*/ */
private void givePointsXY() { private void givePointsXY() {
Pair<Integer, Integer> canvasLocation; Point2D canvasLocation;
ArrayList<Mark> allPoints = new ArrayList<>(raceViewController.getRace().getCourse()); List<Mark> allPoints = new ArrayList<>(raceViewController.getRace().getCourse());
for (Mark mark : allPoints) { for (Mark mark : allPoints) {
if (mark.getMarkType() != MarkType.SINGLE_MARK) { if (mark.getMarkType() != MarkType.SINGLE_MARK) {
GateMark gateMark = (GateMark) mark; GateMark gateMark = (GateMark) mark;
canvasLocation = findScaledXY(gateMark.getSingleMark1()); canvasLocation = findScaledXY(gateMark.getSingleMark1());
gateMark.getSingleMark1().setX(canvasLocation.getKey()); gateMark.getSingleMark1().setX((int) canvasLocation.getX());
gateMark.getSingleMark1().setY(canvasLocation.getValue()); gateMark.getSingleMark1().setY((int) canvasLocation.getY());
canvasLocation = findScaledXY(gateMark.getSingleMark2()); canvasLocation = findScaledXY(gateMark.getSingleMark2());
gateMark.getSingleMark2().setX(canvasLocation.getKey()); gateMark.getSingleMark2().setX((int) canvasLocation.getX());
gateMark.getSingleMark2().setY(canvasLocation.getValue()); gateMark.getSingleMark2().setY((int) canvasLocation.getY());
} }
if (mark.getMarkType() == MarkType.CLOSED_GATE) if (mark.getMarkType() == MarkType.CLOSED_GATE)
((GateMark) mark).assignXYCentered(); ((GateMark) mark).assignXYCentered();
else { else {
canvasLocation = findScaledXY(mark); canvasLocation = findScaledXY(mark);
mark.setX(canvasLocation.getKey()); mark.setX((int) canvasLocation.getX());
mark.setY(canvasLocation.getValue()); mark.setY((int) canvasLocation.getY());
} }
} }
} }
private Pair<Integer, Integer> findScaledXY (Mark unscaled) { private Point2D findScaledXY (Mark unscaled) {
return findScaledXY (minLatPoint.getLatitude(), minLatPoint.getLongitude(),
unscaled.getLatitude(), unscaled.getLongitude());
}
private Point2D findScaledXY (double latA, double lonA, double latB, double lonB) {
double distanceFromReference; double distanceFromReference;
double angleFromReference; double angleFromReference;
int yAxisLocation; int yAxisLocation;
int xAxisLocation; int xAxisLocation;
angleFromReference = Mark.calculateHeadingRad(minLatPoint, unscaled); angleFromReference = Mark.calculateHeadingRad(latA, lonA, latB, lonB);
distanceFromReference = Mark.calculateDistance(minLatPoint, unscaled); distanceFromReference = Mark.calculateDistance(latA, lonA, latB, lonB);
//angleFromReference = Mark.calculateHeadingRad(lon1, lon2, lat1, lat2);
//distanceFromReference = Mark.calculateDistance(lon1, lon2, lat1, lat2);
if (angleFromReference > (Math.PI / 2)) { if (angleFromReference > (Math.PI / 2)) {
angleFromReference = (Math.PI * 2) - angleFromReference; angleFromReference = (Math.PI * 2) - angleFromReference;
@@ -434,6 +500,40 @@ public class CanvasController {
yAxisLocation = referencePointY; yAxisLocation = referencePointY;
yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
return new Pair<>(xAxisLocation, yAxisLocation); return new Point2D(xAxisLocation, yAxisLocation);
}
/**
* Find the number of meters per pixel.
*/
private void findMetersToPixels () {
Double angularDistance;
Double angle;
Double straightLineDistance;
if (scaleDirection == ScaleDirection.HORIZONTAL) {
angularDistance = Mark.calculateDistance(minLonPoint, maxLonPoint);
angle = Mark.calculateHeadingRad(minLonPoint, maxLonPoint);
if (angle > Math.PI / 2) {
straightLineDistance = Math.cos(angle - Math.PI) * angularDistance;
} else {
straightLineDistance = Math.cos(angle) * angularDistance;
}
metersToPixels = (CANVAS_WIDTH - RHS_BUFFER - LHS_BUFFER) / straightLineDistance;
} else {
angularDistance = Mark.calculateDistance(minLatPoint, maxLatPoint);
angle = Mark.calculateHeadingRad(minLatPoint, maxLatPoint);
if (angle < Math.PI / 2) {
straightLineDistance = Math.cos(angle) * angularDistance;
} else {
straightLineDistance = Math.cos(-angle + Math.PI * 2) * angularDistance;
}
metersToPixels = (CANVAS_HEIGHT - TOP_BUFFER - BOT_BUFFER) / straightLineDistance;
}
}
private Point2D latLonToXY (double latitude, double longitude) {
return findScaledXY(minLatPoint.getLatitude(), minLatPoint.getLongitude(), latitude, longitude);
} }
} }
@@ -2,10 +2,7 @@ package seng302.controllers;
import javafx.animation.Animation; import javafx.animation.Animation;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@@ -65,15 +62,15 @@ public class RaceViewController {
// } // }
includedCanvasController.setup(this); includedCanvasController.setup(this);
includedCanvasController.setUpBoats(); includedCanvasController.initializeCanvas();
initializeTimer(); //initializeTimer();
initializeSettings(); initializeSettings();
//set wind direction!!!!!!! can't find another place to put my code --haoming //set wind direction!!!!!!! can't find another place to put my code --haoming
double windDirection = new ConfigParser("/config/config.xml").getWindDirection(); double windDirection = new ConfigParser("/config/config.xml").getWindDirection();
windDirectionText.setText(String.format("%.1f°", windDirection)); windDirectionText.setText(String.format("%.1f°", windDirection));
windArrowText.setRotate(windDirection); windArrowText.setRotate(windDirection);
includedCanvasController.timer.start();
} }
private void initializeSettings(){ private void initializeSettings(){
+19 -115
View File
@@ -5,42 +5,26 @@ import javafx.scene.shape.Polygon;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate; import javafx.scene.transform.Translate;
import javafx.util.Pair;
/** /**
* Represents a boat in the race. * Represents a boat in the race.
*/ */
public class Boat { public class Boat {
private static final double TEAMNAME_X_OFFSET = 15d; private String teamName;
private static final double TEAMNAME_Y_OFFSET = -20d; private double velocity;
private static final double VELOCITY_X_OFFSET = 15d; private double lat;
private static final double VELOCITY_Y_OFFSET = -10d; private double lon;
private static final double VELOCITY_WAKE_RATIO = 2d; //Ratio for deciding how long the wake will be wrt velocity
private static final double BOAT_HEIGHT = 15d;
private static final double BOAT_WIDTH = 10d;
private String teamName; // The name of the team, this is also the name of the boat
private double velocity; // In meters/second
private double lat; // Boats position
private double lon; // -
private double distanceToNextMark;
private Color color;
private int markLastPast;
private double heading; private double heading;
private int markLastPast;
private String shortName; private String shortName;
//Graphical
private Polygon boatObject;
private Polygon wake;
private Text teamNameObject;
private Text velocityObject;
public Boat(String teamName) { public Boat(String teamName) {
this.teamName = teamName; this.teamName = teamName;
this.velocity = 10; // Default velocity this.velocity = 10; // Default velocity
this.lat = 0.0; this.lat = 0.0;
this.lon = 0.0; this.lon = 0.0;
this.distanceToNextMark = 0.0;
this.shortName = ""; this.shortName = "";
} }
@@ -54,16 +38,7 @@ public class Boat {
public Boat(String teamName, double boatVelocity, String shortName) { public Boat(String teamName, double boatVelocity, String shortName) {
this.teamName = teamName; this.teamName = teamName;
this.velocity = boatVelocity; this.velocity = boatVelocity;
this.distanceToNextMark = 0.0;
this.color = Colors.getColor();
this.shortName = shortName; this.shortName = shortName;
this.boatObject = new Polygon();
this.boatObject.getPoints().addAll(BOAT_WIDTH /2,0.0,
BOAT_WIDTH, BOAT_HEIGHT,
0.0, BOAT_HEIGHT);
createWake();
this.teamNameObject = new Text(shortName);
this.velocityObject = new Text(Double.toString(boatVelocity) + "ms");
} }
/** /**
@@ -113,8 +88,9 @@ public class Boat {
this.lon = lon; this.lon = lon;
} }
public void setDistanceToNextMark(double distance){ public Pair<Double, Double> getLocation ()
this.distanceToNextMark = distance; {
return new Pair<>(this.lat, this.lon);
} }
public double getLatitude(){ public double getLatitude(){
@@ -125,8 +101,12 @@ public class Boat {
return this.lon; return this.lon;
} }
public Color getColor() { public void setLatitude (double latitude) {
return color; this.lat = latitude;
}
public void setlongitude (double longitude) {
this.lon =longitude;
} }
public double getSpeedInKnots(){ public double getSpeedInKnots(){
@@ -141,92 +121,16 @@ public class Boat {
return markLastPast; return markLastPast;
} }
public void setHeading(double heading){
boatObject.getTransforms().clear();
wake.getTransforms().clear();
wake.getTransforms().add(new Translate(0, BOAT_HEIGHT));
wake.getTransforms().add(new Rotate(heading, BOAT_WIDTH/2, -BOAT_HEIGHT));
boatObject.getTransforms().add(new Rotate(heading, BOAT_WIDTH/2, 0));
this.heading = heading;
}
public double getHeading(){ public double getHeading(){
return this.heading; return this.heading;
} }
public void setHeading(double heading) {
this.heading = heading;
}
public String getShortName(){ public String getShortName(){
return this.shortName; return this.shortName;
} }
/**
* Moves the boat and its children annotations from its current coordinates by specified amounts.
* @param x The amount to move the X coordinate by
* @param y The amount to move the Y coordinate by
*/
void moveBoatBy(Double x, Double y) {
boatObject.setLayoutX(boatObject.getLayoutX() + x);
boatObject.setLayoutY(boatObject.getLayoutY() + y);
boatObject.relocate(boatObject.getLayoutX(), boatObject.getLayoutY());
teamNameObject.setX(teamNameObject.getX() + x);
teamNameObject.setY(teamNameObject.getY() + y);
teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY());
velocityObject.setX(velocityObject.getX() + x);
velocityObject.setY(velocityObject.getY() + y);
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
wake.setLayoutX(wake.getLayoutX() + x);
wake.setLayoutY(wake.getLayoutY() + y);
wake.relocate(wake.getLayoutX(), wake.getLayoutY());
}
/**
* Moves the boat and its children annotations to coordinates specified
* @param x The X coordinate to move the boat to
* @param y The Y coordinate to move the boat to
*/
public void moveBoatTo(Double x, Double y) {
boatObject.setLayoutX(x);
boatObject.setLayoutY(y);
boatObject.relocate(boatObject.getLayoutX(), boatObject.getLayoutY());
teamNameObject.setX(x + TEAMNAME_X_OFFSET);
teamNameObject.setY(y + TEAMNAME_Y_OFFSET);
teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY());
velocityObject.setX(x + VELOCITY_X_OFFSET);
velocityObject.setY(y + VELOCITY_Y_OFFSET);
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
wake.setLayoutX(x);
wake.setLayoutY(y);
wake.relocate(wake.getLayoutX(), wake.getLayoutY());
}
private void createWake(){
wake = new Polygon();
wake.setFill(Color.LIGHTSKYBLUE);
wake.getPoints().addAll(5.0,0.0,
10.0, velocity * VELOCITY_WAKE_RATIO,
0.0, velocity * VELOCITY_WAKE_RATIO);
}
public Polygon getWake() {
return wake;
}
public Polygon getBoatObject() {
return boatObject;
}
public Text getTeamNameObject() {
return teamNameObject;
}
public Text getVelocityObject() {
return velocityObject;
}
} }
@@ -0,0 +1,171 @@
package seng302.models;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
/**
* Created by cir27 on 24/04/17.
*/
public class BoatPolygon extends Polygon {
private static final double TEAMNAME_X_OFFSET = 15d;
private static final double TEAMNAME_Y_OFFSET = -20d;
private static final double VELOCITY_X_OFFSET = 15d;
private static final double VELOCITY_Y_OFFSET = -10d;
private static final double VELOCITY_WAKE_RATIO = 2d;
private static final double BOAT_HEIGHT = 15d;
private static final double BOAT_WIDTH = 10d;
//Time between sections of race - Should be changed to 200 for actual program.
private static double expectedUpdateInterval = 5000;
private Boat boat;
private Polygon wake;
private Text teamNameObject;
private Text velocityObject;
private double rotation;
private double pixelVelocityX;
private double pixelVelocityY;
//private double destinationX;
//private double destinationY;
public BoatPolygon (Boat boat, Color color){
super();
super.setFill(color);
super.getPoints().addAll(
BOAT_WIDTH / 2, 0.0,
BOAT_WIDTH , BOAT_HEIGHT,
0.0 , BOAT_HEIGHT
);
this.boat = boat;
initAnnotations();
}
public BoatPolygon (Boat boat, Color color, double... points)
{
super(points);
super.setFill(color);
this.boat = boat;
initAnnotations();
}
private void initAnnotations ()
{
wake = new Polygon();
wake.setFill(Color.DARKBLUE);
wake.getPoints().addAll(
5.0,0.0,
10.0, boat.getVelocity() * VELOCITY_WAKE_RATIO,
0.0, boat.getVelocity() * VELOCITY_WAKE_RATIO
);
teamNameObject = new Text(boat.getShortName());
velocityObject = new Text(String.valueOf(boat.getVelocity()));
}
/**
* Moves the boat and its children annotations from its current coordinates by specified amounts.
* @param dx The amount to move the X coordinate by
* @param dy The amount to move the Y coordinate by
*/
void moveBy(Double dx, Double dy) {
super.setLayoutX(super.getLayoutX() + dx);
super.setLayoutY(super.getLayoutY() + dy);
super.relocate(super.getLayoutX(), super.getLayoutY());
teamNameObject.setX(teamNameObject.getX() + dx);
teamNameObject.setY(teamNameObject.getY() + dy);
teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY());
velocityObject.setX(velocityObject.getX() + dx);
velocityObject.setY(velocityObject.getY() + dy);
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
wake.setLayoutX(wake.getLayoutX() + dx);
wake.setLayoutY(wake.getLayoutY() + dy);
wake.relocate(wake.getLayoutX(), wake.getLayoutY());
}
/**
* Moves the boat and its children annotations to coordinates specified
* @param x The X coordinate to move the boat to
* @param y The Y coordinate to move the boat to
*/
public void moveBoatTo(Double x, Double y) {
super.setLayoutX(x);
super.setLayoutY(y);
super.relocate(super.getLayoutX(), super.getLayoutY());
teamNameObject.setX(x + TEAMNAME_X_OFFSET);
teamNameObject.setY(y + TEAMNAME_Y_OFFSET);
teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY());
velocityObject.setX(x + VELOCITY_X_OFFSET);
velocityObject.setY(y + VELOCITY_Y_OFFSET);
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
wake.setLayoutX(x);
wake.setLayoutY(y);
wake.relocate(wake.getLayoutX(), wake.getLayoutY());
}
public void updatePosition (double timeInterval) {
double dx = pixelVelocityX * timeInterval;
double dy = pixelVelocityY * timeInterval;
moveBy(dx, dy);
}
public void setDestination (double newXValue, double newYValue) {
this.pixelVelocityX = (newXValue - super.getLayoutX()) / expectedUpdateInterval;
this.pixelVelocityY = (newYValue - super.getLayoutY()) / expectedUpdateInterval;
//this.destinationX = newXValue;
//this.destinationY = newYValue;
this.rotation = Math.abs(
Math.toDegrees(
Math.atan(
(newYValue - super.getLayoutY()) / (newXValue - super.getLayoutX())
)
)
);
if (super.getLayoutY() >= newYValue && super.getLayoutX() <= newXValue)
rotation = 90 - rotation;
else if (super.getLayoutY() < newYValue && super.getLayoutX() <= newXValue)
rotation = 90 + rotation;
else if (super.getLayoutY() >= newYValue && super.getLayoutX() > newXValue)
rotation = 270 + rotation;
else
rotation = 270 - rotation;
rotateBoat ();
}
private void rotateBoat () {
super.getTransforms().clear();
super.getTransforms().add(new Rotate(rotation, BOAT_WIDTH/2, 0));
wake.getTransforms().clear();
wake.getTransforms().add(new Translate(0, BOAT_HEIGHT));
wake.getTransforms().add(new Rotate(rotation, BOAT_WIDTH/2, -BOAT_HEIGHT));
}
public static double getExpectedUpdateInterval() {
return expectedUpdateInterval;
}
public static void setExpectedUpdateInterval(double expectedUpdateInterval) {
BoatPolygon.expectedUpdateInterval = expectedUpdateInterval;
}
public Polygon getWake() {
return wake;
}
public Text getTeamNameObject() {
return teamNameObject;
}
public Text getVelocityObject() {
return velocityObject;
}
}
+3 -4
View File
@@ -11,10 +11,9 @@ public enum Colors {
static Integer index = 0; static Integer index = 0;
public static Color getColor() { public static Color getColor() {
index++; if (index == 6) {
if (index > 6) { index = 0;
index = 1;
} }
return Color.valueOf(values()[index-1].toString()); return Color.valueOf(values()[index++].toString());
} }
} }
+1
View File
@@ -9,6 +9,7 @@ import java.util.*;
* Created by mra106 on 8/3/2017. * Created by mra106 on 8/3/2017.
*/ */
public class Race { public class Race {
private ArrayList<Boat> boats; // The boats in the race private ArrayList<Boat> boats; // The boats in the race
private ArrayList<Boat> finishingOrder; // The order in which the boats finish the race private ArrayList<Boat> finishingOrder; // The order in which the boats finish the race
private HashMap<Boat, List> events = new HashMap<>(); // The events that occur in the race private HashMap<Boat, List> events = new HashMap<>(); // The events that occur in the race
+4 -4
View File
@@ -42,7 +42,7 @@ public abstract class Mark {
Double longitude2 = pointTwo.getLongitude(); Double longitude2 = pointTwo.getLongitude();
Double latitude1 = pointOne.getLatitude(); Double latitude1 = pointOne.getLatitude();
Double latitude2 = pointTwo.getLatitude(); Double latitude2 = pointTwo.getLatitude();
return calculateHeadingRad(longitude1, longitude2, latitude1, latitude2); return calculateHeadingRad(latitude1, longitude1, latitude2, longitude2);
} }
/** /**
@@ -54,7 +54,7 @@ public abstract class Mark {
* @param latitude2 Latitude of first point in degrees * @param latitude2 Latitude of first point in degrees
* @return Heading in radians * @return Heading in radians
*/ */
public static double calculateHeadingRad (Double longitude1, Double longitude2, Double latitude1, Double latitude2) { public static double calculateHeadingRad (Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
latitude1 = Math.toRadians(latitude1); latitude1 = Math.toRadians(latitude1);
latitude2 = Math.toRadians(latitude2); latitude2 = Math.toRadians(latitude2);
Double longDiff= Math.toRadians(longitude2-longitude1); Double longDiff= Math.toRadians(longitude2-longitude1);
@@ -75,7 +75,7 @@ public abstract class Mark {
Double longitude2 = pointTwo.getLongitude(); Double longitude2 = pointTwo.getLongitude();
Double latitude1 = pointOne.getLatitude(); Double latitude1 = pointOne.getLatitude();
Double latitude2 = pointTwo.getLatitude(); Double latitude2 = pointTwo.getLatitude();
return calculateDistance(longitude1, longitude2, latitude1, latitude2); return calculateDistance(latitude1, longitude1, latitude2, longitude2);
} }
/** /**
@@ -88,7 +88,7 @@ public abstract class Mark {
* @param latitude2 Latitude of first point in degrees * @param latitude2 Latitude of first point in degrees
* @return Distance in meters * @return Distance in meters
*/ */
public static Double calculateDistance (Double longitude1, Double longitude2, Double latitude1, Double latitude2) { public static Double calculateDistance (Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
Double theta = longitude1 - longitude2; Double theta = longitude1 - longitude2;
Double dist = Math.sin(Math.toRadians(latitude1)) * Math.sin(Math.toRadians(latitude2)) + Double dist = Math.sin(Math.toRadians(latitude1)) * Math.sin(Math.toRadians(latitude2)) +
Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(latitude2)) * Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(latitude2)) *
+10 -24
View File
@@ -1,8 +1,11 @@
package seng302; package seng302;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import seng302.models.Boat; import seng302.models.Boat;
import seng302.models.BoatPolygon;
import seng302.models.Colors; import seng302.models.Colors;
import java.util.ArrayList; import java.util.ArrayList;
@@ -16,30 +19,13 @@ import static org.junit.Assert.assertEquals;
* Created by ryan_ on 16/03/2017. * Created by ryan_ on 16/03/2017.
*/ */
public class ColorsTest { public class ColorsTest {
//@Test
@Test
public void testNextColor() { public void testNextColor() {
List<Boat> boats = new ArrayList<>(); Color expectedColors[] = {Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.PURPLE};
boats.add(new Boat("Team 1")); for (int i = 0; i<6; i++)
boats.add(new Boat("Team 2")); {
boats.add(new Boat("Team 3")); Assert.assertEquals(expectedColors[i], Colors.getColor());
boats.add(new Boat("Team 4")); }
boats.add(new Boat("Team 5"));
boats.add(new Boat("Team 6"));
int count = 0;
List<Color> enumColors = new ArrayList<>();
while (count < 6) {
Color color = Colors.getColor();
enumColors.add(color);
count++;
}
List<Color> boatColors = new ArrayList<>();
for (Boat boat : boats) {
Color color = boat.getColor();
boatColors.add(color);
}
assertEquals(enumColors, boatColors);
} }
} }