Merge branch 'master' into submission

# Conflicts:
#	mock/src/main/java/seng302/Model/Race.java
#	mock/src/test/java/seng302/Model/RaceTest.java
#	visualiser/src/main/java/seng302/Model/ResizableRaceCanvas.java
main
Joseph Gardner 9 years ago
commit 5d34b49316

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

@ -3,16 +3,27 @@ package seng302;
import javafx.application.Application; import javafx.application.Application;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import seng302.DataInput.RaceDataSource; import seng302.DataInput.XMLReader;
import seng302.DataInput.RaceXMLReader;
import seng302.DataInput.RegattaDataSource;
import seng302.DataInput.RegattaXMLReader;
import seng302.Model.Event; import seng302.Model.Event;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; 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.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 { public class App extends Application {
@ -28,16 +39,36 @@ public class App extends Application {
@Override @Override
public void start(Stage primaryStage) { public void start(Stage primaryStage) {
try { try {
RaceDataSource raceData = new RaceXMLReader("raceXML/bermuda_AC35.xml");
RegattaDataSource regattaData = new RegattaXMLReader("mockXML/regattaTest.xml"); String regattaXML = readFile("mockXML/regattaTest.xml", StandardCharsets.UTF_8);
Event raceEvent = new Event(raceData, regattaData); 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(); raceEvent.start();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) { } catch (SAXException e) {
e.printStackTrace(); e.printStackTrace();
} catch (ParserConfigurationException e) { } catch (TransformerException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
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 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;
/**
* Created by cbt24 on 10/05/17.
*/
public interface BoatDataSource {
Map<Integer, Boat> getBoats();
Map<Integer, Mark> getMarkerBoats();
}

@ -0,0 +1,115 @@
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;
/**
* Created by cbt24 on 10/05/17.
*/
public class BoatXMLReader extends XMLReader implements BoatDataSource {
private final Map<Integer, Boat> boatMap = new HashMap<>();
private final Map<Integer, Mark> markerMap = new HashMap<>();
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();
}
}
public void read() {
readSettings();
readShapes();
readBoats();
}
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() {
}
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);
}
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));
}
}
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);
}
@Override
public Map<Integer, Boat> getBoats() {
return boatMap;
}
@Override
public Map<Integer, Mark> getMarkerBoats() {
return markerMap;
}
}

