Added Important and Partial Annotations and other refactors and documentation.

- Important, Partial, Hidden, Visible are all radiobuttons
- Fixed bug where the Visualiser would end the race before the last boat had finished
- Refactored the visualiser and the mock to use the race finished status message
- Added and Changed many Javadocs
#story[877]
main
Fan-Wu Yang 9 years ago
commit 671d62aeb1

@ -1,7 +1,7 @@
junit:
stage: test
script:
- mvn -B clean test
- mvn -B -Dprism.verbose=true clean test
generate_artifacts:
stage: deploy

@ -3,16 +3,27 @@ package seng302;
import javafx.application.Application;
import javafx.stage.Stage;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import seng302.DataInput.RaceDataSource;
import seng302.DataInput.RaceXMLReader;
import seng302.DataInput.RegattaDataSource;
import seng302.DataInput.RegattaXMLReader;
import seng302.DataInput.XMLReader;
import seng302.Model.Event;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class App extends Application {
@ -28,16 +39,46 @@ public class App extends Application {
@Override
public void start(Stage primaryStage) {
try {
RaceDataSource raceData = new RaceXMLReader("raceXML/bermuda_AC35.xml");
RegattaDataSource regattaData = new RegattaXMLReader("mockXML/regattaTest.xml");
Event raceEvent = new Event(raceData, regattaData);
String regattaXML = readFile("mockXML/regattaTest.xml", StandardCharsets.UTF_8);
String raceXML = readFile("mockXML/raceTest.xml", StandardCharsets.UTF_8);
String boatXML = readFile("mockXML/boatTest.xml", StandardCharsets.UTF_8);
Event raceEvent = new Event(raceXML, regattaXML, boatXML);
raceEvent.start();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
} catch (TransformerException e) {
e.printStackTrace();
}
}
/**
* Reads the Initial Race XML files that are necessary to run the mock.
* @param path path of the XML
* @param encoding encoding of the xml
* @return
* @throws IOException No file etc
* @throws ParserConfigurationException Issue with the XML formatting
* @throws SAXException Issue with XML formatting
* @throws TransformerException Issue with the XML format
*/
private String readFile(String path, Charset encoding) throws IOException, ParserConfigurationException, SAXException, TransformerException {
InputSource fXmlFile = new InputSource(getClass().getClassLoader().getResourceAsStream(path));
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
return XMLReader.getContents(doc);
}
}

@ -8,5 +8,7 @@ public class Constants {
public static final int NMToMetersConversion = 1852; // 1 nautical mile = 1852 meters
public static final int PRE_RACE_WAIT_TIME = 18000;
public static final int TEST_VELOCITIES[] = new int[] { 30, 15, 64, 52, 25, 24 };
}

@ -1,220 +0,0 @@
package seng302.Data;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import seng302.Exceptions.InvalidBoatDataException;
import seng302.Model.Boat;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.util.List;
/**
* Created by esa46 on 25/04/17.
*/
public class BoatData {
Document doc;
private List<Boat> boatData;
public BoatData(List<Boat> boatData) {
this.boatData = boatData;
}
/**
* Creates an AC35 officially formatted xml description of boats competing in a race
*
* @return String containing xml-formatted boats description
*/
public String createXML() {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
//root element
doc = docBuilder.newDocument();
Element rootElement = doc.createElement("BoatConfig");
doc.appendChild(rootElement);
//Boats element
Element boats = doc.createElement("Boats");
rootElement.appendChild(boats);
appendIndividualBoats(boats);
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(doc);
//Serialize document.
StringWriter stringWriter = new StringWriter();
StreamResult result = new StreamResult(stringWriter);
transformer.transform(source, result);
System.out.println(stringWriter.toString());
return stringWriter.toString();
} catch (ParserConfigurationException pce) {
throw new InvalidBoatDataException();
} catch (TransformerException tfe) {
throw new InvalidBoatDataException();
}
}
/**
* Runs through competing boats, creating an element for each
*
* @param boatsElement boats element to be added to
*/
private void appendIndividualBoats(Element boatsElement) {
for (int i = 0; i < boatData.size(); i++) {
Element boat = doc.createElement("Boat");
appendType(boat);
appendSourceID(boat, i);
appendShapeID(boat);
appendHullNum(boat);
appendStoweName(boat, i);
appendShortName(boat, i);
appendBoatName(boat, i);
appendGPSCoords(boat, i);
//Write boat to boats
boatsElement.appendChild(boat);
}
}
/**
* Creates and appends type attribute of a boat
*
* @param boat element being added to
*/
private void appendType(Element boat) {
//Type attribute
Attr attrType = doc.createAttribute("Type");
attrType.setValue("Yacht");
boat.setAttributeNode(attrType);
}
/**
* Creates and appends sourceID attribute of a boat
*
* @param boat element being added to
* @param i boat number
*/
private void appendSourceID(Element boat, int i) {
//SourceID attribute
Attr attrSourceID = doc.createAttribute("SourceID");
attrSourceID.setValue(Integer.toString(boatData.get(i).getSourceID()));
boat.setAttributeNode(attrSourceID);
}
/**
* Creates and appends shapeID attribute of a boat
*
* @param boat element being added to
*/
private void appendShapeID(Element boat) {
//ShapeID attribute
Attr attrShapeID = doc.createAttribute("ShapeID");
attrShapeID.setValue("0");
boat.setAttributeNode(attrShapeID);
}
/**
* Creates and appends hull name attribute of a boat
*
* @param boat element being added to
*/
private void appendHullNum(Element boat) {
//HullNum attribute
Attr attrHullNum = doc.createAttribute("HullNum");
attrHullNum.setValue("RG01");
boat.setAttributeNode(attrHullNum);
}
/**
* Creates and appends stow name attribute of a boat
*
* @param boat element being added to
* @param i boat number
*/
private void appendStoweName(Element boat, int i) {
//StoweName attribute
Attr attrStoweName = doc.createAttribute("StoweName");
attrStoweName.setValue(boatData.get(i).getAbbrev());
boat.setAttributeNode(attrStoweName);
}
/**
* Creates and appends short name attribute of a boat
*
* @param boat element being added to
* @param i boat number
*/
private void appendShortName(Element boat, int i) {
//ShortName attribute
Attr attrShortName = doc.createAttribute("ShortName");
attrShortName.setValue(boatData.get(i).getAbbrev());
boat.setAttributeNode(attrShortName);
}
/**
* Creates and appends boat name attribute of a boat
*
* @param boat element being added to
* @param i boat number
*/
private void appendBoatName(Element boat, int i) {
//BoatName attribute
Attr attrBoatName = doc.createAttribute("BoatName");
attrBoatName.setValue(boatData.get(i).getName());
boat.setAttributeNode(attrBoatName);
}
/**
* Creates and appends gps attributes of a boat
*
* @param boat element being added to
* @param i boat number
*/
private void appendGPSCoords(Element boat, int i) {
//GPSCoord for element
Element GPSCoord = doc.createElement("GPSposition");
//Z axis attribute
Attr attrZCoord = doc.createAttribute("Z");
attrZCoord.setValue("0");
GPSCoord.setAttributeNode(attrZCoord);
//Y axis attribute
Attr attrYCoord = doc.createAttribute("Y");
attrYCoord.setValue(Double.toString(boatData.get(i).getCurrentPosition().getLatitude()));
GPSCoord.setAttributeNode(attrYCoord);
//X axis attribute
Attr attrXCoord = doc.createAttribute("X");
attrXCoord.setValue(Double.toString(boatData.get(i).getCurrentPosition().getLongitude()));
GPSCoord.setAttributeNode(attrXCoord);
//Write GPSCoord to boat
boat.appendChild(GPSCoord);
}
}

@ -1,250 +0,0 @@
package seng302.Data;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import seng302.DataInput.RaceDataSource;
import seng302.Exceptions.InvalidRaceDataException;
import seng302.Model.Boat;
import seng302.Model.GPSCoordinate;
import seng302.Model.Marker;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* Created by esa46 on 21/04/17.
*/
public class RaceData {
private RaceDataSource dataSource;
private Document doc;
private Element rootElement;
private ZonedDateTime creationTimeDate;
public RaceData(RaceDataSource dataSource) {
this.dataSource = dataSource;
creationTimeDate = ZonedDateTime.now();
}
/**
* Creates an AC35 officially formatted xml description of a race.
*
* @return String containing xml-formatted race description
*/
public String createXML() {
try {
//create base xml document
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
doc = docBuilder.newDocument();
//create root element (In this case, "Race")
rootElement = doc.createElement("Race");
doc.appendChild(rootElement);
appendChildElements();
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(doc);
//Serialize document.
StringWriter stringWriter = new StringWriter();
StreamResult result = new StreamResult(stringWriter);
transformer.transform(source, result);
return stringWriter.toString();
} catch (ParserConfigurationException pce) {
throw new InvalidRaceDataException();
} catch (TransformerException tfe) {
throw new InvalidRaceDataException();
}
}
/**
* Creates all necessary child elements and appends them to the xml doc
*/
private void appendChildElements() {
appendRaceId();
appendRaceType();
appendCreationTimeDate();
appendRaceStartTime();
appendParticipants();
appendCourse();
appendCourseLimit();
}
/**
* Creates and appends race id element
*/
private void appendRaceId() {
Element raceIdElement = doc.createElement("RaceID");
raceIdElement.appendChild(doc.createTextNode(Integer.toString(dataSource.getRaceId())));
rootElement.appendChild(raceIdElement);
}
/**
* Creates and appends race type element
*/
private void appendRaceType() {
Element raceTypeElement = doc.createElement("RaceType");
raceTypeElement.appendChild(doc.createTextNode(dataSource.getRaceType()));
rootElement.appendChild(raceTypeElement);
}
/**
* Creates and appends creation time date element
*/
private void appendCreationTimeDate() {
Element creationTimeElement = doc.createElement("CreationTimeDate");
creationTimeElement.appendChild(doc.createTextNode(toTruncatedString(creationTimeDate)));
rootElement.appendChild(creationTimeElement);
}
/**
* Creates and appends race start time element, which is 3 minutes after the race was created by default
*/
private void appendRaceStartTime() {
Element startTimeElement = doc.createElement("RaceStartTime");
startTimeElement.setAttribute("Time", (toTruncatedString(creationTimeDate.plusMinutes(0))));
startTimeElement.setAttribute("Postpone", "false");
rootElement.appendChild(startTimeElement);
}
/**
* Creates and appends participants element
*/
private void appendParticipants() {
Element participantsElement = doc.createElement("Participants");
for (Boat boat : dataSource.getBoats()) {
Element yachtElement = doc.createElement("Yacht");
yachtElement.setAttribute("SourceID", boat.getSourceID() + "");
participantsElement.appendChild(yachtElement);
}
rootElement.appendChild(participantsElement);
}
/**
* Creates and appends course elements
*/
private void appendCourse() {
Element courseElement = doc.createElement("Course");
Element compoundMarkSeqElement = doc.createElement("CompoundMarkSequence");
int i = 1;
for (Marker marker : dataSource.getMarkers()) {
courseElement.appendChild(createCompoundMarker(marker, i));
compoundMarkSeqElement.appendChild(createCornerElement(i));
i++;
}
rootElement.appendChild(compoundMarkSeqElement);
rootElement.appendChild(courseElement);
}
/**
* Creates a mark element for insertion in a coumpound mark element
*
* @param marker GPS coordinates of the mark
* @return Element mark element
*/
private Element createMark(GPSCoordinate marker) {
Element mark = doc.createElement("Mark");
mark.setAttribute("TargetLat", marker.getLatitude() + "");
mark.setAttribute("TargetLng", marker.getLongitude() + "");
return mark;
}
/**
* Creates a compound marker holding one or two marks,and a sequence number
*
* @param marker marker
* @param i sequence number
* @return Element compound mark element
*/
private Element createCompoundMarker(Marker marker, int i) {
Element compoundMarkElement = doc.createElement("CompoundMark");
compoundMarkElement.setAttribute("CompoundMarkID", i + "");
compoundMarkElement.setAttribute("Name", marker.getName());
compoundMarkElement.appendChild(createMark(marker.getMark1()));
if (!(marker.getMark1().equals(marker.getMark2()))) {
compoundMarkElement.appendChild(createMark(marker.getMark2()));
}
return compoundMarkElement;
}
/**
* Creates a corner element
*
* @param i sequence number
* @return Element corner element
*/
private Element createCornerElement(int i) {
Element cornerElement = doc.createElement("Corner");
cornerElement.setAttribute("SeqID", i + "");
cornerElement.setAttribute("CompoundMarkID", i + "");
return cornerElement;
}
/**
* Creates and appends course limits element (boundaries)
*/
private void appendCourseLimit() {
int j = 1;
Element courseLimitElement = doc.createElement("CourseLimit");
for (GPSCoordinate coordinate : dataSource.getBoundary()) {
Element limitElement = doc.createElement("Limit");
limitElement.setAttribute("SeqID", j + "");
limitElement.setAttribute("Lat", coordinate.getLatitude() + "");
limitElement.setAttribute("Lon", coordinate.getLongitude() + "");
courseLimitElement.appendChild(limitElement);
j++;
}
rootElement.appendChild(courseLimitElement);
}
/**
* Format time data and return it.
* @param time time data.
* @return formatted time data.
*/
private String toTruncatedString(ZonedDateTime time) {
DateTimeFormatter dateFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
String text = dateFormat.format(time);
return text;
}
}

@ -1,169 +0,0 @@
package seng302.Data;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import seng302.DataInput.RegattaDataSource;
import seng302.Exceptions.InvalidRegattaDataException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
/**
* Created by esa46 on 25/04/17.
*/
public class RegattaData {
private RegattaDataSource regattaDataSource;
private Document doc;
private Element rootElement;
public RegattaData(RegattaDataSource regattaDataSource) {
this.regattaDataSource = regattaDataSource;
}
/**
* Creates an AC35 officially formatted xml description of a regatta
*
* @return String containing xml-formatted regatta description
*/
public String createXML() {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
//root element
doc = docBuilder.newDocument();
rootElement = doc.createElement("RegattaConfig");
doc.appendChild(rootElement);
appendChildElements();
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(doc);
//Serialize document.
StringWriter stringWriter = new StringWriter();
StreamResult result = new StreamResult(stringWriter);
transformer.transform(source, result);
return stringWriter.toString();
} catch (ParserConfigurationException pce) {
throw new InvalidRegattaDataException();
} catch (TransformerException tfe) {
throw new InvalidRegattaDataException();
}
}
/**
* Creates all necessary child elements and appends them to the xml doc
*/
private void appendChildElements() {
appendRegattaID();
appendRegattaName();
appendCourseName();
appendCentralLatitude();
appendCentralLongitude();
appendCentralAltitude();
appedUtcOffset();
appendMagneticVariation();
}
/**
* Creates and appends regatta id element
*/
private void appendRegattaID() {
//regattaID element
Element regattaID = doc.createElement("RegattaID");
regattaID.appendChild(doc.createTextNode(Integer.toString(regattaDataSource.getRegatta().getRegattaID())));
rootElement.appendChild(regattaID);
}
/**
* Creates and appends regatta name element
*/
private void appendRegattaName() {
//regattaName element
Element regattaName = doc.createElement("RegattaName");
regattaName.appendChild(doc.createTextNode(regattaDataSource.getRegatta().getRegattaName()));
rootElement.appendChild(regattaName);
}
/**
* Creates and appends course name element
*/
private void appendCourseName() {
//courseName element
Element courseName = doc.createElement("CourseName");
courseName.appendChild(doc.createTextNode(regattaDataSource.getRegatta().getCourseName()));
rootElement.appendChild(courseName);
}
/**
* Creates and appends central latitude element
*/
private void appendCentralLatitude() {
//centralLatitude element
Element centralLat = doc.createElement("CentralLatitude");
centralLat.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getCentralLatitude())));
rootElement.appendChild(centralLat);
}
/**
* Creates and appends central longitude element
*/
private void appendCentralLongitude() {
//centralLongitude element
Element centralLong = doc.createElement("CentralLongitude");
centralLong.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getCentralLongitude())));
rootElement.appendChild(centralLong);
}
/**
* Creates and appends central altitude element
*/
private void appendCentralAltitude() {
//centralAltitude element
Element centralAlt = doc.createElement("CentralAltitude");
centralAlt.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getCentralAltitude())));
rootElement.appendChild(centralAlt);
}
/**
* Creates and appends utc offset element
*/
private void appedUtcOffset() {
//utcOffset element
Element utcOffset = doc.createElement("UtcOffset");
utcOffset.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getUtcOffset())));
rootElement.appendChild(utcOffset);
}
/**
* Creates and appends magnetic variation element
*/
private void appendMagneticVariation() {
//magneticVariation element
Element magneticVariation = doc.createElement("MagneticVariation");
magneticVariation.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getMagneticVariation())));
rootElement.appendChild(magneticVariation);
}
}

@ -0,0 +1,14 @@
package seng302.DataInput;
import seng302.Model.Boat;
import seng302.Model.Mark;
import java.util.Map;
/**
* Boats Data
*/
public interface BoatDataSource {
Map<Integer, Boat> getBoats();
Map<Integer, Mark> getMarkerBoats();
}

@ -0,0 +1,153 @@
package seng302.DataInput;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import seng302.Model.Boat;
import seng302.Model.GPSCoordinate;
import seng302.Model.Mark;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Xml Reader class for Boat XML used for the race
*/
public class BoatXMLReader extends XMLReader implements BoatDataSource {
private final Map<Integer, Boat> boatMap = new HashMap<>();
private final Map<Integer, Mark> markerMap = new HashMap<>();
/**
* Constructor
* @param filePath File to read
* @throws ParserConfigurationException Error in the XML file
* @throws SAXException Error in the XMl format
* @throws IOException Error of the file
*/
public BoatXMLReader(String filePath) throws ParserConfigurationException, SAXException, IOException {
this(filePath, true);
}
/**
* COnstructor for Boat XML
*
* @param filePath file path to read
* @param read whether or not to read and store the files straight away.
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public BoatXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException {
super(filePath);
if (read) {
read();
}
}
/**
* Read the XML
*/
public void read() {
readSettings();
readShapes();
readBoats();
}
/**
* Read the Boats
*/
private void readBoats() {
Element nBoats = (Element) doc.getElementsByTagName("Boats").item(0);
for (int i = 0; i < nBoats.getChildNodes().getLength(); i++) {
Node boat = nBoats.getChildNodes().item(i);
if (boat.getNodeName().equals("Boat")) {
readBoatNode(boat);
}
}
}
/**
* Ignored data
*/
private void readShapes() {
}
/**
* Ignored data
*/
private void readSettings() {
}
/**
* Checks if the node (XMl data node) is a Yacht or not
* @param boatNode Node from the XML
* @return Whether the node is a yacht node or not
*/
private boolean isYachtNode(Node boatNode) {
return boatNode.getAttributes().getNamedItem("Type").getTextContent().toLowerCase().equals("yacht");
}
/**
* Reads the information about one boat
* Ignored values: ShapeID, StoweName, HullNum, Skipper, Type
*/
private void readBoatNode(Node boatNode) {
int sourceID = Integer.parseInt(boatNode.getAttributes().getNamedItem("SourceID").getTextContent());
String name = boatNode.getAttributes().getNamedItem("BoatName").getTextContent();
if (isYachtNode(boatNode)) readYacht(boatNode, sourceID, name);
else readMark(boatNode, sourceID, name);
}
/**
* Read a Yacht Node
* @param boatNode Node to be read
* @param sourceID Source ID of the Yacht
* @param name Name of the Boat
*/
private void readYacht(Node boatNode, int sourceID, String name) {
String shortName = boatNode.getAttributes().getNamedItem("ShortName").getTextContent();
if (exists(boatNode, "Country")) {
String country = boatNode.getAttributes().getNamedItem("Country").getTextContent();
boatMap.put(sourceID, new Boat(sourceID, name, country));
} else {
boatMap.put(sourceID, new Boat(sourceID, name, shortName));
}
}
/**
* Read Marker Boats
* @param boatNode Node to be read
* @param sourceID Source ID of the boat
* @param name Name of the Marker Boat
*/
private void readMark(Node boatNode, int sourceID, String name) {
Node nCoord = ((Element)boatNode).getElementsByTagName("GPSposition").item(0);
double x = Double.parseDouble(nCoord.getAttributes().getNamedItem("X").getTextContent());
double y = Double.parseDouble(nCoord.getAttributes().getNamedItem("Y").getTextContent());
Mark mark = new Mark(sourceID, name, new GPSCoordinate(y,x));
markerMap.put(sourceID, mark);
}
/**
* Get the boats that are going to participate in this race
* @return Dictionary of boats that are to participate in this race indexed by SourceID
*/
@Override
public Map<Integer, Boat> getBoats() {
return boatMap;
}
/**
* Get the marker BOats that are participating in this race
* @return Dictionary of the Markers BOats that are in this race indexed by their Source ID.
*/
@Override
public Map<Integer, Mark> getMarkerBoats() {
return markerMap;
}
}

