package seng302.Model; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import org.geotools.referencing.GeodeticCalculator; import seng302.GPSCoordinate; import java.awt.geom.Point2D; import java.time.ZonedDateTime; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; /** * Created by fwy13 on 3/03/17. */ public class Boat { private final StringProperty name; protected double velocity; private final StringProperty velocityProp; private final String abbrev; private GPSCoordinate currentPosition; protected double heading; private Leg currentLeg; private final StringProperty currentLegName; private boolean finished = false; private long timeFinished; private final StringProperty position; private boolean started = false; private boolean dnf = false; private int sourceID; private final Queue track = new ConcurrentLinkedQueue<>(); private long nextValidTime = 0; private ZonedDateTime timeSinceLastMark; /** * Boat initializer which keeps all of the information of the boat. * * @param name Name of the Boat. * @param velocity Speed in m/s that the boat travels at. * @param abbrev nam abbreviation */ public Boat(String name, double velocity, String abbrev) { this.velocity = velocity; this.velocityProp = new SimpleStringProperty(String.valueOf(Math.round(velocity))); this.abbrev = abbrev; this.name = new SimpleStringProperty(name); currentLegName = new SimpleStringProperty(""); position = new SimpleStringProperty("-"); } /** * Boat initializer which keeps all of the information of the boat. * * @param name Name of the Boat. * @param abbrev nam abbreviation */ protected Boat(String name, String abbrev) { 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 wakeScale = 5; 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 * @see seng302.Model.TrackPoint */ public void addTrackPoint(GPSCoordinate coordinate) { Boolean added = System.currentTimeMillis() >= nextValidTime; long currentTime = System.currentTimeMillis(); if (added && this.started) { float trackPointTimeInterval = 5000; nextValidTime = currentTime + (long) trackPointTimeInterval; int TRACK_POINT_LIMIT = 10; track.add(new TrackPoint(coordinate, currentTime, TRACK_POINT_LIMIT * (long) trackPointTimeInterval)); } } /** * 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; } /** * @return Name of the boat */ public StringProperty getName() { return name; } /** * Sets the boat name * * @param name of boat */ public void setName(String name) { this.name.setValue(name); } /** * @return Speed of the boat. */ public double getVelocity() { return velocity; } /** * Sets the speed of the boat in knots. * * @param velocity speed in knots */ public void setVelocity(double velocity) { this.velocity = velocity; this.velocityProp.setValue(String.valueOf(Math.round(velocity))); } /** * Print method prints the name of the boat * * @return Name of the boat. */ public String toString() { return getName().getValue(); } /** * @return Velocity String Property of the boat */ public StringProperty getVelocityProp() { return velocityProp; } /** * @return Abbreviation of the boat */ public String getAbbrev() { 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, RaceClock raceClock) { this.currentLeg = currentLeg; this.currentLegName.setValue(currentLeg.getName()); this.setTimeSinceLastMark(raceClock.getTime()); } 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; } public int getSourceID() { return this.sourceID; } public boolean isDnf() { return dnf; } public void setDnf(boolean dnf) { this.dnf = dnf; } public ZonedDateTime getTimeSinceLastMark() { return timeSinceLastMark; } public void setTimeSinceLastMark(ZonedDateTime timeSinceLastMark) { this.timeSinceLastMark = timeSinceLastMark; } }