Merge branch 'master' into story_64_sails
# Conflicts: # racevisionGame/src/main/java/mock/model/MockRace.java # racevisionGame/src/main/java/visualiser/Controllers/ConnectionController.java # racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java
This commit is contained in:
@@ -4,7 +4,9 @@ import mock.dataInput.PolarParser;
|
||||
import mock.exceptions.EventConstructionException;
|
||||
import mock.model.*;
|
||||
import mock.model.commandFactory.CompositeCommand;
|
||||
import mock.xml.RaceXMLCreator;
|
||||
import network.Messages.LatestMessages;
|
||||
import org.xml.sax.SAXException;
|
||||
import shared.dataInput.*;
|
||||
import shared.enums.XMLFileType;
|
||||
import shared.exceptions.InvalidBoatDataException;
|
||||
@@ -14,6 +16,8 @@ import shared.exceptions.XMLReaderException;
|
||||
import shared.model.Bearing;
|
||||
import shared.model.Constants;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
@@ -82,12 +86,22 @@ public class Event {
|
||||
|
||||
//Read XML files.
|
||||
try {
|
||||
this.raceXML = getRaceXMLAtCurrentTime(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8));
|
||||
this.raceXML = RaceXMLCreator.alterRaceToWind(raceXMLFile, 90);
|
||||
this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8);
|
||||
this.regattaXML = XMLReader.readXMLFileToString(regattaXMLFile, StandardCharsets.UTF_8);
|
||||
|
||||
} catch (XMLReaderException e) {
|
||||
throw new EventConstructionException("Could not read XML files.", e);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidRaceDataException e) {
|
||||
e.printStackTrace();
|
||||
} catch (JAXBException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
this.xmlFileType = XMLFileType.Contents;
|
||||
@@ -171,27 +185,4 @@ public class Event {
|
||||
|
||||
connectionAcceptor.setBoatsXml(boatXML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the xml description of the race to show the race was created now, and starts in 4 minutes
|
||||
* @param raceXML The race.xml contents.
|
||||
* @return String containing edited xml
|
||||
*/
|
||||
private String getRaceXMLAtCurrentTime(String raceXML) {
|
||||
|
||||
//The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute.
|
||||
long millisecondsToAdd = Constants.RacePreStartTime + Duration.ofMinutes(1).toMillis();
|
||||
long secondsToAdd = millisecondsToAdd / 1000;
|
||||
//Scale the time using our time scalar.
|
||||
secondsToAdd = secondsToAdd / Constants.RaceTimeScale;
|
||||
|
||||
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
ZonedDateTime creationTime = ZonedDateTime.now();
|
||||
raceXML = raceXML.replace("CREATION_TIME", dateFormat.format(creationTime));
|
||||
|
||||
raceXML = raceXML.replace("START_TIME", dateFormat.format(creationTime.plusSeconds(secondsToAdd)));
|
||||
|
||||
return raceXML;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
package mock.model;
|
||||
|
||||
import javafx.animation.AnimationTimer;
|
||||
import mock.xml.*;
|
||||
import network.Messages.BoatLocation;
|
||||
import network.Messages.BoatStatus;
|
||||
import network.Messages.Enums.BoatStatusEnum;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
import shared.dataInput.BoatDataSource;
|
||||
@@ -8,6 +12,8 @@ import shared.dataInput.RegattaDataSource;
|
||||
import shared.exceptions.BoatNotFoundException;
|
||||
import shared.enums.RoundingType;
|
||||
import shared.model.*;
|
||||
import shared.model.Bearing;
|
||||
import shared.model.Race;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
@@ -311,7 +317,7 @@ public class MockRace extends Race {
|
||||
//Checks if the current boat has finished the race or not.
|
||||
boolean finish = this.isLastLeg(boat.getCurrentLeg());
|
||||
|
||||
if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds & boat.isSailsOut()) {
|
||||
if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds && boat.isSailsOut()) {
|
||||
|
||||
checkPosition(boat, totalElapsedMilliseconds);
|
||||
|
||||
@@ -389,7 +395,7 @@ public class MockRace extends Race {
|
||||
double lastAngle = -1;
|
||||
boolean lastAngleWasGood = false;
|
||||
|
||||
//Check all bearings between [0, 360).
|
||||
//Check all bearings between [0, 360)
|
||||
for (double angle = 0; angle < 360; angle += 1) {
|
||||
|
||||
//Create bearing from angle.
|
||||
@@ -516,7 +522,7 @@ public class MockRace extends Race {
|
||||
if (boat.isStarboardSide(roundingMark) &&
|
||||
GPSCoordinate.passesLine(roundingMark.getPosition(),
|
||||
roundingChecks.get(0), boat.getPosition(), legBearing) &&
|
||||
gateCheck &&
|
||||
gateCheck &&
|
||||
boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) {
|
||||
boat.increaseRoundingStatus();
|
||||
if (boat.getCurrentLeg().getLegNumber() + 2 >= legs.size()){
|
||||
@@ -625,7 +631,6 @@ public class MockRace extends Race {
|
||||
protected int getNumberOfActiveBoats() {
|
||||
|
||||
int numberOfActiveBoats = 0;
|
||||
|
||||
for (MockBoat boat : this.boats) {
|
||||
|
||||
//If the boat is currently racing, count it.
|
||||
@@ -698,6 +703,7 @@ public class MockRace extends Race {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<CompoundMark> getCompoundMarks() {
|
||||
return compoundMarks;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
package mock.xml;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
import shared.dataInput.RaceXMLReader;
|
||||
import shared.enums.XMLFileType;
|
||||
import shared.exceptions.InvalidRaceDataException;
|
||||
import shared.exceptions.XMLReaderException;
|
||||
import shared.model.*;
|
||||
import shared.xml.Race.*;
|
||||
import shared.xml.XMLUtilities;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.bind.util.JAXBSource;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import javax.xml.validation.Validator;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URL;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Helper Class for creating a Race XML
|
||||
*/
|
||||
public class RaceXMLCreator {
|
||||
|
||||
|
||||
/**
|
||||
* get the windward gate in a race
|
||||
* @param reader reads in the mark
|
||||
* @return the windward gate.
|
||||
*/
|
||||
public static CompoundMark getWindwardGate(RaceXMLReader reader){
|
||||
for (CompoundMark mark: reader.getCompoundMarks()){
|
||||
if (mark.getName().equals("Windward Gate")) return mark;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the leeward gate in a race
|
||||
* @param reader reads in the mark
|
||||
* @return the leeward gate.
|
||||
*/
|
||||
public static CompoundMark getLeewardGate(RaceXMLReader reader){
|
||||
for (CompoundMark mark: reader.getCompoundMarks()){
|
||||
if (mark.getName().equals("Leeward Gate")) return mark;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the race in a specified direction.
|
||||
* @param s xml file name
|
||||
* @param degrees degrees to rotate
|
||||
* @return the new xml file as a string
|
||||
* @throws XMLReaderException if the xml is not readable
|
||||
* @throws InvalidRaceDataException if the race is invalid
|
||||
* @throws JAXBException if the Race class cannot be parsed into a xml.
|
||||
* @throws IOException if the schema file cannot be found
|
||||
* @throws SAXException error in schema file
|
||||
* @throws ParserConfigurationException error in parsing the schema file
|
||||
*/
|
||||
public static String alterRaceToWind(String s, double degrees) throws XMLReaderException, InvalidRaceDataException, JAXBException, IOException, SAXException, ParserConfigurationException {
|
||||
RaceXMLReader reader = new RaceXMLReader(s, XMLFileType.ResourcePath);
|
||||
|
||||
XMLRace race = (XMLRace) XMLUtilities.xmlToClass(new File(RaceXMLCreator.class.getClassLoader().getResource(s).getFile()),
|
||||
RaceXMLCreator.class.getClassLoader().getResource("mock/mockXML/schema/raceSchema.xsd"),
|
||||
XMLRace.class);
|
||||
|
||||
setRaceXMLAtCurrentTimeToNow(race);
|
||||
|
||||
double raceOriginalBearing = getLineAngle(getLeewardGate(reader).getMark1Position(), getWindwardGate(reader).getMark1Position());
|
||||
|
||||
double degreesToRotate = degrees - raceOriginalBearing;
|
||||
|
||||
alterRaceRotation(race, degreesToRotate);
|
||||
|
||||
JAXBContext context = JAXBContext.newInstance(XMLRace.class);
|
||||
Marshaller jaxbMarshaller = context.createMarshaller();
|
||||
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
|
||||
jaxbMarshaller.marshal(race, sw);
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the features in a race such as the boundary, and the marks.
|
||||
* @param race the race to alter
|
||||
* @param degrees the degrees to rotate by.
|
||||
*/
|
||||
public static void alterRaceRotation(XMLRace race, double degrees){
|
||||
GPSCoordinate center = getCenter(race);
|
||||
for(XMLLimit limit: race.getCourseLimit().getLimit()){
|
||||
GPSCoordinate rotatedLim = rotate(center, limitToGPSCoordinate(limit), degrees);
|
||||
limit.setLat(rotatedLim.getLatitude());
|
||||
limit.setLon(rotatedLim.getLongitude());
|
||||
}
|
||||
|
||||
for(XMLCompoundMark compoundMark: race.getCourse().getCompoundMark()){
|
||||
for (XMLMark mark: compoundMark.getMark()){
|
||||
GPSCoordinate rotatedMark = rotate(center, markToGPSCoordinate(mark), degrees);
|
||||
mark.setTargetLat(rotatedMark.getLatitude());
|
||||
mark.setTargetLng(rotatedMark.getLongitude());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Race.CourseLimit.Limit to a GPS coordinate
|
||||
* @param limit limit to convert
|
||||
* @return gps coordinate corresponding to the limit
|
||||
*/
|
||||
public static GPSCoordinate limitToGPSCoordinate(XMLLimit limit){
|
||||
return new GPSCoordinate(limit.getLat(), limit.getLon());
|
||||
}
|
||||
|
||||
/**
|
||||
* get new gps coordinate after rotating
|
||||
* @param pivot center point to rotating from.
|
||||
* @param point point to rotate
|
||||
* @param degrees number of degress to rotate by
|
||||
* @return the new GPSCoordinate of the transformed point.
|
||||
*/
|
||||
public static GPSCoordinate rotate(GPSCoordinate pivot, GPSCoordinate point, double degrees){
|
||||
double radDeg = Math.toRadians(degrees);
|
||||
double deltaLat = (point.getLatitude() - pivot.getLatitude());
|
||||
double deltaLon = (point.getLongitude() - pivot.getLongitude());
|
||||
//map to (0,1) vector and use vector maths to rotate.
|
||||
double resLat = deltaLat * Math.cos(radDeg) - deltaLon * Math.sin(radDeg) + pivot.getLatitude();
|
||||
double resLon = deltaLat * Math.sin(radDeg) + deltaLon * Math.cos(radDeg) + pivot.getLongitude();
|
||||
return new GPSCoordinate(resLat, resLon);
|
||||
}
|
||||
|
||||
/**
|
||||
* obtains the GPSCoordinates of a mark
|
||||
* @param mark mark to obtain the GPSCoordinates of
|
||||
* @return the GPSCOordinatess of a mark
|
||||
*/
|
||||
public static GPSCoordinate markToGPSCoordinate(XMLMark mark){
|
||||
return new GPSCoordinate(mark.getTargetLat(), mark.getTargetLng());
|
||||
}
|
||||
|
||||
/**
|
||||
* get the center of a race
|
||||
* @param race race to get the center of
|
||||
* @return GPSCoordinates of the center
|
||||
*/
|
||||
public static GPSCoordinate getCenter(XMLRace race){
|
||||
double avgLat = 0;
|
||||
double avgLng = 0;
|
||||
for (XMLLimit limit: race.getCourseLimit().getLimit()){
|
||||
avgLat += limit.getLat();
|
||||
avgLng += limit.getLon();
|
||||
}
|
||||
avgLat = avgLat/race.getCourseLimit().getLimit().size();
|
||||
avgLng = avgLng/race.getCourseLimit().getLimit().size();
|
||||
return new GPSCoordinate(avgLat, avgLng);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the angle of a line
|
||||
* @param coord1 point a of the line
|
||||
* @param coord2 point b of the line
|
||||
* @return the angle in degrees that the bearing of the line is [-180, 180]
|
||||
*/
|
||||
public static double getLineAngle(GPSCoordinate coord1, GPSCoordinate coord2){
|
||||
double dx = coord1.getLongitude() - coord2.getLongitude();
|
||||
double dy = coord1.getLatitude() - coord2.getLatitude();
|
||||
return Math.atan2(dy, dx)/Math.PI * 180;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the xml description of the race to show the race was created now, and starts in 4 minutes
|
||||
* @param raceXML The race.xml contents.
|
||||
*/
|
||||
public static void setRaceXMLAtCurrentTimeToNow(XMLRace raceXML) {
|
||||
|
||||
//The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute.
|
||||
long millisecondsToAdd = Constants.RacePreStartTime + (1 * 60 * 1000);
|
||||
long secondsToAdd = millisecondsToAdd / 1000;
|
||||
//Scale the time using our time scalar.
|
||||
secondsToAdd = secondsToAdd / Constants.RaceTimeScale;
|
||||
|
||||
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
ZonedDateTime creationTime = ZonedDateTime.now();
|
||||
raceXML.setCreationTimeDate(dateFormat.format(creationTime));
|
||||
raceXML.getRaceStartTime().setTime(dateFormat.format(creationTime.plusSeconds(secondsToAdd)));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user