diff --git a/visualiser/src/main/java/seng302/Controllers/RaceController.java b/visualiser/src/main/java/seng302/Controllers/RaceController.java index a96f1436..9f1a55f7 100644 --- a/visualiser/src/main/java/seng302/Controllers/RaceController.java +++ b/visualiser/src/main/java/seng302/Controllers/RaceController.java @@ -1,19 +1,25 @@ package seng302.Controllers; +import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.layout.GridPane; +import org.xml.sax.SAXException; import seng302.Mock.StreamedRace; -import seng302.Model.BoatInRace; -import seng302.Model.Race; -import seng302.Model.RaceClock; -import seng302.Model.ResizableRaceCanvas; +import seng302.Model.*; import seng302.RaceDataSource; +import seng302.RaceXMLReader; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.ResourceBundle; /** @@ -22,11 +28,16 @@ import java.util.ResourceBundle; public class RaceController extends Controller { @FXML GridPane canvasBase; + + //user saved data for annotation display + private ArrayList presetAnno; + ResizableRaceCanvas raceMap; @FXML SplitPane race; @FXML CheckBox showFPS; + @FXML CheckBox showBoatPath; @FXML @@ -37,6 +48,7 @@ public class RaceController extends Controller { Label FPS; @FXML Label timeZone; + @FXML CheckBox showName; @FXML @@ -47,18 +59,17 @@ public class RaceController extends Controller { Button saveAnno; @FXML Button showSetAnno; + @FXML - TableView boatInfoTable; + TableView boatInfoTable; @FXML - TableColumn boatPlacingColumn; + TableColumn boatPlacingColumn; @FXML - TableColumn boatTeamColumn; + TableColumn boatTeamColumn; @FXML - TableColumn boatMarkColumn; + TableColumn boatMarkColumn; @FXML - TableColumn boatSpeedColumn; - //user saved data for annotation display - private ArrayList presetAnno; + TableColumn boatSpeedColumn; /** * Updates the ResizableRaceCanvas (raceMap) with most recent data @@ -66,7 +77,7 @@ public class RaceController extends Controller { * @param boats boats that are to be displayed in the race * @see ResizableRaceCanvas */ - public void updateMap(ObservableList boats) { + public void updateMap(ObservableList boats) { raceMap.setBoats(boats); raceMap.update(); } diff --git a/visualiser/src/main/java/seng302/Controllers/StartController.java b/visualiser/src/main/java/seng302/Controllers/StartController.java index 95ce2198..859b2264 100644 --- a/visualiser/src/main/java/seng302/Controllers/StartController.java +++ b/visualiser/src/main/java/seng302/Controllers/StartController.java @@ -14,9 +14,10 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; import org.xml.sax.SAXException; import seng302.Mock.*; -import seng302.Model.BoatInRace; +import seng302.Model.Boat; import seng302.Model.RaceClock; import seng302.RaceDataSource; +import seng302.RaceXMLReader; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; @@ -30,28 +31,20 @@ import java.util.ResourceBundle; */ public class StartController extends Controller { - @FXML - Button oneMinButton; - @FXML - Button fiveMinButton; - @FXML - Button fifteenMinButton; - @FXML - private GridPane start; - @FXML - private AnchorPane startWrapper; - @FXML - private TableView boatNameTable; - @FXML - private TableColumn boatNameColumn; - @FXML - private TableColumn boatCodeColumn; - @FXML - private Label timeZoneTime; - @FXML - private Label timer; - @FXML - private int PRERACE_TIME = 15000; + @FXML private GridPane start; + @FXML private AnchorPane startWrapper; + + @FXML private TableView boatNameTable; + @FXML private TableColumn boatNameColumn; + @FXML private TableColumn boatCodeColumn; + @FXML private Label timeZoneTime; + @FXML private Label timer; + @FXML private int PRERACE_TIME = 15000; + + @FXML Button oneMinButton; + @FXML Button fiveMinButton; + @FXML Button fifteenMinButton; + private RaceClock raceClock; private RaceDataSource raceData; @@ -78,7 +71,7 @@ public class StartController extends Controller { startRace(1); } - private void startRace(int raceScale) { + private void startRace(int raceScale){ oneMinButton.setDisable(true); fiveMinButton.setDisable(true); @@ -87,7 +80,7 @@ public class StartController extends Controller { } @Override - public void initialize(URL location, ResourceBundle resources) { + public void initialize(URL location, ResourceBundle resources){ raceData = null; try { StreamedCourse streamedCourse = new StreamedCourse(new BoatXMLReader("mockXML/boatXML/boatTest.xml")); @@ -109,13 +102,13 @@ public class StartController extends Controller { setRaceClock(); } - public AnchorPane startWrapper() { + public AnchorPane startWrapper(){ return startWrapper; } private void initialiseTables() { - List boats = raceData.getBoats(); - ObservableList observableBoats = FXCollections.observableArrayList(boats); + List boats = raceData.getBoats(); + ObservableList observableBoats = FXCollections.observableArrayList(boats); boatNameTable.setItems(observableBoats); boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().getName()); @@ -140,7 +133,7 @@ public class StartController extends Controller { protected void countdownTimer(int scaleFactor) { new AnimationTimer() { long currentTime = System.currentTimeMillis(); - long startTime = currentTime + (PRERACE_TIME / scaleFactor); + long startTime = currentTime + (PRERACE_TIME/scaleFactor); long minutes; long currentTimeInSeconds; long remainingSeconds; @@ -156,7 +149,7 @@ public class StartController extends Controller { startWrapper.setVisible(false); } else { - currentTimeInSeconds = (timeLeft * scaleFactor) / 1000; + currentTimeInSeconds = (timeLeft*scaleFactor) / 1000; minutes = currentTimeInSeconds / 60; remainingSeconds = currentTimeInSeconds % 60; hours = minutes / 60; diff --git a/visualiser/src/main/java/seng302/Mock/BoatXMLReader.java b/visualiser/src/main/java/seng302/Mock/BoatXMLReader.java index 5d386c0a..9a614faa 100644 --- a/visualiser/src/main/java/seng302/Mock/BoatXMLReader.java +++ b/visualiser/src/main/java/seng302/Mock/BoatXMLReader.java @@ -3,11 +3,14 @@ package seng302.Mock; import javafx.scene.paint.Color; import org.w3c.dom.Element; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import seng302.Model.Boat; import seng302.XMLReader; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; +import java.lang.annotation.ElementType; import java.text.ParseException; import java.util.*; @@ -15,36 +18,30 @@ import java.util.*; * Created by Joseph on 24/04/2017. */ public class BoatXMLReader extends XMLReader { - private static int currentColourIndex = 0; Map streamedBoatMap = new HashMap<>(); Map participants = new HashMap<>(); - private List colours; /** * Constructor for Boat XML Reader - * * @param filePath path of the file - * @throws IOException error - * @throws SAXException error + * @throws IOException error + * @throws SAXException error * @throws ParserConfigurationException error */ public BoatXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException, ParseException { this(filePath, false); - makeColours(); } /** * Constructor for Boat XML Reader - * * @param filePath file path to read - * @param read whether or not to read and store the files straight away. - * @throws IOException error - * @throws SAXException error + * @param read whether or not to read and store the files straight away. + * @throws IOException error + * @throws SAXException error * @throws ParserConfigurationException error */ public BoatXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException, ParseException { super(filePath); - makeColours(); if (read) { read(); } @@ -81,7 +78,6 @@ public class BoatXMLReader extends XMLReader { Node boat = nBoats.getChildNodes().item(i); if (boat.getNodeName().equals("Boat")) { readSingleBoat(boat); - currentColourIndex = (currentColourIndex + 1) % colours.size(); } } } @@ -98,8 +94,7 @@ public class BoatXMLReader extends XMLReader { String shortName = null; String country = null; if (exists(boat, "Type")) type = boat.getAttributes().getNamedItem("Type").getTextContent(); - if (exists(boat, "SourceID")) - sourceID = Integer.parseInt(boat.getAttributes().getNamedItem("SourceID").getTextContent()); + if (exists(boat, "SourceID")) sourceID = Integer.parseInt(boat.getAttributes().getNamedItem("SourceID").getTextContent()); if (exists(boat, "BoatName")) boatName = boat.getAttributes().getNamedItem("BoatName").getTextContent(); if (exists(boat, "ShortName")) shortName = boat.getAttributes().getNamedItem("ShortName").getTextContent(); if (exists(boat, "Country")) country = boat.getAttributes().getNamedItem("Country").getTextContent(); @@ -109,9 +104,9 @@ public class BoatXMLReader extends XMLReader { if (!streamedBoatMap.containsKey(sourceID)) { if (country != null) { - streamedBoat = new StreamedBoat(sourceID, boatName, colours.get(currentColourIndex), country); + streamedBoat = new StreamedBoat(sourceID, boatName, country); } else { - streamedBoat = new StreamedBoat(sourceID, boatName, colours.get(currentColourIndex), shortName); + streamedBoat = new StreamedBoat(sourceID, boatName, shortName); } streamedBoatMap.put(sourceID, streamedBoat); // Override boat with new boat @@ -133,20 +128,6 @@ public class BoatXMLReader extends XMLReader { // TODO Get relative point before implementing. (GPSposition is based off a relative point). } - private void makeColours() { - colours = new ArrayList(Arrays.asList( - Color.BLUEVIOLET, - Color.BLACK, - Color.RED, - Color.ORANGE, - Color.DARKOLIVEGREEN, - Color.LIMEGREEN, - Color.PURPLE, - Color.DARKGRAY, - Color.YELLOW - )); - } - public void setParticipants(Map participants) { this.participants = participants; } @@ -154,4 +135,8 @@ public class BoatXMLReader extends XMLReader { public Map getStreamedBoatMap() { return streamedBoatMap; } + + public List getBoats() { + return new ArrayList<>(streamedBoatMap.values()); + } } diff --git a/visualiser/src/main/java/seng302/Mock/StreamedBoat.java b/visualiser/src/main/java/seng302/Mock/StreamedBoat.java index f31d2a71..19b27c9f 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedBoat.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedBoat.java @@ -1,44 +1,48 @@ package seng302.Mock; import javafx.scene.paint.Color; +import org.geotools.referencing.GeodeticCalculator; +import seng302.GPSCoordinate; +import seng302.Model.Boat; import seng302.Model.BoatInRace; +import seng302.Model.Leg; +import seng302.Model.Marker; /** * Created by Joseph on 24/04/2017. */ -public class StreamedBoat extends BoatInRace { +public class StreamedBoat extends Boat { private int sourceID; - private boolean complete; + private boolean dnf = false; - public StreamedBoat(int sourceID, String name, Color colour, String abbrev) { - super(name, colour, abbrev); - this.sourceID = sourceID; - this.complete = true; + private void init() { + this.velocity = 0; } - public StreamedBoat(int sourceID) { - super("None", Color.BLACK, "None"); + public StreamedBoat(int sourceID, String name, String abbrev) { + super(name, abbrev); this.sourceID = sourceID; - this.complete = false; + this.init(); } - - /** - * Overridden to ignore this function - * - * @return 0 - * @deprecated - */ - public double getScaledVelocity() { - return 0; + public StreamedBoat(int sourceID) { + super("None", "None"); + this.sourceID = sourceID; + this.init(); } /** - * Overridden to ignore this function + * Calculates the azimuth of the travel via heading of the boat * - * @param velocity of boat - * @deprecated + * @return the direction that the boat is heading towards in degrees (-180 to 180). */ - public void setScaledVelocity(double velocity) { + public double calculateAzimuth() { + double azimuth; + if (heading <= 180) { + azimuth = heading; + } else { + azimuth = -heading + 180; + } + return azimuth; } } diff --git a/visualiser/src/main/java/seng302/Mock/StreamedCourse.java b/visualiser/src/main/java/seng302/Mock/StreamedCourse.java index 85831bd8..fb46ee81 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedCourse.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedCourse.java @@ -1,15 +1,11 @@ package seng302.Mock; import seng302.GPSCoordinate; -import seng302.Model.BoatInRace; -import seng302.Model.Leg; -import seng302.Model.Marker; -import seng302.Model.RaceClock; +import seng302.Model.*; import seng302.RaceDataSource; import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; +import java.util.*; /** * Created by jjg64 on 21/04/17. @@ -44,16 +40,16 @@ public class StreamedCourse implements RaceDataSource { } } - public RegattaXMLReader getRegattaXMLReader() { - return regattaXMLReader; - } - public void setRegattaXMLReader(RegattaXMLReader regattaXMLReader) { this.regattaXMLReader = regattaXMLReader; } - public List getBoats() { - return new ArrayList<>(boatXMLReader.getStreamedBoatMap().values()); + public RegattaXMLReader getRegattaXMLReader() { + return regattaXMLReader; + } + + public List getBoats() { + return boatXMLReader.getBoats(); } public List getLegs() { diff --git a/visualiser/src/main/java/seng302/Mock/StreamedRace.java b/visualiser/src/main/java/seng302/Mock/StreamedRace.java index c44b6ce6..375d7502 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedRace.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedRace.java @@ -1,10 +1,16 @@ package seng302.Mock; +import javafx.collections.FXCollections; +import org.geotools.referencing.GeodeticCalculator; +import seng302.Constants; import seng302.Controllers.RaceController; -import seng302.Model.BoatInRace; -import seng302.Model.Race; +import seng302.GPSCoordinate; +import seng302.Model.*; import seng302.RaceDataSource; +import java.awt.geom.Point2D; +import java.util.*; + /** * Created by jjg64 on 21/04/17. */ @@ -14,18 +20,30 @@ public class StreamedRace extends Race { public StreamedRace(RaceDataSource raceData, RaceController controller, int scaleFactor) { super(raceData.getBoats(), raceData.getLegs(), controller, scaleFactor); this.raceData = raceData; + this.scaleFactor = 1; // There will be no scaling in a live streamed race } public void initialiseBoats() { + Leg officialStart = legs.get(0); + String name = officialStart.getName(); + Marker endMarker = officialStart.getEndMarker(); + for (int i = 0; i < startingBoats.size(); i++) { + Boat boat = startingBoats.get(i); + if (boat != null) { + Leg startLeg = new Leg(name, 0); + startLeg.setEndMarker(endMarker); + boat.setCurrentLeg(startLeg); + } + } } /** * Checks if the boat cannot finish the race - * * @return True if boat cannot finish the race */ protected boolean doNotFinish() { + // DNF is no longer random and is now determined by a dnf packet return false; } @@ -36,18 +54,30 @@ public class StreamedRace extends Race { * @param timeElapsed Time that has elapse since the start of the the race. * @see BoatInRace */ - protected void checkPosition(BoatInRace boat, long timeElapsed) { - + protected void checkPosition(Boat boat, long timeElapsed) { + if (boat.getCurrentLeg().getName().toLowerCase().contains("finish")) { + //boat has finished + boatsFinished++; + boat.setFinished(true); + boat.setTimeFinished(timeElapsed); + } + //Update the boat display table in the GUI to reflect the leg change + updatePositions(); } /** * Updates the boat's gps coordinates * - * @param boat to be updated + * @param boat to be updated * @param millisecondsElapsed time since last update */ - protected void updatePosition(BoatInRace boat, int millisecondsElapsed) { + protected void updatePosition(Boat boat, int millisecondsElapsed) { + //TODO Grab info from network + // setPostiion(boat, coordinate); + } + protected void setPostion(Boat boat, GPSCoordinate coordinate) { + boat.setCurrentPosition(coordinate); } } diff --git a/visualiser/src/main/java/seng302/Model/Boat.java b/visualiser/src/main/java/seng302/Model/Boat.java index 5b9842f2..c1102b3b 100644 --- a/visualiser/src/main/java/seng302/Model/Boat.java +++ b/visualiser/src/main/java/seng302/Model/Boat.java @@ -2,16 +2,39 @@ package seng302.Model; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import org.geotools.referencing.GeodeticCalculator; +import seng302.Constants; +import seng302.GPSCoordinate; + +import java.awt.geom.Point2D; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; /** * Created by fwy13 on 3/03/17. */ public class Boat { - private StringProperty name; - private double velocity; + protected StringProperty name; + protected double velocity; private StringProperty velocityProp; - private String abbrev; + protected String abbrev; + protected GPSCoordinate currentPosition; + protected double heading; + protected Leg currentLeg; + protected StringProperty currentLegName; + protected boolean finished = false; + protected long timeFinished; + protected StringProperty position; + protected boolean started = false; + private double wakeScale = 1 / 50; + + protected Queue track = new ConcurrentLinkedQueue<>(); + protected long nextValidTime = 0; + + protected static final float BASE_TRACK_POINT_TIME_INTERVAL = 5000; + protected static float trackPointTimeInterval = 5000; // every 1 seconds + protected final int TRACK_POINT_LIMIT = 10; /** * Boat initialiser which keeps all of the information of the boat. @@ -25,6 +48,8 @@ public class Boat { this.velocityProp = new SimpleStringProperty(String.valueOf(Math.round(velocity))); this.abbrev = abbrev; this.name = new SimpleStringProperty(name); + currentLegName = new SimpleStringProperty(""); + position = new SimpleStringProperty("-"); } /** @@ -34,8 +59,52 @@ public class Boat { * @param abbrev nam abbreviation */ public Boat(String name, String abbrev) { - this.abbrev = abbrev; - this.name = new SimpleStringProperty(name); + this(name, 0, abbrev); + } + + /** + * Returns the position of the end of the boat's wake, which is 180 degrees + * from the boat's heading, and whose length is proportional to the boat's + * speed. + * + * @return GPSCoordinate of wake endpoint. + */ + public GPSCoordinate getWake() { + double reverseHeading = getHeading() - 180; + double distance = wakeScale * getVelocity(); + + GeodeticCalculator calc = new GeodeticCalculator(); + calc.setStartingGeographicPoint( + new Point2D.Double(getCurrentPosition().getLongitude(), getCurrentPosition().getLatitude()) + ); + calc.setDirection(reverseHeading, distance); + Point2D endpoint = calc.getDestinationGeographicPoint(); + return new GPSCoordinate(endpoint.getY(), endpoint.getX()); + } + + /** + * Adds a new point to boat's track. + * @param coordinate of point on track + * @return whether add is successful + * @see seng302.Model.TrackPoint + */ + public boolean addTrackPoint(GPSCoordinate coordinate) { + Boolean added = System.currentTimeMillis() >= nextValidTime; + long currentTime = System.currentTimeMillis(); + if (added && this.started) { + nextValidTime = currentTime + (long) trackPointTimeInterval; + track.add(new TrackPoint(coordinate, currentTime, TRACK_POINT_LIMIT * (long) trackPointTimeInterval)); + } + return added; + } + + /** + * Returns the boat's sampled track between start of race and current time. + * @return queue of track points + * @see seng302.Model.TrackPoint + */ + public Queue getTrack() { + return track; } /** @@ -94,4 +163,67 @@ public class Boat { return abbrev; } + public GPSCoordinate getCurrentPosition() { + return currentPosition; + } + + public void setCurrentPosition(GPSCoordinate currentPosition) { + this.currentPosition = currentPosition; + } + + public double getHeading() { + return heading; + } + + public void setHeading(double heading) { + this.heading = heading; + } + + public Leg getCurrentLeg() { + return currentLeg; + } + + public void setCurrentLeg(Leg currentLeg) { + this.currentLeg = currentLeg; + this.currentLegName.setValue(currentLeg.getName()); + } + + public boolean isFinished() { + return finished; + } + + public void setFinished(boolean finished) { + this.finished = finished; + } + + public long getTimeFinished() { + return timeFinished; + } + + public void setTimeFinished(long timeFinished) { + this.timeFinished = timeFinished; + } + + public StringProperty positionProperty() { + return position; + } + + public void setPosition(String position) { + this.position.set(position); + } + + public boolean isStarted() { + return started; + } + + public void setStarted(boolean started) { + this.started = started; + } + + /** + * @return Name of boat's current leg + */ + public StringProperty getCurrentLegName() { + return currentLegName; + } } diff --git a/visualiser/src/main/java/seng302/Model/BoatInRace.java b/visualiser/src/main/java/seng302/Model/BoatInRace.java index 6b55c567..3cc3f8d7 100644 --- a/visualiser/src/main/java/seng302/Model/BoatInRace.java +++ b/visualiser/src/main/java/seng302/Model/BoatInRace.java @@ -17,10 +17,8 @@ import java.util.concurrent.ConcurrentLinkedQueue; */ public class BoatInRace extends Boat { - protected static final float BASE_TRACK_POINT_TIME_INTERVAL = 5000; - protected static float trackPointTimeInterval = 5000; // every 1 seconds - protected final int TRACK_POINT_LIMIT = 10; protected Leg currentLeg; + protected double scaledVelocity; protected double distanceTravelledInLeg; protected GPSCoordinate currentPosition; protected long timeFinished; @@ -30,10 +28,13 @@ public class BoatInRace extends Boat { protected boolean started = false; protected StringProperty position; protected double heading; + protected Queue track = new ConcurrentLinkedQueue<>(); protected long nextValidTime = 0; - protected boolean trackVisible = true; - private double scaledVelocity; + + protected static final float BASE_TRACK_POINT_TIME_INTERVAL = 5000; + protected static float trackPointTimeInterval = 5000; // every 1 seconds + protected final int TRACK_POINT_LIMIT = 10; /** * Constructor method. @@ -41,7 +42,7 @@ public class BoatInRace extends Boat { * @param name Name of the boat. * @param velocity Speed that the boat travels. * @param colour Colour the boat will be displayed as on the map - * @param abbrev of boat + * @param abbrev of boat */ public BoatInRace(String name, double velocity, Color colour, String abbrev) { super(name, velocity, abbrev); @@ -53,8 +54,8 @@ public class BoatInRace extends Boat { /** * Constructor method. * - * @param name Name of the boat. - * @param colour Colour the boat will be displayed as on the map + * @param name Name of the boat. + * @param colour Colour the boat will be displayed as on the map * @param abbrev of boat */ public BoatInRace(String name, Color colour, String abbrev) { @@ -64,38 +65,6 @@ public class BoatInRace extends Boat { position = new SimpleStringProperty("-"); } - /** - * Converts an azimuth to a bearing - * - * @param azimuth azimuth value to be converted - * @return the bearings in degrees (0 to 360). - */ - public static double calculateHeading(double azimuth) { - if (azimuth >= 0) { - return azimuth; - } else { - return azimuth + 360; - } - } - - /** - * Get base track point time interval - * - * @return base track point time interval - */ - public static float getBaseTrackPointTimeInterval() { - return BASE_TRACK_POINT_TIME_INTERVAL; - } - - /** - * Set track point time interval - * - * @param value track point time interval value - */ - public static void setTrackPointTimeInterval(float value) { - trackPointTimeInterval = value; - } - /** * Calculates the azimuth of the travel via map coordinates of the raceMarkers * @@ -113,6 +82,20 @@ public class BoatInRace extends Boat { return calc.getAzimuth(); } + /** + * Converts an azimuth to a bearing + * + * @param azimuth azimuth value to be converted + * @return the bearings in degrees (0 to 360). + */ + public static double calculateHeading(double azimuth) { + if (azimuth >= 0) { + return azimuth; + } else { + return azimuth + 360; + } + } + public double getHeading() { return heading; } @@ -127,7 +110,7 @@ public class BoatInRace extends Boat { * @return the direction that the boat is heading towards in degrees (0 to 360). */ public double calculateHeading() { - double azimuth = this.calculateAzimuth(); + double azimuth = calculateAzimuth(); return calculateHeading(azimuth); } @@ -292,17 +275,16 @@ public class BoatInRace extends Boat { return position.get(); } - public void setPosition(String position) { - this.position.set(position); - } - public StringProperty positionProperty() { return position; } + public void setPosition(String position) { + this.position.set(position); + } + /** * Adds a new point to boat's track. - * * @param coordinate of point on track * @return whether add is successful * @see seng302.Model.TrackPoint @@ -319,7 +301,6 @@ public class BoatInRace extends Boat { /** * Returns the boat's sampled track between start of race and current time. - * * @return queue of track points * @see seng302.Model.TrackPoint */ @@ -328,20 +309,18 @@ public class BoatInRace extends Boat { } /** - * Returns whether track is visible - * - * @return true if visible + * Get base track point time interval + * @return base track point time interval */ - public boolean isTrackVisible() { - return trackVisible; + public static float getBaseTrackPointTimeInterval() { + return BASE_TRACK_POINT_TIME_INTERVAL; } /** - * Sets track visibility. - * - * @param trackVisible visible if true. + * Set track point time interval + * @param value track point time interval value */ - public void setTrackVisible(boolean trackVisible) { - this.trackVisible = trackVisible; + public static void setTrackPointTimeInterval(float value) { + trackPointTimeInterval = value; } } diff --git a/visualiser/src/main/java/seng302/Model/ConstantVelocityRace.java b/visualiser/src/main/java/seng302/Model/ConstantVelocityRace.java index a0f415eb..47e699b3 100644 --- a/visualiser/src/main/java/seng302/Model/ConstantVelocityRace.java +++ b/visualiser/src/main/java/seng302/Model/ConstantVelocityRace.java @@ -1,209 +1,208 @@ -package seng302.Model; - -import org.geotools.referencing.GeodeticCalculator; -import seng302.Constants; -import seng302.Controllers.RaceController; -import seng302.GPSCoordinate; -import seng302.RaceDataSource; - -import java.awt.geom.Point2D; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -/** - * Created by cbt24 on 6/03/17. - * - * @deprecated - */ -public class ConstantVelocityRace extends Race { - - private int dnfChance = 0; //%percentage chance a boat fails at each checkpoint - - /** - * Initialiser for a constant velocity race without standard data source - * - * @param startingBoats in race - * @param legs in race - * @param controller for graphics - * @param scaleFactor of timer - */ - public ConstantVelocityRace(List startingBoats, List legs, RaceController controller, int scaleFactor) { - super(startingBoats, legs, controller, scaleFactor); - } - - /** - * Initialiser for legacy tests - * - * @param startingBoats in race - * @param legs in race - * @param controller for graphics - * @param scaleFactor of timer - * @deprecated Please use {@link #ConstantVelocityRace(List, List, RaceController, int) } for future tests. - */ - public ConstantVelocityRace(BoatInRace[] startingBoats, List legs, RaceController controller, int scaleFactor) { - super(Arrays.asList(startingBoats), legs, controller, scaleFactor); - } - - /** - * Initialiser for constant velocity race with standard data source - * - * @param raceData for race - * @param controller for graphics - * @param scaleFactor of timer - */ - public ConstantVelocityRace(RaceDataSource raceData, RaceController controller, int scaleFactor) { - super(raceData, controller, scaleFactor); - } - - /** - * Calculates the boats next GPS position based on its distance travelled and heading - * - * @param oldCoordinates GPS coordinates of the boat's starting position - * @param distanceTravelled distance in nautical miles - * @param azimuth boat's current direction. Value between -180 and 180 - * @return The boat's new coordinate - */ - public static GPSCoordinate calculatePosition(GPSCoordinate oldCoordinates, double distanceTravelled, double azimuth) { - - //Find new coordinate using current heading and distance - - GeodeticCalculator geodeticCalculator = new GeodeticCalculator(); - //Load start point into calculator - Point2D startPoint = new Point2D.Double(oldCoordinates.getLongitude(), oldCoordinates.getLatitude()); - geodeticCalculator.setStartingGeographicPoint(startPoint); - //load direction and distance tranvelled into calculator - geodeticCalculator.setDirection(azimuth, distanceTravelled * Constants.NMToMetersConversion); - //get new point - Point2D endPoint = geodeticCalculator.getDestinationGeographicPoint(); - - return new GPSCoordinate(endPoint.getY(), endPoint.getX()); - } - - public void initialiseBoats() { - Leg officialStart = legs.get(0); - String name = officialStart.getName(); - Marker endMarker = officialStart.getEndMarker(); - - BoatInRace.setTrackPointTimeInterval(BoatInRace.getBaseTrackPointTimeInterval() / scaleFactor); - - ArrayList startMarkers = getSpreadStartingPositions(); - for (int i = 0; i < startingBoats.size(); i++) { - BoatInRace boat = startingBoats.get(i); - if (boat != null) { - boat.setScaledVelocity(boat.getVelocity() * scaleFactor); - Leg startLeg = new Leg(name, 0); - boat.setCurrentPosition(startMarkers.get(i).getAverageGPSCoordinate()); - startLeg.setStartMarker(startMarkers.get(i)); - startLeg.setEndMarker(endMarker); - startLeg.calculateDistance(); - boat.setCurrentLeg(startLeg); - boat.setHeading(boat.calculateHeading()); - } - } - } - - /** - * Creates a list of starting positions for the different boats, so they do not appear cramped at the start line - * - * @return list of starting positions - */ - public ArrayList getSpreadStartingPositions() { - - int nBoats = startingBoats.size(); - Marker marker = legs.get(0).getStartMarker(); - - GeodeticCalculator initialCalc = new GeodeticCalculator(); - initialCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); - initialCalc.setDestinationGeographicPoint(marker.getMark2().getLongitude(), marker.getMark2().getLatitude()); - - double azimuth = initialCalc.getAzimuth(); - double distanceBetweenMarkers = initialCalc.getOrthodromicDistance(); - double distanceBetweenBoats = distanceBetweenMarkers / (nBoats + 1); - - GeodeticCalculator positionCalc = new GeodeticCalculator(); - positionCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); - ArrayList positions = new ArrayList<>(); - - for (int i = 0; i < nBoats; i++) { - positionCalc.setDirection(azimuth, distanceBetweenBoats); - Point2D position = positionCalc.getDestinationGeographicPoint(); - positions.add(new Marker(new GPSCoordinate(position.getY(), position.getX()))); - - positionCalc = new GeodeticCalculator(); - positionCalc.setStartingGeographicPoint(position); - } - return positions; - } - - /** - * Sets the chance each boat has of failing at a gate or marker - * - * @param chance percentage chance a boat has of failing per checkpoint. - */ - protected void setDnfChance(int chance) { - if (chance >= 0 && chance <= 100) { - dnfChance = chance; - } - } - - protected boolean doNotFinish() { - Random rand = new Random(); - return rand.nextInt(100) < dnfChance; - } - - /** - * Calculates the distance a boat has travelled and updates its current position according to this value. - * - * @param boat to be updated - * @param millisecondsElapsed since last update - */ - protected void updatePosition(BoatInRace boat, int millisecondsElapsed) { - - //distanceTravelled = velocity (nm p hr) * time taken to update loop - double distanceTravelled = (boat.getScaledVelocity() * millisecondsElapsed) / 3600000; - - double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg(); - - boolean finish = boat.getCurrentLeg().getName().equals("Finish"); - if (!finish) { - boat.setHeading(boat.calculateHeading()); - //update boat's distance travelled - boat.setDistanceTravelledInLeg(totalDistanceTravelled); - //Calculate boat's new position by adding the distance travelled onto the start point of the leg - boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartMarker().getAverageGPSCoordinate(), - totalDistanceTravelled, boat.calculateAzimuth())); - } - } - - protected void checkPosition(BoatInRace boat, long timeElapsed) { - if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) { - //boat has passed onto new leg - if (boat.getCurrentLeg().getName().equals("Finish")) { - //boat has finished - boatsFinished++; - boat.setFinished(true); - boat.setTimeFinished(timeElapsed); - } else if (doNotFinish()) { - boatsFinished++; - boat.setFinished(true); - boat.setCurrentLeg(new Leg("DNF", -1)); - boat.setVelocity(0); - boat.setScaledVelocity(0); - } else { - //Calculate how much the boat overshot the marker by - boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance()); - //Move boat on to next leg - Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1); - - boat.setCurrentLeg(nextLeg); - //Add overshoot distance into the distance travelled for the next leg - boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg()); - } - //Update the boat display table in the GUI to reflect the leg change - updatePositions(); - } - } - -} \ No newline at end of file +//package seng302.Model; +// +//import org.geotools.referencing.GeodeticCalculator; +//import seng302.Constants; +//import seng302.Controllers.RaceController; +//import seng302.GPSCoordinate; +//import seng302.RaceDataSource; +// +//import java.awt.geom.Point2D; +//import java.util.ArrayList; +//import java.util.Arrays; +//import java.util.List; +//import java.util.Random; +// +///** +// * Created by cbt24 on 6/03/17. +// * +// * @deprecated +// */ +//public class ConstantVelocityRace extends Race { +// +// private int dnfChance = 0; //%percentage chance a boat fails at each checkpoint +// +// /** +// * Initialiser for a constant velocity race without standard data source +// * +// * @param startingBoats in race +// * @param legs in race +// * @param controller for graphics +// * @param scaleFactor of timer +// */ +// public ConstantVelocityRace(List startingBoats, List legs, RaceController controller, int scaleFactor) { +// super(startingBoats, legs, controller, scaleFactor); +// } +// +// /** +// * Initialiser for legacy tests +// * +// * @param startingBoats in race +// * @param legs in race +// * @param controller for graphics +// * @param scaleFactor of timer +// * +// * @deprecated Please use {@link #ConstantVelocityRace(List, List, RaceController, int) } for future tests. +// */ +// public ConstantVelocityRace(BoatInRace[] startingBoats, List legs, RaceController controller, int scaleFactor) { +// super(Arrays.asList(startingBoats), legs, controller, scaleFactor); +// } +// +// /** +// * Initialiser for constant velocity race with standard data source +// * @param raceData for race +// * @param controller for graphics +// * @param scaleFactor of timer +// */ +// public ConstantVelocityRace(RaceDataSource raceData, RaceController controller, int scaleFactor) { +// super(raceData, controller, scaleFactor); +// } +// +// public void initialiseBoats() { +// Leg officialStart = legs.get(0); +// String name = officialStart.getName(); +// Marker endMarker = officialStart.getEndMarker(); +// +// BoatInRace.setTrackPointTimeInterval(BoatInRace.getBaseTrackPointTimeInterval() / scaleFactor); +// +// ArrayList startMarkers = getSpreadStartingPositions(); +// for (int i = 0; i < startingBoats.size(); i++) { +// BoatInRace boat = startingBoats.get(i); +// if (boat != null) { +// boat.setScaledVelocity(boat.getVelocity() * scaleFactor); +// Leg startLeg = new Leg(name, 0); +// boat.setCurrentPosition(startMarkers.get(i).getAverageGPSCoordinate()); +// startLeg.setStartMarker(startMarkers.get(i)); +// startLeg.setEndMarker(endMarker); +// startLeg.calculateDistance(); +// boat.setCurrentLeg(startLeg); +// boat.setHeading(boat.calculateHeading()); +// } +// } +// } +// +// /** +// * Creates a list of starting positions for the different boats, so they do not appear cramped at the start line +// * +// * @return list of starting positions +// */ +// public ArrayList getSpreadStartingPositions() { +// +// int nBoats = startingBoats.size(); +// Marker marker = legs.get(0).getStartMarker(); +// +// GeodeticCalculator initialCalc = new GeodeticCalculator(); +// initialCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); +// initialCalc.setDestinationGeographicPoint(marker.getMark2().getLongitude(), marker.getMark2().getLatitude()); +// +// double azimuth = initialCalc.getAzimuth(); +// double distanceBetweenMarkers = initialCalc.getOrthodromicDistance(); +// double distanceBetweenBoats = distanceBetweenMarkers / (nBoats + 1); +// +// GeodeticCalculator positionCalc = new GeodeticCalculator(); +// positionCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); +// ArrayList positions = new ArrayList<>(); +// +// for (int i = 0; i < nBoats; i++) { +// positionCalc.setDirection(azimuth, distanceBetweenBoats); +// Point2D position = positionCalc.getDestinationGeographicPoint(); +// positions.add(new Marker(new GPSCoordinate(position.getY(), position.getX()))); +// +// positionCalc = new GeodeticCalculator(); +// positionCalc.setStartingGeographicPoint(position); +// } +// return positions; +// } +// +// /** +// * Sets the chance each boat has of failing at a gate or marker +// * @param chance percentage chance a boat has of failing per checkpoint. +// */ +// protected void setDnfChance(int chance) { +// if (chance >= 0 && chance <= 100) { +// dnfChance = chance; +// } +// } +// +// protected boolean doNotFinish() { +// Random rand = new Random(); +// return rand.nextInt(100) < dnfChance; +// } +// +// /** +// * Calculates the distance a boat has travelled and updates its current position according to this value. +// * +// * @param boat to be updated +// * @param millisecondsElapsed since last update +// */ +// protected void updatePosition(BoatInRace boat, int millisecondsElapsed) { +// +// //distanceTravelled = velocity (nm p hr) * time taken to update loop +// double distanceTravelled = (boat.getScaledVelocity() * millisecondsElapsed) / 3600000; +// +// double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg(); +// +// boolean finish = boat.getCurrentLeg().getName().equals("Finish"); +// if (!finish) { +// boat.setHeading(boat.calculateHeading()); +// //update boat's distance travelled +// boat.setDistanceTravelledInLeg(totalDistanceTravelled); +// //Calculate boat's new position by adding the distance travelled onto the start point of the leg +// boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartMarker().getAverageGPSCoordinate(), +// totalDistanceTravelled, boat.calculateAzimuth())); +// } +// } +// +// protected void checkPosition(BoatInRace boat, long timeElapsed) { +// if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) { +// //boat has passed onto new leg +// if (boat.getCurrentLeg().getName().equals("Finish")) { +// //boat has finished +// boatsFinished++; +// boat.setFinished(true); +// boat.setTimeFinished(timeElapsed); +// } else if (doNotFinish()) { +// boatsFinished++; +// boat.setFinished(true); +// boat.setCurrentLeg(new Leg("DNF", -1)); +// boat.setVelocity(0); +// boat.setScaledVelocity(0); +// } else { +// //Calculate how much the boat overshot the marker by +// boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance()); +// //Move boat on to next leg +// Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1); +// +// boat.setCurrentLeg(nextLeg); +// //Add overshoot distance into the distance travelled for the next leg +// boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg()); +// } +// //Update the boat display table in the GUI to reflect the leg change +// updatePositions(); +// } +// } +// +// /** +// * Calculates the boats next GPS position based on its distance travelled and heading +// * +// * @param oldCoordinates GPS coordinates of the boat's starting position +// * @param distanceTravelled distance in nautical miles +// * @param azimuth boat's current direction. Value between -180 and 180 +// * @return The boat's new coordinate +// */ +// public static GPSCoordinate calculatePosition(GPSCoordinate oldCoordinates, double distanceTravelled, double azimuth) { +// +// //Find new coordinate using current heading and distance +// +// GeodeticCalculator geodeticCalculator = new GeodeticCalculator(); +// //Load start point into calculator +// Point2D startPoint = new Point2D.Double(oldCoordinates.getLongitude(), oldCoordinates.getLatitude()); +// geodeticCalculator.setStartingGeographicPoint(startPoint); +// //load direction and distance tranvelled into calculator +// geodeticCalculator.setDirection(azimuth, distanceTravelled * Constants.NMToMetersConversion); +// //get new point +// Point2D endPoint = geodeticCalculator.getDestinationGeographicPoint(); +// +// return new GPSCoordinate(endPoint.getY(), endPoint.getX()); +// } +// +//} \ No newline at end of file diff --git a/visualiser/src/main/java/seng302/Model/Race.java b/visualiser/src/main/java/seng302/Model/Race.java index 8ff0aaa4..ed36fc92 100644 --- a/visualiser/src/main/java/seng302/Model/Race.java +++ b/visualiser/src/main/java/seng302/Model/Race.java @@ -5,37 +5,44 @@ import javafx.animation.AnimationTimer; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import org.geotools.referencing.GeodeticCalculator; import seng302.Controllers.RaceController; +import seng302.GPSCoordinate; import seng302.RaceDataSource; +import java.awt.geom.Point2D; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Random; /** * Parent class for races * Created by fwy13 on 3/03/17. */ public abstract class Race implements Runnable { - //protected BoatInRace[] startingBoats; - protected ObservableList startingBoats; + //protected Boat[] startingBoats; + protected ObservableList startingBoats; protected List legs; protected RaceController controller; protected int boatsFinished = 0; protected long totalTimeElapsed; + private int lastFPS = 20; + protected int scaleFactor; + protected int PRERACE_TIME = 120000; //time in milliseconds to pause during pre-race - private int lastFPS = 20; private boolean timerEnabled = true; //boolean to determine if timer is ran /** * Initailiser for Race * - * @param boats Takes in an array of boats that are participating in the race. - * @param legs Number of marks in order that the boats pass in order to complete the race. - * @param controller race controller + * @param boats Takes in an array of boats that are participating in the race. + * @param legs Number of marks in order that the boats pass in order to complete the race. + * @param controller race controller * @param scaleFactor for race */ - public Race(List boats, List legs, RaceController controller, int scaleFactor) { + public Race(List boats, List legs, RaceController controller, int scaleFactor) { this.startingBoats = FXCollections.observableArrayList(boats); this.legs = legs; @@ -47,19 +54,25 @@ public abstract class Race implements Runnable { } } - public Race(BoatInRace[] startingBoats, List legs, RaceController controller, int scaleFactor) { - this(Arrays.asList(startingBoats), legs, controller, scaleFactor); - } - public Race(RaceDataSource raceData, RaceController controller, int scaleFactor) { this(raceData.getBoats(), raceData.getLegs(), controller, scaleFactor); } + /** + * @deprecated + * @param startingBoats + * @param legs + * @param controller + * @param scaleFactor + */ + public Race(Boat[] startingBoats, List legs, RaceController controller, int scaleFactor) { + this(Arrays.asList(startingBoats), legs, controller, scaleFactor); + } + public abstract void initialiseBoats(); /** * Checks if the boat cannot finish the race - * * @return True if boat cannot finish the race */ protected abstract boolean doNotFinish(); @@ -69,17 +82,17 @@ public abstract class Race implements Runnable { * * @param boat Boat that the postion is to be updated for. * @param timeElapsed Time that has elapse since the start of the the race. - * @see BoatInRace + * @see Boat */ - protected abstract void checkPosition(BoatInRace boat, long timeElapsed); + protected abstract void checkPosition(Boat boat, long timeElapsed); /** * Updates the boat's gps coordinates * - * @param boat to be updated + * @param boat to be updated * @param millisecondsElapsed time since last update */ - protected abstract void updatePosition(BoatInRace boat, int millisecondsElapsed); + protected abstract void updatePosition(Boat boat, int millisecondsElapsed); /** * Runnable for the thread. @@ -105,7 +118,7 @@ public abstract class Race implements Runnable { protected void countdownTimer() { new AnimationTimer() { long currentTime = System.currentTimeMillis(); - long startTime = currentTime + (PRERACE_TIME / scaleFactor); + long startTime = currentTime + (PRERACE_TIME/scaleFactor); long minutes; long currentTimeInSeconds; long remainingSeconds; @@ -114,22 +127,22 @@ public abstract class Race implements Runnable { @Override public void handle(long arg0) { - timeLeft = startTime - currentTime; - if (timeLeft <= 0 && controller != null) { - updateTime("Race is starting..."); - stop(); - simulateRace(); - } else { - currentTimeInSeconds = (timeLeft * scaleFactor) / 1000; - minutes = currentTimeInSeconds / 60; - remainingSeconds = currentTimeInSeconds % 60; - hours = minutes / 60; - minutes = minutes % 60; - if (controller != null) { - updateTime(String.format("Race clock: -%02d:%02d:%02d", hours, minutes, remainingSeconds)); + timeLeft = startTime - currentTime; + if (timeLeft <= 0 && controller != null) { + updateTime("Race is starting..."); + stop(); + simulateRace(); + } else { + currentTimeInSeconds = (timeLeft*scaleFactor) / 1000; + minutes = currentTimeInSeconds / 60; + remainingSeconds = currentTimeInSeconds % 60; + hours = minutes / 60; + minutes = minutes % 60; + if (controller != null) { + updateTime(String.format("Race clock: -%02d:%02d:%02d", hours, minutes, remainingSeconds)); + } } - } - currentTime = System.currentTimeMillis(); + currentTime = System.currentTimeMillis(); } }.start(); } @@ -183,7 +196,7 @@ public abstract class Race implements Runnable { System.setProperty("javafx.animation.fullspeed", "true"); - for (BoatInRace boat : startingBoats) { + for (Boat boat : startingBoats) { boat.setStarted(true); } @@ -199,7 +212,7 @@ public abstract class Race implements Runnable { if (boatsFinished < startingBoats.size()) { totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted; - for (BoatInRace boat : startingBoats) { + for (Boat boat : startingBoats) { if (boat != null && !boat.isFinished()) { boat.addTrackPoint(boat.getCurrentPosition()); updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS)); @@ -228,8 +241,8 @@ public abstract class Race implements Runnable { */ protected void updatePositions() { FXCollections.sort(startingBoats, (a, b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber()); - for (BoatInRace boat : startingBoats) { - if (boat != null) { + for(Boat boat: startingBoats) { + if(boat != null) { boat.setPosition(Integer.toString(startingBoats.indexOf(boat) + 1)); if (boat.getCurrentLeg().getName().equals("DNF") || boat.getCurrentLeg().getLegNumber() == 0) boat.setPosition("-"); @@ -247,11 +260,11 @@ public abstract class Race implements Runnable { /** * Returns the boats that have started the race. * - * @return ObservableList of BoatInRace class that participated in the race. + * @return ObservableList of Boat class that participated in the race. * @see ObservableList - * @see BoatInRace + * @see Boat */ - public ObservableList getStartingBoats() { + public ObservableList getStartingBoats() { return startingBoats; } } diff --git a/visualiser/src/main/java/seng302/Model/RaceClock.java b/visualiser/src/main/java/seng302/Model/RaceClock.java index 7f64e50e..4fe25c30 100644 --- a/visualiser/src/main/java/seng302/Model/RaceClock.java +++ b/visualiser/src/main/java/seng302/Model/RaceClock.java @@ -57,6 +57,7 @@ public class RaceClock { } public String getTimeZone() { + System.out.println(zoneId.toString()); return zoneId.toString(); } diff --git a/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java b/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java index 66ccb518..dc062c20 100644 --- a/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java +++ b/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java @@ -21,12 +21,13 @@ import java.util.List; public class ResizableRaceCanvas extends Canvas { private GraphicsContext gc; private RaceMap map; - private List boats; + private List boats; private boolean raceAnno = true; private boolean annoName = true; private boolean annoAbbrev = true; private boolean annoSpeed = true; private boolean annoPath = true; + private List colours; private List raceBoundaries; private List markers; double[] xpoints = {}, ypoints = {}; @@ -46,6 +47,7 @@ public class ResizableRaceCanvas extends Canvas { this.raceBoundaries = raceData.getBoundary(); this.markers = raceData.getMarkers(); + makeColours(); } /** @@ -53,7 +55,7 @@ public class ResizableRaceCanvas extends Canvas { * * @param boats in race */ - public void setBoats(List boats) { + public void setBoats(List boats) { this.boats = boats; } @@ -81,9 +83,9 @@ public class ResizableRaceCanvas extends Canvas { gc.fillOval(graphCoordinate.getX() - (d / 2), graphCoordinate.getY() - (d / 2), d, d); } - public void displayBoat(BoatInRace boat, double angle) { + public void displayBoat(Boat boat, double angle, Color colour) { GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition()); - Paint paint = boat.getColour(); + Paint paint = colour; double[] x = {pos.getX() - 6, pos.getX(), pos.getX() + 6}; double[] y = {pos.getY() + 12, pos.getY() - 12, pos.getY() + 12}; @@ -322,27 +324,29 @@ public class ResizableRaceCanvas extends Canvas { * Draws boats while race in progress, when leg heading is set. */ public void updateBoats() { + int currentColour = 0; // TODO Remove null when boats are ready boats = null; if (boats != null) { - for (BoatInRace boat : boats) { + for (Boat boat : boats) { boolean finished = boat.getCurrentLeg().getName().equals("Finish") || boat.getCurrentLeg().getName().equals("DNF"); boolean isStart = boat.isStarted(); if (!finished && isStart) { - displayBoat(boat, boat.getHeading()); + displayBoat(boat, boat.getHeading(), colours.get(currentColour)); GraphCoordinate wakeFrom = this.map.convertGPS(boat.getCurrentPosition()); GraphCoordinate wakeTo = this.map.convertGPS(boat.getWake()); - displayLine(wakeFrom, wakeTo, boat.getColour()); + displayLine(wakeFrom, wakeTo, colours.get(currentColour)); } else if (!isStart) { - displayBoat(boat, boat.getHeading()); + displayBoat(boat, boat.getHeading(), colours.get(currentColour)); } else { - displayBoat(boat, 0); + displayBoat(boat, 0, colours.get(currentColour)); } if (raceAnno) displayText(boat.toString(), boat.getAbbrev(), boat.getVelocity(), this.map.convertGPS(boat.getCurrentPosition())); - if(boat.isTrackVisible()) drawTrack(boat); + drawTrack(boat, colours.get(currentColour)); + currentColour = (currentColour + 1) % colours.size(); } } } @@ -352,11 +356,11 @@ public class ResizableRaceCanvas extends Canvas { * @param boat whose track is displayed * @see seng302.Model.TrackPoint */ - private void drawTrack(BoatInRace boat) { + private void drawTrack(Boat boat, Color colour) { if (annoPath && raceAnno) { for (TrackPoint point : boat.getTrack()) { GraphCoordinate scaledCoordinate = this.map.convertGPS(point.getCoordinate()); - Color boatColour = boat.getColour(); + Color boatColour = colour; gc.setFill(new Color(boatColour.getRed(), boatColour.getGreen(), boatColour.getBlue(), point.getAlpha())); gc.fillOval(scaledCoordinate.getX(), scaledCoordinate.getY(), 5, 5); } @@ -381,6 +385,20 @@ public class ResizableRaceCanvas extends Canvas { } } + private void makeColours() { + colours = new ArrayList(Arrays.asList( + Color.BLUEVIOLET, + Color.BLACK, + Color.RED, + Color.ORANGE, + Color.DARKOLIVEGREEN, + Color.LIMEGREEN, + Color.PURPLE, + Color.DARKGRAY, + Color.YELLOW + )); + } + /** * Set the Canvas to resizable. * diff --git a/visualiser/src/main/java/seng302/RaceDataSource.java b/visualiser/src/main/java/seng302/RaceDataSource.java index c309661b..8d6a1d1c 100644 --- a/visualiser/src/main/java/seng302/RaceDataSource.java +++ b/visualiser/src/main/java/seng302/RaceDataSource.java @@ -1,5 +1,6 @@ package seng302; +import seng302.Model.Boat; import seng302.Model.BoatInRace; import seng302.Model.Leg; import seng302.Model.Marker; @@ -11,7 +12,7 @@ import java.util.List; * Created by connortaylorbrown on 19/04/17. */ public interface RaceDataSource { - List getBoats(); + List getBoats(); List getLegs(); List getMarkers(); List getBoundary(); diff --git a/visualiser/src/main/java/seng302/RaceXMLReader.java b/visualiser/src/main/java/seng302/RaceXMLReader.java index 2f0df23e..8be2b022 100644 --- a/visualiser/src/main/java/seng302/RaceXMLReader.java +++ b/visualiser/src/main/java/seng302/RaceXMLReader.java @@ -4,10 +4,7 @@ import javafx.scene.paint.Color; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import seng302.Model.BoatInRace; -import seng302.Model.Leg; -import seng302.Model.Marker; -import seng302.Model.RaceClock; +import seng302.Model.*; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; @@ -20,20 +17,19 @@ import java.util.List; * @deprecated use {@link seng302.Mock.StreamedCourseXMLReader} */ public class RaceXMLReader extends XMLReader implements RaceDataSource { - private static double COORDINATEPADDING = 0.0005; - private List boats = new ArrayList<>(); + private List boats = new ArrayList<>(); private Color[] colors = {Color.BLUEVIOLET, Color.BLACK, Color.RED, Color.ORANGE, Color.DARKOLIVEGREEN, Color.LIMEGREEN};//TODO make this established in xml or come up with a better system. private List legs = new ArrayList<>(); private GPSCoordinate mark, startPt1, startPt2, finishPt1, finishPt2, leewardPt1, leewardPt2, windwardPt1, windwardPt2; private GPSCoordinate mapTopLeft, mapBottomRight; private List boundary = new ArrayList<>(); + private static double COORDINATEPADDING = 0.0005; /** * Constractor for Race XML - * * @param filePath path of the file - * @throws IOException error - * @throws SAXException error + * @throws IOException error + * @throws SAXException error * @throws ParserConfigurationException error */ public RaceXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException { @@ -42,11 +38,10 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { /** * COnstructor for Race XML - * * @param filePath file path to read - * @param read whether or not to read and store the files straight away. - * @throws IOException error - * @throws SAXException error + * @param read whether or not to read and store the files straight away. + * @throws IOException error + * @throws SAXException error * @throws ParserConfigurationException error */ public RaceXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException { @@ -67,7 +62,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { /** * Read all the boats in the XML file - */ + */ public void readBoats() { //get all boats NodeList nBoats = doc.getElementsByTagName("boat"); @@ -174,7 +169,6 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { /** * gets a marker from the XML file - * * @param start base nodelist this should be the tag that contains * @return */ @@ -184,8 +178,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { /** * gets a marker from the XML file - * - * @param start base nodelist this should be the tag that contains + * @param start base nodelist this should be the tag that contains * @param startIndex index in the node that has the coordinate tag * @return */ @@ -195,10 +188,9 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { /** * gets a marker from the XML file - * - * @param start base nodelist this should be the tag that contains + * @param start base nodelist this should be the tag that contains * @param startIndex index in the node that has the coordinate tag - * @param nodeIndex coordinate index + * @param nodeIndex coordinate index * @return */ private Marker getMarker(NodeList start, int startIndex, int nodeIndex) { @@ -209,7 +201,6 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { /** * gets a changes a marker to GPS coordinates into a marker - * * @param markerNode marker to turn into coordinates * @return */ @@ -230,7 +221,6 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { /** * gets a coordinates from the XML file - * * @param start base nodelist this should be the tag that contains * @return */ @@ -238,10 +228,9 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { return getCoordinates(start, 0); } - /** + /** * gets a coordinates from the XML file - * - * @param start base nodelist this should be the tag that contains + * @param start base nodelist this should be the tag that contains * @param startIndex the index the tag containing the coordinate should be in * @return */ @@ -249,12 +238,11 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { return getCoordinates(start, startIndex, 0); } - /** + /** * gets a coordinates from the XML file - * - * @param start base nodelist this should be the tag that contains + * @param start base nodelist this should be the tag that contains * @param startIndex the index the tag containing the coordinate should be in - * @param nodeIndex The coordinate index + * @param nodeIndex The coordinate index * @return */ private GPSCoordinate getCoordinates(NodeList start, int startIndex, int nodeIndex) { @@ -281,7 +269,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { return null; } - public List getBoats() { + public List getBoats() { return boats; } diff --git a/visualiser/src/test/java/seng302/Model/ConstantVelocityRaceTest.java b/visualiser/src/test/java/seng302/Model/ConstantVelocityRaceTest.java index 25877897..3094dad4 100644 --- a/visualiser/src/test/java/seng302/Model/ConstantVelocityRaceTest.java +++ b/visualiser/src/test/java/seng302/Model/ConstantVelocityRaceTest.java @@ -1,139 +1,140 @@ -package seng302.Model; - - -import javafx.scene.paint.Color; -import org.geotools.referencing.GeodeticCalculator; -import org.junit.Test; -import seng302.Constants; -import seng302.GPSCoordinate; - -import java.util.ArrayList; - -import static org.junit.Assert.assertEquals; - -/** - * Created by esa46 on 16/03/17. - */ -public class ConstantVelocityRaceTest { - - Marker START_MARKER = new Marker(new GPSCoordinate(0, 0)); - Marker END_MARKER = new Marker(new GPSCoordinate(10, 10)); - Leg START_LEG = new Leg("Start", START_MARKER, END_MARKER, 0); - - int ONE_HOUR = 3600000; //1 hour in milliseconds - - - private ArrayList generateLegsArray() { - ArrayList legs = new ArrayList<>(); - legs.add(START_LEG); - return legs; - } - - @Test - public void updatePositionChangesDistanceTravelled() { - ArrayList legs = generateLegsArray(); - BoatInRace boat = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt"); - boat.setCurrentLeg(legs.get(0)); - boat.setDistanceTravelledInLeg(0); - BoatInRace[] boats = new BoatInRace[]{boat}; - - ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1); - - race.updatePosition(boat, ONE_HOUR); - assertEquals(boat.getDistanceTravelledInLeg(), boat.getVelocity(), 1e-8); - } - - - @Test - public void updatePositionHandlesNoChangeToDistanceTravelled() { - - ArrayList legs = generateLegsArray(); - BoatInRace boat = new BoatInRace("Test", 0, Color.ALICEBLUE, "tt"); - boat.setCurrentLeg(legs.get(0)); - boat.setDistanceTravelledInLeg(0); - BoatInRace[] boats = new BoatInRace[]{boat}; - - ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1); - - race.updatePosition(boat, ONE_HOUR); - assertEquals(boat.getDistanceTravelledInLeg(), 0, 1e-8); - } - - @Test - public void changesToDistanceTravelledAreAdditive() { - - ArrayList legs = generateLegsArray(); - BoatInRace boat = new BoatInRace("Test", 5, Color.ALICEBLUE, "tt"); - boat.setCurrentLeg(legs.get(0)); - boat.setDistanceTravelledInLeg(50); - BoatInRace[] boats = new BoatInRace[]{boat}; - - ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1); - - race.updatePosition(boat, ONE_HOUR); - assertEquals(boat.getDistanceTravelledInLeg(), boat.getVelocity() + 50, 1e-8); - } - - @Test - public void travelling10nmNorthGivesCorrectNewCoordinates() { - GPSCoordinate oldPos = new GPSCoordinate(0, 0); - GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 0); - - GeodeticCalculator calc = new GeodeticCalculator(); - calc.setStartingGeographicPoint(0, 0); - calc.setDirection(0, 10 * Constants.NMToMetersConversion); - - assertEquals(newPos.getLongitude(), 0, 1e-8); - assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8); - assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8); - } - - - @Test - public void travelling10nmEastGivesCorrectNewCoordinates() { - GPSCoordinate oldPos = new GPSCoordinate(0, 0); - GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 90); - - GeodeticCalculator calc = new GeodeticCalculator(); - calc.setStartingGeographicPoint(0, 0); - calc.setDirection(90, 10 * Constants.NMToMetersConversion); - - - assertEquals(newPos.getLatitude(), 0, 1e-8); - assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8); - assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8); - } - - - @Test - public void travelling10nmWestGivesCorrectNewCoordinates() { - GPSCoordinate oldPos = new GPSCoordinate(0, 0); - GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, -90); - - GeodeticCalculator calc = new GeodeticCalculator(); - calc.setStartingGeographicPoint(0, 0); - calc.setDirection(-90, 10 * Constants.NMToMetersConversion); - - - assertEquals(newPos.getLatitude(), 0, 1e-8); - assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8); - assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8); - } - - - @Test - public void travelling10nmSouthGivesCorrectNewCoordinates() { - GPSCoordinate oldPos = new GPSCoordinate(0, 0); - GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 180); - - GeodeticCalculator calc = new GeodeticCalculator(); - calc.setStartingGeographicPoint(0, 0); - calc.setDirection(180, 10 * Constants.NMToMetersConversion); - - - assertEquals(newPos.getLongitude(), 0, 1e-8); - assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8); - assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8); - } - -} +//package seng302.Model; +// +// +//import javafx.scene.paint.Color; +//import org.geotools.referencing.GeodeticCalculator; +//import org.junit.Test; +//import seng302.Constants; +//import seng302.GPSCoordinate; +// +//import java.lang.reflect.Array; +//import java.util.ArrayList; +// +//import static org.junit.Assert.assertEquals; +// +///** +// * Created by esa46 on 16/03/17. +// */ +//public class ConstantVelocityRaceTest { +// +// Marker START_MARKER = new Marker(new GPSCoordinate(0, 0)); +// Marker END_MARKER = new Marker(new GPSCoordinate(10, 10)); +// Leg START_LEG = new Leg("Start", START_MARKER, END_MARKER, 0); +// +// int ONE_HOUR = 3600000; //1 hour in milliseconds +// +// +// private ArrayList generateLegsArray() { +// ArrayList legs = new ArrayList<>(); +// legs.add(START_LEG); +// return legs; +// } +// +// @Test +// public void updatePositionChangesDistanceTravelled() { +// ArrayList legs = generateLegsArray(); +// BoatInRace boat = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt"); +// boat.setCurrentLeg(legs.get(0)); +// boat.setDistanceTravelledInLeg(0); +// BoatInRace[] boats = new BoatInRace[]{boat}; +// +// ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1); +// +// race.updatePosition(boat, ONE_HOUR); +// assertEquals(boat.getDistanceTravelledInLeg(), boat.getVelocity(), 1e-8); +// } +// +// +// @Test +// public void updatePositionHandlesNoChangeToDistanceTravelled() { +// +// ArrayList legs = generateLegsArray(); +// BoatInRace boat = new BoatInRace("Test", 0, Color.ALICEBLUE, "tt"); +// boat.setCurrentLeg(legs.get(0)); +// boat.setDistanceTravelledInLeg(0); +// BoatInRace[] boats = new BoatInRace[]{boat}; +// +// ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1); +// +// race.updatePosition(boat, ONE_HOUR); +// assertEquals(boat.getDistanceTravelledInLeg(), 0, 1e-8); +// } +// +// @Test +// public void changesToDistanceTravelledAreAdditive() { +// +// ArrayList legs = generateLegsArray(); +// BoatInRace boat = new BoatInRace("Test", 5, Color.ALICEBLUE, "tt"); +// boat.setCurrentLeg(legs.get(0)); +// boat.setDistanceTravelledInLeg(50); +// BoatInRace[] boats = new BoatInRace[]{boat}; +// +// ConstantVelocityRace race = new ConstantVelocityRace(boats, legs, null, 1); +// +// race.updatePosition(boat, ONE_HOUR); +// assertEquals(boat.getDistanceTravelledInLeg(), boat.getVelocity() + 50, 1e-8); +// } +// +// @Test +// public void travelling10nmNorthGivesCorrectNewCoordinates() { +// GPSCoordinate oldPos = new GPSCoordinate(0, 0); +// GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 0); +// +// GeodeticCalculator calc = new GeodeticCalculator(); +// calc.setStartingGeographicPoint(0, 0); +// calc.setDirection(0, 10 * Constants.NMToMetersConversion); +// +// assertEquals(newPos.getLongitude(), 0, 1e-8); +// assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8); +// assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8); +// } +// +// +// @Test +// public void travelling10nmEastGivesCorrectNewCoordinates() { +// GPSCoordinate oldPos = new GPSCoordinate(0, 0); +// GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 90); +// +// GeodeticCalculator calc = new GeodeticCalculator(); +// calc.setStartingGeographicPoint(0, 0); +// calc.setDirection(90, 10 * Constants.NMToMetersConversion); +// +// +// assertEquals(newPos.getLatitude(), 0, 1e-8); +// assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8); +// assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8); +// } +// +// +// @Test +// public void travelling10nmWestGivesCorrectNewCoordinates() { +// GPSCoordinate oldPos = new GPSCoordinate(0, 0); +// GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, -90); +// +// GeodeticCalculator calc = new GeodeticCalculator(); +// calc.setStartingGeographicPoint(0, 0); +// calc.setDirection(-90, 10 * Constants.NMToMetersConversion); +// +// +// assertEquals(newPos.getLatitude(), 0, 1e-8); +// assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8); +// assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8); +// } +// +// +// @Test +// public void travelling10nmSouthGivesCorrectNewCoordinates() { +// GPSCoordinate oldPos = new GPSCoordinate(0, 0); +// GPSCoordinate newPos = ConstantVelocityRace.calculatePosition(oldPos, 10, 180); +// +// GeodeticCalculator calc = new GeodeticCalculator(); +// calc.setStartingGeographicPoint(0, 0); +// calc.setDirection(180, 10 * Constants.NMToMetersConversion); +// +// +// assertEquals(newPos.getLongitude(), 0, 1e-8); +// assertEquals(newPos.getLatitude(), calc.getDestinationGeographicPoint().getY(), 1e-8); +// assertEquals(newPos.getLongitude(), calc.getDestinationGeographicPoint().getX(), 1e-8); +// } +// +//} diff --git a/visualiser/src/test/java/seng302/Model/RaceXMLTest.java b/visualiser/src/test/java/seng302/Model/RaceXMLTest.java index 0101ddc6..21b6ff3f 100644 --- a/visualiser/src/test/java/seng302/Model/RaceXMLTest.java +++ b/visualiser/src/test/java/seng302/Model/RaceXMLTest.java @@ -26,7 +26,7 @@ public class RaceXMLTest { try { RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false); raceXMLReader.readBoats(); - List boats = raceXMLReader.getBoats(); + List boats = raceXMLReader.getBoats(); assertTrue(boats.size() == 6); //test boat 1 assertEquals(boats.get(0).getName().getValue(), "ORACLE TEAM USA");