Merge remote-tracking branch 'origin/develop' into Story66_Collision

# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/model/Yacht.java
This commit is contained in:
Zhi You Tan
2017-08-08 17:04:34 +12:00
15 changed files with 772 additions and 534 deletions
+64 -23
View File
@@ -14,6 +14,7 @@ import javafx.beans.property.ReadOnlyLongWrapper;
import javafx.scene.paint.Color;
import seng302.gameServer.GameState;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.utilities.GeoUtility;
/**
@@ -29,6 +30,8 @@ public class Yacht {
void notifyLocation(Yacht yacht, double lat, double lon, double heading, double velocity);
}
private static final Double ROUNDING_DISTANCE = 15d; // TODO: 3/08/17 wmu16 - Look into this value further
//BOTH AFAIK
private String boatType;
private Integer sourceId;
@@ -38,12 +41,12 @@ public class Yacht {
private String country;
private Long estimateTimeAtFinish;
private Long timeTillNext;
private Long lastMark;
private Long markRoundTime;
private Double distanceToNextMark;
private Long timeTillNext;
private CompoundMark nextMark;
private Double heading;
private Double lat;
private Double lon;
private Integer legNumber = 0;
//SERVER SIDE
@@ -53,6 +56,11 @@ public class Yacht {
private GeoPoint location;
private Integer boatStatus;
private Double velocity;
//MARK ROUNDING INFO
private GeoPoint lastLocation; //For purposes of mark rounding calculations
private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round
private Boolean hasPassedFirstLine; //The line extrapolated from the next mark to the current mark
private Boolean hasPassedSecondLine; //The line extrapolated from the last mark to the current mark
//CLIENT SIDE
private List<YachtLocationListener> locationListeners = new ArrayList<>();
@@ -73,8 +81,13 @@ public class Yacht {
this.country = country;
this.sailIn = false;
this.location = new GeoPoint(57.670341, 11.826856);
this.lastLocation = location;
this.heading = 120.0; //In degrees
this.velocity = 0d; //in mms-1
this.hasEnteredRoundingZone = false;
this.hasPassedFirstLine = false;
this.hasPassedSecondLine = false;
}
/**
@@ -120,6 +133,34 @@ public class Yacht {
} else {
location = calculatedPoint;
}
//CHECK FOR MARK ROUNDING
distanceToNextMark = calcDistanceToNextMark();
if (distanceToNextMark < ROUNDING_DISTANCE) {
hasEnteredRoundingZone = true;
}
// TODO: 3/08/17 wmu16 - Implement line cross check here
}
/**
* Calculates the distance to the next mark (closest of the two if a gate mark).
*
* @return A distance in metres. Returns -1 if there is no next mark
*/
public Double calcDistanceToNextMark() {
if (nextMark == null) {
return -1d;
} else if (nextMark.isGate()) {
Mark sub1 = nextMark.getSubMark(1);
Mark sub2 = nextMark.getSubMark(2);
Double distance1 = GeoUtility.getDistance(location, sub1);
Double distance2 = GeoUtility.getDistance(location, sub2);
return (distance1 < distance2) ? distance1 : distance2;
} else {
return GeoUtility.getDistance(location, nextMark.getSubMark(1));
}
}
public void adjustHeading(Double amount) {
@@ -340,20 +381,21 @@ public class Yacht {
return nextMark;
}
public Double getLat() {
return lat;
public GeoPoint getLocation() {
return location;
}
public void setLat(Double lat) {
this.lat = lat;
}
public Double getLon() {
return lon;
}
public void setLon(Double lon) {
this.lon = lon;
/**
* Sets the current location of the boat in lat and long whilst preserving the last location
*
* @param lat Latitude
* @param lng Longitude
*/
public void setLocation(Double lat, Double lng) {
lastLocation.setLat(location.getLat());
lastLocation.setLng(location.getLng());
location.setLat(lat);
location.setLng(lng);
}
public Double getHeading() {
@@ -373,10 +415,6 @@ public class Yacht {
return boatName;
}
public GeoPoint getLocation() {
return location;
}
public void updateTimeSinceLastMarkProperty(long timeSinceLastMark) {
this.timeSinceLastMarkProperty.set(timeSinceLastMark);
}
@@ -407,14 +445,17 @@ public class Yacht {
this.velocity = velocity;
}
public void updateLocation(double lat, double lon, double heading, double velocity) {
this.lat = lat;
this.lon = lon;
public Double getDistanceToNextMark() {
return distanceToNextMark;
}
public void updateLocation(double lat, double lng, double heading, double velocity) {
setLocation(lat, lng);
this.heading = heading;
this.velocity = velocity;
updateVelocityProperty(velocity);
for (YachtLocationListener yll : locationListeners) {
yll.notifyLocation(this, lat, lon, heading, velocity);
yll.notifyLocation(this, lat, lng, heading, velocity);
}
}
@@ -86,4 +86,46 @@ public class CompoundMark {
public List<Mark> getMarks () {
return marks;
}
// @Override
// public boolean equals(Object other) {
// if (other == null) {
// return false;
// }
//
// if (!(other instanceof Mark)){
// return false;
// }
//
// Mark otherMark = (Mark) other;
//
// if (otherMark.getLat() != getLat() || otherMark.getLongitude() != getLongitude()) {
// return false;
// }
//
// if (otherMark.getCompoundMarkID() != getCompoundMarkID()){
// return false;
// }
//
// if (otherMark.getId() != getId()){
// return false;
// }
//
// if (!otherMark.getName().equals(name)){
// return false;
// }
//
// return true;
// }
@Override
public int hashCode() {
int hash = 0;
for (Mark mark : marks) {
hash += Double.hashCode(mark.getSourceID()) + Double.hashCode(mark.getLat())
+ Double.hashCode(mark.getLng()) + mark.getName().hashCode();
}
return hash + getName().hashCode() + Integer.hashCode(getId());
}
}
@@ -0,0 +1,135 @@
package seng302.model.mark;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Class to hold the order of the marks in the race.
*/
public class MarkOrder {
private List<Mark> raceMarkOrder;
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
public MarkOrder(){
loadRaceProperties();
}
/**
* @return An ordered list of marks in the race
* OR null if the mark order could not be loaded
*/
public List<Mark> getMarkOrder(){
if (raceMarkOrder == null){
logger.warn("Race order accessed but not instantiated");
return null;
}
return Collections.unmodifiableList(raceMarkOrder);
}
/**
* Returns the mark in the race after the previous mark
* @param position The current race position
* @return the next race position
* OR null if there is no position
*/
public RacePosition getNextPosition(RacePosition position){
Mark previousMark = position.getNextMark();
Mark nextMark;
if (position.getPositionIndex() + 1 >= raceMarkOrder.size() - 1){
RacePosition nextRacePosition = new RacePosition(raceMarkOrder.size() - 1, null, previousMark);
nextRacePosition.setFinishingLeg();
return nextRacePosition;
}
Integer nextPositionIndex = position.getPositionIndex() + 1;
RacePosition nextRacePosition = new RacePosition(nextPositionIndex, raceMarkOrder.get(nextPositionIndex), previousMark);
return nextRacePosition;
}
/**
* Loads the race order from an XML string
* @param xml An AC35 RaceXML
* @return An ordered list of marks in the race
*/
private List<Mark> loadRaceOrderFromXML(String xml){
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
Document doc;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(new InputSource(new StringReader(xml)));
} catch (ParserConfigurationException | IOException | SAXException e) {
logger.error("Failed to read generated race XML");
return null;
}
RaceXMLData data = XMLParser.parseRace(doc);
if (data != null){
logger.debug("Loaded RaceXML for mark order");
List<Corner> corners = data.getMarkSequence();
Map<Integer, CompoundMark> marks = data.getCompoundMarks();
List<Mark> course = new ArrayList<>();
for (Corner corner : corners){
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
course.add(compoundMark.getMarks().get(0));
}
return course;
}
return null;
}
/**
* @return The first position in the race
*/
public RacePosition getFirstPosition(){
if (raceMarkOrder.size() > 0){
return new RacePosition(-1, raceMarkOrder.get(0), null);
}
return null;
}
/**
* Load the raceXML and mark order
*/
private void loadRaceProperties(){
XMLGenerator generator = new XMLGenerator();
generator.setRace(new Race());
String raceXML = generator.getRaceAsXml();
if (raceXML == null){
logger.error("Failed to generate raceXML (for race properties)");
return;
}
raceMarkOrder = loadRaceOrderFromXML(raceXML);
}
}
@@ -0,0 +1,55 @@
package seng302.model.mark;
/**
* Represents a boats position between two marks
*/
public class RacePosition {
private Integer positionIndex;
private Mark nextMark;
private Mark previousMark;
private Boolean isFinishingLeg;
public RacePosition(Integer positionIndex, Mark nextMark, Mark previousMark){
this.positionIndex = positionIndex;
this.nextMark = nextMark;
this.previousMark = previousMark;
isFinishingLeg = false;
}
/**
* @return The position of the boat (0...number of marks in race - 1)
*/
public Integer getPositionIndex(){
return positionIndex;
}
/**
* @return The mark the boat is heading to
* will return NULL if this is the finishing legg
*/
public Mark getNextMark(){
return nextMark;
}
/**
* @return The mark the boat is heading away from,
* Will return NULL if this is the starting leg
*/
public Mark getPreviousMark(){
return previousMark;
}
/**
* Sets a flag that this is the last leg in the race
*/
public void setFinishingLeg(){
isFinishingLeg = true;
}
/**
* @return true if this is the last leg in the race
*/
public boolean getIsFinishingLeg() {
return isFinishingLeg;
}
}