- RaceXmlReaders can handle strings now - Not working with visualiser, gps coords may be worng #story[881]main
parent
91b1773703
commit
ffa3d530ae
@ -1,376 +1,274 @@
|
||||
package seng302.DataInput;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import seng302.Exceptions.StreamedCourseXMLException;
|
||||
import seng302.Model.*;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by fwy13 on 26/03/2017.
|
||||
* @deprecated please use {@link seng302.Model.StreamedCourseXMLReader}
|
||||
* Created by jjg64 on 21/04/17.
|
||||
*/
|
||||
public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
private static double COORDINATEPADDING = 0.0005;
|
||||
private int raceID;
|
||||
private List<Boat> boats = new ArrayList<>();
|
||||
private Color[] colors = {Color.BLUEVIOLET, Color.BLACK, Color.RED, Color.ORANGE, Color.DARKOLIVEGREEN, Color.LIMEGREEN};//TODO make this established in xml or come up with a better system.
|
||||
private List<Leg> legs = new ArrayList<>();
|
||||
private GPSCoordinate mark, startPt1, startPt2, finishPt1, finishPt2, leewardPt1, leewardPt2, windwardPt1, windwardPt2;
|
||||
private static final double COORDINATEPADDING = 0.000;
|
||||
private GPSCoordinate mapTopLeft, mapBottomRight;
|
||||
private List<GPSCoordinate> boundary = new ArrayList<>();
|
||||
private List<CompoundMark> compoundMarks = new ArrayList<>();
|
||||
private final List<GPSCoordinate> boundary = new ArrayList<>();
|
||||
private final Map<Integer,Element> compoundMarkMap = new HashMap<>();
|
||||
private final Map<Integer, Boat> participants = new HashMap<>();
|
||||
private final List<Leg> legs = new ArrayList<>();
|
||||
private final List<CompoundMark> compoundMarks = new ArrayList<>();
|
||||
private ZonedDateTime creationTimeDate;
|
||||
private ZonedDateTime raceStartTime;
|
||||
private int raceID;
|
||||
private String raceType;
|
||||
private boolean postpone;
|
||||
|
||||
private Map<Integer, Boat> boats;
|
||||
private Map<Integer, Mark> marks;
|
||||
|
||||
/**
|
||||
* Constractor for Race XML
|
||||
*
|
||||
* Constructor for Streamed Race XML
|
||||
* @param filePath path of the file
|
||||
* @throws IOException error
|
||||
* @throws SAXException error
|
||||
* @throws IOException error
|
||||
* @throws SAXException error
|
||||
* @throws ParserConfigurationException error
|
||||
* @throws ParseException error
|
||||
* @throws StreamedCourseXMLException error
|
||||
*/
|
||||
public RaceXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException {
|
||||
this(filePath, true);
|
||||
public RaceXMLReader(String filePath, BoatDataSource boatData) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
|
||||
this(filePath, boatData, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* COnstructor for Race XML
|
||||
*
|
||||
* Constructor for Streamed Race XML
|
||||
* @param filePath file path to read
|
||||
* @param read whether or not to read and store the files straight away.
|
||||
* @throws IOException error
|
||||
* @throws SAXException error
|
||||
* @param read whether or not to read and store the files straight away.
|
||||
* @throws IOException error
|
||||
* @throws SAXException error
|
||||
* @throws ParserConfigurationException error
|
||||
* @throws ParseException error
|
||||
* @throws StreamedCourseXMLException error
|
||||
*/
|
||||
public RaceXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException {
|
||||
public RaceXMLReader(String filePath, BoatDataSource boatData, boolean read) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
|
||||
super(filePath);
|
||||
this.boats = boatData.getBoats();
|
||||
this.marks = boatData.getMarkerBoats();
|
||||
if (read) {
|
||||
read();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the files
|
||||
* reads
|
||||
* @throws StreamedCourseXMLException error
|
||||
*/
|
||||
private void read() {
|
||||
|
||||
private void read() throws StreamedCourseXMLException {
|
||||
readRace();
|
||||
readParticipants();
|
||||
readCourse();
|
||||
readID();
|
||||
readLegs();
|
||||
readMarkers();
|
||||
readBoats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in race ID from XML object.
|
||||
* reads a race
|
||||
*/
|
||||
public void readID() {
|
||||
NodeList race = doc.getElementsByTagName("race");
|
||||
raceID = Integer.parseInt(getTextValueOfNode((Element) race.item(0), "raceId"));
|
||||
}
|
||||
private void readRace() {
|
||||
DateTimeFormatter dateFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||
Element settings = (Element) doc.getElementsByTagName("Race").item(0);
|
||||
NamedNodeMap raceTimeTag = doc.getElementsByTagName("RaceStartTime").item(0).getAttributes();
|
||||
|
||||
/**
|
||||
* Read all the boats in the XML file
|
||||
*/
|
||||
public void readBoats() {
|
||||
//get all boats
|
||||
NodeList nBoats = doc.getElementsByTagName("boat");
|
||||
|
||||
for (int i = 0; i < nBoats.getLength(); i++) {
|
||||
String name = getTextValueOfNode((Element) nBoats.item(i), "name");
|
||||
String country = getTextValueOfNode((Element) nBoats.item(i), "abbr");
|
||||
int sourceID = Integer.parseInt(getTextValueOfNode((Element) nBoats.item(i), "sourceID"));
|
||||
Boat boat = new Boat(sourceID, name, country);
|
||||
boat.setCurrentPosition(startPt1);
|
||||
if (legs.size() > 0) {
|
||||
boat.setCurrentLeg(legs.get(0));
|
||||
}
|
||||
boats.add(boat);
|
||||
}
|
||||
}
|
||||
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 readMarkers() {
|
||||
//get all boats
|
||||
NodeList nMarkers = doc.getElementsByTagName("marker");
|
||||
raceID = Integer.parseInt(getTextValueOfNode(settings, "RaceID"));
|
||||
raceType = getTextValueOfNode(settings, "RaceType");
|
||||
|
||||
for (int i = 0; i < nMarkers.getLength(); i++) {
|
||||
CompoundMark compoundMark = getMarker((Element) nMarkers.item(i));
|
||||
if (compoundMark.getName() != null) compoundMarks.add(compoundMark);
|
||||
}
|
||||
}
|
||||
creationTimeDate = ZonedDateTime.parse(getTextValueOfNode(settings, "CreationTimeDate"), dateFormat);
|
||||
|
||||
/**
|
||||
* 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");
|
||||
CompoundMark startCompoundMark = getMarker(start);
|
||||
NodeList finish = ((Element) nLegs.item(i)).getElementsByTagName("finish");
|
||||
CompoundMark finishCompoundMark = getMarker(finish);
|
||||
legs.add(new Leg(label, startCompoundMark, finishCompoundMark, i));
|
||||
}
|
||||
if (raceTimeTag.getNamedItem("Time") != null) raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Time").getTextContent(), dateFormat);
|
||||
else raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Start").getTextContent(), dateFormat);
|
||||
|
||||
postpone = Boolean.parseBoolean(raceTimeTag.getNamedItem("Postpone").getTextContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read 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();
|
||||
private void readParticipants() {
|
||||
Element nParticipants = (Element) doc.getElementsByTagName("Participants").item(0);
|
||||
nParticipants.getChildNodes().getLength();
|
||||
for (int i = 0; i < nParticipants.getChildNodes().getLength(); i++) {
|
||||
int sourceID;
|
||||
Node yacht = nParticipants.getChildNodes().item(i);
|
||||
if (yacht.getNodeName().equals("Yacht")) {
|
||||
if (exists(yacht, "SourceID")) {
|
||||
sourceID = Integer.parseInt(yacht.getAttributes().getNamedItem("SourceID").getTextContent());
|
||||
participants.put(sourceID, boats.get(sourceID));
|
||||
}
|
||||
}
|
||||
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 CompoundMark getMarker(NodeList start) {
|
||||
return getMarker(start, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a marker from the XML file
|
||||
*
|
||||
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
|
||||
* @param startIndex index in the node that has the coordinate tag
|
||||
* @return
|
||||
* reads a course
|
||||
* @throws StreamedCourseXMLException error
|
||||
*/
|
||||
private CompoundMark getMarker(NodeList start, int startIndex) {
|
||||
return getMarker(start, startIndex, 0);
|
||||
private void readCourse() throws StreamedCourseXMLException {
|
||||
readCompoundMarks();
|
||||
readCompoundMarkSequence();
|
||||
readCourseLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a marker from the XML file
|
||||
*
|
||||
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
|
||||
* @param startIndex index in the node that has the coordinate tag
|
||||
* @param nodeIndex coordinate index
|
||||
* @return
|
||||
* Indexes CompoundMark elements by their ID for use in generating the course, and populates list of Markers.
|
||||
* @see CompoundMark
|
||||
*/
|
||||
private CompoundMark getMarker(NodeList start, int startIndex, int nodeIndex) {
|
||||
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("marker");
|
||||
Element marker = (Element) nodeList.item(nodeIndex);
|
||||
return getMarker(marker);
|
||||
private void readCompoundMarks() throws StreamedCourseXMLException {
|
||||
Element nCourse = (Element) doc.getElementsByTagName("Course").item(0);
|
||||
for(int i = 0; i < nCourse.getChildNodes().getLength(); i++) {
|
||||
Node compoundMark = nCourse.getChildNodes().item(i);
|
||||
if(compoundMark.getNodeName().equals("CompoundMark")) {
|
||||
int compoundMarkID = getCompoundMarkID((Element) compoundMark);
|
||||
compoundMarkMap.put(compoundMarkID, (Element)compoundMark);
|
||||
compoundMarks.add(getCompoundMark(compoundMarkID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a changes a marker to GPS coordinates into a marker
|
||||
*
|
||||
* @param markerNode marker to turn into coordinates
|
||||
* @return
|
||||
* Generates a CompoundMark from the CompoundMark element with given ID.
|
||||
* @param compoundMarkID index of required CompoundMark element
|
||||
* @return generated CompoundMark
|
||||
* @throws StreamedCourseXMLException if CompoundMark element contains unhandled number of compoundMarks
|
||||
* @see CompoundMark
|
||||
*/
|
||||
private CompoundMark 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;
|
||||
private CompoundMark getCompoundMark(int compoundMarkID) throws StreamedCourseXMLException {
|
||||
Element compoundMark = compoundMarkMap.get(compoundMarkID);
|
||||
NodeList nMarks = compoundMark.getElementsByTagName("Mark");
|
||||
CompoundMark marker;
|
||||
|
||||
switch(nMarks.getLength()) {
|
||||
case 1: marker = new CompoundMark(getMark((Element)nMarks.item(0))); break;
|
||||
case 2: marker = new CompoundMark(getMark((Element)nMarks.item(0)), getMark((Element)nMarks.item(1))); break;
|
||||
default: throw new StreamedCourseXMLException();
|
||||
}
|
||||
NodeList name = markerNode.getElementsByTagName("name");
|
||||
return null;//name.getLength() == 1 ? new CompoundMark(getTextValueOfNode((Element) markerNode, "name"), side1, side2) : new CompoundMark(side1, side2);
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a coordinates from the XML file
|
||||
*
|
||||
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
|
||||
* @return
|
||||
*/
|
||||
private GPSCoordinate getCoordinates(NodeList start) {
|
||||
return getCoordinates(start, 0);
|
||||
private Mark getMark(Element mark) {
|
||||
int sourceID = Integer.parseInt(mark.getAttribute("SourceID"));
|
||||
return marks.get(sourceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a coordinates from the XML file
|
||||
*
|
||||
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
|
||||
* @param startIndex the index the tag containing the coordinate should be in
|
||||
* @return
|
||||
* Reads "compoundMarkID" attribute of CompoundMark or Corner element
|
||||
* @param element with "compoundMarkID" attribute
|
||||
* @return value of "compoundMarkID" attribute
|
||||
*/
|
||||
private GPSCoordinate getCoordinates(NodeList start, int startIndex) {
|
||||
return getCoordinates(start, startIndex, 0);
|
||||
private int getCompoundMarkID(Element element) {
|
||||
return Integer.parseInt(element.getAttribute("CompoundMarkID"));
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a coordinates from the XML file
|
||||
*
|
||||
* @param start base nodelist this should be the tag that contains <coordinate></coordinate>
|
||||
* @param startIndex the index the tag containing the coordinate should be in
|
||||
* @param nodeIndex The coordinate index
|
||||
* @return
|
||||
* Reads "name" attribute of CompoundMark element with corresponding CompoundMarkID
|
||||
* @param compoundMarkID unique ID for CompoundMark element
|
||||
* @return value of "name" attribute
|
||||
*/
|
||||
private GPSCoordinate getCoordinates(NodeList start, int startIndex, int nodeIndex) {
|
||||
NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("coordinate");
|
||||
Element coord = (Element) nodeList.item(nodeIndex);
|
||||
return getCoordinates(coord);
|
||||
private String getCompoundMarkName(int compoundMarkID) {
|
||||
return compoundMarkMap.get(compoundMarkID).getAttribute("Name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the coordinate TODO raise exception that runs when the XML is formatted wrongly.
|
||||
*
|
||||
* @param coordNode
|
||||
* @return
|
||||
* Populates list of legs given CompoundMarkSequence element and referenced CompoundMark elements.
|
||||
* @throws StreamedCourseXMLException if compoundMarks cannot be resolved from CompoundMark
|
||||
*/
|
||||
private GPSCoordinate getCoordinates(Element coordNode) {
|
||||
|
||||
double startLat = Double.parseDouble(getTextValueOfNode(coordNode, "latitude"));
|
||||
double startLong = Double.parseDouble(getTextValueOfNode(coordNode, "longitude"));
|
||||
return new GPSCoordinate(startLat, startLong);
|
||||
}
|
||||
|
||||
public List<Boat> getBoats() {
|
||||
return boats;
|
||||
}
|
||||
|
||||
public List<Leg> getLegs() {
|
||||
return legs;
|
||||
private void readCompoundMarkSequence() throws StreamedCourseXMLException {
|
||||
Element nCompoundMarkSequence = (Element) doc.getElementsByTagName("CompoundMarkSequence").item(0);
|
||||
NodeList nCorners = nCompoundMarkSequence.getElementsByTagName("Corner");
|
||||
Element markXML = (Element)nCorners.item(0);
|
||||
CompoundMark lastCompoundMark = getCompoundMark(getCompoundMarkID(markXML));
|
||||
String legName = getCompoundMarkName(getCompoundMarkID(markXML));
|
||||
for(int i = 1; i < nCorners.getLength(); i++) {
|
||||
markXML = (Element)nCorners.item(i);
|
||||
CompoundMark currentCompoundMark = getCompoundMark(getCompoundMarkID(markXML));
|
||||
legs.add(new Leg(legName, lastCompoundMark, currentCompoundMark, i-1));
|
||||
lastCompoundMark = currentCompoundMark;
|
||||
legName = getCompoundMarkName(getCompoundMarkID(markXML));
|
||||
}
|
||||
}
|
||||
|
||||
public GPSCoordinate getMark() {
|
||||
return mark;
|
||||
}
|
||||
private void readCourseLimit() {
|
||||
Element nCourseLimit = (Element) doc.getElementsByTagName("CourseLimit").item(0);
|
||||
for(int i = 0; i < nCourseLimit.getChildNodes().getLength(); i++) {
|
||||
Node limit = nCourseLimit.getChildNodes().item(i);
|
||||
if (limit.getNodeName().equals("Limit")) {
|
||||
double lat = Double.parseDouble(limit.getAttributes().getNamedItem("Lat").getTextContent());
|
||||
double lon = Double.parseDouble(limit.getAttributes().getNamedItem("Lon").getTextContent());
|
||||
boundary.add(new GPSCoordinate(lat, lon));
|
||||
}
|
||||
}
|
||||
|
||||
public GPSCoordinate getStartPt1() {
|
||||
return startPt1;
|
||||
}
|
||||
|
||||
public GPSCoordinate getStartPt2() {
|
||||
return startPt2;
|
||||
}
|
||||
double maxLatitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING;
|
||||
double maxLongitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude() + COORDINATEPADDING;
|
||||
double minLatitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING;
|
||||
double minLongitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude() + COORDINATEPADDING;
|
||||
|
||||
public GPSCoordinate getFinishPt1() {
|
||||
return finishPt1;
|
||||
mapTopLeft = new GPSCoordinate(minLatitude, minLongitude);
|
||||
mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude);
|
||||
}
|
||||
|
||||
public GPSCoordinate getFinishPt2() {
|
||||
return finishPt2;
|
||||
public List<GPSCoordinate> getBoundary() {
|
||||
return boundary;
|
||||
}
|
||||
|
||||
public GPSCoordinate getLeewardPt1() {
|
||||
return leewardPt1;
|
||||
public GPSCoordinate getMapTopLeft() {
|
||||
return mapTopLeft;
|
||||
}
|
||||
|
||||
public GPSCoordinate getLeewardPt2() {
|
||||
return leewardPt2;
|
||||
public GPSCoordinate getMapBottomRight() {
|
||||
return mapBottomRight;
|
||||
}
|
||||
|
||||
public GPSCoordinate getWindwardPt1() {
|
||||
return windwardPt1;
|
||||
public List<Leg> getLegs() {
|
||||
return legs;
|
||||
}
|
||||
|
||||
public GPSCoordinate getWindwardPt2() {
|
||||
return windwardPt2;
|
||||
}
|
||||
public List<CompoundMark> getCompoundMarks() { return compoundMarks; }
|
||||
|
||||
public List<GPSCoordinate> getBoundary() {
|
||||
return boundary;
|
||||
public Double getPadding() {
|
||||
return COORDINATEPADDING;
|
||||
}
|
||||
|
||||
public GPSCoordinate getMapTopLeft() {
|
||||
return mapTopLeft;
|
||||
public ZonedDateTime getCreationTimeDate() {
|
||||
return creationTimeDate;
|
||||
}
|
||||
|
||||
public GPSCoordinate getMapBottomRight() {
|
||||
return mapBottomRight;
|
||||
public ZonedDateTime getZonedDateTime() {
|
||||
return raceStartTime;
|
||||
}
|
||||
|
||||
public int getRaceId() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
public List<CompoundMark> getCompoundMarks() {
|
||||
return compoundMarks;
|
||||
public String getRaceType() {
|
||||
return raceType;
|
||||
}
|
||||
|
||||
public String getRaceType() {
|
||||
return "FLEET";
|
||||
public boolean isPostpone() {
|
||||
return postpone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZonedDateTime getZonedDateTime() {
|
||||
return null;
|
||||
public List<Boat> getBoats() {
|
||||
return new ArrayList<>(participants.values());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package seng302.Model;
|
||||
package seng302.Exceptions;
|
||||
|
||||
/**
|
||||
* Created by cbt24 on 25/04/17.
|
||||
@ -1,274 +0,0 @@
|
||||
package seng302.Model;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
import seng302.DataInput.BoatDataSource;
|
||||
import seng302.DataInput.RaceDataSource;
|
||||
import seng302.DataInput.XMLReader;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by jjg64 on 21/04/17.
|
||||
*/
|
||||
public class StreamedCourseXMLReader extends XMLReader implements RaceDataSource {
|
||||
private static final double COORDINATEPADDING = 0.000;
|
||||
private GPSCoordinate mapTopLeft, mapBottomRight;
|
||||
private final List<GPSCoordinate> boundary = new ArrayList<>();
|
||||
private final Map<Integer,Element> compoundMarkMap = new HashMap<>();
|
||||
private final Map<Integer, Boat> participants = new HashMap<>();
|
||||
private final List<Leg> legs = new ArrayList<>();
|
||||
private final List<CompoundMark> compoundMarks = new ArrayList<>();
|
||||
private ZonedDateTime creationTimeDate;
|
||||
private ZonedDateTime raceStartTime;
|
||||
private int raceID;
|
||||
private String raceType;
|
||||
private boolean postpone;
|
||||
|
||||
private Map<Integer, Boat> boats;
|
||||
private Map<Integer, Mark> marks;
|
||||
|
||||
/**
|
||||
* 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, BoatDataSource boatData) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
|
||||
this(filePath, boatData, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Streamed Race XML
|
||||
* @param filePath file path to read
|
||||
* @param read whether or not to read and store the files straight away.
|
||||
* @throws IOException error
|
||||
* @throws SAXException error
|
||||
* @throws ParserConfigurationException error
|
||||
* @throws ParseException error
|
||||
* @throws StreamedCourseXMLException error
|
||||
*/
|
||||
public StreamedCourseXMLReader(String filePath, BoatDataSource boatData, boolean read) throws IOException, SAXException, ParserConfigurationException, ParseException, StreamedCourseXMLException {
|
||||
super(filePath);
|
||||
this.boats = boatData.getBoats();
|
||||
this.marks = boatData.getMarkerBoats();
|
||||
if (read) {
|
||||
read();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reads
|
||||
* @throws StreamedCourseXMLException error
|
||||
*/
|
||||
private void read() throws StreamedCourseXMLException {
|
||||
readRace();
|
||||
readParticipants();
|
||||
readCourse();
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a race
|
||||
*/
|
||||
private void readRace() {
|
||||
DateTimeFormatter dateFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||
Element settings = (Element) doc.getElementsByTagName("Race").item(0);
|
||||
NamedNodeMap raceTimeTag = doc.getElementsByTagName("RaceStartTime").item(0).getAttributes();
|
||||
|
||||
if (raceTimeTag.getNamedItem("Time") != null) dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
|
||||
|
||||
raceID = Integer.parseInt(getTextValueOfNode(settings, "RaceID"));
|
||||
raceType = getTextValueOfNode(settings, "RaceType");
|
||||
|
||||
creationTimeDate = ZonedDateTime.parse(getTextValueOfNode(settings, "CreationTimeDate"), dateFormat);
|
||||
|
||||
if (raceTimeTag.getNamedItem("Time") != null) raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Time").getTextContent(), dateFormat);
|
||||
else raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Start").getTextContent(), dateFormat);
|
||||
|
||||
postpone = Boolean.parseBoolean(raceTimeTag.getNamedItem("Postpone").getTextContent());
|
||||
}
|
||||
|
||||
private void readParticipants() {
|
||||
Element nParticipants = (Element) doc.getElementsByTagName("Participants").item(0);
|
||||
nParticipants.getChildNodes().getLength();
|
||||
for (int i = 0; i < nParticipants.getChildNodes().getLength(); i++) {
|
||||
int sourceID;
|
||||
Node yacht = nParticipants.getChildNodes().item(i);
|
||||
if (yacht.getNodeName().equals("Yacht")) {
|
||||
if (exists(yacht, "SourceID")) {
|
||||
sourceID = Integer.parseInt(yacht.getAttributes().getNamedItem("SourceID").getTextContent());
|
||||
participants.put(sourceID, boats.get(sourceID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a course
|
||||
* @throws StreamedCourseXMLException error
|
||||
*/
|
||||
private void readCourse() throws StreamedCourseXMLException {
|
||||
readCompoundMarks();
|
||||
readCompoundMarkSequence();
|
||||
readCourseLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes CompoundMark elements by their ID for use in generating the course, and populates list of Markers.
|
||||
* @see CompoundMark
|
||||
*/
|
||||
private void readCompoundMarks() throws StreamedCourseXMLException {
|
||||
Element nCourse = (Element) doc.getElementsByTagName("Course").item(0);
|
||||
for(int i = 0; i < nCourse.getChildNodes().getLength(); i++) {
|
||||
Node compoundMark = nCourse.getChildNodes().item(i);
|
||||
if(compoundMark.getNodeName().equals("CompoundMark")) {
|
||||
int compoundMarkID = getCompoundMarkID((Element) compoundMark);
|
||||
compoundMarkMap.put(compoundMarkID, (Element)compoundMark);
|
||||
compoundMarks.add(getCompoundMark(compoundMarkID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a CompoundMark from the CompoundMark element with given ID.
|
||||
* @param compoundMarkID index of required CompoundMark element
|
||||
* @return generated CompoundMark
|
||||
* @throws StreamedCourseXMLException if CompoundMark element contains unhandled number of compoundMarks
|
||||
* @see CompoundMark
|
||||
*/
|
||||
private CompoundMark getCompoundMark(int compoundMarkID) throws StreamedCourseXMLException {
|
||||
Element compoundMark = compoundMarkMap.get(compoundMarkID);
|
||||
NodeList nMarks = compoundMark.getElementsByTagName("Mark");
|
||||
CompoundMark marker;
|
||||
|
||||
switch(nMarks.getLength()) {
|
||||
case 1: marker = new CompoundMark(getMark((Element)nMarks.item(0))); break;
|
||||
case 2: marker = new CompoundMark(getMark((Element)nMarks.item(0)), getMark((Element)nMarks.item(1))); break;
|
||||
default: throw new StreamedCourseXMLException();
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
private Mark getMark(Element mark) {
|
||||
int sourceID = Integer.parseInt(mark.getAttribute("SourceID"));
|
||||
System.out.println(marks.get(sourceID).getPosition());
|
||||
return marks.get(sourceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads "compoundMarkID" attribute of CompoundMark or Corner element
|
||||
* @param element with "compoundMarkID" attribute
|
||||
* @return value of "compoundMarkID" attribute
|
||||
*/
|
||||
private int getCompoundMarkID(Element element) {
|
||||
return Integer.parseInt(element.getAttribute("CompoundMarkID"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads "name" attribute of CompoundMark element with corresponding CompoundMarkID
|
||||
* @param compoundMarkID unique ID for CompoundMark element
|
||||
* @return value of "name" attribute
|
||||
*/
|
||||
private String getCompoundMarkName(int compoundMarkID) {
|
||||
return compoundMarkMap.get(compoundMarkID).getAttribute("Name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates list of legs given CompoundMarkSequence element and referenced CompoundMark elements.
|
||||
* @throws StreamedCourseXMLException if compoundMarks cannot be resolved from CompoundMark
|
||||
*/
|
||||
private void readCompoundMarkSequence() throws StreamedCourseXMLException {
|
||||
Element nCompoundMarkSequence = (Element) doc.getElementsByTagName("CompoundMarkSequence").item(0);
|
||||
NodeList nCorners = nCompoundMarkSequence.getElementsByTagName("Corner");
|
||||
Element markXML = (Element)nCorners.item(0);
|
||||
CompoundMark lastCompoundMark = getCompoundMark(getCompoundMarkID(markXML));
|
||||
String legName = getCompoundMarkName(getCompoundMarkID(markXML));
|
||||
for(int i = 1; i < nCorners.getLength(); i++) {
|
||||
markXML = (Element)nCorners.item(i);
|
||||
CompoundMark currentCompoundMark = getCompoundMark(getCompoundMarkID(markXML));
|
||||
legs.add(new Leg(legName, lastCompoundMark, currentCompoundMark, i-1));
|
||||
lastCompoundMark = currentCompoundMark;
|
||||
legName = getCompoundMarkName(getCompoundMarkID(markXML));
|
||||
}
|
||||
}
|
||||
|
||||
private void readCourseLimit() {
|
||||
Element nCourseLimit = (Element) doc.getElementsByTagName("CourseLimit").item(0);
|
||||
for(int i = 0; i < nCourseLimit.getChildNodes().getLength(); i++) {
|
||||
Node limit = nCourseLimit.getChildNodes().item(i);
|
||||
if (limit.getNodeName().equals("Limit")) {
|
||||
double lat = Double.parseDouble(limit.getAttributes().getNamedItem("Lat").getTextContent());
|
||||
double lon = Double.parseDouble(limit.getAttributes().getNamedItem("Lon").getTextContent());
|
||||
boundary.add(new GPSCoordinate(lat, lon));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double maxLatitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING;
|
||||
double maxLongitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude() + COORDINATEPADDING;
|
||||
double minLatitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude() + COORDINATEPADDING;
|
||||
double minLongitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude() + COORDINATEPADDING;
|
||||
|
||||
mapTopLeft = new GPSCoordinate(minLatitude, minLongitude);
|
||||
mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude);
|
||||
}
|
||||
|
||||
public List<GPSCoordinate> getBoundary() {
|
||||
return boundary;
|
||||
}
|
||||
|
||||
public GPSCoordinate getMapTopLeft() {
|
||||
return mapTopLeft;
|
||||
}
|
||||
|
||||
public GPSCoordinate getMapBottomRight() {
|
||||
return mapBottomRight;
|
||||
}
|
||||
|
||||
public List<Leg> getLegs() {
|
||||
return legs;
|
||||
}
|
||||
|
||||
public List<CompoundMark> getCompoundMarks() { return compoundMarks; }
|
||||
|
||||
public Double getPadding() {
|
||||
return COORDINATEPADDING;
|
||||
}
|
||||
|
||||
public ZonedDateTime getCreationTimeDate() {
|
||||
return creationTimeDate;
|
||||
}
|
||||
|
||||
public ZonedDateTime getZonedDateTime() {
|
||||
return raceStartTime;
|
||||
}
|
||||
|
||||
public int getRaceId() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
public String getRaceType() {
|
||||
return raceType;
|
||||
}
|
||||
|
||||
public boolean isPostpone() {
|
||||
return postpone;
|
||||
}
|
||||
|
||||
public List<Boat> getBoats() {
|
||||
return new ArrayList<>(participants.values());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue