Merge branch 'longMethodClassSmells' into 'master'

Long method class smells



See merge request !15
main
Fraser Cope 9 years ago
commit 93c1199392

@ -1,9 +1,5 @@
package seng302.DataInput; package seng302.DataInput;
/**
* Created by hba56 on 10/05/17.
*/
import seng302.Exceptions.InvalidPolarFileException; import seng302.Exceptions.InvalidPolarFileException;
import seng302.Model.Bearing; import seng302.Model.Bearing;
import seng302.Model.Polars; import seng302.Model.Polars;

@ -13,7 +13,6 @@ import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;

@ -1,9 +1,5 @@
package seng302.Exceptions; package seng302.Exceptions;
/**
* Created by f123 on 25-Apr-17.
*/
/** /**
* An exception thrown when we cannot generate Boats.xml and send an XML message. * An exception thrown when we cannot generate Boats.xml and send an XML message.
*/ */

@ -1,9 +1,5 @@
package seng302.Exceptions; package seng302.Exceptions;
/**
* Created by f123 on 10-May-17.
*/
/** /**
* An exception thrown when we cannot parse a polar data file. * An exception thrown when we cannot parse a polar data file.
*/ */

@ -1,9 +1,5 @@
package seng302.Exceptions; package seng302.Exceptions;
/**
* Created by f123 on 25-Apr-17.
*/
/** /**
* Exception thrown when we cannot generate Race.xml data, and send an XML message. * Exception thrown when we cannot generate Race.xml data, and send an XML message.
*/ */

