From 46037b5aea3b308bfa7a2854fbd22e9cb17207bb Mon Sep 17 00:00:00 2001 From: Calum Date: Mon, 24 Apr 2017 23:06:30 +1200 Subject: [PATCH] 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 --- .../seng302/controllers/CanvasController.java | 264 ++++++++++++------ .../controllers/RaceViewController.java | 9 +- src/main/java/seng302/models/Boat.java | 134 ++------- src/main/java/seng302/models/BoatPolygon.java | 171 ++++++++++++ src/main/java/seng302/models/Colors.java | 7 +- src/main/java/seng302/models/Race.java | 1 + src/main/java/seng302/models/mark/Mark.java | 8 +- src/test/java/seng302/ColorsTest.java | 32 +-- 8 files changed, 392 insertions(+), 234 deletions(-) create mode 100644 src/main/java/seng302/models/BoatPolygon.java diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 0499eb05..03db02f1 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -3,6 +3,7 @@ package seng302.controllers; import javafx.animation.*; import javafx.beans.property.SimpleDoubleProperty; import javafx.fxml.FXML; +import javafx.geometry.Point2D; import javafx.scene.Group; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; @@ -11,6 +12,8 @@ import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.util.Pair; import seng302.models.Boat; +import seng302.models.BoatPolygon; +import seng302.models.Colors; import seng302.models.mark.GateMark; import seng302.models.mark.Mark; import seng302.models.mark.MarkType; @@ -32,14 +35,17 @@ public class CanvasController { private ResizableCanvas canvas; private Group group; private GraphicsContext gc; + private List boatPolygons = new ArrayList<>(); - private final int MARK_SIZE = 10; - private final int BUFFER_SIZE = 25; - private final int CANVAS_SIZE = 1000; - private final int LHS_BUFFER = BUFFER_SIZE; - private final int RHS_BUFFER = BUFFER_SIZE + MARK_SIZE / 2; - private final int TOP_BUFFER = BUFFER_SIZE; - private final int BOT_BUFFER = TOP_BUFFER + MARK_SIZE / 2; + private final int MARK_SIZE = 10; + private final int BUFFER_SIZE = 25; + private final int CANVAS_WIDTH = 1000; + private final int CANVAS_HEIGHT = 1000; + private final int LHS_BUFFER = BUFFER_SIZE; + private final int RHS_BUFFER = BUFFER_SIZE + MARK_SIZE / 2; + private final int TOP_BUFFER = BUFFER_SIZE; + private final int BOT_BUFFER = TOP_BUFFER + MARK_SIZE / 2; + private final int FRAME_RATE = 60; private double distanceScaleFactor; private ScaleDirection scaleDirection; @@ -49,6 +55,9 @@ public class CanvasController { private Mark maxLonPoint; private int referencePointX; private int referencePointY; + private double metersToPixels; + + public AnimationTimer timer; private enum ScaleDirection { HORIZONTAL, @@ -67,70 +76,119 @@ public class CanvasController { canvasPane.getChildren().add(canvas); canvasPane.getChildren().add(group); // Bind canvas size to stack pane size. - canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_SIZE)); - canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_SIZE)); - group.minWidth(CANVAS_SIZE); - group.minHeight(CANVAS_SIZE); -// canvas.widthProperty().bind(canvasPane.widthProperty()); -// canvas.heightProperty().bind(canvasPane.heightProperty()); -// group.minWidth(canvas.getWidth()); -// group.minHeight(canvas.getHeight()); - - + canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH)); + canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT)); + group.minWidth(CANVAS_WIDTH); + group.minHeight(CANVAS_HEIGHT); } - - public void setUpBoats(){ + public void initializeCanvas (){ gc = canvas.getGraphicsContext2D(); gc.save(); gc.setFill(Color.SKYBLUE); - gc.fillRect(0,0, CANVAS_SIZE,CANVAS_SIZE); + gc.fillRect(0,0, CANVAS_WIDTH, CANVAS_HEIGHT); gc.restore(); 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(); - drawFps(12); - // overriding the handle so that it can clean canvas and redraw boats and course marks - AnimationTimer timer = new AnimationTimer() { - private long lastUpdate = 0; - private long lastFpsUpdate = 0; - private int lastFpsCount = 0; - private int fpsCount = 0; - boolean done = true; +// drawFps(12); +// // overriding the handle so that it can clean canvas and redraw boats and course marks +// AnimationTimer timer = new AnimationTimer() { +// private long lastUpdate = 0; +// private long lastFpsUpdate = 0; +// private int lastFpsCount = 0; +// private int fpsCount = 0; +// 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 marks = raceViewController.getRace().getCourse(); @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(); + boolean raceFinished = true; + boolean descending; + int boatIndex = 0; + Mark nextMark; + if (countdown == 0) { + for (BoatPolygon bp : boatPolygons) { + if (currentRaceMarker[boatIndex] < marks.size()) { + if (currentRaceMarker[boatIndex] == 6) { + int debugLine = 4; + } + double xb4 = bp.getLayoutX(); + double yb4 = bp.getLayoutY(); + 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() + ); + } + double xnew = bp.getLayoutX(); + double ynew = bp.getLayoutY(); + double dx = xnew - xb4; + double dy = ynew -yb4; + raceFinished = false; + boatIndex++; + } } - // Race has not started, pause the timelines - else { - raceViewController.pauseTimelines(); - } - lastUpdate = now; - fpsCount ++; - if (now - lastFpsUpdate >= 1000000000){ - lastFpsCount = fpsCount; - fpsCount = 0; - lastFpsUpdate = now; + 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 { @@ -179,16 +237,22 @@ public class CanvasController { */ private void drawBoats() { // Map timelineInfos = raceViewController.getTimelineInfos(); - ArrayList boats = raceViewController.getStartingBoats(); - Double startingX = (double) raceViewController.getRace().getCourse().get(0).getX(); - Double startingY = (double) raceViewController.getRace().getCourse().get(0).getY(); + List boats = raceViewController.getStartingBoats(); + List marks = raceViewController.getRace().getCourse(); + 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) { - boat.moveBoatTo(startingX, startingY); - group.getChildren().add(boat.getWake()); - group.getChildren().add(boat.getBoatObject()); - group.getChildren().add(boat.getTeamNameObject()); - group.getChildren().add(boat.getVelocityObject()); + BoatPolygon bp = new BoatPolygon(boat, Colors.getColor()); + bp.moveBoatTo(startingX, startingY); + bp.setDestination(firstMarkX, firstMarkY); + group.getChildren().add(bp.getWake()); + 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()); } } @@ -248,11 +312,11 @@ public class CanvasController { Color color = Color.BLUE; if (gateMark.getName().equals("Start")){ - color = Color.RED; + color = Color.GREEN; } if (gateMark.getName().equals("Finish")){ - color = Color.GREEN; + color = Color.RED; } drawSingleMark(gateMark.getSingleMark1(), color); @@ -282,14 +346,16 @@ public class CanvasController { double minLonToMaxLon = scaleRaceExtremities(); calculateReferencePointLocation(minLonToMaxLon); givePointsXY(); + findMetersToPixels(); } + /** * 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. */ private void findMinMaxPoint() { - ArrayList sortedPoints = new ArrayList<>(); + List sortedPoints = new ArrayList<>(); for (Mark mark : raceViewController.getRace().getCourse()) { if (mark.getMarkType() == MarkType.SINGLE_MARK) @@ -348,9 +414,6 @@ public class CanvasController { } referencePoint.setX(referencePointX); 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. */ private void givePointsXY() { - Pair canvasLocation; - ArrayList allPoints = new ArrayList<>(raceViewController.getRace().getCourse()); + Point2D canvasLocation; + List allPoints = new ArrayList<>(raceViewController.getRace().getCourse()); for (Mark mark : allPoints) { if (mark.getMarkType() != MarkType.SINGLE_MARK) { GateMark gateMark = (GateMark) mark; canvasLocation = findScaledXY(gateMark.getSingleMark1()); - gateMark.getSingleMark1().setX(canvasLocation.getKey()); - gateMark.getSingleMark1().setY(canvasLocation.getValue()); + gateMark.getSingleMark1().setX((int) canvasLocation.getX()); + gateMark.getSingleMark1().setY((int) canvasLocation.getY()); canvasLocation = findScaledXY(gateMark.getSingleMark2()); - gateMark.getSingleMark2().setX(canvasLocation.getKey()); - gateMark.getSingleMark2().setY(canvasLocation.getValue()); + gateMark.getSingleMark2().setX((int) canvasLocation.getX()); + gateMark.getSingleMark2().setY((int) canvasLocation.getY()); } if (mark.getMarkType() == MarkType.CLOSED_GATE) ((GateMark) mark).assignXYCentered(); else { canvasLocation = findScaledXY(mark); - mark.setX(canvasLocation.getKey()); - mark.setY(canvasLocation.getValue()); + mark.setX((int) canvasLocation.getX()); + mark.setY((int) canvasLocation.getY()); } } } - private Pair 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 angleFromReference; int yAxisLocation; int xAxisLocation; - angleFromReference = Mark.calculateHeadingRad(minLatPoint, unscaled); - distanceFromReference = Mark.calculateDistance(minLatPoint, unscaled); - //angleFromReference = Mark.calculateHeadingRad(lon1, lon2, lat1, lat2); - //distanceFromReference = Mark.calculateDistance(lon1, lon2, lat1, lat2); + angleFromReference = Mark.calculateHeadingRad(latA, lonA, latB, lonB); + distanceFromReference = Mark.calculateDistance(latA, lonA, latB, lonB); if (angleFromReference > (Math.PI / 2)) { angleFromReference = (Math.PI * 2) - angleFromReference; @@ -434,6 +500,40 @@ public class CanvasController { yAxisLocation = referencePointY; 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); } } \ No newline at end of file diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 83352357..8acfba2b 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -2,10 +2,7 @@ package seng302.controllers; import javafx.animation.Animation; import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; import javafx.animation.Timeline; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; @@ -65,15 +62,15 @@ public class RaceViewController { // } includedCanvasController.setup(this); - includedCanvasController.setUpBoats(); - initializeTimer(); + includedCanvasController.initializeCanvas(); + //initializeTimer(); initializeSettings(); //set wind direction!!!!!!! can't find another place to put my code --haoming double windDirection = new ConfigParser("/config/config.xml").getWindDirection(); windDirectionText.setText(String.format("%.1f°", windDirection)); windArrowText.setRotate(windDirection); - + includedCanvasController.timer.start(); } private void initializeSettings(){ diff --git a/src/main/java/seng302/models/Boat.java b/src/main/java/seng302/models/Boat.java index f39f9e3b..004ddc57 100644 --- a/src/main/java/seng302/models/Boat.java +++ b/src/main/java/seng302/models/Boat.java @@ -5,42 +5,26 @@ import javafx.scene.shape.Polygon; import javafx.scene.text.Text; import javafx.scene.transform.Rotate; import javafx.scene.transform.Translate; +import javafx.util.Pair; /** * Represents a boat in the race. */ public class Boat { - 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; //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 String teamName; + private double velocity; + private double lat; + private double lon; private double heading; + private int markLastPast; private String shortName; - //Graphical - private Polygon boatObject; - private Polygon wake; - private Text teamNameObject; - private Text velocityObject; - public Boat(String teamName) { this.teamName = teamName; this.velocity = 10; // Default velocity this.lat = 0.0; this.lon = 0.0; - this.distanceToNextMark = 0.0; this.shortName = ""; } @@ -54,16 +38,7 @@ public class Boat { public Boat(String teamName, double boatVelocity, String shortName) { this.teamName = teamName; this.velocity = boatVelocity; - this.distanceToNextMark = 0.0; - this.color = Colors.getColor(); 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; } - public void setDistanceToNextMark(double distance){ - this.distanceToNextMark = distance; + public Pair getLocation () + { + return new Pair<>(this.lat, this.lon); } public double getLatitude(){ @@ -125,8 +101,12 @@ public class Boat { return this.lon; } - public Color getColor() { - return color; + public void setLatitude (double latitude) { + this.lat = latitude; + } + + public void setlongitude (double longitude) { + this.lon =longitude; } public double getSpeedInKnots(){ @@ -141,92 +121,16 @@ public class Boat { 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(){ return this.heading; } + public void setHeading(double heading) { + this.heading = heading; + } + public String getShortName(){ 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; - } } \ No newline at end of file diff --git a/src/main/java/seng302/models/BoatPolygon.java b/src/main/java/seng302/models/BoatPolygon.java new file mode 100644 index 00000000..f2e8ea43 --- /dev/null +++ b/src/main/java/seng302/models/BoatPolygon.java @@ -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; + } + +} diff --git a/src/main/java/seng302/models/Colors.java b/src/main/java/seng302/models/Colors.java index 419753dc..23ef8f4e 100644 --- a/src/main/java/seng302/models/Colors.java +++ b/src/main/java/seng302/models/Colors.java @@ -11,10 +11,9 @@ public enum Colors { static Integer index = 0; public static Color getColor() { - index++; - if (index > 6) { - index = 1; + if (index == 6) { + index = 0; } - return Color.valueOf(values()[index-1].toString()); + return Color.valueOf(values()[index++].toString()); } } diff --git a/src/main/java/seng302/models/Race.java b/src/main/java/seng302/models/Race.java index 165d9468..01d1adf8 100644 --- a/src/main/java/seng302/models/Race.java +++ b/src/main/java/seng302/models/Race.java @@ -9,6 +9,7 @@ import java.util.*; * Created by mra106 on 8/3/2017. */ public class Race { + private ArrayList boats; // The boats in the race private ArrayList finishingOrder; // The order in which the boats finish the race private HashMap events = new HashMap<>(); // The events that occur in the race diff --git a/src/main/java/seng302/models/mark/Mark.java b/src/main/java/seng302/models/mark/Mark.java index 44e9877b..98af4057 100644 --- a/src/main/java/seng302/models/mark/Mark.java +++ b/src/main/java/seng302/models/mark/Mark.java @@ -42,7 +42,7 @@ public abstract class Mark { Double longitude2 = pointTwo.getLongitude(); Double latitude1 = pointOne.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 * @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); latitude2 = Math.toRadians(latitude2); Double longDiff= Math.toRadians(longitude2-longitude1); @@ -75,7 +75,7 @@ public abstract class Mark { Double longitude2 = pointTwo.getLongitude(); Double latitude1 = pointOne.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 * @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 dist = Math.sin(Math.toRadians(latitude1)) * Math.sin(Math.toRadians(latitude2)) + Math.cos(Math.toRadians(latitude1)) * Math.cos(Math.toRadians(latitude2)) * diff --git a/src/test/java/seng302/ColorsTest.java b/src/test/java/seng302/ColorsTest.java index a6681b26..84fc01dd 100644 --- a/src/test/java/seng302/ColorsTest.java +++ b/src/test/java/seng302/ColorsTest.java @@ -1,8 +1,11 @@ package seng302; import javafx.scene.paint.Color; +import javafx.scene.paint.Paint; +import org.junit.Assert; import org.junit.Test; import seng302.models.Boat; +import seng302.models.BoatPolygon; import seng302.models.Colors; import java.util.ArrayList; @@ -16,30 +19,13 @@ import static org.junit.Assert.assertEquals; * Created by ryan_ on 16/03/2017. */ public class ColorsTest { - //@Test + + @Test public void testNextColor() { - List boats = new ArrayList<>(); - boats.add(new Boat("Team 1")); - boats.add(new Boat("Team 2")); - boats.add(new Boat("Team 3")); - boats.add(new Boat("Team 4")); - boats.add(new Boat("Team 5")); - boats.add(new Boat("Team 6")); - - int count = 0; - List enumColors = new ArrayList<>(); - while (count < 6) { - Color color = Colors.getColor(); - enumColors.add(color); - count++; + Color expectedColors[] = {Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.PURPLE}; + for (int i = 0; i<6; i++) + { + Assert.assertEquals(expectedColors[i], Colors.getColor()); } - - List boatColors = new ArrayList<>(); - for (Boat boat : boats) { - Color color = boat.getColor(); - boatColors.add(color); - } - - assertEquals(enumColors, boatColors); } }