@ -2,10 +2,11 @@ package seng302.DataInput;
; ;
import seng302.Model.Boat; import seng302.Model.Boat;
import seng302.Model.CompoundMark;
import seng302.Model.GPSCoordinate; import seng302.Model.GPSCoordinate;
import seng302.Model.Leg; import seng302.Model.Leg;
import seng302.Model.Marker;
import java.time.ZonedDateTime;
import java.util.List; import java.util.List;
/** /**
@ -18,13 +19,13 @@ public interface RaceDataSource {
List<GPSCoordinate> getBoundary(); List<GPSCoordinate> getBoundary();
List<Marker> getMarkers(); List<CompoundMark> getCompoundMarks();
int getRaceId(); int getRaceId();
String getRaceType(); String getRaceType();
GPSCoordinate getMark(); ZonedDateTime getZonedDateTime();
GPSCoordinate getMapTopLeft(); GPSCoordinate getMapTopLeft();

@ -1,373 +1,274 @@
package seng302.DataInput; package seng302.DataInput;
import javafx.scene.paint.Color;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import seng302.Exceptions.StreamedCourseXMLException;
import seng302.Model.Boat; import seng302.Model.*;
import seng302.Model.GPSCoordinate;
import seng302.Model.Leg;
import seng302.Model.Marker;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.text.ParseException;
import java.util.List; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/** /**
* Created by fwy13 on 26/03/2017. * Created by jjg64 on 21/04/17.
*/ */
public class RaceXMLReader extends XMLReader implements RaceDataSource { public class RaceXMLReader extends XMLReader implements RaceDataSource {
private static double COORDINATEPADDING = 0.0005; private static final double COORDINATEPADDING = 0.000;
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 GPSCoordinate mapTopLeft, mapBottomRight; private GPSCoordinate mapTopLeft, mapBottomRight;
private List<GPSCoordinate> boundary = new ArrayList<>(); private final List<GPSCoordinate> boundary = new ArrayList<>();
private List<Marker> markers = 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 * @param filePath path of the file
* @throws IOException error * @throws IOException error
* @throws SAXException error * @throws SAXException error
* @throws ParserConfigurationException error * @throws ParserConfigurationException error
* @throws ParseException error
* @throws StreamedCourseXMLException error
*/ */
public RaceXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException { public RaceXMLReader(String filePath, BoatDataSource boatData) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
this(filePath, true); this(filePath, boatData, true);
} }
/** /**
* COnstructor for Race XML * Constructor for Streamed Race XML
*
* @param filePath file path to read * @param filePath file path to read
* @param read whether or not to read and store the files straight away. * @param read whether or not to read and store the files straight away.
* @throws IOException error * @throws IOException error
* @throws SAXException error * @throws SAXException error
* @throws ParserConfigurationException 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); super(filePath);
this.boats = boatData.getBoats();
this.marks = boatData.getMarkerBoats();
if (read) { if (read) {
read(); read();
} }
} }
/** /**
* Read the files * reads
* @throws StreamedCourseXMLException error
*/ */
private void read() { private void read() throws StreamedCourseXMLException {
readRace();
readParticipants();
readCourse(); readCourse();
readID();
readLegs();
readMarkers();
readBoats();
} }
/** /**
* Read in race ID from XML object. * reads a race
*/ */
public void readID() { private void readRace() {
NodeList race = doc.getElementsByTagName("race"); DateTimeFormatter dateFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
raceID = Integer.parseInt(getTextValueOfNode((Element) race.item(0), "raceId")); Element settings = (Element) doc.getElementsByTagName("Race").item(0);
} NamedNodeMap raceTimeTag = doc.getElementsByTagName("RaceStartTime").item(0).getAttributes();
/** if (raceTimeTag.getNamedItem("Time") != null) dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
* 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"));
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"));
* Read all the boats in the XML file raceType = getTextValueOfNode(settings, "RaceType");
*/
public void readMarkers() {
//get all boats
NodeList nMarkers = doc.getElementsByTagName("marker");
for (int i = 0; i < nMarkers.getLength(); i++) { creationTimeDate = ZonedDateTime.parse(getTextValueOfNode(settings, "CreationTimeDate"), dateFormat);
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);
* Read all the legs in the XML file else raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Start").getTextContent(), dateFormat);
*/
public void readLegs() { postpone = Boolean.parseBoolean(raceTimeTag.getNamedItem("Postpone").getTextContent());
//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() {
* Read courses in XML file Element nParticipants = (Element) doc.getElementsByTagName("Participants").item(0);
*/ nParticipants.getChildNodes().getLength();
public void readCourse() { for (int i = 0; i < nParticipants.getChildNodes().getLength(); i++) {
NodeList nCourse = doc.getElementsByTagName("course"); int sourceID;
Node yacht = nParticipants.getChildNodes().item(i);
NodeList nBounds = ((Element) nCourse.item(0)).getElementsByTagName("boundaries"); if (yacht.getNodeName().equals("Yacht")) {
nBounds = ((Element) nBounds.item(0)).getElementsByTagName("coordinate"); if (exists(yacht, "SourceID")) {
int maxLatitudeIndex = 0; sourceID = Integer.parseInt(yacht.getAttributes().getNamedItem("SourceID").getTextContent());
double maxLatitude = -Double.MIN_VALUE; participants.put(sourceID, boats.get(sourceID));
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 * reads a course
* * @throws StreamedCourseXMLException error
* @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) { private void readCourse() throws StreamedCourseXMLException {
return getMarker(start, startIndex, 0); readCompoundMarks();
readCompoundMarkSequence();
readCourseLimit();
} }
/** /**
* gets a marker from the XML file * Indexes CompoundMark elements by their ID for use in generating the course, and populates list of Markers.
* * @see CompoundMark
* @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) { private void readCompoundMarks() throws StreamedCourseXMLException {
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("marker"); Element nCourse = (Element) doc.getElementsByTagName("Course").item(0);
Element marker = (Element) nodeList.item(nodeIndex); for(int i = 0; i < nCourse.getChildNodes().getLength(); i++) {
return getMarker(marker); 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 * Generates a CompoundMark from the CompoundMark element with given ID.
* * @param compoundMarkID index of required CompoundMark element
* @param markerNode marker to turn into coordinates * @return generated CompoundMark
* @return * @throws StreamedCourseXMLException if CompoundMark element contains unhandled number of compoundMarks
* @see CompoundMark
*/ */
private Marker getMarker(Element markerNode) { private CompoundMark getCompoundMark(int compoundMarkID) throws StreamedCourseXMLException {
Element compoundMark = compoundMarkMap.get(compoundMarkID);
NodeList nCoordinates = markerNode.getElementsByTagName("coordinate"); NodeList nMarks = compoundMark.getElementsByTagName("Mark");
CompoundMark marker;
GPSCoordinate side1 = getCoordinates((Element) nCoordinates.item(0));
GPSCoordinate side2; switch(nMarks.getLength()) {
if (nCoordinates.getLength() > 1) { case 1: marker = new CompoundMark(getMark((Element)nMarks.item(0)));
side2 = getCoordinates((Element) nCoordinates.item(1)); break;
} else { case 2: marker = new CompoundMark(getMark((Element)nMarks.item(0)), getMark((Element)nMarks.item(1))); break;
side2 = side1; 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;
} }
/** private Mark getMark(Element mark) {
* gets a coordinates from the XML file int sourceID = Integer.parseInt(mark.getAttribute("SourceID"));
* return marks.get(sourceID);
* @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 * Reads "compoundMarkID" attribute of CompoundMark or Corner element
* * @param element with "compoundMarkID" attribute
* @param start base nodelist this should be the tag that contains <coordinate></coordinate> * @return value of "compoundMarkID" attribute
* @param startIndex the index the tag containing the coordinate should be in
* @return
*/ */
private GPSCoordinate getCoordinates(NodeList start, int startIndex) { private int getCompoundMarkID(Element element) {
return getCoordinates(start, startIndex, 0); return Integer.parseInt(element.getAttribute("CompoundMarkID"));
} }
/** /**
* gets a coordinates from the XML file * Reads "name" attribute of CompoundMark element with corresponding CompoundMarkID
* * @param compoundMarkID unique ID for CompoundMark element
* @param start base nodelist this should be the tag that contains <coordinate></coordinate> * @return value of "name" attribute
* @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) { private String getCompoundMarkName(int compoundMarkID) {
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("coordinate"); return compoundMarkMap.get(compoundMarkID).getAttribute("Name");
Element coord = (Element) nodeList.item(nodeIndex);
return getCoordinates(coord);
} }
/** /**
* Returns the coordinate TODO raise exception that runs when the XML is formatted wrongly. * Populates list of legs given CompoundMarkSequence element and referenced CompoundMark elements.
* * @throws StreamedCourseXMLException if compoundMarks cannot be resolved from CompoundMark
* @param coordNode
* @return
*/ */
private GPSCoordinate getCoordinates(Element coordNode) { private void readCompoundMarkSequence() throws StreamedCourseXMLException {
Element nCompoundMarkSequence = (Element) doc.getElementsByTagName("CompoundMarkSequence").item(0);
double startLat = Double.parseDouble(getTextValueOfNode(coordNode, "latitude")); NodeList nCorners = nCompoundMarkSequence.getElementsByTagName("Corner");
double startLong = Double.parseDouble(getTextValueOfNode(coordNode, "longitude")); Element markXML = (Element)nCorners.item(0);
return new GPSCoordinate(startLat, startLong); CompoundMark lastCompoundMark = getCompoundMark(getCompoundMarkID(markXML));
} String legName = getCompoundMarkName(getCompoundMarkID(markXML));
for(int i = 1; i < nCorners.getLength(); i++) {
public List<Boat> getBoats() { markXML = (Element)nCorners.item(i);
return boats; CompoundMark currentCompoundMark = getCompoundMark(getCompoundMarkID(markXML));
} legs.add(new Leg(legName, lastCompoundMark, currentCompoundMark, i-1));
lastCompoundMark = currentCompoundMark;
public List<Leg> getLegs() { legName = getCompoundMarkName(getCompoundMarkID(markXML));
return legs; }
}
public GPSCoordinate getMark() {
return mark;
} }
public GPSCoordinate getStartPt1() { private void readCourseLimit() {
return startPt1; 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 getStartPt2() { double maxLatitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING;
return startPt2; 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() { mapTopLeft = new GPSCoordinate(minLatitude, minLongitude);
return finishPt1; mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude);
} }
public GPSCoordinate getFinishPt2() { public List<GPSCoordinate> getBoundary() {
return finishPt2; return boundary;
} }
public GPSCoordinate getLeewardPt1() { public GPSCoordinate getMapTopLeft() {
return leewardPt1; return mapTopLeft;
} }
public GPSCoordinate getLeewardPt2() { public GPSCoordinate getMapBottomRight() {
return leewardPt2; return mapBottomRight;
} }
public GPSCoordinate getWindwardPt1() { public List<Leg> getLegs() {
return windwardPt1; return legs;
} }
public GPSCoordinate getWindwardPt2() { public List<CompoundMark> getCompoundMarks() { return compoundMarks; }
return windwardPt2;
}
public List<GPSCoordinate> getBoundary() { public Double getPadding() {
return boundary; return COORDINATEPADDING;
} }
public GPSCoordinate getMapTopLeft() { public ZonedDateTime getCreationTimeDate() {
return mapTopLeft; return creationTimeDate;
} }
public GPSCoordinate getMapBottomRight() { public ZonedDateTime getZonedDateTime() {
return mapBottomRight; return raceStartTime;
} }
public int getRaceId() { public int getRaceId() {
return raceID; return raceID;
} }
public List<Marker> getMarkers() { public String getRaceType() {
return markers; return raceType;
} }
public String getRaceType() { public boolean isPostpone() {
return "FLEET"; return postpone;
}
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,13 +2,20 @@ package seng302.DataInput;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
/** /**
* Created by fwy13 on 26/03/2017. * Created by fwy13 on 26/03/2017.
@ -25,13 +32,26 @@ public abstract class XMLReader {
* @throws SAXException * @throws SAXException
*/ */
public XMLReader(String filePath) throws ParserConfigurationException, IOException, SAXException { 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(); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
doc = dBuilder.parse(fXmlFile); doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize(); doc.getDocumentElement().normalize();
} }
public XMLReader(String xmlFile, Boolean isWholeFile) {
}
/** /**
* Return Document data of the read-in XML * Return Document data of the read-in XML
* @return XML document * @return XML document
@ -60,4 +80,23 @@ public abstract class XMLReader {
return n.getAttribute(attr); return n.getAttribute(attr);
} }
protected boolean exists(Node node, String attribute) {
return node.getAttributes().getNamedItem(attribute) != null;
}
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 {
}

@ -10,7 +10,7 @@ public class Boat {
private String name; private String name;
private double velocity; private double velocity;
private double scaledVelocity; private double scaledVelocity;
private String abbrev; private String country;
private int sourceID; private int sourceID;
private Leg currentLeg; private Leg currentLeg;
private double distanceTravelledInLeg; private double distanceTravelledInLeg;
@ -22,14 +22,12 @@ public class Boat {
/** /**
* Boat initialiser which keeps all of the information of the 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 sourceID id of boat
* @param name Name of the Boat.
* @param country nam abbreviation
*/ */
public Boat(String name, double velocity, String abbrev, int sourceID) { public Boat(int sourceID, String name, String country) {
this.velocity = velocity; this.country = this.country;
this.abbrev = abbrev;
this.name = name; this.name = name;
this.sourceID = sourceID; this.sourceID = sourceID;
} }
@ -42,8 +40,8 @@ public class Boat {
public double calculateAzimuth() { public double calculateAzimuth() {
GeodeticCalculator calc = new GeodeticCalculator(); GeodeticCalculator calc = new GeodeticCalculator();
GPSCoordinate start = currentLeg.getStartMarker().getAverageGPSCoordinate(); GPSCoordinate start = currentLeg.getStartCompoundMark().getAverageGPSCoordinate();
GPSCoordinate end = currentLeg.getEndMarker().getAverageGPSCoordinate(); GPSCoordinate end = currentLeg.getEndCompoundMark().getAverageGPSCoordinate();
calc.setStartingGeographicPoint(start.getLongitude(), start.getLatitude()); calc.setStartingGeographicPoint(start.getLongitude(), start.getLatitude());
calc.setDestinationGeographicPoint(end.getLongitude(), end.getLatitude()); calc.setDestinationGeographicPoint(end.getLongitude(), end.getLatitude());
@ -90,12 +88,12 @@ public class Boat {
this.scaledVelocity = scaledVelocity; this.scaledVelocity = scaledVelocity;
} }
public String getAbbrev() { public String getCountry() {
return abbrev; return country;
} }
public void setAbbrev(String abbrev) { public void setCountry(String country) {
this.abbrev = abbrev; this.country = country;
} }
public int getSourceID() { public int getSourceID() {

@ -0,0 +1,61 @@
package seng302.Model;
import org.geotools.referencing.GeodeticCalculator;
import java.awt.geom.Point2D;
/**
* Created by esa46 on 29/03/17.
*/
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,16 +1,16 @@
package seng302.Model; package seng302.Model;
import seng302.Data.BoatData; import org.xml.sax.SAXException;
import seng302.Data.RaceData; import seng302.DataInput.*;
import seng302.Data.RegattaData; import seng302.Exceptions.StreamedCourseXMLException;
import seng302.DataInput.RaceDataSource;
import seng302.DataInput.RegattaDataSource;
import seng302.Exceptions.InvalidBoatDataException;
import seng302.Exceptions.InvalidRaceDataException;
import seng302.Exceptions.InvalidRegattaDataException;
import seng302.MockOutput; 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;
/** /**
@ -18,14 +18,16 @@ import java.io.IOException;
*/ */
public class Event { public class Event {
RaceDataSource raceDataSource; String raceXML;
RegattaDataSource regattaDataSource; String regattaXML;
String boatXML;
MockOutput mockOutput; MockOutput mockOutput;
public Event(RaceDataSource raceData, RegattaDataSource regattaData) { public Event(String raceXML, String regattaXML, String boatXML) {
this.raceDataSource = raceData;
this.regattaDataSource = regattaData; this.raceXML = getRaceXMLAtCurrentTime(raceXML);
this.boatXML = boatXML;
this.regattaXML = regattaXML;
try { try {
mockOutput = new MockOutput(); mockOutput = new MockOutput();
new Thread(mockOutput).start(); 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() { public void start() {
System.out.println("Sending Regatta"); try {
sendRegattaData(); sendXMLs();
System.out.println("Sending Race"); Race newRace = new Race(new RaceXMLReader(this.raceXML, new BoatXMLReader(boatXML)), mockOutput);
sendRaceData(); new Thread((newRace)).start();
System.out.println("Sending Boat");
sendBoatData();
int scaleFactor = 5;//TEMP - was 15. } catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
Race newRace = new Race(raceDataSource, scaleFactor, mockOutput); e.printStackTrace();
new Thread((newRace)).start(); }
} }
/** /**
* Send XML string of initial regatta data to the visualiser * Sends out each xml string, via the mock output
* @throws InvalidRegattaDataException Invalid regatta
*/ */
public void sendRegattaData() throws InvalidRegattaDataException { private void sendXMLs() {
System.setOut(System.out); mockOutput.setRegattaXml(regattaXML);
RegattaData regattaData = new RegattaData(regattaDataSource); mockOutput.parseXMLString(regattaXML, MessageType.XMLMESSAGE.getValue());
String xmlString = regattaData.createXML();
mockOutput.setRegattaXml(xmlString);
mockOutput.parseXMLString(xmlString, 26);
} mockOutput.setRaceXml(raceXML);
mockOutput.parseXMLString(raceXML, MessageType.XMLMESSAGE.getValue());
/** mockOutput.setBoatsXml(boatXML);
* Send XML string of initial race data to the visualiser mockOutput.parseXMLString(boatXML, MessageType.XMLMESSAGE.getValue());
* @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);
} }
/** /**
* Send XML string of initial boat data to the visualiser * Sets the xml description of the race to show the race was created now, and starts in 3 minutes
* @throws InvalidBoatDataException Invalid boat * @param raceXML
* @return String containing edited xml
*/ */
public void sendBoatData() throws InvalidBoatDataException { private String getRaceXMLAtCurrentTime(String raceXML) {
BoatData boatData = new BoatData(raceDataSource.getBoats()); DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
//Serialize race data to an XML as a string. ZonedDateTime creationTime = ZonedDateTime.now();
String xmlString = boatData.createXML(); return raceXML.replace("CREATION_TIME", dateFormat.format(creationTime))
mockOutput.setBoatsXml(xmlString); .replace("START_TIME", dateFormat.format(creationTime.plusMinutes(3)));
mockOutput.parseXMLString(xmlString, 26);
} }
} }

@ -10,8 +10,8 @@ import seng302.Constants;
public class Leg { public class Leg {
private String name; //nautical miles private String name; //nautical miles
private double distance; private double distance;
private Marker startMarker; private Marker startCompoundMark;
private Marker endMarker; private Marker endCompoundMark;
private int legNumber; private int legNumber;
/** /**
@ -24,8 +24,8 @@ public class Leg {
*/ */
public Leg(String name, Marker start, Marker end, int number) { public Leg(String name, Marker start, Marker end, int number) {
this.name = name; this.name = name;
this.startMarker = start; this.startCompoundMark = start;
this.endMarker = end; this.endCompoundMark = end;
this.legNumber = number; this.legNumber = number;
calculateDistance(); calculateDistance();
} }
@ -69,20 +69,20 @@ public class Leg {
} }
public Marker getStartMarker() { public Marker getStartCompoundMark() {
return startMarker; return startCompoundMark;
} }
public void setStartMarker(Marker startMarker) { public void setStartCompoundMark(Marker startCompoundMark) {
this.startMarker = startMarker; this.startCompoundMark = startCompoundMark;
} }
public Marker getEndMarker() { public Marker getEndCompoundMark() {
return endMarker; return endCompoundMark;
} }
public void setEndMarker(Marker endMarker) { public void setEndCompoundMark(Marker endCompoundMark) {
this.endMarker = endMarker; this.endCompoundMark = endCompoundMark;
} }
/** /**
@ -92,8 +92,8 @@ public class Leg {
GeodeticCalculator calc = new GeodeticCalculator(); GeodeticCalculator calc = new GeodeticCalculator();
//Load start and end of leg //Load start and end of leg
GPSCoordinate startMarker = this.startMarker.getAverageGPSCoordinate(); GPSCoordinate startMarker = this.startCompoundMark.getAverageGPSCoordinate();
GPSCoordinate endMarker = this.endMarker.getAverageGPSCoordinate(); GPSCoordinate endMarker = this.endCompoundMark.getAverageGPSCoordinate();
calc.setStartingGeographicPoint(startMarker.getLongitude(), startMarker.getLatitude()); calc.setStartingGeographicPoint(startMarker.getLongitude(), startMarker.getLatitude());
calc.setDestinationGeographicPoint(endMarker.getLongitude(), endMarker.getLatitude()); calc.setDestinationGeographicPoint(endMarker.getLongitude(), endMarker.getLatitude());
this.distance = calc.getOrthodromicDistance() / Constants.NMToMetersConversion; this.distance = calc.getOrthodromicDistance() / Constants.NMToMetersConversion;

@ -0,0 +1,28 @@
package seng302.Model;
/**
* Created by cbt24 on 10/05/17.
*/
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;
}
}

@ -1,12 +1,10 @@
package seng302.Model; package seng302.Model;
import javafx.animation.AnimationTimer; import javafx.animation.AnimationTimer;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import org.geotools.referencing.GeodeticCalculator; import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants; import seng302.Constants;
import seng302.DataInput.RaceDataSource; import seng302.DataInput.RaceDataSource;
import seng302.MockOutput; import seng302.MockOutput;
@ -19,289 +17,174 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
/** /**
* Parent class for races * Parent class for races
* Created by fwy13 on 3/03/17. * Created by fwy13 on 3/03/17.
*/ */
public class Race implements Runnable { public class Race implements Runnable {
//protected Boat[] startingBoats;
protected ObservableList<Boat> startingBoats; protected ObservableList<Boat> startingBoats;
protected ObservableList<CompoundMark> compoundMarks;
protected List<Leg> legs; protected List<Leg> legs;
protected int boatsFinished = 0; protected int boatsFinished = 0;
protected long totalTimeElapsed; protected long totalTimeElapsed;
protected int scaleFactor=25; protected int scaleFactor = 3;
protected int PRERACE_TIME = 180000; //time in milliseconds to pause during pre-race. At the moment, 3 minutes
private long startTime; private long startTime;
protected boolean countdownFinish = false;
protected boolean runRace = true;
private int lastFPS = 20;
private int raceId; private int raceId;
private int dnfChance = 0; //percentage chance a boat fails at each checkpoint private int dnfChance = 0; //percentage chance a boat fails at each checkpoint
private MockOutput mockOutput; private MockOutput mockOutput;
private static int boatOffset = 0;
private int finished = 0;
private int windDir;
private int changeWindChance = 4;
/**
* 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); public Race(RaceDataSource raceData, MockOutput mockOutput) {
this.legs = legs; 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.legs.add(new Leg("Finish", this.legs.size()));
this.raceId = raceID; this.raceId = raceData.getRaceId();
this.scaleFactor = scaleFactor;
this.mockOutput = mockOutput; this.mockOutput = mockOutput;
this.startTime = System.currentTimeMillis() + (Constants.PRE_RACE_WAIT_TIME / this.scaleFactor);
//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());
} }
/** /**
* Runnable for the thread. * Runnable for the thread.
*/ */
public void run() { public void run() {
initialiseWindDir();
initialiseBoats(); initialiseBoats();
countdownTimer(); countdownTimer.start();
}
/**
* Initiate a random wind direction
*/
protected void initialiseWindDir(){
windDir = (int) new Random().nextInt(65535+1);
} }
/** /**
* Changes the wind direction. Checks to make sure wind direction is between 0 - 65535 * Parse the marker boats through mock output
*/ */
protected void changeWindDir(){ public void parseMarks() {
int r = new Random().nextInt(changeWindChance) + 1; for (CompoundMark mark : compoundMarks){
if (r == 1){ mockOutput.parseBoatLocation(mark.getMark1Source().getSourceID(), mark.getMark1().getLatitude(), mark.getMark1().getLongitude(),0,0);
windDir+=100; if (mark.getMark2Source()!=null){
} else if (r == 2) { mockOutput.parseBoatLocation(mark.getMark2Source().getSourceID(), mark.getMark2().getLatitude(), mark.getMark2().getLongitude(),0,0);
windDir-=100; }
}
if (windDir > 65535){
windDir -= 65535;
}
if (windDir < 0){
windDir += 65535;
} }
} }
protected void setWindDir(int windDir){
this.windDir = windDir;
}
protected void setWindChangeChance(int windChance){
this.changeWindChance = windChance;
}
protected int getWindDir(){
return this.windDir;
}
/**
* Starts the heartbeat timer, which sends a heartbeat message every so often (i.e., 5 seconds).
*/
/** /**
* Countdown timer until race starts. Use PRERACE_TIME to set countdown duration. * Countdown timer until race starts.
*/ */
protected void countdownTimer() {
AnimationTimer timer = 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()));
}
}
boatOffset = (boatOffset + 1) % (startingBoats.size());
if (timeLeft <= 60000/scaleFactor && timeLeft > 0) { protected AnimationTimer countdownTimer = new AnimationTimer() {
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 2, startTime, windDir, 2300, 1, boatStatuses); long currentTime = System.currentTimeMillis();
mockOutput.parseRaceStatus(raceStatus); long timeLeft;
} @Override
else if (timeLeft <= 0) { public void handle(long arg0) {
countdownFinish = true; timeLeft = startTime - currentTime;
if (runRace) { if (timeLeft <= 0) {
simulateRace(); System.setProperty("javafx.animation.fullspeed", "true");
} raceTimer.start();
stop(); stop();
}
else {
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 1, startTime, windDir, 2300,1, boatStatuses);
mockOutput.parseRaceStatus(raceStatus);
}
currentTime = System.currentTimeMillis();
} }
};
timer.start();
//countdownFinish = true;
}
/** ArrayList<BoatStatus> boatStatuses = new ArrayList<>();
* Starts the Race Simulation, playing the race start to finish with the timescale. for (Boat boat : startingBoats) {
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events. mockOutput.parseBoatLocation(boat.getSourceID(), boat.getCurrentPosition().getLatitude(),
*/ boat.getCurrentPosition().getLongitude(), boat.getHeading(), 0);
private void simulateRace() { boatStatuses.add(new BoatStatus(boat.getSourceID(), BoatStatusEnum.PRESTART, 0));
}
parseMarks();
System.setProperty("javafx.animation.fullspeed", "true"); 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);
for (Boat boat : startingBoats) { currentTime = System.currentTimeMillis();
boat.setStarted(true);
} }
};
new AnimationTimer() { private AnimationTimer raceTimer = new AnimationTimer() {
//Start time of loop. //Start time of loop.
long timeRaceStarted = System.currentTimeMillis(); long timeRaceStarted = System.currentTimeMillis();
int boatOffset = 0;
@Override
public void handle(long arg0) { @Override
System.out.println(windDir); public void handle(long arg0) {
if (boatsFinished < startingBoats.size()) { if (boatsFinished < startingBoats.size()) {
//Get the current time. //Get the current time.
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
//Update the total elapsed time. //Update the total elapsed time.
totalTimeElapsed = currentTime - timeRaceStarted; totalTimeElapsed = currentTime - timeRaceStarted;
ArrayList<BoatStatus> boatStatuses = new ArrayList<BoatStatus>(); ArrayList<BoatStatus> boatStatuses = new ArrayList<>();
finished = 0; //For each boat, we update its position, and generate a BoatLocationMessage.
//For each boat, we update it's position, and generate a BoatLocationMessage. for (int i = 0; i < startingBoats.size(); i++) {
for (int i = 0; i < startingBoats.size(); i++) { Boat boat = startingBoats.get((i + boatOffset) % startingBoats.size());
Boat boat = startingBoats.get((i + boatOffset) % startingBoats.size()); if (boat != null) {
if (boat != null) { //Update position.
//Update position. if (boat.getTimeFinished() < 0) {
if (boat.getTimeFinished() < 0) { updatePosition(boat, 15);
updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS)); checkPosition(boat, totalTimeElapsed);
checkPosition(boat, totalTimeElapsed); }
} if (boat.getTimeFinished() > 0) {
if (boat.getTimeFinished() > 0) { mockOutput.parseBoatLocation(boat.getSourceID(), boat.getCurrentPosition().getLatitude(), boat.getCurrentPosition().getLongitude(), boat.getHeading(), boat.getVelocity());
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()));
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, windDir, 2300, 2, boatStatuses);//TODO FIX the second currentTime is a placeholder! Also, replace magic values.
mockOutput.parseRaceStatus(raceStatus);
}
} else { } else {
stop(); 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()));
} }
} else {
stop();
} }
boatOffset = (boatOffset + 1) % (startingBoats.size());
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 3, startTime, windDir, 2300, 2, boatStatuses);//TODO FIX the second currentTime is a placeholder! Also, replace magic values.
mockOutput.parseRaceStatus(raceStatus);
} }
changeWindDir(); parseMarks();
boatOffset = (boatOffset + 1) % (startingBoats.size());
RaceStatus raceStatus = new RaceStatus(System.currentTimeMillis(), raceId, 3, startTime, 0, 2300, 2, boatStatuses);
mockOutput.parseRaceStatus(raceStatus);
} }
}.start(); }
} };
public void initialiseBoats() { public void initialiseBoats() {
Leg officialStart = legs.get(0); Leg officialStart = legs.get(0);
String name = officialStart.getName(); 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++) { for (int i = 0; i < startingBoats.size(); i++) {
Boat boat = startingBoats.get(i); Boat boat = startingBoats.get(i);
if (boat != null) { 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); boat.setScaledVelocity(boat.getVelocity() * scaleFactor);
Leg startLeg = new Leg(name, 0); boat.setCurrentPosition(startingPositions.get(i));
boat.setCurrentPosition(startMarkers.get(i).getAverageGPSCoordinate());
startLeg.setStartMarker(startMarkers.get(i));
startLeg.setEndMarker(endMarker);
startLeg.calculateDistance();
boat.setCurrentLeg(startLeg);
boat.setHeading(boat.calculateHeading()); boat.setHeading(boat.calculateHeading());
} }
} }
} }
/** /**
* Creates a list of starting positions for the different boats, so they do not appear cramped at the start line * 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 * @return list of starting positions
*/ */
public ArrayList<Marker> getSpreadStartingPositions() { public ArrayList<GPSCoordinate> getSpreadStartingPositions() {
int nBoats = startingBoats.size(); int nBoats = startingBoats.size();
Marker marker = legs.get(0).getStartMarker(); Marker compoundMark = legs.get(0).getStartCompoundMark();
GeodeticCalculator initialCalc = new GeodeticCalculator(); GeodeticCalculator initialCalc = new GeodeticCalculator();
initialCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); initialCalc.setStartingGeographicPoint(compoundMark.getMark1().getLongitude(), compoundMark.getMark1().getLatitude());
initialCalc.setDestinationGeographicPoint(marker.getMark2().getLongitude(), marker.getMark2().getLatitude()); initialCalc.setDestinationGeographicPoint(compoundMark.getMark2().getLongitude(), compoundMark.getMark2().getLatitude());
double azimuth = initialCalc.getAzimuth(); double azimuth = initialCalc.getAzimuth();
double distanceBetweenMarkers = initialCalc.getOrthodromicDistance(); double distanceBetweenMarkers = initialCalc.getOrthodromicDistance();
double distanceBetweenBoats = distanceBetweenMarkers / (nBoats + 1); double distanceBetweenBoats = distanceBetweenMarkers / (nBoats + 1);
GeodeticCalculator positionCalc = new GeodeticCalculator(); GeodeticCalculator positionCalc = new GeodeticCalculator();
positionCalc.setStartingGeographicPoint(marker.getMark1().getLongitude(), marker.getMark1().getLatitude()); positionCalc.setStartingGeographicPoint(compoundMark.getMark1().getLongitude(), compoundMark.getMark1().getLatitude());
ArrayList<Marker> positions = new ArrayList<>(); ArrayList<GPSCoordinate> positions = new ArrayList<>();
for (int i = 0; i < nBoats; i++) { for (int i = 0; i < nBoats; i++) {
positionCalc.setDirection(azimuth, distanceBetweenBoats); positionCalc.setDirection(azimuth, distanceBetweenBoats);
Point2D position = positionCalc.getDestinationGeographicPoint(); 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 = new GeodeticCalculator();
positionCalc.setStartingGeographicPoint(position); positionCalc.setStartingGeographicPoint(position);
@ -310,19 +193,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) { public static GPSCoordinate calculatePosition(GPSCoordinate oldCoordinates, double distanceTravelled, double azimuth) {
if (chance >= 0 && chance <= 100) {
dnfChance = chance;
}
}
protected boolean doNotFinish() { //Find new coordinate using current heading and distance
Random rand = new Random(); GeodeticCalculator geodeticCalculator = new GeodeticCalculator();
return rand.nextInt(100) < dnfChance; //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());
} }
/** /**
@ -335,7 +225,6 @@ public class Race implements Runnable {
//distanceTravelled = velocity (nm p hr) * time taken to update loop //distanceTravelled = velocity (nm p hr) * time taken to update loop
double distanceTravelled = (boat.getScaledVelocity() * millisecondsElapsed) / 3600000; double distanceTravelled = (boat.getScaledVelocity() * millisecondsElapsed) / 3600000;
double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg(); double totalDistanceTravelled = distanceTravelled + boat.getDistanceTravelledInLeg();
boolean finish = boat.getCurrentLeg().getName().equals("Finish"); boolean finish = boat.getCurrentLeg().getName().equals("Finish");
@ -344,7 +233,7 @@ public class Race implements Runnable {
//update boat's distance travelled //update boat's distance travelled
boat.setDistanceTravelledInLeg(totalDistanceTravelled); boat.setDistanceTravelledInLeg(totalDistanceTravelled);
//Calculate boat's new position by adding the distance travelled onto the start point of the leg //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())); totalDistanceTravelled, boat.calculateAzimuth()));
} }
} }
@ -352,11 +241,14 @@ public class Race implements Runnable {
protected void checkPosition(Boat boat, long timeElapsed) { protected void checkPosition(Boat boat, long timeElapsed) {
if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) { if (boat.getDistanceTravelledInLeg() > boat.getCurrentLeg().getDistance()) {
//boat has passed onto new leg //boat has passed onto new leg
if (boat.getCurrentLeg().getName().equals("Finish")) { if (boat.getCurrentLeg().getName().equals("Finish")) {
//boat has finished //boat has finished
boatsFinished++; boatsFinished++;
boat.setTimeFinished(timeElapsed); boat.setTimeFinished(timeElapsed);
boat.setTimeFinished(timeElapsed); boat.setTimeFinished(timeElapsed);
boat.setVelocity(0);
boat.setScaledVelocity(0);
} else if (doNotFinish()) { } else if (doNotFinish()) {
boatsFinished++; boatsFinished++;
boat.setTimeFinished(timeElapsed); boat.setTimeFinished(timeElapsed);
@ -368,22 +260,25 @@ public class Race implements Runnable {
boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance()); boat.setDistanceTravelledInLeg(boat.getDistanceTravelledInLeg() - boat.getCurrentLeg().getDistance());
//Move boat on to next leg //Move boat on to next leg
Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1); Leg nextLeg = legs.get(boat.getCurrentLeg().getLegNumber() + 1);
boat.setCurrentLeg(nextLeg); 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. * @param chance percentage chance a boat has of failing per checkpoint.
* @see ObservableList
* @see Boat
*/ */
public ObservableList<Boat> getStartingBoats() { protected void setDnfChance(int chance) {
return startingBoats; if (chance >= 0 && chance <= 100) {
dnfChance = chance;
}
} }
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 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 @Test
public void calculateDueNorthAzimuthReturns0() { public void calculateDueNorthAzimuthReturns0() {

@ -4,11 +4,12 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.testng.AssertJUnit.assertEquals;
/** /**
* Created by esa46 on 29/03/17. * Created by esa46 on 29/03/17.
*/ */
public class MarkerTest { public class CompoundMarkTest {
GPSCoordinate ORIGIN_COORD = new GPSCoordinate(0, 0); GPSCoordinate ORIGIN_COORD = new GPSCoordinate(0, 0);
@ -29,13 +30,12 @@ public class MarkerTest {
} }
@Ignore
@Test @Test
public void averageLatOfTwoMarksIsAccurate() { public void averageLatOfTwoMarksIsAccurate() {
GPSCoordinate testCoord = new GPSCoordinate(10, 0); GPSCoordinate testCoord = new GPSCoordinate(0.001, 0);
Marker testMark = new Marker(ORIGIN_COORD, testCoord); Marker testMark = new Marker(ORIGIN_COORD, testCoord);
assertTrue(testMark.getAverageGPSCoordinate().equals(new GPSCoordinate(5, 0))); assertEquals(testMark.getAverageGPSCoordinate(), new GPSCoordinate(0.0005, 0));
} }
@Test @Test
@ -50,10 +50,11 @@ public class MarkerTest {
@Test @Test
public void averageLatAndLongOfTwoMarksIsAccurate() { public void averageLatAndLongOfTwoMarksIsAccurate() {
GPSCoordinate testCoord1 = new GPSCoordinate(10, 30); GPSCoordinate testCoord1 = new GPSCoordinate(0.0, 30);
GPSCoordinate testCoord2 = new GPSCoordinate(30, 60); GPSCoordinate testCoord2 = new GPSCoordinate(0.001, 60);
Marker testMark = new Marker(testCoord1, testCoord2); 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 { 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 @Test
public void calculateDistanceHandles5nmNorth() { public void calculateDistanceHandles5nmNorth() {
@ -23,7 +23,7 @@ public class LegTest {
calc.setDirection(0, 5 * Constants.NMToMetersConversion); calc.setDirection(0, 5 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint()); 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); assertEquals(test.getDistance(), 5, 1e-8);
} }
@ -34,7 +34,7 @@ public class LegTest {
calc.setDirection(90, 12 * Constants.NMToMetersConversion); calc.setDirection(90, 12 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint()); 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); assertEquals(test.getDistance(), 12, 1e-8);
} }
@ -45,7 +45,7 @@ public class LegTest {
calc.setDirection(180, 0.5 * Constants.NMToMetersConversion); calc.setDirection(180, 0.5 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint()); 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); assertEquals(test.getDistance(), 0.5, 1e-8);
} }
@ -56,14 +56,14 @@ public class LegTest {
calc.setDirection(-90, 0.1 * Constants.NMToMetersConversion); calc.setDirection(-90, 0.1 * Constants.NMToMetersConversion);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint()); 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); assertEquals(test.getDistance(), 0.1, 1e-8);
} }
@Test @Test
public void calculateDistanceHandlesZeroDifference() { 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); assertEquals(test.getDistance(), 0, 1e-8);
} }

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

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

