Renamed sharedModel module to racevisionGame - this is intended to be our single module program.
Moved Boat/MockBoat/VisualiserBoat into it. Moved Polars, polarParser, VMG, and polar exception. Moved the networking stuff into it. Moved angle, azimuth, bearing into it. Moved gpscoordinate into it. Moved mark/compoundMark into it. Moved leg into it. Moved trackpoint into it.
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
package shared.model;
|
||||
|
||||
/**
|
||||
* This represents an angle.
|
||||
* Has functions to return angle as either degrees or radians.
|
||||
*/
|
||||
public class Angle implements Comparable<Angle> {
|
||||
|
||||
/**
|
||||
* The angle stored in this object.
|
||||
* Degrees.
|
||||
*/
|
||||
private double degrees;
|
||||
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
* Don't use this.
|
||||
* This is protected because you need to use the static helper functions {@link #fromDegrees(double)} and {@link #fromRadians(double)} to construct an Angle object.
|
||||
*
|
||||
* @param degrees The value, in degrees, to initialize this Angle object with.
|
||||
*/
|
||||
protected Angle(double degrees) {
|
||||
this.degrees = degrees;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an Angle object from an angle value in degrees.
|
||||
* @param degrees Angle value in degrees.
|
||||
* @return Angle object.
|
||||
*/
|
||||
public static Angle fromDegrees(double degrees) {
|
||||
Angle angle = new Angle(degrees);
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an Angle object from an angle value in radians.
|
||||
* @param radians Angle value in radians.
|
||||
* @return Angle object.
|
||||
*/
|
||||
public static Angle fromRadians(double radians) {
|
||||
return Angle.fromDegrees(Math.toDegrees(radians));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of this Angle object, in degrees.
|
||||
* @return The value of this Angle object, in degrees.
|
||||
*/
|
||||
public double degrees() {
|
||||
return this.degrees;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of this Angle object, in radians.
|
||||
* @return The value of this Angle object, in radians.
|
||||
*/
|
||||
public double radians() {
|
||||
return Math.toRadians(this.degrees);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if two Angle objects have equal values.
|
||||
* @param obj Other angle object to compare.
|
||||
* @return True if they are equal, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
//Cast other side.
|
||||
Angle other = (Angle) obj;
|
||||
|
||||
//Compare values.
|
||||
if (this.degrees() == other.degrees()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an int describing the ordering between this angle object, and another.
|
||||
* @param o Other angle to compare to.
|
||||
* @return {@literal int < 0} if this angle is less than the other angle, {@literal int > 0} if this angle is greater than the other angle, and {@literal int = 0} if this angle is equal to the other angle,
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Angle o) {
|
||||
|
||||
if (this.degrees() < o.degrees()) {
|
||||
return -1;
|
||||
} else if (this.degrees() > o.degrees()) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts an angle to an angle in a given periodic interval (e.g., degrees have a periodic interval of 360, radians have a periodic interval of 2Pi) of [lowerBound, upperBound).
|
||||
* @param angle The angle to convert.
|
||||
* @param lowerBound The lower bound of the interval.
|
||||
* @param upperBound The upper bound of the interval.
|
||||
* @param period The period of the interval.
|
||||
* @return The angle in the desired periodic interval.
|
||||
*/
|
||||
public static double toPeriodicInterval(double angle, double lowerBound, double upperBound, double period) {
|
||||
|
||||
|
||||
while (angle >= upperBound) {
|
||||
//Too large.
|
||||
angle -= period;
|
||||
}
|
||||
|
||||
while (angle < lowerBound) {
|
||||
//Too small.
|
||||
angle += period;
|
||||
}
|
||||
|
||||
return angle;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package shared.model;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Represents an azimuth.
|
||||
* If treated as an absolute azimuth this is the angle between north and a target point.
|
||||
* If treated as a relative azimuth, this is the angle between from one target point to the other.
|
||||
* It has the interval [-180, 180) degrees, and clockwise is positive.
|
||||
*/
|
||||
public class Azimuth extends Angle{
|
||||
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
* This is protected because you need to use the static helper functions {@link #fromDegrees(double)} and {@link #fromRadians(double)} to construct an Azimuth object.
|
||||
*
|
||||
* @param degrees The value, in degrees, to initialize this Azimuth object with.
|
||||
*/
|
||||
protected Azimuth(double degrees) {
|
||||
super(degrees);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts an angle in degrees into an angle in degrees in the correct interval for an azimuth - [-180, 180).
|
||||
* E.g., converts -183 to 177, or converts 250 to -110, or converts 180 to -180.
|
||||
* @param degrees Degree value to convert.
|
||||
* @return Degree value in interval [-180, 180).
|
||||
*/
|
||||
public static double toAzimuthInterval(double degrees) {
|
||||
|
||||
return Angle.toPeriodicInterval(degrees, -180d, 180d, 360d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an Azimuth object from an angle value in degrees.
|
||||
* @param degrees Azimuth value in degrees.
|
||||
* @return Azimuth object.
|
||||
*/
|
||||
public static Azimuth fromDegrees(double degrees) {
|
||||
//Ensure the angle is in the correct interval.
|
||||
double degreesInInterval = Azimuth.toAzimuthInterval(degrees);
|
||||
|
||||
Azimuth azimuth = new Azimuth(degreesInInterval);
|
||||
return azimuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an Azimuth object from an angle value in radians.
|
||||
* @param radians Azimuth value in radians.
|
||||
* @return Azimuth object.
|
||||
*/
|
||||
public static Azimuth fromRadians(double radians) {
|
||||
return Azimuth.fromDegrees(Math.toDegrees(radians));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an Azimuth object from a Bearing object.
|
||||
* @param bearing Bearing object to read value from.
|
||||
* @return Azimuth object.
|
||||
*/
|
||||
public static Azimuth fromBearing(Bearing bearing) {
|
||||
return Azimuth.fromDegrees(bearing.degrees());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package shared.model;
|
||||
|
||||
/**
|
||||
* Represents a bearing. Also known as a heading.
|
||||
* If treated as an absolute bearing this is the angle between north and a target point.
|
||||
* If treated as a relative bearing, this is the angle between from one target point to the other.
|
||||
* Has the interval [0, 360) degrees, and clockwise is positive.
|
||||
*/
|
||||
public class Bearing extends Angle {
|
||||
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
* This is protected because you need to use the static helper functions {@link #fromDegrees(double)} and {@link #fromRadians(double)} to construct a Bearing object.
|
||||
*
|
||||
* @param degrees The value, in degrees, to initialize this Bearing object with.
|
||||
*/
|
||||
protected Bearing(double degrees) {
|
||||
super(degrees);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts an angle in degrees into an angle in degrees in the correct interval for a bearing - [0, 360).
|
||||
* E.g., converts -183 to 177, or converts 425 to 65.
|
||||
* @param degrees Degree value to convert.
|
||||
* @return Degree value in interval [0, 360).
|
||||
*/
|
||||
public static double toBearingInterval(double degrees) {
|
||||
|
||||
return Angle.toPeriodicInterval(degrees, -0d, 360d, 360d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Bearing object from an angle value in degrees.
|
||||
* @param degrees Bearing value in degrees.
|
||||
* @return Bearing object.
|
||||
*/
|
||||
public static Bearing fromDegrees(double degrees) {
|
||||
//Ensure the angle is in the correct interval.
|
||||
double degreesInInterval = Bearing.toBearingInterval(degrees);
|
||||
|
||||
Bearing bearing = new Bearing(degreesInInterval);
|
||||
return bearing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Bearing object from an angle value in radians.
|
||||
* @param radians Bearing value in radians.
|
||||
* @return Bearing object.
|
||||
*/
|
||||
public static Bearing fromRadians(double radians) {
|
||||
return Bearing.fromDegrees(Math.toDegrees(radians));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a Bearing object from an Azimuth object.
|
||||
* @param azimuth Azimuth object to read value from.
|
||||
* @return Bearing object.
|
||||
*/
|
||||
public static Bearing fromAzimuth(Azimuth azimuth) {
|
||||
return Bearing.fromDegrees(azimuth.degrees());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
package shared.model;
|
||||
|
||||
|
||||
import network.Messages.Enums.BoatStatusEnum;
|
||||
|
||||
/**
|
||||
* Boat Model that is used to store information on the boats that are running in the race.
|
||||
*/
|
||||
public class Boat {
|
||||
/**
|
||||
* The name of the boat/team.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The current speed of the boat, in knots.
|
||||
* TODO knots
|
||||
*/
|
||||
private double currentSpeed;
|
||||
|
||||
/**
|
||||
* The current bearing/heading of the boat.
|
||||
*/
|
||||
private Bearing bearing;
|
||||
|
||||
/**
|
||||
* The current position of the boat.
|
||||
*/
|
||||
private GPSCoordinate currentPosition;
|
||||
|
||||
/**
|
||||
* The country or team abbreviation of the boat.
|
||||
*/
|
||||
private String country;
|
||||
|
||||
/**
|
||||
* The source ID of the boat.
|
||||
* This uniquely identifies an entity during a race.
|
||||
*/
|
||||
private int sourceID;
|
||||
|
||||
/**
|
||||
* The leg of the race that the boat is currently on.
|
||||
*/
|
||||
private Leg currentLeg;
|
||||
|
||||
/**
|
||||
* The distance, in meters, that the boat has travelled in the current leg.
|
||||
* TODO meters
|
||||
*/
|
||||
private double distanceTravelledInLeg;
|
||||
|
||||
/**
|
||||
* The time, in milliseconds, that has elapsed during the current leg.
|
||||
* TODO milliseconds
|
||||
*/
|
||||
private long timeElapsedInCurrentLeg;
|
||||
|
||||
/**
|
||||
* The timestamp, in milliseconds, of when the boat finished the race.
|
||||
* Is -1 if it hasn't finished.
|
||||
* TODO milliseconds
|
||||
*/
|
||||
private long timeFinished = -1;
|
||||
|
||||
/**
|
||||
* The current status of the boat.
|
||||
*/
|
||||
private BoatStatusEnum status;
|
||||
|
||||
|
||||
|
||||
private long estimatedTime = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a boat object with a given sourceID, name, country/team abbreviation, and polars table.
|
||||
*
|
||||
* @param sourceID The id of the boat
|
||||
* @param name The name of the Boat.
|
||||
* @param country The abbreviation or country code for the boat.
|
||||
*/
|
||||
public Boat(int sourceID, String name, String country) {
|
||||
this.country = country;
|
||||
this.name = name;
|
||||
this.sourceID = sourceID;
|
||||
|
||||
this.bearing = Bearing.fromDegrees(0d);
|
||||
|
||||
this.status = BoatStatusEnum.UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the boat/team.
|
||||
* @return Name of the boat/team.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the boat/team.
|
||||
* @param name Name of the boat/team.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current speed of the boat, in knots.
|
||||
* @return The current speed of the boat, in knots.
|
||||
*/
|
||||
public double getCurrentSpeed() {
|
||||
return currentSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speed of the boat, in knots.
|
||||
* @param currentSpeed The new speed of the boat, in knots.
|
||||
*/
|
||||
public void setCurrentSpeed(double currentSpeed) {
|
||||
this.currentSpeed = currentSpeed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the country/team abbreviation of the boat.
|
||||
* @return The country/team abbreviation of the boat.
|
||||
*/
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the country/team abbreviation of the boat.
|
||||
* @param country The new country/team abbreviation for the boat.
|
||||
*/
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the source ID of the boat.
|
||||
* @return The source ID of the boat.
|
||||
*/
|
||||
public int getSourceID() {
|
||||
return sourceID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source ID of the boat.
|
||||
* @param sourceID The new source ID for the boat.
|
||||
*/
|
||||
public void setSourceID(int sourceID) {
|
||||
this.sourceID = sourceID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current leg of the race the boat is in.
|
||||
* @return The current leg of the race the boat is in.
|
||||
*/
|
||||
public Leg getCurrentLeg() {
|
||||
return currentLeg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current leg of the race the boat is in.
|
||||
* Clears time elapsed in current leg and distance travelled in current leg.
|
||||
* @param currentLeg The new leg of the race the boat is in.
|
||||
*/
|
||||
public void setCurrentLeg(Leg currentLeg) {
|
||||
this.currentLeg = currentLeg;
|
||||
this.setTimeElapsedInCurrentLeg(0);
|
||||
this.setDistanceTravelledInLeg(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the distance, in meters, the boat has travelled in the current leg.
|
||||
* @return The distance, in meters, the boat has travelled in the current leg.
|
||||
*/
|
||||
public double getDistanceTravelledInLeg() {
|
||||
return distanceTravelledInLeg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the distance, in meters, the boat has travelled in the current leg.
|
||||
* @param distanceTravelledInLeg The distance, in meters, the boat has travelled in the current leg.
|
||||
*/
|
||||
public void setDistanceTravelledInLeg(double distanceTravelledInLeg) {
|
||||
this.distanceTravelledInLeg = distanceTravelledInLeg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current position of the boat.
|
||||
* @return The current position of the boat.
|
||||
*/
|
||||
public GPSCoordinate getCurrentPosition() {
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current position of the boat.
|
||||
* @param currentPosition The new position for the boat.
|
||||
*/
|
||||
public void setCurrentPosition(GPSCoordinate currentPosition) {
|
||||
this.currentPosition = currentPosition;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the timestamp, in milliseconds, at which the boat finished the race.
|
||||
* @return The timestamp, in milliseconds, at which the boat finished the race.
|
||||
*/
|
||||
public long getTimeFinished() {
|
||||
return timeFinished;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp, in milliseconds, at which the boat finished the race.
|
||||
* @param timeFinished The timestamp, in milliseconds, at which the boat finished the race.
|
||||
*/
|
||||
public void setTimeFinished(long timeFinished) {
|
||||
this.timeFinished = timeFinished;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current bearing of the boat.
|
||||
* @return The current bearing of the boat.
|
||||
*/
|
||||
public Bearing getBearing() {
|
||||
return bearing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current bearing of the boat.
|
||||
* @param bearing The new bearing of the boat.
|
||||
*/
|
||||
public void setBearing(Bearing bearing) {
|
||||
this.bearing = bearing;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the time, in milliseconds, that has elapsed since the boat started the current leg.
|
||||
* @return The time, in milliseconds, that has elapsed since the boat started the current leg.
|
||||
*/
|
||||
public long getTimeElapsedInCurrentLeg() {
|
||||
return timeElapsedInCurrentLeg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time, in milliseconds, that has elapsed since the boat started the current leg.
|
||||
* @param timeElapsedInCurrentLeg The new time, in milliseconds, that has elapsed since the boat started the current leg.
|
||||
*/
|
||||
public void setTimeElapsedInCurrentLeg(long timeElapsedInCurrentLeg) {
|
||||
this.timeElapsedInCurrentLeg = timeElapsedInCurrentLeg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the status of the boat.
|
||||
* @return The sttus of the boat.
|
||||
*/
|
||||
public BoatStatusEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status of the boat.
|
||||
* @param status The new status of the boat.
|
||||
*/
|
||||
public void setStatus(BoatStatusEnum status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public long getEstimatedTime() {
|
||||
return estimatedTime;
|
||||
}
|
||||
|
||||
public void setEstimatedTime(long estimatedTime) {
|
||||
this.estimatedTime = estimatedTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package shared.model;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a compound mark - that is, either one or two individual marks which form a single compound mark.
|
||||
*/
|
||||
public class CompoundMark {
|
||||
|
||||
/**
|
||||
* The first mark in the compound mark.
|
||||
*/
|
||||
private Mark mark1;
|
||||
|
||||
/**
|
||||
* The second mark in the compound mark.
|
||||
*/
|
||||
private Mark mark2;
|
||||
|
||||
/**
|
||||
* The average coordinate of the compound mark.
|
||||
*/
|
||||
private GPSCoordinate averageGPSCoordinate;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a compound mark from a single mark.
|
||||
* @param mark1 The individual mark that comprises this compound mark.
|
||||
*/
|
||||
public CompoundMark(Mark mark1) {
|
||||
this.mark1 = mark1;
|
||||
this.averageGPSCoordinate = calculateAverage();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a compound mark from a pair of marks.
|
||||
* @param mark1 The first individual mark that comprises this compound mark.
|
||||
* @param mark2 The second individual mark that comprises this compound mark.
|
||||
*/
|
||||
public CompoundMark(Mark mark1, Mark mark2) {
|
||||
this.mark1 = mark1;
|
||||
this.mark2 = mark2;
|
||||
this.averageGPSCoordinate = calculateAverage();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the first mark of the compound mark.
|
||||
* @return The first mark of the compound mark.
|
||||
*/
|
||||
public Mark getMark1() {
|
||||
return mark1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the second mark of the compound mark.
|
||||
* @return The second mark of the compound mark.
|
||||
*/
|
||||
public Mark getMark2() {
|
||||
return mark2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the position of the first mark in the compound mark.
|
||||
* @return The position of the first mark in the compound mark.
|
||||
*/
|
||||
public GPSCoordinate getMark1Position() {
|
||||
return mark1.getPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the second mark in the compound mark.
|
||||
* @return The position of the second mark in the compound mark.
|
||||
*/
|
||||
public GPSCoordinate getMark2Position() {
|
||||
return mark2.getPosition();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the average coordinate of the compound mark.
|
||||
* @return The average coordinate of the compound mark.
|
||||
*/
|
||||
public GPSCoordinate getAverageGPSCoordinate() {
|
||||
return averageGPSCoordinate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the average coordinate of the compound mark.
|
||||
* @return The average coordinate of the compound mark.
|
||||
*/
|
||||
private GPSCoordinate calculateAverage() {
|
||||
|
||||
//If the compound mark only contains one mark, the average is simply the first mark's position.
|
||||
if (this.mark2 == null) {
|
||||
return this.getMark1Position();
|
||||
}
|
||||
|
||||
|
||||
//Otherwise, calculate the average of both marks.
|
||||
GPSCoordinate averageCoordinate = GPSCoordinate.calculateAverageCoordinate(this.getMark1Position(), this.getMark2Position());
|
||||
|
||||
return averageCoordinate;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package shared.model;
|
||||
|
||||
/**
|
||||
* Constants that are used throughout the program
|
||||
* Created by Erika on 19-Mar-17.
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
/**
|
||||
* Multiply by this factor to convert nautical miles to meters.
|
||||
* <br>
|
||||
* Divide by this factor to convert meters to nautical miles.
|
||||
* <br>
|
||||
* 1 nautical mile = 1852 meters.
|
||||
*/
|
||||
public static final int NMToMetersConversion = 1852;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Multiply by this factor to convert Knots to millimeters per second.
|
||||
* <br>
|
||||
* Divide by this factor to convert millimeters per second to Knots.
|
||||
* <br>
|
||||
* 1 knot = 514.444 millimeters per second.
|
||||
*/
|
||||
public static final double KnotsToMMPerSecond = 514.444;
|
||||
|
||||
|
||||
/**
|
||||
* The race pre-start time, in milliseconds. 3 minutes.
|
||||
*/
|
||||
public static final long RacePreStartTime = 3 * 60 * 1000;
|
||||
|
||||
|
||||
/**
|
||||
* The race preparatory time, in milliseconds. 1 minutes.
|
||||
*/
|
||||
public static final long RacePreparatoryTime = 1 * 60 * 1000;
|
||||
|
||||
|
||||
/**
|
||||
* The number of milliseconds in one hour.
|
||||
*/
|
||||
public static long OneHourMilliseconds = 1 * 60 * 60 * 1000;
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
package shared.model;
|
||||
|
||||
import javafx.util.Pair;
|
||||
import org.geotools.referencing.GeodeticCalculator;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* GPS Coordinate for the world map, containing a longitude and latitude.
|
||||
* Created by esa46 on 15/03/17.
|
||||
*/
|
||||
public class GPSCoordinate {
|
||||
|
||||
/**
|
||||
* The latitude of the coordinate.
|
||||
*/
|
||||
private double latitude;
|
||||
|
||||
/**
|
||||
* The longitude of the coordinate.
|
||||
*/
|
||||
private double longitude;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a GPSCoordinate from a latitude and longitude value.
|
||||
* @param latitude Latitude the coordinate is located at.
|
||||
* @param longitude Longitude that the coordinate is located at.
|
||||
*/
|
||||
public GPSCoordinate(double latitude, double longitude) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the Latitude that the Coordinate is at.
|
||||
*
|
||||
* @return Returns the latitude of the Coordinate.
|
||||
*/
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Longitude that the Coordinate is at.
|
||||
*
|
||||
* @return Returns the longitude of the Coordinate.
|
||||
*/
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* To String method of the Coordinate in the form Latitude: $f, Longitude: $f.
|
||||
*
|
||||
* @return A String representation of the GPSCoordinate Class.
|
||||
*/
|
||||
public String toString() {
|
||||
return String.format("Latitude: %f, Longitude: %f", latitude, longitude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GPSCoordinate that = (GPSCoordinate) o;
|
||||
|
||||
if (Math.abs(this.latitude - that.latitude) > 1e-7) return false;
|
||||
return (Math.abs(this.longitude - that.longitude) < 1e-7);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(latitude);
|
||||
result = (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(longitude);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculates min and max values and passed it to calculate if coordinate is in the boundary
|
||||
* @param coordinate coordinate of interest
|
||||
* @param boundary List of points which make a boundary
|
||||
* @return true if coordinate is in the boundary
|
||||
*/
|
||||
public static boolean isInsideBoundary(GPSCoordinate coordinate, List<GPSCoordinate> boundary) {
|
||||
int length = boundary.size();
|
||||
|
||||
boolean inside = false;
|
||||
|
||||
// Check if inside using ray casting algorithm
|
||||
for (int i = 0, j = length - 1; i < length; j = i++) {
|
||||
if (intersects(boundary.get(i), boundary.get(j), coordinate)) {
|
||||
inside = !inside;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return inside;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates if the coordinate is in the boundary
|
||||
* @param coordinate coordinate of interest
|
||||
* @param boundary List of points which make a boundary
|
||||
* @param minValues max GPS
|
||||
* @param maxValues min GPS
|
||||
* @return true if coordinate is in the boundary
|
||||
*/
|
||||
public static boolean isInsideBoundary(GPSCoordinate coordinate, List<GPSCoordinate> boundary, GPSCoordinate minValues, GPSCoordinate maxValues) {
|
||||
double minLat = minValues.getLatitude();
|
||||
double minLon = minValues.getLongitude();
|
||||
double maxLat = maxValues.getLatitude();
|
||||
double maxLon = maxValues.getLongitude();
|
||||
double coordinateLat = coordinate.getLatitude();
|
||||
double coordinateLon = coordinate.getLongitude();
|
||||
// End computation early
|
||||
if (coordinateLat <= minLat || coordinateLat >= maxLat || coordinateLon <= minLon || coordinateLon >= maxLon) {
|
||||
return false;
|
||||
} else {
|
||||
return isInsideBoundary(coordinate, boundary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to find if a point is in a boundary
|
||||
* @param boundaryA The first coordinate of the boundary.
|
||||
* @param boundaryB The second coordinate of the boundary.
|
||||
* @param coordinate The coordinate to test.
|
||||
* @return true if a line from the point intersects the two boundary points
|
||||
*/
|
||||
private static boolean intersects(GPSCoordinate boundaryA, GPSCoordinate boundaryB, GPSCoordinate coordinate) {
|
||||
double boundaryALat = boundaryA.getLatitude();
|
||||
double boundaryALon = boundaryA.getLongitude();
|
||||
double boundaryBLat = boundaryB.getLatitude();
|
||||
double boundaryBLon = boundaryB.getLongitude();
|
||||
double coordinateLat = coordinate.getLatitude();
|
||||
double coordinateLon = coordinate.getLongitude();
|
||||
|
||||
if (boundaryALat > boundaryBLat) {
|
||||
return intersects(boundaryB, boundaryA, coordinate);
|
||||
}
|
||||
if (coordinateLat == boundaryALat || coordinateLat == boundaryBLat) {
|
||||
// Move coordinate off intersection line
|
||||
coordinateLat += 1e-9;
|
||||
}
|
||||
if (coordinateLat > boundaryBLat || coordinateLat < boundaryALat || coordinateLon > Double.max(boundaryALon, boundaryBLon)) {
|
||||
return false;
|
||||
}
|
||||
if (coordinateLon < Double.min(boundaryALon, boundaryBLon)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double aRatio = (coordinateLat - boundaryALat) / (coordinateLon - boundaryALon);
|
||||
double bRatio = (coordinateLat - boundaryBLat) / (coordinateLon - boundaryBLon);
|
||||
return aRatio >= bRatio;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the azimuth between two points.
|
||||
* @param start The starting point.
|
||||
* @param end The ending point.
|
||||
* @return The azimuth from the start point to the end point.
|
||||
*/
|
||||
public static Azimuth calculateAzimuth(GPSCoordinate start, GPSCoordinate end) {
|
||||
|
||||
GeodeticCalculator calc = new GeodeticCalculator();
|
||||
|
||||
calc.setStartingGeographicPoint(start.getLongitude(), start.getLatitude());
|
||||
calc.setDestinationGeographicPoint(end.getLongitude(), end.getLatitude());
|
||||
|
||||
return Azimuth.fromDegrees(calc.getAzimuth());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the bearing between two points.
|
||||
* @param start The starting point.
|
||||
* @param end The ending point.
|
||||
* @return The Bearing from the start point to the end point.
|
||||
*/
|
||||
public static Bearing calculateBearing(GPSCoordinate start, GPSCoordinate end) {
|
||||
|
||||
//Calculates the azimuth between the two points.
|
||||
Azimuth azimuth = GPSCoordinate.calculateAzimuth(start, end);
|
||||
|
||||
//And converts it into a bearing.
|
||||
return Bearing.fromAzimuth(azimuth);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the distance, in meters, between two points.
|
||||
* Note: all other distance calculations (e.g., nautical miles between two points) should use this, and convert from meters to their desired unit.
|
||||
* @param start The starting point.
|
||||
* @param end The ending point.
|
||||
* @return The distance, in meters, between the two given points.
|
||||
*/
|
||||
public static double calculateDistanceMeters(GPSCoordinate start, GPSCoordinate end) {
|
||||
|
||||
GeodeticCalculator calc = new GeodeticCalculator();
|
||||
|
||||
calc.setStartingGeographicPoint(start.getLongitude(), start.getLatitude());
|
||||
calc.setDestinationGeographicPoint(end.getLongitude(), end.getLatitude());
|
||||
|
||||
double distanceMeters = calc.getOrthodromicDistance();
|
||||
|
||||
return distanceMeters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the distance, in nautical miles, between two points.
|
||||
* @param start The starting point.
|
||||
* @param end The ending point.
|
||||
* @return The distance, in nautical miles, between the two given points.
|
||||
*/
|
||||
public static double calculateDistanceNauticalMiles(GPSCoordinate start, GPSCoordinate end) {
|
||||
//Find distance in meters.
|
||||
double distanceMeters = GPSCoordinate.calculateDistanceMeters(start, end);
|
||||
|
||||
//Convert to nautical miles.
|
||||
double distanceNauticalMiles = distanceMeters / Constants.NMToMetersConversion;
|
||||
|
||||
return distanceNauticalMiles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the GPS position an entity will be at, given a starting position, distance (in meters), and an azimuth.
|
||||
*
|
||||
* @param oldCoordinates GPS coordinates of the entity's starting position.
|
||||
* @param distanceMeters The distance in meters.
|
||||
* @param azimuth The entity's current azimuth.
|
||||
* @return The entity's new coordinate.
|
||||
*/
|
||||
public static GPSCoordinate calculateNewPosition(GPSCoordinate oldCoordinates, double distanceMeters, Azimuth azimuth) {
|
||||
|
||||
|
||||
GeodeticCalculator calc = new GeodeticCalculator();
|
||||
|
||||
//Set starting position.
|
||||
calc.setStartingGeographicPoint(oldCoordinates.getLongitude(), oldCoordinates.getLatitude());
|
||||
|
||||
//Set direction.
|
||||
calc.setDirection(azimuth.degrees(), distanceMeters);
|
||||
|
||||
//Get the destination.
|
||||
Point2D destinationPoint = calc.getDestinationGeographicPoint();
|
||||
|
||||
return new GPSCoordinate(destinationPoint.getY(), destinationPoint.getX());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the average coordinate of two coordinates.
|
||||
* @param point1 The first coordinate to average.
|
||||
* @param point2 The second coordinate to average.
|
||||
* @return The average of the two coordinates.
|
||||
*/
|
||||
public static GPSCoordinate calculateAverageCoordinate(GPSCoordinate point1, GPSCoordinate point2) {
|
||||
|
||||
//Calculate distance between them.
|
||||
double distanceMeters = GPSCoordinate.calculateDistanceMeters(point1, point2);
|
||||
//We want the average, so get half the distance between points.
|
||||
distanceMeters = distanceMeters / 2d;
|
||||
|
||||
//Calculate azimuth between them.
|
||||
Azimuth azimuth = GPSCoordinate.calculateAzimuth(point1, point2);
|
||||
|
||||
//Calculate the middle coordinate.
|
||||
GPSCoordinate middleCoordinate = GPSCoordinate.calculateNewPosition(point1, distanceMeters, azimuth);
|
||||
|
||||
return middleCoordinate;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Takes a list of GPS coordinates describing a course boundary, and "shrinks" it inwards by 50m.
|
||||
* @param boundary The boundary of course.
|
||||
* @return A copy of the course boundary list, shrunk inwards by 50m.
|
||||
*/
|
||||
public static List<GPSCoordinate> getShrinkBoundary(List<GPSCoordinate> boundary) {
|
||||
|
||||
|
||||
double shrinkDistance = 50d;
|
||||
List<GPSCoordinate> shrunkBoundary = new ArrayList<>(boundary.size());
|
||||
//This is a list of edges that have been shrunk/shifted inwards.
|
||||
List<Pair<GPSCoordinate, GPSCoordinate>> shrunkEdges = new ArrayList<>();
|
||||
|
||||
|
||||
//We need to invert some of our operations depending if the boundary is clockwise or anti-clockwise.
|
||||
boolean isClockwise = GPSCoordinate.isClockwisePolygon(boundary);
|
||||
double clockwiseScaleFactor = 0;
|
||||
|
||||
if (isClockwise) {
|
||||
clockwiseScaleFactor = 1;
|
||||
} else {
|
||||
clockwiseScaleFactor = -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Starting at a vertex, face anti-clockwise along an adjacent edge.
|
||||
Replace the edge with a new, parallel edge placed at distance d to the "left" of the old one.
|
||||
Repeat for all edges.
|
||||
Find the intersections of the new edges to get the new vertices.
|
||||
Detect if you've become a crossed polynomial and decide what to do about it. Probably add a new vertex at the crossing-point and get rid of some old ones. I'm not sure whether there's a better way to detect this than just to compare every pair of non-adjacent edges to see if their intersection lies between both pairs of vertices.
|
||||
*/
|
||||
|
||||
//For the first (size-1) adjacent pairs.
|
||||
for (int i = 0; i < (boundary.size() - 1); i++) {
|
||||
|
||||
//Get the points.
|
||||
GPSCoordinate firstPoint = boundary.get(i);
|
||||
GPSCoordinate secondPoint = boundary.get(i + 1);
|
||||
|
||||
//Get the bearing between two adjacent points.
|
||||
Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint);
|
||||
|
||||
//Calculate angle perpendicular to bearing.
|
||||
Bearing perpendicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor));
|
||||
|
||||
//Translate both first and second point by 50m, using this bearing. These form our inwards shifted edge.
|
||||
GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
|
||||
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
|
||||
|
||||
//Add edge to list.
|
||||
shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated));
|
||||
|
||||
}
|
||||
|
||||
//For the final adjacent pair, between the last and first point.
|
||||
//Get the points.
|
||||
GPSCoordinate firstPoint = boundary.get(boundary.size() - 1);
|
||||
GPSCoordinate secondPoint = boundary.get(0);
|
||||
|
||||
//Get the bearing between two adjacent points.
|
||||
Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint);
|
||||
|
||||
//Calculate angle perpendicular to bearing.
|
||||
Bearing perpendicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor));
|
||||
|
||||
//Translate both first and second point by 50m, using this bearing. These form our inwards shifted edge.
|
||||
GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
|
||||
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
|
||||
|
||||
//Add edge to list.
|
||||
shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated));
|
||||
|
||||
|
||||
//We now have a list of edges that have been shifted inwards.
|
||||
//We need to find the intersections between adjacent vertices in our edge list. E.g., intersection between edge1-right, and edge2-left.
|
||||
|
||||
//For the first (size-1) adjacent pairs.
|
||||
for (int i = 0; i < (shrunkEdges.size() - 1); i++) {
|
||||
|
||||
//Get the pair of adjacent edges.
|
||||
Pair<GPSCoordinate, GPSCoordinate> edge1 = shrunkEdges.get(i);
|
||||
Pair<GPSCoordinate, GPSCoordinate> edge2 = shrunkEdges.get(i + 1);
|
||||
|
||||
//Get the x and y coordinates of first edge.
|
||||
double x1 = edge1.getKey().getLongitude();
|
||||
double x2 = edge1.getValue().getLongitude();
|
||||
double y1 = edge1.getKey().getLatitude();
|
||||
double y2 = edge1.getValue().getLatitude();
|
||||
|
||||
//Get the x and y coordinates of second edge.
|
||||
double x3 = edge2.getKey().getLongitude();
|
||||
double x4 = edge2.getValue().getLongitude();
|
||||
double y3 = edge2.getKey().getLatitude();
|
||||
double y4 = edge2.getValue().getLatitude();
|
||||
|
||||
//Find the equations for both edges.
|
||||
// y = a*x + b
|
||||
//First equation.
|
||||
double a1 = (y2 - y1) / (x2 - x1);
|
||||
double b1 = y1 - a1 * x1;
|
||||
|
||||
//Second equation.
|
||||
double a2 = (y4 - y3) / (x4 - x3);
|
||||
double b2 = y3 - a2 * x3;
|
||||
|
||||
|
||||
//Find intersecting x coordinate.
|
||||
// a1 * x + b1 = a2 * x + b2
|
||||
double x0 = -(b1 - b2) / (a1 - a2);
|
||||
//Find intersecting y coordinate.
|
||||
double y0 = x0 * a1 + b1;
|
||||
|
||||
//Add this to shrunk boundary list.
|
||||
GPSCoordinate coordinate = new GPSCoordinate(y0, x0);
|
||||
shrunkBoundary.add(coordinate);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//For the final adjacent pair, between the last and first point.
|
||||
//Get the pair of adjacent edges.
|
||||
Pair<GPSCoordinate, GPSCoordinate> edge1 = shrunkEdges.get(shrunkEdges.size() - 1);
|
||||
Pair<GPSCoordinate, GPSCoordinate> edge2 = shrunkEdges.get(0);
|
||||
|
||||
//Get the x and y coordinates of first edge.
|
||||
double x1 = edge1.getKey().getLongitude();
|
||||
double x2 = edge1.getValue().getLongitude();
|
||||
double y1 = edge1.getKey().getLatitude();
|
||||
double y2 = edge1.getValue().getLatitude();
|
||||
|
||||
//Get the x and y coordinates of second edge.
|
||||
double x3 = edge2.getKey().getLongitude();
|
||||
double x4 = edge2.getValue().getLongitude();
|
||||
double y3 = edge2.getKey().getLatitude();
|
||||
double y4 = edge2.getValue().getLatitude();
|
||||
|
||||
//Find the equations for both edges.
|
||||
// y = a*x + b
|
||||
//First equation.
|
||||
double a1 = (y2 - y1) / (x2 - x1);
|
||||
double b1 = y1 - a1 * x1;
|
||||
|
||||
//Second equation.
|
||||
double a2 = (y4 - y3) / (x4 - x3);
|
||||
double b2 = y3 - a2 * x3;
|
||||
|
||||
|
||||
//Find intersecting x coordinate.
|
||||
// a1 * x + b1 = a2 * x + b2
|
||||
double x0 = -(b1 - b2) / (a1 - a2);
|
||||
//Find intersecting y coordinate.
|
||||
double y0 = x0 * a1 + b1;
|
||||
|
||||
//Add this to shrunk boundary list.
|
||||
GPSCoordinate coordinate = new GPSCoordinate(y0, x0);
|
||||
shrunkBoundary.add(coordinate);
|
||||
|
||||
|
||||
|
||||
return shrunkBoundary;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if a list of coordinates describes a boundary polygon in clockwise or anti-clockwise order.
|
||||
* @param boundary The list of coordinates.
|
||||
* @return True if clockwise, false if anti-clockwise.
|
||||
*/
|
||||
public static boolean isClockwisePolygon(List<GPSCoordinate> boundary) {
|
||||
|
||||
/* From https://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
|
||||
sum all pairs (x2 − x1)(y2 + y1)
|
||||
point[0] = (5,0) edge[0]: (6-5)(4+0) = 4
|
||||
point[1] = (6,4) edge[1]: (4-6)(5+4) = -18
|
||||
point[2] = (4,5) edge[2]: (1-4)(5+5) = -30
|
||||
point[3] = (1,5) edge[3]: (1-1)(0+5) = 0
|
||||
point[4] = (1,0) edge[4]: (5-1)(0+0) = 0
|
||||
---
|
||||
-44 counter-clockwise
|
||||
*/
|
||||
|
||||
double sum = 0;
|
||||
|
||||
//For the first (size-1) adjacent pairs.
|
||||
for (int i = 0; i < (boundary.size() - 1); i++) {
|
||||
|
||||
//Get the points.
|
||||
GPSCoordinate firstPoint = boundary.get(i);
|
||||
GPSCoordinate secondPoint = boundary.get(i + 1);
|
||||
|
||||
double xDelta = secondPoint.getLongitude() - firstPoint.getLongitude();
|
||||
double ySum = secondPoint.getLatitude() + firstPoint.getLatitude();
|
||||
|
||||
double product = xDelta * ySum;
|
||||
|
||||
sum += product;
|
||||
|
||||
}
|
||||
|
||||
//For the final adjacent pair, between the last and first point.
|
||||
//Get the points.
|
||||
GPSCoordinate firstPoint = boundary.get(boundary.size() - 1);
|
||||
GPSCoordinate secondPoint = boundary.get(0);
|
||||
|
||||
double xDelta = secondPoint.getLongitude() - firstPoint.getLongitude();
|
||||
double ySum = secondPoint.getLatitude() + firstPoint.getLatitude();
|
||||
|
||||
double product = xDelta * ySum;
|
||||
|
||||
sum += product;
|
||||
|
||||
|
||||
//sum > 0 is clockwise, sum < 0 is anticlockwise.
|
||||
return sum > 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package shared.model;
|
||||
|
||||
|
||||
/**
|
||||
* Leg of the race, this is what each part of the race is divided into, from mark to mark.
|
||||
*/
|
||||
public class Leg {
|
||||
|
||||
/**
|
||||
* The name of the leg.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The distance of the leg, in nautical miles.
|
||||
*/
|
||||
private double distanceNauticalMiles;
|
||||
|
||||
/**
|
||||
* The starting marker of the leg.
|
||||
*/
|
||||
private CompoundMark startCompoundMark;
|
||||
|
||||
/**
|
||||
* The ending marking of the leg.
|
||||
*/
|
||||
private CompoundMark endCompoundMark;
|
||||
|
||||
/**
|
||||
* The leg number within a race.
|
||||
*/
|
||||
private int legNumber;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a leg from a name, start marker, end marker, and leg number.
|
||||
*
|
||||
* @param name Name of the Leg.
|
||||
* @param start Starting marker of the leg.
|
||||
* @param end Ending marker of the leg.
|
||||
* @param number Leg's position within the race.
|
||||
*/
|
||||
public Leg(String name, CompoundMark start, CompoundMark end, int number) {
|
||||
this.name = name;
|
||||
this.startCompoundMark = start;
|
||||
this.endCompoundMark = end;
|
||||
this.legNumber = number;
|
||||
this.calculateLegDistance();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a leg from a name and leg number.
|
||||
* This is currently used for constructing "dummy" DNF and Finish legs.
|
||||
*
|
||||
* @param name Name of the leg.
|
||||
* @param number Leg's position within the race.
|
||||
*/
|
||||
public Leg(String name, int number) {
|
||||
this.name = name;
|
||||
this.legNumber = number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the Leg.
|
||||
* @return The name of the Leg.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the distance in nautical miles.
|
||||
* @return The total distance of the leg.
|
||||
*/
|
||||
public double getDistanceNauticalMiles() {
|
||||
return distanceNauticalMiles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the leg number of the leg within a race.
|
||||
* @return The leg number of the leg within a race
|
||||
*/
|
||||
public int getLegNumber() {
|
||||
return legNumber;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the starting marker of the leg.
|
||||
* @return The starting marker of the leg.
|
||||
*/
|
||||
public CompoundMark getStartCompoundMark() {
|
||||
return startCompoundMark;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ending marker of the leg.
|
||||
* @return The ending marker of the leg.
|
||||
*/
|
||||
public CompoundMark getEndCompoundMark() {
|
||||
return endCompoundMark;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the distance of the leg, in nautical miles.
|
||||
*/
|
||||
public void calculateLegDistance() {
|
||||
|
||||
//Gets the start and end coordinates.
|
||||
GPSCoordinate startMarker = this.startCompoundMark.getAverageGPSCoordinate();
|
||||
GPSCoordinate endMarker = this.endCompoundMark.getAverageGPSCoordinate();
|
||||
|
||||
//Calculates the distance between markers.
|
||||
double distanceNauticalMiles = GPSCoordinate.calculateDistanceNauticalMiles(startMarker, endMarker);
|
||||
|
||||
this.distanceNauticalMiles = distanceNauticalMiles;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package shared.model;
|
||||
|
||||
/**
|
||||
* Represents an individual mark.
|
||||
* Has a source ID, name, and position.
|
||||
*/
|
||||
public class Mark {
|
||||
|
||||
/**
|
||||
* The source ID of the mark.
|
||||
*/
|
||||
private int sourceID;
|
||||
|
||||
/**
|
||||
* The name of the mark.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The position of the mark.
|
||||
*/
|
||||
private GPSCoordinate position;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a mark with a given source ID, name, and position.
|
||||
* @param sourceID The source ID of the mark.
|
||||
* @param name The name of the mark.
|
||||
* @param position The position of the mark.
|
||||
*/
|
||||
public Mark(int sourceID, String name, GPSCoordinate position) {
|
||||
this.sourceID = sourceID;
|
||||
this.name = name;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the mark.
|
||||
* @return The name of the mark.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source ID of the mark.
|
||||
* @return The source ID of the mark.
|
||||
*/
|
||||
public int getSourceID() {
|
||||
return sourceID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the mark.
|
||||
* @return The position of the mark.
|
||||
*/
|
||||
public GPSCoordinate getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user