@ -2,12 +2,10 @@ package seng302.Model;
import javafx.util.Pair; import javafx.util.Pair;
import org.geotools.referencing.GeodeticCalculator; import org.geotools.referencing.GeodeticCalculator;
import org.opengis.geometry.DirectPosition;
import seng302.Constants; import seng302.Constants;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
/** /**
@ -94,7 +92,7 @@ public class GPSCoordinate {
/** /**
* Calculates min and max values and passed it to calculate if coordinate is in the boundary * Calculates min and max values and passed it to calculate if coordinate is in the boundary
* @param coordinate coordinate of interest * @param coordinate coordinate of interest
* @param boundary List of points which make a boundry * @param boundary List of points which make a boundary
* @return true if coordinate is in the boundary * @return true if coordinate is in the boundary
*/ */
public static boolean isInsideBoundary(GPSCoordinate coordinate, List<GPSCoordinate> boundary) { public static boolean isInsideBoundary(GPSCoordinate coordinate, List<GPSCoordinate> boundary) {
@ -141,7 +139,7 @@ public class GPSCoordinate {
/** /**
* Helper function to find if a point is in a boundary * Helper function to find if a point is in a boundary
* @param boundaryA The first coordinate of the boundary. * @param boundaryA The first coordinate of the boundary.
* @param boundaryB The second coordinate of the bounary. * @param boundaryB The second coordinate of the boundary.
* @param coordinate The coordinate to test. * @param coordinate The coordinate to test.
* @return true if a line from the point intersects the two boundary points * @return true if a line from the point intersects the two boundary points
*/ */
@ -309,7 +307,7 @@ public class GPSCoordinate {
List<Pair<GPSCoordinate, GPSCoordinate>> shrunkEdges = new ArrayList<>(); List<Pair<GPSCoordinate, GPSCoordinate>> shrunkEdges = new ArrayList<>();
//We need to invert some of our opertations depending if the boundary is clockwise or anti-clockwise. //We need to invert some of our operations depending if the boundary is clockwise or anti-clockwise.
boolean isClockwise = GPSCoordinate.isClockwisePolygon(boundary); boolean isClockwise = GPSCoordinate.isClockwisePolygon(boundary);
double clockwiseScaleFactor = 0; double clockwiseScaleFactor = 0;
@ -320,8 +318,8 @@ public class GPSCoordinate {
} }
/** /*
* Starting at a vertex, face anti-clockwise along an adjacent edge. 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. Replace the edge with a new, parallel edge placed at distance d to the "left" of the old one.
Repeat for all edges. Repeat for all edges.
Find the intersections of the new edges to get the new vertices. Find the intersections of the new edges to get the new vertices.
@ -339,11 +337,11 @@ public class GPSCoordinate {
Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint); Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint);
//Calculate angle perpendicular to bearing. //Calculate angle perpendicular to bearing.
Bearing perpindicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor)); 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. //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(perpindicularBearing)); GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing)); GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
//Add edge to list. //Add edge to list.
shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated)); shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated));
@ -359,11 +357,11 @@ public class GPSCoordinate {
Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint); Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint);
//Calculate angle perpendicular to bearing. //Calculate angle perpendicular to bearing.
Bearing perpindicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor)); 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. //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(perpindicularBearing)); GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing)); GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
//Add edge to list. //Add edge to list.
shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated)); shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated));
@ -462,13 +460,13 @@ public class GPSCoordinate {
/** /**
* Determines if a list of coordinates describes a boundary polygon in clockwise or anti-clockwise order. * Determines if a list of coordinates describes a boundary polygon in clockwise or anti-clockwise order.
* @param boundary The list of coodinates. * @param boundary The list of coordinates.
* @return True if clockwise, false if anti-clockwise. * @return True if clockwise, false if anti-clockwise.
*/ */
public static boolean isClockwisePolygon(List<GPSCoordinate> boundary) { 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 /* 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) sum all pairs (x2 x1)(y2 + y1)
point[0] = (5,0) edge[0]: (6-5)(4+0) = 4 point[0] = (5,0) edge[0]: (6-5)(4+0) = 4
point[1] = (6,4) edge[1]: (4-6)(5+4) = -18 point[1] = (6,4) edge[1]: (4-6)(5+4) = -18
point[2] = (4,5) edge[2]: (1-4)(5+5) = -30 point[2] = (4,5) edge[2]: (1-4)(5+5) = -30

@ -4,10 +4,6 @@ import javafx.util.Pair;
import java.util.*; import java.util.*;
/**
* Created by hba56 on 10/05/17.
*/
/** /**
* Encapsulates an entire polar table. Has a function to calculate VMG. * Encapsulates an entire polar table. Has a function to calculate VMG.
*/ */

@ -6,7 +6,6 @@ import javafx.collections.ObservableList;
import seng302.Constants; import seng302.Constants;
import seng302.DataInput.RaceDataSource; import seng302.DataInput.RaceDataSource;
import seng302.MockOutput; import seng302.MockOutput;
import seng302.Networking.Messages.BoatLocation;
import seng302.Networking.Messages.BoatStatus; import seng302.Networking.Messages.BoatStatus;
import seng302.Networking.Messages.Enums.BoatStatusEnum; import seng302.Networking.Messages.Enums.BoatStatusEnum;
import seng302.Networking.Messages.Enums.RaceStatusEnum; import seng302.Networking.Messages.Enums.RaceStatusEnum;

@ -1,9 +1,5 @@
package seng302.Model; package seng302.Model;
/**
* Created by f123 on 10-May-17.
*/
/** /**
* This class encapsulates VMG - that is, velocity made good. It has a speed component and a bearing component. * This class encapsulates VMG - that is, velocity made good. It has a speed component and a bearing component.
*/ */

@ -5,8 +5,6 @@ import org.testng.annotations.Test;
import seng302.Exceptions.InvalidPolarFileException; import seng302.Exceptions.InvalidPolarFileException;
import seng302.Model.Polars; import seng302.Model.Polars;
import java.io.File;
import static org.testng.Assert.*; import static org.testng.Assert.*;
/** /**
@ -15,8 +13,8 @@ import static org.testng.Assert.*;
public class PolarParserTest { public class PolarParserTest {
@Test @Test
/** /*
* Tests if we can parse a polar data file (stored in a string), and create a polar table. Tests if we can parse a polar data file (stored in a string), and create a polar table.
*/ */
public void testParse() throws Exception { public void testParse() throws Exception {

@ -20,7 +20,6 @@ import java.util.ArrayList;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
/** /**

@ -10,10 +10,6 @@ import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.zip.CRC32; import java.util.zip.CRC32;
/**
* Created by hba56 on 21/04/17.
*/
/** /**
* This class can be used to decode/convert a byte array into a messageBody object, descended from AC35Data. * This class can be used to decode/convert a byte array into a messageBody object, descended from AC35Data.
*/ */
@ -187,7 +183,7 @@ public class BinaryMessageDecoder {
return mrDecoder.getMarkRounding(); return mrDecoder.getMarkRounding();
case COURSEWIND: case COURSEWIND:
//System.out.println("Couse Wind Message!"); //System.out.println("Course Wind Message!");
CourseWindDecoder cwDecoder = new CourseWindDecoder(messageBody); CourseWindDecoder cwDecoder = new CourseWindDecoder(messageBody);
return new CourseWinds(cwDecoder.getMessageVersionNumber(), cwDecoder.getByteWindID(), cwDecoder.getLoopMessages()); return new CourseWinds(cwDecoder.getMessageVersionNumber(), cwDecoder.getByteWindID(), cwDecoder.getLoopMessages());

@ -10,10 +10,6 @@ import static seng302.Networking.Utils.ByteConverter.intToBytes;
import static seng302.Networking.Utils.ByteConverter.longToBytes; import static seng302.Networking.Utils.ByteConverter.longToBytes;
import static seng302.Networking.Utils.ByteConverter.shortToBytes; import static seng302.Networking.Utils.ByteConverter.shortToBytes;
/**
* Created by hba56 on 21/04/17.
*/
/** /**
* This class can be used to encode/convert a byte array message body, plus header data into a byte array containing the entire message, ready to send. * This class can be used to encode/convert a byte array message body, plus header data into a byte array containing the entire message, ready to send.
*/ */

@ -1,9 +1,5 @@
package seng302.Networking.Exceptions; package seng302.Networking.Exceptions;
/**
* Created by f123 on 07-May-17.
*/
/** /**
* Exception which is thrown when a message is read, but it is invalid in some way (CRC is wrong, sync bytes, etc...). * Exception which is thrown when a message is read, but it is invalid in some way (CRC is wrong, sync bytes, etc...).
*/ */

@ -2,9 +2,6 @@ package seng302.Networking.MessageDecoders;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import static seng302.Networking.Utils.ByteConverter.*; import static seng302.Networking.Utils.ByteConverter.*;

@ -1,12 +1,7 @@
package seng302.Networking.MessageDecoders; package seng302.Networking.MessageDecoders;
import org.xml.sax.InputSource;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;

@ -1,8 +1,6 @@
package seng302.Networking.MessageEncoders; package seng302.Networking.MessageEncoders;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import static seng302.Networking.Utils.ByteConverter.intToBytes; import static seng302.Networking.Utils.ByteConverter.intToBytes;
import static seng302.Networking.Utils.ByteConverter.longToBytes; import static seng302.Networking.Utils.ByteConverter.longToBytes;

@ -1,10 +1,6 @@
package seng302.Networking.Messages; package seng302.Networking.Messages;
/**
* Created by fwy13 on 25/04/17.
*/
import seng302.Networking.Messages.Enums.MessageType; import seng302.Networking.Messages.Enums.MessageType;
/** /**

@ -1,12 +1,7 @@
package seng302.Networking.Messages; package seng302.Networking.Messages;
/**
* Created by f123 on 21-Apr-17.
*/
import SharedModel.Constants;
import seng302.Networking.Utils.AC35UnitConverter;
import seng302.Networking.Messages.Enums.MessageType; import seng302.Networking.Messages.Enums.MessageType;
import seng302.Networking.Utils.AC35UnitConverter;
import static seng302.Networking.Utils.AC35UnitConverter.convertGPS; import static seng302.Networking.Utils.AC35UnitConverter.convertGPS;
import static seng302.Networking.Utils.AC35UnitConverter.convertGPSToInt; import static seng302.Networking.Utils.AC35UnitConverter.convertGPSToInt;
@ -16,6 +11,9 @@ import static seng302.Networking.Utils.AC35UnitConverter.convertGPSToInt;
*/ */
public class BoatLocation extends AC35Data { public class BoatLocation extends AC35Data {
//Knots x this = meters per second.
public static final double KnotsToMetersPerSecondConversionFactor =
0.514444;
public static final byte Unknown = 0; public static final byte Unknown = 0;
public static final byte RacingYacht = 1; public static final byte RacingYacht = 1;
public static final byte CommitteeBoat = 2; public static final byte CommitteeBoat = 2;
@ -266,7 +264,7 @@ public class BoatLocation extends AC35Data {
*/ */
public static int convertBoatSpeedDoubleToInt(double speed) { public static int convertBoatSpeedDoubleToInt(double speed) {
//Calculate meters per second. //Calculate meters per second.
double metersPerSecond = speed * Constants.KnotsToMetersPerSecondConversionFactor; double metersPerSecond = speed * KnotsToMetersPerSecondConversionFactor;
//Calculate millimeters per second. //Calculate millimeters per second.
double millimetersPerSecond = metersPerSecond * 1000.0; double millimetersPerSecond = metersPerSecond * 1000.0;
@ -288,7 +286,7 @@ public class BoatLocation extends AC35Data {
double metersPerSecond = speed / 1000.0; double metersPerSecond = speed / 1000.0;
//Calculate knots. //Calculate knots.
double knots = metersPerSecond / Constants.KnotsToMetersPerSecondConversionFactor; double knots = metersPerSecond / KnotsToMetersPerSecondConversionFactor;
return knots; return knots;
} }

@ -3,10 +3,6 @@ package seng302.Networking.Messages.Enums;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* Created by esa46 on 28/04/17.
*/
/** /**
* Enumeration that encapsulates the various statuses a boat can have. * Enumeration that encapsulates the various statuses a boat can have.
*/ */
@ -46,8 +42,8 @@ public enum BoatStatusEnum {
private static final Map<Byte, BoatStatusEnum> byteToStatusMap = new HashMap<>(); private static final Map<Byte, BoatStatusEnum> byteToStatusMap = new HashMap<>();
/** /*
* Static initialization block. Initializes the byteToStatusMap. Static initialization block. Initializes the byteToStatusMap.
*/ */
static { static {
for (BoatStatusEnum type : BoatStatusEnum.values()) { for (BoatStatusEnum type : BoatStatusEnum.values()) {

@ -1,9 +1,5 @@
package seng302.Networking.Messages.Enums; package seng302.Networking.Messages.Enums;
/**
* Created by hba56 on 21/04/17.
*/
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -49,8 +45,8 @@ public enum MessageType {
private static final Map<Byte, MessageType> byteToTypeMap = new HashMap<>(); private static final Map<Byte, MessageType> byteToTypeMap = new HashMap<>();
/** /*
* Static initialization block. Initializes the byteToTypeMap. Static initialization block. Initializes the byteToTypeMap.
*/ */
static { static {
for (MessageType type : MessageType.values()) { for (MessageType type : MessageType.values()) {

@ -76,8 +76,8 @@ public enum RaceStatusEnum {
private static final Map<Byte, RaceStatusEnum> byteToStatusMap = new HashMap<>(); private static final Map<Byte, RaceStatusEnum> byteToStatusMap = new HashMap<>();
/** /*
* Static initialization block. Initializes the byteToStatusMap. Static initialization block. Initializes the byteToStatusMap.
*/ */
static { static {
for (RaceStatusEnum type : RaceStatusEnum.values()) { for (RaceStatusEnum type : RaceStatusEnum.values()) {

@ -54,8 +54,8 @@ public enum RaceTypeEnum {
private static final Map<Byte, RaceTypeEnum> byteToStatusMap = new HashMap<>(); private static final Map<Byte, RaceTypeEnum> byteToStatusMap = new HashMap<>();
/** /*
* Static initialization block. Initializes the byteToStatusMap. Static initialization block. Initializes the byteToStatusMap.
*/ */
static { static {
for (RaceTypeEnum type : RaceTypeEnum.values()) { for (RaceTypeEnum type : RaceTypeEnum.values()) {

@ -2,10 +2,6 @@ package seng302.Networking.Messages;
import seng302.Networking.Messages.Enums.MessageType; import seng302.Networking.Messages.Enums.MessageType;
/**
* Created by fwy13 on 25/04/17.
*/
/** /**
* Represents a Heartbeat message. * Represents a Heartbeat message.
*/ */

@ -3,7 +3,6 @@ package seng302.Networking.Messages;
import seng302.Networking.Messages.Enums.MessageType; import seng302.Networking.Messages.Enums.MessageType;
import seng302.Networking.Utils.AC35UnitConverter; import seng302.Networking.Utils.AC35UnitConverter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**

@ -13,8 +13,6 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
/** /**
* Created by fwy13 on 25/04/17. * Created by fwy13 on 25/04/17.

@ -4,9 +4,7 @@ import org.junit.Test;
import seng302.Networking.Utils.ByteConverter; import seng302.Networking.Utils.ByteConverter;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;

@ -7,7 +7,6 @@ import seng302.Networking.MessageEncoders.XMLMessageEncoder;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader;
/** /**
* Created by hba56 on 20/04/17. * Created by hba56 on 20/04/17.

@ -1,13 +0,0 @@
package SharedModel;
/**
* Constants that are used throughout the program
* Created by Erika on 19-Mar-17.
*/
public class Constants {
//Knots x this = meters per second.
public static final double KnotsToMetersPerSecondConversionFactor = 0.514444;
public static final double wakeScale = 10;
}

@ -1,99 +0,0 @@
package SharedModel;
/**
* Created by jjg64 on 19/04/17.
*/
public class Regatta {
int regattaID;
String RegattaName;
int raceID = 0;
String courseName;
double centralLatitude;
double centralLongitude;
double centralAltitude;
float utcOffset;
float magneticVariation;
public Regatta(int regattaID, String regattaName, String courseName, double centralLatitude, double centralLongitude, double centralAltitude, float utcOffset, float magneticVariation) {
this.regattaID = regattaID;
this.RegattaName = regattaName;
this.courseName = courseName;
this.centralLatitude = centralLatitude;
this.centralLongitude = centralLongitude;
this.centralAltitude = centralAltitude;
this.utcOffset = utcOffset;
this.magneticVariation = magneticVariation;
}
public int getRegattaID() {
return regattaID;
}
public void setRegattaID(int ID) {
this.regattaID = ID;
}
public String getRegattaName() {
return RegattaName;
}
public void setRegattaName(String regattaName) {
RegattaName = regattaName;
}
public int getRaceID() {
return raceID;
}
public void setRaceID(int raceID) {
this.raceID = raceID;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public double getCentralLatitude() {
return centralLatitude;
}
public void setCentralLatitude(double centralLatitude) {
this.centralLatitude = centralLatitude;
}
public double getCentralLongitude() {
return centralLongitude;
}
public void setCentralLongitude(double centralLongitude) {
this.centralLongitude = centralLongitude;
}
public double getCentralAltitude() {
return centralAltitude;
}
public void setCentralAltitude(double centralAltitude) {
this.centralAltitude = centralAltitude;
}
public float getUtcOffset() {
return utcOffset;
}
public void setUtcOffset(float utcOffset) {
this.utcOffset = utcOffset;
}
public float getMagneticVariation() {
return magneticVariation;
}
public void setMagneticVariation(float magneticVariation) {
this.magneticVariation = magneticVariation;
}
}

@ -1,17 +0,0 @@
package seng302.Controllers;
import javafx.fxml.FXML;
import javafx.scene.layout.Pane;
import java.net.URL;
import java.util.ResourceBundle;
/**
* Created by Joseph on 22/05/2017.
*/
public class ArrowController extends Controller {
@Override
public void initialize(URL location, ResourceBundle resources) {
}
}

@ -5,86 +5,45 @@ import javafx.application.Platform;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.chart.LineChart; import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import seng302.Mock.StreamedRace; import seng302.Mock.StreamedRace;
import seng302.Model.*; import seng302.Model.*;
import seng302.VisualiserInput; import seng302.VisualiserInput;
import java.net.URL; import java.net.URL;
import java.util.*; import java.util.ResourceBundle;
/** /**
* Created by fwy13 on 15/03/2017. * Created by fwy13 on 15/03/2017.
*/ */
public class RaceController extends Controller { public class RaceController extends Controller {
@FXML GridPane canvasBase;
//user saved data for annotation display
private ArrayList<Boolean> presetAnno;
private Map<String, Boolean> importantAnno;
private Map<String, Boolean> annoShownBeforeHide;
private int buttonChecked;//button currently checked allows the checkboxes to know whether or not to put it's state in history (if not hidden then store)
private int prevBtnChecked;//button to keep track of previous pressed button incase we want to check a checkbox straight from hidden we do not wish for all previous to come on.
private boolean radioBtnChecked;
private boolean selectShow = false; //button to make it so that show doesn't run the listener
private static String nameCheckAnno = "name";
private static String abbrevCheckAnno = "abbrev";
private static String speedCheckAnno = "speed";
private static String pathCheckAnno = "path";
private static String timeCheckAnno = "time";
private static String estTimeCheckAnno = "est time";
private static int noBtn = 0;
private static int hideBtn = 1;
private static int showBtn = 2;
private static int partialBtn = 3;
private static int importantBtn = 4;
private ArrayList<Boat> startBoats;
private Integer sparkLineNumber = 0;
private ResizableRaceCanvas raceMap; private ResizableRaceCanvas raceMap;
private ResizableRaceMap raceBoundaries; private ResizableRaceMap raceBoundaries;
private ToggleGroup annotationGroup;
private ArrayList<String> colours;
private Map<Integer, String> boatColours = new HashMap<>();
private int legNum;
private RaceClock raceClock; private RaceClock raceClock;
private Sparkline sparkline;
private int legNum;
@FXML GridPane canvasBase;
@FXML Pane arrow; @FXML Pane arrow;
@FXML SplitPane race; @FXML SplitPane race;
@FXML StackPane arrowPane; @FXML StackPane arrowPane;
@FXML CheckBox showFPS;
@FXML CheckBox showBoatPath;
@FXML CheckBox showName;
@FXML CheckBox showAbbrev;
@FXML CheckBox showSpeed;
@FXML CheckBox showTime;
@FXML CheckBox showEstTime;
@FXML Label timer; @FXML Label timer;
@FXML Label FPS; @FXML Label FPS;
@FXML Label timeZone; @FXML Label timeZone;
@FXML Button saveAnno; @FXML CheckBox showFPS;
@FXML TableView<Boat> boatInfoTable; @FXML TableView<Boat> boatInfoTable;
@FXML TableColumn<Boat, String> boatPlacingColumn; @FXML TableColumn<Boat, String> boatPlacingColumn;
@FXML TableColumn<Boat, String> boatTeamColumn; @FXML TableColumn<Boat, String> boatTeamColumn;
@FXML TableColumn<Boat, String> boatMarkColumn; @FXML TableColumn<Boat, String> boatMarkColumn;
@FXML TableColumn<Boat, String> boatSpeedColumn; @FXML TableColumn<Boat, String> boatSpeedColumn;
@FXML RadioButton hideAnnoRBTN;
@FXML RadioButton showAnnoRBTN;
@FXML RadioButton partialAnnoRBTN;
@FXML RadioButton importantAnnoRBTN;
@FXML LineChart<Number, Number> sparklineChart; @FXML LineChart<Number, Number> sparklineChart;
@FXML NumberAxis xAxis; @FXML AnchorPane annotationPane;
@FXML NumberAxis yAxis;
/** /**
* Updates the ResizableRaceCanvas (raceMap) with most recent data * Updates the ResizableRaceCanvas (raceMap) with most recent data
@ -107,8 +66,6 @@ public class RaceController extends Controller {
* @param race Race to listen to. * @param race Race to listen to.
*/ */
public void setInfoTable(StreamedRace race) { public void setInfoTable(StreamedRace race) {
//boatInfoTable.getItems().clear();
ObservableList<Boat> startingBoats = race.getStartingBoats();
boatInfoTable.setItems(race.getStartingBoats()); boatInfoTable.setItems(race.getStartingBoats());
boatTeamColumn.setCellValueFactory(cellData -> cellData.getValue().getName()); boatTeamColumn.setCellValueFactory(cellData -> cellData.getValue().getName());
boatSpeedColumn.setCellValueFactory(cellData -> cellData.getValue().getVelocityProp()); boatSpeedColumn.setCellValueFactory(cellData -> cellData.getValue().getVelocityProp());
@ -120,7 +77,6 @@ public class RaceController extends Controller {
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
//listener for fps //listener for fps
startBoats = new ArrayList<>();
showFPS.selectedProperty().addListener((ov, old_val, new_val) -> { showFPS.selectedProperty().addListener((ov, old_val, new_val) -> {
if (showFPS.isSelected()) { if (showFPS.isSelected()) {
FPS.setVisible(true); FPS.setVisible(true);
@ -128,70 +84,22 @@ public class RaceController extends Controller {
FPS.setVisible(false); FPS.setVisible(false);
} }
}); });
//adds all radios buttons for annotations to a group
annotationGroup = new ToggleGroup();
hideAnnoRBTN.setToggleGroup(annotationGroup);
showAnnoRBTN.setToggleGroup(annotationGroup);
partialAnnoRBTN.setToggleGroup(annotationGroup);
importantAnnoRBTN.setToggleGroup(annotationGroup);
} }
/** /**
* Creates and sets initial display for Sparkline for race positions. * Creates and sets initial display for Sparkline for race positions.
* A data series for each boat in the race is added.
* Position numbers are displayed.
*
* @param boats boats to display on the sparkline * @param boats boats to display on the sparkline
*/ */
public void createSparkLine(ObservableList<Boat> boats){ public void createSparkLine(ObservableList<Boat> boats){
// NOTE: Y axis is in negatives to display correct positions sparkline = new Sparkline(boats, legNum, sparklineChart);
}
makeColours();
startBoats.addAll(boats); /**
mapBoatColours(); * Updates the sparkline to display current boat positions.
* @param boatsInRace used for current boat positions.
// all boats start in 'last' place */
for (int i=0; i<startBoats.size(); i++){ public void updateSparkline(ObservableList<Boat> boatsInRace){
XYChart.Series<Number, Number> series = new XYChart.Series(); sparkline.updateSparkline(boatsInRace);
series.getData().add(new XYChart.Data(0, -startBoats.size()));
series.getData().add(new XYChart.Data(0, -startBoats.size()));
sparklineChart.getData().add(series);
sparklineChart.getData().get(i).getNode().setStyle("-fx-stroke: " +
""+boatColours.get(startBoats.get(i).getSourceID())+";");
}
sparklineChart.setCreateSymbols(false);
// set x axis details
xAxis.setAutoRanging(false);
xAxis.setTickMarkVisible(false);
xAxis.setTickLabelsVisible(false);
xAxis.setMinorTickVisible(false);
xAxis.setUpperBound((startBoats.size()+1)*legNum);
xAxis.setTickUnit((startBoats.size()+1)*legNum);
// set y axis details
yAxis.setLowerBound(-(startBoats.size()+1));
yAxis.setUpperBound(0);
yAxis.setAutoRanging(false);
yAxis.setLabel("Position in Race");
yAxis.setTickUnit(1);
yAxis.setTickMarkVisible(false);
yAxis.setMinorTickVisible(false);
// hide minus number from displaying on axis
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
@Override
public String toString(Number value) {
if ((Double)value == 0.0
|| (Double)value < -startBoats.size()){
return "";
}
else {
return String.format("%7.0f", -value.doubleValue());
}
}
});
} }
/** /**
@ -203,7 +111,6 @@ public class RaceController extends Controller {
*/ */
public void startRace(VisualiserInput visualiserInput, RaceClock raceClock) { public void startRace(VisualiserInput visualiserInput, RaceClock raceClock) {
//newRace.initialiseBoats();
legNum = visualiserInput.getCourse().getLegs().size()-1; legNum = visualiserInput.getCourse().getLegs().size()-1;
makeArrow(); makeArrow();
@ -212,7 +119,6 @@ public class RaceController extends Controller {
raceMap.setMouseTransparent(true); raceMap.setMouseTransparent(true);
raceMap.widthProperty().bind(canvasBase.widthProperty()); raceMap.widthProperty().bind(canvasBase.widthProperty());
raceMap.heightProperty().bind(canvasBase.heightProperty()); raceMap.heightProperty().bind(canvasBase.heightProperty());
//raceMap.setBoats(newRace.getStartingBoats());
raceMap.draw(); raceMap.draw();
raceMap.setVisible(true); raceMap.setVisible(true);
raceMap.setArrow(arrow.getChildren().get(0)); raceMap.setArrow(arrow.getChildren().get(0));
@ -230,7 +136,6 @@ public class RaceController extends Controller {
race.setVisible(true); race.setVisible(true);
//Initialize save annotation array, fps listener, and annotation listeners
timeZone.setText(raceClock.getTimeZone()); timeZone.setText(raceClock.getTimeZone());
//RaceClock.duration isn't necessarily being changed in the javaFX thread, so we need to runlater the update. //RaceClock.duration isn't necessarily being changed in the javaFX thread, so we need to runlater the update.
@ -244,8 +149,11 @@ public class RaceController extends Controller {
raceMap.setRaceClock(raceClock); raceMap.setRaceClock(raceClock);
StreamedRace newRace = new StreamedRace(visualiserInput, this); StreamedRace newRace = new StreamedRace(visualiserInput, this);
initializeFPS(); initializeFPS();
initializeAnnotations();
// set up annotation displays
new Annotations(annotationPane, raceMap);
new Thread((newRace)).start(); new Thread((newRace)).start();
} }
@ -282,260 +190,6 @@ public class RaceController extends Controller {
}); });
} }
/**
* Updates the sparkline to display current boat positions.
* New points are plotted to represent each boat when required.
*
* @param boatsInRace used for current boat positions.
*/
public void updateSparkline(ObservableList<Boat> boatsInRace){
int placingVal = boatsInRace.size();
sparkLineNumber++;
for (int i = boatsInRace.size() - 1; i >= 0; i--){
for (int j = startBoats.size() - 1; j >= 0; j--){
if (boatsInRace.get(i)==startBoats.get(j)){
// when a boat is on its first leg
if (boatsInRace.get(i).getCurrentLeg().getLegNumber()==0){
// adjust boats latest point on X axis
sparklineChart.getData().get(j).getData().get(1)
.setXValue(sparkLineNumber);
}
// when a boat first enters its second leg
else if (boatsInRace.get(i).getCurrentLeg().getLegNumber
()==1 && sparklineChart.getData().get(j).getData
().size()==2){
// adjust boats position from start mark
sparklineChart.getData().get(j).getData().get(1)
.setYValue(-placingVal);
sparklineChart.getData().get(j).getData().get(1)
.setXValue(sparkLineNumber);
sparklineChart.getData().get(j).getData().add(new XYChart.Data<>
(sparkLineNumber, -placingVal));
}
// plot new point for boats current position
else {
sparklineChart.getData().get(j).getData().add
(new XYChart.Data<>(sparkLineNumber, -placingVal));
}
placingVal-=1;
}
}
}
// xAxis.setUpperBound(sparkLineNumber);
// xAxis.setTickUnit(sparkLineNumber);
}
private void makeColours() {
colours = new ArrayList<>(Arrays.asList(
colourToHex(Color.BLUEVIOLET),
colourToHex(Color.BLACK),
colourToHex(Color.RED),
colourToHex(Color.ORANGE),
colourToHex(Color.DARKOLIVEGREEN),
colourToHex(Color.LIMEGREEN),
colourToHex(Color.PURPLE),
colourToHex(Color.DARKGRAY),
colourToHex(Color.YELLOW)
));
}
private void mapBoatColours() {
int currentColour = 0;
for (Boat boat : startBoats) {
if (!boatColours.containsKey(boat.getSourceID())) {
boatColours.put(boat.getSourceID(), colours.get(currentColour));
}
currentColour = (currentColour + 1) % colours.size();
}
}
private void storeCurrentAnnotationState(String dictionaryAnnotationKey, boolean selected){
if (buttonChecked != hideBtn) {
//if we are checking the box straight out of hide instead of using the radio buttons
annoShownBeforeHide.put(dictionaryAnnotationKey, selected);
if (prevBtnChecked == hideBtn && buttonChecked == noBtn){
storeCurrentAnnotationDictionary();
}
if (buttonChecked == noBtn) {
selectShow = false;
annotationGroup.selectToggle(showAnnoRBTN);
}
}
}
private void storeCurrentAnnotationDictionary(){
annoShownBeforeHide.put(nameCheckAnno, showName.isSelected());
annoShownBeforeHide.put(abbrevCheckAnno, showAbbrev.isSelected());
annoShownBeforeHide.put(pathCheckAnno, showBoatPath.isSelected());
annoShownBeforeHide.put(speedCheckAnno, showSpeed.isSelected());
annoShownBeforeHide.put(timeCheckAnno, showTime.isSelected());
annoShownBeforeHide.put(estTimeCheckAnno, showEstTime.isSelected());
}
/**
* Set up boat annotations
*/
private void initializeAnnotations() {
presetAnno = new ArrayList<>();
importantAnno = new HashMap<>();
importantAnno.put(nameCheckAnno, false);
importantAnno.put(abbrevCheckAnno, false);
importantAnno.put(pathCheckAnno, false);
importantAnno.put(speedCheckAnno, false);
importantAnno.put(timeCheckAnno, false);
importantAnno.put(estTimeCheckAnno, false);
annoShownBeforeHide = new HashMap<>();
annoShownBeforeHide.put(nameCheckAnno, true);
annoShownBeforeHide.put(abbrevCheckAnno, true);
annoShownBeforeHide.put(pathCheckAnno, true);
annoShownBeforeHide.put(speedCheckAnno, true);
annoShownBeforeHide.put(timeCheckAnno, true);
annoShownBeforeHide.put(estTimeCheckAnno, true);
//listener for show name in annotation
showName.selectedProperty().addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoName();
radioBtnChecked = false;
storeCurrentAnnotationState(nameCheckAnno, new_val);
raceMap.update();
}
});
//listener for show abbreviation for annotation
showAbbrev.selectedProperty().addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoAbbrev();
radioBtnChecked = false;
storeCurrentAnnotationState(abbrevCheckAnno, new_val);
raceMap.update();
}
});
//listener for show boat path for annotation
showBoatPath.selectedProperty().addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleBoatPath();
radioBtnChecked = false;
storeCurrentAnnotationState(pathCheckAnno, new_val);
raceMap.update();
}
});
//listener to show speed for annotation
showSpeed.selectedProperty().addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoSpeed();
radioBtnChecked = false;
storeCurrentAnnotationState(speedCheckAnno, new_val);
raceMap.update();
}
});
showTime.selectedProperty().addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoTime();
radioBtnChecked = false;
storeCurrentAnnotationState(timeCheckAnno, new_val);
raceMap.update();
}
});
showEstTime.selectedProperty().addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoEstTime();
radioBtnChecked = false;
storeCurrentAnnotationState(estTimeCheckAnno, new_val);
raceMap.update();
}
});
//listener to save currently selected annotation
saveAnno.setOnAction(event -> {
presetAnno.clear();
presetAnno.add(showName.isSelected());
presetAnno.add(showAbbrev.isSelected());
presetAnno.add(showSpeed.isSelected());
presetAnno.add(showBoatPath.isSelected());
presetAnno.add(showTime.isSelected());
presetAnno.add(showEstTime.isSelected());
});
//listener for hiding
hideAnnoRBTN.setOnAction((e)->{
buttonChecked = hideBtn;
selectShow = false;
showName.setSelected(false);
showAbbrev.setSelected(false);
showBoatPath.setSelected(false);
showSpeed.setSelected(false);
showTime.setSelected(false);
showEstTime.setSelected(false);
raceMap.update();
buttonChecked = noBtn;
prevBtnChecked = hideBtn;
selectShow = true;
});
//listener for showing all annotations
showAnnoRBTN.setOnAction((e)->{
if (selectShow) {
buttonChecked = showBtn;
showName.setSelected(annoShownBeforeHide.get(nameCheckAnno));
showAbbrev.setSelected(annoShownBeforeHide.get(abbrevCheckAnno));
showBoatPath.setSelected(annoShownBeforeHide.get(pathCheckAnno));
showSpeed.setSelected(annoShownBeforeHide.get(speedCheckAnno));
showTime.setSelected(annoShownBeforeHide.get(timeCheckAnno));
showEstTime.setSelected(annoShownBeforeHide.get(estTimeCheckAnno));
raceMap.update();
buttonChecked = noBtn;
prevBtnChecked = showBtn;
}
selectShow = true;
});
//listener for showing all important
partialAnnoRBTN.setOnAction((e)->{
selectShow = false;
buttonChecked = partialBtn;
showName.setSelected(false);
showAbbrev.setSelected(true);
showSpeed.setSelected(true);
showBoatPath.setSelected(false);
showTime.setSelected(false);
showEstTime.setSelected(false);
raceMap.update();
buttonChecked = noBtn;
prevBtnChecked = partialBtn;
selectShow = true;
});
//listener for showing all important
importantAnnoRBTN.setOnAction((e) ->{
selectShow = false;
buttonChecked = importantBtn;
if (presetAnno.size() > 0) {
showName.setSelected(presetAnno.get(0));
showAbbrev.setSelected(presetAnno.get(1));
showSpeed.setSelected(presetAnno.get(2));
showBoatPath.setSelected(presetAnno.get(3));
showTime.setSelected(presetAnno.get(4));
showEstTime.setSelected(presetAnno.get(5));
storeCurrentAnnotationDictionary();
raceMap.update();
}
buttonChecked = noBtn;
prevBtnChecked = importantBtn;
selectShow = true;
});
annotationGroup.selectToggle(showAnnoRBTN);
}
private String colourToHex(Color color) {
return String.format( "#%02X%02X%02X",
(int)( color.getRed() * 255 ),
(int)( color.getGreen() * 255 ),
(int)( color.getBlue() * 255 ) );
}
private void makeArrow() { private void makeArrow() {
arrowPane.getChildren().add(arrow); arrowPane.getChildren().add(arrow);
} }

@ -2,7 +2,9 @@ package seng302;
/** /**
* GPS Coordinate for the world map. * GPS Coordinate for the world map.
* Created by esa46 on 15/03/17. * It is converted to a {@link seng302.GraphCoordinate GraphCoordinate} via
* the {@link seng302.RaceMap RaceMap} to display objects in their relative
* positions on the {@link seng302.Model.ResizableRaceMap ResizableRaceMap}.
*/ */
public class GPSCoordinate { public class GPSCoordinate {

@ -1,8 +1,10 @@
package seng302; package seng302;
/** /**
* Graph Coordinate that is to be displayed on the Canvas * It is a coordinate representing a location on the
* Created by cbt24 on 15/03/17. * {@link seng302.Model.ResizableRaceMap ResizableRaceMap}.
* It has been converted from a {@link seng302.GPSCoordinate GPSCoordinate}
* to display objects in their relative positions.
*/ */
public class GraphCoordinate { public class GraphCoordinate {
private final int x; private final int x;

@ -15,7 +15,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* XML Read that reads the Boats that are goign to participate in the Race * XML Reader that reads in a file and initializes
* {@link seng302.Mock.StreamedBoat StreamedBoat}s that will be participating
* in a race.
*/ */
public class BoatXMLReader extends XMLReader { public class BoatXMLReader extends XMLReader {
private final Map<Integer, StreamedBoat> streamedBoatMap = new HashMap<>(); private final Map<Integer, StreamedBoat> streamedBoatMap = new HashMap<>();
@ -122,8 +124,9 @@ public class BoatXMLReader extends XMLReader {
} }
for (int i = 0; i < boat.getChildNodes().getLength(); i++) { for (int i = 0; i < boat.getChildNodes().getLength(); i++) {
Node GPSPosition = boat.getChildNodes().item(i); Node GPSposition = boat.getChildNodes().item(i);
if (GPSPosition.getNodeName().equals("GPSposition")) readBoatPositionInformation(sourceID, GPSPosition); if (GPSposition.getNodeName().equals("GPSposition"))
readBoatPositionInformation(sourceID, GPSposition);
} }
} }
} }
@ -131,12 +134,13 @@ public class BoatXMLReader extends XMLReader {
/** /**
* Reads the positional information about a boat * Reads the positional information about a boat
* Ignored values: FlagPosition, MastTop, Z value of GPSposition * Ignored values: FlagPosition, MastTop, Z value of GPSPosition
* @param sourceID The source ID of the boat. * @param sourceID The source ID of the boat.
* @param GPSPosition The relative GPS position of the boat. * @param GPSposition The relative GPS position of the boat.
*/ */
private void readBoatPositionInformation(int sourceID, Node GPSPosition) { private void readBoatPositionInformation(int sourceID, Node GPSposition) {
// TODO Get relative point before implementing. (GPSposition is based off a relative point). // TODO Get relative point before implementing. (GPSposition is based
// off a relative point).
} }
/** /**

@ -268,9 +268,10 @@ public class StreamedRace implements Runnable {
} }
/** /**
* Takes an estimated time an event will occur, and converts it to the number of seconds before the event will occur. * Takes an estimated time an event will occur, and converts it to the
* number of seconds before the event will occur.
* *
* @param estTimeMillis * @param estTimeMillis estimated time in milliseconds
* @return int difference between time the race started and the estimated time * @return int difference between time the race started and the estimated time
*/ */
private int convertEstTime(long estTimeMillis, long currentTime) { private int convertEstTime(long estTimeMillis, long currentTime) {

@ -0,0 +1,284 @@
package seng302.Model;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Toggle;
import javafx.scene.layout.AnchorPane;
import java.util.HashMap;
import java.util.Map;
/**
* Class that processes user selected annotation visibility options to
* display the requested information on the
* {@link seng302.Model.ResizableRaceMap ResizbleRaceMap}. These are displayed
* via the {@link seng302.Controllers.RaceController RaceController}. <br>
* Annotation options for a {@link seng302.Model.Boat Boat} include: its name,
* abbreviation, speed, the time since it passed the last
* {@link seng302.Model.Marker Marker}, estimated time to the next marker,
* and a path it has travelled made up of
* {@link seng302.Model.TrackPoint TrackPoint}s.
*/
public class Annotations {
private ResizableRaceCanvas raceMap;
// checkable objects in the anchor pane
private Map<String, CheckBox> checkBoxes = new HashMap<>();
private Map<String, Toggle> annoToggles = new HashMap<>();
// maps of selected and saved annotations
private Map<String, Boolean> importantAnno = new HashMap<>();
private Map<String, Boolean> annoShownBeforeHide = new HashMap<>();
// string values match the fx:id value of check boxes
private static String nameCheckAnno = "showName";
private static String abbrevCheckAnno = "showAbbrev";
private static String speedCheckAnno = "showSpeed";
private static String pathCheckAnno = "showBoatPath";
private static String timeCheckAnno = "showTime";
private static String estTimeCheckAnno = "showEstTime";
// string values match the fx:id value of radio buttons
private static String noBtn = "noBtn";
private static String hideBtn = "hideAnnoRBtn";
private static String showBtn = "showAnnoRBtn";
private static String partialBtn = "partialAnnoRBtn";
private static String importantBtn = "importantAnnoRBtn";
private Boolean selectShow = false;
private String buttonChecked;
private String prevBtnChecked;
@FXML Button saveAnnoBtn;
/**
* Constructor to set up and display initial annotations
* @param annotationPane javaFX pane containing annotation options
* @param raceMap the canvas to update annotation displays
*/
public Annotations(AnchorPane annotationPane, ResizableRaceCanvas raceMap){
this.raceMap = raceMap;
for (Node child : annotationPane.getChildren()) {
// collect all check boxes into a map
if (child.getClass()==CheckBox.class){
checkBoxes.put(child.getId(), (CheckBox)child);
}
// collect annotation toggle radio buttons into a map
else if (child.getClass()== RadioButton.class){
//annotationGroup.getToggles().add((RadioButton)child);
annoToggles.put(child.getId(), (RadioButton)child);
}
else if (child.getClass() == Button.class){
saveAnnoBtn = (Button)child;
}
}
initializeAnnotations();
}
/**
* Set up initial boat annotations and shows all data.
* Defines partial annotations.
* Creates listeners for when the user selects a different annotation
* visibility.
*/
public void initializeAnnotations() {
for (Map.Entry<String, CheckBox> checkBox : checkBoxes.entrySet())
{ annoShownBeforeHide.put(checkBox.getKey(), true); }
addCheckBoxListeners();
addSaveAnnoListener();
addAnnoToggleListeners();
annoToggles.get(showBtn).setSelected(true);
}
/**
* Creates listeners for each checkbox so the annotation display is
* updated when a user selects a different level of annotation visibility.
*/
private void addCheckBoxListeners(){
//listener for show name in annotation
checkBoxes.get(nameCheckAnno).selectedProperty()
.addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoName();
storeCurrentAnnotationState(nameCheckAnno, new_val);
raceMap.update();
}
});
//listener for show abbreviation for annotation
checkBoxes.get(abbrevCheckAnno).selectedProperty()
.addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoAbbrev();
storeCurrentAnnotationState(abbrevCheckAnno, new_val);
raceMap.update();
}
});
//listener for show boat path for annotation
checkBoxes.get(pathCheckAnno).selectedProperty()
.addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleBoatPath();
storeCurrentAnnotationState(pathCheckAnno, new_val);
raceMap.update();
}
});
//listener to show speed for annotation
checkBoxes.get(speedCheckAnno).selectedProperty()
.addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoSpeed();
storeCurrentAnnotationState(speedCheckAnno, new_val);
raceMap.update();
}
});
//listener to show time for annotation
checkBoxes.get(timeCheckAnno).selectedProperty()
.addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoTime();
storeCurrentAnnotationState(timeCheckAnno, new_val);
raceMap.update();
}
});
//listener to show estimated time for annotation
checkBoxes.get(estTimeCheckAnno).selectedProperty()
.addListener((ov, old_val, new_val) -> {
if (old_val != new_val) {
raceMap.toggleAnnoEstTime();
storeCurrentAnnotationState(estTimeCheckAnno, new_val);
raceMap.update();
}
});
}
/**
* Creates a listener so the system knows when to save a users currently
* selected annotation options as important for future use.
*/
private void addSaveAnnoListener(){
//listener to save currently selected annotations as important
saveAnnoBtn.setOnAction(event -> {
importantAnno.clear();
for (Map.Entry<String, CheckBox> checkBox : checkBoxes.entrySet()){
importantAnno.put(checkBox.getKey(),
checkBox.getValue().isSelected());
}
});
}
/**
* Creates listeners for each visibility option so that the annotation
* display is updated when a user selects a different level of annotation
* visibility.
*/
private void addAnnoToggleListeners(){
//listener for hiding all annotations
RadioButton hideAnnoRBtn = (RadioButton)annoToggles.get(hideBtn);
hideAnnoRBtn.setOnAction((e)->{
buttonChecked = hideBtn;
selectShow = false;
for (Map.Entry<String, CheckBox> checkBox : checkBoxes.entrySet()){
checkBox.getValue().setSelected(false);
}
raceMap.update();
buttonChecked = noBtn;
prevBtnChecked = hideBtn;
selectShow = true;
});
//listener for showing previously visible annotations
RadioButton showAnnoRBTN = (RadioButton)annoToggles.get(showBtn);
showAnnoRBTN.setOnAction((e)->{
if (selectShow) {
buttonChecked = showBtn;
for (Map.Entry<String, CheckBox> checkBox : checkBoxes.entrySet()){
checkBox.getValue().setSelected(
annoShownBeforeHide.get(checkBox.getKey()));
}
raceMap.update();
buttonChecked = noBtn;
prevBtnChecked = showBtn;
}
selectShow = true;
});
//listener for showing a predetermined subset of annotations
RadioButton partialAnnoRBTN = (RadioButton)annoToggles.get(partialBtn);
partialAnnoRBTN.setOnAction((e)->{
selectShow = false;
buttonChecked = partialBtn;
for (Map.Entry<String, CheckBox> checkBox : checkBoxes.entrySet()){
// the checkbox defaults for partial annotations
if (checkBox.getKey().equals(abbrevCheckAnno)
|| checkBox.getKey().equals(speedCheckAnno)){
checkBox.getValue().setSelected(true);
}
else { checkBox.getValue().setSelected(false); }
}
raceMap.update();
buttonChecked = noBtn;
prevBtnChecked = partialBtn;
selectShow = true;
});
//listener for showing all saved important annotations
RadioButton importantAnnoRBTN = (RadioButton)annoToggles.get(importantBtn);
importantAnnoRBTN.setOnAction((e) ->{
selectShow = false;
buttonChecked = importantBtn;
if (importantAnno.size()>0){
for (Map.Entry<String, CheckBox> checkBox : checkBoxes.entrySet()){
checkBox.getValue().setSelected
(importantAnno.get(checkBox.getKey()));
}
}
buttonChecked = noBtn;
prevBtnChecked = importantBtn;
selectShow = true;
});
}
/**
* Updates the current state of an annotation so that when a user
* deselects the hidden visibility option, the previous annotations will
* be displayed again.
* @param dictionaryAnnotationKey annotation checkbox
* @param selected boolean value representing the state of the checkbox
*/
private void storeCurrentAnnotationState(String dictionaryAnnotationKey, boolean selected){
if (buttonChecked != hideBtn) {
//if we are checking the box straight out of hide instead of using the radio buttons
annoShownBeforeHide.put(dictionaryAnnotationKey, selected);
if (prevBtnChecked == hideBtn && buttonChecked == noBtn){
storeCurrentAnnotationDictionary();
}
if (buttonChecked == noBtn) {
selectShow = false;
annoToggles.get(showBtn).setSelected(true);
}
}
}
/**
* Stores all current annotation states so that when a user
* deselects the hidden visibility option, the previous annotations will
* be displayed again.
*/
private void storeCurrentAnnotationDictionary(){
for (Map.Entry<String, CheckBox> checkBox : checkBoxes.entrySet()){
annoShownBeforeHide.put(checkBox.getKey(),
checkBox.getValue().isSelected());
}
}
}

@ -11,7 +11,10 @@ import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
/** /**
* Created by fwy13 on 3/03/17. * This class is used to represent and store information about a boat which may
* travel around in a race. It is displayed on the
* {@link seng302.Model.ResizableRaceCanvas ResizableRaceCanvas} via the
* {@link seng302.Controllers.RaceController RaceController}.
*/ */
public class Boat { public class Boat {

@ -1,310 +1,311 @@
package seng302.Model; //package seng302.Model;
//
import javafx.beans.property.SimpleStringProperty; //import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; //import javafx.beans.property.StringProperty;
import javafx.scene.paint.Color; //import javafx.scene.paint.Color;
import org.geotools.referencing.GeodeticCalculator; //import org.geotools.referencing.GeodeticCalculator;
import seng302.GPSCoordinate; //import seng302.GPSCoordinate;
//
import java.awt.geom.Point2D; //import java.awt.geom.Point2D;
import java.util.Queue; //import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; //import java.util.concurrent.ConcurrentLinkedQueue;
//
/** ///**
* Boat in the Race extends Boat. // * Boat in the Race extends {@link seng302.Model.Boat Boat}.
* Created by esa46 on 15/03/17. // * The extended properties are related to the boats current race position.
*/ // * @See seng302.Model.Boat
public class BoatInRace extends Boat { // */
//public class BoatInRace extends Boat {
private Leg currentLeg; //
private double scaledVelocity; // private Leg currentLeg;
private double distanceTravelledInLeg; // private double scaledVelocity;
private GPSCoordinate currentPosition; // private double distanceTravelledInLeg;
private long timeFinished; // private GPSCoordinate currentPosition;
private Color colour; // private long timeFinished;
private boolean finished = false; // private Color colour;
private final StringProperty currentLegName; // private boolean finished = false;
private boolean started = false; // private final StringProperty currentLegName;
private final StringProperty position; // private boolean started = false;
private double heading; // private final StringProperty position;
private static final double WAKE_SCALE = 10; // private double heading;
// private static final double WAKE_SCALE = 10;
private final Queue<TrackPoint> track = new ConcurrentLinkedQueue<>(); //
private long nextValidTime = 0; // private final Queue<TrackPoint> track = new ConcurrentLinkedQueue<>();
// private long nextValidTime = 0;
private static final float BASE_TRACK_POINT_TIME_INTERVAL = 5000; //
private static float trackPointTimeInterval = 5000; // every 1 seconds // private static final float BASE_TRACK_POINT_TIME_INTERVAL = 5000;
// private static float trackPointTimeInterval = 5000; // every 1 seconds
/** //
* Constructor method. // /**
* // * Constructor method.
* @param name Name of the boat. // *
* @param velocity Speed that the boat travels. // * @param name Name of the boat.
* @param colour Colour the boat will be displayed as on the map // * @param velocity Speed that the boat travels.
* @param abbrev of boat // * @param colour Colour the boat will be displayed as on the map
*/ // * @param abbrev of boat
public BoatInRace(String name, double velocity, Color colour, String abbrev) { // */
super(name, velocity, abbrev); // public BoatInRace(String name, double velocity, Color colour, String abbrev) {
setColour(colour); // super(name, velocity, abbrev);
currentLegName = new SimpleStringProperty(""); // setColour(colour);
position = new SimpleStringProperty("-"); // currentLegName = new SimpleStringProperty("");
} // position = new SimpleStringProperty("-");
// }
/** //
* Calculates the azimuth of the travel via map coordinates of the raceMarkers // /**
* // * Calculates the azimuth of the travel via map coordinates of the raceMarkers
* @return the direction that the boat is heading towards in degrees (-180 to 180). // *
*/ // * @return the direction that the boat is heading towards in degrees (-180 to 180).
public double calculateAzimuth() { // */
// public double calculateAzimuth() {
GeodeticCalculator calc = new GeodeticCalculator(); //
GPSCoordinate start = currentLeg.getStartMarker().getAverageGPSCoordinate(); // GeodeticCalculator calc = new GeodeticCalculator();
GPSCoordinate end = currentLeg.getEndMarker().getAverageGPSCoordinate(); // GPSCoordinate start = currentLeg.getStartMarker().getAverageGPSCoordinate();
// GPSCoordinate end = currentLeg.getEndMarker().getAverageGPSCoordinate();
calc.setStartingGeographicPoint(start.getLongitude(), start.getLatitude()); //
calc.setDestinationGeographicPoint(end.getLongitude(), end.getLatitude()); // calc.setStartingGeographicPoint(start.getLongitude(), start.getLatitude());
// calc.setDestinationGeographicPoint(end.getLongitude(), end.getLatitude());
return calc.getAzimuth(); //
} // return calc.getAzimuth();
// }
/** //
* Converts an azimuth to a bearing // /**
* // * Converts an azimuth to a bearing
* @param azimuth azimuth value to be converted // *
* @return the bearings in degrees (0 to 360). // * @param azimuth azimuth value to be converted
*/ // * @return the bearings in degrees (0 to 360).
private static double calculateHeading(double azimuth) { // */
if (azimuth >= 0) { // private static double calculateHeading(double azimuth) {
return azimuth; // if (azimuth >= 0) {
} else { // return azimuth;
return azimuth + 360; // } else {
} // return azimuth + 360;
} // }
// }
public double getHeading() { //
return heading; // public double getHeading() {
} // return heading;
// }
public void setHeading(double heading) { //
this.heading = heading; // public void setHeading(double heading) {
} // this.heading = heading;
// }
/** //
* Calculates the bearing of the travel via map coordinates of the raceMarkers // /**
* // * Calculates the bearing of the travel via map coordinates of the raceMarkers
* @return the direction that the boat is heading towards in degrees (0 to 360). // *
*/ // * @return the direction that the boat is heading towards in degrees (0 to 360).
public double calculateHeading() { // */
double azimuth = calculateAzimuth(); // public double calculateHeading() {
return calculateHeading(azimuth); // double azimuth = calculateAzimuth();
} // return calculateHeading(azimuth);
// }
/** //
* 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 // * Returns the position of the end of the boat's wake, which is 180 degrees
* speed. // * from the boat's heading, and whose length is proportional to the boat's
* // * speed.
* @return GPSCoordinate of wake endpoint. // *
*/ // * @return GPSCoordinate of wake endpoint.
public GPSCoordinate getWake() { // */
double reverseHeading = getHeading() - 180; // public GPSCoordinate getWake() {
double distance = WAKE_SCALE * getVelocity(); // double reverseHeading = getHeading() - 180;
// double distance = WAKE_SCALE * getVelocity();
GeodeticCalculator calc = new GeodeticCalculator(); //
calc.setStartingGeographicPoint( // GeodeticCalculator calc = new GeodeticCalculator();
new Point2D.Double(getCurrentPosition().getLongitude(), getCurrentPosition().getLatitude()) // calc.setStartingGeographicPoint(
); // new Point2D.Double(getCurrentPosition().getLongitude(), getCurrentPosition().getLatitude())
calc.setDirection(reverseHeading, distance); // );
Point2D endpoint = calc.getDestinationGeographicPoint(); // calc.setDirection(reverseHeading, distance);
return new GPSCoordinate(endpoint.getY(), endpoint.getX()); // Point2D endpoint = calc.getDestinationGeographicPoint();
} // return new GPSCoordinate(endpoint.getY(), endpoint.getX());
// }
/** //
* @return Scaled velocity of the boat // /**
*/ // * @return Scaled velocity of the boat
public double getScaledVelocity() { // */
return scaledVelocity; // public double getScaledVelocity() {
} // return scaledVelocity;
// }
/** //
* Sets the boat's scaled velocity // /**
* // * Sets the boat's scaled velocity
* @param velocity of boat // *
*/ // * @param velocity of boat
public void setScaledVelocity(double velocity) { // */
this.scaledVelocity = velocity; // public void setScaledVelocity(double velocity) {
} // this.scaledVelocity = velocity;
// }
/** //
* @return Returns the current position of the boat in a GPSCoordinate Class. // /**
* @see GPSCoordinate // * @return Returns the current position of the boat in a GPSCoordinate Class.
*/ // * @see GPSCoordinate
public GPSCoordinate getCurrentPosition() { // */
return currentPosition; // public GPSCoordinate getCurrentPosition() {
} // return currentPosition;
// }
/** //
* Sets the current position on the GPS that the boat. // /**
* // * Sets the current position on the GPS that the boat.
* @param position GPSCoordinate of the position that the boat is currently on. // *
* @see GPSCoordinate // * @param position GPSCoordinate of the position that the boat is currently on.
*/ // * @see GPSCoordinate
public void setCurrentPosition(GPSCoordinate position) { // */
this.currentPosition = position; // public void setCurrentPosition(GPSCoordinate position) {
} // this.currentPosition = position;
// }
/** //
* @return Returns the time that the boat finished the race. // /**
*/ // * @return Returns the time that the boat finished the race.
public long getTimeFinished() { // */
return timeFinished; // public long getTimeFinished() {
} // return timeFinished;
// }
/** //
* Sets the time that the boat finished the race. // /**
* // * Sets the time that the boat finished the race.
* @param timeFinished Time the boat finished the race. // *
*/ // * @param timeFinished Time the boat finished the race.
public void setTimeFinished(long timeFinished) { // */
this.timeFinished = timeFinished; // public void setTimeFinished(long timeFinished) {
} // this.timeFinished = timeFinished;
// }
/** //
* @return Returns the colour of the boat. // /**
*/ // * @return Returns the colour of the boat.
public Color getColour() { // */
return colour; // public Color getColour() {
} // return colour;
// }
/** //
* Sets the colour that boat will be shown as when drawn on the ResizableRaceCanvas. // /**
* // * Sets the colour that boat will be shown as when drawn on the ResizableRaceCanvas.
* @param colour Colour that the boat is to be set to. // *
* @see ResizableRaceCanvas // * @param colour Colour that the boat is to be set to.
*/ // * @see ResizableRaceCanvas
private void setColour(Color colour) { // */
this.colour = colour; // private void setColour(Color colour) {
} // this.colour = colour;
// }
/** //
* Gets the current leg that the boat is on. // /**
* // * Gets the current leg that the boat is on.
* @return returns the leg the boat is on in a Leg class // *
* @see Leg // * @return returns the leg the boat is on in a Leg class
*/ // * @see Leg
public Leg getCurrentLeg() { // */
return currentLeg; // public Leg getCurrentLeg() {
} // return currentLeg;
// }
/** //
* Sets the boat's current leg. // /**
* // * Sets the boat's current leg.
* @param currentLeg Leg class that the boat is currently on. // *
* @see Leg // * @param currentLeg Leg class that the boat is currently on.
*/ // * @see Leg
public void setCurrentLeg(Leg currentLeg) { // */
this.currentLeg = currentLeg; // public void setCurrentLeg(Leg currentLeg) {
this.currentLegName.setValue(currentLeg.getName()); // this.currentLeg = currentLeg;
} // this.currentLegName.setValue(currentLeg.getName());
// }
/** //
* @return Name of boat's current leg // /**
*/ // * @return Name of boat's current leg
public StringProperty getCurrentLegName() { // */
return currentLegName; // public StringProperty getCurrentLegName() {
} // return currentLegName;
// }
/** //
* Gets the distance travelled by the boat in the leg. // /**
* // * Gets the distance travelled by the boat in the leg.
* @return Returns the value in nautical miles (1.852km) that the boat has traversed. // *
*/ // * @return Returns the value in nautical miles (1.852km) that the boat has traversed.
public double getDistanceTravelledInLeg() { // */
return distanceTravelledInLeg; // public double getDistanceTravelledInLeg() {
} // return distanceTravelledInLeg;
// }
/** //
* Sets the distance travelled by the boat in the leg in nautical miles (1.852km) // /**
* // * Sets the distance travelled by the boat in the leg in nautical miles (1.852km)
* @param distanceTravelledInLeg Distance travelled by the boat in nautical miles. // *
*/ // * @param distanceTravelledInLeg Distance travelled by the boat in nautical miles.
public void setDistanceTravelledInLeg(double distanceTravelledInLeg) { // */
this.distanceTravelledInLeg = distanceTravelledInLeg; // public void setDistanceTravelledInLeg(double distanceTravelledInLeg) {
} // this.distanceTravelledInLeg = distanceTravelledInLeg;
// }
/** //
* @return true if boat has finished, false if not // /**
*/ // * @return true if boat has finished, false if not
public boolean isFinished() { // */
return this.finished; // public boolean isFinished() {
} // return this.finished;
// }
/** //
* Sets whether boat is finished or not // /**
* // * Sets whether boat is finished or not
* @param bool is finished value // *
*/ // * @param bool is finished value
public void setFinished(boolean bool) { // */
this.finished = bool; // public void setFinished(boolean bool) {
} // this.finished = bool;
// }
public boolean isStarted() { //
return started; // public boolean isStarted() {
} // return started;
// }
public void setStarted(boolean started) { //
this.started = started; // public void setStarted(boolean started) {
} // this.started = started;
// }
public String getPosition() { //
return position.get(); // public String getPosition() {
} // return position.get();
// }
public StringProperty positionProperty() { //
return position; // public StringProperty positionProperty() {
} // return position;
// }
public void setPosition(String position) { //
this.position.set(position); // public void setPosition(String position) {
} // this.position.set(position);
// }
/** //
* Adds a new point to boat's track. // /**
* @param coordinate of point on track // * Adds a new point to boat's track.
* @see seng302.Model.TrackPoint // * @param coordinate of point on track
*/ // * @see seng302.Model.TrackPoint
public void addTrackPoint(GPSCoordinate coordinate) { // */
Boolean added = System.currentTimeMillis() >= nextValidTime; // public void addTrackPoint(GPSCoordinate coordinate) {
long currentTime = System.currentTimeMillis(); // Boolean added = System.currentTimeMillis() >= nextValidTime;
if (added && this.started) { // long currentTime = System.currentTimeMillis();
nextValidTime = currentTime + (long) trackPointTimeInterval; // if (added && this.started) {
int TRACK_POINT_LIMIT = 10; // nextValidTime = currentTime + (long) trackPointTimeInterval;
track.add(new TrackPoint(coordinate, currentTime, TRACK_POINT_LIMIT * (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 // * Returns the boat's sampled track between start of race and current time.
* @see seng302.Model.TrackPoint // * @return queue of track points
*/ // * @see seng302.Model.TrackPoint
public Queue<TrackPoint> getTrack() { // */
return track; // public Queue<TrackPoint> getTrack() {
} // return track;
// }
/** //
* Get base track point time interval // /**
* @return base track point time interval // * Get base track point time interval
*/ // * @return base track point time interval
public static float getBaseTrackPointTimeInterval() { // */
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 // * Set track point time interval
*/ // * @param value track point time interval value
public static void setTrackPointTimeInterval(float value) { // */
trackPointTimeInterval = value; // public static void setTrackPointTimeInterval(float value) {
} // trackPointTimeInterval = value;
} // }
//}

@ -4,7 +4,9 @@ import org.geotools.referencing.GeodeticCalculator;
import seng302.GPSCoordinate; import seng302.GPSCoordinate;
/** /**
* Created by cbt24 on 6/03/17. * This class represents a leg, which is a portion of a race between two
* {@link seng302.Model.Marker Marker}s. A leg is used to identify a
* {@link seng302.Model.Boat Boat}'s progress through a race.
*/ */
public class Leg { public class Leg {
private final String name; //nautical miles private final String name; //nautical miles

@ -6,7 +6,11 @@ import seng302.GPSCoordinate;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
/** /**
* Created by esa46 on 29/03/17. * A marker on a race course that a boat can pass, to be displayed on the
* {@link seng302.Model.ResizableRaceCanvas ResizableRaceCanvas}. This is
* displayed via the {@link seng302.Controllers.RaceController RaceController}.
* <br>Markers are also used to calculate a {@link seng302.Model.Leg Leg}
* distance.
*/ */
public class Marker { public class Marker {
private final GPSCoordinate averageGPSCoordinate; private final GPSCoordinate averageGPSCoordinate;

@ -16,7 +16,11 @@ import java.time.temporal.ChronoUnit;
import java.util.Date; import java.util.Date;
/** /**
* Created by Gondr on 19/04/2017. * This class is used to implement a clock which keeps track of and
* displays times relevant to a race. This is displayed on the
* {@link seng302.Model.ResizableRaceCanvas ResizableRaceCanvas} via the
* {@link seng302.Controllers.RaceController RaceController} and the
* {@link seng302.Controllers.StartController StartController}.
*/ */
public class RaceClock implements Runnable { public class RaceClock implements Runnable {
private long lastTime; private long lastTime;

@ -4,7 +4,7 @@ import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext; import javafx.scene.canvas.GraphicsContext;
/** /**
* Created by fwy13 on 4/05/17. * The abstract class for the resizable race canvases.
*/ */
public abstract class ResizableCanvas extends Canvas { public abstract class ResizableCanvas extends Canvas {
protected final GraphicsContext gc; protected final GraphicsContext gc;

@ -16,9 +16,16 @@ import java.time.ZonedDateTime;
import java.util.*; import java.util.*;
/** /**
* This creates a JavaFX Canvas that is fills it's parent. * This JavaFX Canvas is used to update and display details for a
* Cannot be downsized. * {@link seng302.RaceMap RaceMap} via the
* Created by fwy13 on 17/03/17. * {@link seng302.Controllers.RaceController RaceController}.<br>
* It fills it's parent and cannot be downsized. <br>
* Details displayed include:
* {@link seng302.Model.Boat Boats} (and their
* {@link seng302.Model.TrackPoint TrackPoint}s),
* {@link seng302.Model.Marker Markers}, a
* {@link seng302.Model.RaceClock RaceClock}, a wind direction arrow and
* various user selected {@link seng302.Model.Annotations Annotations}.
*/ */
public class ResizableRaceCanvas extends ResizableCanvas { public class ResizableRaceCanvas extends ResizableCanvas {
private RaceMap map; private RaceMap map;

@ -9,7 +9,10 @@ import seng302.RaceMap;
import java.util.List; import java.util.List;
/** /**
* Created by fwy13 on 4/05/17. * This JavaFX Canvas is used to generate the size of a
* {@link seng302.RaceMap RaceMap} using co-ordinates from a
* {@link seng302.RaceDataSource RaceDataSource}. This is done via the
* {@link seng302.Controllers.RaceController RaceController}.
*/ */
public class ResizableRaceMap extends ResizableCanvas { public class ResizableRaceMap extends ResizableCanvas {
private RaceMap map; private RaceMap map;
@ -34,8 +37,8 @@ public class ResizableRaceMap extends ResizableCanvas {
} }
/** /**
* Sets the map race that it is auppost to be viewing. * Sets the map race that it is supposed to be viewing.
* @param map * @param map the map to be set
*/ */
private void setMap(RaceMap map) { private void setMap(RaceMap map) {
this.map = map; this.map = map;

@ -0,0 +1,179 @@
package seng302.Model;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.paint.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* Class to process and modify a sparkline display. This display keeps visual
* track of {@link seng302.Model.Boat Boats}s in a race and their current
* placing position as they complete each {@link seng302.Model.Leg Leg} by
* passing a course {@link seng302.Model.Marker Marker}. <br>
* This sparkline is displayed using the
* {@link seng302.Controllers.RaceController RaceController}.
*/
public class Sparkline {
private ArrayList<String> colours;
private ArrayList<Boat> startBoats = new ArrayList<>();
private Map<Integer, String> boatColours = new HashMap<>();
private Integer legNum;
private Integer sparkLineNumber = 0;
@FXML LineChart<Number, Number> sparklineChart;
@FXML NumberAxis xAxis;
@FXML NumberAxis yAxis;
/**
* Constructor to set up initial sparkline (LineChart) object
* @param boats boats to display on the sparkline
* @param legNum total number of legs in the race
* @param sparklineChart javaFX LineChart for the sparkline
*/
public Sparkline(ObservableList<Boat> boats, Integer legNum,
LineChart<Number,Number> sparklineChart) {
this.sparklineChart = sparklineChart;
this.legNum = legNum;
this.yAxis = (NumberAxis)sparklineChart.getYAxis();
this.xAxis = (NumberAxis)sparklineChart.getXAxis();
startBoats.addAll(boats);
makeColours();
mapBoatColours();
createSparkline();
}
/**
* Creates and sets initial display for Sparkline for race positions.
* A data series for each boat in the race is added.
* Position numbers are displayed.
*/
public void createSparkline(){
// NOTE: Y axis is in negatives to display correct positions
// all boats start in 'last' place
for (int i=0; i<startBoats.size(); i++){
XYChart.Series<Number, Number> series = new XYChart.Series();
series.getData().add(new XYChart.Data(0, -startBoats.size()));
series.getData().add(new XYChart.Data(0, -startBoats.size()));
sparklineChart.getData().add(series);
sparklineChart.getData().get(i).getNode().setStyle("-fx-stroke: " +
""+boatColours.get(startBoats.get(i).getSourceID())+";");
}
sparklineChart.setCreateSymbols(false);
// set x axis details
xAxis.setAutoRanging(false);
xAxis.setTickMarkVisible(false);
xAxis.setTickLabelsVisible(false);
xAxis.setMinorTickVisible(false);
xAxis.setUpperBound((startBoats.size()+1)*legNum);
xAxis.setTickUnit((startBoats.size()+1)*legNum);
// set y axis details
yAxis.setLowerBound(-(startBoats.size()+1));
yAxis.setUpperBound(0);
yAxis.setAutoRanging(false);
yAxis.setLabel("Position in Race");
yAxis.setTickUnit(1);
yAxis.setTickMarkVisible(false);
yAxis.setMinorTickVisible(false);
// hide minus number from displaying on axis
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
@Override
public String toString(Number value) {
if ((Double)value == 0.0
|| (Double)value < -startBoats.size()){
return "";
}
else {
return String.format("%7.0f", -value.doubleValue());
}
}
});
}
/**
* Updates the sparkline to display current boat positions.
* New points are plotted to represent each boat when required.
* @param boatsInRace current position of the boats in race
*/
public void updateSparkline(ObservableList<Boat> boatsInRace){
int placingVal = boatsInRace.size();
sparkLineNumber++;
for (int i = boatsInRace.size() - 1; i >= 0; i--){
for (int j = startBoats.size() - 1; j >= 0; j--){
if (boatsInRace.get(i)==startBoats.get(j)){
// when a boat is on its first leg
if (boatsInRace.get(i).getCurrentLeg().getLegNumber()==0){
// adjust boats latest point on X axis
sparklineChart.getData().get(j).getData().get(1)
.setXValue(sparkLineNumber);
}
// when a boat first enters its second leg
else if (boatsInRace.get(i).getCurrentLeg().getLegNumber
()==1 && sparklineChart.getData().get(j).getData
().size()==2){
// adjust boats position from start mark
sparklineChart.getData().get(j).getData().get(1)
.setYValue(-placingVal);
sparklineChart.getData().get(j).getData().get(1)
.setXValue(sparkLineNumber);
sparklineChart.getData().get(j).getData().add(new XYChart.Data<>
(sparkLineNumber, -placingVal));
}
// plot new point for boats current position
else {
sparklineChart.getData().get(j).getData().add
(new XYChart.Data<>(sparkLineNumber, -placingVal));
}
placingVal-=1;
}
}
}
}
private void makeColours() {
colours = new ArrayList<>(Arrays.asList(
colourToHex(Color.BLUEVIOLET),
colourToHex(Color.BLACK),
colourToHex(Color.RED),
colourToHex(Color.ORANGE),
colourToHex(Color.DARKOLIVEGREEN),
colourToHex(Color.LIMEGREEN),
colourToHex(Color.PURPLE),
colourToHex(Color.DARKGRAY),
colourToHex(Color.YELLOW)
));
}
private String colourToHex(Color color) {
return String.format( "#%02X%02X%02X",
(int)( color.getRed() * 255 ),
(int)( color.getGreen() * 255 ),
(int)( color.getBlue() * 255 ) );
}
private void mapBoatColours() {
int currentColour = 0;
for (Boat boat : startBoats) {
if (!boatColours.containsKey(boat.getSourceID())) {
boatColours.put(boat.getSourceID(), colours.get(currentColour));
}
currentColour = (currentColour + 1) % colours.size();
}
}
}

@ -3,7 +3,13 @@ package seng302.Model;
import seng302.GPSCoordinate; import seng302.GPSCoordinate;
/** /**
* Created by cbt24 on 7/04/17. * A TrackPoint is a point plotted to display the track a
* {@link seng302.Model.Boat Boat} has travelled in a race. <br>
* TrackPoints are displayed on a
* {@link seng302.Model.ResizableRaceCanvas ResizableRaceCanvas}, via the
* {@link seng302.Controllers.RaceController RaceController}. <br>
* Track points can be made visible or hidden via the RaceController's
* {@link seng302.Model.Annotations Annotations}.
*/ */
public class TrackPoint { public class TrackPoint {
private final GPSCoordinate coordinate; private final GPSCoordinate coordinate;

@ -8,7 +8,11 @@ import java.time.ZonedDateTime;
import java.util.List; import java.util.List;
/** /**
* Created by connortaylorbrown on 19/04/17. * An object that holds relevant data for a race. <br>
* Information includes: {@link seng302.Model.Boat Boat}s,
* {@link seng302.Model.Leg Leg}s, {@link seng302.Model.Marker Marker}s and
* the {@link seng302.GPSCoordinate GPSCoordinate}s to create a
* {@link seng302.Model.ResizableRaceMap ResizableRaceMap}.
*/ */
public interface RaceDataSource { public interface RaceDataSource {
List<Boat> getBoats(); List<Boat> getBoats();

@ -1,7 +1,11 @@
package seng302; package seng302;
/** /**
* Created by cbt24 on 15/03/17. * The base size of the map to be used for the
* {@link seng302.Model.ResizableRaceMap ResizableRaceMap} and
* {@link seng302.Model.ResizableRaceCanvas ResizableRaceCanvas}. It is used
* to convert {@link seng302.GPSCoordinate GPSCoordinate}s to relative
* {@link seng302.GraphCoordinate GraphCoordinate}s.
*/ */
public class RaceMap { public class RaceMap {
private final double x1; private final double x1;

@ -14,12 +14,13 @@ import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import static seng302.Networking.Utils.ByteConverter.bytesToShort; import static seng302.Networking.Utils.ByteConverter.bytesToShort;
/** /**
* TCP client which receives packets/messages from a race data source (e.g., mock source, official source), and exposes them to any observers. * TCP client which receives packets/messages from a race data source
* (e.g., mock source, official source), and exposes them to any observers.
* @see seng302.Mock.StreamedCourse
*/ */
public class VisualiserInput implements Runnable { public class VisualiserInput implements Runnable {

@ -12,7 +12,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/** /**
* Created by fwy13 on 26/03/2017. * The abstract class for reading in XML race data.
*/ */
public abstract class XMLReader { public abstract class XMLReader {

@ -3,25 +3,10 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.chart.LineChart?> <?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?> <?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Accordion?> <?import javafx.scene.control.*?>
<?import javafx.scene.control.Button?> <?import javafx.scene.layout.*?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<SplitPane fx:id="race" dividerPositions="0.7" prefHeight="431.0" prefWidth="610.0" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.Controllers.RaceController">
<SplitPane fx:id="race" dividerPositions="0.7" prefHeight="431.0" prefWidth="610.0" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.Controllers.RaceController">
<items> <items>
<GridPane fx:id="canvasBase"> <GridPane fx:id="canvasBase">
<columnConstraints> <columnConstraints>
@ -38,7 +23,7 @@
<panes> <panes>
<TitledPane animated="false" prefHeight="395.0" prefWidth="222.0" text="Annotation Control"> <TitledPane animated="false" prefHeight="395.0" prefWidth="222.0" text="Annotation Control">
<content> <content>
<AnchorPane minHeight="0.0" minWidth="0.0"> <AnchorPane fx:id="annotationPane" minHeight="0.0" minWidth="0.0">
<children> <children>
<CheckBox fx:id="showName" layoutY="39.0" mnemonicParsing="false" selected="true" text="Show Boat Name" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" /> <CheckBox fx:id="showName" layoutY="39.0" mnemonicParsing="false" selected="true" text="Show Boat Name" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
<CheckBox fx:id="showAbbrev" layoutY="61.0" mnemonicParsing="false" selected="true" text="Show Boat Abbreviation" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="25.0" /> <CheckBox fx:id="showAbbrev" layoutY="61.0" mnemonicParsing="false" selected="true" text="Show Boat Abbreviation" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="25.0" />
@ -48,11 +33,14 @@
<CheckBox fx:id="showEstTime" mnemonicParsing="false" selected="true" text="Show Est. Time to Next Mark" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="125.0" /> <CheckBox fx:id="showEstTime" mnemonicParsing="false" selected="true" text="Show Est. Time to Next Mark" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="125.0" />
<Separator layoutX="19.6" layoutY="175.6" prefHeight="0.0" prefWidth="200.0" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="150.0" /> <Separator layoutX="19.6" layoutY="175.6" prefHeight="0.0" prefWidth="200.0" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="150.0" />
<Label text="Annotations" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="150.0" /> <Label text="Annotations" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="150.0" />
<RadioButton fx:id="hideAnnoRBTN" mnemonicParsing="false" text="Hidden" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="175.0" /> <RadioButton fx:id="hideAnnoRBtn" mnemonicParsing="false" text="Hidden" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="175.0">
<RadioButton fx:id="showAnnoRBTN" mnemonicParsing="false" text="Visible" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="200.0" /> <toggleGroup>
<RadioButton fx:id="partialAnnoRBTN" mnemonicParsing="false" text="Partial" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="225.0" /> <ToggleGroup fx:id="annoToggleGroup" />
<RadioButton fx:id="importantAnnoRBTN" mnemonicParsing="false" text="Important" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="250.0" /> </toggleGroup></RadioButton>
<Button fx:id="saveAnno" layoutX="11.0" layoutY="126.0" maxWidth="154.0" mnemonicParsing="false" prefWidth="154.0" text="Save Important Annotations" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="275.0" /> <RadioButton fx:id="showAnnoRBtn" mnemonicParsing="false" text="Visible" toggleGroup="$annoToggleGroup" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="200.0" />
<RadioButton fx:id="partialAnnoRBtn" mnemonicParsing="false" text="Partial" toggleGroup="$annoToggleGroup" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="225.0" />
<RadioButton fx:id="importantAnnoRBtn" mnemonicParsing="false" text="Important" toggleGroup="$annoToggleGroup" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="250.0" />
<Button fx:id="saveAnno" layoutX="11.0" layoutY="126.0" mnemonicParsing="false" text="Save Important Annotations" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="275.0" />
</children> </children>
</AnchorPane> </AnchorPane>
</content> </content>

@ -1,154 +1,149 @@
package seng302.Model; package seng302.Model;
import javafx.scene.paint.Color;
import org.junit.Test;
import seng302.GPSCoordinate;
import static junit.framework.TestCase.*;
/** /**
* Created by esa46 on 22/03/17. * Tests various aspects of a boat in race perform correctly.
*/ */
public class BoatInRaceTest { public class BoatInRaceTest {
// TODO change this test to use Boat and not BoatInRace ??
// TODO delete BoatInRace class
private final GPSCoordinate ORIGIN_COORDS = new GPSCoordinate(0, 0);
private final BoatInRace TEST_BOAT = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt"); // private final GPSCoordinate ORIGIN_COORDS = new GPSCoordinate(0, 0);
// private final BoatInRace TEST_BOAT = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt");
//
@Test //
public void calculateDueNorthAzimuthReturns0() { // @Test
// public void calculateDueNorthAzimuthReturns0() {
Marker startMarker = new Marker(ORIGIN_COORDS); //
Marker endMarker = new Marker(new GPSCoordinate(50, 0)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg start = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(50, 0));
TEST_BOAT.setCurrentLeg(start); // Leg start = new Leg("Start", startMarker, endMarker, 0);
assertEquals(TEST_BOAT.calculateAzimuth(), 0, 1e-8); // TEST_BOAT.setCurrentLeg(start);
} // assertEquals(TEST_BOAT.calculateAzimuth(), 0, 1e-8);
// }
@Test //
public void calculateDueSouthAzimuthReturns180() { // @Test
Marker startMarker = new Marker(ORIGIN_COORDS); // public void calculateDueSouthAzimuthReturns180() {
Marker endMarker = new Marker(new GPSCoordinate(-50, 0)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg start = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(-50, 0));
TEST_BOAT.setCurrentLeg(start); // Leg start = new Leg("Start", startMarker, endMarker, 0);
assertEquals(TEST_BOAT.calculateAzimuth(), 180, 1e-8); // TEST_BOAT.setCurrentLeg(start);
} // assertEquals(TEST_BOAT.calculateAzimuth(), 180, 1e-8);
// }
//
@Test //
public void calculateDueEastAzimuthReturns90() { // @Test
// public void calculateDueEastAzimuthReturns90() {
Marker startMarker = new Marker(ORIGIN_COORDS); //
Marker endMarker = new Marker(new GPSCoordinate(0, 50)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg start = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(0, 50));
TEST_BOAT.setCurrentLeg(start); // Leg start = new Leg("Start", startMarker, endMarker, 0);
assertEquals(TEST_BOAT.calculateAzimuth(), 90, 1e-8); // TEST_BOAT.setCurrentLeg(start);
} // assertEquals(TEST_BOAT.calculateAzimuth(), 90, 1e-8);
// }
//
@Test //
public void calculateDueWestAzimuthReturnsNegative90() { // @Test
Marker startMarker = new Marker(ORIGIN_COORDS); // public void calculateDueWestAzimuthReturnsNegative90() {
Marker endMarker = new Marker(new GPSCoordinate(0, -50)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg start = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(0, -50));
TEST_BOAT.setCurrentLeg(start); // Leg start = new Leg("Start", startMarker, endMarker, 0);
assertEquals(TEST_BOAT.calculateAzimuth(), -90, 1e-8); // TEST_BOAT.setCurrentLeg(start);
// assertEquals(TEST_BOAT.calculateAzimuth(), -90, 1e-8);
} //
// }
@Test //
public void calculateDueNorthHeadingReturns0() { // @Test
// public void calculateDueNorthHeadingReturns0() {
Marker startMarker = new Marker(ORIGIN_COORDS); //
Marker endMarker = new Marker(new GPSCoordinate(50, 0)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg start = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(50, 0));
TEST_BOAT.setCurrentLeg(start); // Leg start = new Leg("Start", startMarker, endMarker, 0);
assertEquals(TEST_BOAT.calculateHeading(), 0, 1e-8); // TEST_BOAT.setCurrentLeg(start);
} // assertEquals(TEST_BOAT.calculateHeading(), 0, 1e-8);
// }
//
@Test //
public void calculateDueEastHeadingReturns90() { // @Test
Marker startMarker = new Marker(ORIGIN_COORDS); // public void calculateDueEastHeadingReturns90() {
Marker endMarker = new Marker(new GPSCoordinate(0, 50)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg start = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(0, 50));
TEST_BOAT.setCurrentLeg(start); // Leg start = new Leg("Start", startMarker, endMarker, 0);
assertEquals(TEST_BOAT.calculateHeading(), 90, 1e-8); // TEST_BOAT.setCurrentLeg(start);
} // assertEquals(TEST_BOAT.calculateHeading(), 90, 1e-8);
// }
@Test //
public void calculateDueSouthHeadingReturns180() { // @Test
Marker startMarker = new Marker(ORIGIN_COORDS); // public void calculateDueSouthHeadingReturns180() {
Marker endMarker = new Marker(new GPSCoordinate(-50, 0)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg start = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(-50, 0));
TEST_BOAT.setCurrentLeg(start); // Leg start = new Leg("Start", startMarker, endMarker, 0);
assertEquals(TEST_BOAT.calculateHeading(), 180, 1e-8); // TEST_BOAT.setCurrentLeg(start);
} // assertEquals(TEST_BOAT.calculateHeading(), 180, 1e-8);
// }
@Test //
public void calculateDueWestHeadingReturns270() { // @Test
Marker startMarker = new Marker(ORIGIN_COORDS); // public void calculateDueWestHeadingReturns270() {
Marker endMarker = new Marker(new GPSCoordinate(0, -50)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg start = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(0, -50));
TEST_BOAT.setCurrentLeg(start); // Leg start = new Leg("Start", startMarker, endMarker, 0);
assertEquals(TEST_BOAT.calculateHeading(), 270, 1e-8); // TEST_BOAT.setCurrentLeg(start);
} // assertEquals(TEST_BOAT.calculateHeading(), 270, 1e-8);
// }
@Test //
public void createNewBoatCratesInstanceOfSuperClass() { // @Test
// public void createNewBoatCratesInstanceOfSuperClass() {
BoatInRace testBoat = new BoatInRace("Boat", 20, Color.ALICEBLUE, "tt"); //
testBoat.setName("Name can change"); // BoatInRace testBoat = new BoatInRace("Boat", 20, Color.ALICEBLUE, "tt");
assertTrue(testBoat instanceof Boat); // testBoat.setName("Name can change");
assertTrue(testBoat.getCurrentLeg() == null); // assertTrue(testBoat instanceof Boat);
assertTrue(testBoat.getCurrentPosition() == null); // assertTrue(testBoat.getCurrentLeg() == null);
assertTrue(testBoat.toString().contains("Name can change")); // assertTrue(testBoat.getCurrentPosition() == null);
assertEquals(testBoat.getVelocity(), 20.0); // assertTrue(testBoat.toString().contains("Name can change"));
assertTrue(testBoat.getVelocityProp().toString().contains("20")); // assertEquals(testBoat.getVelocity(), 20.0);
assertTrue(testBoat.getAbbrev().equals("tt")); // assertTrue(testBoat.getVelocityProp().toString().contains("20"));
assertTrue(testBoat.getColour().equals(Color.ALICEBLUE)); // assertTrue(testBoat.getAbbrev().equals("tt"));
assertFalse(testBoat.isFinished()); // assertTrue(testBoat.getColour().equals(Color.ALICEBLUE));
} // assertFalse(testBoat.isFinished());
// }
//
@Test //
public void getWakeAtProperHeading() throws Exception { // @Test
BoatInRace boat = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt"); // public void getWakeAtProperHeading() throws Exception {
// BoatInRace boat = new BoatInRace("Test", 1, Color.ALICEBLUE, "tt");
// Construct leg of 0 degrees //
Marker startMarker = new Marker(ORIGIN_COORDS); // // Construct leg of 0 degrees
Marker endMarker = new Marker(new GPSCoordinate(50, 0)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg leg0deg = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(50, 0));
boat.setCurrentLeg(leg0deg); // Leg leg0deg = new Leg("Start", startMarker, endMarker, 0);
boat.setCurrentPosition(new GPSCoordinate(0, 0)); // boat.setCurrentLeg(leg0deg);
// boat.setCurrentPosition(new GPSCoordinate(0, 0));
assertEquals(0, boat.calculateHeading(), 1e-8); //
// assertEquals(0, boat.calculateHeading(), 1e-8);
// Construct leg from wake - heading should be 180 degrees //
Leg leg180deg = new Leg("Start", startMarker, new Marker(boat.getWake()), 0); // // Construct leg from wake - heading should be 180 degrees
boat.setCurrentLeg(leg180deg); // Leg leg180deg = new Leg("Start", startMarker, new Marker(boat.getWake()), 0);
// boat.setCurrentLeg(leg180deg);
assertEquals(180, boat.calculateHeading(), 1e-8); //
} // assertEquals(180, boat.calculateHeading(), 1e-8);
// }
//
@Test //
public void getWakeProportionalToVelocity() throws Exception { // @Test
BoatInRace boat = new BoatInRace("Test", 10, Color.ALICEBLUE, "tt"); // public void getWakeProportionalToVelocity() throws Exception {
// BoatInRace boat = new BoatInRace("Test", 10, Color.ALICEBLUE, "tt");
// Construct leg of 0 degrees at 0 N //
Marker startMarker = new Marker(ORIGIN_COORDS); // // Construct leg of 0 degrees at 0 N
Marker endMarker = new Marker(new GPSCoordinate(50, 0)); // Marker startMarker = new Marker(ORIGIN_COORDS);
Leg leg0deg = new Leg("Start", startMarker, endMarker, 0); // Marker endMarker = new Marker(new GPSCoordinate(50, 0));
boat.setCurrentLeg(leg0deg); // Leg leg0deg = new Leg("Start", startMarker, endMarker, 0);
boat.setCurrentPosition(new GPSCoordinate(0, 0)); // boat.setCurrentLeg(leg0deg);
// boat.setCurrentPosition(new GPSCoordinate(0, 0));
// Get latitude of endpoint of wake at 10 kn (longitude is 0) //
double endpointAt10Kn = boat.getWake().getLatitude(); // // Get latitude of endpoint of wake at 10 kn (longitude is 0)
// double endpointAt10Kn = boat.getWake().getLatitude();
// Latitude of endpoint at 20 kn should be twice endpoint at 10 kn //
boat.setVelocity(20); // // Latitude of endpoint at 20 kn should be twice endpoint at 10 kn
assertEquals(2 * endpointAt10Kn, boat.getWake().getLatitude(), 1e-8); // boat.setVelocity(20);
} // assertEquals(2 * endpointAt10Kn, boat.getWake().getLatitude(), 1e-8);
// }
} }

@ -10,7 +10,8 @@ import static junit.framework.TestCase.assertEquals;
import static seng302.Model.Leg.NM_TO_METERS; import static seng302.Model.Leg.NM_TO_METERS;
/** /**
* Created by esa46 on 22/03/17. * Tests that using a start and end mark initialises the correct leg between
* the markers.
*/ */
public class LegTest { public class LegTest {

Loading…
Cancel
Save