From 34872a822b30c0fb1a7853a89bff3e9c96fc580c Mon Sep 17 00:00:00 2001 From: William Muir Date: Sat, 8 Apr 2017 17:49:50 +1200 Subject: [PATCH] Stripped back codebase to make to create basic model for streaming data Removed many classes involved with visualisation such as controllers and multiple fxmls. Now there is just one for debugging Merged in Boat updating pattern from team 27 #story[828] --- .../seng302/controllers/CanvasController.java | 283 ------------------ .../java/seng302/controllers/Controller.java | 180 +++++++++-- .../seng302/controllers/RaceController.java | 80 ----- .../controllers/RaceResultController.java | 37 --- .../controllers/RaceViewController.java | 280 ----------------- src/main/java/seng302/models/Boat.java | 74 ++++- src/main/java/seng302/models/Course.java | 54 ++++ src/main/java/seng302/models/Event.java | 148 --------- src/main/java/seng302/models/Leg.java | 165 +++++----- src/main/java/seng302/models/Race.java | 219 ++++++++------ .../java/seng302/models/TimelineInfo.java | 31 -- src/main/resources/config/course.xml | 4 +- src/main/resources/views/CanvasView.fxml | 7 - src/main/resources/views/FinishView.fxml | 55 ---- src/main/resources/views/MainView.fxml | 48 ++- src/main/resources/views/RaceView.fxml | 59 ---- src/test/java/seng302/BoatTest.java | 35 --- src/test/java/seng302/ColorsTest.java | 45 --- src/test/java/seng302/EventTest.java | 38 --- src/test/java/seng302/LegTest.java | 54 ---- src/test/java/seng302/RaceTest.java | 41 --- src/test/java/seng302/TestRaceTimer.java | 25 -- .../java/seng302/models/mark/MarkTest.java | 44 --- .../models/parsers/ConfigParserTest.java | 42 --- .../models/parsers/CourseParserTest.java | 60 ---- .../models/parsers/TeamsParserTest.java | 35 --- 26 files changed, 518 insertions(+), 1625 deletions(-) delete mode 100644 src/main/java/seng302/controllers/CanvasController.java delete mode 100644 src/main/java/seng302/controllers/RaceController.java delete mode 100644 src/main/java/seng302/controllers/RaceResultController.java delete mode 100644 src/main/java/seng302/controllers/RaceViewController.java create mode 100644 src/main/java/seng302/models/Course.java delete mode 100644 src/main/java/seng302/models/Event.java delete mode 100644 src/main/java/seng302/models/TimelineInfo.java delete mode 100644 src/main/resources/views/CanvasView.fxml delete mode 100644 src/main/resources/views/FinishView.fxml delete mode 100644 src/main/resources/views/RaceView.fxml delete mode 100644 src/test/java/seng302/BoatTest.java delete mode 100644 src/test/java/seng302/ColorsTest.java delete mode 100644 src/test/java/seng302/EventTest.java delete mode 100644 src/test/java/seng302/LegTest.java delete mode 100644 src/test/java/seng302/RaceTest.java delete mode 100644 src/test/java/seng302/TestRaceTimer.java delete mode 100644 src/test/java/seng302/models/mark/MarkTest.java delete mode 100644 src/test/java/seng302/models/parsers/ConfigParserTest.java delete mode 100644 src/test/java/seng302/models/parsers/CourseParserTest.java delete mode 100644 src/test/java/seng302/models/parsers/TeamsParserTest.java diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java deleted file mode 100644 index c0b20e26..00000000 --- a/src/main/java/seng302/controllers/CanvasController.java +++ /dev/null @@ -1,283 +0,0 @@ -package seng302.controllers; - -import javafx.animation.*; -import javafx.fxml.FXML; -import javafx.scene.canvas.Canvas; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.layout.AnchorPane; -import javafx.scene.paint.Color; -import javafx.scene.text.Font; -import seng302.models.Boat; -import seng302.models.TimelineInfo; -import seng302.models.mark.GateMark; -import seng302.models.mark.Mark; -import seng302.models.mark.MarkType; -import seng302.models.mark.SingleMark; - -import java.util.*; - -/** - * Created by ptg19 on 15/03/17. - * Modified by Haoming Yin (hyi25) on 20/3/2017. - */ -public class CanvasController { - - @FXML - private AnchorPane canvasPane; - - private RaceViewController raceViewController; - private ResizableCanvas canvas; - private GraphicsContext gc; - - private final double ORIGIN_LAT = 32.321504; - private final double ORIGIN_LON = -64.857063; - private final int SCALE = 16000; - - public void setup(RaceViewController raceViewController){ - this.raceViewController = raceViewController; - } - - public void initialize() { - canvas = new ResizableCanvas(); - canvasPane.getChildren().add(canvas); - // Bind canvas size to stack pane size. - canvas.widthProperty().bind(canvasPane.widthProperty()); - canvas.heightProperty().bind(canvasPane.heightProperty()); - gc = canvas.getGraphicsContext2D(); - - - // 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; - - @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()); - drawCourse(); - drawBoats(); - drawFps(lastFpsCount); - - // 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(); - } - - class ResizableCanvas extends Canvas { - - public ResizableCanvas() { - // Redraw canvas when size changes. - widthProperty().addListener(evt -> draw()); - heightProperty().addListener(evt -> draw()); - } - - private void draw() { - double width = getWidth(); - double height = getHeight(); - - GraphicsContext gc = getGraphicsContext2D(); - gc.clearRect(0, 0, width, height); - } - - @Override - public boolean isResizable() { - return true; - } - - @Override - public double prefWidth(double height) { - return getWidth(); - } - - @Override - public double prefHeight(double width) { - return getHeight(); - } - } - - private void drawFps(int fps){ - if (raceViewController.isDisplayFps()){ - gc.setFill(Color.BLACK); - gc.setFont(new Font(14)); - gc.setLineWidth(3); - gc.fillText(fps + " FPS", 5, 20); - } - } - - /** - * Draws all the boats. - */ - private void drawBoats() { - Map timelineInfos = raceViewController.getTimelineInfos(); - for (Boat boat : timelineInfos.keySet()) { - TimelineInfo timelineInfo = timelineInfos.get(boat); - - boat.setLocation(timelineInfo.getY().doubleValue(), timelineInfo.getX().doubleValue()); - - drawBoat(boat.getLongitude(), boat.getLatitude(), boat.getColor(), boat.getShortName(), boat.getSpeedInKnots(), boat.getHeading()); - } - } - - /** - * Draw the wake line behind a boat - * @param gc The graphics context used for drawing the wake - * @param x the x position of the boat - * @param y the y position of the boat - * @param speed the speed of the boat - * @param color the color of the wake line - * @param heading the heading of the boat - */ - private void drawWake(GraphicsContext gc, double x, double y, double speed, Color color, double heading){ - double angle = Math.toRadians(heading); - speed = speed * 2; - Point newP = new Point(0, speed); - newP.rotate(angle); - - gc.setStroke(color); - gc.setLineWidth(1.0); - gc.strokeLine(x, y, newP.x + x, newP.y + y); - } - - /** - * Draws a boat with given (x, y) position in the given color - * - * @param lat - * @param lon - * @param color - * @param name - * @param speed - */ - private void drawBoat(double lat, double lon, Color color, String name, double speed, double heading) { - // Latitude - double x = (lon - ORIGIN_LON) * SCALE; - double y = (ORIGIN_LAT - lat) * SCALE; - - gc.setFill(color); - - if (raceViewController.isDisplayAnnotations()) { - // Set boat text - gc.setFont(new Font(14)); - gc.setLineWidth(3); - gc.fillText(name + ", " + speed + " knots", x + 15, y + 15); - } -// double diameter = 9; -// gc.fillOval(x, y, diameter, diameter); - double angle = Math.toRadians(heading); - - Point p1 = new Point(0, -15); // apex point - Point p2 = new Point(7, 4); // base point - Point p3 = new Point(-7, 4); // base point - p1.rotate(angle); - p2.rotate(angle); - p3.rotate(angle); - double[] xx = new double[] {p1.x + x, p2.x + x, x, p3.x + x}; - double[] yy = new double[] {p1.y + y, p2.y + y, y, p3.y + y}; - gc.fillPolygon(xx, yy, 4); - - if (raceViewController.isDisplayAnnotations()){ - drawWake(gc, x, y, speed, color, heading); - } - } - - /** - * Inner class for creating point so that you can rotate it around origin point. - */ - class Point { - - double x, y; - - Point (double x, double y) { - this.x = x; - this.y = y; - } - - void rotate(double angle) { - double oldX = x; - double oldY = y; - this.x = oldX * Math.cos(angle) - oldY * Math.sin(angle); - this.y = oldX * Math.sin(angle) + oldY * Math.cos(angle); - - } - } - - /** - * Draws the course. - */ - private void drawCourse() { - for (Mark mark : raceViewController.getRace().getCourse()) { - if (mark.getMarkType() == MarkType.SINGLE_MARK) { - drawSingleMark((SingleMark) mark, Color.BLACK); - } else if (mark.getMarkType() == MarkType.GATE_MARK) { - drawGateMark((GateMark) mark); - } - } - } - - /** - * Draw a given mark on canvas - * - * @param singleMark - */ - private void drawSingleMark(SingleMark singleMark, Color color) { - double x = (singleMark.getLongitude() - ORIGIN_LON) * SCALE; - double y = (ORIGIN_LAT - singleMark.getLatitude()) * SCALE; - - gc.setFill(color); - gc.fillRect(x,y,5.5,5.5); - } - - /** - * Draw a gate mark which contains two single marks - * - * @param gateMark - */ - private void drawGateMark(GateMark gateMark) { - Color color = Color.BLUE; - - if (gateMark.getName().equals("Start")){ - color = Color.RED; - } - - if (gateMark.getName().equals("Finish")){ - color = Color.GREEN; - } - - drawSingleMark(gateMark.getSingleMark1(), color); - drawSingleMark(gateMark.getSingleMark2(), color); - - GraphicsContext gc = canvas.getGraphicsContext2D(); - - gc.setStroke(color); - - // Convert lat/lon to x,y - double x1 = (gateMark.getSingleMark1().getLongitude()- ORIGIN_LON) * SCALE; - double y1 = (ORIGIN_LAT - gateMark.getSingleMark1().getLatitude()) * SCALE; - - double x2 = (gateMark.getSingleMark2().getLongitude() - ORIGIN_LON) * SCALE; - double y2 = (ORIGIN_LAT - gateMark.getSingleMark2().getLatitude()) * SCALE; - - gc.setLineWidth(1); - gc.strokeLine(x1, y1, x2, y2); - } -} \ No newline at end of file diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index 1892d472..080e06ab 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -1,38 +1,176 @@ package seng302.controllers; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; +import javafx.scene.Group; +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.control.Button; +import javafx.scene.paint.Color; +import seng302.models.Boat; +import seng302.models.Course; +import seng302.models.Race; +import seng302.models.mark.Mark; +import seng302.models.mark.MarkType; +import seng302.models.parsers.ConfigParser; +import seng302.models.parsers.CourseParser; +import seng302.models.parsers.TeamsParser; -import java.io.IOException; import java.net.URL; +import java.util.ArrayList; import java.util.ResourceBundle; /** - * Created by michaelrausch on 21/03/17. + * Controller for main window for RaceVision + * Created by Kusal on 3/22/2017. */ public class Controller implements Initializable { - @FXML - private AnchorPane contentPane; - private void setContentPane(String jfxUrl){ - try{ - contentPane.getChildren().removeAll(); - contentPane.getChildren().clear(); - contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl))); - } - catch(javafx.fxml.LoadException e){ - System.err.println(e.getCause()); - } - catch(IOException e){ - System.err.println(e); - } - } + private static final int MARKER_WIDTH = 10; + private static final int MARKER_HEIGHT = 10; + private static final double ORIGINAL_LAT = 32.321504; + private static final double ORIGINAL_LON = -64.857063; + + + @FXML + private Canvas courseCanvas; + + @FXML + private Group boatGroup; + + @FXML + private Button playPauseButton; + + + private Course thisCourse; + private ArrayList startingBoats; + private int raceDuration; + private Race race; + private boolean raceRunning = false; + + private CourseParser cp; + private TeamsParser tp; + private ConfigParser cop; @Override public void initialize(URL location, ResourceBundle resources) { - setContentPane("/views/RaceView.fxml"); + cp = new CourseParser("/config/course.xml"); + tp = new TeamsParser("/config/teams.xml"); + cop = new ConfigParser("/config/config.xml"); + + thisCourse = new Course(cp.getCourse()); + startingBoats = tp.getBoats(); + race = new Race(thisCourse.getMarks(), startingBoats, cop.getTimeScale(), this); + init(); + } + + /** + * Initialises a race on the screen after it has been loaded + */ + private void init() { + initMap(); + initBoats(); + playPauseButton.setDisable(false); + } + + /** + * Initialise the map by drawing it onto courseCanvas. + */ + private void initMap() { + //Create the boundary of the course displayed on the map + drawCourse(); + } + + + /** + * Draw the markers and gates onto the courseCanvas. + */ + private void drawCourse() { + GraphicsContext gc = courseCanvas.getGraphicsContext2D(); + gc.save(); + + for(Mark rp : thisCourse.getMarks()) { + if (rp.getMarkType().equals(MarkType.SINGLE_MARK)) { + gc.setFill(Color.GRAY); + gc.fillOval(convertLongToX(rp.getLongitude()), convertLatToY(rp.getLatitude()), MARKER_WIDTH, MARKER_HEIGHT); + } else if (rp.getMarkType().equals(MarkType.GATE_MARK)) { + gc.setFill(Color.GRAY); + gc.fillOval(convertLongToX(rp.getLongitude()), convertLatToY(rp.getLatitude()), MARKER_WIDTH, MARKER_HEIGHT); +// gc.fillOval(((OpenGate) rp).getDrawX2(), ((OpenGate) rp).getDrawY2(), MARKER_WIDTH, MARKER_HEIGHT); + + gc.setLineWidth(2); + gc.setFill(Color.GREEN); + gc.setStroke(Color.GREEN); + } + gc.fillOval(convertLongToX(rp.getLongitude()), convertLatToY(rp.getLatitude()), MARKER_WIDTH, MARKER_HEIGHT); +// gc.fillOval(((ClosedGate) rp).getDrawX2(), ((ClosedGate) rp).getDrawY2(), MARKER_WIDTH, MARKER_HEIGHT); +// gc.strokeLine(convertLongToX(rp.getLongitude()) + 5, convertLatToY(rp.getLatitude()) + 5, ((ClosedGate) rp).getDrawX2() + 5, ((ClosedGate) rp).getDrawY2() + 5); + } + gc.restore(); + } + + /** + * Places boats at starting line + */ + private void initBoats() { + +// int startingX = (convertLongToX(thisCourse.getMarks().get(0).getLongitude())).intValue(); +// int startingY = (convertLatToY(thisCourse.getMarks().get(0).getLongitude())).intValue(); + + int startingX = 50; + int startingY = 100; + + for(Boat boat : startingBoats) { + boat.moveBoatTo(startingX, startingY); + boatGroup.getChildren().add(boat.getBoatObject()); + boat.setCurrentLeg(race.getRaceLegs().get(0)); + boat.setHeading(race.getRaceLegs().get(0).getHeading()); + boat.setLegDistance(0d); + } + } + + + /** + * Starts and stops the race depending on whether or not it is already running + */ + public void playPause() { + if (!raceRunning) { + play(); + } else { + pause(); + } + } + + /** + * Plays the race and updates the play / pause button + */ + private void play() { + race.run(); + raceRunning = true; + playPauseButton.setText("Pause"); + + } + + /** + * Pauses the race and updates the play / pause button + */ + private void pause() { + race.pause(); + raceRunning = false; + playPauseButton.setText("Play"); + } + + + + private Double convertLongToX(Double lon) { + return (lon - ORIGINAL_LON) * thisCourse.getDistanceScaleFactor(); + } + + private Double convertLatToY(Double lat) { + return (ORIGINAL_LAT - lat) * thisCourse.getDistanceScaleFactor(); + } + + public Button getPlayPauseButton() { + return playPauseButton; } } diff --git a/src/main/java/seng302/controllers/RaceController.java b/src/main/java/seng302/controllers/RaceController.java deleted file mode 100644 index b5fa2847..00000000 --- a/src/main/java/seng302/controllers/RaceController.java +++ /dev/null @@ -1,80 +0,0 @@ -package seng302.controllers; - -import seng302.models.Boat; -import seng302.models.Race; -import seng302.models.parsers.ConfigParser; -import seng302.models.parsers.CourseParser; -import seng302.models.parsers.TeamsParser; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Random; - -/** - * Created by zyt10 on 17/03/17. - * run before CanvasController to initialize race events - * the CanvasController then uses the event data to make the animations - */ -public class RaceController { - Race race = null; - - public void initializeRace() { - String raceConfigFile = "/config/config.xml"; - String teamsConfigFile = "/config/teams.xml"; - - try { - race = createRace(raceConfigFile, teamsConfigFile); - } catch (Exception e) { - System.out.println("There was an error creating the race."); - } - - if (race != null) { - race.startRace(); - } else { - System.out.println("There was an error creating the race. Exiting."); - } - } - - public Race createRace(String configFile, String teamsConfigFile) throws Exception { - Race race = new Race(); - - // Read team names from file - TeamsParser tp = new TeamsParser(teamsConfigFile); - - // Read course from file - ConfigParser config = new ConfigParser(configFile); - - ArrayList boatNames = new ArrayList<>(); - ArrayList teams = tp.getBoats(); - - //get race size - int numberOfBoats = teams.size(); - - //get time scale - double timeScale = config.getTimeScale(); - race.setTimeScale(timeScale); - - for (Boat boat : teams) { - boatNames.add(boat.getTeamName()); - race.addBoat(boat); - } - - // Shuffle team names - long seed = System.nanoTime(); - Collections.shuffle(boatNames, new Random(seed)); - - if (numberOfBoats > Array.getLength(boatNames.toArray())) { - return null; - } - - CourseParser course = new CourseParser("/config/course.xml"); - race.addCourse(course.getCourse()); - - return race; - } - - public Race getRace() { - return race; - } -} diff --git a/src/main/java/seng302/controllers/RaceResultController.java b/src/main/java/seng302/controllers/RaceResultController.java deleted file mode 100644 index 7378fa68..00000000 --- a/src/main/java/seng302/controllers/RaceResultController.java +++ /dev/null @@ -1,37 +0,0 @@ -package seng302.controllers; - -import javafx.fxml.FXML; -import javafx.fxml.Initializable; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.Text; -import seng302.models.Race; - -import java.net.URL; -import java.util.ResourceBundle; - -/** - * Created by ptg19 on 20/03/17. - */ -public class RaceResultController implements Initializable{ - @FXML private AnchorPane window; - @FXML private VBox resultsVBox; - private Race race; - - RaceResultController(Race race){ - this.race = race; - } - - @Override - public void initialize(URL location, ResourceBundle resources) { - int boatPosition = this.race.getFinishedBoats().length; - - for (int i = this.race.getFinishedBoats().length - 1; i >= 0; i--){ - resultsVBox.getChildren().add(0, new Text(boatPosition + ": " + this.race.getFinishedBoats()[i].getTeamName())); - boatPosition--; - } - - - - } -} diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java deleted file mode 100644 index 965fbc7d..00000000 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ /dev/null @@ -1,280 +0,0 @@ -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; -import javafx.fxml.FXMLLoader; -import javafx.scene.control.CheckBox; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; -import javafx.scene.layout.VBox; -import javafx.scene.text.Text; -import javafx.util.Duration; -import seng302.models.Boat; -import seng302.models.Event; -import seng302.models.Race; -import seng302.models.TimelineInfo; -import seng302.models.parsers.ConfigParser; - -import java.io.IOException; -import java.util.*; - -/** - * Created by ptg19 on 29/03/17. - */ -public class RaceViewController { - @FXML - private VBox positionVbox; - @FXML - private CheckBox toggleAnnotation, toggleFps; - @FXML - private Text timerLabel; - @FXML - private AnchorPane contentAnchorPane; - @FXML - private Text windArrowText, windDirectionText; - @FXML - private CanvasController includedCanvasController; - - private boolean displayAnnotations; - private boolean displayFps; - private Timeline timerTimeline; - private Map timelineInfos = new HashMap<>(); - private ArrayList boatOrder = new ArrayList<>(); - private Race race; - - public void initialize() { - includedCanvasController.setup(this); - RaceController raceController = new RaceController(); - raceController.initializeRace(); - race = raceController.getRace(); - - initializeTimer(); - initializeSettings(); - try{ - initializeTimelines(); - } - catch (Exception e){ - e.printStackTrace(); - } - - //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); - } - - private void initializeSettings(){ - displayAnnotations = true; - displayFps = true; - - toggleAnnotation.selectedProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { - displayAnnotations = !displayAnnotations; - } - }); - toggleFps.selectedProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { - displayFps = !displayFps; - } - }); - } - - private void initializeTimer(){ - timerTimeline = new Timeline(); - timerTimeline.setCycleCount(Timeline.INDEFINITE); - // Run timer update every second - timerTimeline.getKeyFrames().add( - new KeyFrame(Duration.seconds(1), - event -> { - // Stop timer if race is finished - if (this.race.isRaceFinished()) { - this.timerTimeline.stop(); - } else { - timerLabel.setText(convertTimeToMinutesSeconds(race.getRaceTime())); - this.race.incrementRaceTime(); - } - }) - ); - - // Start the timer - timerTimeline.playFromStart(); - } - - /** - * Generates time line for each boat, and stores time time into timelineInfos hash map - */ - private void initializeTimelines() { - HashMap boat_events = race.getEvents(); - - for (Boat boat : boat_events.keySet()) { - // x, y are the real time coordinates - DoubleProperty x = new SimpleDoubleProperty(); - DoubleProperty y = new SimpleDoubleProperty(); - - List keyFrames = new ArrayList<>(); - List events = boat_events.get(boat); - - // iterates all events and convert each event to keyFrame, then add them into a list - for (Event event : events) { - if (event.getIsFinishingEvent()) { - keyFrames.add( - new KeyFrame(Duration.seconds(event.getTime()), - onFinished -> {race.setBoatFinished(boat); handleEvent(event);}, - new KeyValue(x, event.getThisMark().getLatitude()), - new KeyValue(y, event.getThisMark().getLongitude()) - ) - ); - } else { - keyFrames.add( - new KeyFrame(Duration.seconds(event.getTime()), - onFinished ->{ - handleEvent(event); - boat.setHeading(event.getBoatHeading()); - }, - new KeyValue(x, event.getThisMark().getLatitude()), - new KeyValue(y, event.getThisMark().getLongitude()) - ) - ); - } - } - timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y)); - } - setRaceDuration(); - } - - private void setRaceDuration(){ - Double maxDuration = 0.0; - Timeline maxTimeline = null; - - for (TimelineInfo timelineInfo : timelineInfos.values()) { - - Timeline timeline = timelineInfo.getTimeline(); - if (timeline.getTotalDuration().toMillis() >= maxDuration) { - maxDuration = timeline.getTotalDuration().toMillis(); - maxTimeline = timeline; - } - - // Timelines are paused by default - timeline.play(); - timeline.pause(); - } - - maxTimeline.setOnFinished(event -> { - race.setRaceFinished(); - loadRaceResultView(); - }); - } - - /** - * Play each boats timerTimeline - */ - public void playTimelines(){ - for (TimelineInfo timelineInfo : timelineInfos.values()){ - Timeline timeline = timelineInfo.getTimeline(); - - if (timeline.getStatus() == Animation.Status.PAUSED){ - timeline.play(); - } - } - } - - /** - * Pause each boats timerTimeline - */ - public void pauseTimelines(){ - for (TimelineInfo timelineInfo : timelineInfos.values()){ - Timeline timeline = timelineInfo.getTimeline(); - - if (timeline.getStatus() == Animation.Status.RUNNING){ - timeline.pause(); - } - } - } - - /** - * Display the list of boats in the order they finished the race - */ - private void loadRaceResultView() { - FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml")); - loader.setController(new RaceResultController(race)); - - try { - contentAnchorPane.getChildren().removeAll(); - contentAnchorPane.getChildren().clear(); - contentAnchorPane.getChildren().addAll((Pane) loader.load()); - - } catch (javafx.fxml.LoadException e) { - System.err.println(e.getCause()); - } catch (IOException e) { - System.err.println(e); - } - } - - public void handleEvent(Event event) { - Boat boat = event.getBoat(); - boatOrder.remove(boat); - boat.setMarkLastPast(event.getMarkPosInRace()); - boatOrder.add(boat); - boatOrder.sort(new Comparator() { - @Override - public int compare(Boat b1, Boat b2) { - return b2.getMarkLastPast() - b1.getMarkLastPast(); - } - }); - showOrder(); - } - - private void showOrder() { - positionVbox.getChildren().clear(); - positionVbox.getChildren().removeAll(); - - for (Boat boat : boatOrder) { - positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots")); - } - } - - /** - * Convert seconds to a string of the format mm:ss - * - * @param time the time in seconds - * @return a formatted string - */ - public String convertTimeToMinutesSeconds(int time) { - if (time < 0) { - return String.format("-%02d:%02d", (time * -1) / 60, (time * -1) % 60); - } - return String.format("%02d:%02d", time / 60, time % 60); - } - - public void stopTimer() { - timerTimeline.stop(); - } - public void startTimer() { - timerTimeline.play(); - } - - public boolean isDisplayFps() { - return displayFps; - } - - public boolean isDisplayAnnotations() { - return displayAnnotations; - } - - public Race getRace() { - return race; - } - - public Map getTimelineInfos() { - return timelineInfos; - } -} \ No newline at end of file diff --git a/src/main/java/seng302/models/Boat.java b/src/main/java/seng302/models/Boat.java index 0973ad38..e081efb9 100644 --- a/src/main/java/seng302/models/Boat.java +++ b/src/main/java/seng302/models/Boat.java @@ -1,28 +1,36 @@ package seng302.models; import javafx.scene.paint.Color; +import javafx.scene.shape.Polygon; +import javafx.scene.text.Text; /** * Represents a boat in the race. */ public class Boat { + private static final double BOAT_HEIGHT = 15d; + private static final double BOAT_WIDTH = 10d; + private static final double VELOCITY_WAKE_RATIO = 1/2d; //Ratio for deciding how long the wake will be wrt velocity + 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 Double velocity; // In meters/second + private Double lat; // Boats position + private Double lon; // - + private Double legDistance; private Color color; - private int markLastPast; - private double heading; + private Leg currentLeg; + private Double heading; private String shortName; + private Polygon boatObject = new Polygon(); + public Boat(String teamName) { this.teamName = teamName; - this.velocity = 10; // Default velocity + this.velocity = 10d; // Default velocity this.lat = 0.0; this.lon = 0.0; - this.distanceToNextMark = 0.0; + this.legDistance = 0.0; this.shortName = ""; } @@ -36,9 +44,12 @@ public class Boat { public Boat(String teamName, double boatVelocity, String shortName) { this.teamName = teamName; this.velocity = boatVelocity; - this.distanceToNextMark = 0.0; + this.legDistance = 0.0; this.color = Colors.getColor(); this.shortName = shortName; + this.boatObject.getPoints().addAll(BOAT_WIDTH /2,0.0, + BOAT_WIDTH, BOAT_HEIGHT, + 0.0, BOAT_HEIGHT); } /** @@ -88,8 +99,12 @@ public class Boat { this.lon = lon; } - public void setDistanceToNextMark(double distance){ - this.distanceToNextMark = distance; + public Double getLegDistance() { + return legDistance; + } + + public void setLegDistance(double legDistance){ + this.legDistance = legDistance; } public double getLatitude(){ @@ -108,12 +123,12 @@ public class Boat { return Math.round((this.velocity * 1.94384) * 100d) / 100d; } - public void setMarkLastPast(int markLastPast) { - this.markLastPast = markLastPast; + public Leg getCurrentLeg() { + return currentLeg; } - public int getMarkLastPast() { - return markLastPast; + public void setCurrentLeg(Leg currentLeg) { + this.currentLeg = currentLeg; } public void setHeading(double heading){ @@ -127,4 +142,33 @@ public class Boat { 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()); + + } + + /** + * 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(int x, int y) { + boatObject.setLayoutX(x); + boatObject.setLayoutY(y); + boatObject.relocate(boatObject.getLayoutX(), boatObject.getLayoutY()); + + } + + public Polygon getBoatObject() { + return boatObject; + } } \ No newline at end of file diff --git a/src/main/java/seng302/models/Course.java b/src/main/java/seng302/models/Course.java new file mode 100644 index 00000000..d6647a02 --- /dev/null +++ b/src/main/java/seng302/models/Course.java @@ -0,0 +1,54 @@ +package seng302.models; + +/** + * Created by wmu16 on 4/8/17. + */ +import javafx.scene.canvas.Canvas; +import javafx.util.Pair; +import seng302.models.mark.Mark; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +/** + * Class for describing the course information for the canvas + * Created by wmu16 on 22/03/17. + */ +public class Course { + + private ArrayList Legs; + private ArrayList marks; + public static final Integer SCALE = 160000; + + + public Course(ArrayList marks) { + this.marks = marks; + this.Legs = makeLegs(); + } + + /** + * Makes the race legs out of all the marker marks for the course + * @return ArrayList of Legs + */ + private ArrayList makeLegs() { + ArrayList Legs = new ArrayList<>(); + for (int i = 0; i < marks.size()-1; i++) { + Legs.add(new Leg(marks.get(i), marks.get(i+1))); + } + return Legs; + } + + + public ArrayList getMarks() { + return marks; + } + + public double getDistanceScaleFactor() { + return SCALE; + } + + public ArrayList getLegs() { + return Legs; + } +} \ No newline at end of file diff --git a/src/main/java/seng302/models/Event.java b/src/main/java/seng302/models/Event.java deleted file mode 100644 index e803845d..00000000 --- a/src/main/java/seng302/models/Event.java +++ /dev/null @@ -1,148 +0,0 @@ -package seng302.models; - -import seng302.models.mark.Mark; - -import java.text.SimpleDateFormat; -import java.util.Date; - -/** -* Event class containing the time of specific event, related team/boat, and -* event location such as leg. -*/ -public class Event { - private Double time; // Time the event occurs - private Boat boat; - private boolean isFinishingEvent = false; // This event occurs when a boat finishes the race - private Mark mark1; // This mark - private Mark mark2; // Next mark - private int markPosInRace; // the position of the current mark in the race course - - private final double ORIGIN_LAT = 32.320504; - private final double ORIGIN_LON = -64.857063; - private final double SCALE = 16000; - - - - /** - * Event class containing the time of specific event, related team/boat, and - * event location such as leg. - * - * @param eventTime, what time the event happens - * @param eventBoat, the boat that the event belongs to - */ - public Event(Double eventTime, Boat eventBoat, Mark mark1, Mark mark2, int markPosInRace) { - this.time = eventTime; - this.boat = eventBoat; - this.mark1 = mark1; - this.mark2 = mark2; - this.markPosInRace = markPosInRace; - } - - /** - * Event class containing the time of specific event, related team/boat, and - * event location such as leg. - * - * @param eventTime, what time the event happens - * @param eventBoat, the boat that the event belongs to - */ - public Event(Double eventTime, Boat eventBoat, Mark mark1, int markPosInRace) { - this.time = eventTime; - this.boat = eventBoat; - this.mark1 = mark1; - this.markPosInRace = markPosInRace; - this.isFinishingEvent = true; - } - - public double getTime() { - return this.time; - } - - public void setTime(double eventTime) { - this.time = eventTime; - } - - /** - * Gets the time in a formatted string - * - * @return the string of time - */ - public String getTimeString() { - return (new SimpleDateFormat("mm:ss:SSS")).format(new Date(time.longValue())); - } - - public Boat getBoat() { - return this.boat; - } - - public void setBoat(Boat eventBoat) { - this.boat = eventBoat; - } - - public boolean getIsFinishingEvent() { - return this.isFinishingEvent; - } - - /** - * Get a string that contains the timestamp and course information for this event - * - * @return A string that details what happened in this event - */ - public String getEventString() { - // This event is a boat finishing the race - if (this.isFinishingEvent) { - return (this.getTimeString() + ", " + this.getBoat().getTeamName() + " finished the race"); - } - System.out.println(this.getDistanceBetweenMarks()); - return (this.getTimeString() + ", " + this.getBoat().getTeamName() + " passed " + this.mark1.getName() + " going heading " + this.getBoatHeading() + "°"); - } - - /** - * @return the distance between the two marks - */ - public double getDistanceBetweenMarks() { - double earth_radius = 6378.137; - double dLat = this.mark2.getLatitude() * Math.PI / 180 - this.mark1.getLatitude() * Math.PI / 180; - double dLon = this.mark2.getLongitude() * Math.PI / 180 - this.mark1.getLongitude() * Math.PI / 180; - - double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(this.mark1.getLatitude() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2); - - double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - double d = earth_radius * c; - - return d * 1000; - } - - /** - * Calculates current boat heading direction. - * @return the boats heading as degree. vertical upward is 0 degree, and degree goes up clockwise. - */ - public double getBoatHeading() { - if (mark2 == null){ - return 0.0; - } - - double x1 = (mark1.getLongitude() - ORIGIN_LON) * SCALE; - double y1 = (ORIGIN_LAT - mark1.getLatitude()) * SCALE; - double x2 = (mark2.getLongitude() - ORIGIN_LON) * SCALE; - double y2 = (ORIGIN_LAT - mark2.getLatitude()) * SCALE; - - double headingRadians = Math.atan2(y2-y1, x2-x1); - - if (headingRadians < 0){ - headingRadians += 2 * Math.PI; - } - - // Convert back to degrees, and flip 180 degrees -// return ((headingRadians) * 180) / Math.PI; - return (Math.toDegrees(headingRadians) + 90) % 360; - - } - - public Mark getThisMark() { - return this.mark1; - } - - public int getMarkPosInRace() { - return markPosInRace; - } -} \ No newline at end of file diff --git a/src/main/java/seng302/models/Leg.java b/src/main/java/seng302/models/Leg.java index 8f21a6ea..7e03e195 100644 --- a/src/main/java/seng302/models/Leg.java +++ b/src/main/java/seng302/models/Leg.java @@ -1,116 +1,97 @@ package seng302.models; -import seng302.models.mark.SingleMark; + +import seng302.models.mark.Mark; /** -* Represents the leg of a race. -*/ + * Class for defining the leg of a race between two markers + * Created by cir27 on 3/03/17. + */ public class Leg { - private int heading; - private int distance; - private boolean isFinishingLeg; - private SingleMark startingSingleMark; + + private final double ORIGIN_LAT = 32.320504; + private final double ORIGIN_LON = -64.857063; + private final double SCALE = 16000; + + private Double distance; + private Double heading; + private Mark end; + private Mark start; + + Leg(Mark start, Mark end) { + this.distance = calculateMarkerDistance(start, end); + this.heading = angleFromCoordinate(start, end); + this.start = start; + this.end = end; + } /** - * Create a new leg + * Calculates the euclidian distance between two markers on the canvas using xy coordinates * - * @param heading, the magnetic heading of this leg - * @param distance, the total distance of this leg in meters - * @param singleMark, the singleMark this leg starts on + * @param geoPointOne first geographical point + * @param geoPointTwo second geographical point + * @return the distance between two points in meters */ - public Leg(int heading, int distance, SingleMark singleMark) { - this.heading = heading; - this.distance = distance; - this.startingSingleMark = singleMark; - this.isFinishingLeg = false; + private Double calculateMarkerDistance(Mark geoPointOne, Mark geoPointTwo) { + + double earth_radius = 6378.137; + double dLat = geoPointTwo.getLatitude() * Math.PI / 180 - geoPointOne.getLatitude() * Math.PI / 180; + double dLon = geoPointTwo.getLongitude() * Math.PI / 180 - geoPointOne.getLongitude() * Math.PI / 180; + + double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(geoPointOne.getLatitude() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2); + + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + double d = earth_radius * c; + + return d * 1000; } /** - * Create a new leg + * Calculates the angle between to angular co-ordinates on a sphere. * - * @param heading, the magnetic heading of this leg - * @param distance, the total distance of this leg in meters - * @param markerName, the name of the marker this leg starts on + * @param geoPointOne first geographical location + * @param geoPointTwo second geographical location + * @return the angle from point one to point two */ - public Leg(int heading, int distance, String markerName) { - this.heading = heading; - this.distance = distance; - this.startingSingleMark = new SingleMark(markerName); - this.isFinishingLeg = false; + private Double angleFromCoordinate(Mark geoPointOne, Mark geoPointTwo) { + + if (geoPointTwo == null){ + return 0.0; + } + + double x1 = (geoPointOne.getLongitude() - ORIGIN_LON) * SCALE; + double y1 = (ORIGIN_LAT - geoPointOne.getLatitude()) * SCALE; + double x2 = (geoPointTwo.getLongitude() - ORIGIN_LON) * SCALE; + double y2 = (ORIGIN_LAT - geoPointTwo.getLatitude()) * SCALE; + + double headingRadians = Math.atan2(y2-y1, x2-x1); + + if (headingRadians < 0){ + headingRadians += 2 * Math.PI; + } + + // Convert back to degrees, and flip 180 degrees +// return ((headingRadians) * 180) / Math.PI; + return (Math.toDegrees(headingRadians) + 90) % 360; + } - /** - * Get the heading of this leg - * @return int - */ - public int getHeading() { - return this.heading; - } - - /** - * Set the heading for this leg - * @param heading - */ - public void setHeading(int heading) { - this.heading = heading; - } - - /** - * Get the total distance of this leg in meters - * @return int - */ - public int getDistance() { + Double getDistance() + { return this.distance; } - /** - * Set the distance of this leg in meters - * @param distance - */ - public void setDistance(int distance) { - this.distance = distance; + Mark getEnd() + { + return this.end; } - /** - * Returns the marker this leg started on - * @return SingleMark - */ - public SingleMark getMarker() { - return this.startingSingleMark; + public Mark getStart() { + return start; } - /** - * Set the singleMark this leg starts on - * @param singleMark - */ - public void setMarker(SingleMark singleMark) { - this.startingSingleMark = singleMark; + public Double getHeading() + { + return this.heading; } - - /** - * Returns the name of the marker this leg started on - * @return String - */ - public String getMarkerLabel() { - return this.startingSingleMark.getName(); - } - - - - /** - * Specify whether or not the race finishes on this leg - * - * @param isFinishingLeg whether or not the race finishes on this leg - */ - public void setFinishingLeg(boolean isFinishingLeg) { - this.isFinishingLeg = isFinishingLeg; - } - - /** - * Returns whether or not the race finishes after this leg - * @return true if this the race finishes after this leg - */ - public boolean getIsFinishingLeg() { - return this.isFinishingLeg; - } -} \ No newline at end of file +} diff --git a/src/main/java/seng302/models/Race.java b/src/main/java/seng302/models/Race.java index 165d9468..a396b508 100644 --- a/src/main/java/seng302/models/Race.java +++ b/src/main/java/seng302/models/Race.java @@ -1,5 +1,7 @@ package seng302.models; +import javafx.animation.AnimationTimer; +import seng302.controllers.Controller; import seng302.models.mark.Mark; import java.util.*; @@ -8,47 +10,137 @@ import java.util.*; * Race class containing the boats and legs in the race * Created by mra106 on 8/3/2017. */ -public class Race { +public class Race extends Thread { + + private static final double UPDATE_TIME = 0.016666; // 1 / 60 ie 60fps + + 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 - private List course; // Marks in the race - private long startTime = 0; - private double timeScale = 1; + private List markers; // Marks in the race + private List raceLegs; private boolean raceFinished = false; // Race is finished private int raceTime = -2; // Current time in the race + private Double timeScale = null; + private boolean raceStarted = false; + private Controller controller; /** * Race class containing the boats and legs in the race */ - public Race() { - this.boats = new ArrayList<>(); + public Race(List markers, ArrayList boats, Double timescale, Controller controller) { + this.boats = boats; + this.markers = markers; + this.raceLegs = makeRaceLegs(); + this.controller = controller; + + this.timeScale = timescale; this.finishingOrder = new ArrayList<>(); - this.course = new ArrayList<>(); + } + + + /** + * Makes the race legs out of all the marker points for the course + * @return ArrayList of raceLegs + */ + private ArrayList makeRaceLegs() { + ArrayList raceLegs = new ArrayList<>(); + for (int i=0; i < markers.size()-1; i++) { + raceLegs.add(new Leg(markers.get(i), markers.get(i+1))); + } + return raceLegs; + } + + + /** + * A timer that is called every frame to call the action of moving the boats + */ + private AnimationTimer at = new AnimationTimer() { + @Override + public void handle(long now) { + + //Updating Boat positions + if(finishingOrder.size() != boats.size()) { + // update the time + boats.stream().filter(boat -> !finishingOrder.contains(boat)).forEach(boat -> { + updateBoatPosition(boat); + }); + } else { + at.stop(); + } + } + + }; + + + /** + * Begins the race simulation + */ + @Override + public void run() { + if (!raceStarted) { +// controller.getPlayPauseButton().setDisable(true); + at.start(); + } + } + + + /** + * Moves the coordinates of the boats. + * @param boat The boat to update the position of + */ + private void updateBoatPosition(Boat boat) { + Double thisHeading = boat.getHeading(); + // TODO: 4/8/17 wmu16 - Add a distance scale factor from lat long distance in Metres to xy equivalent + Double hypMove = boat.getVelocity() * UPDATE_TIME * timeScale; //* distanceScaleFactor + boat.setLegDistance(boat.getLegDistance() + hypMove); + moveBoat(boat, thisHeading, hypMove); } /** - * Add a boat to the race - * - * @param boat, the boat to add + * Moves a boat along coordinates by breaking down the distance moved along the hypotenuse into x and y components + * @param boat The Boat to move + * @param heading The heading the boat is moving at + * @param hypMove The distance moved along the hypotenuse (absolute distance) */ - public void addBoat(Boat boat) { - boats.add(boat); + private void moveBoat(Boat boat, Double heading, Double hypMove) { + //If the boat has not yet passed the marker at the end of the leg increase its (x,y) as per normal + // TODO: 4/8/17 wmu16 - Initialising boat positions and legs and headings etc. + if(boat.getLegDistance() <= boat.getCurrentLeg().getDistance()) { + Double xMove = hypMove * Math.sin(Math.toRadians(heading)); + Double yMove = - hypMove * Math.cos(Math.toRadians(heading)); + boat.moveBoatBy(xMove, yMove); + + //If the boat has finished... + } else if (getNextRaceLeg(boat.getCurrentLeg()).equals(boat.getCurrentLeg())) { + finishingOrder.add(boat); + //Otherwise apply the overflow distance of the leg to the next leg + } else { + Double overflowDistance = boat.getLegDistance() - boat.getCurrentLeg().getDistance(); + boat.setCurrentLeg(getNextRaceLeg(boat.getCurrentLeg())); + boat.setHeading(boat.getCurrentLeg().getHeading()); + boat.setLegDistance(overflowDistance); + moveBoat(boat, boat.getHeading(), overflowDistance); + } + } /** - * Returns a list of boats in a random order - * - * @return a list of boats + * Returns the next leg in the race + * @param currentRaceLeg The leg that you are currently on + * @return The next race leg or the same race leg if it has reached the end */ - public Boat[] getShuffledBoats() { - // Shuffle the list of boats - long seed = System.nanoTime(); - Collections.shuffle(this.boats, new Random(seed)); - - return boats.toArray(new Boat[boats.size()]); + private Leg getNextRaceLeg(Leg currentRaceLeg) { + Leg nextRaceLeg = currentRaceLeg; + for(int i = 0; i< raceLegs.size() - 1; i++) { + if (raceLegs.get(i).equals(currentRaceLeg)) { + nextRaceLeg = raceLegs.get(i + 1); + } + } + return nextRaceLeg; } + /** * Returns a list of boats in the order that they * finished the race (position 0 is first place) @@ -69,85 +161,28 @@ public class Race { return boats.toArray(new Boat[boats.size()]); } - /** - * Sets time scale - * - * @param timeScale - */ - public void setTimeScale(double timeScale) { - this.timeScale = timeScale; - } - - /** - * Generate all events that will happen during the race. - */ - private void generateEvents() { - - for (Boat boat : this.boats) { - double totalDistance = 0; - int numberOfMarks = this.course.size(); - - for (int i = 0; i < numberOfMarks; i++) { - Double time = (totalDistance / boat.getVelocity() / timeScale); - - // If there are singleMarks after this event - if (i < numberOfMarks - 1) { - Event event = new Event(time, boat, course.get(i), course.get(i + 1), i); - - try { - events.get(boat).add(event); - - } catch (NullPointerException e) { - events.put(boat, new ArrayList<>(Arrays.asList(event))); - } - totalDistance += event.getDistanceBetweenMarks(); - System.out.println(totalDistance); - System.out.println(boat.getVelocity()); - } - - // There are no more marks after this event - - else{ - Event event = new Event(time, boat, course.get(i), i); - events.get(boat).add(event); - } - } - } - } - - /** * Starts a race and generates all events for the race. */ public void startRace() { // record start time. - this.startTime = System.currentTimeMillis(); - generateEvents(); + + + + } + + public void pause() { + at.stop(); } /** - * Set the race course - * @param course a list of marks in the course - */ - public void addCourse(List course) { - this.course = course; - } - - /** - * Get a list of marks in the course + * Get a list of marks in the markers * @return */ - public List getCourse() { - return course; + public List getMarkers() { + return markers; } - /** - * Get a map of the events in the race - * @return - */ - public HashMap getEvents() { - return events; - } /** * Set a boat as finished @@ -191,7 +226,11 @@ public class Race { /** * Increment the race time by one second */ - public void incrementRaceTime(){ + public void incrementRaceTime() { this.raceTime += this.timeScale; } + + public List getRaceLegs() { + return raceLegs; + } } \ No newline at end of file diff --git a/src/main/java/seng302/models/TimelineInfo.java b/src/main/java/seng302/models/TimelineInfo.java deleted file mode 100644 index 867ce67b..00000000 --- a/src/main/java/seng302/models/TimelineInfo.java +++ /dev/null @@ -1,31 +0,0 @@ -package seng302.models; - -import javafx.animation.Timeline; -import javafx.beans.property.DoubleProperty; - - -/** - * Created by zyt10 on 17/03/17. - * this class is literally just to associate a timeline with a DoubleProperty x and y - */ -public class TimelineInfo { - private Timeline timeline; - private DoubleProperty x; - private DoubleProperty y; - - public TimelineInfo(Timeline timeline, DoubleProperty x, DoubleProperty y) { - this.timeline = timeline; - this.x = x; - this.y = y; - } - - public Timeline getTimeline() { - return timeline; - } - public DoubleProperty getX() { - return x; - } - public DoubleProperty getY() { - return y; - } -} diff --git a/src/main/resources/config/course.xml b/src/main/resources/config/course.xml index f8bfa00e..2886ff77 100644 --- a/src/main/resources/config/course.xml +++ b/src/main/resources/config/course.xml @@ -1,6 +1,6 @@ - + Start @@ -68,4 +68,4 @@ Leeward Gate Finish - + diff --git a/src/main/resources/views/CanvasView.fxml b/src/main/resources/views/CanvasView.fxml deleted file mode 100644 index bc16ad7e..00000000 --- a/src/main/resources/views/CanvasView.fxml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/main/resources/views/FinishView.fxml b/src/main/resources/views/FinishView.fxml deleted file mode 100644 index debdea26..00000000 --- a/src/main/resources/views/FinishView.fxml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/views/MainView.fxml b/src/main/resources/views/MainView.fxml index ac0b944e..a89478b6 100644 --- a/src/main/resources/views/MainView.fxml +++ b/src/main/resources/views/MainView.fxml @@ -1,11 +1,47 @@ - + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml deleted file mode 100644 index f7fcbfeb..00000000 --- a/src/main/resources/views/RaceView.fxml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/java/seng302/BoatTest.java b/src/test/java/seng302/BoatTest.java deleted file mode 100644 index 0160bb8d..00000000 --- a/src/test/java/seng302/BoatTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package seng302; - -import org.junit.Test; -import seng302.models.Boat; - -import static org.junit.Assert.assertEquals; - -/** - * Unit test for the Team class. - */ -public class BoatTest { - - @Test - public void testBoatCreation() { - Boat boat1 = new Boat("Team 1"); - assertEquals(boat1.getTeamName(), "Team 1"); - assertEquals(boat1.getVelocity(), (double) 10.0, 1e-15); - } - - @Test - public void testChangeTeamName() { - Boat boat1 = new Boat("Team 1"); - boat1.setTeamName("Team 2"); - assertEquals(boat1.getTeamName(), "Team 2"); - } - - @Test - public void testSetVelocity() { - Boat boat1 = new Boat("Team 1", 29.0, ""); - assertEquals(boat1.getVelocity(), (double) 29.0, 1e-15); - - boat1.setVelocity(12.0); - assertEquals(boat1.getVelocity(), (double)12.0, 1e-15); - } -} diff --git a/src/test/java/seng302/ColorsTest.java b/src/test/java/seng302/ColorsTest.java deleted file mode 100644 index a6681b26..00000000 --- a/src/test/java/seng302/ColorsTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package seng302; - -import javafx.scene.paint.Color; -import org.junit.Test; -import seng302.models.Boat; -import seng302.models.Colors; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -/** - * Created by ryan_ on 16/03/2017. - */ -public class ColorsTest { - //@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++; - } - - List boatColors = new ArrayList<>(); - for (Boat boat : boats) { - Color color = boat.getColor(); - boatColors.add(color); - } - - assertEquals(enumColors, boatColors); - } -} diff --git a/src/test/java/seng302/EventTest.java b/src/test/java/seng302/EventTest.java deleted file mode 100644 index 0be0fc98..00000000 --- a/src/test/java/seng302/EventTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package seng302; - -import org.junit.Test; -import seng302.models.Boat; -import seng302.models.Event; -import seng302.models.mark.SingleMark; - -import static org.junit.Assert.assertEquals; - -/** - * Test for Event class - * Created by Haoming on 7/03/17. - */ -public class EventTest { - - @Test - public void getTimeString() throws Exception { - Boat boat = new Boat("testBoat"); - Event event = new Event(1231242.2, boat, new SingleMark("mark1"), new SingleMark("mark2"), 0); - assertEquals("20:31:242", event.getTimeString()); - } - - @Test - public void testBoatHeading() throws Exception { - Boat boat = new Boat("testBoat"); - Event event = new Event(1231242.2, boat, new SingleMark("mark1", 142.5, 122.1), new SingleMark("mark2", 121.9,99.2), 0); - - assertEquals(event.getBoatHeading(), 228.0266137055349, 1e-15); - } - - @Test - public void testDistanceBetweenMarks() throws Exception { - Boat boat = new Boat("testBoat"); - Event event = new Event(1231242.2, boat, new SingleMark("mark1", 142.5, 122.1), new SingleMark("mark2", 121.9,99.2), 0); - - assertEquals(event.getDistanceBetweenMarks(), 339059.653830461, 1e-15); - } -} \ No newline at end of file diff --git a/src/test/java/seng302/LegTest.java b/src/test/java/seng302/LegTest.java deleted file mode 100644 index 9bb64b6c..00000000 --- a/src/test/java/seng302/LegTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package seng302; - -import org.junit.Test; -import seng302.models.Leg; -import seng302.models.mark.SingleMark; - -import static org.junit.Assert.assertEquals; - -/** - * Unit test for the Leg class. - */ -public class LegTest { - - /** - * Test creation of the leg by specifying a string - * for the marker label - */ - @Test - public void testLegCreationUsingMarkerLabel() { - Leg leg = new Leg(010, 100, "SingleMark"); - - assertEquals(leg.getHeading(), 010); - assertEquals(leg.getDistance(), 100); - assertEquals(leg.getMarkerLabel(), "SingleMark"); - assertEquals(leg.getIsFinishingLeg(), false); - } - - /** - * Test creation of the leg by providing a - * SingleMark object - */ - @Test - public void testLegCreation() { - Leg leg = new Leg(010, 100, new SingleMark("SingleMark")); - - assertEquals(leg.getHeading(), 010); - assertEquals(leg.getDistance(), 100); - assertEquals(leg.getMarkerLabel(), "SingleMark"); - assertEquals(leg.getIsFinishingLeg(), false); - } - - /** - * Test changing whether or not a - * leg is the finishing leg - */ - @Test - public void testSetFinishLeg() { - Leg leg = new Leg(010, 100, "SingleMark"); - - leg.setFinishingLeg(true); - assertEquals(leg.getIsFinishingLeg(), true); - } - -} diff --git a/src/test/java/seng302/RaceTest.java b/src/test/java/seng302/RaceTest.java deleted file mode 100644 index ab318331..00000000 --- a/src/test/java/seng302/RaceTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package seng302; - -import org.junit.Test; -import seng302.models.Boat; -import seng302.models.Race; - -import java.lang.reflect.Array; - -import static org.junit.Assert.assertEquals; - -/** - * Unit test for the Race class. - */ -public class RaceTest { - /** - * Test that all boats were added to the race - */ - @Test - public void testAddingBoatsToRace() { - Boat boat1 = new Boat("Team 1"); - Boat boat2 = new Boat("Team 2"); - - Race race = new Race(); - race.addBoat(boat1); - race.addBoat(boat2); - - assertEquals(Array.getLength(race.getBoats()), 2); - } - - @Test - public void testGetShuffledBoats(){ - Boat boat1 = new Boat("Team 1"); - Boat boat2 = new Boat("Team 2"); - - Race race = new Race(); - race.addBoat(boat1); - race.addBoat(boat2); - - assertEquals(Array.getLength(race.getShuffledBoats()), 2); - } -} diff --git a/src/test/java/seng302/TestRaceTimer.java b/src/test/java/seng302/TestRaceTimer.java deleted file mode 100644 index 542405b1..00000000 --- a/src/test/java/seng302/TestRaceTimer.java +++ /dev/null @@ -1,25 +0,0 @@ -package seng302; - -import org.junit.Test; -import seng302.controllers.RaceViewController; - -import static org.junit.Assert.assertTrue; - - -public class TestRaceTimer { - @Test - public void testPositiveTimeString(){ - RaceViewController controller = new RaceViewController(); - String result = controller.convertTimeToMinutesSeconds(61); - - assertTrue(result.equals("01:01")); - } - - @Test - public void testNegativeTimeString(){ - RaceViewController controller = new RaceViewController(); - String result = controller.convertTimeToMinutesSeconds(-61); - - assertTrue(result.equals("-01:01")); - } -} diff --git a/src/test/java/seng302/models/mark/MarkTest.java b/src/test/java/seng302/models/mark/MarkTest.java deleted file mode 100644 index f1943c64..00000000 --- a/src/test/java/seng302/models/mark/MarkTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package seng302.models.mark; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Created by Haoming on 17/3/17. - */ -public class MarkTest { - - private SingleMark singleMark1; - private SingleMark singleMark2; - private GateMark gateMark; - - @Before - public void setUp() throws Exception { - this.singleMark1 = new SingleMark("testMark_SM1", 12.23234, -34.342); - this.singleMark2 = new SingleMark("testMark_SM2", 12.23239, -34.352); - this.gateMark = new GateMark("testMark_GM", singleMark1, singleMark2, singleMark1.getLatitude(), singleMark2.getLongitude()); - } - - @Test - public void getName() throws Exception { - assertEquals("testMark_SM1", this.singleMark1.getName()); - assertEquals("testMark_GM", this.gateMark.getName()); - } - - @Test - public void getMarkType() throws Exception { - assertTrue(this.singleMark2.getMarkType() == MarkType.SINGLE_MARK); - assertTrue(this.gateMark.getMarkType() == MarkType.GATE_MARK); - } - - @Test - public void getMarkContent() throws Exception { - assertEquals(12.23234, this.singleMark1.getLatitude(), 1e-10); - assertEquals(-34.342, this.singleMark1.getLongitude(), 1e-10); - assertEquals("testMark_SM1", this.gateMark.getSingleMark1().getName()); - assertEquals(-34.352, this.gateMark.getSingleMark2().getLongitude(), 1e-10); - } - -} \ No newline at end of file diff --git a/src/test/java/seng302/models/parsers/ConfigParserTest.java b/src/test/java/seng302/models/parsers/ConfigParserTest.java deleted file mode 100644 index 8a0c0c8c..00000000 --- a/src/test/java/seng302/models/parsers/ConfigParserTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package seng302.models.parsers; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Created by Haoming on 23/03/17. - */ -public class ConfigParserTest { - - private ConfigParser cp; - - @Before - public void initializeParser() throws Exception { - cp = new ConfigParser("/config/config.xml"); - } - - @Test - public void getWindDirection() throws Exception { - assertEquals(135, cp.getWindDirection(), 1e-10); - } - - @Test - public void getTimeScale() throws Exception { - assertEquals(10.0, cp.getTimeScale(), 1e-10); - } - - @Test - public void getDoubleByTagName() throws Exception { - assertEquals(6, cp.getDoubleByTagName("race-size", 0), 1e-10); - assertEquals(100, cp.getDoubleByTagName("noTag", 100), 1e-10); - } - - @Test - public void getStringByTagName() throws Exception { - assertEquals("AC35", cp.getStringByTagName("race-name", "11")); - assertEquals("oops", cp.getStringByTagName("noTag", "oops")); - } - -} \ No newline at end of file diff --git a/src/test/java/seng302/models/parsers/CourseParserTest.java b/src/test/java/seng302/models/parsers/CourseParserTest.java deleted file mode 100644 index 865caec6..00000000 --- a/src/test/java/seng302/models/parsers/CourseParserTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package seng302.models.parsers; - -import org.junit.Before; -import org.junit.Test; -import seng302.models.mark.*; - -import java.util.ArrayList; - -import static org.junit.Assert.*; - -/** - * To test if course parser works as expected. - * Created by Haoming on 17/03/17. - */ -public class CourseParserTest { - - private CourseParser cp; - - @Before - public void initializeParser() throws Exception { - cp = new CourseParser("/config/course.xml"); - } - - @Test - public void getGates() throws Exception { - ArrayList course = cp.getCourse(); - - assertTrue(MarkType.GATE_MARK == course.get(0).getMarkType()); - - GateMark gateMark1 = (GateMark) course.get(0); - assertEquals(32.293771, gateMark1.getSingleMark2().getLatitude(), 0.00000001); - assertEquals(-64.855242, gateMark1.getSingleMark2().getLongitude(), 0.00000001); - - GateMark gateMark2 = (GateMark) course.get(5); - - assertEquals("Finish1", gateMark2.getSingleMark1().getName()); - assertEquals("Finish2", gateMark2.getSingleMark2().getName()); - assertEquals(32.317257, gateMark2.getSingleMark2().getLatitude(), 0.00000001); - assertEquals(-64.83626, gateMark2.getSingleMark2().getLongitude(), 0.00000001); - } - - @Test - public void getMarks() throws Exception { - ArrayList course = cp.getCourse(); - assertEquals("Mid Mark", course.get(1).getName()); - } - - @Test - public void getOrder() { - ArrayList course = cp.getCourse(); - assertEquals(6, course.size()); - assertEquals("Start", course.get(0).getName()); - assertEquals("Mid Mark", course.get(1).getName()); - assertEquals("Leeward Gate", course.get(2).getName()); - assertEquals("Windward Gate", course.get(3).getName()); - assertEquals("Leeward Gate", course.get(4).getName()); - assertEquals("Finish", course.get(5).getName()); - } - -} \ No newline at end of file diff --git a/src/test/java/seng302/models/parsers/TeamsParserTest.java b/src/test/java/seng302/models/parsers/TeamsParserTest.java deleted file mode 100644 index 3c31b519..00000000 --- a/src/test/java/seng302/models/parsers/TeamsParserTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package seng302.models.parsers; - -import org.junit.Before; -import org.junit.Test; -import seng302.models.Boat; - -import java.util.ArrayList; - -import static org.junit.Assert.*; - -/** - * Created by Haoming on 18/03/17. - */ -public class TeamsParserTest { - - private TeamsParser tp; - @Before - public void readFile() { - tp = new TeamsParser("/config/teams.xml"); - } - - @Test - public void getBoats() throws Exception { - ArrayList boats = tp.getBoats(); - - assertEquals(6, boats.size(), 1e-10); - - assertEquals("Oracle Team USA", boats.get(0).getTeamName()); - //assertEquals(30.9, boats.get(0).getVelocity(), 1e-10); - - assertEquals("Groupama Team France", boats.get(5).getTeamName()); - //assertEquals(45.6, boats.get(5).getVelocity(), 1e-10); - } - -} \ No newline at end of file