@ -148,7 +148,7 @@ public class BinaryMessageDecoder {
case DISPLAYTEXTMESSAGE: case DISPLAYTEXTMESSAGE:
//System.out.println("Display Text Message"); //System.out.println("Display Text Message");
//No decoder for this. //No decoder for this.
throw new InvalidMessageException("Cannot decode DISPLAYTEXTMESSAGE - no decoder."); //throw new InvalidMessageException("Cannot decode DISPLAYTEXTMESSAGE - no decoder.");
case XMLMESSAGE: case XMLMESSAGE:
//System.out.println("XML Message!"); //System.out.println("XML Message!");
@ -164,17 +164,17 @@ public class BinaryMessageDecoder {
case YACHTEVENTCODE: case YACHTEVENTCODE:
//System.out.println("Yacht Action Code!"); //System.out.println("Yacht Action Code!");
//No decoder for this. //No decoder for this.
throw new InvalidMessageException("Cannot decode YACHTEVENTCODE - no decoder."); //throw new InvalidMessageException("Cannot decode YACHTEVENTCODE - no decoder.");
case YACHTACTIONCODE: case YACHTACTIONCODE:
//System.out.println("Yacht Action Code!"); //System.out.println("Yacht Action Code!");
//No decoder for this. //No decoder for this.
throw new InvalidMessageException("Cannot decode YACHTACTIONCODE - no decoder."); //throw new InvalidMessageException("Cannot decode YACHTACTIONCODE - no decoder.");
case CHATTERTEXT: case CHATTERTEXT:
//System.out.println("Chatter Text Message!"); //System.out.println("Chatter Text Message!");
//No decoder for this. //No decoder for this.
throw new InvalidMessageException("Cannot decode CHATTERTEXT - no decoder."); //throw new InvalidMessageException("Cannot decode CHATTERTEXT - no decoder.");
case BOATLOCATION: case BOATLOCATION:
//System.out.println("Boat Location Message!"); //System.out.println("Boat Location Message!");
@ -198,10 +198,10 @@ public class BinaryMessageDecoder {
default: default:
//System.out.println("Broken Message!"); //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,44 +36,100 @@ public class BoatLocationDecoder {
private BoatLocation message; private BoatLocation message;
public BoatLocationDecoder(byte[] encodedBoatLocation) { public BoatLocationDecoder(byte[] encodedBoatLocation) {
messageVersionNumber = encodedBoatLocation[0]; byte numMessageVersionNumber = 0;
time = Arrays.copyOfRange(encodedBoatLocation, 1, 7); long numTime = 0;
sourceID = Arrays.copyOfRange(encodedBoatLocation, 7, 11); int numSourceID = 0;
seqNum = Arrays.copyOfRange(encodedBoatLocation, 11, 15); int numSeqNum = 0;
deviceType = encodedBoatLocation[15]; byte numDeviceType = 0;
latitude = Arrays.copyOfRange(encodedBoatLocation, 16, 20); int numLatitude = 0;
longitude = Arrays.copyOfRange(encodedBoatLocation,20, 24); int numLongitude = 0;
altitude = Arrays.copyOfRange(encodedBoatLocation, 24, 28); int numAltitude = 0;
heading = Arrays.copyOfRange(encodedBoatLocation,28, 30); int numHeading = 0;
pitch =Arrays.copyOfRange(encodedBoatLocation,30,32); short numPitch = 0;
roll = Arrays.copyOfRange(encodedBoatLocation,32,34); short numRoll = 0;
boatSpeed = Arrays.copyOfRange(encodedBoatLocation,34,36); int numBoatSpeed = 0;
cog = Arrays.copyOfRange(encodedBoatLocation,36,38); int numCog = 0;
sog = Arrays.copyOfRange(encodedBoatLocation,38, 40); int numSog = 0;
apparentWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 40, 42); int numApparentWindSpeed = 0;
apparentWindAngle = Arrays.copyOfRange(encodedBoatLocation, 42, 44); short numApparentWindAngle = 0;
trueWindSpeed = Arrays.copyOfRange(encodedBoatLocation,44, 46); int numTrueWindSpeed = 0;
trueWindDirection = Arrays.copyOfRange(encodedBoatLocation, 46, 48); short numTrueWindDirection = 0;
trueWindAngle = Arrays.copyOfRange(encodedBoatLocation, 48, 50); short numTrueWindAngle = 0;
currentDrift = Arrays.copyOfRange(encodedBoatLocation,50,52); int numCurrentDrift = 0;
currentSet = Arrays.copyOfRange(encodedBoatLocation,52, 54); int numCurrentSet = 0;
rudderAngle = Arrays.copyOfRange(encodedBoatLocation,54, 56); short numRudderAngle = 0;
// System.out.println(bytesToInt(sourceID)); try {
// System.out.println(bytesToInt(boatSpeed)); 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){
}
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), message = new BoatLocation(messageVersionNumber, bytesToLong(time),
bytesToInt(sourceID), bytesToInt(seqNum), bytesToInt(sourceID), bytesToInt(seqNum),
deviceType, bytesToInt(latitude), deviceType, bytesToInt(latitude),
bytesToInt(longitude), bytesToInt(altitude), bytesToInt(longitude), bytesToInt(altitude),
bytesToInt(heading), bytesToShort(pitch), bytesToInt(heading), bytesToShort(pitch),
bytesToShort(roll), bytesToInt(boatSpeed), bytesToShort(roll), bytesToInt(boatSpeed),
bytesToInt(cog), bytesToInt(sog), bytesToInt(cog), bytesToInt(sog),
bytesToInt(apparentWindSpeed), bytesToShort(apparentWindAngle), bytesToInt(apparentWindSpeed), bytesToShort(apparentWindAngle),
bytesToInt(trueWindSpeed), bytesToShort(trueWindDirection), bytesToInt(trueWindSpeed), bytesToShort(trueWindDirection),
bytesToShort(trueWindAngle), bytesToInt(currentDrift), bytesToShort(trueWindAngle), bytesToInt(currentDrift),
bytesToInt(currentSet), bytesToShort(rudderAngle) 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 * @return race status number
*/ */
public int getRaceStatus() public int getRaceStatus()

@ -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")};
}

@ -57,10 +57,12 @@ public class RaceController extends Controller {
* Updates the ResizableRaceCanvas (raceMap) with most recent data * Updates the ResizableRaceCanvas (raceMap) with most recent data
* *
* @param boats boats that are to be displayed in the race * @param boats boats that are to be displayed in the race
* @param boatMarkers Markers for boats
* @see ResizableRaceCanvas * @see ResizableRaceCanvas
*/ */
public void updateMap(ObservableList<Boat> boats) { public void updateMap(ObservableList<Boat> boats, ObservableList<Marker> boatMarkers) {
raceMap.setBoats(boats); raceMap.setBoats(boats);
raceMap.setBoatMarkers(boatMarkers);
raceMap.update(); raceMap.update();
raceBoundaries.draw(); raceBoundaries.draw();
//stop if the visualiser is no longer running //stop if the visualiser is no longer running
@ -71,7 +73,7 @@ public class RaceController extends Controller {
* *
* @param race Race to listen to. * @param race Race to listen to.
*/ */
public void setInfoTable(Race race) { public void setInfoTable(StreamedRace race) {
//boatInfoTable.getItems().clear(); //boatInfoTable.getItems().clear();
ObservableList<Boat> startingBoats = race.getStartingBoats(); ObservableList<Boat> startingBoats = race.getStartingBoats();
boatInfoTable.setItems(race.getStartingBoats()); boatInfoTable.setItems(race.getStartingBoats());

@ -19,7 +19,6 @@ import seng302.VisualiserInput;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.Observable; import java.util.Observable;
@ -43,8 +42,6 @@ public class StartController extends Controller implements Observer {
@FXML private Label timer; @FXML private Label timer;
@FXML private Label raceStatusLabel; @FXML private Label raceStatusLabel;
private ZonedDateTime startingTime;
//@FXML Button fifteenMinButton; //@FXML Button fifteenMinButton;
private RaceClock raceClock; private RaceClock raceClock;
@ -61,17 +58,11 @@ public class StartController extends Controller implements Observer {
* Begins the race with a scale factor of 1 * Begins the race with a scale factor of 1
*/ */
private void startRaceNoScaling() { private void startRaceNoScaling() {
//startRace(1);
while(visualiserInput.getRaceStatus() == null);//TODO probably remove this. while(visualiserInput.getRaceStatus() == null);//TODO probably remove this.
countdownTimer(); countdownTimer();
} }
private void startRace(int raceScale){
//fifteenMinButton.setDisable(true);
//countdownTimer(raceScale);
}
@Override @Override
public void initialize(URL location, ResourceBundle resources){ public void initialize(URL location, ResourceBundle resources){
raceData = new StreamedCourse(); raceData = new StreamedCourse();

@ -88,7 +88,7 @@ public class BoatXMLReader extends XMLReader {
Element nBoats = (Element) doc.getElementsByTagName("Boats").item(0); Element nBoats = (Element) doc.getElementsByTagName("Boats").item(0);
for (int i = 0; i < nBoats.getChildNodes().getLength(); i++) { for (int i = 0; i < nBoats.getChildNodes().getLength(); i++) {
Node boat = nBoats.getChildNodes().item(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); readSingleBoat(boat);
} }
} }

@ -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. * Created by jjg64 on 19/04/17.
*/ */
public class RegattaXMLReader extends XMLReader { public class RegattaXMLReader extends XMLReader {
private Regatta regatta;
private int regattaID; private int regattaID;
private String regattaName; private String regattaName;
private int raceID = 0; private int raceID = 0;
@ -78,10 +77,6 @@ public class RegattaXMLReader extends XMLReader {
this.magneticVariation = Float.parseFloat(getTextValueOfNode(attributes, "MagneticVariation")); this.magneticVariation = Float.parseFloat(getTextValueOfNode(attributes, "MagneticVariation"));
} }
public Regatta getRegatta() {
return regatta;
}
public int getRegattaID() { public int getRegattaID() {
return regattaID; return regattaID;
} }

@ -29,18 +29,4 @@ public class StreamedBoat extends Boat {
return sourceID; 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;
}
} }

@ -21,14 +21,6 @@ public class StreamedCourse extends Observable implements RaceDataSource {
public StreamedCourse() {} public StreamedCourse() {}
public StreamedCourse(StreamedCourseXMLReader streamedCourseXMLReader) {
this.streamedCourseXMLReader = streamedCourseXMLReader;
}
public StreamedCourse(BoatXMLReader boatXMLReader) {
this.boatXMLReader = boatXMLReader;
}
public void setBoatXMLReader(BoatXMLReader boatXMLReader) { public void setBoatXMLReader(BoatXMLReader boatXMLReader) {
this.boatXMLReader = boatXMLReader; this.boatXMLReader = boatXMLReader;
if (streamedCourseXMLReader != null && boatXMLReader != null) { if (streamedCourseXMLReader != null && boatXMLReader != null) {

@ -13,7 +13,6 @@ import seng302.XMLReader;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.text.ParseException;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
@ -35,19 +34,6 @@ public class StreamedCourseXMLReader extends XMLReader {
private String raceType; private String raceType;
private boolean postpone; 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 * Constructor for Streamed Race XML
* @param filePath file path to read * @param filePath file path to read
@ -55,10 +41,9 @@ public class StreamedCourseXMLReader extends XMLReader {
* @throws IOException error * @throws IOException error
* @throws SAXException error * @throws SAXException error
* @throws ParserConfigurationException error * @throws ParserConfigurationException error
* @throws ParseException error
* @throws StreamedCourseXMLException 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); super(filePath);
if (read) { if (read) {
read(); read();
@ -71,10 +56,9 @@ public class StreamedCourseXMLReader extends XMLReader {
* @throws IOException error * @throws IOException error
* @throws SAXException error * @throws SAXException error
* @throws ParserConfigurationException error * @throws ParserConfigurationException error
* @throws ParseException error
* @throws StreamedCourseXMLException 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); super(xmlString);
read(); read();
} }
@ -165,8 +149,9 @@ public class StreamedCourseXMLReader extends XMLReader {
Marker marker; Marker marker;
switch(nMarks.getLength()) { switch(nMarks.getLength()) {
case 1: marker = new Marker(getCoordinate((Element)nMarks.item(0))); 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))); 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(); default: throw new StreamedCourseXMLException();
} }
@ -179,6 +164,14 @@ public class StreamedCourseXMLReader extends XMLReader {
return new GPSCoordinate(lat,lon); return new GPSCoordinate(lat,lon);
} }
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 * Reads "compoundMarkID" attribute of CompoundMark or Corner element
* @param element with "compoundMarkID" attribute * @param element with "compoundMarkID" attribute
@ -259,10 +252,6 @@ public class StreamedCourseXMLReader extends XMLReader {
return COORDINATEPADDING; return COORDINATEPADDING;
} }
public ZonedDateTime getCreationTimeDate() {
return creationTimeDate;
}
public ZonedDateTime getRaceStartTime() { public ZonedDateTime getRaceStartTime() {
return raceStartTime; return raceStartTime;
} }

@ -1,37 +1,60 @@
package seng302.Mock; 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.Controllers.RaceController;
import seng302.GPSCoordinate; import seng302.GPSCoordinate;
import seng302.Model.Boat; import seng302.Model.Boat;
import seng302.Model.Leg; import seng302.Model.Leg;
import seng302.Model.Marker; import seng302.Model.Marker;
import seng302.Model.Race;
import seng302.Networking.Messages.BoatLocation; import seng302.Networking.Messages.BoatLocation;
import seng302.Networking.Messages.BoatStatus; import seng302.Networking.Messages.BoatStatus;
import seng302.Networking.Messages.Enums.BoatStatusEnum; import seng302.Networking.Messages.Enums.BoatStatusEnum;
import seng302.VisualiserInput; import seng302.VisualiserInput;
import java.util.List;
/** /**
* Created by jjg64 on 21/04/17. * Created by jjg64 on 21/04/17.
*/ */
public class StreamedRace extends Race { public class StreamedRace implements Runnable {
private final VisualiserInput visualiserInput; 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) { 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; this.visualiserInput = visualiserInput;
} }
public void initialiseBoats() { private void initialiseBoats() {
Leg officialStart = legs.get(0); Leg officialStart = legs.get(0);
String name = officialStart.getName(); String name = officialStart.getName();
Marker endMarker = officialStart.getEndMarker(); Marker endCompoundMark = officialStart.getEndMarker();
for (int i = 0; i < startingBoats.size(); i++) { for (Boat boat : startingBoats) {
Boat boat = startingBoats.get(i);
if (boat != null) { if (boat != null) {
Leg startLeg = new Leg(name, 0); Leg startLeg = new Leg(name, 0);
startLeg.setEndMarker(endMarker); startLeg.setEndMarker(endCompoundMark);
boat.setCurrentLeg(startLeg); boat.setCurrentLeg(startLeg);
} }
} }
@ -52,7 +75,7 @@ public class StreamedRace extends Race {
* @param boat Boat that the position is to be updated for. * @param boat Boat that the position is to be updated for.
* @param timeElapsed Time that has elapse since the start of the the race. * @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(); StreamedCourse raceData = visualiserInput.getCourse();
BoatStatus boatStatusMessage = visualiserInput.getBoatStatusMap().get(boat.getSourceID()); BoatStatus boatStatusMessage = visualiserInput.getBoatStatusMap().get(boat.getSourceID());
if (boatStatusMessage != null) { if (boatStatusMessage != null) {
@ -72,7 +95,7 @@ public class StreamedRace extends Race {
boatsFinished++; boatsFinished++;
boat.setTimeFinished(timeElapsed); boat.setTimeFinished(timeElapsed);
boat.setFinished(true); 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 //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 boat to be updated
* @param millisecondsElapsed time since last update * @param millisecondsElapsed time since last update
*/ */
protected void updatePosition(Boat boat, int millisecondsElapsed) { private void updatePosition(Boat boat, int millisecondsElapsed) {
int sourceID = boat.getSourceID(); int sourceID = boat.getSourceID();
BoatLocation boatLocation = visualiserInput.getBoatLocationMessage(sourceID); BoatLocation boatLocation = visualiserInput.getBoatLocationMessage(sourceID);
if(boatLocation != null) { if(boatLocation != null) {
@ -99,12 +122,136 @@ public class StreamedRace extends Race {
} }
/** /**
* sets the position of a boat from coordinate * Updates the boat's gps coordinates
* @param boat the boat to set *
* @param coordinate the position of the boat * @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) {
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++;
}
}
for (Marker mark: boatMarkers){
if (mark != null){
updateMarker(mark);
}
}
//System.out.println(boatsFinished + ":" + startingBoats.size());
} else {
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) { public ObservableList<Boat> getStartingBoats() {
boat.setCurrentPosition(coordinate); return startingBoats;
} }
} }

@ -4,7 +4,6 @@ import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import org.geotools.referencing.GeodeticCalculator; import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants;
import seng302.GPSCoordinate; import seng302.GPSCoordinate;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
@ -28,6 +27,7 @@ public class BoatInRace extends Boat {
private boolean started = false; private boolean started = false;
private final StringProperty position; private final StringProperty position;
private double heading; private double heading;
private static final double WAKE_SCALE = 10;
private final Queue<TrackPoint> track = new ConcurrentLinkedQueue<>(); private final Queue<TrackPoint> track = new ConcurrentLinkedQueue<>();
private long nextValidTime = 0; private long nextValidTime = 0;
@ -50,20 +50,6 @@ public class BoatInRace extends Boat {
position = new SimpleStringProperty("-"); 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 * Calculates the azimuth of the travel via map coordinates of the raceMarkers
* *
@ -122,7 +108,7 @@ public class BoatInRace extends Boat {
*/ */
public GPSCoordinate getWake() { public GPSCoordinate getWake() {
double reverseHeading = getHeading() - 180; double reverseHeading = getHeading() - 180;
double distance = Constants.wakeScale * getVelocity(); double distance = WAKE_SCALE * getVelocity();
GeodeticCalculator calc = new GeodeticCalculator(); GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint( calc.setStartingGeographicPoint(

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

@ -1,7 +1,6 @@
package seng302.Model; package seng302.Model;
import org.geotools.referencing.GeodeticCalculator; import org.geotools.referencing.GeodeticCalculator;
import seng302.Constants;
import seng302.GPSCoordinate; import seng302.GPSCoordinate;
/** /**
@ -13,6 +12,8 @@ public class Leg {
private Marker startMarker; private Marker startMarker;
private Marker endMarker; private Marker endMarker;
private final int legNumber; private final int legNumber;
// 1 nautical mile = 1852 meters
public static final int NM_TO_METERS = 1852;
/** /**
* Leg Initializer * Leg Initializer
@ -63,7 +64,6 @@ public class Leg {
* Returns the leg number that the leg exists in the Race * Returns the leg number that the leg exists in the Race
* *
* @return Returns the Leg * @return Returns the Leg
* @see Race
*/ */
public int getLegNumber() { public int getLegNumber() {
return legNumber; return legNumber;
@ -97,7 +97,7 @@ public class Leg {
GPSCoordinate endMarker = this.endMarker.getAverageGPSCoordinate(); GPSCoordinate endMarker = this.endMarker.getAverageGPSCoordinate();
calc.setStartingGeographicPoint(startMarker.getLongitude(), startMarker.getLatitude()); calc.setStartingGeographicPoint(startMarker.getLongitude(), startMarker.getLatitude());
calc.setDestinationGeographicPoint(endMarker.getLongitude(), endMarker.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 { public class Marker {
private final GPSCoordinate averageGPSCoordinate; private final GPSCoordinate averageGPSCoordinate;
private final GPSCoordinate mark1; private GPSCoordinate mark1;
private final GPSCoordinate mark2; private GPSCoordinate mark2;
private final int sourceId1;
public Marker(GPSCoordinate mark1) { private final int sourceId2;
this.mark1 = mark1;
this.mark2 = mark1;
this.averageGPSCoordinate = calculateAverage();
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.mark1 = mark1;
this.mark2 = mark2; this.mark2 = mark2;
this.averageGPSCoordinate = calculateAverage(); 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() { public GPSCoordinate getMark1() {
return mark1; 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); 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) { public static ZonedDateTime getCurrentZonedDateTime(GPSCoordinate gpsCoordinate) {
TimeZoneLookup timeZoneLookup = new TimeZoneLookup(); TimeZoneLookup timeZoneLookup = new TimeZoneLookup();
TimeZoneResult timeZoneResult = timeZoneLookup.getTimeZone(gpsCoordinate.getLatitude(), gpsCoordinate.getLongitude()); TimeZoneResult timeZoneResult = timeZoneLookup.getTimeZone(gpsCoordinate.getLatitude(), gpsCoordinate.getLongitude());

@ -4,10 +4,10 @@ package seng302.Model;
import eu.hansolo.medusa.Gauge; import eu.hansolo.medusa.Gauge;
import eu.hansolo.medusa.GaugeBuilder; import eu.hansolo.medusa.GaugeBuilder;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.collections.ObservableList;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Paint; import javafx.scene.paint.Paint;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
import seng302.GPSCoordinate;
import seng302.GraphCoordinate; import seng302.GraphCoordinate;
import seng302.Mock.StreamedCourse; import seng302.Mock.StreamedCourse;
import seng302.RaceDataSource; import seng302.RaceDataSource;
@ -25,6 +25,7 @@ import java.util.List;
public class ResizableRaceCanvas extends ResizableCanvas { public class ResizableRaceCanvas extends ResizableCanvas {
private RaceMap map; private RaceMap map;
private List<Boat> boats; private List<Boat> boats;
private List<Marker> boatMarkers;
private boolean raceAnno = true; private boolean raceAnno = true;
private boolean annoName = true; private boolean annoName = true;
private boolean annoAbbrev = true; private boolean annoAbbrev = true;
@ -32,7 +33,6 @@ public class ResizableRaceCanvas extends ResizableCanvas {
private boolean annoPath = true; private boolean annoPath = true;
private List<Color> colours; private List<Color> colours;
private final List<Marker> markers; private final List<Marker> markers;
double[] xpoints = {}, ypoints = {};
private final RaceDataSource raceData; private final RaceDataSource raceData;
private Gauge arrow; private Gauge arrow;
@ -60,29 +60,23 @@ public class ResizableRaceCanvas extends ResizableCanvas {
this.boats = boats; 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) { public void setBoatMarkers(ObservableList<Marker> boatMarkers) {
this.map = map; 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 * @param map race map
* is to be displayed as.
* @param paint Colour the mark is to be coloured.
* @see GraphCoordinate
* @see Color
* @see Paint
*/ */
public void displayMark(GraphCoordinate graphCoordinate, Paint paint) { private void setMap(RaceMap map) {
double d = 25; this.map = map;
this.gc.setFill(paint);
gc.fillOval(graphCoordinate.getX() - (d / 2), graphCoordinate.getY() - (d / 2), d, d);
} }
private void displayBoat(Boat boat, double angle, Color colour) { private void displayBoat(Boat boat, double angle, Color colour) {
@ -257,19 +251,6 @@ 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
*/
public void drawBoat(Color colour, GPSCoordinate gpsCoordinates) {
GraphCoordinate graphCoordinate = this.map.convertGPS(gpsCoordinates);
displayPoint(graphCoordinate, colour);
}
/** /**
* Toggle the raceAnno value * Toggle the raceAnno value
*/ */

@ -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; package seng302;
import javafx.application.Platform;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import seng302.Mock.*; import seng302.Mock.*;
import seng302.Networking.BinaryMessageDecoder; import seng302.Networking.BinaryMessageDecoder;
@ -10,7 +11,6 @@ import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.text.ParseException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -23,9 +23,6 @@ import static seng302.Networking.Utils.ByteConverter.bytesToShort;
*/ */
public class VisualiserInput implements Runnable { 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. ///Timestamp of the last heartbeat.
private long lastHeartbeatTime = -1; private long lastHeartbeatTime = -1;
///Sequence number of the last heartbeat. ///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. * @throws IOException Thrown when an error occurs while reading from the socket.
*/ */
private byte[] getNextMessageBytes() throws IOException { private byte[] getNextMessageBytes() throws IOException {
inStream.mark(0);
short CRCLength = 4; short CRCLength = 4;
short headerLength = 15; short headerLength = 15;
@ -256,12 +253,17 @@ public class VisualiserInput implements Runnable {
catch (InvalidMessageException | IOException e) { catch (InvalidMessageException | IOException e) {
//Prints exception to stderr, and iterate loop (that is, read the next message). //Prints exception to stderr, and iterate loop (that is, read the next message).
System.err.println("Unable to read message: " + e.getMessage()); 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 to the next loop iteration/message.
continue; continue;
} }/*
//Add it to message queue. //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. //Checks which message is being received and does what is needed for that message.
@ -298,42 +300,43 @@ public class VisualiserInput implements Runnable {
//System.out.println("XML Message!"); //System.out.println("XML Message!");
if (xmlMessage.getXmlMsgSubType() == XMLMessage.XMLTypeRegatta){ Platform.runLater(()-> {
//System.out.println("Setting Regatta"); if (xmlMessage.getXmlMsgSubType() == XMLMessage.XMLTypeRegatta) {
try { //System.out.println("Setting Regatta");
course.setRegattaXMLReader(new RegattaXMLReader(xmlMessage.getXmlMessage())); try {
} course.setRegattaXMLReader(new RegattaXMLReader(xmlMessage.getXmlMessage()));
//TODO REFACTOR should put all of these exceptions behind a RegattaXMLReaderException.
catch (IOException | SAXException | ParserConfigurationException e) { }
System.err.println("Error creating RegattaXMLReader: " + e.getMessage()); //TODO REFACTOR should put all of these exceptions behind a RegattaXMLReaderException.
//Continue to the next loop iteration/message. catch (IOException | SAXException | ParserConfigurationException e) {
} System.err.println("Error creating RegattaXMLReader: " + e.getMessage());
//Continue to the next loop iteration/message.
} else if (xmlMessage.getXmlMsgSubType() == XMLMessage.XMLTypeRace){ }
//System.out.println("Setting Course");
try { } else if (xmlMessage.getXmlMsgSubType() == XMLMessage.XMLTypeRace) {
course.setStreamedCourseXMLReader(new StreamedCourseXMLReader(xmlMessage.getXmlMessage())); //System.out.println("Setting Course");
} try {
//TODO REFACTOR should put all of these exceptions behind a StreamedCourseXMLReaderException. course.setStreamedCourseXMLReader(new StreamedCourseXMLReader(xmlMessage.getXmlMessage()));
catch (IOException | SAXException | ParserConfigurationException | ParseException | StreamedCourseXMLException e) { }
System.err.println("Error creating StreamedCourseXMLReader: " + e.getMessage()); //TODO REFACTOR should put all of these exceptions behind a StreamedCourseXMLReaderException.
//Continue to the next loop iteration/message. 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 {
course.setBoatXMLReader(new BoatXMLReader(xmlMessage.getXmlMessage()));
}
//TODO REFACTOR should put all of these exceptions behind a BoatXMLReaderException.
catch (IOException | SAXException | ParserConfigurationException e) {
System.err.println("Error creating BoatXMLReader: " + e.getMessage());
//Continue to the next loop iteration/message.
}
} else if (xmlMessage.getXmlMsgSubType() == XMLMessage.XMLTypeBoat){
//System.out.println("Setting Boats");
try
{
course.setBoatXMLReader(new BoatXMLReader(xmlMessage.getXmlMessage()));
} }
//TODO REFACTOR should put all of these exceptions behind a BoatXMLReaderException. });
catch (IOException | SAXException | ParserConfigurationException e) {
System.err.println("Error creating BoatXMLReader: " + e.getMessage());
//Continue to the next loop iteration/message.
}
}
} }
//RaceStartStatus. //RaceStartStatus.
else if (message instanceof 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. //If the map _doesn't_ already contain a message for this boat, insert the message.
this.boatLocationMap.put(boatLocation.getSourceID(), boatLocation); this.boatLocationMap.put(boatLocation.getSourceID(), boatLocation);
} }
} }
//MarkRounding. //MarkRounding.
else if (message instanceof MarkRounding) { else if (message instanceof MarkRounding) {

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

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

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

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

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

@ -2,28 +2,28 @@ package seng302.Model;
import org.geotools.referencing.GeodeticCalculator; import org.geotools.referencing.GeodeticCalculator;
import org.junit.Test; import org.junit.Test;
import seng302.Constants;
import seng302.GPSCoordinate; import seng302.GPSCoordinate;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertEquals;
import static seng302.Model.Leg.NM_TO_METERS;
/** /**
* Created by esa46 on 22/03/17. * Created by esa46 on 22/03/17.
*/ */
public class LegTest { 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 @Test
public void calculateDistanceHandles5nmNorth() { public void calculateDistanceHandles5nmNorth() {
GeodeticCalculator calc = new GeodeticCalculator(); GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0); calc.setStartingGeographicPoint(0, 0);
calc.setDirection(0, 5 * Constants.NMToMetersConversion); calc.setDirection(0, 5 * NM_TO_METERS);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint()); 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); assertEquals(test.getDistance(), 5, 1e-8);
} }
@ -31,10 +31,10 @@ public class LegTest {
public void calculateDistanceHandles12nmEast() { public void calculateDistanceHandles12nmEast() {
GeodeticCalculator calc = new GeodeticCalculator(); GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0); calc.setStartingGeographicPoint(0, 0);
calc.setDirection(90, 12 * Constants.NMToMetersConversion); calc.setDirection(90, 12 * NM_TO_METERS);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint()); 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); assertEquals(test.getDistance(), 12, 1e-8);
} }
@ -42,10 +42,10 @@ public class LegTest {
public void calculateDistanceHandlesHalfnmSouth() { public void calculateDistanceHandlesHalfnmSouth() {
GeodeticCalculator calc = new GeodeticCalculator(); GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0); calc.setStartingGeographicPoint(0, 0);
calc.setDirection(180, 0.5 * Constants.NMToMetersConversion); calc.setDirection(180, 0.5 * NM_TO_METERS);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint()); 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); assertEquals(test.getDistance(), 0.5, 1e-8);
} }
@ -53,17 +53,17 @@ public class LegTest {
public void calculateDistanceHandlesPoint1nmWest() { public void calculateDistanceHandlesPoint1nmWest() {
GeodeticCalculator calc = new GeodeticCalculator(); GeodeticCalculator calc = new GeodeticCalculator();
calc.setStartingGeographicPoint(0, 0); calc.setStartingGeographicPoint(0, 0);
calc.setDirection(-90, 0.1 * Constants.NMToMetersConversion); calc.setDirection(-90, 0.1 * NM_TO_METERS);
Marker endMarker = getEndMarker(calc.getDestinationGeographicPoint()); 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); assertEquals(test.getDistance(), 0.1, 1e-8);
} }
@Test @Test
public void calculateDistanceHandlesZeroDifference() { 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); 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> <leg>
<name>Start to Mark 1</name> <name>Start to Mark 1</name>
<start> <start>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.296577</latitude> <latitude>32.296577</latitude>
<longitude>-64.854304</longitude> <longitude>-64.854304</longitude>
@ -50,29 +50,29 @@
<latitude>32.293771</latitude> <latitude>32.293771</latitude>
<longitude>-64.855242</longitude> <longitude>-64.855242</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</start> </start>
<finish> <finish>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.293039</latitude> <latitude>32.293039</latitude>
<longitude>-64.843983</longitude> <longitude>-64.843983</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</finish> </finish>
</leg> </leg>
<leg> <leg>
<name>Mark 1 to Leeward Gate</name> <name>Mark 1 to Leeward Gate</name>
<start> <start>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.293039</latitude> <latitude>32.293039</latitude>
<longitude>-64.843983</longitude> <longitude>-64.843983</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</start> </start>
<finish> <finish>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.309693</latitude> <latitude>32.309693</latitude>
<longitude>-64.835249</longitude> <longitude>-64.835249</longitude>
@ -81,13 +81,13 @@
<latitude>32.308046</latitude> <latitude>32.308046</latitude>
<longitude>-64.831785</longitude> <longitude>-64.831785</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</finish> </finish>
</leg> </leg>
<leg> <leg>
<name>Leeward Gate to Windward Gate</name> <name>Leeward Gate to Windward Gate</name>
<start> <start>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.309693</latitude> <latitude>32.309693</latitude>
<longitude>-64.835249</longitude> <longitude>-64.835249</longitude>
@ -96,10 +96,10 @@
<latitude>32.308046</latitude> <latitude>32.308046</latitude>
<longitude>-64.831785</longitude> <longitude>-64.831785</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</start> </start>
<finish> <finish>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.284680</latitude> <latitude>32.284680</latitude>
<longitude>-64.850045</longitude> <longitude>-64.850045</longitude>
@ -108,13 +108,13 @@
<latitude>32.280164</latitude> <latitude>32.280164</latitude>
<longitude>-64.847591</longitude> <longitude>-64.847591</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</finish> </finish>
</leg> </leg>
<leg> <leg>
<name>Windward Gate to Leeward Gate</name> <name>Windward Gate to Leeward Gate</name>
<start> <start>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.284680</latitude> <latitude>32.284680</latitude>
<longitude>-64.850045</longitude> <longitude>-64.850045</longitude>
@ -123,10 +123,10 @@
<latitude>32.280164</latitude> <latitude>32.280164</latitude>
<longitude>-64.847591</longitude> <longitude>-64.847591</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</start> </start>
<finish> <finish>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.309693</latitude> <latitude>32.309693</latitude>
<longitude>-64.835249</longitude> <longitude>-64.835249</longitude>
@ -135,13 +135,13 @@
<latitude>32.308046</latitude> <latitude>32.308046</latitude>
<longitude>-64.831785</longitude> <longitude>-64.831785</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</finish> </finish>
</leg> </leg>
<leg> <leg>
<name>Leeward Gate to Finish</name> <name>Leeward Gate to Finish</name>
<start> <start>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.309693</latitude> <latitude>32.309693</latitude>
<longitude>-64.835249</longitude> <longitude>-64.835249</longitude>
@ -150,10 +150,10 @@
<latitude>32.308046</latitude> <latitude>32.308046</latitude>
<longitude>-64.831785</longitude> <longitude>-64.831785</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</start> </start>
<finish> <finish>
<marker> <compoundMark>
<coordinate> <coordinate>
<latitude>32.317379</latitude> <latitude>32.317379</latitude>
<longitude>-64.839291</longitude> <longitude>-64.839291</longitude>
@ -162,7 +162,7 @@
<latitude>32.317257</latitude> <latitude>32.317257</latitude>
<longitude>-64.836260</longitude> <longitude>-64.836260</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</finish> </finish>
</leg> </leg>
</legs> </legs>
@ -213,7 +213,7 @@
<longitude>-64.849184</longitude> <longitude>-64.849184</longitude>
</coordinate> </coordinate>
</boundaries> </boundaries>
<marker> <compoundMark>
<name>Start Line</name> <name>Start Line</name>
<coordinate> <coordinate>
<latitude>32.296577</latitude> <latitude>32.296577</latitude>
@ -223,15 +223,15 @@
<latitude>32.293771</latitude> <latitude>32.293771</latitude>
<longitude>-64.855242</longitude> <longitude>-64.855242</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
<marker> <compoundMark>
<name>Mark</name> <name>Mark</name>
<coordinate> <coordinate>
<latitude>32.293039</latitude> <latitude>32.293039</latitude>
<longitude>-64.843983</longitude> <longitude>-64.843983</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
<marker> <compoundMark>
<name>Windward Gate</name> <name>Windward Gate</name>
<coordinate> <coordinate>
<latitude>32.284680</latitude> <latitude>32.284680</latitude>
@ -241,8 +241,8 @@
<latitude>32.280164</latitude> <latitude>32.280164</latitude>
<longitude>-64.847591</longitude> <longitude>-64.847591</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
<marker> <compoundMark>
<name>Leeward Gate</name> <name>Leeward Gate</name>
<coordinate> <coordinate>
<latitude>32.309693</latitude> <latitude>32.309693</latitude>
@ -252,8 +252,8 @@
<latitude>32.308046</latitude> <latitude>32.308046</latitude>
<longitude>-64.831785</longitude> <longitude>-64.831785</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
<marker> <compoundMark>
<name>Finish Line</name> <name>Finish Line</name>
<coordinate> <coordinate>
<latitude>32.317379</latitude> <latitude>32.317379</latitude>
@ -263,6 +263,6 @@
<latitude>32.317257</latitude> <latitude>32.317257</latitude>
<longitude>-64.836260</longitude> <longitude>-64.836260</longitude>
</coordinate> </coordinate>
</marker> </compoundMark>
</course> </course>
</race> </race>

Loading…
Cancel
Save