@ -2,14 +2,15 @@ package seng302.DataInput;
;
import seng302.Model.Boat;
import seng302.Model.CompoundMark;
import seng302.Model.GPSCoordinate;
import seng302.Model.Leg;
import seng302.Model.Marker;
import java.time.ZonedDateTime;
import java.util.List;
/**
* Created by connortaylorbrown on 19/04/17.
* Data Class for a Race
*/
public interface RaceDataSource {
List<Boat> getBoats();
@ -18,13 +19,13 @@ public interface RaceDataSource {
List<GPSCoordinate> getBoundary();
List<Marker> getMarkers();
List<CompoundMark> getCompoundMarks();
int getRaceId();
String getRaceType();
GPSCoordinate getMark();
ZonedDateTime getZonedDateTime();
GPSCoordinate getMapTopLeft();

@ -1,373 +1,285 @@
package seng302.DataInput;
import javafx.scene.paint.Color;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import seng302.Model.Boat;
import seng302.Model.GPSCoordinate;
import seng302.Model.Leg;
import seng302.Model.Marker;
import seng302.Exceptions.StreamedCourseXMLException;
import seng302.Model.*;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.text.ParseException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* Created by fwy13 on 26/03/2017.
* XML Reader that reads in the race data required for this race
*/
public class RaceXMLReader extends XMLReader implements RaceDataSource {
private static double COORDINATEPADDING = 0.0005;
private int raceID;
private List<Boat> boats = new ArrayList<>();
private Color[] colors = {Color.BLUEVIOLET, Color.BLACK, Color.RED, Color.ORANGE, Color.DARKOLIVEGREEN, Color.LIMEGREEN};//TODO make this established in xml or come up with a better system.
private List<Leg> legs = new ArrayList<>();
private GPSCoordinate mark, startPt1, startPt2, finishPt1, finishPt2, leewardPt1, leewardPt2, windwardPt1, windwardPt2;
private static final double COORDINATEPADDING = 0.000;
private GPSCoordinate mapTopLeft, mapBottomRight;
private List<GPSCoordinate> boundary = new ArrayList<>();
private List<Marker> markers = new ArrayList<>();
private final List<GPSCoordinate> boundary = new ArrayList<>();
private final Map<Integer,Element> compoundMarkMap = new HashMap<>();
private final Map<Integer, Boat> participants = new HashMap<>();
private final List<Leg> legs = new ArrayList<>();
private final List<CompoundMark> compoundMarks = new ArrayList<>();
private ZonedDateTime creationTimeDate;
private ZonedDateTime raceStartTime;
private int raceID;
private String raceType;
private boolean postpone;
private Map<Integer, Boat> boats;
private Map<Integer, Mark> marks;
/**
* Constractor for Race XML
*
* Constructor for Streamed Race XML
* @param filePath path of the file
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
* @throws ParseException error
* @throws StreamedCourseXMLException error
*/
public RaceXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException {
this(filePath, true);
public RaceXMLReader(String filePath, BoatDataSource boatData) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
this(filePath, boatData, true);
}
/**
* COnstructor for Race XML
*
* Constructor for Streamed Race XML
* @param filePath file path to read
* @param read whether or not to read and store the files straight away.
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
* @throws ParseException error
* @throws StreamedCourseXMLException error
*/
public RaceXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException {
public RaceXMLReader(String filePath, BoatDataSource boatData, boolean read) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
super(filePath);
this.boats = boatData.getBoats();
this.marks = boatData.getMarkerBoats();
if (read) {
read();
}
}
/**
* Read the files
* reads
* @throws StreamedCourseXMLException error
*/
private void read() {
private void read() throws StreamedCourseXMLException {
readRace();
readParticipants();
readCourse();
readID();
readLegs();
readMarkers();
readBoats();
}
/**
* Read in race ID from XML object.
* reads a race
*/
public void readID() {
NodeList race = doc.getElementsByTagName("race");
raceID = Integer.parseInt(getTextValueOfNode((Element) race.item(0), "raceId"));
}
private void readRace() {
DateTimeFormatter dateFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
Element settings = (Element) doc.getElementsByTagName("Race").item(0);
NamedNodeMap raceTimeTag = doc.getElementsByTagName("RaceStartTime").item(0).getAttributes();
/**
* Read all the boats in the XML file
*/
public void readBoats() {
//get all boats
NodeList nBoats = doc.getElementsByTagName("boat");
if (raceTimeTag.getNamedItem("Time") != null) dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
for (int i = 0; i < nBoats.getLength(); i++) {
String name = getTextValueOfNode((Element) nBoats.item(i), "name");
String abbrev = getTextValueOfNode((Element) nBoats.item(i), "abbr");
double velo = Double.parseDouble(getTextValueOfNode((Element) nBoats.item(i), "speed"));
int sourceID = Integer.parseInt(getTextValueOfNode((Element) nBoats.item(i), "sourceID"));
Boat boat = new Boat(name, velo, abbrev, sourceID);
boat.setCurrentPosition(startPt1);
if (legs.size() > 0) {
boat.setCurrentLeg(legs.get(0));
}
boats.add(boat);
}
}
raceID = Integer.parseInt(getTextValueOfNode(settings, "RaceID"));
raceType = getTextValueOfNode(settings, "RaceType");
/**
* Read all the boats in the XML file
*/
public void readMarkers() {
//get all boats
NodeList nMarkers = doc.getElementsByTagName("marker");
creationTimeDate = ZonedDateTime.parse(getTextValueOfNode(settings, "CreationTimeDate"), dateFormat);
for (int i = 0; i < nMarkers.getLength(); i++) {
Marker marker = getMarker((Element) nMarkers.item(i));
if (marker.getName() != null) markers.add(marker);
}
if (raceTimeTag.getNamedItem("Time") != null) raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Time").getTextContent(), dateFormat);
else raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Start").getTextContent(), dateFormat);
postpone = Boolean.parseBoolean(raceTimeTag.getNamedItem("Postpone").getTextContent());
}
/**
* Read all the legs in the XML file
* Reads in the participants for htis race
*/
public void readLegs() {
//get all legs
NodeList nLegs = doc.getElementsByTagName("leg");
for (int i = 0; i < nLegs.getLength(); i++) {
String label = getTextValueOfNode((Element) nLegs.item(i), "name");
NodeList start = ((Element) nLegs.item(i)).getElementsByTagName("start");
Marker startMarker = getMarker(start);
NodeList finish = ((Element) nLegs.item(i)).getElementsByTagName("finish");
Marker finishMarker = getMarker(finish);
legs.add(new Leg(label, startMarker, finishMarker, i));
private void readParticipants() {
Element nParticipants = (Element) doc.getElementsByTagName("Participants").item(0);
nParticipants.getChildNodes().getLength();
for (int i = 0; i < nParticipants.getChildNodes().getLength(); i++) {
int sourceID;
Node yacht = nParticipants.getChildNodes().item(i);
if (yacht.getNodeName().equals("Yacht")) {
if (exists(yacht, "SourceID")) {
sourceID = Integer.parseInt(yacht.getAttributes().getNamedItem("SourceID").getTextContent());
participants.put(sourceID, boats.get(sourceID));
}
}
/**
* Read courses in XML file
*/
public void readCourse() {
NodeList nCourse = doc.getElementsByTagName("course");
NodeList nBounds = ((Element) nCourse.item(0)).getElementsByTagName("boundaries");
nBounds = ((Element) nBounds.item(0)).getElementsByTagName("coordinate");
int maxLatitudeIndex = 0;
double maxLatitude = -Double.MIN_VALUE;
int maxLongitudeIndex = 0;
double maxLongitude = -180;
int minLatitudeIndex = 0;
double minLatitude = Double.MAX_VALUE;
int minLongitudeIndex = 0;
double minLongitude = Double.MAX_VALUE;
for (int i = 0; i < nBounds.getLength(); i++) {
boundary.add(getCoordinates((Element) nBounds.item(i)));
if (boundary.get(i).getLatitude() > maxLatitude) {
maxLatitudeIndex = i;
maxLatitude = boundary.get(i).getLatitude();
}
if (boundary.get(i).getLatitude() < minLatitude) {
minLatitudeIndex = i;
minLatitude = boundary.get(i).getLatitude();
}
if (boundary.get(i).getLongitude() > maxLongitude) {
maxLongitudeIndex = i;
maxLongitude = boundary.get(i).getLongitude();
}
if (boundary.get(i).getLongitude() < minLongitude) {
minLongitudeIndex = i;
minLongitude = boundary.get(i).getLongitude();
}
}
double difference = 0;//this will hold the largest difference so we can make the map square.
double latitudeDiff = Math.abs(Math.abs(boundary.get(maxLatitudeIndex).getLatitude()) - Math.abs(boundary.get(minLatitudeIndex).getLatitude()));
double longitudeDiff = Math.abs(Math.abs(boundary.get(maxLongitudeIndex).getLongitude()) - Math.abs(boundary.get(minLongitudeIndex).getLongitude()));
if (latitudeDiff >= longitudeDiff) {
difference = latitudeDiff - longitudeDiff;
maxLongitude += difference / 2;
minLongitude -= difference / 2;
} else {
difference = longitudeDiff - latitudeDiff;
maxLatitude += difference / 2;
minLatitude -= difference / 2;
}
maxLatitude += COORDINATEPADDING;
minLatitude -= COORDINATEPADDING;
maxLongitude += COORDINATEPADDING;
minLongitude -= COORDINATEPADDING;
//now create map boundaries
//top left canvas point is min logitude, max latitude
//bottom right of canvas point is min longitude, max latitude.
mapTopLeft = new GPSCoordinate(minLatitude, minLongitude);
mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude);
NodeList nMarks = ((Element) nCourse.item(0)).getElementsByTagName("marker");
startPt1 = getCoordinates(nMarks, 0);
startPt2 = getCoordinates(nMarks, 0, 1);
mark = getCoordinates(nMarks, 1);
windwardPt1 = getCoordinates(nMarks, 2);
windwardPt2 = getCoordinates(nMarks, 2, 1);
leewardPt1 = getCoordinates(nMarks, 3);
leewardPt2 = getCoordinates(nMarks, 3, 1);
finishPt1 = getCoordinates(nMarks, 4);
finishPt2 = getCoordinates(nMarks, 4, 1);
}
/**
* gets a marker from the XML file
*
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @return
*/
private Marker getMarker(NodeList start) {
return getMarker(start, 0);
}
/**
* gets a marker from the XML file
*
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex index in the node that has the coordinate tag
* @return
* reads a course
* @throws StreamedCourseXMLException error
*/
private Marker getMarker(NodeList start, int startIndex) {
return getMarker(start, startIndex, 0);
private void readCourse() throws StreamedCourseXMLException {
readCompoundMarks();
readCompoundMarkSequence();
readCourseLimit();
}
/**
* gets a marker from the XML file
*
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex index in the node that has the coordinate tag
* @param nodeIndex coordinate index
* @return
* Indexes CompoundMark elements by their ID for use in generating the course, and populates list of Markers.
* @see CompoundMark
*/
private Marker getMarker(NodeList start, int startIndex, int nodeIndex) {
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("marker");
Element marker = (Element) nodeList.item(nodeIndex);
return getMarker(marker);
private void readCompoundMarks() throws StreamedCourseXMLException {
Element nCourse = (Element) doc.getElementsByTagName("Course").item(0);
for(int i = 0; i < nCourse.getChildNodes().getLength(); i++) {
Node compoundMark = nCourse.getChildNodes().item(i);
if(compoundMark.getNodeName().equals("CompoundMark")) {
int compoundMarkID = getCompoundMarkID((Element) compoundMark);
compoundMarkMap.put(compoundMarkID, (Element)compoundMark);
compoundMarks.add(getCompoundMark(compoundMarkID));
}
}
}
/**
* gets a changes a marker to GPS coordinates into a marker
*
* @param markerNode marker to turn into coordinates
* @return
* Generates a CompoundMark from the CompoundMark element with given ID.
* @param compoundMarkID index of required CompoundMark element
* @return generated CompoundMark
* @throws StreamedCourseXMLException if CompoundMark element contains unhandled number of compoundMarks
* @see CompoundMark
*/
private Marker getMarker(Element markerNode) {
NodeList nCoordinates = markerNode.getElementsByTagName("coordinate");
private CompoundMark getCompoundMark(int compoundMarkID) throws StreamedCourseXMLException {
Element compoundMark = compoundMarkMap.get(compoundMarkID);
NodeList nMarks = compoundMark.getElementsByTagName("Mark");
CompoundMark marker;
GPSCoordinate side1 = getCoordinates((Element) nCoordinates.item(0));
GPSCoordinate side2;
if (nCoordinates.getLength() > 1) {
side2 = getCoordinates((Element) nCoordinates.item(1));
} else {
side2 = side1;
switch(nMarks.getLength()) {
case 1: marker = new CompoundMark(getMark((Element)nMarks.item(0)));
break;
case 2: marker = new CompoundMark(getMark((Element)nMarks.item(0)), getMark((Element)nMarks.item(1))); break;
default: throw new StreamedCourseXMLException();
}
NodeList name = markerNode.getElementsByTagName("name");
return name.getLength() == 1 ? new Marker(getTextValueOfNode((Element) markerNode, "name"), side1, side2) : new Marker(side1, side2);
return marker;
}
/**
* gets a coordinates from the XML file
*
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @return
* Gets a mark from an Element
* @param mark Element the mark is suppose to be part of
* @return a Mark that existed in the element
*/
private GPSCoordinate getCoordinates(NodeList start) {
return getCoordinates(start, 0);
private Mark getMark(Element mark) {
int sourceID = Integer.parseInt(mark.getAttribute("SourceID"));
return marks.get(sourceID);
}
/**
* gets a coordinates from the XML file
*
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex the index the tag containing the coordinate should be in
* @return
* Reads "compoundMarkID" attribute of CompoundMark or Corner element
* @param element with "compoundMarkID" attribute
* @return value of "compoundMarkID" attribute
*/
private GPSCoordinate getCoordinates(NodeList start, int startIndex) {
return getCoordinates(start, startIndex, 0);
private int getCompoundMarkID(Element element) {
return Integer.parseInt(element.getAttribute("CompoundMarkID"));
}
/**
* gets a coordinates from the XML file
*
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex the index the tag containing the coordinate should be in
* @param nodeIndex The coordinate index
* @return
* Reads "name" attribute of CompoundMark element with corresponding CompoundMarkID
* @param compoundMarkID unique ID for CompoundMark element
* @return value of "name" attribute
*/
private GPSCoordinate getCoordinates(NodeList start, int startIndex, int nodeIndex) {
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("coordinate");
Element coord = (Element) nodeList.item(nodeIndex);
return getCoordinates(coord);
private String getCompoundMarkName(int compoundMarkID) {
return compoundMarkMap.get(compoundMarkID).getAttribute("Name");
}
/**
* Returns the coordinate TODO raise exception that runs when the XML is formatted wrongly.
*
* @param coordNode
* @return
* Populates list of legs given CompoundMarkSequence element and referenced CompoundMark elements.
* @throws StreamedCourseXMLException if compoundMarks cannot be resolved from CompoundMark
*/
private GPSCoordinate getCoordinates(Element coordNode) {
double startLat = Double.parseDouble(getTextValueOfNode(coordNode, "latitude"));
double startLong = Double.parseDouble(getTextValueOfNode(coordNode, "longitude"));
return new GPSCoordinate(startLat, startLong);
private void readCompoundMarkSequence() throws StreamedCourseXMLException {
Element nCompoundMarkSequence = (Element) doc.getElementsByTagName("CompoundMarkSequence").item(0);
NodeList nCorners = nCompoundMarkSequence.getElementsByTagName("Corner");
Element markXML = (Element)nCorners.item(0);
CompoundMark lastCompoundMark = getCompoundMark(getCompoundMarkID(markXML));
String legName = getCompoundMarkName(getCompoundMarkID(markXML));
for(int i = 1; i < nCorners.getLength(); i++) {
markXML = (Element)nCorners.item(i);
CompoundMark currentCompoundMark = getCompoundMark(getCompoundMarkID(markXML));
legs.add(new Leg(legName, lastCompoundMark, currentCompoundMark, i-1));
lastCompoundMark = currentCompoundMark;
legName = getCompoundMarkName(getCompoundMarkID(markXML));
}
public List<Boat> getBoats() {
return boats;
}
public List<Leg> getLegs() {
return legs;
}
public GPSCoordinate getMark() {
return mark;
/**
* Reads the boundary limits of the course
*/
private void readCourseLimit() {
Element nCourseLimit = (Element) doc.getElementsByTagName("CourseLimit").item(0);
for(int i = 0; i < nCourseLimit.getChildNodes().getLength(); i++) {
Node limit = nCourseLimit.getChildNodes().item(i);
if (limit.getNodeName().equals("Limit")) {
double lat = Double.parseDouble(limit.getAttributes().getNamedItem("Lat").getTextContent());
double lon = Double.parseDouble(limit.getAttributes().getNamedItem("Lon").getTextContent());
boundary.add(new GPSCoordinate(lat, lon));
}
public GPSCoordinate getStartPt1() {
return startPt1;
}
public GPSCoordinate getStartPt2() {
return startPt2;
}
double maxLatitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING;
double maxLongitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude() + COORDINATEPADDING;
double minLatitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING;
double minLongitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude() + COORDINATEPADDING;
public GPSCoordinate getFinishPt1() {
return finishPt1;
mapTopLeft = new GPSCoordinate(minLatitude, minLongitude);
mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude);
}
public GPSCoordinate getFinishPt2() {
return finishPt2;
public List<GPSCoordinate> getBoundary() {
return boundary;
}
public GPSCoordinate getLeewardPt1() {
return leewardPt1;
public GPSCoordinate getMapTopLeft() {
return mapTopLeft;
}
public GPSCoordinate getLeewardPt2() {
return leewardPt2;
public GPSCoordinate getMapBottomRight() {
return mapBottomRight;
}
public GPSCoordinate getWindwardPt1() {
return windwardPt1;
public List<Leg> getLegs() {
return legs;
}
public GPSCoordinate getWindwardPt2() {
return windwardPt2;
}
public List<CompoundMark> getCompoundMarks() { return compoundMarks; }
public List<GPSCoordinate> getBoundary() {
return boundary;
public Double getPadding() {
return COORDINATEPADDING;
}
public GPSCoordinate getMapTopLeft() {
return mapTopLeft;
public ZonedDateTime getCreationTimeDate() {
return creationTimeDate;
}
public GPSCoordinate getMapBottomRight() {
return mapBottomRight;
public ZonedDateTime getZonedDateTime() {
return raceStartTime;
}
public int getRaceId() {
return raceID;
}
public List<Marker> getMarkers() {
return markers;
public String getRaceType() {
return raceType;
}
public boolean isPostpone() {
return postpone;
}
public String getRaceType() {
return "FLEET";
public List<Boat> getBoats() {
return new ArrayList<>(participants.values());
}
}

@ -1,11 +0,0 @@
package seng302.DataInput;
import seng302.Model.Regatta;
/**
* Created by zwu18 on 25/04/17.
*/
public interface RegattaDataSource {
Regatta getRegatta();
}

@ -1,75 +0,0 @@
package seng302.DataInput;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import seng302.Model.Regatta;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
/**
* Created by jjg64 on 19/04/17.
*/
public class RegattaXMLReader extends XMLReader implements RegattaDataSource {
private Regatta regatta;
/**
* Constructor for Regatta XML
*
* @param filePath path of the file
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public RegattaXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException {
this(filePath, true);
}
/**
* Constructor for Regatta XML
*
* @param filePath file path to read
* @param read whether or not to read and store the files straight away.
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public RegattaXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException {
super(filePath);
if (read) {
read();
}
}
/**
* Read the XML
*/
private void read() {
NodeList attributeConfig = doc.getElementsByTagName("RegattaConfig");
Element attributes = (Element) attributeConfig.item(0);
makeRegatta(attributes);
}
/**
* Create new regatta
* @param attributes
*/
private void makeRegatta(Element attributes) {
int regattaID = Integer.parseInt(getTextValueOfNode(attributes, "RegattaID"));
String regattaName = getTextValueOfNode(attributes, "RegattaName");
String courseName = getTextValueOfNode(attributes, "CourseName");
double centralLatitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralLatitude"));
double centralLongitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralLongitude"));
double centralAltitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralAltitude"));
float utcOffset = Float.parseFloat(getTextValueOfNode(attributes, "UtcOffset"));
float magneticVariation = Float.parseFloat(getTextValueOfNode(attributes, "MagneticVariation"));
regatta = new Regatta(regattaID, regattaName, courseName, centralLatitude, centralLongitude, centralAltitude, utcOffset, magneticVariation);
}
public Regatta getRegatta() {
return regatta;
}
}

@ -2,16 +2,23 @@ package seng302.DataInput;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
/**
* Created by fwy13 on 26/03/2017.
* Base Reader for XML Files
*/
public abstract class XMLReader {
@ -20,18 +27,36 @@ public abstract class XMLReader {
/**
* Read in XML file
* @param filePath filepath for XML file
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
* @throws ParserConfigurationException Error in reading the XML File
* @throws IOException Issues Accessing the XML FIle
* @throws SAXException Error With the XML FIle's format
*/
public XMLReader(String filePath) throws ParserConfigurationException, IOException, SAXException {
InputStream fXmlFile = getClass().getClassLoader().getResourceAsStream(filePath);
InputSource fXmlFile;
if (filePath.contains("<")) {
fXmlFile = new InputSource();
fXmlFile.setCharacterStream(new StringReader(filePath));
} else {
fXmlFile = new InputSource(getClass().getClassLoader().getResourceAsStream(filePath));
}
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
}
/**
* Alternate constructor
* @param xmlFile
* @param isWholeFile
*/
public XMLReader(String xmlFile, Boolean isWholeFile) {
}
/**
* Return Document data of the read-in XML
* @return XML document
@ -60,4 +85,29 @@ public abstract class XMLReader {
return n.getAttribute(attr);
}
protected boolean exists(Node node, String attribute) {
return node.getAttributes().getNamedItem(attribute) != null;
}
/**
* Get the contents of the XML FILe.
* @param document
* @return
* @throws TransformerException
*/
public static String getContents(Document document) throws TransformerException {
DOMSource source = new DOMSource(document);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
StringWriter stringWriter = new StringWriter();
StreamResult result = new StreamResult(stringWriter);
transformer.transform(source, result);
return stringWriter.toString();
}
}

@ -1,17 +0,0 @@
package seng302.Exceptions;
/**
* Created by f123 on 25-Apr-17.
*/
/**
* An exception thrown when a Regatta.xml message cannot be generated and sent.
*/
public class InvalidRegattaDataException extends RuntimeException {
public InvalidRegattaDataException() {
}
public InvalidRegattaDataException(String message) {
super(message);
}
}

@ -0,0 +1,7 @@
package seng302.Exceptions;
/**
* Created by cbt24 on 25/04/17.
*/
public class StreamedCourseXMLException extends Throwable {
}

@ -49,6 +49,7 @@ public class MockOutput implements Runnable
private String regattaXml;
private String boatsXml;
private boolean stop = false; //whether or not hte thread keeps running
/**
* Ctor.
@ -158,18 +159,25 @@ public class MockOutput implements Runnable
this.messagesToSendQueue.add(messagesToSendBuffer);
}
/**
* Sending loop of the Server
*/
public void run() {
try {
while (true){
while (!stop){
System.out.println("Waiting for a connection...");//TEMP DEBUG REMOVE
mockSocket = serverSocket.accept();
outToVisualiser = new DataOutputStream(mockSocket.getOutputStream());
while(boatsXml == null || regattaXml == null || raceXml == null) {
if (boatsXml == null || regattaXml == null || raceXml == null){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
parseXMLString(raceXml, XMLMessage.XMLTypeRace);
@ -205,18 +213,30 @@ public class MockOutput implements Runnable
}
}
public void stop(){
stop = true;
}
/**
* Sets the Race XML to send
* @param raceXml XML to send to the CLient
*/
public void setRaceXml(String raceXml) {
this.raceXml = raceXml;
}
/**
* Sets the Regatta XMl to send
* @param regattaXml XML to send to CLient
*/
public void setRegattaXml(String regattaXml) {
this.regattaXml = regattaXml;
}
/**
* Sets the Boats XML to send
* @param boatsXml XMl to send to the CLient
*/
public void setBoatsXml(String boatsXml) {
this.boatsXml = boatsXml;
}

@ -4,13 +4,13 @@ import org.geotools.referencing.GeodeticCalculator;
/**
* Created by esa46 on 1/05/17.
* Boat Model that is used to store information on the boats that are running in the race.
*/
public class Boat {
private String name;
private double velocity;
private double scaledVelocity;
private String abbrev;
private String country;
private int sourceID;
private Leg currentLeg;
private double distanceTravelledInLeg;
@ -22,14 +22,12 @@ public class Boat {
/**
* Boat initialiser which keeps all of the information of the boat.
*
* @param name Name of the Boat.
* @param velocity Speed in m/s that the boat travels at.
* @param abbrev nam abbreviation
* @param sourceID id of boat
* @param name Name of the Boat.
* @param country nam abbreviation
*/
public Boat(String name, double velocity, String abbrev, int sourceID) {
this.velocity = velocity;
this.abbrev = abbrev;
public Boat(int sourceID, String name, String country) {
this.country = this.country;
this.name = name;
this.sourceID = sourceID;
}
@ -42,8 +40,8 @@ public class Boat {
public double calculateAzimuth() {
GeodeticCalculator calc = new GeodeticCalculator();
GPSCoordinate start = currentLeg.getStartMarker().getAverageGPSCoordinate();
GPSCoordinate end = currentLeg.getEndMarker().getAverageGPSCoordinate();
GPSCoordinate start = currentLeg.getStartCompoundMark().getAverageGPSCoordinate();
GPSCoordinate end = currentLeg.getEndCompoundMark().getAverageGPSCoordinate();
calc.setStartingGeographicPoint(start.getLongitude(), start.getLatitude());
calc.setDestinationGeographicPoint(end.getLongitude(), end.getLatitude());
@ -90,12 +88,12 @@ public class Boat {
this.scaledVelocity = scaledVelocity;
}
public String getAbbrev() {
return abbrev;
public String getCountry() {
return country;
}
public void setAbbrev(String abbrev) {
this.abbrev = abbrev;
public void setCountry(String country) {
this.country = country;
}
public int getSourceID() {

@ -0,0 +1,61 @@
package seng302.Model;
import org.geotools.referencing.GeodeticCalculator;
import java.awt.geom.Point2D;
/**
* Compound Marks that exist in the race
*/
public class CompoundMark extends Marker{
private GPSCoordinate averageGPSCoordinate;
private Mark mark1;
private Mark mark2 = null;
public CompoundMark(Mark mark1) {
super(mark1.getPosition());
this.mark1 = mark1;
this.averageGPSCoordinate = calculateAverage();
}
public CompoundMark(Mark mark1, Mark mark2) {
super(mark1.getPosition(), mark2.getPosition());
this.mark1 = mark1;
this.mark2 = mark2;
this.averageGPSCoordinate = calculateAverage();
}
public Mark getMark1Source() { return mark1; }
public Mark getMark2Source() { return mark2; }
public GPSCoordinate getMark1() {
return mark1.getPosition();
}
public GPSCoordinate getMark2() {
return mark2.getPosition();
}
public GPSCoordinate getAverageGPSCoordinate() {
return averageGPSCoordinate;
}
private GPSCoordinate calculateAverage() {
if(mark2 != null) {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(mark1.getPosition().getLongitude(), mark1.getPosition().getLatitude());
calc.setDestinationGeographicPoint(mark2.getPosition().getLongitude(), mark2.getPosition().getLatitude());
double azimuth = calc.getAzimuth();
double distance = calc.getOrthodromicDistance();
GeodeticCalculator middleCalc = new GeodeticCalculator();
middleCalc.setStartingGeographicPoint(mark1.getPosition().getLongitude(), mark1.getPosition().getLatitude());
middleCalc.setDirection(azimuth, distance / 2);
Point2D middlePoint = middleCalc.getDestinationGeographicPoint();
return new GPSCoordinate(middlePoint.getY(), middlePoint.getX());
} else return mark1.getPosition();
}
}

@ -1,31 +1,33 @@
package seng302.Model;
import seng302.Data.BoatData;
import seng302.Data.RaceData;
import seng302.Data.RegattaData;
import seng302.DataInput.RaceDataSource;
import seng302.DataInput.RegattaDataSource;
import seng302.Exceptions.InvalidBoatDataException;
import seng302.Exceptions.InvalidRaceDataException;
import seng302.Exceptions.InvalidRegattaDataException;
import org.xml.sax.SAXException;
import seng302.DataInput.*;
import seng302.Exceptions.StreamedCourseXMLException;
import seng302.MockOutput;
import seng302.Networking.Messages.Enums.MessageType;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.text.ParseException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* Created by esa46 on 21/04/17.
* A Race Event, this holds all of the race's information as well as handling the connection to its clients.
*/
public class Event {
RaceDataSource raceDataSource;
RegattaDataSource regattaDataSource;
String raceXML;
String regattaXML;
String boatXML;
MockOutput mockOutput;
public Event(RaceDataSource raceData, RegattaDataSource regattaData) {
this.raceDataSource = raceData;
this.regattaDataSource = regattaData;
public Event(String raceXML, String regattaXML, String boatXML) {
this.raceXML = getRaceXMLAtCurrentTime(raceXML);
this.boatXML = boatXML;
this.regattaXML = regattaXML;
try {
mockOutput = new MockOutput();
new Thread(mockOutput).start();
@ -35,59 +37,44 @@ public class Event {
}
/**
* Send the initial race data and then begin race simulation
* Sends the initial race data and then begins race simulation
*/
public void start() {
System.out.println("Sending Regatta");
sendRegattaData();
System.out.println("Sending Race");
sendRaceData();
System.out.println("Sending Boat");
sendBoatData();
int scaleFactor = 5;//TEMP - was 15.
Race newRace = new Race(raceDataSource, scaleFactor, mockOutput);
try {
sendXMLs();
Race newRace = new Race(new RaceXMLReader(this.raceXML, new BoatXMLReader(boatXML)), mockOutput);
new Thread((newRace)).start();
}
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
}
}
/**
* Send XML string of initial regatta data to the visualiser
* @throws InvalidRegattaDataException Invalid regatta
* Sends out each xml string, via the mock output
*/
public void sendRegattaData() throws InvalidRegattaDataException {
private void sendXMLs() {
System.setOut(System.out);
RegattaData regattaData = new RegattaData(regattaDataSource);
String xmlString = regattaData.createXML();
mockOutput.setRegattaXml(xmlString);
mockOutput.parseXMLString(xmlString, 26);
mockOutput.setRegattaXml(regattaXML);
mockOutput.parseXMLString(regattaXML, MessageType.XMLMESSAGE.getValue());
}
mockOutput.setRaceXml(raceXML);
mockOutput.parseXMLString(raceXML, MessageType.XMLMESSAGE.getValue());
/**
* Send XML string of initial race data to the visualiser
* @throws InvalidRaceDataException Invalid race
*/
public void sendRaceData() throws InvalidRaceDataException {
RaceData raceData = new RaceData(raceDataSource);
//Serialize race data to an XML as a string.
String xmlString = raceData.createXML();
mockOutput.setRaceXml(xmlString);
mockOutput.parseXMLString(xmlString, 26);
mockOutput.setBoatsXml(boatXML);
mockOutput.parseXMLString(boatXML, MessageType.XMLMESSAGE.getValue());
}
/**
* Send XML string of initial boat data to the visualiser
* @throws InvalidBoatDataException Invalid boat
* Sets the xml description of the race to show the race was created now, and starts in 3 minutes
* @param raceXML
* @return String containing edited xml
*/
public void sendBoatData() throws InvalidBoatDataException {
BoatData boatData = new BoatData(raceDataSource.getBoats());
//Serialize race data to an XML as a string.
String xmlString = boatData.createXML();
mockOutput.setBoatsXml(xmlString);
mockOutput.parseXMLString(xmlString, 26);
private String getRaceXMLAtCurrentTime(String raceXML) {
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
ZonedDateTime creationTime = ZonedDateTime.now();
return raceXML.replace("CREATION_TIME", dateFormat.format(creationTime))
.replace("START_TIME", dateFormat.format(creationTime.plusMinutes(3)));
}
}

@ -5,13 +5,13 @@ import seng302.Constants;
/**
* Created by cbt24 on 6/03/17.
* Leg of the race, this is what each part of the race is divided into, from mark to mark.
*/
public class Leg {
private String name; //nautical miles
private double distance;
private Marker startMarker;
private Marker endMarker;
private Marker startCompoundMark;
private Marker endCompoundMark;
private int legNumber;
/**
@ -24,8 +24,8 @@ public class Leg {
*/
public Leg(String name, Marker start, Marker end, int number) {
this.name = name;
this.startMarker = start;
this.endMarker = end;
this.startCompoundMark = start;
this.endCompoundMark = end;
this.legNumber = number;
calculateDistance();
}
@ -69,20 +69,20 @@ public class Leg {
}
public Marker getStartMarker() {
return startMarker;
public Marker getStartCompoundMark() {
return startCompoundMark;
}
public void setStartMarker(Marker startMarker) {
this.startMarker = startMarker;
public void setStartCompoundMark(Marker startCompoundMark) {
this.startCompoundMark = startCompoundMark;
}
public Marker getEndMarker() {
return endMarker;
public Marker getEndCompoundMark() {
return endCompoundMark;
}
public void setEndMarker(Marker endMarker) {
this.endMarker = endMarker;
public void setEndCompoundMark(Marker endCompoundMark) {
this.endCompoundMark = endCompoundMark;
}
/**
@ -92,8 +92,8 @@ public class Leg {
GeodeticCalculator calc = new GeodeticCalculator();
//Load start and end of leg
GPSCoordinate startMarker = this.startMarker.getAverageGPSCoordinate();
GPSCoordinate endMarker = this.endMarker.getAverageGPSCoordinate();
GPSCoordinate startMarker = this.startCompoundMark.getAverageGPSCoordinate();
GPSCoordinate endMarker = this.endCompoundMark.getAverageGPSCoordinate();
calc.setStartingGeographicPoint(startMarker.getLongitude(), startMarker.getLatitude());
calc.setDestinationGeographicPoint(endMarker.getLongitude(), endMarker.getLatitude());
this.distance = calc.getOrthodromicDistance() / Constants.NMToMetersConversion;

@ -0,0 +1,28 @@
package seng302.Model;
/**
* A coordinate position
*/
public class Mark {
private int sourceID;
private String name;
private GPSCoordinate position;
public Mark(int sourceID, String name, GPSCoordinate position) {
this.sourceID = sourceID;
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public int getSourceID() {
return sourceID;
}
public GPSCoordinate getPosition() {
return position;
}
}

@ -4,7 +4,7 @@ import org.geotools.referencing.GeodeticCalculator;
import java.awt.geom.Point2D;
/**
* Created by esa46 on 29/03/17.
* A Mark that exists on the race and pinpoints an objective.
*/
public class Marker {

@ -1,12 +1,10 @@
package seng302.Model;
import javafx.animation.AnimationTimer;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants;
import seng302.DataInput.RaceDataSource;
import seng302.MockOutput;
@ -19,81 +17,31 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Parent class for races
* Created by fwy13 on 3/03/17.
*/
public class Race implements Runnable {
//protected Boat[] startingBoats;
protected ObservableList<Boat> startingBoats;
protected ObservableList<CompoundMark> compoundMarks;
protected List<Leg> legs;
protected int boatsFinished = 0;
protected long totalTimeElapsed;
protected int scaleFactor=25;
protected int PRERACE_TIME = 180000; //time in milliseconds to pause during pre-race. At the moment, 3 minutes
protected int scaleFactor = 50;
private long startTime;
protected boolean countdownFinish = false;
protected boolean runRace = true;
private int lastFPS = 20;
private int raceId;
private int dnfChance = 0; //percentage chance a boat fails at each checkpoint
private MockOutput mockOutput;
private static int boatOffset = 0;
private int finished = 0;
/**
* Initailiser for Race
*
* @param boats Takes in an array of boats that are participating in the race.
* @param legs Number of marks in order that the boats pass in order to complete the race.
* @param scaleFactor for race
*/
public Race(List<Boat> boats, List<Leg> legs, int raceID, int scaleFactor, MockOutput mockOutput) {
this.startingBoats = FXCollections.observableArrayList(boats);
this.legs = legs;
public Race(RaceDataSource raceData, MockOutput mockOutput) {
this.startingBoats = FXCollections.observableArrayList(raceData.getBoats());
this.legs = raceData.getLegs();
this.compoundMarks = FXCollections.observableArrayList(raceData.getCompoundMarks());
this.legs.add(new Leg("Finish", this.legs.size()));
this.raceId = raceID;
this.scaleFactor = scaleFactor;
this.raceId = raceData.getRaceId();
this.mockOutput = mockOutput;
//TODO refactor
this.startTime = System.currentTimeMillis() + (this.PRERACE_TIME / this.scaleFactor);
if (startingBoats != null && startingBoats.size() > 0) {
initialiseBoats();
}
}
public Race(RaceDataSource raceData, int scaleFactor, MockOutput mockOutput) {
this(raceData.getBoats(), raceData.getLegs(), raceData.getRaceId(), scaleFactor, mockOutput);
}
/**
* Calculates the boats next GPS position based on its distance travelled and heading
*
* @param oldCoordinates GPS coordinates of the boat's starting position
* @param distanceTravelled distance in nautical miles
* @param azimuth boat's current direction. Value between -180 and 180
* @return The boat's new coordinate
*/
public static GPSCoordinate calculatePosition(GPSCoordinate oldCoordinates, double distanceTravelled, double azimuth) {
//Find new coordinate using current heading and distance
GeodeticCalculator geodeticCalculator = new GeodeticCalculator();
//Load start point into calculator
Point2D startPoint = new Point2D.Double(oldCoordinates.getLongitude(), oldCoordinates.getLatitude());
geodeticCalculator.setStartingGeographicPoint(startPoint);
//load direction and distance tranvelled into calculator
geodeticCalculator.setDirection(azimuth, distanceTravelled * Constants.NMToMetersConversion);
//get new point
Point2D endPoint = geodeticCalculator.getDestinationGeographicPoint();
return new GPSCoordinate(endPoint.getY(), endPoint.getX());
this.startTime = System.currentTimeMillis() + (Constants.PRE_RACE_WAIT_TIME / this.scaleFactor);
}
/**
@ -101,75 +49,61 @@ public class Race implements Runnable {
*/
public void run() {
initialiseBoats();
countdownTimer();
countdownTimer.start();
}
/**
* Starts the heartbeat timer, which sends a heartbeat message every so often (i.e., 5 seconds).
* Parse the marker boats through mock output
*/
public void parseMarks() {
for (CompoundMark mark : compoundMarks){
mockOutput.parseBoatLocation(mark.getMark1Source().getSourceID(), mark.getMark1().getLatitude(), mark.getMark1().getLongitude(),0,0);
if (mark.getMark2Source()!=null){
mockOutput.parseBoatLocation(mark.getMark2Source().getSourceID(), mark.getMark2().getLatitude(), mark.getMark2().getLongitude(),0,0);
}
}
}
/**
* Countdown timer until race starts. Use PRERACE_TIME to set countdown duration.
* Countdown timer until race starts.
*/
protected void countdownTimer() {
AnimationTimer timer = new AnimationTimer() {
protected AnimationTimer countdownTimer = new AnimationTimer() {
long currentTime = System.currentTimeMillis();
//long startTime = currentTime + (PRERACE_TIME / scaleFactor);
//long minutes;
//long hours;
long timeLeft;
@Override
public void handle(long arg0) {
timeLeft = startTime - currentTime;
ArrayList<BoatStatus> boatStatuses = new ArrayList<>();
//For each boat, we update it's position, and generate a BoatLocationMessage.
for (int i = 0; i < startingBoats.size(); i++) {
Boat boat = startingBoats.get((i + boatOffset) % startingBoats.size());
if (boat != null) {
mockOutput.parseBoatLocation(boat.getSourceID(), boat.getCurrentPosition().getLatitude(), boat.getCurrentPosition().getLongitude(), boat.getHeading(), 0);
boatStatuses.add(new BoatStatus(boat.getSourceID(),
boat.getCurrentLeg().getLegNumber() >= 0 ? BoatStatusEnum.RACING : BoatStatusEnum.DNF, boat.getCurrentLeg().getLegNumber()));
}
if (timeLeft <= 0) {
System.setProperty("javafx.animation.fullspeed", "true");
raceTimer.start();
stop();
}
boatOffset = (boatOffset + 1) % (startingBoats.size());
if (timeLeft <= 60000/scaleFactor && timeLeft > 0) {
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 2, startTime, 0, 2300, 1, boatStatuses);
mockOutput.parseRaceStatus(raceStatus);
}
else if (timeLeft <= 0) {
countdownFinish = true;
if (runRace) {
simulateRace();
}
stop();
ArrayList<BoatStatus> boatStatuses = new ArrayList<>();
for (Boat boat : startingBoats) {
mockOutput.parseBoatLocation(boat.getSourceID(), boat.getCurrentPosition().getLatitude(),
boat.getCurrentPosition().getLongitude(), boat.getHeading(), 0);
boatStatuses.add(new BoatStatus(boat.getSourceID(), BoatStatusEnum.PRESTART, 0));
}
else {
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 1, startTime, 0, 2300,1, boatStatuses);
parseMarks();
int raceStatusNumber = timeLeft <= 60000 / scaleFactor && timeLeft > 0? 2 : 1;
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, raceStatusNumber, startTime, 0, 2300, 1, boatStatuses);
mockOutput.parseRaceStatus(raceStatus);
}
currentTime = System.currentTimeMillis();
}
};
timer.start();
//countdownFinish = true;
}
/**
* Starts the Race Simulation, playing the race start to finish with the timescale.
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events.
* Starts the race
*/
private void simulateRace() {
System.setProperty("javafx.animation.fullspeed", "true");
for (Boat boat : startingBoats) {
boat.setStarted(true);
}
new AnimationTimer() {
private AnimationTimer raceTimer = new AnimationTimer() {
//Start time of loop.
long timeRaceStarted = System.currentTimeMillis();
int boatOffset = 0;
@Override
public void handle(long arg0) {
@ -178,88 +112,102 @@ public class Race implements Runnable {
long currentTime = System.currentTimeMillis();
//Update the total elapsed time.
totalTimeElapsed = currentTime - timeRaceStarted;
ArrayList<BoatStatus> boatStatuses = new ArrayList<BoatStatus>();
finished = 0;
//For each boat, we update it's position, and generate a BoatLocationMessage.
ArrayList<BoatStatus> boatStatuses = new ArrayList<>();
//For each boat, we update its position, and generate a BoatLocationMessage.
for (int i = 0; i < startingBoats.size(); i++) {
Boat boat = startingBoats.get((i + boatOffset) % startingBoats.size());
if (boat != null) {
//Update position.
if (boat.getTimeFinished() < 0) {
updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS));
updatePosition(boat, 15);
checkPosition(boat, totalTimeElapsed);
}
if (boat.getTimeFinished() > 0) {
mockOutput.parseBoatLocation(boat.getSourceID(), boat.getCurrentPosition().getLatitude(), boat.getCurrentPosition().getLongitude(), boat.getHeading(), boat.getVelocity());
boatStatuses.add(new BoatStatus(boat.getSourceID(), BoatStatusEnum.FINISHED, boat.getCurrentLeg().getLegNumber()));
finished++;
} else {
mockOutput.parseBoatLocation(boat.getSourceID(), boat.getCurrentPosition().getLatitude(), boat.getCurrentPosition().getLongitude(), boat.getHeading(), boat.getVelocity());
boatStatuses.add(new BoatStatus(boat.getSourceID(),
boat.getCurrentLeg().getLegNumber() >= 0 ? BoatStatusEnum.RACING : BoatStatusEnum.DNF, boat.getCurrentLeg().getLegNumber()));
}
if (startingBoats.size()==finished){
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 4, startTime, 0, 2300, 2, boatStatuses);//TODO FIX the second currentTime is a placeholder! Also, replace magic values.
mockOutput.parseRaceStatus(raceStatus);
}
} else {
raceFinished.start();
stop();
}
}
parseMarks();
boatOffset = (boatOffset + 1) % (startingBoats.size());
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 3, startTime, 0, 2300, 2, boatStatuses);//TODO FIX the second currentTime is a placeholder! Also, replace magic values.
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 3, startTime, 0, 2300, 2, boatStatuses);
mockOutput.parseRaceStatus(raceStatus);
}
}
}.start();
};
/**
* Broadcast that the race has finished.
*/
protected AnimationTimer raceFinished = new AnimationTimer(){
int iters = 0;
@Override
public void handle(long now) {
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 4, startTime, 0, 2300, 2, null);
mockOutput.parseRaceStatus(raceStatus);
if (iters > 500){
mockOutput.stop();
stop();
}
iters++;
}
};
/**
* Initailises all of the boats
*/
public void initialiseBoats() {
Leg officialStart = legs.get(0);
String name = officialStart.getName();
Marker endMarker = officialStart.getEndMarker();
Marker endMark = officialStart.getEndCompoundMark();
ArrayList<GPSCoordinate> startingPositions = getSpreadStartingPositions();
ArrayList<Marker> startMarkers = getSpreadStartingPositions();
for (int i = 0; i < startingBoats.size(); i++) {
Boat boat = startingBoats.get(i);
if (boat != null) {
Leg newLeg = new Leg(name, new Marker(startingPositions.get(i)), endMark, 0);
boat.setCurrentLeg(newLeg);
boat.setVelocity(Constants.TEST_VELOCITIES[i]);
boat.setScaledVelocity(boat.getVelocity() * scaleFactor);
Leg startLeg = new Leg(name, 0);
boat.setCurrentPosition(startMarkers.get(i).getAverageGPSCoordinate());
startLeg.setStartMarker(startMarkers.get(i));
startLeg.setEndMarker(endMarker);
startLeg.calculateDistance();
boat.setCurrentLeg(startLeg);
boat.setCurrentPosition(startingPositions.get(i));
boat.setHeading(boat.calculateHeading());
}
}
}
/**
* Creates a list of starting positions for the different boats, so they do not appear cramped at the start line
*
* @return list of starting positions
*/
public ArrayList<Marker> getSpreadStartingPositions() {
public ArrayList<GPSCoordinate> getSpreadStartingPositions() {
int nBoats = startingBoats.size();
Marker marker = legs.get(0).getStartMarker();
Marker compoundMark = legs.get(0).getStartCompoundMark();
GeodeticCalculator initialCalc = new GeodeticCalculator();
initialCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude());
initialCalc.setDestinationGeographicPoint(marker.getMark2().getLongitude(), marker.getMark2().getLatitude());
initialCalc.setStartingGeographicPoint(compoundMark.getMark1().getLongitude(), compoundMark.getMark1().getLatitude());
initialCalc.setDestinationGeographicPoint(compoundMark.getMark2().getLongitude(), compoundMark.getMark2().getLatitude());
double azimuth = initialCalc.getAzimuth();
double distanceBetweenMarkers = initialCalc.getOrthodromicDistance();
double distanceBetweenBoats = distanceBetweenMarkers / (nBoats + 1);
GeodeticCalculator positionCalc = new GeodeticCalculator();
positionCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude());
ArrayList<Marker> positions = new ArrayList<>();
positionCalc.setStartingGeographicPoint(compoundMark.getMark1().getLongitude(), compoundMark.getMark1().getLatitude());
ArrayList<GPSCoordinate> positions = new ArrayList<>();
for (int i = 0; i < nBoats; i++) {
positionCalc.setDirection(azimuth, distanceBetweenBoats);
Point2D position = positionCalc.getDestinationGeographicPoint();
positions.add(new Marker(new GPSCoordinate(position.getY(), position.getX())));
positions.add(new GPSCoordinate(position.getY(), position.getX()));
positionCalc = new GeodeticCalculator();
positionCalc.setStartingGeographicPoint(position);
@ -268,19 +216,26 @@ public class Race implements Runnable {
}
/**
* Sets the chance each boat has of failing at a gate or marker
* Calculates the boats next GPS position based on its distance travelled and heading
*
* @param chance percentage chance a boat has of failing per checkpoint.
* @param oldCoordinates GPS coordinates of the boat's starting position
* @param distanceTravelled distance in nautical miles
* @param azimuth boat's current direction. Value between -180 and 180
* @return The boat's new coordinate
*/
protected void setDnfChance(int chance) {
if (chance >= 0 && chance <= 100) {
dnfChance = chance;
}
}
public static GPSCoordinate calculatePosition(GPSCoordinate oldCoordinates, double distanceTravelled, double azimuth) {
protected boolean doNotFinish() {
Random rand = new Random();
return rand.nextInt(100) < dnfChance;
//Find new coordinate using current heading and distance
GeodeticCalculator geodeticCalculator = new GeodeticCalculator();
//Load start point into calculator
Point2D startPoint = new Point2D.Double(oldCoordinates.getLongitude(), oldCoordinates.getLatitude());
geodeticCalculator.setStartingGeographicPoint(startPoint);
//load direction and distance travelled into calculator
geodeticCalculator.setDirection(azimuth, distanceTravelled * Constants.NMToMetersConversion);
//get new point
Point2D endPoint = geodeticCalculator.getDestinationGeographicPoint();
return new GPSCoordinate(endPoint.getY(), endPoint.getX());
}
/**
@ -293,7 +248,6 @@ public class Race implements Runnable {
//distanceTravelled = velocity (nm p hr) * time taken to update loop
double distanceTravelled = (boat.getScaledVelocity() * millisecondsElapsed) / 3600000;
double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg();
boolean finish = boat.getCurrentLeg().getName().equals("Finish");
@ -302,19 +256,26 @@ public class Race implements Runnable {
//update boat's distance travelled
boat.setDistanceTravelledInLeg(totalDistanceTravelled);
//Calculate boat's new position by adding the distance travelled onto the start point of the leg
boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartMarker().getAverageGPSCoordinate(),
boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartCompoundMark().getAverageGPSCoordinate(),
totalDistanceTravelled, boat.calculateAzimuth()));
}
}
/**
* Checks the position of the boat
* @param boat Boat to check the position of
* @param timeElapsed time that has past since the last position check.
*/
protected void checkPosition(Boat boat, long timeElapsed) {
if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) {
//boat has passed onto new leg
if (boat.getCurrentLeg().getName().equals("Finish")) {
//boat has finished
boatsFinished++;
boat.setTimeFinished(timeElapsed);
boat.setTimeFinished(timeElapsed);
boat.setVelocity(0);
boat.setScaledVelocity(0);
} else if (doNotFinish()) {
boatsFinished++;
boat.setTimeFinished(timeElapsed);
@ -326,22 +287,29 @@ public class Race implements Runnable {
boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance());
//Move boat on to next leg
Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1);
boat.setCurrentLeg(nextLeg);
//Add overshoot distance into the distance travelled for the next leg
boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg());
}
}
}
/**
* Returns the boats that have started the race.
* Sets the chance each boat has of failing at a gate or marker
*
* @return ObservableList of Boat class that participated in the race.
* @see ObservableList
* @see Boat
* @param chance percentage chance a boat has of failing per checkpoint.
*/
public ObservableList<Boat> getStartingBoats() {
return startingBoats;
protected void setDnfChance(int chance) {
if (chance >= 0 && chance <= 100) {
dnfChance = chance;
}
}
/**
* Rolls a chance for the boat not to finish
* @return whether the boat rolled a dud and did not finish.
*/
protected boolean doNotFinish() {
Random rand = new Random();
return rand.nextInt(100) < dnfChance;
}
}

@ -1,99 +0,0 @@
package seng302.Model;
/**
* 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;
}
}

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<BoatConfig>
<Boats>
<!--Mark Boats-->
<Boat Type="Mark" BoatName="PRO" SourceID="101" >
<GPSposition X= "-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="PIN" SourceID="102" >
<GPSposition X= "-64.855242" Y="32.293771" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="Marker1" SourceID="103" >
<GPSposition X= "-64.843983" Y="32.293039" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="WGL" SourceID="104" >
<GPSposition X= "-64.850045" Y="32.28468" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="WGR" SourceID="105" >
<GPSposition X= "-64.847591" Y="32.280164" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="LGL" SourceID="106" >
<GPSposition X= "-64.835249" Y="32.309693" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="LGR" SourceID="107" >
<GPSposition X= "-64.831785" Y="32.308046" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="FL" SourceID="108" >
<GPSposition X= "-64.839291" Y="32.317379" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="FR" SourceID="109" >
<GPSposition X= "-64.83626" Y="32.317257" Z="0"/>
</Boat>
<!--Participants-->
<Boat BoatName="Team ORACLE USA" HullNum="RG01" ShapeID="0" ShortName="USA" SourceID="121" StoweName="USA" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="Land Rover BAR" HullNum="RG01" ShapeID="0" ShortName="GBR" SourceID="122" StoweName="GBR" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="SoftBank Team Japan" HullNum="RG01" ShapeID="0" ShortName="JPN" SourceID="123" StoweName="JPN" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="Groupama Team France" HullNum="RG01" ShapeID="0" ShortName="FRA" SourceID="124" StoweName="FRA" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="Artemis Racing" HullNum="RG01" ShapeID="0" ShortName="SWE" SourceID="125" StoweName="SWE" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="Emirates Team New Zealand" HullNum="RG01" ShapeID="0" ShortName="NZL" SourceID="126" StoweName="NZL" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
</Boats>
</BoatConfig>

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Race>
<RaceID>5326</RaceID>
<RaceType>FLEET</RaceType>
<CreationTimeDate>CREATION_TIME</CreationTimeDate>
<RaceStartTime Postpone="false" Time="START_TIME"/>
<Participants>
<Yacht SourceID="121"/>
<Yacht SourceID="122"/>
<Yacht SourceID="123"/>
<Yacht SourceID="124"/>
<Yacht SourceID="125"/>
<Yacht SourceID="126"/>
</Participants>
<CompoundMarkSequence>
<Corner CompoundMarkID="1" SeqID="1"/>
<Corner CompoundMarkID="2" SeqID="2"/>
<Corner CompoundMarkID="4" SeqID="3"/>
<Corner CompoundMarkID="3" SeqID="4"/>
<Corner CompoundMarkID="4" SeqID="5"/>
<Corner CompoundMarkID="5" SeqID="6"/>
</CompoundMarkSequence>
<Course>
<CompoundMark CompoundMarkID="1" Name="Start Line">
<Mark SeqId="1" Name="PRO" TargetLat="32.296577" TargetLng="-64.854304" SourceID="101"/>
<Mark SeqId="2" Name="PIN" TargetLat="32.293771" TargetLng="-64.855242" SourceID="102"/>
</CompoundMark>
<CompoundMark CompoundMarkID="2" Name="Marker 1">
<Mark Name="Marker1" TargetLat="32.293039" TargetLng="-64.843983" SourceID="103"/>
</CompoundMark>
<CompoundMark CompoundMarkID="3" Name="Windward Gate">
<Mark Name="WGL" SeqId="1" TargetLat="32.28468" TargetLng="-64.850045" SourceID="104"/>
<Mark Name="WGR" SeqId="2" TargetLat="32.280164" TargetLng="-64.847591" SourceID="105"/>
</CompoundMark>
<CompoundMark CompoundMarkID="4" Name="Leeward Gate">
<Mark Name="LGL" SeqId="1" TargetLat="32.309693" TargetLng="-64.835249" SourceID="106"/>
<Mark Name="LGR" SeqId="2" TargetLat="32.308046" TargetLng="-64.831785" SourceID="107"/>
</CompoundMark>
<CompoundMark CompoundMarkID="5" Name="Finish Line">
<Mark Name="FL" SeqId="1" TargetLat="32.317379" TargetLng="-64.839291" SourceID="108"/>
<Mark Name="FR" SeqId="2" TargetLat="32.317257" TargetLng="-64.83626" SourceID="109"/>
</CompoundMark>
</Course>
<CourseLimit>
<Limit Lat="32.313922" Lon="-64.837168" SeqID="1"/>
<Limit Lat="32.317379" Lon="-64.839291" SeqID="2"/>
<Limit Lat="32.317911" Lon="-64.836996" SeqID="3"/>
<Limit Lat="32.317257" Lon="-64.83626" SeqID="4"/>
<Limit Lat="32.304273" Lon="-64.822834" SeqID="5"/>
<Limit Lat="32.279097" Lon="-64.841545" SeqID="6"/>
<Limit Lat="32.279604" Lon="-64.849871" SeqID="7"/>
<Limit Lat="32.289545" Lon="-64.854162" SeqID="8"/>
<Limit Lat="32.290198" Lon="-64.858711" SeqID="9"/>
<Limit Lat="32.297164" Lon="-64.856394" SeqID="10"/>
<Limit Lat="32.296148" Lon="-64.849184" SeqID="11"/>
</CourseLimit>
</Race>

@ -1,286 +0,0 @@
<race>
<raceId>5326</raceId>
<boats>
<boat>
<name>Team ORACLE USA</name>
<speed>20</speed>
<abbr>USA</abbr>
<sourceID>121</sourceID>
<colour>BLUEVIOLET</colour>
</boat>
<boat>
<name>Land Rover BAR</name>
<speed>30</speed>
<abbr>GBR</abbr>
<sourceID>122</sourceID>
<colour>BLACK</colour>
</boat>
<boat>
<name>SoftBank Team Japan</name>
<speed>25</speed>
<abbr>JPN</abbr>
<sourceID>123</sourceID>
<colour>RED</colour>
</boat>
<boat>
<name>Groupama Team France</name>
<speed>20</speed>
<abbr>FRA</abbr>
<sourceID>124</sourceID>
<colour>ORANGE</colour>
</boat>
<boat>
<name>Artemis Racing</name>
<speed>29</speed>
<abbr>SWE</abbr>
<sourceID>125</sourceID>
<colour>DARKOLIVEGREEN</colour>
</boat>
<boat>
<name>Emirates Team New Zealand</name>
<speed>62</speed>
<abbr>NZL</abbr>
<sourceID>126</sourceID>
<colour>LIMEGREEN</colour>
</boat>
</boats>
<legs>
<leg>
<name>Start to Mark 1</name>
<start>
<marker>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
</coordinate>
<coordinate>
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Mark 1 to Leeward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Leeward Gate to Windward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Windward Gate to Leeward Gate</name>
<start>
<marker>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</finish>
</leg>
<leg>
<name>Leeward Gate to Finish</name>
<start>
<marker>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</start>
<finish>
<marker>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</finish>
</leg>
</legs>
<course>
<boundaries>
<coordinate>
<latitude>32.313922</latitude>
<longitude>-64.837168</longitude>
</coordinate>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317911</latitude>
<longitude>-64.836996</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
<coordinate>
<latitude>32.304273</latitude>
<longitude>-64.822834</longitude>
</coordinate>
<coordinate>
<latitude>32.279097</latitude>
<longitude>-64.841545</longitude>
</coordinate>
<coordinate>
<latitude>32.279604</latitude>
<longitude>-64.849871</longitude>
</coordinate>
<coordinate>
<latitude>32.289545</latitude>
<longitude>-64.854162</longitude>
</coordinate>
<coordinate>
<latitude>32.290198</latitude>
<longitude>-64.858711</longitude>
</coordinate>
<coordinate>
<latitude>32.297164</latitude>
<longitude>-64.856394</longitude>
</coordinate>
<coordinate>
<latitude>32.296148</latitude>
<longitude>-64.849184</longitude>
</coordinate>
</boundaries>
<marker>
<name>Start Line</name>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
</coordinate>
<coordinate>
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
<marker>
<name>Mark</name>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
<marker>
<name>Windward Gate</name>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
<marker>
<name>Leeward Gate</name>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</coordinate>
<coordinate>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
<marker>
<name>Windward Gate</name>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</coordinate>
<coordinate>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
<marker>
<name>Finish Line</name>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</coordinate>
<coordinate>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</course>
</race>

@ -1,87 +0,0 @@
package seng302.Data;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;
import seng302.DataInput.RaceDataSource;
import seng302.DataInput.RaceXMLReader;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import static junit.framework.TestCase.assertTrue;
/**
* Created by esa46 on 25/04/17.
*/
public class BoatDataTest {
private static final String ROOT_TAG = "BoatConfig";
private static final String[] REQUIRED_TAGS = new String[]{
"Boats", "GPSposition"
};
private static final String[] REQUIRED_ATTRIBUTES = new String[]{
"SourceID", "ShapeID", "HullNum", "StoweName",
"ShortName", "BoatName"
};
String result;
RaceDataSource raceDataSource;
@Before
public void initReader() {
try {
raceDataSource = new RaceXMLReader("raceXML/bermuda_AC35.xml");
BoatData boatData = new BoatData(raceDataSource.getBoats());
result = boatData.createXML();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
@Test
public void xmlHasAllNecessaryTags() {
assertTrue(result.contains("<" + ROOT_TAG + ">"));
for (String tag : REQUIRED_TAGS) {
assertTrue(result.contains("<" + tag + ">") || result.contains("<" + tag + " "));
}
}
@Test
public void xmlHasAllNecessaryAttributes() {
for (String attribute : REQUIRED_ATTRIBUTES) {
assertTrue(result.contains(attribute + "="));
}
}
@Test
public void allTagsAreTerminated() {
for (String tag : REQUIRED_TAGS) {
int lastIndex = 0;
String openTag = "<" + tag + ">";
String closeTag = "</" + tag + ">";
while (lastIndex < result.length() && lastIndex > 0) {
lastIndex = result.indexOf(openTag, lastIndex);
if (lastIndex > 0) {
lastIndex = result.indexOf(closeTag, lastIndex);
assertTrue(lastIndex > 0);
}
}
}
}
}

@ -1,83 +0,0 @@
package seng302.Data;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;
import seng302.DataInput.RaceDataSource;
import seng302.DataInput.RaceXMLReader;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import static junit.framework.TestCase.assertTrue;
/**
* Created by esa46 on 25/04/17.
*/
public class RaceDataTest {
private static final String ROOT_TAG = "Race";
private static final String[] REQUIRED_TAGS = new String[]{
"RaceID", "RaceType", "CreationTimeDate", "RaceStartTime", "Participants", "Yacht",
"CompoundMarkSequence", "Course", "CompoundMark", "Mark", "CourseLimit", "Limit"
};
String result;
RaceDataSource raceDataSource;
@Before
public void initReader() {
try {
raceDataSource = new RaceXMLReader("raceXML/bermuda_AC35.xml");
RaceData raceData = new RaceData(raceDataSource);
result = raceData.createXML();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
@Test
public void xmlHasAllNecessaryFields() {
assertTrue(result.contains("<" + ROOT_TAG + ">"));
for (String tag : REQUIRED_TAGS) {
System.out.println(tag);
assertTrue(result.contains("<" + tag + ">") || result.contains("<" + tag + " "));
}
}
@Test
public void allTagsAreTerminated() {
for (String tag : REQUIRED_TAGS) {
int lastIndex = 0;
String openTag = "<" + tag + ">";
String closeTag = "</" + tag + ">";
while (lastIndex < result.length() && lastIndex > 0) {
lastIndex = result.indexOf(openTag, lastIndex);
if (lastIndex > 0) {
lastIndex = result.indexOf(closeTag, lastIndex);
assertTrue(lastIndex > 0);
}
}
}
}
@Test
public void idAndTypeAreEquivalent() {
String newId = result.substring(result.indexOf("<RaceID>") + 8, result.indexOf("</RaceID>"));
String newRaceType = result.substring(result.indexOf("<RaceType>") + 10, result.indexOf("</RaceType>"));
assertTrue(raceDataSource.getRaceId() == Integer.parseInt(newId));
assertTrue(raceDataSource.getRaceType().equals(newRaceType));
}
}

@ -1,74 +0,0 @@
package seng302.Data;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;
import seng302.DataInput.RaceDataSource;
import seng302.DataInput.RaceXMLReader;
import seng302.DataInput.RegattaDataSource;
import seng302.DataInput.RegattaXMLReader;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import static junit.framework.TestCase.assertTrue;
/**
* Created by esa46 on 25/04/17.
*/
public class RegattaDataTest {
private static final String ROOT_TAG = "RegattaConfig";
private static final String[] REQUIRED_TAGS = new String[]{
"RegattaID", "RegattaName", "CourseName", "CentralLatitude", "CentralLongitude",
"CentralAltitude", "UtcOffset", "MagneticVariation"
};
String result;
RegattaDataSource regattaDataSource;
@Before
public void initReader() {
try {
regattaDataSource = new RegattaXMLReader("mockXML/regattaTest.xml");
RegattaData regattaData = new RegattaData(regattaDataSource);
result = regattaData.createXML();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
@Test
public void xmlHasAllNecessaryFields() {
assertTrue(result.contains("<" + ROOT_TAG + ">"));
for (String tag : REQUIRED_TAGS) {
System.out.println(tag);
assertTrue(result.contains("<" + tag + ">") || result.contains("<" + tag + " "));
}
}
@Test
public void allTagsAreTerminated() {
for (String tag : REQUIRED_TAGS) {
int lastIndex = 0;
String openTag = "<" + tag + ">";
String closeTag = "</" + tag + ">";
while (lastIndex < result.length() && lastIndex > 0) {
lastIndex = result.indexOf(openTag, lastIndex);
if (lastIndex > 0) {
lastIndex = result.indexOf(closeTag, lastIndex);
assertTrue(lastIndex > 0);
}
}
}
}
}

@ -0,0 +1,58 @@
package seng302.DataInput;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;
import seng302.Model.Boat;
import seng302.Model.Mark;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.testng.Assert.*;
/**
* Created by cbt24 on 10/05/17.
*/
public class BoatXMLReaderTest {
BoatDataSource boatData;
List<Boat> boats;
List<Mark> marks;
@Before
public void setUp() {
try {
boatData = new BoatXMLReader("mockXML/boatTest.xml");
boats = new ArrayList<>(boatData.getBoats().values());
marks = new ArrayList<>(boatData.getMarkerBoats().values());
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void boatsReadNameFromFile() {
String[] names = {
"Team ORACLE USA","Land Rover BAR","SoftBank Team Japan","Groupama Team France","Artemis Racing","Emirates Team New Zealand"
};
for(int i = 0; i < boats.size(); i++) {
assertEquals(names[i], boats.get(i).getName());
}
}
@Test
public void marksReadNameFromFile() {
String[] names = {
"PRO","PIN","Marker1","WGL","WGR","LGL","LGR","FL","FR"
};
for(int i = 0; i < marks.size(); i++) {
assertEquals(names[i], marks.get(i).getName());
}
}
}

@ -1,51 +0,0 @@
package seng302.DataInput;
import org.junit.Before;
import org.junit.Test;
import seng302.Model.Regatta;
import static org.junit.Assert.*;
/**
* Created by jjg64 on 19/04/17.
*/
public class RegattaXMLTest {
RegattaXMLReader regattaXMLReader;
@Before
public void findFile() {
try {
regattaXMLReader = new RegattaXMLReader("mockXML/regattaTest.xml", false);
} catch (Exception e) {
fail("Cannot find mockXML/regattaXML/regattaTest.xml in the resources folder");
}
}
@Test
public void makeRegattaTest() {
try {
regattaXMLReader = new RegattaXMLReader("mockXML/regattaTest.xml");
assertNotEquals(regattaXMLReader.getRegatta(), null);
} catch (Exception e) {
fail("Did not make a Regatta object");
}
}
@Test
public void correctValuesTest() {
try {
regattaXMLReader = new RegattaXMLReader("mockXML/regattaTest.xml");
Regatta regatta = regattaXMLReader.getRegatta();
assertEquals(regatta.getRegattaID(), 3);
assertEquals(regatta.getRegattaName(), "New Zealand Test");
assertEquals(regatta.getCourseName(), "North Head");
assertEquals(regatta.getCentralLatitude(), -36.82791529, 0.00000001);
assertEquals(regatta.getCentralLongitude(), 174.81218919, 0.00000001);
assertEquals(regatta.getCentralAltitude(), 0.00, 0.00000001);
assertEquals(regatta.getUtcOffset(), 12.0, 0.001);
assertEquals(regatta.getMagneticVariation(), 14.1, 0.001);
} catch (Exception e) {
fail("Did not have the correct values");
}
}
}

@ -13,7 +13,7 @@ public class BoatTest {
private GPSCoordinate ORIGIN_COORDS = new GPSCoordinate(0, 0);
private Boat TEST_BOAT = new Boat("Test", 1, "tt", 1);
private Boat TEST_BOAT = new Boat(1, "Test", "tt");
@Test
public void calculateDueNorthAzimuthReturns0() {

@ -4,11 +4,12 @@ import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static org.testng.AssertJUnit.assertEquals;
/**
* Created by esa46 on 29/03/17.
*/
public class MarkerTest {
public class CompoundMarkTest {
GPSCoordinate ORIGIN_COORD = new GPSCoordinate(0, 0);
@ -29,13 +30,12 @@ public class MarkerTest {
}
@Ignore
@Test
public void averageLatOfTwoMarksIsAccurate() {
GPSCoordinate testCoord = new GPSCoordinate(10, 0);
GPSCoordinate testCoord = new GPSCoordinate(0.001, 0);
Marker testMark = new Marker(ORIGIN_COORD, testCoord);
assertTrue(testMark.getAverageGPSCoordinate().equals(new GPSCoordinate(5, 0)));
assertEquals(testMark.getAverageGPSCoordinate(), new GPSCoordinate(0.0005, 0));
}
@Test
@ -50,10 +50,11 @@ public class MarkerTest {
@Test
public void averageLatAndLongOfTwoMarksIsAccurate() {
GPSCoordinate testCoord1 = new GPSCoordinate(10, 30);
GPSCoordinate testCoord2 = new GPSCoordinate(30, 60);
GPSCoordinate testCoord1 = new GPSCoordinate(0.0, 30);
GPSCoordinate testCoord2 = new GPSCoordinate(0.001, 60);
Marker testMark = new Marker(testCoord1, testCoord2);
assertTrue(testMark.getAverageGPSCoordinate().equals(new GPSCoordinate(020.644102, 44.014817)));
assertEquals(testMark.getAverageGPSCoordinate().getLatitude(), 0.00051776, 1e-8);
assertEquals(testMark.getAverageGPSCoordinate().getLongitude(), 45.000000, 1e-8);
}
}

@ -14,7 +14,7 @@ import static junit.framework.TestCase.assertEquals;
*/
public class LegTest {
private Marker ORIGIN_MARKER = new Marker(new GPSCoordinate(0, 0));
private Marker ORIGIN_Compound_MARKER = new Marker(new GPSCoordinate(0, 0));
@Test
public void calculateDistanceHandles5nmNorth() {
@ -23,7 +23,7 @@ public class LegTest {
calc.setDirection(0, 5 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
Leg test = new Leg("Test", ORIGIN_Compound_MARKER, endMarker, 0);
assertEquals(test.getDistance(), 5, 1e-8);
}
@ -34,7 +34,7 @@ public class LegTest {
calc.setDirection(90, 12 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
Leg test = new Leg("Test", ORIGIN_Compound_MARKER, endMarker, 0);
assertEquals(test.getDistance(), 12, 1e-8);
}
@ -45,7 +45,7 @@ public class LegTest {
calc.setDirection(180, 0.5 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
Leg test = new Leg("Test", ORIGIN_Compound_MARKER, endMarker, 0);
assertEquals(test.getDistance(), 0.5, 1e-8);
}
@ -56,14 +56,14 @@ public class LegTest {
calc.setDirection(-90, 0.1 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
Leg test = new Leg("Test", ORIGIN_Compound_MARKER, endMarker, 0);
assertEquals(test.getDistance(), 0.1, 1e-8);
}
@Test
public void calculateDistanceHandlesZeroDifference() {
Leg test = new Leg("Test", ORIGIN_MARKER, ORIGIN_MARKER, 0);
Leg test = new Leg("Test", ORIGIN_Compound_MARKER, ORIGIN_Compound_MARKER, 0);
assertEquals(test.getDistance(), 0, 1e-8);
}

@ -1,251 +1,300 @@
//package seng302.Model;
//
//import javafx.scene.paint.Color;
//import org.junit.BeforeClass;
//import org.junit.Ignore;
//import org.junit.Test;
//import org.mockito.Mockito;
//import org.xml.sax.SAXException;
//import seng302.DataInput.RaceDataSource;
//import seng302.DataInput.RaceXMLReader;
//import seng302.MockOutput;
//
//import javax.xml.parsers.ParserConfigurationException;
//import java.io.IOException;
//import java.util.ArrayList;
//import java.util.List;
//
//import static org.junit.Assert.assertEquals;
//import static org.junit.Assert.assertTrue;
//import static org.junit.Assert.fail;
//import static org.mockito.Matchers.any;
//import static org.mockito.Mockito.atLeast;
//import static org.mockito.Mockito.verify;
//
///**
// * Created by esa46 on 15/03/17.
// */
//public class RaceTest{
//
// private static MockOutput mockOutput;
// SharedModel.Leg START_LEG = new SharedModel.Leg("Start", new SharedModel.Marker(new SharedModel.GPSCoordinate(0, 0)), new SharedModel.Marker(new SharedModel.GPSCoordinate(1, 1)), 0);
// SharedModel.Leg FINISH_LEG = new SharedModel.Leg("Finish", new SharedModel.Marker(new SharedModel.GPSCoordinate(1, 1)), new SharedModel.Marker(new SharedModel.GPSCoordinate(2, 2)), 0);
//
//// @Override
//// public void start(Stage primaryStage) throws Exception{}
////
//// public static void main(String[] args) {
//// launch(args);
//// }
//
//
//// @BeforeClass
//// public static void initJFX() {
//// Thread t = new Thread("JavaFX Init Thread") {
//// public void run() {
//// Application.launch(TestApp.class, new String[0]);
//// }
//// };
//// t.setDaemon(true);
//// t.start();
//// }
//
// @BeforeClass
// public static void setUp() {
// try {
// mockOutput = new MockOutput();
// } catch(IOException e) {
// fail();
// }
// }
//
// @Ignore
// @Test
// public void boatLocationMessagesAreGenerated() {
// try {
// RaceDataSource raceDataSource = new RaceXMLReader("raceXML/bermuda_AC35.xml");
//
// MockOutput mockOutput = Mockito.mock(MockOutput.class);
// Race race = new Race(raceDataSource, 100, mockOutput);
// new Thread((race)).start();
//
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// fail();
// }
// verify(mockOutput, atLeast(400)).parseBoatLocation(any());
//
// } catch (IOException e) {
// fail();
// } catch (SAXException e) {
// fail();
// } catch (ParserConfigurationException e) {
// fail();
// }
// }
//
// @Test
// public void timerCanBeDisabled() {
// SharedModel.BoatInRace boat1 = new SharedModel.BoatInRace("Test 1", 10000, Color.ALICEBLUE, "t1", 1);
// SharedModel.BoatInRace boat2 = new SharedModel.BoatInRace("Test 2", 10000, Color.BURLYWOOD, "t2", 2);
// List<SharedModel.BoatInRace> boats = new ArrayList<>();
// boats.add(boat1);
// boats.add(boat2);
//
// ArrayList<SharedModel.Leg> legs = new ArrayList<>();
// legs.add(START_LEG);
// legs.add(FINISH_LEG);
//
//
// Race race = new Race(boats, legs, 5, mockOutput);
// race.setDnfChance(0);
// long timeStarted = System.currentTimeMillis();
// race.run();
// assertTrue(System.currentTimeMillis() - timeStarted < 4000);
// }
//
// @Test
// public void checkPositionUpdatesNumberFinishedBoats() {
//
// SharedModel.BoatInRace finishedBoat = new SharedModel.BoatInRace("Test", 1000, Color.ALICEBLUE, "tt", 1);
// finishedBoat.setDistanceTravelledInLeg(500);
//
// finishedBoat.setCurrentLeg(FINISH_LEG);
//
// ArrayList<SharedModel.BoatInRace> boats = new ArrayList<>();
// boats.add(finishedBoat);
//
// ArrayList<SharedModel.Leg> legs = new ArrayList<>();
// legs.add(FINISH_LEG);
//
// Race race = new Race(boats, legs, 5, mockOutput);
// race.setDnfChance(0);
// assertEquals(race.boatsFinished, 0);
//
// race.checkPosition(finishedBoat, 100000);
// assertEquals(race.boatsFinished, 1);
// assertEquals(finishedBoat.getTimeFinished(), 100000);
//
// }
//
// @Test
// public void checkPositionDoesntUpdateNumberFinishedBoats() {
//
// SharedModel.BoatInRace unFinishedBoat = new SharedModel.BoatInRace("Test", 10, Color.ALICEBLUE, "tt", 1);
// unFinishedBoat.setDistanceTravelledInLeg(0);
//
// unFinishedBoat.setCurrentLeg(FINISH_LEG);
//
// ArrayList<SharedModel.BoatInRace> boats = new ArrayList<>();
// boats.add(unFinishedBoat);
//
// ArrayList<SharedModel.Leg> legs = new ArrayList<>();
// legs.add(FINISH_LEG);
//
//
// Race race = new Race(boats, legs, 1, mockOutput);
// race.setDnfChance(0);
// assertEquals(race.boatsFinished, 0);
// race.checkPosition(unFinishedBoat, 100);
// assertEquals(race.boatsFinished, 0);
//
// }
//
// @Test
// public void distanceTravelledBeforeUpdatingLegIsRetained() {
//
// ArrayList<SharedModel.BoatInRace> boats = new ArrayList<>();
//
// ArrayList<SharedModel.Leg> legs = new ArrayList<>();
//
// legs.add(START_LEG);
// legs.add(FINISH_LEG);
//
// Race race = new Race(boats, legs, 1, mockOutput);
// race.setDnfChance(0);
//
// SharedModel.BoatInRace unFinishedBoat = new SharedModel.BoatInRace("Test", 10, Color.ALICEBLUE, "tt", 4);
// unFinishedBoat.setDistanceTravelledInLeg(100);
// unFinishedBoat.setCurrentLeg(START_LEG);
//
// race.checkPosition(unFinishedBoat, 100);
// assertEquals(unFinishedBoat.getCurrentLeg().getName(), "Finish");
// assertTrue(unFinishedBoat.getDistanceTravelledInLeg() > 0);
// assertTrue(unFinishedBoat.getDistanceTravelledInLeg() < 100);
// }
//
// @Ignore
// @Test
// public void timerDelaysByHalfSecond() throws InterruptedException {
//
// ArrayList<SharedModel.BoatInRace> boats = new ArrayList<>();
//
// ArrayList<SharedModel.Leg> legs = new ArrayList<>();
// legs.add(START_LEG);
//
// Race race = new Race(boats, legs, 1, mockOutput);
// race.PRERACE_TIME = 500;
// race.runRace = false;
//
// race.countdownTimer();
//
// long timeStarted = System.currentTimeMillis();
// long currentTime = System.currentTimeMillis();
// while (!race.countdownFinish) {
// currentTime = System.currentTimeMillis();
// }
//
// assertTrue(currentTime - timeStarted > 500);
// }
//
// @Test
// public void scalerScalesVelocityCorrectly() {
//
// int scaleFactor = 3;
// float vel1 = 0;
// float vel2 = (float) 1.999;
// float vel3 = (float) 32.5;
// float vel4 = 500;
// SharedModel.BoatInRace boat1 = new SharedModel.BoatInRace("test", vel1, Color.ALICEBLUE, "tt",1);
// SharedModel.BoatInRace boat2 = new SharedModel.BoatInRace("test", vel2, Color.ALICEBLUE, "tt", 2);
// SharedModel.BoatInRace boat3 = new SharedModel.BoatInRace("test", vel3, Color.ALICEBLUE, "tt", 3);
// SharedModel.BoatInRace boat4 = new SharedModel.BoatInRace("test", vel4, Color.ALICEBLUE, "tt", 4);
// ArrayList<SharedModel.BoatInRace> boats = new ArrayList<>();
// boats.add(boat1);
// boats.add(boat2);
// boats.add(boat3);
// boats.add(boat4);
//
// ArrayList<SharedModel.Leg> legs = new ArrayList<>();
// legs.add(START_LEG);
//
//
// Race race = new Race(boats, legs, scaleFactor, mockOutput);
// race.setDnfChance(0);
//
// assertEquals(race.getStartingBoats().get(0).getScaledVelocity(), vel1 * scaleFactor, 1e-6);
// assertEquals(race.getStartingBoats().get(1).getScaledVelocity(), vel2 * scaleFactor, 1e-6);
// assertEquals(race.getStartingBoats().get(2).getScaledVelocity(), vel3 * scaleFactor, 1e-6);
// assertEquals(race.getStartingBoats().get(3).getScaledVelocity(), vel4 * scaleFactor, 1e-6);
//
// }
// @Test
// public void doNotFinishCorrectly() {
// ArrayList<SharedModel.BoatInRace> boats = new ArrayList<>();
//
// ArrayList<SharedModel.Leg> legs = new ArrayList<>();
// legs.add(START_LEG);
//
// Race race = new Race(boats, legs, 1, mockOutput);
//
// race.setDnfChance(100);
// assertTrue(race.doNotFinish());
//
// race.setDnfChance(0);
// assertTrue(!race.doNotFinish());
// }
//
//
//
//}
package seng302.Model;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import org.xml.sax.SAXException;
import seng302.DataInput.BoatDataSource;
import seng302.DataInput.BoatXMLReader;
import seng302.DataInput.RaceDataSource;
import seng302.DataInput.RaceXMLReader;
import seng302.Exceptions.StreamedCourseXMLException;
import seng302.MockOutput;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
/**
* Created by esa46 on 15/03/17.
*/
public class RaceTest{
public static final Marker ORIGIN = new Marker(new GPSCoordinate(0, 0));
public static final Marker THREE_NM_FROM_ORIGIN = new Marker(new GPSCoordinate(0.050246769, 0));
public static final Marker FIFTEEN_NM_FROM_ORIGIN = new Marker(new GPSCoordinate(0.251233845, 0));
public static ArrayList<Leg> TEST_LEGS = new ArrayList<>();
public static final int START_LEG_DISTANCE = 3;
public static final int MIDDLE_LEG_DISTANCE = 12;
public static final Leg START_LEG = new Leg("Start", ORIGIN, THREE_NM_FROM_ORIGIN, 0);
public static final Leg MIDDLE_LEG = new Leg("Middle", THREE_NM_FROM_ORIGIN, FIFTEEN_NM_FROM_ORIGIN, 1);
public static final Leg FINISH_LEG = new Leg("Finish", FIFTEEN_NM_FROM_ORIGIN, FIFTEEN_NM_FROM_ORIGIN, 2);
@Before
public void setUp() {
TEST_LEGS.add(START_LEG);
TEST_LEGS.add(MIDDLE_LEG);
TEST_LEGS.add(FINISH_LEG);
}
@Ignore
@Test
public void countdownTimerSendsBoatLocations() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml");
RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource);
Race testRace = new Race(raceDataSource, mockOutput);
testRace.initialiseBoats();
testRace.countdownTimer.handle(1);
verify(mockOutput, atLeast(boatDataSource.getBoats().size())).parseBoatLocation(anyInt(), anyDouble(), anyDouble(), anyDouble(), anyDouble());
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void countdownTimerSendsRaceStatusMessages() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml"));
Race testRace = new Race(dataSource, mockOutput);
testRace.initialiseBoats();
testRace.countdownTimer.handle(1);
verify(mockOutput, atLeast(1)).parseRaceStatus(any());
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void checkPositionFinishedUpdatesNumberFinishedBoats() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml"));
Race testRace = new Race(dataSource, mockOutput);
testRace.initialiseBoats();
Boat testBoat = testRace.startingBoats.get(0);
testBoat.setCurrentLeg(FINISH_LEG);
testBoat.setDistanceTravelledInLeg(1);
testRace.checkPosition(testBoat, 1);
assertEquals(testRace.boatsFinished, 1);
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void checkPositionSetFinishedBoatVelocityTo0() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml"));
Race testRace = new Race(dataSource, mockOutput);
testRace.initialiseBoats();
Boat testBoat = testRace.startingBoats.get(0);
testBoat.setCurrentLeg(FINISH_LEG);
testBoat.setDistanceTravelledInLeg(1);
testRace.checkPosition(testBoat, 1);
assertEquals(testBoat.getVelocity(), 0, 1e-8);
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void checkPositionSetsFinishTime() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml"));
Race testRace = new Race(dataSource, mockOutput);
testRace.initialiseBoats();
Boat testBoat = testRace.startingBoats.get(0);
testBoat.setCurrentLeg(FINISH_LEG);
testBoat.setDistanceTravelledInLeg(1);
testRace.checkPosition(testBoat, 1);
assertEquals(testBoat.getTimeFinished(), 1, 1e-8);
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void checkPositionUnfinishedDoesntUpdateNumberFinishedBoats() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml"));
Race testRace = new Race(dataSource, mockOutput);
testRace.initialiseBoats();
Boat testBoat = testRace.startingBoats.get(0);
testBoat.setCurrentLeg(START_LEG);
testBoat.setDistanceTravelledInLeg(START_LEG_DISTANCE);
testRace.checkPosition(testBoat, 1);
assertEquals(testRace.boatsFinished, 0);
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void distanceTravelledBeforeUpdatingLegIsRetained() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
RaceDataSource dataSource = new RaceXMLReader("mockXML/raceTest.xml", new BoatXMLReader("mockXML/boatTest.xml"));
Race testRace = new Race(dataSource, mockOutput);
testRace.initialiseBoats();
Boat testBoat = testRace.startingBoats.get(0);
testBoat.setCurrentLeg(START_LEG);
testBoat.setDistanceTravelledInLeg(START_LEG_DISTANCE + 1);
testRace.checkPosition(testBoat, 0);
assertEquals(testBoat.getDistanceTravelledInLeg(), 1, 1e-7);
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void doNotFinishAnswersYesIf100PercentChance() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml");
RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource);
Race testRace = new Race(raceDataSource, mockOutput);
testRace.setDnfChance(100);
assertTrue(testRace.doNotFinish());
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void doNotFinishAnswersNoIf0PercentChance() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml");
RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource);
Race testRace = new Race(raceDataSource, mockOutput);
testRace.setDnfChance(0);
assertFalse(testRace.doNotFinish());
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void boatsAreSetToDNF() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml");
RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource);
Race testRace = new Race(raceDataSource, mockOutput);
testRace.setDnfChance(100);
Boat testBoat = testRace.startingBoats.get(0);
testBoat.setCurrentLeg(START_LEG);
testBoat.setDistanceTravelledInLeg(START_LEG_DISTANCE + 1);
testRace.checkPosition(testBoat, 1);
assertEquals(testBoat.getCurrentLeg().getName(), "DNF");
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void updatePositionIgnoresFinishedBoats() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml");
RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource);
Race testRace = new Race(raceDataSource, mockOutput);
Boat testBoat = testRace.startingBoats.get(0);
testBoat.setCurrentLeg(FINISH_LEG);
testBoat.setCurrentPosition(ORIGIN.getAverageGPSCoordinate());
testRace.updatePosition(testBoat, 1);
assertEquals(testBoat.getCurrentPosition(), ORIGIN.getAverageGPSCoordinate());
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
@Ignore
@Test
public void updatePositionChangesBoatPosition() {
try {
MockOutput mockOutput = Mockito.mock(MockOutput.class);
BoatDataSource boatDataSource = new BoatXMLReader("mockXML/boatTest.xml");
RaceDataSource raceDataSource = new RaceXMLReader("mockXML/raceTest.xml", boatDataSource);
Race testRace = new Race(raceDataSource, mockOutput);
testRace.initialiseBoats();
Boat testBoat = testRace.startingBoats.get(0);
testBoat.setCurrentLeg(START_LEG);
testBoat.setDistanceTravelledInLeg(START_LEG_DISTANCE - 1);
testBoat.setCurrentPosition(ORIGIN.getAverageGPSCoordinate());
testRace.updatePosition(testBoat, 100);
assertFalse(testBoat.getCurrentPosition() == ORIGIN.getAverageGPSCoordinate());
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
e.printStackTrace();
fail();
}
}
}

@ -1,96 +0,0 @@
package seng302.Model;/**
* Created by Gondr on 26/03/2017.
*/
import org.junit.Ignore;
import org.junit.Test;
import seng302.DataInput.RaceXMLReader;
import java.util.List;
import static org.junit.Assert.*;
public class RaceXMLTest {
RaceXMLReader raceXMLReader;
@Test
public void canFindFile() {
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
} catch (Exception e) {
fail("Cannot find raceXML/bermuda_AC35.xml in the resources folder");
}
}
@Ignore
@Test
public void canReadBoats() {
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readBoats();
List<Boat> boats = raceXMLReader.getBoats();
assertTrue(boats.size() == 6);
//test boat 1
assertEquals(boats.get(0).getName(), "ORACLE TEAM USA");
assertTrue(boats.get(0).getVelocity() == 20);
//test boat 2
assertEquals(boats.get(1).getName(), "Land Rover BAR");
assertTrue(boats.get(1).getVelocity() == 30);
assertEquals(boats.get(1).getAbbrev(), "GBR");
//test boat 3
assertEquals(boats.get(2).getName(), "SoftBank Team Japan");
assertTrue(boats.get(2).getVelocity() == 25);
assertEquals(boats.get(2).getAbbrev(), "JPN");
//test boat 4
assertEquals(boats.get(3).getName(), "Groupama Team France");
assertTrue(boats.get(3).getVelocity() == 20);
assertEquals(boats.get(3).getAbbrev(), "FRA");
//test boat 5
assertEquals(boats.get(4).getName(), "Artemis Racing");
assertTrue(boats.get(4).getVelocity() == 29);
assertEquals(boats.get(4).getAbbrev(), "SWE");
//test boat 6
assertEquals(boats.get(5).getName(), "Emirates Team New Zealand");
assertTrue(boats.get(5).getVelocity() == 62);
assertEquals(boats.get(5).getAbbrev(), "NZL");
} catch (Exception e) {
fail("Boat Unreadable");
}
}
@Test
public void canReadLegs() {
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readLegs();
assertTrue(raceXMLReader.getLegs().size() == 5);
} catch (Exception e) {
fail("Legs Unreadable");
}
}
@Test
public void canReadCourse() {
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readCourse();
assertTrue(raceXMLReader.getMapTopLeft() != null);
assertTrue(raceXMLReader.getMapBottomRight() != null);
assertTrue(raceXMLReader.getFinishPt1() != null);
assertTrue(raceXMLReader.getFinishPt2() != null);
assertTrue(raceXMLReader.getStartPt1() != null);
assertTrue(raceXMLReader.getStartPt2() != null);
assertTrue(raceXMLReader.getLeewardPt1() != null);
assertTrue(raceXMLReader.getLeewardPt2() != null);
assertTrue(raceXMLReader.getWindwardPt1() != null);
assertTrue(raceXMLReader.getWindwardPt2() != null);
assertTrue(raceXMLReader.getMark() != null);
assertTrue(raceXMLReader.getBoundary().size() == 11);
} catch (Exception e) {
e.printStackTrace();
fail("Course Unreadable");
}
}
}

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<BoatConfig>
<Boats>
<!--Mark Boats-->
<Boat Type="Mark" BoatName="PRO" SourceID="101" >
<GPSposition X= "-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="PIN" SourceID="102" >
<GPSposition X= "-64.855242" Y="32.293771" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="Marker1" SourceID="103" >
<GPSposition X= "-64.843983" Y="32.293039" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="WGL" SourceID="104" >
<GPSposition X= "-64.850045" Y="32.28468" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="WGR" SourceID="105" >
<GPSposition X= "-64.847591" Y="32.280164" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="LGL" SourceID="106" >
<GPSposition X= "-64.835249" Y="32.309693" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="LGR" SourceID="107" >
<GPSposition X= "-64.831785" Y="32.308046" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="FL" SourceID="108" >
<GPSposition X= "-64.839291" Y="32.317379" Z="0"/>
</Boat>
<Boat Type="Mark" BoatName="FR" SourceID="109" >
<GPSposition X= "-64.83626" Y="32.317257" Z="0"/>
</Boat>
<!--Participants-->
<Boat BoatName="Team ORACLE USA" HullNum="RG01" ShapeID="0" ShortName="USA" SourceID="121" StoweName="USA" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="Land Rover BAR" HullNum="RG01" ShapeID="0" ShortName="GBR" SourceID="122" StoweName="GBR" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="SoftBank Team Japan" HullNum="RG01" ShapeID="0" ShortName="JPN" SourceID="123" StoweName="JPN" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="Groupama Team France" HullNum="RG01" ShapeID="0" ShortName="FRA" SourceID="124" StoweName="FRA" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="Artemis Racing" HullNum="RG01" ShapeID="0" ShortName="SWE" SourceID="125" StoweName="SWE" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
<Boat BoatName="Emirates Team New Zealand" HullNum="RG01" ShapeID="0" ShortName="NZL" SourceID="126" StoweName="NZL" Type="Yacht">
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
</Boat>
</Boats>
</BoatConfig>

@ -1,251 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<BoatConfig>
<Modified>2012-05-17T07:49:40+0200</Modified>
<Version>12</Version>
<Settings>
<RaceBoatType Type="AC45"/>
<BoatDimension BoatLength="14.019" HullLength="13.449"/>
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="40.347"/>
<ZoneLimits Limit1="200" Limit2="100" Limit3="40.347" Limit4="0" Limit5="-100"/>
</Settings>
<BoatShapes>
<BoatShape ShapeID="0">
<Vertices>
<Vtx Seq="1" Y="0" X="-2.659"/>
<Vtx Seq="2" Y="18.359" X="-2.659"/>
<Vtx Seq="3" Y="18.359" X="2.659"/>
<Vtx Seq="4" Y="0" X="2.659"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="1">
<Vertices>
<Vtx Seq="1" Y="0" X="-1.278"/>
<Vtx Seq="2" Y="8.876" X="-1.278"/>
<Vtx Seq="3" Y="8.876" X="1.278"/>
<Vtx Seq="4" Y="0" X="1.278"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="2">
<Vertices>
<Vtx Seq="1" Y="0" X="-1.1"/>
<Vtx Seq="2" Y="8.3" X="-1.1"/>
<Vtx Seq="3" Y="8.3" X="1.1"/>
<Vtx Seq="4" Y="0" X="1.1"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="3">
<Vertices>
<Vtx Seq="1" Y="0" X="-0.75"/>
<Vtx Seq="2" Y="3" X="-0.75"/>
<Vtx Seq="3" Y="3" X="0.75"/>
<Vtx Seq="4" Y="0" X="0.75"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="4">
<Vertices>
<Vtx Seq="1" Y="0" X="-3.46"/>
<Vtx Seq="2" Y="13.449" X="-3.46"/>
<Vtx Seq="3" Y="14.019" X="0"/>
<Vtx Seq="4" Y="13.449" X="3.46"/>
<Vtx Seq="5" Y="0" X="3.46"/>
</Vertices>
<Catamaran>
<Vtx Seq="1" Y="1.769" X="-2.752"/>
<Vtx Seq="2" Y="0" X="-2.813"/>
<Vtx Seq="3" Y="0" X="-3.34"/>
<Vtx Seq="4" Y="5.351" X="-3.46"/>
<Vtx Seq="5" Y="10.544" X="-3.387"/>
<Vtx Seq="6" Y="13.449" X="-3.075"/>
<Vtx Seq="7" Y="10.851" X="-2.793"/>
<Vtx Seq="8" Y="6.669" X="-2.699"/>
<Vtx Seq="9" Y="6.669" X="2.699"/>
<Vtx Seq="10" Y="10.851" X="2.793"/>
<Vtx Seq="11" Y="13.449" X="3.075"/>
<Vtx Seq="12" Y="10.544" X="3.387"/>
<Vtx Seq="13" Y="5.351" X="3.46"/>
<Vtx Seq="14" Y="0" X="3.34"/>
<Vtx Seq="15" Y="0" X="2.813"/>
<Vtx Seq="16" Y="1.769" X="2.752"/>
</Catamaran>
<Bowsprit>
<Vtx Seq="1" Y="6.669" X="-0.2"/>
<Vtx Seq="2" Y="11.377" X="-0.2"/>
<Vtx Seq="3" Y="14.019" X="0"/>
<Vtx Seq="4" Y="11.377" X="0.2"/>
<Vtx Seq="5" Y="6.669" X="0.2"/>
</Bowsprit>
<Trampoline>
<Vtx Seq="1" Y="2" X="-2.699"/>
<Vtx Seq="2" Y="6.438" X="-2.699"/>
<Vtx Seq="3" Y="6.438" X="2.699"/>
<Vtx Seq="4" Y="2" X="2.699"/>
</Trampoline>
</BoatShape>
<BoatShape ShapeID="5"/>
</BoatShapes>
<Boats>
<Boat Type="RC" SourceID="121" ShapeID="0" HullNum="RG01" StoweName="PRO" ShortName="PRO"
BoatName="Regardless">
<GPSposition Z="6.840" Y="7.800" X="0.000"/>
<FlagPosition Z="0.000" Y="7.800" X="0.000"/>
</Boat>
<Boat Type="Mark" SourceID="122" ShapeID="1" HullNum="LC05" StoweName="CON" ShortName="Constellation"
BoatName="Constellation">
<GPSposition Z="5.334" Y="3.804" X="0.000"/>
<FlagPosition Z="0.000" Y="3.426" X="0.000"/>
</Boat>
<Boat Type="Mark" SourceID="123" ShapeID="1" HullNum="LC04" StoweName="MIS" ShortName="Mischief"
BoatName="Mischief">
<GPSposition Z="5.334" Y="3.804" X="0.000"/>
<FlagPosition Z="0.000" Y="3.426" X="0.000"/>
</Boat>
<Boat Type="Mark" SourceID="124" ShapeID="1" HullNum="LC03" ShortName="Atalanta" BoatName="Atalanta">
<GPSposition Z="5.334" Y="3.804" X="0.000"/>
<FlagPosition Z="0.000" Y="3.426" X="0.000"/>
</Boat>
<Boat SourceID="125" ShapeID="1" StoweName="VOL" HullNum="LC01" ShortName="Volunteer"
BoatName="Volunteer">
<GPSposition Z="5.334" Y="3.804" X="0.000"/>
<FlagPosition Z="0.000" Y="3.426" X="0.000"/>
</Boat>
<Boat Type="Mark" SourceID="126" ShapeID="1" HullNum="LC13" StoweName="MS2" ShortName="Defender"
BoatName="Defender">
<GPSposition Z="5.334" Y="3.804" X="0.000"/>
<FlagPosition Z="0.000" Y="3.426" X="0.000"/>
</Boat>
<Boat Type="Mark" SourceID="128" ShapeID="1" HullNum="LC01" ShortName="Shamrock" BoatName="Shamrock">
<GPSposition Z="5.334" Y="3.804" X="0.000"/>
<FlagPosition Z="0.000" Y="3.426" X="0.000"/>
</Boat>
<Boat Type="Yacht" SourceID="101" ShapeID="4" HullNum="AC4501" StoweName="KOR" ShortName="TEAM KOREA"
BoatName="TEAM KOREA" Country="KOR">
<GPSposition Z="1.738" Y="0.625" X="0.001"/>
<MastTop Z="21.496" Y="4.233" X="0.000"/>
</Boat>
</Boats>
</BoatConfig>

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Race>
<RaceID>5326</RaceID>
<RaceType>FLEET</RaceType>
<CreationTimeDate>2017-04-19T15:30:00+1200</CreationTimeDate>
<RaceStartTime Postpone="false" Time="2017-04-19T15:33:00+1200"/>
<Participants>
<Yacht SourceID="121"/>
<Yacht SourceID="122"/>
<Yacht SourceID="123"/>
<Yacht SourceID="124"/>
<Yacht SourceID="125"/>
<Yacht SourceID="126"/>
</Participants>
<CompoundMarkSequence>
<Corner CompoundMarkID="1" SeqID="1"/>
<Corner CompoundMarkID="2" SeqID="2"/>
<Corner CompoundMarkID="4" SeqID="3"/>
<Corner CompoundMarkID="3" SeqID="4"/>
<Corner CompoundMarkID="4" SeqID="5"/>
<Corner CompoundMarkID="5" SeqID="6"/>
</CompoundMarkSequence>
<Course>
<CompoundMark CompoundMarkID="1" Name="Start Line">
<Mark SeqId="1" Name="PRO" TargetLat="32.296577" TargetLng="-64.854304" SourceID="101"/>
<Mark SeqId="2" Name="PIN" TargetLat="32.293771" TargetLng="-64.855242" SourceID="102"/>
</CompoundMark>
<CompoundMark CompoundMarkID="2" Name="Marker 1">
<Mark Name="Marker1" TargetLat="32.293039" TargetLng="-64.843983" SourceID="103"/>
</CompoundMark>
<CompoundMark CompoundMarkID="3" Name="Windward Gate">
<Mark Name="WGL" SeqId="1" TargetLat="32.28468" TargetLng="-64.850045" SourceID="104"/>
<Mark Name="WGR" SeqId="2" TargetLat="32.280164" TargetLng="-64.847591" SourceID="105"/>
</CompoundMark>
<CompoundMark CompoundMarkID="4" Name="Leeward Gate">
<Mark Name="LGL" SeqId="1" TargetLat="32.309693" TargetLng="-64.835249" SourceID="106"/>
<Mark Name="LGR" SeqId="2" TargetLat="32.308046" TargetLng="-64.831785" SourceID="107"/>
</CompoundMark>
<CompoundMark CompoundMarkID="5" Name="Finish Line">
<Mark Name="FL" SeqId="1" TargetLat="32.317379" TargetLng="-64.839291" SourceID="108"/>
<Mark Name="FR" SeqId="2" TargetLat="32.317257" TargetLng="-64.83626" SourceID="109"/>
</CompoundMark>
</Course>
<CourseLimit>
<Limit Lat="32.313922" Lon="-64.837168" SeqID="1"/>
<Limit Lat="32.317379" Lon="-64.839291" SeqID="2"/>
<Limit Lat="32.317911" Lon="-64.836996" SeqID="3"/>
<Limit Lat="32.317257" Lon="-64.83626" SeqID="4"/>
<Limit Lat="32.304273" Lon="-64.822834" SeqID="5"/>
<Limit Lat="32.279097" Lon="-64.841545" SeqID="6"/>
<Limit Lat="32.279604" Lon="-64.849871" SeqID="7"/>
<Limit Lat="32.289545" Lon="-64.854162" SeqID="8"/>
<Limit Lat="32.290198" Lon="-64.858711" SeqID="9"/>
<Limit Lat="32.297164" Lon="-64.856394" SeqID="10"/>
<Limit Lat="32.296148" Lon="-64.849184" SeqID="11"/>
</CourseLimit>
</Race>

@ -1,20 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<RegattaConfig>
<RegattaID>3</RegattaID>
<RegattaName>New Zealand Test</RegattaName>
<CourseName>North Head</CourseName>
<CentralLatitude>-36.82791529</CentralLatitude>
<CentralLongitude>174.81218919</CentralLongitude>
<CentralAltitude>0.00</CentralAltitude>
<UtcOffset>12</UtcOffset>
<MagneticVariation>14.1</MagneticVariation>
</RegattaConfig>

@ -48,7 +48,7 @@
<leg>
<name>Start to Mark 1</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
@ -57,29 +57,29 @@
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Mark 1 to Leeward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -88,13 +88,13 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Leeward Gate to Windward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -103,10 +103,10 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
@ -115,13 +115,13 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Windward Gate to Leeward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
@ -130,10 +130,10 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -142,13 +142,13 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Leeward Gate to Finish</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -157,10 +157,10 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
@ -169,7 +169,7 @@
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
</legs>
@ -220,7 +220,7 @@
<longitude>-64.849184</longitude>
</coordinate>
</boundaries>
<marker>
<compoundMark>
<name>Start Line</name>
<coordinate>
<latitude>32.296577</latitude>
@ -230,15 +230,15 @@
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Mark</name>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Windward Gate</name>
<coordinate>
<latitude>32.284680</latitude>
@ -248,8 +248,8 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Leeward Gate</name>
<coordinate>
<latitude>32.309693</latitude>
@ -259,8 +259,8 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Finish Line</name>
<coordinate>
<latitude>32.317379</latitude>
@ -270,6 +270,6 @@
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</compoundMark>
</course>
</race>

@ -148,7 +148,7 @@ public class BinaryMessageDecoder {
case DISPLAYTEXTMESSAGE:
//System.out.println("Display Text Message");
//No decoder for this.
throw new InvalidMessageException("Cannot decode DISPLAYTEXTMESSAGE - no decoder.");
//throw new InvalidMessageException("Cannot decode DISPLAYTEXTMESSAGE - no decoder.");
case XMLMESSAGE:
//System.out.println("XML Message!");
@ -164,17 +164,17 @@ public class BinaryMessageDecoder {
case YACHTEVENTCODE:
//System.out.println("Yacht Action Code!");
//No decoder for this.
throw new InvalidMessageException("Cannot decode YACHTEVENTCODE - no decoder.");
//throw new InvalidMessageException("Cannot decode YACHTEVENTCODE - no decoder.");
case YACHTACTIONCODE:
//System.out.println("Yacht Action Code!");
//No decoder for this.
throw new InvalidMessageException("Cannot decode YACHTACTIONCODE - no decoder.");
//throw new InvalidMessageException("Cannot decode YACHTACTIONCODE - no decoder.");
case CHATTERTEXT:
//System.out.println("Chatter Text Message!");
//No decoder for this.
throw new InvalidMessageException("Cannot decode CHATTERTEXT - no decoder.");
//throw new InvalidMessageException("Cannot decode CHATTERTEXT - no decoder.");
case BOATLOCATION:
//System.out.println("Boat Location Message!");
@ -198,10 +198,10 @@ public class BinaryMessageDecoder {
default:
//System.out.println("Broken Message!");
throw new InvalidMessageException("Broken message! Did not recognise message type: " + headerMessageType + ".");
//throw new InvalidMessageException("Broken message! Did not recognise message type: " + headerMessageType + ".");
return null;
}
}

@ -36,32 +36,85 @@ public class BoatLocationDecoder {
private BoatLocation message;
public BoatLocationDecoder(byte[] encodedBoatLocation) {
byte numMessageVersionNumber = 0;
long numTime = 0;
int numSourceID = 0;
int numSeqNum = 0;
byte numDeviceType = 0;
int numLatitude = 0;
int numLongitude = 0;
int numAltitude = 0;
int numHeading = 0;
short numPitch = 0;
short numRoll = 0;
int numBoatSpeed = 0;
int numCog = 0;
int numSog = 0;
int numApparentWindSpeed = 0;
short numApparentWindAngle = 0;
int numTrueWindSpeed = 0;
short numTrueWindDirection = 0;
short numTrueWindAngle = 0;
int numCurrentDrift = 0;
int numCurrentSet = 0;
short numRudderAngle = 0;
try {
messageVersionNumber = encodedBoatLocation[0];
numMessageVersionNumber = messageVersionNumber;
time = Arrays.copyOfRange(encodedBoatLocation, 1, 7);
numTime = bytesToLong(time);
sourceID = Arrays.copyOfRange(encodedBoatLocation, 7, 11);
numSourceID = bytesToInt(sourceID);
seqNum = Arrays.copyOfRange(encodedBoatLocation, 11, 15);
numSeqNum = bytesToInt(seqNum);
deviceType = encodedBoatLocation[15];
numDeviceType = deviceType;
latitude = Arrays.copyOfRange(encodedBoatLocation, 16, 20);
numLatitude = bytesToInt(latitude);
longitude = Arrays.copyOfRange(encodedBoatLocation, 20, 24);
numLongitude = bytesToInt(longitude);
altitude = Arrays.copyOfRange(encodedBoatLocation, 24, 28);
numAltitude = bytesToInt(altitude);
heading = Arrays.copyOfRange(encodedBoatLocation, 28, 30);
numHeading = bytesToInt(heading);
pitch = Arrays.copyOfRange(encodedBoatLocation, 30, 32);
numPitch = bytesToShort(pitch);
roll = Arrays.copyOfRange(encodedBoatLocation, 32, 34);
numRoll = bytesToShort(roll);
boatSpeed = Arrays.copyOfRange(encodedBoatLocation, 34, 36);
numBoatSpeed = bytesToInt(boatSpeed);
cog = Arrays.copyOfRange(encodedBoatLocation, 36, 38);
numCog = bytesToInt(cog);
sog = Arrays.copyOfRange(encodedBoatLocation, 38, 40);
numSog = bytesToInt(sog);
apparentWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 40, 42);
numApparentWindSpeed = bytesToInt(apparentWindSpeed);
apparentWindAngle = Arrays.copyOfRange(encodedBoatLocation, 42, 44);
numApparentWindAngle = bytesToShort(apparentWindAngle);
trueWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 44, 46);
numTrueWindSpeed = bytesToInt(trueWindSpeed);
trueWindDirection = Arrays.copyOfRange(encodedBoatLocation, 46, 48);
numTrueWindDirection = bytesToShort(trueWindDirection);
trueWindAngle = Arrays.copyOfRange(encodedBoatLocation, 48, 50);
numTrueWindAngle = bytesToShort(trueWindAngle);
currentDrift = Arrays.copyOfRange(encodedBoatLocation, 50, 52);
numCurrentDrift = bytesToInt(currentDrift);
currentSet = Arrays.copyOfRange(encodedBoatLocation, 52, 54);
numCurrentSet = bytesToShort(currentSet);
rudderAngle = Arrays.copyOfRange(encodedBoatLocation, 54, 56);
numRudderAngle = bytesToShort(rudderAngle);
} catch(ArrayIndexOutOfBoundsException e){
// System.out.println(bytesToInt(sourceID));
// System.out.println(bytesToInt(boatSpeed));
}
message = new BoatLocation(numMessageVersionNumber, numTime,
numSourceID, numSeqNum, numDeviceType, numLatitude,
numLongitude, numAltitude, numHeading, numPitch,
numRoll, numBoatSpeed, numCog, numSog, numApparentWindSpeed,
numApparentWindAngle, numTrueWindSpeed, numTrueWindDirection,
numTrueWindAngle, numCurrentDrift, numCurrentSet, numRudderAngle
);/*
message = new BoatLocation(messageVersionNumber, bytesToLong(time),
bytesToInt(sourceID), bytesToInt(seqNum),
deviceType, bytesToInt(latitude),
@ -73,7 +126,10 @@ public class BoatLocationDecoder {
bytesToInt(trueWindSpeed), bytesToShort(trueWindDirection),
bytesToShort(trueWindAngle), bytesToInt(currentDrift),
bytesToInt(currentSet), bytesToShort(rudderAngle)
);
);*/
// System.out.println(bytesToInt(sourceID));
// System.out.println(bytesToInt(boatSpeed));
}

@ -46,7 +46,7 @@ public class RaceStatus extends AC35Data {
}
/**
* @deprecated use status booleans
*
* @return race status number
*/
public int getRaceStatus()

@ -20,6 +20,15 @@ public class XMLMessage extends AC35Data {
public static int XMLTypeRace = 6;
public static int XMLTypeBoat = 7;
/**
* Constructor for an XML Message
* @param ackNumber Number for acknowledgement inherited for the AC35Data Packet
* @param timeStamp Time received
* @param xmlMsgSubType Type of XML message
* @param sequenceNumber Order that it has arrived in
* @param xmlMsgLength Length of the xml message
* @param xmlMessage XML message
*/
public XMLMessage(int ackNumber, long timeStamp, int xmlMsgSubType, int sequenceNumber, int xmlMsgLength, InputStream xmlMessage){
super(MessageType.XMLMESSAGE);
this.ackNumber = ackNumber;
@ -30,10 +39,18 @@ public class XMLMessage extends AC35Data {
this.xmlMessage = xmlMessage;
}
/**
* Get the XML Message
* @return the XML message as an input stream
*/
public InputStream getXmlMessage() {
return xmlMessage;
}
/**
* Get the type of message
* @return Gets the type of message the XML message is
*/
public int getXmlMsgSubType() {
return xmlMsgSubType;
}

@ -1,34 +0,0 @@
package seng302;
import javafx.scene.paint.Color;
import seng302.Model.BoatInRace;
/**
* Constants that are used throughout the program
* Created by Erika on 19-Mar-17.
* @deprecated please use XML for constant data
*/
public class Constants {
public static final int NMToMetersConversion = 1852; // 1 nautical mile = 1852 meters
public static final GPSCoordinate startLineMarker1 = new GPSCoordinate(32.296577, -64.854304);
public static final GPSCoordinate startLineMarker2 = new GPSCoordinate(32.293771, -64.855242);
public static final GPSCoordinate mark1 = new GPSCoordinate(32.293039, -64.843983);
public static final GPSCoordinate windwardGate1 = new GPSCoordinate(32.284680, -64.850045);
public static final GPSCoordinate windwardGate2 = new GPSCoordinate(32.280164, -64.847591);
public static final GPSCoordinate leewardGate1 = new GPSCoordinate(32.309693, -64.835249);
public static final GPSCoordinate leewardGate2 = new GPSCoordinate(32.308046, -64.831785);
public static final GPSCoordinate finishLineMarker1 = new GPSCoordinate(32.317379, -64.839291);
public static final GPSCoordinate finishLineMarker2 = new GPSCoordinate(32.317257, -64.836260);
public static final double wakeScale = 10;
public static final BoatInRace[] OFFICIAL_AC35_COMPETITORS = new BoatInRace[]
{new BoatInRace("Oracle Team USA", 30.0, Color.BLUEVIOLET, "Oracle"),
new BoatInRace("Land Rover BAR", 23.0, Color.BLACK, "BGR"),
new BoatInRace("SoftBank Team Japan", 27.0, Color.RED, "JPN"),
new BoatInRace("Groupama Team France", 25.0, Color.ORANGE, "FRA"),
new BoatInRace("Artemis Racing", 22.5, Color.DARKOLIVEGREEN, "SWE"),
new BoatInRace("Emirates Team New Zealand", 62, Color.LIMEGREEN, "ETNZ")};
}

@ -16,7 +16,7 @@ import java.net.URL;
import java.util.ResourceBundle;
/**
* Created by cbt24 on 3/05/17.
* Controls the connection that the VIsualiser can connect to.
*/
public class ConnectionController extends Controller {
@FXML

@ -14,7 +14,7 @@ import java.util.ResourceBundle;
/**
* Created by zwu18 on 6/05/17.
* Finish Screen for when the race finishs.
*/
public class FinishController extends Controller {
@ -33,10 +33,10 @@ public class FinishController extends Controller {
@FXML
Label raceWinnerLabel;
/**
* Sets up the finish table
* @param boats Boats to display
*/
private void setFinishTable(ObservableList<Boat> boats){
boatInfoTable.setItems(boats);
boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().getName());
@ -52,6 +52,10 @@ public class FinishController extends Controller {
public void initialize(URL location, ResourceBundle resources){
}
/**
* Display the table
* @param boats boats to display on the table.
*/
public void enterFinish(ObservableList<Boat> boats){
finishWrapper.setVisible(true);
setFinishTable(boats);

@ -12,7 +12,7 @@ import java.net.URL;
import java.util.ResourceBundle;
/**
* Created by fwy13 on 15/03/2017.
* Controller that everything is overlayed onto. This makes it so that changing scenes does not resize your stage.
*/
public class MainController extends Controller {
@FXML private StartController startController;

@ -27,7 +27,6 @@ public class RaceController extends Controller {
@FXML SplitPane race;
@FXML CheckBox showFPS;
@FXML CheckBox showBoatPath;
@FXML CheckBox showAnnotations;
@FXML Label timer;
@FXML Label FPS;
@FXML Label timeZone;
@ -35,21 +34,26 @@ public class RaceController extends Controller {
@FXML CheckBox showAbbrev;
@FXML CheckBox showSpeed;
@FXML Button saveAnno;
@FXML Button showSetAnno;
@FXML TableView<Boat> boatInfoTable;
@FXML TableColumn<Boat, String> boatPlacingColumn;
@FXML TableColumn<Boat, String> boatTeamColumn;
@FXML TableColumn<Boat, String> boatMarkColumn;
@FXML TableColumn<Boat, String> boatSpeedColumn;
@FXML RadioButton hideAnnoRBTN;
@FXML RadioButton showAnnoRBTN;
@FXML RadioButton partialAnnoRBTN;
@FXML RadioButton importantAnnoRBTN;
/**
* Updates the ResizableRaceCanvas (raceMap) with most recent data
*
* @param boats boats that are to be displayed in the race
* @param boatMarkers Markers for boats
* @see ResizableRaceCanvas
*/
public void updateMap(ObservableList<Boat> boats) {
public void updateMap(ObservableList<Boat> boats, ObservableList<Marker> boatMarkers) {
raceMap.setBoats(boats);
raceMap.setBoatMarkers(boatMarkers);
raceMap.update();
raceBoundaries.draw();
//stop if the visualiser is no longer running
@ -60,7 +64,7 @@ public class RaceController extends Controller {
*
* @param race Race to listen to.
*/
public void setInfoTable(Race race) {
public void setInfoTable(StreamedRace race) {
//boatInfoTable.getItems().clear();
ObservableList<Boat> startingBoats = race.getStartingBoats();
boatInfoTable.setItems(race.getStartingBoats());
@ -81,6 +85,12 @@ public class RaceController extends Controller {
FPS.setVisible(false);
}
});
//adds all radios buttons for annotations to a group
ToggleGroup annotationGroup = new ToggleGroup();
hideAnnoRBTN.setToggleGroup(annotationGroup);
showAnnoRBTN.setToggleGroup(annotationGroup);
partialAnnoRBTN.setToggleGroup(annotationGroup);
importantAnnoRBTN.setToggleGroup(annotationGroup);
}
/**
@ -123,21 +133,15 @@ public class RaceController extends Controller {
new Thread((newRace)).start();
}
/**
* Finish Race View
* @param boats boats there are in the race.
*/
public void finishRace(ObservableList<Boat> boats){
race.setVisible(false);
parent.enterFinish(boats);
}
/**
* Set the value for the race clock label
*
* @param time time that the label will be updated to
*/
public void setTimer(String time) {
//timer.setText(time);
}
/**
* Set the value for the fps label
*
@ -166,11 +170,6 @@ public class RaceController extends Controller {
*/
private void initializeAnnotations() {
presetAnno = new ArrayList<>();
//listener for annotation
showAnnotations.selectedProperty().addListener((ov, old_val, new_val) -> {
raceMap.toggleAnnotations();
raceMap.update();
});
//listener for show name in annotation
showName.selectedProperty().addListener((ov, old_val, new_val) -> {
raceMap.toggleAnnoName();
@ -200,13 +199,33 @@ public class RaceController extends Controller {
presetAnno.add(showSpeed.isSelected());
presetAnno.add(showBoatPath.isSelected());
});
//listener to show saved annotation
showSetAnno.setOnAction(event -> {
//listener for hiding
hideAnnoRBTN.selectedProperty().addListener((ov, old_val, new_val) ->{
raceMap.hideAnnotations();
raceMap.update();
});
//listener for showing all annotations
showAnnoRBTN.selectedProperty().addListener((ov, old_val, new_val) ->{
raceMap.showAnnotations();
raceMap.update();
});
//listener for showing all important
partialAnnoRBTN.selectedProperty().addListener((ov, old_val, new_val) ->{
showName.setSelected(false);
showAbbrev.setSelected(true);
showSpeed.setSelected(true);
showBoatPath.setSelected(false);
raceMap.showAnnotations();
raceMap.update();
});
//listener for showing all important
importantAnnoRBTN.selectedProperty().addListener((ov, old_val, new_val) ->{
if (presetAnno.size() > 0) {
showName.setSelected(presetAnno.get(0));
showAbbrev.setSelected(presetAnno.get(1));
showSpeed.setSelected(presetAnno.get(2));
showBoatPath.setSelected(presetAnno.get(3));
raceMap.showAnnotations();
raceMap.update();
}
});

@ -19,7 +19,6 @@ import seng302.VisualiserInput;
import java.io.IOException;
import java.net.Socket;
import java.net.URL;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Observable;
@ -27,7 +26,7 @@ import java.util.Observer;
import java.util.ResourceBundle;
/**
* Created by esa46 on 6/04/17.
* Controller to for waiting for the race to start
*/
public class StartController extends Controller implements Observer {
@ -43,8 +42,6 @@ public class StartController extends Controller implements Observer {
@FXML private Label timer;
@FXML private Label raceStatusLabel;
private ZonedDateTime startingTime;
//@FXML Button fifteenMinButton;
private RaceClock raceClock;
@ -61,17 +58,11 @@ public class StartController extends Controller implements Observer {
* Begins the race with a scale factor of 1
*/
private void startRaceNoScaling() {
//startRace(1);
while(visualiserInput.getRaceStatus() == null);//TODO probably remove this.
countdownTimer();
}
private void startRace(int raceScale){
//fifteenMinButton.setDisable(true);
//countdownTimer(raceScale);
}
@Override
public void initialize(URL location, ResourceBundle resources){
raceData = new StreamedCourse();
@ -82,6 +73,9 @@ public class StartController extends Controller implements Observer {
return startWrapper;
}
/**
* Initiliases the tables that are to be shown on the pane
*/
private void initialiseTables() {
List<Boat> boats = raceData.getBoats();
ObservableList<Boat> observableBoats = FXCollections.observableArrayList(boats);
@ -113,12 +107,18 @@ public class StartController extends Controller implements Observer {
}.start();
}
/**
* Sets the clock that displays the time of at the current race venue.
*/
private void setRaceClock() {
raceClock = new RaceClock(raceData.getZonedDateTime());
timeZoneTime.textProperty().bind(raceClock.timeStringProperty());
raceClock.run();
}
/**
* Sets the time that the race is going to start.
*/
private void setStartingTime() {
String dateFormat = "'Starting time:' HH:mm dd/MM/YYYY";
Platform.runLater(()-> {
@ -129,6 +129,9 @@ public class StartController extends Controller implements Observer {
});
}
/**
* set the current time, may be used to update the time on the clock.
*/
private void setCurrentTime() {
Platform.runLater(()->
raceClock.setUTCTime(visualiserInput.getRaceStatus().getCurrentTime())

@ -15,7 +15,7 @@ import java.util.List;
import java.util.Map;
/**
* Created by Joseph on 24/04/2017.
* XML Read that reads the Boats that are goign to participate in the Race
*/
public class BoatXMLReader extends XMLReader {
private final Map<Integer, StreamedBoat> streamedBoatMap = new HashMap<>();
@ -88,7 +88,7 @@ public class BoatXMLReader extends XMLReader {
Element nBoats = (Element) doc.getElementsByTagName("Boats").item(0);
for (int i = 0; i < nBoats.getChildNodes().getLength(); i++) {
Node boat = nBoats.getChildNodes().item(i);
if (boat.getNodeName().equals("Boat")) {
if (boat.getNodeName().equals("Boat") && boat.getAttributes().getNamedItem("Type").getTextContent().equals("Yacht")) {
readSingleBoat(boat);
}
}
@ -135,6 +135,10 @@ public class BoatXMLReader extends XMLReader {
// TODO Get relative point before implementing. (GPSposition is based off a relative point).
}
/**
* Sets the participants
* @param participants boats participating the race mapped by their source ID's
*/
public void setParticipants(Map<Integer, StreamedBoat> participants) {
this.participants = participants;
}

@ -1,106 +0,0 @@
package seng302.Mock;
import seng302.GPSCoordinate;
/**
* Created by jjg64 on 19/04/17.
* @deprecated use the RegattaXMLReader
*/
public class Regatta {
private int regattaID;
private String RegattaName;
private int raceID = 0;
private String courseName;
private double centralLatitude;
private double centralLongitude;
private double centralAltitude;
private float utcOffset;
private 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;
}
public GPSCoordinate getGPSCoordinate() {
return new GPSCoordinate(centralLatitude, centralLongitude);
}
}

@ -14,7 +14,6 @@ import java.io.InputStream;
* Created by jjg64 on 19/04/17.
*/
public class RegattaXMLReader extends XMLReader {
private Regatta regatta;
private int regattaID;
private String regattaName;
private int raceID = 0;
@ -53,6 +52,13 @@ public class RegattaXMLReader extends XMLReader {
}
}
/**
* Alternate Constructor that takes in an inputstream instead
* @param xmlString Input stream of the XML
* @throws IOException Error with input
* @throws SAXException Error with XML Format
* @throws ParserConfigurationException Error with XMl contents
*/
public RegattaXMLReader(InputStream xmlString) throws IOException, SAXException, ParserConfigurationException {
super(xmlString);
read();
@ -67,6 +73,10 @@ public class RegattaXMLReader extends XMLReader {
makeRegatta(attributes);
}
/**
* Extracts the information from the attributes
* @param attributes attributes to extract information form.
*/
private void makeRegatta(Element attributes) {
this.regattaID = Integer.parseInt(getTextValueOfNode(attributes, "RegattaID"));
this.regattaName = getTextValueOfNode(attributes, "RegattaName");
@ -78,10 +88,6 @@ public class RegattaXMLReader extends XMLReader {
this.magneticVariation = Float.parseFloat(getTextValueOfNode(attributes, "MagneticVariation"));
}
public Regatta getRegatta() {
return regatta;
}
public int getRegattaID() {
return regattaID;
}

@ -3,7 +3,7 @@ package seng302.Mock;
import seng302.Model.Boat;
/**
* Created by Joseph on 24/04/2017.
* Boats that are been received.
*/
public class StreamedBoat extends Boat {
private final int sourceID;
@ -13,6 +13,12 @@ public class StreamedBoat extends Boat {
this.velocity = 0;
}
/**
* COnstructor
* @param sourceID ID of the BOat
* @param name Name of the Boat
* @param abbrev Boat's name shortened.
*/
public StreamedBoat(int sourceID, String name, String abbrev) {
super(name, abbrev);
this.sourceID = sourceID;
@ -20,27 +26,11 @@ public class StreamedBoat extends Boat {
}
public StreamedBoat(int sourceID) {
super("None", "None");
this.sourceID = sourceID;
this.init();
this(sourceID, "None", "None");
}
public int getSourceID() {
return sourceID;
}
/**
* Calculates the azimuth of the travel via heading of the boat
*
* @return the direction that the boat is heading towards in degrees (-180 to 180).
*/
public double calculateAzimuth() {
double azimuth;
if (heading <= 180) {
azimuth = heading;
} else {
azimuth = -heading + 180;
}
return azimuth;
}
}

@ -11,7 +11,7 @@ import java.util.List;
import java.util.Observable;
/**
* Created by jjg64 on 21/04/17.
* COurse that the is being received.
*/
public class StreamedCourse extends Observable implements RaceDataSource {
private StreamedCourseXMLReader streamedCourseXMLReader = null;
@ -21,14 +21,10 @@ public class StreamedCourse extends Observable implements RaceDataSource {
public StreamedCourse() {}
public StreamedCourse(StreamedCourseXMLReader streamedCourseXMLReader) {
this.streamedCourseXMLReader = streamedCourseXMLReader;
}
public StreamedCourse(BoatXMLReader boatXMLReader) {
this.boatXMLReader = boatXMLReader;
}
/**
* Read and set the new XML that has been received.
* @param boatXMLReader new XMl of the boats.
*/
public void setBoatXMLReader(BoatXMLReader boatXMLReader) {
this.boatXMLReader = boatXMLReader;
if (streamedCourseXMLReader != null && boatXMLReader != null) {
@ -44,6 +40,10 @@ public class StreamedCourse extends Observable implements RaceDataSource {
return streamedCourseXMLReader;
}
/**
* Read and sets the new Course that has been received
* @param streamedCourseXMLReader COurse XML that has been received
*/
public void setStreamedCourseXMLReader(StreamedCourseXMLReader streamedCourseXMLReader) {
this.streamedCourseXMLReader = streamedCourseXMLReader;
if (streamedCourseXMLReader != null && boatXMLReader != null) {
@ -52,6 +52,10 @@ public class StreamedCourse extends Observable implements RaceDataSource {
}
}
/**
* Reads and sets the new Regatta that has been received
* @param regattaXMLReader Regatta XMl that has been received.
*/
public void setRegattaXMLReader(RegattaXMLReader regattaXMLReader) {
this.regattaXMLReader = regattaXMLReader;
setChanged();

@ -13,13 +13,12 @@ import seng302.XMLReader;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* Created by jjg64 on 21/04/17.
* XML Read for the Course that is being received
*/
public class StreamedCourseXMLReader extends XMLReader {
private static final double COORDINATEPADDING = 0.000;
@ -35,19 +34,6 @@ public class StreamedCourseXMLReader extends XMLReader {
private String raceType;
private boolean postpone;
/**
* Constructor for Streamed Race XML
* @param filePath path of the file
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
* @throws ParseException error
* @throws StreamedCourseXMLException error
*/
public StreamedCourseXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
this(filePath, true);
}
/**
* Constructor for Streamed Race XML
* @param filePath file path to read
@ -55,10 +41,9 @@ public class StreamedCourseXMLReader extends XMLReader {
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
* @throws ParseException error
* @throws StreamedCourseXMLException error
*/
public StreamedCourseXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
public StreamedCourseXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException, StreamedCourseXMLException {
super(filePath);
if (read) {
read();
@ -71,10 +56,9 @@ public class StreamedCourseXMLReader extends XMLReader {
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
* @throws ParseException error
* @throws StreamedCourseXMLException error
*/
public StreamedCourseXMLReader(InputStream xmlString) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
public StreamedCourseXMLReader(InputStream xmlString) throws IOException, SAXException, ParserConfigurationException, StreamedCourseXMLException {
super(xmlString);
read();
}
@ -111,6 +95,9 @@ public class StreamedCourseXMLReader extends XMLReader {
postpone = Boolean.parseBoolean(raceTimeTag.getNamedItem("Postpone").getTextContent());
}
/**
* Reads the participants of the race.
*/
private void readParticipants() {
Element nParticipants = (Element) doc.getElementsByTagName("Participants").item(0);
nParticipants.getChildNodes().getLength();
@ -165,20 +152,39 @@ public class StreamedCourseXMLReader extends XMLReader {
Marker marker;
switch(nMarks.getLength()) {
case 1: marker = new Marker(getCoordinate((Element)nMarks.item(0))); break;
case 2: marker = new Marker(getCoordinate((Element)nMarks.item(0)), getCoordinate((Element)nMarks.item(1))); break;
case 1: marker = new Marker(getCoordinate((Element)nMarks.item(0)),getSourceId((Element)nMarks.item(0))); break;
case 2: marker = new Marker(getCoordinate((Element)nMarks.item(0)), getCoordinate((Element)nMarks.item(1)),
getSourceId((Element)nMarks.item(0)), getSourceId((Element)nMarks.item(1))); break;
default: throw new StreamedCourseXMLException();
}
return marker;
}
/**
* Extracts the GPS Coordinates from a XMl Element
* @param mark Element to Extract from
* @return the GPS coordinate that it reflects
*/
private GPSCoordinate getCoordinate(Element mark) {
double lat = Double.parseDouble(mark.getAttribute("TargetLat"));
double lon = Double.parseDouble(mark.getAttribute("TargetLng"));
return new GPSCoordinate(lat,lon);
}
/**
* Extracts the SourceID from a XML ELement
* @param mark Element to Extract from
* @return the Source ID of the Extracted Element.
*/
private int getSourceId(Element mark) {
String sourceId = mark.getAttribute("SourceID");
if (sourceId.isEmpty()){
return 0;
}
return Integer.parseInt(sourceId);
}
/**
* Reads "compoundMarkID" attribute of CompoundMark or Corner element
* @param element with "compoundMarkID" attribute
@ -216,6 +222,9 @@ public class StreamedCourseXMLReader extends XMLReader {
}
}
/**
* Reads the course boundary limitations of the course recieved.
*/
private void readCourseLimit() {
Element nCourseLimit = (Element) doc.getElementsByTagName("CourseLimit").item(0);
for(int i = 0; i < nCourseLimit.getChildNodes().getLength(); i++) {
@ -259,10 +268,6 @@ public class StreamedCourseXMLReader extends XMLReader {
return COORDINATEPADDING;
}
public ZonedDateTime getCreationTimeDate() {
return creationTimeDate;
}
public ZonedDateTime getRaceStartTime() {
return raceStartTime;
}

@ -1,37 +1,60 @@
package seng302.Mock;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import seng302.Controllers.FinishController;
import seng302.Controllers.RaceController;
import seng302.GPSCoordinate;
import seng302.Model.Boat;
import seng302.Model.Leg;
import seng302.Model.Marker;
import seng302.Model.Race;
import seng302.Networking.Messages.BoatLocation;
import seng302.Networking.Messages.BoatStatus;
import seng302.Networking.Messages.Enums.BoatStatusEnum;
import seng302.VisualiserInput;
import java.util.List;
/**
* Created by jjg64 on 21/04/17.
* The Class used to view the race streamed.
*/
public class StreamedRace extends Race {
public class StreamedRace implements Runnable {
private final VisualiserInput visualiserInput;
private final ObservableList<Boat> startingBoats;
private final ObservableList<Marker> boatMarkers;
private final List<Leg> legs;
private RaceController controller;
protected FinishController finishController;
private int boatsFinished = 0;
private long totalTimeElapsed;
private int lastFPS = 20;
public StreamedRace(VisualiserInput visualiserInput, RaceController controller) {
super(visualiserInput.getCourse(), controller, 1);
StreamedCourse course = visualiserInput.getCourse();
this.startingBoats = FXCollections.observableArrayList(course.getBoats());
this.boatMarkers = FXCollections.observableArrayList(course.getMarkers());
this.legs = course.getLegs();
this.legs.add(new Leg("Finish", this.legs.size()));
this.controller = controller;
if (startingBoats != null && startingBoats.size() > 0) {
initialiseBoats();
}
this.visualiserInput = visualiserInput;
}
public void initialiseBoats() {
private void initialiseBoats() {
Leg officialStart = legs.get(0);
String name = officialStart.getName();
Marker endMarker = officialStart.getEndMarker();
Marker endCompoundMark = officialStart.getEndMarker();
for (int i = 0; i < startingBoats.size(); i++) {
Boat boat = startingBoats.get(i);
for (Boat boat : startingBoats) {
if (boat != null) {
Leg startLeg = new Leg(name, 0);
startLeg.setEndMarker(endMarker);
startLeg.setEndMarker(endCompoundMark);
boat.setCurrentLeg(startLeg);
}
}
@ -52,7 +75,7 @@ public class StreamedRace extends Race {
* @param boat Boat that the position is to be updated for.
* @param timeElapsed Time that has elapse since the start of the the race.
*/
protected void checkPosition(Boat boat, long timeElapsed) {
private void checkPosition(Boat boat, long timeElapsed) {
StreamedCourse raceData = visualiserInput.getCourse();
BoatStatus boatStatusMessage = visualiserInput.getBoatStatusMap().get(boat.getSourceID());
if (boatStatusMessage != null) {
@ -72,7 +95,7 @@ public class StreamedRace extends Race {
boatsFinished++;
boat.setTimeFinished(timeElapsed);
boat.setFinished(true);
System.out.println("Boat finished");
//System.out.println("Boat finished");
}
}
//Update the boat display table in the GUI to reflect the leg change
@ -85,7 +108,7 @@ public class StreamedRace extends Race {
* @param boat to be updated
* @param millisecondsElapsed time since last update
*/
protected void updatePosition(Boat boat, int millisecondsElapsed) {
private void updatePosition(Boat boat, int millisecondsElapsed) {
int sourceID = boat.getSourceID();
BoatLocation boatLocation = visualiserInput.getBoatLocationMessage(sourceID);
if(boatLocation != null) {
@ -99,12 +122,131 @@ public class StreamedRace extends Race {
}
/**
* sets the position of a boat from coordinate
* @param boat the boat to set
* @param coordinate the position of the boat
* Updates the boat's gps coordinates
*
* @param mark to be updated
*/
private void updateMarker(Marker mark) {
int sourceID = mark.getSourceId1();
BoatLocation boatLocation1 = visualiserInput.getBoatLocationMessage(sourceID);
if(boatLocation1 != null) {
double lat = boatLocation1.getLatitudeDouble();
double lon = boatLocation1.getLongitudeDouble();
mark.setCurrentPosition1(new GPSCoordinate(lat, lon));
}
int sourceID2 = mark.getSourceId2();
BoatLocation boatLocation2 = visualiserInput.getBoatLocationMessage(sourceID2);
if(boatLocation2 != null) {
double lat = boatLocation2.getLatitudeDouble();
double lon = boatLocation2.getLongitudeDouble();
mark.setCurrentPosition2(new GPSCoordinate(lat, lon));
}
}
public void setController(RaceController controller) {
this.controller = controller;
}
/**
* Runnable for the thread.
*/
public void run() {
setControllerListeners();
initialiseBoats();
startRaceStream();
}
/**
* Update the calculated fps to the fps label
*
* @param fps The new calculated fps value
*/
private void updateFPS(int fps) {
Platform.runLater(() -> controller.setFrames("FPS: " + fps));
}
/**
* Starts the Race Simulation, playing the race start to finish with the timescale.
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events.
*/
private void startRaceStream() {
System.setProperty("javafx.animation.fullspeed", "true");
for (Boat boat : startingBoats) {
boat.setStarted(true);
}
new AnimationTimer() {
final long timeRaceStarted = System.currentTimeMillis(); //start time of loop
int fps = 0; //init fps value
long timeCurrent = System.currentTimeMillis(); //current time
@Override
public void handle(long arg0) {
totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted;
for (Boat boat : startingBoats) {
if (boat != null && !boat.isFinished()) {
updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS));
checkPosition(boat, totalTimeElapsed);
}
}
for (Marker mark: boatMarkers){
if (mark != null){
updateMarker(mark);
}
}
//System.out.println(boatsFinished + ":" + startingBoats.size());
if (visualiserInput.getRaceStatus().isFinished()){
controller.finishRace(startingBoats);
stop();
}
controller.updateMap(startingBoats, boatMarkers);
fps++;
if ((System.currentTimeMillis() - timeCurrent) > 1000) {
updateFPS(fps);
lastFPS = fps;
fps = 0;
timeCurrent = System.currentTimeMillis();
}
}
}.start();
}
/**
* Update position of boats in race, no position if on starting leg or DNF.
*/
private void updatePositions() {
FXCollections.sort(startingBoats, (a, b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber());
for(Boat boat: startingBoats) {
if(boat != null) {
boat.setPosition(Integer.toString(startingBoats.indexOf(boat) + 1));
if (boat.isDnf() || !boat.isStarted() || boat.getCurrentLeg().getLegNumber() < 0)
boat.setPosition("-");
}
}
}
/**
* Update call for the controller.
*/
private void setControllerListeners() {
if (controller != null) controller.setInfoTable(this);
}
/**
* Returns the boats that have started the race.
*
* @return ObservableList of Boat class that participated in the race.
* @see ObservableList
* @see Boat
*/
protected void setPosition(Boat boat, GPSCoordinate coordinate) {
boat.setCurrentPosition(coordinate);
public ObservableList<Boat> getStartingBoats() {
return startingBoats;
}
}

@ -4,7 +4,6 @@ import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.paint.Color;
import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants;
import seng302.GPSCoordinate;
import java.awt.geom.Point2D;
@ -28,6 +27,7 @@ public class BoatInRace extends Boat {
private boolean started = false;
private final StringProperty position;
private double heading;
private static final double WAKE_SCALE = 10;
private final Queue<TrackPoint> track = new ConcurrentLinkedQueue<>();
private long nextValidTime = 0;
@ -50,20 +50,6 @@ public class BoatInRace extends Boat {
position = new SimpleStringProperty("-");
}
/**
* Constructor method.
*
* @param name Name of the boat.
* @param colour Colour the boat will be displayed as on the map
* @param abbrev of boat
*/
public BoatInRace(String name, Color colour, String abbrev) {
super(name, abbrev);
setColour(colour);
currentLegName = new SimpleStringProperty("");
position = new SimpleStringProperty("-");
}
/**
* Calculates the azimuth of the travel via map coordinates of the raceMarkers
*
@ -122,7 +108,7 @@ public class BoatInRace extends Boat {
*/
public GPSCoordinate getWake() {
double reverseHeading = getHeading() - 180;
double distance = Constants.wakeScale * getVelocity();
double distance = WAKE_SCALE * getVelocity();
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(

@ -60,19 +60,19 @@
// public void initialiseBoats() {
// Leg officialStart = legs.get(0);
// String name = officialStart.getName();
// Marker endMarker = officialStart.getEndMarker();
// CompoundMark endMarker = officialStart.getEndCompoundMark();
//
// BoatInRace.setTrackPointTimeInterval(BoatInRace.getBaseTrackPointTimeInterval() / scaleFactor);
//
// ArrayList<Marker> startMarkers = getSpreadStartingPositions();
// ArrayList<CompoundMark> startMarkers = getSpreadStartingPositions();
// for (int i = 0; i < startingBoats.size(); i++) {
// BoatInRace boat = startingBoats.get(i);
// if (boat != null) {
// boat.setScaledVelocity(boat.getVelocity() * scaleFactor);
// Leg startLeg = new Leg(name, 0);
// boat.setCurrentPosition(startMarkers.get(i).getAverageGPSCoordinate());
// startLeg.setStartMarker(startMarkers.get(i));
// startLeg.setEndMarker(endMarker);
// startLeg.setStartCompoundMark(startMarkers.get(i));
// startLeg.setEndCompoundMark(endMarker);
// startLeg.calculateDistance();
// boat.setCurrentLeg(startLeg);
// boat.setHeading(boat.calculateHeading());
@ -85,10 +85,10 @@
// *
// * @return list of starting positions
// */
// public ArrayList<Marker> getSpreadStartingPositions() {
// public ArrayList<CompoundMark> getSpreadStartingPositions() {
//
// int nBoats = startingBoats.size();
// Marker marker = legs.get(0).getStartMarker();
// CompoundMark marker = legs.get(0).getStartCompoundMark();
//
// GeodeticCalculator initialCalc = new GeodeticCalculator();
// initialCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude());
@ -100,12 +100,12 @@
//
// GeodeticCalculator positionCalc = new GeodeticCalculator();
// positionCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude());
// ArrayList<Marker> positions = new ArrayList<>();
// ArrayList<CompoundMark> positions = new ArrayList<>();
//
// for (int i = 0; i < nBoats; i++) {
// positionCalc.setDirection(azimuth, distanceBetweenBoats);
// Point2D position = positionCalc.getDestinationGeographicPoint();
// positions.add(new Marker(new GPSCoordinate(position.getY(), position.getX())));
// positions.add(new CompoundMark(new GPSCoordinate(position.getY(), position.getX())));
//
// positionCalc = new GeodeticCalculator();
// positionCalc.setStartingGeographicPoint(position);
@ -147,7 +147,7 @@
// //update boat's distance travelled
// boat.setDistanceTravelledInLeg(totalDistanceTravelled);
// //Calculate boat's new position by adding the distance travelled onto the start point of the leg
// boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartMarker().getAverageGPSCoordinate(),
// boat.setCurrentPosition(calculatePosition(boat.getCurrentLeg().getStartCompoundMark().getAverageGPSCoordinate(),
// totalDistanceTravelled, boat.calculateAzimuth()));
// }
// }

@ -1,7 +1,6 @@
package seng302.Model;
import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants;
import seng302.GPSCoordinate;
/**
@ -13,6 +12,8 @@ public class Leg {
private Marker startMarker;
private Marker endMarker;
private final int legNumber;
// 1 nautical mile = 1852 meters
public static final int NM_TO_METERS = 1852;
/**
* Leg Initializer
@ -63,7 +64,6 @@ public class Leg {
* Returns the leg number that the leg exists in the Race
*
* @return Returns the Leg
* @see Race
*/
public int getLegNumber() {
return legNumber;
@ -97,7 +97,7 @@ public class Leg {
GPSCoordinate endMarker = this.endMarker.getAverageGPSCoordinate();
calc.setStartingGeographicPoint(startMarker.getLongitude(), startMarker.getLatitude());
calc.setDestinationGeographicPoint(endMarker.getLongitude(), endMarker.getLatitude());
this.distance = calc.getOrthodromicDistance() / Constants.NMToMetersConversion;
this.distance = calc.getOrthodromicDistance() / NM_TO_METERS;
}

@ -10,25 +10,42 @@ import java.awt.geom.Point2D;
*/
public class Marker {
private final GPSCoordinate averageGPSCoordinate;
private final GPSCoordinate mark1;
private final GPSCoordinate mark2;
public Marker(GPSCoordinate mark1) {
this.mark1 = mark1;
this.mark2 = mark1;
this.averageGPSCoordinate = calculateAverage();
private GPSCoordinate mark1;
private GPSCoordinate mark2;
private final int sourceId1;
private final int sourceId2;
public Marker(GPSCoordinate mark1, int sourceId) {
this(mark1, mark1, sourceId, sourceId);
}
public Marker(GPSCoordinate mark1, GPSCoordinate mark2) {
public Marker(GPSCoordinate mark1, GPSCoordinate mark2, int sourceId1, int sourceId2) {
this.mark1 = mark1;
this.mark2 = mark2;
this.averageGPSCoordinate = calculateAverage();
this.sourceId1 = sourceId1;
this.sourceId2 = sourceId2;
}
/**
*
* @param mark1 Mark coordinates.
*/
public Marker(GPSCoordinate mark1) {
this(mark1, mark1, 0,0);
}
/**
*
* @param mark1 Mark one coordinate
* @param mark2 Mark two coordinate
*/
public Marker(GPSCoordinate mark1, GPSCoordinate mark2) {
this(mark1, mark2, 0,0);
}
public GPSCoordinate getMark1() {
return mark1;
}
@ -66,4 +83,19 @@ public class Marker {
}
public void setCurrentPosition1(GPSCoordinate gpsCoordinate){
mark1 = gpsCoordinate;
}
public void setCurrentPosition2(GPSCoordinate gpsCoordinate){
mark2 = gpsCoordinate;
}
public int getSourceId1() {
return sourceId1;
}
public int getSourceId2() {
return sourceId2;
}
}

@ -1,191 +0,0 @@
package seng302.Model;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import seng302.Controllers.FinishController;
import seng302.Controllers.RaceController;
import seng302.RaceDataSource;
import java.util.Arrays;
import java.util.List;
/**
* Parent class for races
* Created by fwy13 on 3/03/17.
*/
public abstract class Race implements Runnable {
protected final ObservableList<Boat> startingBoats;
protected final List<Leg> legs;
private RaceController controller;
protected FinishController finishController;
protected int boatsFinished = 0;
private long totalTimeElapsed;
private int lastFPS = 20;
/**
* Initializer for Race
*
* @param boats Takes in an array of boats that are participating in the race.
* @param legs Number of marks in order that the boats pass in order to complete the race.
* @param controller race controller
* @param scaleFactor for race
*/
private Race(List<Boat> boats, List<Leg> legs, RaceController controller, int scaleFactor) {
this.startingBoats = FXCollections.observableArrayList(boats);
this.legs = legs;
this.legs.add(new Leg("Finish", this.legs.size()));
this.controller = controller;
if (startingBoats != null && startingBoats.size() > 0) {
initialiseBoats();
}
}
protected Race(RaceDataSource raceData, RaceController controller, int scaleFactor) {
this(raceData.getBoats(), raceData.getLegs(), controller, scaleFactor);
}
/**
* @deprecated
* @param startingBoats boats starting the race
* @param legs legs in race
* @param controller controller for the race
* @param scaleFactor factor to scale by
*/
public Race(Boat[] startingBoats, List<Leg> legs, RaceController controller, int scaleFactor) {
this(Arrays.asList(startingBoats), legs, controller, scaleFactor);
}
public void setController(RaceController controller) {
this.controller = controller;
}
protected abstract void initialiseBoats();
/**
* Checks if the boat cannot finish the race
* @return True if boat cannot finish the race
*/
protected abstract boolean doNotFinish();
/**
* Checks the position of the boat, this updates the boats current position.
*
* @param boat Boat that the position is to be updated for.
* @param timeElapsed Time that has elapse since the start of the the race.
* @see Boat
*/
protected abstract void checkPosition(Boat boat, long timeElapsed);
/**
* Updates the boat's gps coordinates
*
* @param boat to be updated
* @param millisecondsElapsed time since last update
*/
protected abstract void updatePosition(Boat boat, int millisecondsElapsed);
/**
* Runnable for the thread.
*/
public void run() {
setControllerListeners();
initialiseBoats();
simulateRace();
}
/**
* Update the calculated fps to the fps label
*
* @param fps The new calculated fps value
*/
private void updateFPS(int fps) {
Platform.runLater(() -> controller.setFrames("FPS: " + fps));
}
/**
* Starts the Race Simulation, playing the race start to finish with the timescale.
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events.
*/
private void simulateRace() {
System.setProperty("javafx.animation.fullspeed", "true");
for (Boat boat : startingBoats) {
boat.setStarted(true);
}
new AnimationTimer() {
final long timeRaceStarted = System.currentTimeMillis(); //start time of loop
int fps = 0; //init fps value
long timeCurrent = System.currentTimeMillis(); //current time
@Override
public void handle(long arg0) {
if (boatsFinished < startingBoats.size()) {
boatsFinished = 0;
totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted;
for (Boat boat : startingBoats) {
if (boat != null && !boat.isFinished()) {
updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS));
checkPosition(boat, totalTimeElapsed);
}
if (boat.isFinished()){
boatsFinished++;
}
}
//System.out.println(boatsFinished + ":" + startingBoats.size());
} else {
controller.finishRace(startingBoats);
stop();
}
controller.updateMap(startingBoats);
fps++;
if ((System.currentTimeMillis() - timeCurrent) > 1000) {
updateFPS(fps);
lastFPS = fps;
fps = 0;
timeCurrent = System.currentTimeMillis();
}
}
}.start();
}
/**
* Update position of boats in race, no position if on starting leg or DNF.
*/
protected void updatePositions() {
FXCollections.sort(startingBoats, (a, b) -> b.getCurrentLeg().getLegNumber() - a.getCurrentLeg().getLegNumber());
for(Boat boat: startingBoats) {
if(boat != null) {
boat.setPosition(Integer.toString(startingBoats.indexOf(boat) + 1));
if (boat.isDnf() || !boat.isStarted() || boat.getCurrentLeg().getLegNumber() < 0)
boat.setPosition("-");
}
}
}
/**
* Update call for the controller.
*/
private void setControllerListeners() {
if (controller != null) controller.setInfoTable(this);
}
/**
* Returns the boats that have started the race.
*
* @return ObservableList of Boat class that participated in the race.
* @see ObservableList
* @see Boat
*/
public ObservableList<Boat> getStartingBoats() {
return startingBoats;
}
}

@ -34,13 +34,6 @@ public class RaceClock implements Runnable {
setTime(time);
}
public RaceClock(long utcTime, ZoneId zoneId) {
this.zoneId = zoneId;
this.timeString = new SimpleStringProperty();
this.time = (new Date(utcTime)).toInstant().atZone(zoneId);
setTime(time);
}
public static ZonedDateTime getCurrentZonedDateTime(GPSCoordinate gpsCoordinate) {
TimeZoneLookup timeZoneLookup = new TimeZoneLookup();
TimeZoneResult timeZoneResult = timeZoneLookup.getTimeZone(gpsCoordinate.getLatitude(), gpsCoordinate.getLongitude());

@ -1,10 +1,10 @@
package seng302.Model;
import javafx.collections.ObservableList;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.transform.Rotate;
import seng302.GPSCoordinate;
import seng302.GraphCoordinate;
import seng302.Mock.StreamedCourse;
import seng302.RaceDataSource;
@ -22,6 +22,7 @@ import java.util.List;
public class ResizableRaceCanvas extends ResizableCanvas {
private RaceMap map;
private List<Boat> boats;
private List<Marker> boatMarkers;
private boolean raceAnno = true;
private boolean annoName = true;
private boolean annoAbbrev = true;
@ -29,7 +30,6 @@ public class ResizableRaceCanvas extends ResizableCanvas {
private boolean annoPath = true;
private List<Color> colours;
private final List<Marker> markers;
double[] xpoints = {}, ypoints = {};
private final RaceDataSource raceData;
public ResizableRaceCanvas(RaceDataSource raceData) {
@ -56,29 +56,23 @@ public class ResizableRaceCanvas extends ResizableCanvas {
this.boats = boats;
}
/**
* Sets the RaceMap that the RaceCanvas is to be displaying for.
* Sets the boat markers that are to be displayed in this race.
*
* @param map race map
* @param boatMarkers in race
*/
private void setMap(RaceMap map) {
this.map = map;
public void setBoatMarkers(ObservableList<Marker> boatMarkers) {
this.boatMarkers = boatMarkers;
}
/**
* Displays the mark of a race as a circle.
* Sets the RaceMap that the RaceCanvas is to be displaying for.
*
* @param graphCoordinate Latitude and Longitude in GraphCoordinate that it
* is to be displayed as.
* @param paint Colour the mark is to be coloured.
* @see GraphCoordinate
* @see Color
* @see Paint
* @param map race map
*/
public void displayMark(GraphCoordinate graphCoordinate, Paint paint) {
double d = 25;
this.gc.setFill(paint);
gc.fillOval(graphCoordinate.getX() - (d / 2), graphCoordinate.getY() - (d / 2), d, d);
private void setMap(RaceMap map) {
this.map = map;
}
private void displayBoat(Boat boat, double angle, Color colour) {
@ -247,23 +241,24 @@ public class ResizableRaceCanvas extends ResizableCanvas {
}
/**
* Draws a boat at a certain GPSCoordinate
*
* @param colour Colour to colour boat.
* @param gpsCoordinates GPScoordinate that the boat is to be drawn at.
* @see GPSCoordinate
* @see Color
* Toggle the raceAnno value
*/
public void drawBoat(Color colour, GPSCoordinate gpsCoordinates) {
GraphCoordinate graphCoordinate = this.map.convertGPS(gpsCoordinates);
displayPoint(graphCoordinate, colour);
public void toggleAnnotations() {
raceAnno = !raceAnno;
}
/**
* Toggle the raceAnno value
* Shows the race Annotations
*/
public void toggleAnnotations() {
raceAnno = !raceAnno;
public void showAnnotations(){
raceAnno = true;
}
/**
* Hides the Race ANnotations
*/
public void hideAnnotations(){
raceAnno = false;
}
/**
@ -273,6 +268,9 @@ public class ResizableRaceCanvas extends ResizableCanvas {
annoName = !annoName;
}
/**
* Toggles the path of the boat
*/
public void toggleBoatPath() {
annoPath = !annoPath;
}
@ -335,6 +333,9 @@ public class ResizableRaceCanvas extends ResizableCanvas {
}
}
/**
* makes colours
*/
private void makeColours() {
colours = new ArrayList<>(Arrays.asList(
Color.BLUEVIOLET,

@ -17,6 +17,10 @@ public class ResizableRaceMap extends ResizableCanvas {
private double[] xpoints = {};
private double[] ypoints = {};
/**
* Constructor
* @param raceData Race which it is taking its information to be displayed from
*/
public ResizableRaceMap(RaceDataSource raceData){
super();
raceBoundaries = raceData.getBoundary();
@ -29,9 +33,14 @@ public class ResizableRaceMap extends ResizableCanvas {
//draw();
}
/**
* Sets the map race that it is auppost to be viewing.
* @param map
*/
private void setMap(RaceMap map) {
this.map = map;
}
/**
* Draw boundary of the race.
*/
@ -46,6 +55,9 @@ public class ResizableRaceMap extends ResizableCanvas {
gc.fillPolygon(xpoints, ypoints, xpoints.length);
}
/**
* Sets the coordinately of the race boundaries
*/
private void setRaceBoundCoordinates() {
xpoints = new double[this.raceBoundaries.size()];
ypoints = new double[this.raceBoundaries.size()];
@ -56,6 +68,9 @@ public class ResizableRaceMap extends ResizableCanvas {
}
}
/**
* Draw update for the canvas
*/
public void draw(){
double width = getWidth();

@ -1,327 +0,0 @@
package seng302;
import javafx.scene.paint.Color;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import seng302.Model.*;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* Created by fwy13 on 26/03/2017.
* @deprecated use {@link seng302.Mock.StreamedCourseXMLReader}
*/
public class RaceXMLReader extends XMLReader implements RaceDataSource {
private final List<Boat> boats = new ArrayList<>();
private final Color[] colors = {Color.BLUEVIOLET, Color.BLACK, Color.RED, Color.ORANGE, Color.DARKOLIVEGREEN, Color.LIMEGREEN};//TODO make this established in xml or come up with a better system.
private final List<Leg> legs = new ArrayList<>();
private GPSCoordinate mark, startPt1, startPt2, finishPt1, finishPt2, leewardPt1, leewardPt2, windwardPt1, windwardPt2;
private GPSCoordinate mapTopLeft, mapBottomRight;
private final List<GPSCoordinate> boundary = new ArrayList<>();
/**
* Constructor for Race XML
* @param filePath path of the file
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public RaceXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException {
this(filePath, true);
}
/**
* Constructor for Race XML
* @param filePath file path to read
* @param read whether or not to read and store the files straight away.
* @throws IOException error
* @throws SAXException error
* @throws ParserConfigurationException error
*/
public RaceXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException {
super(filePath);
if (read) {
read();
}
}
/**
* Read the files
*/
private void read() {
readCourse();
readLegs();
readBoats();
}
/**
* Read all the boats in the XML file
*/
public void readBoats() {
//get all boats
NodeList nBoats = doc.getElementsByTagName("boat");
for (int i = 0; i < nBoats.getLength(); i++) {
String name = getTextValueOfNode((Element) nBoats.item(i), "name");
String abbrev = getTextValueOfNode((Element) nBoats.item(i), "abbr");
double velo = Double.parseDouble(getTextValueOfNode((Element) nBoats.item(i), "speed"));
BoatInRace boat = new BoatInRace(name, velo, colors[i], abbrev);
boat.setCurrentPosition(startPt1);
if (legs.size() > 0) {
boat.setCurrentLeg(legs.get(0));
}
boats.add(boat);
}
}
/**
* Read all the legs in the XML file
*/
public void readLegs() {
//get all legs
NodeList nLegs = doc.getElementsByTagName("leg");
for (int i = 0; i < nLegs.getLength(); i++) {
String label = getTextValueOfNode((Element) nLegs.item(i), "name");
NodeList start = ((Element) nLegs.item(i)).getElementsByTagName("start");
Marker startMarker = getMarker(start);
NodeList finish = ((Element) nLegs.item(i)).getElementsByTagName("finish");
Marker finishMarker = getMarker(finish);
legs.add(new Leg(label, startMarker, finishMarker, i));
}
}
/**
* Read courses in XML file
*/
public void readCourse() {
NodeList nCourse = doc.getElementsByTagName("course");
NodeList nBounds = ((Element) nCourse.item(0)).getElementsByTagName("boundaries");
nBounds = ((Element) nBounds.item(0)).getElementsByTagName("coordinate");
int maxLatitudeIndex = 0;
double maxLatitude = -Double.MIN_VALUE;
int maxLongitudeIndex = 0;
double maxLongitude = -180;
int minLatitudeIndex = 0;
double minLatitude = Double.MAX_VALUE;
int minLongitudeIndex = 0;
double minLongitude = Double.MAX_VALUE;
for (int i = 0; i < nBounds.getLength(); i++) {
boundary.add(getCoordinates((Element) nBounds.item(i)));
if (boundary.get(i).getLatitude() > maxLatitude) {
maxLatitudeIndex = i;
maxLatitude = boundary.get(i).getLatitude();
}
if (boundary.get(i).getLatitude() < minLatitude) {
minLatitudeIndex = i;
minLatitude = boundary.get(i).getLatitude();
}
if (boundary.get(i).getLongitude() > maxLongitude) {
maxLongitudeIndex = i;
maxLongitude = boundary.get(i).getLongitude();
}
if (boundary.get(i).getLongitude() < minLongitude) {
minLongitudeIndex = i;
minLongitude = boundary.get(i).getLongitude();
}
}
double difference = 0;//this will hold the largest difference so we can make the map square.
double latitudeDiff = Math.abs(Math.abs(boundary.get(maxLatitudeIndex).getLatitude()) - Math.abs(boundary.get(minLatitudeIndex).getLatitude()));
double longitudeDiff = Math.abs(Math.abs(boundary.get(maxLongitudeIndex).getLongitude()) - Math.abs(boundary.get(minLongitudeIndex).getLongitude()));
if (latitudeDiff >= longitudeDiff) {
difference = latitudeDiff - longitudeDiff;
maxLongitude += difference / 2;
minLongitude -= difference / 2;
} else {
difference = longitudeDiff - latitudeDiff;
maxLatitude += difference / 2;
minLatitude -= difference / 2;
}
double COORDINATEPADDING = 0.0005;
maxLatitude += COORDINATEPADDING;
minLatitude -= COORDINATEPADDING;
maxLongitude += COORDINATEPADDING;
minLongitude -= COORDINATEPADDING;
//now create map boundaries
//top left canvas point is min longitude, max latitude
//bottom right of canvas point is min longitude, max latitude.
mapTopLeft = new GPSCoordinate(minLatitude, minLongitude);
mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude);
NodeList nMarks = ((Element) nCourse.item(0)).getElementsByTagName("marker");
startPt1 = getCoordinates(nMarks, 0);
startPt2 = getCoordinates(nMarks, 0, 1);
mark = getCoordinates(nMarks, 1);
windwardPt1 = getCoordinates(nMarks, 2);
windwardPt2 = getCoordinates(nMarks, 2, 1);
leewardPt1 = getCoordinates(nMarks, 3);
leewardPt2 = getCoordinates(nMarks, 3, 1);
finishPt1 = getCoordinates(nMarks, 4);
finishPt2 = getCoordinates(nMarks, 4, 1);
}
/**
* gets a marker from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @return
*/
private Marker getMarker(NodeList start) {
return getMarker(start, 0);
}
/**
* gets a marker from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex index in the node that has the coordinate tag
* @return
*/
private Marker getMarker(NodeList start, int startIndex) {
return getMarker(start, startIndex, 0);
}
/**
* gets a marker from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex index in the node that has the coordinate tag
* @param nodeIndex coordinate index
* @return
*/
private Marker getMarker(NodeList start, int startIndex, int nodeIndex) {
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("marker");
Element marker = (Element) nodeList.item(nodeIndex);
return getMarker(marker);
}
/**
* gets a changes a marker to GPS coordinates into a marker
* @param markerNode marker to turn into coordinates
* @return
*/
private Marker getMarker(Element markerNode) {
NodeList nCoordinates = markerNode.getElementsByTagName("coordinate");
GPSCoordinate side1 = getCoordinates((Element) nCoordinates.item(0));
GPSCoordinate side2;
if (nCoordinates.getLength() > 1) {
side2 = getCoordinates((Element) nCoordinates.item(1));
} else {
side2 = side1;
}
return new Marker(side1, side2);
}
/**
* gets a coordinates from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @return
*/
private GPSCoordinate getCoordinates(NodeList start) {
return getCoordinates(start, 0);
}
/**
* gets a coordinates from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex the index the tag containing the coordinate should be in
* @return
*/
private GPSCoordinate getCoordinates(NodeList start, int startIndex) {
return getCoordinates(start, startIndex, 0);
}
/**
* gets a coordinates from the XML file
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
* @param startIndex the index the tag containing the coordinate should be in
* @param nodeIndex The coordinate index
* @return
*/
private GPSCoordinate getCoordinates(NodeList start, int startIndex, int nodeIndex) {
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("coordinate");
Element coord = (Element) nodeList.item(nodeIndex);
return getCoordinates(coord);
}
/**
* Returns the coordinate TODO raise exception that runs when the XML is formatted wrongly.
*
* @param coordNode
* @return
*/
private GPSCoordinate getCoordinates(Element coordNode) {
double startLat = Double.parseDouble(getTextValueOfNode(coordNode, "latitude"));
double startLong = Double.parseDouble(getTextValueOfNode(coordNode, "longitude"));
return new GPSCoordinate(startLat, startLong);
}
@Override
public List<Marker> getMarkers() {
return null;
}
public List<Boat> getBoats() {
return boats;
}
public List<Leg> getLegs() {
return legs;
}
public ZonedDateTime getZonedDateTime() {
return RaceClock.getCurrentZonedDateTime(mark);
}
public GPSCoordinate getStartPt1() {
return startPt1;
}
public GPSCoordinate getStartPt2() {
return startPt2;
}
public GPSCoordinate getFinishPt1() {
return finishPt1;
}
public GPSCoordinate getFinishPt2() {
return finishPt2;
}
public GPSCoordinate getLeewardPt1() {
return leewardPt1;
}
public GPSCoordinate getLeewardPt2() {
return leewardPt2;
}
public GPSCoordinate getWindwardPt1() {
return windwardPt1;
}
public GPSCoordinate getWindwardPt2() {
return windwardPt2;
}
public List<GPSCoordinate> getBoundary() {
return boundary;
}
public GPSCoordinate getMapTopLeft() {
return mapTopLeft;
}
public GPSCoordinate getMapBottomRight() {
return mapBottomRight;
}
}

@ -1,4 +1,5 @@
package seng302;
import javafx.application.Platform;
import org.xml.sax.SAXException;
import seng302.Mock.*;
import seng302.Networking.BinaryMessageDecoder;
@ -10,7 +11,6 @@ import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -23,9 +23,6 @@ import static seng302.Networking.Utils.ByteConverter.bytesToShort;
*/
public class VisualiserInput implements Runnable {
///A queue that contains messages that have been received, and need to be handled.
private final ArrayBlockingQueue<AC35Data> messagesReceivedQueue = new ArrayBlockingQueue<>(1000000);//We have room for 1,000,000. Is this much capacity actually needed?
///Timestamp of the last heartbeat.
private long lastHeartbeatTime = -1;
///Sequence number of the last heartbeat.
@ -162,7 +159,7 @@ public class VisualiserInput implements Runnable {
* @throws IOException Thrown when an error occurs while reading from the socket.
*/
private byte[] getNextMessageBytes() throws IOException {
inStream.mark(0);
short CRCLength = 4;
short headerLength = 15;
@ -219,7 +216,7 @@ public class VisualiserInput implements Runnable {
//If no heartbeat has been received in more the heartbeat period
//then the connection will need to be restarted.
System.out.println("time since last heartbeat: " + timeSinceHeartbeat());//TEMP REMOVE
//System.out.println("time since last heartbeat: " + timeSinceHeartbeat());//TEMP REMOVE
long heartBeatPeriod = 10 * 1000;
if (timeSinceHeartbeat() > heartBeatPeriod) {
System.out.println("Connection has stopped, trying to reconnect.");
@ -256,12 +253,17 @@ public class VisualiserInput implements Runnable {
catch (InvalidMessageException | IOException e) {
//Prints exception to stderr, and iterate loop (that is, read the next message).
System.err.println("Unable to read message: " + e.getMessage());
try {
inStream.reset();
} catch (IOException e1) {
e1.printStackTrace();
}
//Continue to the next loop iteration/message.
continue;
}
}/*
//Add it to message queue.
this.messagesReceivedQueue.add(message);
this.messagesReceivedQueue.add(message);*/
//Checks which message is being received and does what is needed for that message.
@ -298,10 +300,12 @@ public class VisualiserInput implements Runnable {
//System.out.println("XML Message!");
Platform.runLater(()-> {
if (xmlMessage.getXmlMsgSubType() == XMLMessage.XMLTypeRegatta) {
//System.out.println("Setting Regatta");
try {
course.setRegattaXMLReader(new RegattaXMLReader(xmlMessage.getXmlMessage()));
}
//TODO REFACTOR should put all of these exceptions behind a RegattaXMLReaderException.
catch (IOException | SAXException | ParserConfigurationException e) {
@ -315,15 +319,14 @@ public class VisualiserInput implements Runnable {
course.setStreamedCourseXMLReader(new StreamedCourseXMLReader(xmlMessage.getXmlMessage()));
}
//TODO REFACTOR should put all of these exceptions behind a StreamedCourseXMLReaderException.
catch (IOException | SAXException | ParserConfigurationException | ParseException | StreamedCourseXMLException e) {
catch (IOException | SAXException | ParserConfigurationException | StreamedCourseXMLException e) {
System.err.println("Error creating StreamedCourseXMLReader: " + e.getMessage());
//Continue to the next loop iteration/message.
}
} else if (xmlMessage.getXmlMsgSubType() == XMLMessage.XMLTypeBoat) {
//System.out.println("Setting Boats");
try
{
try {
course.setBoatXMLReader(new BoatXMLReader(xmlMessage.getXmlMessage()));
}
//TODO REFACTOR should put all of these exceptions behind a BoatXMLReaderException.
@ -333,7 +336,7 @@ public class VisualiserInput implements Runnable {
}
}
});
}
//RaceStartStatus.
else if (message instanceof RaceStartStatus) {
@ -379,7 +382,6 @@ public class VisualiserInput implements Runnable {
//If the map _doesn't_ already contain a message for this boat, insert the message.
this.boatLocationMap.put(boatLocation.getSourceID(), boatLocation);
}
}
//MarkRounding.
else if (message instanceof MarkRounding) {

@ -42,7 +42,7 @@
<leg>
<name>Start to Mark 1</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
@ -51,29 +51,29 @@
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Mark 1 to Leeward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -82,13 +82,13 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Leeward Gate to Windward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -97,10 +97,10 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
@ -109,13 +109,13 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Windward Gate to Leeward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
@ -124,10 +124,10 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -136,13 +136,13 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Leeward Gate to Finish</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -151,10 +151,10 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
@ -163,7 +163,7 @@
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
</legs>
@ -214,7 +214,7 @@
<longitude>-64.849184</longitude>
</coordinate>
</boundaries>
<marker>
<compoundMark>
<name>Start Line</name>
<coordinate>
<latitude>32.296577</latitude>
@ -224,15 +224,15 @@
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Mark</name>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Windward Gate</name>
<coordinate>
<latitude>32.284680</latitude>
@ -242,8 +242,8 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Leeward Gate</name>
<coordinate>
<latitude>32.309693</latitude>
@ -253,8 +253,8 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Finish Line</name>
<coordinate>
<latitude>32.317379</latitude>
@ -264,6 +264,6 @@
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</compoundMark>
</course>
</race>

@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<SplitPane xmlns:fx="http://javafx.com/fxml/1" fx:id="race" dividerPositions="0.7" visible="false" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
xmlns="http://javafx.com/javafx/8" fx:controller="seng302.Controllers.RaceController">
<SplitPane fx:id="race" dividerPositions="0.7" 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>
<GridPane fx:id="canvasBase">
<columnConstraints>
@ -16,36 +18,25 @@
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Pane prefHeight="200.0" prefWidth="400.0" GridPane.halignment="LEFT" GridPane.valignment="TOP">
<Pane prefHeight="280.0" prefWidth="400.0" GridPane.halignment="LEFT" GridPane.valignment="TOP">
<children>
<Accordion>
<panes>
<TitledPane animated="false" text="Annotation Control">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="240.0" prefWidth="200.0">
<AnchorPane minHeight="0.0" minWidth="0.0">
<children>
<CheckBox fx:id="showBoatPath" mnemonicParsing="false" selected="true"
text="Show Boat Paths" AnchorPane.leftAnchor="0.0"
AnchorPane.topAnchor="104.0"/>
<CheckBox fx:id="showAnnotations" layoutX="-2.0" layoutY="14.0"
mnemonicParsing="false" selected="true"
text="Show Annotations" 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="26.0"/>
<CheckBox fx:id="showAbbrev" layoutY="61.0" mnemonicParsing="false"
selected="true" text="Show Boat Abbreviation"
AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="52.0"/>
<CheckBox fx:id="showSpeed" layoutY="90.0" mnemonicParsing="false"
selected="true" text="Show Boat Speed"
AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="78.0"/>
<Button fx:id="saveAnno" layoutX="11.0" layoutY="106.0" maxWidth="154.0"
mnemonicParsing="false" prefWidth="154.0" text="Save Annotation"
AnchorPane.topAnchor="130.0"/>
<Button fx:id="showSetAnno" layoutX="11.0" layoutY="139.0"
mnemonicParsing="false" text="Show Set Annotation"
AnchorPane.topAnchor="160.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="showSpeed" layoutY="90.0" mnemonicParsing="false" selected="true" text="Show Boat Speed" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="50.0" />
<CheckBox fx:id="showBoatPath" mnemonicParsing="false" selected="true" text="Show Boat Paths" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="75.0" />
<Separator prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="100.0" />
<Label text="Annotations" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="105.0" />
<RadioButton fx:id="hideAnnoRBTN" mnemonicParsing="false" text="Hidden" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="130.0" />
<RadioButton fx:id="showAnnoRBTN" mnemonicParsing="false" text="Visible" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="155.0" />
<RadioButton fx:id="partialAnnoRBTN" mnemonicParsing="false" text="Partial" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="180.0" />
<RadioButton fx:id="importantAnnoRBTN" mnemonicParsing="false" text="Important" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="205.0" />
<Button fx:id="saveAnno" layoutX="11.0" layoutY="106.0" maxWidth="154.0" mnemonicParsing="false" prefWidth="154.0" text="Save Important Annotations" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="230.0" />
</children>
</AnchorPane>
</content>
@ -54,9 +45,7 @@
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<CheckBox fx:id="showFPS" layoutX="-14.0" layoutY="13.0"
mnemonicParsing="false" selected="true" text="Show FPS"
AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0"/>
<CheckBox fx:id="showFPS" layoutX="-14.0" layoutY="13.0" mnemonicParsing="false" selected="true" text="Show FPS" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
@ -65,15 +54,12 @@
</Accordion>
</children>
</Pane>
<Label fx:id="timer" layoutX="45.0" layoutY="146.0" maxHeight="20.0" text="0:0"
AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0" GridPane.halignment="RIGHT"
GridPane.valignment="BOTTOM">
<Label fx:id="timer" layoutX="45.0" layoutY="146.0" maxHeight="20.0" text="0:0" AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0" GridPane.halignment="RIGHT" GridPane.valignment="BOTTOM">
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
<Label fx:id="FPS" text="FPS: 0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
<Label fx:id="FPS" text="FPS: 0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
<font>
<Font name="System Bold" size="15.0" />
</font>
@ -88,12 +74,9 @@
</Label>
</children>
</GridPane>
<AnchorPane layoutX="450.0" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="200.0"
GridPane.columnIndex="1">
<AnchorPane layoutX="450.0" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="200.0" GridPane.columnIndex="1">
<children>
<TableView fx:id="boatInfoTable" layoutX="-2.0" prefHeight="600.0" prefWidth="264.0"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="-2.0" AnchorPane.rightAnchor="-62.0"
AnchorPane.topAnchor="0.0">
<TableView fx:id="boatInfoTable" layoutX="-2.0" prefHeight="600.0" prefWidth="264.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="-2.0" AnchorPane.rightAnchor="-62.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="boatPlacingColumn" prefWidth="50.0" text="Place" />
<TableColumn fx:id="boatTeamColumn" prefWidth="100.0" text="Team" />

@ -1,47 +1,47 @@
package seng302.Mock;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
/**
* Created by jjg64 on 21/04/17.
*/
public class BoatsXMLTest {
private BoatXMLReader boatXMLReader;
@Before
public void setup() {
try {
boatXMLReader = new BoatXMLReader("mockXML/boatXML/boatTest.xml", false);
} catch (Exception e) {
e.printStackTrace();
//fail("Cannot find mockXML/raceXML/raceTest.xml in the resources folder");
}
}
@Test
public void testInvalidParticipant() {
Map<Integer, StreamedBoat> inputParticipants = new HashMap<>();
inputParticipants.put(420, new StreamedBoat(420));
boatXMLReader.setParticipants(inputParticipants);
boatXMLReader.read();
assertEquals(boatXMLReader.getBoats().size(), 0);
}
@Test
public void testValidParticipant() {
Map<Integer, StreamedBoat> inputParticipants = new HashMap<>();
inputParticipants.put(101, new StreamedBoat(101));
boatXMLReader.setParticipants(inputParticipants);
boatXMLReader.read();
assertEquals(boatXMLReader.getBoats().size(), 1);
StreamedBoat boat = (StreamedBoat) boatXMLReader.getBoats().get(0);
assertEquals(boat.getSourceID(), 101);
}
}
//package seng302.Mock;
//
//import org.junit.Before;
//import org.junit.Test;
//
//import java.util.HashMap;
//import java.util.Map;
//
//import static org.junit.Assert.assertEquals;
//
///**
// * Created by jjg64 on 21/04/17.
// */
//public class BoatsXMLTest {
// private BoatXMLReader boatXMLReader;
//
// @Before
// public void setup() {
// try {
// boatXMLReader = new BoatXMLReader("mockXML/boatXML/boatTest.xml", false);
// } catch (Exception e) {
// e.printStackTrace();
// //fail("Cannot find mockXML/raceXML/raceTest.xml in the resources folder");
// }
// }
//
// @Test
// public void testInvalidParticipant() {
// Map<Integer, StreamedBoat> inputParticipants = new HashMap<>();
// inputParticipants.put(420, new StreamedBoat(420));
// boatXMLReader.setParticipants(inputParticipants);
// boatXMLReader.read();
// assertEquals(boatXMLReader.getBoats().size(), 0);
// }
//
// @Test
// public void testValidParticipant() {
// Map<Integer, StreamedBoat> inputParticipants = new HashMap<>();
// inputParticipants.put(101, new StreamedBoat(101));
// boatXMLReader.setParticipants(inputParticipants);
// boatXMLReader.read();
// assertEquals(boatXMLReader.getBoats().size(), 1);
// StreamedBoat boat = (StreamedBoat) boatXMLReader.getBoats().get(0);
// assertEquals(boat.getSourceID(), 101);
// }
//
//}

@ -1,26 +1,26 @@
package seng302.Mock;
import org.junit.Test;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.text.ParseException;
/**
* Created by jjg64 on 1/05/17.
*/
public class FailBoatXMLTest {
private final String path = "mockXML/boatXML/";
@Test(expected = NumberFormatException.class)
public void invalidSourceID() throws SAXException, ParserConfigurationException, ParseException, IOException {
new BoatXMLReader(path + "invalidSourceID.xml");
}
@Test(expected = NullPointerException.class)
public void insufficientInformation() throws SAXException, ParserConfigurationException, ParseException, IOException {
new BoatXMLReader(path + "insufficientInformation.xml");
}
}
//package seng302.Mock;
//
//import org.junit.Test;
//import org.xml.sax.SAXException;
//
//import javax.xml.parsers.ParserConfigurationException;
//import java.io.IOException;
//import java.text.ParseException;
//
///**
// * Created by jjg64 on 1/05/17.
// */
//public class FailBoatXMLTest {
// private final String path = "mockXML/boatXML/";
//
// @Test(expected = NumberFormatException.class)
// public void invalidSourceID() throws SAXException, ParserConfigurationException, ParseException, IOException {
// new BoatXMLReader(path + "invalidSourceID.xml");
// }
//
// @Test(expected = NullPointerException.class)
// public void insufficientInformation() throws SAXException, ParserConfigurationException, ParseException, IOException {
// new BoatXMLReader(path + "insufficientInformation.xml");
// }
//
//}

@ -87,8 +87,8 @@ public class StreamedRaceTest {
GPSCoordinate topLeft = streamedCourseXMLReader.getMapTopLeft();
GPSCoordinate bottomRight = streamedCourseXMLReader.getMapBottomRight();
for(Marker marker: streamedCourseXMLReader.getMarkers()) {
GPSCoordinate centre = marker.getAverageGPSCoordinate();
for(Marker compoundMark : streamedCourseXMLReader.getMarkers()) {
GPSCoordinate centre = compoundMark.getAverageGPSCoordinate();
assertTrue(centre.getLatitude() < bottomRight.getLatitude());
assertTrue(centre.getLatitude() > topLeft.getLatitude());
assertTrue(centre.getLongitude() > bottomRight.getLongitude());

@ -17,8 +17,8 @@
// */
//public class ConstantVelocityRaceTest {
//
// Marker START_MARKER = new Marker(new GPSCoordinate(0, 0));
// Marker END_MARKER = new Marker(new GPSCoordinate(10, 10));
// CompoundMark START_MARKER = new CompoundMark(new GPSCoordinate(0, 0));
// CompoundMark END_MARKER = new CompoundMark(new GPSCoordinate(10, 10));
// Leg START_LEG = new Leg("Start", START_MARKER, END_MARKER, 0);
//
// int ONE_HOUR = 3600000; //1 hour in milliseconds

@ -2,28 +2,28 @@ package seng302.Model;
import org.geotools.referencing.GeodeticCalculator;
import org.junit.Test;
import seng302.Constants;
import seng302.GPSCoordinate;
import java.awt.geom.Point2D;
import static junit.framework.TestCase.assertEquals;
import static seng302.Model.Leg.NM_TO_METERS;
/**
* Created by esa46 on 22/03/17.
*/
public class LegTest {
private final Marker ORIGIN_MARKER = new Marker(new GPSCoordinate(0, 0));
private final Marker ORIGIN_Marker = new Marker(new GPSCoordinate(0, 0));
@Test
public void calculateDistanceHandles5nmNorth() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(0, 5 * Constants.NMToMetersConversion);
calc.setDirection(0, 5 * NM_TO_METERS);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
Leg test = new Leg("Test", ORIGIN_Marker, endMarker, 0);
assertEquals(test.getDistance(), 5, 1e-8);
}
@ -31,10 +31,10 @@ public class LegTest {
public void calculateDistanceHandles12nmEast() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(90, 12 * Constants.NMToMetersConversion);
calc.setDirection(90, 12 * NM_TO_METERS);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
Leg test = new Leg("Test", ORIGIN_Marker, endMarker, 0);
assertEquals(test.getDistance(), 12, 1e-8);
}
@ -42,10 +42,10 @@ public class LegTest {
public void calculateDistanceHandlesHalfnmSouth() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(180, 0.5 * Constants.NMToMetersConversion);
calc.setDirection(180, 0.5 * NM_TO_METERS);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
Leg test = new Leg("Test", ORIGIN_Marker, endMarker, 0);
assertEquals(test.getDistance(), 0.5, 1e-8);
}
@ -53,17 +53,17 @@ public class LegTest {
public void calculateDistanceHandlesPoint1nmWest() {
GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0);
calc.setDirection(-90, 0.1 * Constants.NMToMetersConversion);
calc.setDirection(-90, 0.1 * NM_TO_METERS);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint());
Leg test = new Leg("Test", ORIGIN_MARKER, endMarker, 0);
Leg test = new Leg("Test", ORIGIN_Marker, endMarker, 0);
assertEquals(test.getDistance(), 0.1, 1e-8);
}
@Test
public void calculateDistanceHandlesZeroDifference() {
Leg test = new Leg("Test", ORIGIN_MARKER, ORIGIN_MARKER, 0);
Leg test = new Leg("Test", ORIGIN_Marker, ORIGIN_Marker, 0);
assertEquals(test.getDistance(), 0, 1e-8);
}

@ -1,93 +0,0 @@
package seng302.Model;
/**
* Created by Gondr on 26/03/2017.
*/
import org.junit.Test;
import seng302.RaceXMLReader;
import java.util.List;
import static org.junit.Assert.*;
public class RaceXMLTest {
RaceXMLReader raceXMLReader;
@Test
public void canFindFile() {
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
} catch (Exception e) {
fail("Cannot find raceXML/bermuda_AC35.xml in the resources folder");
}
}
@Test
public void canReadBoats() {
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readBoats();
List<Boat> boats = raceXMLReader.getBoats();
assertTrue(boats.size() == 6);
//test boat 1
assertEquals(boats.get(0).getName().getValue(), "ORACLE TEAM USA");
assertTrue(boats.get(0).getVelocity() == 20);
//test boat 2
assertEquals(boats.get(1).getName().getValue(), "Land Rover BAR");
assertTrue(boats.get(1).getVelocity() == 30);
assertEquals(boats.get(1).getAbbrev(), "GBR");
//test boat 3
assertEquals(boats.get(2).getName().getValue(), "SoftBank Team Japan");
assertTrue(boats.get(2).getVelocity() == 25);
assertEquals(boats.get(2).getAbbrev(), "JPN");
//test boat 4
assertEquals(boats.get(3).getName().getValue(), "Groupama Team France");
assertTrue(boats.get(3).getVelocity() == 20);
assertEquals(boats.get(3).getAbbrev(), "FRA");
//test boat 5
assertEquals(boats.get(4).getName().getValue(), "Artemis Racing");
assertTrue(boats.get(4).getVelocity() == 29);
assertEquals(boats.get(4).getAbbrev(), "SWE");
//test boat 6
assertEquals(boats.get(5).getName().getValue(), "Emirates Team New Zealand");
assertTrue(boats.get(5).getVelocity() == 62);
assertEquals(boats.get(5).getAbbrev(), "NZL");
} catch (Exception e) {
fail("Boat Unreadable");
}
}
@Test
public void canReadLegs() {
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readLegs();
assertTrue(raceXMLReader.getLegs().size() == 5);
} catch (Exception e) {
fail("Legs Unreadable");
}
}
@Test
public void canReadCourse() {
try {
RaceXMLReader raceXMLReader = new RaceXMLReader("raceXML/bermuda_AC35.xml", false);
raceXMLReader.readCourse();
assertTrue(raceXMLReader.getMapTopLeft() != null);
assertTrue(raceXMLReader.getMapBottomRight() != null);
assertTrue(raceXMLReader.getFinishPt1() != null);
assertTrue(raceXMLReader.getFinishPt2() != null);
assertTrue(raceXMLReader.getStartPt1() != null);
assertTrue(raceXMLReader.getStartPt2() != null);
assertTrue(raceXMLReader.getLeewardPt1() != null);
assertTrue(raceXMLReader.getLeewardPt2() != null);
assertTrue(raceXMLReader.getWindwardPt1() != null);
assertTrue(raceXMLReader.getWindwardPt2() != null);
assertTrue(raceXMLReader.getBoundary().size() == 11);
} catch (Exception e) {
e.printStackTrace();
fail("Course Unreadable");
}
}
}

@ -41,7 +41,7 @@
<leg>
<name>Start to Mark 1</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
@ -50,29 +50,29 @@
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Mark 1 to Leeward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -81,13 +81,13 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Leeward Gate to Windward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -96,10 +96,10 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
@ -108,13 +108,13 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Windward Gate to Leeward Gate</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
@ -123,10 +123,10 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -135,13 +135,13 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
<leg>
<name>Leeward Gate to Finish</name>
<start>
<marker>
<compoundMark>
<coordinate>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
@ -150,10 +150,10 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
</compoundMark>
</start>
<finish>
<marker>
<compoundMark>
<coordinate>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
@ -162,7 +162,7 @@
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</compoundMark>
</finish>
</leg>
</legs>
@ -213,7 +213,7 @@
<longitude>-64.849184</longitude>
</coordinate>
</boundaries>
<marker>
<compoundMark>
<name>Start Line</name>
<coordinate>
<latitude>32.296577</latitude>
@ -223,15 +223,15 @@
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Mark</name>
<coordinate>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Windward Gate</name>
<coordinate>
<latitude>32.284680</latitude>
@ -241,8 +241,8 @@
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Leeward Gate</name>
<coordinate>
<latitude>32.309693</latitude>
@ -252,8 +252,8 @@
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</coordinate>
</marker>
<marker>
</compoundMark>
<compoundMark>
<name>Finish Line</name>
<coordinate>
<latitude>32.317379</latitude>
@ -263,6 +263,6 @@
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</coordinate>
</marker>
</compoundMark>
</course>
</race>

Loading…
Cancel
Save