diff --git a/visualiser/src/main/java/seng302/Mock/StreamedBoat.java b/visualiser/src/main/java/seng302/Mock/StreamedBoat.java index 0ff629a0..ad458e4b 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedBoat.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedBoat.java @@ -1,44 +1,60 @@ 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 { private int sourceID; - private boolean complete; + private boolean dnf = false; + + private void init() { + this.velocity = 0; + this.scaledVelocity = 0; + this.heading = 0; + this.setCurrentLeg(new Leg("None", -1)); + this.setCurrentPosition(new GPSCoordinate(0, 0)); + } public StreamedBoat(int sourceID, String name, Color colour, String abbrev) { super(name, colour, abbrev); this.sourceID = sourceID; - this.complete = true; + this.init(); } public StreamedBoat(int sourceID) { super("None", Color.BLACK, "None"); this.sourceID = sourceID; - this.complete = false; + this.init(); } - /** - * Overridden to ignore this function - * @deprecated - * @return 0 + * Calculates the azimuth of the travel via heading of the boat + * + * @return the direction that the boat is heading towards in degrees (-180 to 180). */ - public double getScaledVelocity() { - return 0; + public double calculateAzimuth() { + double azimuth; + if (heading <= 180) { + azimuth = heading; + } else { + azimuth = -heading + 180; + } + return azimuth; } - /** - * Overridden to ignore this function - * @deprecated - * @param velocity of boat - */ - public void setScaledVelocity(double velocity) { + public boolean isDnf() { + return dnf; + } + + public void setDnf(boolean dnf) { + this.dnf = dnf; } } diff --git a/visualiser/src/main/java/seng302/Mock/StreamedRace.java b/visualiser/src/main/java/seng302/Mock/StreamedRace.java index 56b6a114..c1035d7b 100644 --- a/visualiser/src/main/java/seng302/Mock/StreamedRace.java +++ b/visualiser/src/main/java/seng302/Mock/StreamedRace.java @@ -1,12 +1,14 @@ 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.Leg; -import seng302.Model.Race; +import seng302.GPSCoordinate; +import seng302.Model.*; import seng302.RaceDataSource; +import java.awt.geom.Point2D; import java.util.*; /** @@ -18,10 +20,23 @@ 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++) { + BoatInRace boat = startingBoats.get(i); + if (boat != null) { + Leg startLeg = new Leg(name, 0); + startLeg.setEndMarker(endMarker); + boat.setCurrentLeg(startLeg); + boat.setHeading(boat.calculateHeading()); + } + } } /** @@ -29,6 +44,7 @@ public class StreamedRace extends 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; } @@ -39,17 +55,86 @@ public class StreamedRace extends Race { * @param timeElapsed Time that has elapse since the start of the the race. * @see BoatInRace */ + protected void checkPosition(StreamedBoat boat, long timeElapsed) { + if (boat.getCurrentLeg().getName().toLowerCase().contains("finish")) { + //boat has finished + boatsFinished++; + boat.setFinished(true); + boat.setTimeFinished(timeElapsed); + } else if (boat.isDnf()) { + boatsFinished++; + boat.setFinished(true); + boat.setCurrentLeg(new Leg("DNF", -1)); + boat.setVelocity(0); + boat.setScaledVelocity(0); + } + //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 millisecondsElapsed time since last update + */ + protected void updatePosition(StreamedBoat boat, int millisecondsElapsed) { + //distanceTravelled = velocity (nm p hr) * time taken to update loop + double distanceTravelled = (boat.getVelocity() * millisecondsElapsed) / 3600000; + + boolean finish = boat.getCurrentLeg().getName().toLowerCase().contains("finish"); + if (!finish) { + //Calculate boat's new position by adding the distance travelled onto the start point of the leg + boat.setCurrentPosition(calculatePosition(boat.getCurrentPosition(), distanceTravelled, boat.calculateAzimuth())); + } + } + + protected void setPostion(StreamedBoat boat, GPSCoordinate coordinate) { + boat.setCurrentPosition(coordinate); + } + + /** + * 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 travelled into calculator + geodeticCalculator.setDirection(azimuth, distanceTravelled * Constants.NMToMetersConversion); + //get new point + Point2D endPoint = geodeticCalculator.getDestinationGeographicPoint(); + + return new GPSCoordinate(endPoint.getY(), endPoint.getX()); + } + + /** + * Checks the position of the boat, this updates the boats current position. + * @deprecated + * @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 + */ protected void checkPosition(BoatInRace boat, long timeElapsed) { } /** * Updates the boat's gps coordinates - * + * @deprecated * @param boat to be updated * @param millisecondsElapsed time since last update */ - protected void updatePosition(BoatInRace boat, int millisecondsElapsed) { + protected void updatePosition(BoatInRace boat, int millisecondsElapsed){ } diff --git a/visualiser/src/main/java/seng302/Model/Boat.java b/visualiser/src/main/java/seng302/Model/Boat.java index a3e269d4..4ea9d8ab 100644 --- a/visualiser/src/main/java/seng302/Model/Boat.java +++ b/visualiser/src/main/java/seng302/Model/Boat.java @@ -9,7 +9,7 @@ import javafx.beans.property.StringProperty; public class Boat { private StringProperty name; - private double velocity; + protected double velocity; private StringProperty velocityProp; private String abbrev; diff --git a/visualiser/src/main/java/seng302/Model/BoatInRace.java b/visualiser/src/main/java/seng302/Model/BoatInRace.java index 6f835593..42d9fcb7 100644 --- a/visualiser/src/main/java/seng302/Model/BoatInRace.java +++ b/visualiser/src/main/java/seng302/Model/BoatInRace.java @@ -18,7 +18,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; public class BoatInRace extends Boat { protected Leg currentLeg; - private double scaledVelocity; + protected double scaledVelocity; protected double distanceTravelledInLeg; protected GPSCoordinate currentPosition; protected long timeFinished; @@ -111,7 +111,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); } diff --git a/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java b/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java index dd8287dc..1df65127 100644 --- a/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java +++ b/visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java @@ -22,6 +22,7 @@ public class ResizableRaceCanvas extends Canvas { private GraphicsContext gc; private RaceMap map; private List boats; + private RaceDataSource raceData; private boolean raceAnno = true; private boolean annoName = true; private boolean annoAbbrev = true; @@ -41,6 +42,8 @@ public class ResizableRaceCanvas extends Canvas { double lat2 = raceData.getMapBottomRight().getLatitude(); double long2 = raceData.getMapBottomRight().getLongitude(); setMap(new RaceMap(lat1, long1, lat2, long2, (int) getWidth(), (int) getHeight())); + + this.raceData = raceData; } /** @@ -225,30 +228,64 @@ public class ResizableRaceCanvas extends Canvas { //finish line gc.setLineWidth(2); drawBoundaries(); - GraphCoordinate finishLineCoord1 = this.map.convertGPS(Constants.finishLineMarker1); - GraphCoordinate finishLineCoord2 = this.map.convertGPS(Constants.finishLineMarker2); - displayLine(finishLineCoord1, finishLineCoord2, Color.DARKRED); - //marks - GraphCoordinate markCoord = this.map.convertGPS(Constants.mark1); - GraphCoordinate windwardGate1 = this.map.convertGPS(Constants.windwardGate1); - GraphCoordinate windwardGate2 = this.map.convertGPS(Constants.windwardGate2); - GraphCoordinate leewardGate1 = this.map.convertGPS(Constants.leewardGate1); - GraphCoordinate leewardGate2 = this.map.convertGPS(Constants.leewardGate2); - displayMark(markCoord, Color.GOLD); - displayLine(windwardGate1, windwardGate2, Color.DARKCYAN); - displayLine(leewardGate1, leewardGate2, Color.DARKVIOLET); - //start line - GraphCoordinate startline1 = this.map.convertGPS(Constants.startLineMarker1); - GraphCoordinate startline2 = this.map.convertGPS(Constants.startLineMarker2); - - displayLine(startline1, startline2, Color.GREEN); - + drawPoints(); updateBoats(); //display wind direction arrow - specify origin point and angle - angle now set to random angle displayArrow(new GraphCoordinate((int) getWidth() - 40, 40), 150); } + private void drawPoints() { +// GraphCoordinate finishLineCoord1 = this.map.convertGPS(Constants.finishLineMarker1); +// GraphCoordinate finishLineCoord2 = this.map.convertGPS(Constants.finishLineMarker2); +// displayLine(finishLineCoord1, finishLineCoord2, Color.DARKRED); +// //marks +// GraphCoordinate markCoord = this.map.convertGPS(Constants.mark1); +// GraphCoordinate windwardGate1 = this.map.convertGPS(Constants.windwardGate1); +// GraphCoordinate windwardGate2 = this.map.convertGPS(Constants.windwardGate2); +// GraphCoordinate leewardGate1 = this.map.convertGPS(Constants.leewardGate1); +// GraphCoordinate leewardGate2 = this.map.convertGPS(Constants.leewardGate2); +// displayMark(markCoord, Color.GOLD); +// displayLine(windwardGate1, windwardGate2, Color.DARKCYAN); +// displayLine(leewardGate1, leewardGate2, Color.DARKVIOLET); +// //start line +// GraphCoordinate startline1 = this.map.convertGPS(Constants.startLineMarker1); +// GraphCoordinate startline2 = this.map.convertGPS(Constants.startLineMarker2); +// +// displayLine(startline1, startline2, Color.GREEN); + + for (Leg leg : raceData.getLegs()) { + boolean hasStart = false; + boolean hasEnd = false; + GraphCoordinate start1 = null; + GraphCoordinate start2 = null; + GraphCoordinate end1 = null; + GraphCoordinate end2 = null; + String legName = leg.getName().toLowerCase(); + if (leg.getStartMarker() != null) { + start1 = this.map.convertGPS(leg.getStartMarker().getMark1()); + start2 = this.map.convertGPS(leg.getStartMarker().getMark2()); + hasStart = true; + } if (leg.getEndMarker() != null) { + end1 = this.map.convertGPS(leg.getEndMarker().getMark1()); + end2 = this.map.convertGPS(leg.getEndMarker().getMark2()); + hasEnd = true; + } + + if (legName.contains("line") || legName.contains("gate")) { + if (hasStart && start1 != null && start2 != null) displayLine(start1, start2, Color.BLACK); + if (hasEnd && start1 != null && start2 != null) displayLine(end1, end2, Color.BLACK); + } else if (hasStart && start1 != null && start2 != null) { + if (legName.contains("start")) displayLine(start1, start2, Color.BLACK); + else displayMark(start1, Color.BLACK); + } + else if (hasEnd && end1 != null && end2 != null) { + if (legName.contains("finish")) displayLine(end1, end2, Color.BLACK); + else displayMark(end1, Color.BLACK); + } + } + } + /** * Draws a boat at a certain GPSCoordinate * @@ -319,7 +356,7 @@ public class ResizableRaceCanvas extends Canvas { */ public void updateBoats() { // TODO Remove null when boats are ready - boats = null; + //boats = null; if (boats != null) { for (BoatInRace boat : boats) { boolean finished = boat.getCurrentLeg().getName().equals("Finish") || boat.getCurrentLeg().getName().equals("DNF");