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

# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/model/mark/MarkOrder.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
This commit is contained in:
Zhi You Tan
2017-08-15 14:30:01 +12:00
42 changed files with 1106 additions and 477 deletions
@@ -71,8 +71,6 @@ public final class PolarTable {
} catch (IOException e) {
System.out.println("[PolarTable] IO exception");
}
}
@@ -155,7 +153,6 @@ public final class PolarTable {
public static Double getClosestWindSpeedInPolar(Double thisWindSpeed) {
Double smallestDif = Double.POSITIVE_INFINITY;
Double closestWind = 0d;
for (Double polarWindSpeed : polarTable.keySet()) {
Double difference = Math.abs(polarWindSpeed - thisWindSpeed);
if (difference < smallestDif) {
+114 -30
View File
@@ -32,7 +32,7 @@ public class Yacht extends Observable {
@FunctionalInterface
public interface YachtLocationListener {
void notifyLocation(Yacht yacht, double lat, double lon, double heading, double velocity);
void notifyLocation(Yacht yacht, double lat, double lon, double heading, double velocity, boolean sailIn);
}
private Logger logger = LoggerFactory.getLogger(Yacht.class);
@@ -62,12 +62,14 @@ public class Yacht extends Observable {
private Integer legNumber = 0;
//SERVER SIDE
private final Double TURN_STEP = 5.0;
public static final Double TURN_STEP = 5.0; //This should be in some utils class somewhere 2bh. Public for tests sake.
private Double lastHeading;
private Boolean sailIn;
private Boolean sailIn = false;
private GeoPoint location;
private Integer boatStatus;
private Double velocity;
private Boolean isAuto;
private Double autoHeading;
//MARK ROUNDING INFO
private GeoPoint lastLocation; //For purposes of mark rounding calculations
@@ -85,6 +87,7 @@ public class Yacht extends Observable {
private CompoundMark lastMarkRounded;
private Integer positionInt = 0;
private Color colour;
private Boolean clientSailsIn = true;
public Yacht(String boatType, Integer sourceId, String hullID, String shortName,
String boatName, String country) {
@@ -95,6 +98,7 @@ public class Yacht extends Observable {
this.boatName = boatName;
this.country = country;
this.sailIn = false;
this.isAuto = false;
this.location = new GeoPoint(57.670341, 11.826856);
this.lastLocation = location;
this.heading = 120.0; //In degrees
@@ -152,6 +156,11 @@ public class Yacht extends Observable {
}
}
runAutoPilot();
//UPDATE BOAT LOCATION
lastLocation = location;
location = GeoUtility.getGeoCoordinate(location, heading, velocity * secondsElapsed);
Double metersCovered = velocity * secondsElapsed;
GeoPoint calculatedPoint = getGeoCoordinate(location, heading, metersCovered);
@@ -390,15 +399,60 @@ public class Yacht extends Observable {
}
/**
* Adjusts the heading of the boat by a given amount, while recording the boats
* last heading.
*
* @param amount the amount by which to adjust the boat heading.
*/
public void adjustHeading(Double amount) {
Double newVal = heading + amount;
lastHeading = heading;
heading = (double) Math.floorMod(newVal.longValue(), 360L);
}
/**
* Swaps the boats direction from one side of the wind to the other.
*/
public void tackGybe(Double windDirection) {
Double normalizedHeading = normalizeHeading();
adjustHeading(-2 * normalizedHeading);
if (isAuto) {
disableAutoPilot();
} else {
Double normalizedHeading = normalizeHeading();
Double newVal = (-2 * normalizedHeading) + heading;
Double newHeading = (double) Math.floorMod(newVal.longValue(), 360L);
setAutoPilot(newHeading);
}
}
/**
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
* @param thisHeading The heading to move the boat towards.
*/
private void setAutoPilot(Double thisHeading) {
isAuto = true;
autoHeading = thisHeading;
}
/**
* Disables the auto pilot function.
*/
public void disableAutoPilot() {
isAuto = false;
}
/**
* Moves the boat towards the given heading when the auto pilot was set. Disables the auto pilot
* in the event that the boat is within the range of 1 turn step of its goal.
*/
public void runAutoPilot() {
if (isAuto) {
turnTowardsHeading(autoHeading);
if (Math.abs(heading - autoHeading)
<= TURN_STEP) { //Cancel when within 1 turn step of target.
isAuto = false;
}
}
}
public void toggleSailIn() {
@@ -406,6 +460,7 @@ public class Yacht extends Observable {
}
public void turnUpwind() {
disableAutoPilot();
Double normalizedHeading = normalizeHeading();
if (normalizedHeading == 0) {
if (lastHeading < 180) {
@@ -427,6 +482,7 @@ public class Yacht extends Observable {
}
public void turnDownwind() {
disableAutoPilot();
Double normalizedHeading = normalizeHeading();
if (normalizedHeading == 0) {
if (lastHeading < 180) {
@@ -447,38 +503,59 @@ public class Yacht extends Observable {
}
}
/**
* Takes the VMG from the polartable for upwind or downwind depending on the boats direction,
* and uses this to calculate a heading to move the yacht towards.
*/
public void turnToVMG() {
Double normalizedHeading = normalizeHeading();
Double optimalHeading;
HashMap<Double, Double> optimalPolarMap;
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
optimalHeading = optimalPolarMap.keySet().iterator().next();
if (isAuto) {
disableAutoPilot();
} else {
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
optimalHeading = optimalPolarMap.keySet().iterator().next();
}
// Take optimal heading and turn into correct
optimalHeading =
optimalHeading + (double) Math.floorMod(GameState.getWindDirection().longValue(), 360L);
Double normalizedHeading = normalizeHeading();
Double optimalHeading;
HashMap<Double, Double> optimalPolarMap;
turnTowardsHeading(optimalHeading);
}
private void turnTowardsHeading(Double newHeading) {
if (heading < 90 && newHeading > 270) {
adjustHeading(-TURN_STEP);
} else {
if (heading < newHeading) {
adjustHeading(TURN_STEP);
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
} else {
adjustHeading(-TURN_STEP);
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
}
optimalHeading = optimalPolarMap.keySet().iterator().next();
if (normalizedHeading > 180) {
optimalHeading = 360 - optimalHeading;
}
// Take optimal heading and turn into a boat heading rather than a wind heading.
optimalHeading =
optimalHeading + GameState.getWindDirection();
setAutoPilot(optimalHeading);
}
}
/**
* Takes a given heading and rotates the boat towards that heading.
* This does not care about being upwind or downwind, just which direction will reach a given
* heading faster.
*
* @param newHeading The heading to turn the yacht towards.
*/
private void turnTowardsHeading(Double newHeading) {
Double newVal = heading - newHeading;
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
adjustHeading(TURN_STEP / 5);
} else {
adjustHeading(-TURN_STEP / 5);
}
}
/**
* Returns a heading normalized for the wind direction. Heading direction into the wind is 0,
* directly away is 180.
*
* @return The normalized heading accounting for wind direction.
*/
private Double normalizeHeading() {
Double normalizedHeading = heading - GameState.windDirection;
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
@@ -654,6 +731,9 @@ public class Yacht extends Observable {
this.colour = colour;
}
public void toggleClientSail() {
clientSailsIn = !clientSailsIn;
}
public Double getVelocity() {
return velocity;
@@ -667,13 +747,17 @@ public class Yacht extends Observable {
return distanceToCurrentMark;
}
public Boolean getClientSailsIn(){
return clientSailsIn;
}
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, lng, heading, velocity);
yll.notifyLocation(this, lat, lng, heading, velocity, clientSailsIn);
}
}
@@ -15,7 +15,7 @@ public class CompoundMark {
public CompoundMark(int markID, String name, List<Mark> marks) {
this.compoundMarkId = markID;
this.name = name;
this.name = name;
this.marks.addAll(marks);
if (marks.size() > 1) {
this.midPoint = GeoUtility.getDirtyMidPoint(marks.get(0), marks.get(1));
+12 -14
View File
@@ -1,5 +1,10 @@
package seng302.model.mark;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
@@ -9,12 +14,6 @@ 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.*;
/**
@@ -33,7 +32,7 @@ public class MarkOrder {
* @return An ordered list of marks in the race
* OR null if the mark order could not be loaded
*/
public List<CompoundMark> getMarkOrder(){
public List<CompoundMark> getMarkOrder() {
if (raceMarkOrder == null){
logger.warn("Race order accessed but not instantiated");
return null;
@@ -53,10 +52,9 @@ public class MarkOrder {
/**
* @param currentSeqID The seqID of the current mark the boat is heading to
* @return The mark last passed
* @throws IndexOutOfBoundsException if there is no next mark.
* Check seqID != 0 first
* @throws IndexOutOfBoundsException if there is no next mark. Check seqID != 0 first
*/
public CompoundMark getPreviousMark(Integer currentSeqID) throws IndexOutOfBoundsException{
public CompoundMark getPreviousMark(Integer currentSeqID) throws IndexOutOfBoundsException {
return raceMarkOrder.get(currentSeqID - 1);
}
@@ -67,10 +65,10 @@ public class MarkOrder {
/**
* @param currentSeqID The seqID of the current mark the boat is heading to
* @return The mark following the mark that the boat is heading to
* @throws IndexOutOfBoundsException if there is no next mark.
* Check using {@link #isLastMark(Integer)}
* @throws IndexOutOfBoundsException if there is no next mark. Check using {@link
* #isLastMark(Integer)}
*/
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException{
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException {
return raceMarkOrder.get(currentSeqID + 1);
}
@@ -83,7 +81,7 @@ public class MarkOrder {
* @param xml An AC35 RaceXML
* @return An ordered list of marks in the race
*/
private List<CompoundMark> loadRaceOrderFromXML(String xml){
private List<CompoundMark> loadRaceOrderFromXML(String xml) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
@@ -19,7 +19,9 @@ public enum PacketType {
COURSE_WIND,
AVG_WIND,
BOAT_ACTION,
OTHER;
OTHER,
RACE_REGISTRATION_REQUEST,
RACE_REGISTRATION_RESPONSE;
public static PacketType assignPacketType(int packetType, byte[] payload){
switch(packetType){
@@ -56,6 +58,10 @@ public enum PacketType {
return AVG_WIND;
case 100:
return BOAT_ACTION;
case 101:
return RACE_REGISTRATION_REQUEST;
case 102:
return RACE_REGISTRATION_RESPONSE;
default:
}
return OTHER;