Merge branch 'master' into issue_18_track_alpha

# Conflicts:
#	racevisionGame/src/main/java/visualiser/model/VisualiserRaceState.java
main
fjc40 8 years ago
commit 0f58270c10

@ -4,6 +4,7 @@ import mock.model.RaceLogic;
import mock.model.ClientConnection; import mock.model.ClientConnection;
import mock.model.SourceIdAllocator; import mock.model.SourceIdAllocator;
import mock.model.commandFactory.CompositeCommand; import mock.model.commandFactory.CompositeCommand;
import network.AckSequencer;
import network.Messages.Enums.XMLMessageType; import network.Messages.Enums.XMLMessageType;
import network.Messages.LatestMessages; import network.Messages.LatestMessages;
import network.Messages.XMLMessage; import network.Messages.XMLMessage;
@ -58,11 +59,6 @@ public class ConnectionAcceptor implements Runnable {
*/ */
private SourceIdAllocator sourceIdAllocator; private SourceIdAllocator sourceIdAllocator;
//Acknowledgement number for packets
private int ackNumber = 0;
//race xml sequence number //race xml sequence number
private short raceXMLSequenceNumber; private short raceXMLSequenceNumber;
//boat xml sequence number //boat xml sequence number
@ -263,7 +259,7 @@ public class ConnectionAcceptor implements Runnable {
//Create the message. //Create the message.
XMLMessage message = new XMLMessage( XMLMessage message = new XMLMessage(
XMLMessage.currentVersionNumber, XMLMessage.currentVersionNumber,
getNextAckNumber(), AckSequencer.getNextAckNum(),
System.currentTimeMillis(), System.currentTimeMillis(),
messageType, messageType,
sequenceNumber, sequenceNumber,
@ -272,15 +268,4 @@ public class ConnectionAcceptor implements Runnable {
return message; return message;
} }
/**
* Increments the ackNumber value, and returns it.
* @return Incremented ackNumber.
*/
private int getNextAckNumber(){
this.ackNumber++;
return this.ackNumber;
}
} }

@ -1,6 +1,5 @@
package mock.model; package mock.model;
import shared.model.*; import shared.model.*;
@ -74,7 +73,7 @@ public class MockBoat extends Boat {
public Bearing calculateBearingToNextMarker() { public Bearing calculateBearingToNextMarker() {
//Get the start and end points. //Get the start and end points.
GPSCoordinate currentPosition = this.getCurrentPosition(); GPSCoordinate currentPosition = this.getPosition();
GPSCoordinate nextMarkerPosition; GPSCoordinate nextMarkerPosition;
// if boat is at the finish // if boat is at the finish
@ -87,7 +86,6 @@ public class MockBoat extends Boat {
//Calculate bearing. //Calculate bearing.
Bearing bearing = GPSCoordinate.calculateBearing(currentPosition, nextMarkerPosition); Bearing bearing = GPSCoordinate.calculateBearing(currentPosition, nextMarkerPosition);
return bearing; return bearing;
} }
@ -100,7 +98,7 @@ public class MockBoat extends Boat {
public double calculateDistanceToNextMarker() { public double calculateDistanceToNextMarker() {
//Get start and end markers. //Get start and end markers.
GPSCoordinate startPosition = this.getCurrentPosition(); GPSCoordinate startPosition = this.getPosition();
//When boats finish, their "current leg" doesn't have an end marker. //When boats finish, their "current leg" doesn't have an end marker.
if (this.getCurrentLeg().getEndCompoundMark() == null) { if (this.getCurrentLeg().getEndCompoundMark() == null) {
@ -111,9 +109,7 @@ public class MockBoat extends Boat {
//Calculate distance. //Calculate distance.
double distanceNauticalMiles = GPSCoordinate.calculateDistanceNauticalMiles(startPosition, endMarker); return GPSCoordinate.calculateDistanceNauticalMiles(startPosition, endMarker);
return distanceNauticalMiles;
} }
@ -160,8 +156,8 @@ public class MockBoat extends Boat {
*/ */
public void moveForwards(double meters) { public void moveForwards(double meters) {
//Updates the current position of the boat. //Updates the current position of the boat.
GPSCoordinate newPosition = GPSCoordinate.calculateNewPosition(this.getCurrentPosition(), meters, Azimuth.fromBearing(this.getBearing())); GPSCoordinate newPosition = GPSCoordinate.calculateNewPosition(this.getPosition(), meters, Azimuth.fromBearing(this.getBearing()));
this.setCurrentPosition(newPosition); this.setPosition(newPosition);
} }
@ -219,7 +215,7 @@ public class MockBoat extends Boat {
* @return true if mark is on port side * @return true if mark is on port side
*/ */
public boolean isPortSide(Mark mark){ public boolean isPortSide(Mark mark){
Bearing towardsMark = GPSCoordinate.calculateBearing(this.getCurrentPosition(), mark.getPosition()); Bearing towardsMark = GPSCoordinate.calculateBearing(this.getPosition(), mark.getPosition());
if (towardsMark.degrees() > 315 || towardsMark.degrees() <= 45){ if (towardsMark.degrees() > 315 || towardsMark.degrees() <= 45){
//south quadrant //south quadrant
return this.getBearing().degrees() <= 180; return this.getBearing().degrees() <= 180;
@ -245,7 +241,7 @@ public class MockBoat extends Boat {
*/ */
public boolean isStarboardSide(Mark mark){ public boolean isStarboardSide(Mark mark){
//if this boat is lower than the mark check which way it is facing //if this boat is lower than the mark check which way it is facing
Bearing towardsMark = GPSCoordinate.calculateBearing(this.getCurrentPosition(), mark.getPosition()); Bearing towardsMark = GPSCoordinate.calculateBearing(this.getPosition(), mark.getPosition());
if (towardsMark.degrees() > 315 || towardsMark.degrees() <= 45){ if (towardsMark.degrees() > 315 || towardsMark.degrees() <= 45){
//south quadrant //south quadrant
return !(this.getBearing().degrees() <= 180); return !(this.getBearing().degrees() <= 180);
@ -297,12 +293,11 @@ public class MockBoat extends Boat {
this.roundingStatus = 0; this.roundingStatus = 0;
} }
public boolean getAutoVMG(){
return autoVMG;
}
public void setAutoVMG(boolean autoVMG) { public void setAutoVMG(boolean autoVMG) {
this.autoVMG = autoVMG; this.autoVMG = autoVMG;
} }
public boolean getAutoVMG(){
return autoVMG;
}
} }

@ -2,7 +2,6 @@ package mock.model;
import network.Messages.Enums.BoatStatusEnum; import network.Messages.Enums.BoatStatusEnum;
import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceStatusEnum;
import network.Messages.LatestMessages;
import shared.dataInput.BoatDataSource; import shared.dataInput.BoatDataSource;
import shared.dataInput.RaceDataSource; import shared.dataInput.RaceDataSource;
import shared.dataInput.RegattaDataSource; import shared.dataInput.RegattaDataSource;
@ -29,8 +28,6 @@ public class MockRace extends Race {
*/ */
private List<MockBoat> boats; private List<MockBoat> boats;
/** /**
* A copy of the boundary list, except "shrunk" inwards by 50m. * A copy of the boundary list, except "shrunk" inwards by 50m.
*/ */
@ -72,6 +69,8 @@ public class MockRace extends Race {
//Wind. //Wind.
this.setWind(windGenerator.generateBaselineWind()); this.setWind(windGenerator.generateBaselineWind());
this.colliderRegistry.addAllColliders(boats);
} }
/** /**
@ -195,7 +194,7 @@ public class MockRace extends Race {
boat.setCurrentSpeed(0d); boat.setCurrentSpeed(0d);
//Place the boat at its starting position. //Place the boat at its starting position.
boat.setCurrentPosition(startPosition); boat.setPosition(startPosition);
//Boats start facing their next marker. //Boats start facing their next marker.
boat.setBearing(boat.calculateBearingToNextMarker()); boat.setBearing(boat.calculateBearingToNextMarker());
@ -400,7 +399,7 @@ public class MockRace extends Race {
Bearing bearing = Bearing.fromDegrees(angle); Bearing bearing = Bearing.fromDegrees(angle);
//Check that if it is acceptable. //Check that if it is acceptable.
boolean bearingIsGood = this.checkBearingInsideCourse(bearing, boat.getCurrentPosition()); boolean bearingIsGood = this.checkBearingInsideCourse(bearing, boat.getPosition());
if (lastAngle != -1) { if (lastAngle != -1) {
@ -475,7 +474,7 @@ public class MockRace extends Race {
case 0://hasn't started rounding case 0://hasn't started rounding
if (boat.isPortSide(roundingMark) && if (boat.isPortSide(roundingMark) &&
GPSCoordinate.passesLine(roundingMark.getPosition(), GPSCoordinate.passesLine(roundingMark.getPosition(),
roundingChecks.get(0), boat.getCurrentPosition(), legBearing) && roundingChecks.get(0), boat.getPosition(), legBearing) &&
gateCheck && boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) { gateCheck && boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) {
boat.increaseRoundingStatus(); boat.increaseRoundingStatus();
if (boat.getCurrentLeg().getLegNumber() + 2 >= legs.size()){ if (boat.getCurrentLeg().getLegNumber() + 2 >= legs.size()){
@ -487,7 +486,7 @@ public class MockRace extends Race {
case 1://has been parallel to the mark; case 1://has been parallel to the mark;
if (boat.isPortSide(roundingMark) && if (boat.isPortSide(roundingMark) &&
GPSCoordinate.passesLine(roundingMark.getPosition(), GPSCoordinate.passesLine(roundingMark.getPosition(),
roundingChecks.get(1), boat.getCurrentPosition(), roundingChecks.get(1), boat.getPosition(),
Bearing.fromDegrees(legBearing.degrees() - 90)) &&//negative 90 from bearing because of port rounding Bearing.fromDegrees(legBearing.degrees() - 90)) &&//negative 90 from bearing because of port rounding
boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) { boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) {
boat.increaseRoundingStatus(); boat.increaseRoundingStatus();
@ -519,7 +518,7 @@ public class MockRace extends Race {
case 0://hasn't started rounding case 0://hasn't started rounding
if (boat.isStarboardSide(roundingMark) && if (boat.isStarboardSide(roundingMark) &&
GPSCoordinate.passesLine(roundingMark.getPosition(), GPSCoordinate.passesLine(roundingMark.getPosition(),
roundingChecks.get(0), boat.getCurrentPosition(), legBearing) && roundingChecks.get(0), boat.getPosition(), legBearing) &&
gateCheck && gateCheck &&
boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) { boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) {
boat.increaseRoundingStatus(); boat.increaseRoundingStatus();
@ -532,7 +531,7 @@ public class MockRace extends Race {
case 1://has been parallel to the mark case 1://has been parallel to the mark
if (boat.isStarboardSide(roundingMark) && if (boat.isStarboardSide(roundingMark) &&
GPSCoordinate.passesLine(roundingMark.getPosition(), GPSCoordinate.passesLine(roundingMark.getPosition(),
roundingChecks.get(1), boat.getCurrentPosition(), Bearing.fromDegrees(legBearing.degrees() + 90)) && //positive 90 from bearing because of starboard rounding roundingChecks.get(1), boat.getPosition(), Bearing.fromDegrees(legBearing.degrees() + 90)) && //positive 90 from bearing because of starboard rounding
boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) { boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) {
boat.increaseRoundingStatus(); boat.increaseRoundingStatus();
} }

@ -1,6 +1,8 @@
package mock.model; package mock.model;
import javafx.animation.AnimationTimer; import javafx.animation.AnimationTimer;
import mock.model.collider.Collision;
import mock.model.commandFactory.Command;
import mock.model.commandFactory.CompositeCommand; import mock.model.commandFactory.CompositeCommand;
import mock.model.commandFactory.CommandFactory; import mock.model.commandFactory.CommandFactory;
import network.Messages.Enums.BoatActionEnum; import network.Messages.Enums.BoatActionEnum;
@ -9,8 +11,11 @@ import network.Messages.Enums.RaceStatusEnum;
import network.Messages.LatestMessages; import network.Messages.LatestMessages;
import shared.model.RunnableWithFramePeriod; import shared.model.RunnableWithFramePeriod;
import java.util.Observable;
import java.util.Observer;
public class RaceLogic implements RunnableWithFramePeriod {
public class RaceLogic implements RunnableWithFramePeriod, Observer {
/** /**
* State of current race modified by this object * State of current race modified by this object
*/ */
@ -32,6 +37,8 @@ public class RaceLogic implements RunnableWithFramePeriod {
this.race = race; this.race = race;
this.server = new RaceServer(race, messages); this.server = new RaceServer(race, messages);
this.commands = compositeCommand; this.commands = compositeCommand;
race.getColliderRegistry().addObserver(this);
} }
/** /**
@ -116,7 +123,7 @@ public class RaceLogic implements RunnableWithFramePeriod {
//If it is still racing, update its position. //If it is still racing, update its position.
if (boat.getStatus() == BoatStatusEnum.RACING) { if (boat.getStatus() == BoatStatusEnum.RACING) {
race.updatePosition(boat, framePeriod, race.getRaceClock().getDurationMilli()); race.updatePosition(boat, framePeriod, race.getRaceClock().getDurationMilli());
race.getColliderRegistry().rayCast(boat);
} }
} }
@ -168,4 +175,14 @@ public class RaceLogic implements RunnableWithFramePeriod {
public MockRace getRace() { public MockRace getRace() {
return race; return race;
} }
@Override
public void update(Observable o, Object arg) {
Collision e = (Collision)arg;
if(e.getBearing().degrees() == 0) System.out.println("Ahead");
else if(e.getBearing().degrees() < 90) System.out.println("Starboard");
else if(e.getBearing().degrees() > 270) System.out.println("Port");
else System.out.println("Behind");
}
} }

@ -2,10 +2,8 @@ package mock.model;
import network.Messages.*; import network.Messages.*;
import network.Messages.Enums.BoatLocationDeviceEnum; import network.Messages.Enums.BoatLocationDeviceEnum;
import network.Utils.AC35UnitConverter;
import shared.model.Bearing; import shared.model.Bearing;
import shared.model.CompoundMark; import shared.model.CompoundMark;
import shared.model.Constants;
import shared.model.Mark; import shared.model.Mark;
import java.util.ArrayList; import java.util.ArrayList;
@ -30,7 +28,6 @@ public class RaceServer {
this.latestMessages = latestMessages; this.latestMessages = latestMessages;
} }
/** /**
* Parses the race to create a snapshot, and places it in latestMessages. * Parses the race to create a snapshot, and places it in latestMessages.
*/ */
@ -127,8 +124,8 @@ public class RaceServer {
BoatLocation boatLocation = new BoatLocation( BoatLocation boatLocation = new BoatLocation(
boat.getSourceID(), boat.getSourceID(),
boat.getCurrentPosition().getLatitude(), boat.getPosition().getLatitude(),
boat.getCurrentPosition().getLongitude(), boat.getPosition().getLongitude(),
this.boatLocationSequenceNumber, this.boatLocationSequenceNumber,
BoatLocationDeviceEnum.RacingYacht, BoatLocationDeviceEnum.RacingYacht,
boat.getBearing(), boat.getBearing(),

@ -0,0 +1,52 @@
package mock.model.collider;
import shared.model.Bearing;
import shared.model.Boat;
import shared.model.GPSCoordinate;
import shared.model.Locatable;
import java.util.Observable;
/**
* Interface for all objects sensitive to collision in a race.
*/
public abstract class Collider extends Observable implements Locatable {
/**
* Indicates whether a ray cast from a boat to a target collider is within the specified length.
* @param boat potentially colliding with target
* @param distance distance for valid collision
* @return whether or not a collision has occurred
*/
public boolean rayCast(Boat boat, double distance) {
double actualDistance = GPSCoordinate.calculateDistanceMeters(boat.getPosition(), this.getPosition());
// Compass direction of collider
Bearing absolute = Bearing.fromAzimuth(GPSCoordinate.calculateAzimuth(boat.getPosition(), this.getPosition()));
// Direction of collider from heading
Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees());
if(actualDistance <= distance) {
Collision collision = new Collision(relative, distance);
// Notify object of collision
onCollisionEnter(boat, collision);
// Notify observers of collision
notifyObservers(collision);
this.setChanged();
return true;
} else return false;
}
/**
* Indicates whether a ray cast from a boat to a target collider triggers a collision. Distance is set by the object.
* @param boat potentially colliding with target
* @return whether or not a collision has occurred
*/
public abstract boolean rayCast(Boat boat);
/**
* Handle a collision event
* @param collider Boat that is colliding
* @param e details of collision
*/
public abstract void onCollisionEnter(Boat collider, Collision e);
}

@ -0,0 +1,66 @@
package mock.model.collider;
import shared.model.Boat;
import shared.model.GPSCoordinate;
import java.util.*;
/**
* Registry for all Collider objects in a MockRace. Wraps the Collider interface as part of a Composite Pattern.
*/
public class ColliderRegistry extends Collider implements Observer {
/**
* List of all registered Colliders
*/
private List<Collider> colliders;
/**
* Default constructor for ColliderRegistry
*/
public ColliderRegistry() {
this.colliders = new ArrayList<>();
}
public void addCollider(Collider collider) {
collider.addObserver(this);
colliders.add(collider);
}
public void addAllColliders(Collection<? extends Collider> colliders) {
for(Collider collider: colliders) addCollider(collider);
}
@Override
public boolean rayCast(Boat boat) {
for(Collider collider: colliders) {
if(collider.rayCast(boat)) return true;
}
return false;
}
@Override
public void onCollisionEnter(Boat collider, Collision e) {}
@Override
public GPSCoordinate getPosition() {
return null;
}
@Override
public void setPosition(GPSCoordinate position) {
}
/**
* Fire onCollisionEnter when collision bubbles up from registered colliders.
* @param o object collided with
* @param arg parameters of the collision
*/
@Override
public void update(Observable o, Object arg) {
Collision collision = (Collision)arg;
notifyObservers(collision);
this.setChanged();
}
}

@ -0,0 +1,35 @@
package mock.model.collider;
import shared.model.Bearing;
/**
* Data structure for holding collision details for ray casting and event handling.
*/
public class Collision {
/**
* Bearing from boat heading to target
*/
private Bearing bearing;
/**
* Distance from boat centre to target centre
*/
private double distance;
/**
* Constructor for Collision structure
* @param bearing from boat heading to target
* @param distance from boat centre to target centre
*/
public Collision(Bearing bearing, double distance) {
this.bearing = bearing;
this.distance = distance;
}
public Bearing getBearing() {
return bearing;
}
public double getDistance() {
return distance;
}
}

@ -0,0 +1,21 @@
package network;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Common source of ack numbers for all messages
*/
public class AckSequencer {
/**
* Generator for ack numbers
*/
private static AtomicInteger ackNum = new AtomicInteger(0);
/**
* Retrieve next ack number
* @return next ack number
*/
public static int getNextAckNum() {
return ackNum.getAndIncrement();
}
}

@ -39,7 +39,7 @@ public class DecoderFactory {
case RACESTARTSTATUS: return new RaceStartStatusDecoder(); case RACESTARTSTATUS: return new RaceStartStatusDecoder();
//case YACHTEVENTCODE: return new YachtEventCodeDecoder();//TODO case YACHTEVENTCODE: return new YachtEventCodeDecoder();
//case YACHTACTIONCODE: return new YachtActionCodeDecoder();//TODO //case YACHTACTIONCODE: return new YachtActionCodeDecoder();//TODO

@ -0,0 +1,47 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.Enums.YachtEventEnum;
import network.Messages.YachtEvent;
import java.util.Arrays;
import static network.Utils.ByteConverter.bytesToInt;
import static network.Utils.ByteConverter.bytesToLong;
import static network.Utils.ByteConverter.bytesToShort;
/**
* Decodes {@link YachtEvent} messages.
*/
public class YachtEventCodeDecoder implements MessageDecoder {
private YachtEvent message;
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
// Deserialise message
byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7);
byte[] ackNum = Arrays.copyOfRange(encodedMessage, 7, 9);
byte[] raceID = Arrays.copyOfRange(encodedMessage, 9, 13);
byte[] sourceID = Arrays.copyOfRange(encodedMessage, 13, 17);
byte[] incidentID = Arrays.copyOfRange(encodedMessage, 17, 21);
byte eventID = encodedMessage[21];
// Unpack bytes into YachtEvent
this.message = new YachtEvent(
bytesToLong(timestamp),
bytesToShort(ackNum),
bytesToInt(raceID),
bytesToInt(sourceID),
bytesToInt(incidentID),
YachtEventEnum.fromByte(eventID)
);
// Return YachtEvent
return message;
}
public YachtEvent getMessage() {
return message;
}
}

@ -39,7 +39,7 @@ public class EncoderFactory {
case RACESTARTSTATUS: return new RaceStartStatusEncoder(); case RACESTARTSTATUS: return new RaceStartStatusEncoder();
//case YACHTEVENTCODE: return new YachtEventCodeEncoder();//TODO case YACHTEVENTCODE: return new YachtEventCodeEncoder();
//case YACHTACTIONCODE: return new YachtActionCodeEncoder();//TODO //case YACHTACTIONCODE: return new YachtActionCodeEncoder();//TODO

@ -0,0 +1,43 @@
package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.YachtEvent;
import java.nio.ByteBuffer;
import static network.Utils.ByteConverter.intToBytes;
import static network.Utils.ByteConverter.longToBytes;
/**
* Encodes a {@link YachtEvent} message.
*/
public class YachtEventCodeEncoder implements MessageEncoder {
@Override
public byte[] encode(AC35Data message) throws InvalidMessageException {
// Downcast message
YachtEvent yachtEvent = (YachtEvent)message;
// Serialise message
byte messageVersion = 0b10;
byte[] timestamp = longToBytes(yachtEvent.getCurrentTime(), 6);
byte[] ackNum = intToBytes(yachtEvent.getAckNum(), 2);
byte[] raceID = intToBytes(yachtEvent.getRaceID());
byte[] sourceID = intToBytes(yachtEvent.getSourceID());
byte[] incidentID = intToBytes(yachtEvent.getIncidentID());
byte eventID = yachtEvent.getYachtEvent().getValue();
// Pack bytes into string
ByteBuffer yachtEventMessage = ByteBuffer.allocate(22);
yachtEventMessage.put(messageVersion);
yachtEventMessage.put(timestamp);
yachtEventMessage.put(ackNum);
yachtEventMessage.put(raceID);
yachtEventMessage.put(sourceID);
yachtEventMessage.put(incidentID);
yachtEventMessage.put(eventID);
// Return byte string
return yachtEventMessage.array();
}
}

@ -0,0 +1,24 @@
package network.Messages.Enums;
/**
* Yacht event codes
*/
public enum YachtEventEnum {
NOT_AN_EVENT(-1),
COLLISION(1);
private byte value;
YachtEventEnum(int value) { this.value = (byte)value; }
public byte getValue() {
return value;
}
public static YachtEventEnum fromByte(byte value) {
switch(value) {
case 1: return COLLISION;
default: return NOT_AN_EVENT;
}
}
}

@ -0,0 +1,51 @@
package network.Messages;
import network.Messages.Enums.MessageType;
import network.Messages.Enums.YachtEventEnum;
/**
* Represents a Yacht Event Code message defined in the AC35 spec, with Event IDs amended for the purposes of
* a game.
*/
public class YachtEvent extends AC35Data {
private long currentTime;
private int ackNum;
private int raceID;
private int sourceID;
private int incidentID;
private YachtEventEnum yachtEvent;
public YachtEvent(long currentTime, int ackNum, int raceID, int sourceID, int incidentID, YachtEventEnum yachtEvent) {
super(MessageType.YACHTEVENTCODE);
this.currentTime = currentTime;
this.ackNum = ackNum;
this.raceID = raceID;
this.sourceID = sourceID;
this.incidentID = incidentID;
this.yachtEvent = yachtEvent;
}
public YachtEventEnum getYachtEvent() {
return yachtEvent;
}
public int getSourceID() {
return sourceID;
}
public int getIncidentID() {
return incidentID;
}
public long getCurrentTime() {
return currentTime;
}
public int getAckNum() {
return ackNum;
}
public int getRaceID() {
return raceID;
}
}

@ -2,6 +2,8 @@ package shared.model;
import javafx.beans.property.*; import javafx.beans.property.*;
import mock.model.collider.Collider;
import mock.model.collider.Collision;
import network.Messages.Enums.BoatStatusEnum; import network.Messages.Enums.BoatStatusEnum;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -10,7 +12,7 @@ import java.time.ZonedDateTime;
/** /**
* Boat Model that is used to store information on the boats that are running in the race. * Boat Model that is used to store information on the boats that are running in the race.
*/ */
public class Boat { public class Boat extends Collider {
/** /**
* The name of the boat/team. * The name of the boat/team.
*/ */
@ -30,7 +32,7 @@ public class Boat {
/** /**
* The current position of the boat. * The current position of the boat.
*/ */
private GPSCoordinate currentPosition; private GPSCoordinate position;
/** /**
* The country or team abbreviation of the boat. * The country or team abbreviation of the boat.
@ -57,7 +59,7 @@ public class Boat {
/** /**
* The boat's position within the race (e.g., 5th). * The boat's position within the race (e.g., 5th).
*/ */
private StringProperty positionInRace = new SimpleStringProperty(); private StringProperty placing = new SimpleStringProperty();
/** /**
@ -107,7 +109,7 @@ public class Boat {
this.bearing = Bearing.fromDegrees(0d); this.bearing = Bearing.fromDegrees(0d);
setCurrentPosition(new GPSCoordinate(0, 0)); setPosition(new GPSCoordinate(0, 0));
this.status = BoatStatusEnum.UNDEFINED; this.status = BoatStatusEnum.UNDEFINED;
} }
@ -256,41 +258,32 @@ public class Boat {
* Returns the position within the race the boat has (e.g., 5th). * Returns the position within the race the boat has (e.g., 5th).
* @return The boat's position in race. * @return The boat's position in race.
*/ */
public StringProperty positionProperty() { public StringProperty placingProperty() {
return positionInRace; return placing;
} }
/** /**
* Sets the position within the race the boat has (e.g., 5th). * Sets the position within the race the boat has (e.g., 5th).
* @param position The boat's position in race. * @param position The boat's position in race.
*/ */
public void setPosition(String position) { public void setPlacing(String position) {
this.positionInRace.set(position); this.placing.set(position);
} }
/**
* Returns the position within the race the boat has (e.g., 5th).
* @return The boat's position in race.
*/
public String getPosition() {
return this.positionInRace.get();
}
/** /**
* Returns the current position of the boat. * Returns the current position of the boat.
* @return The current position of the boat. * @return The current position of the boat.
*/ */
public GPSCoordinate getCurrentPosition() { public GPSCoordinate getPosition() {
return currentPosition; return position;
} }
/** /**
* Sets the current position of the boat. * Sets the current position of the boat.
* @param currentPosition The new position for the boat. * @param position The new position for the boat.
*/ */
public void setCurrentPosition(GPSCoordinate currentPosition) { public void setPosition(GPSCoordinate position) {
this.currentPosition = currentPosition; this.position = position;
} }
@ -399,4 +392,22 @@ public class Boat {
this.timeAtLastMark = timeAtLastMark; this.timeAtLastMark = timeAtLastMark;
} }
public void bounce(double repulsionRadius) {
Azimuth reverseAzimuth = Azimuth.fromDegrees(getBearing().degrees() - 180d);
setPosition(GPSCoordinate.calculateNewPosition(getPosition(), 2 * repulsionRadius, reverseAzimuth));
}
@Override
public boolean rayCast(Boat boat) {
if(boat != this) {
return rayCast(boat, 100);
} else return false;
}
@Override
public void onCollisionEnter(Boat collider, Collision e) {
if(e.getBearing().degrees() > 270 || e.getBearing().degrees() < 90) {
collider.bounce(100);
}
}
} }

@ -1,6 +1,5 @@
package shared.model; package shared.model;
import shared.enums.RoundingType; import shared.enums.RoundingType;
/** /**
@ -117,7 +116,7 @@ public class CompoundMark {
* @return The position of the second mark in the compound mark. * @return The position of the second mark in the compound mark.
*/ */
public GPSCoordinate getMark2Position() { public GPSCoordinate getMark2Position() {
return mark2.getPosition(); return mark2 == null? mark1.getPosition() : mark2.getPosition();
} }
@ -135,13 +134,6 @@ public class CompoundMark {
* @return The average coordinate of the compound mark. * @return The average coordinate of the compound mark.
*/ */
private GPSCoordinate calculateAverage() { private GPSCoordinate calculateAverage() {
//If the compound mark only contains one mark, the average is simply the first mark's position.
if (this.mark2 == null) {
return this.getMark1Position();
}
//Otherwise, calculate the average of both marks. //Otherwise, calculate the average of both marks.
GPSCoordinate averageCoordinate = GPSCoordinate.calculateAverageCoordinate(this.getMark1Position(), this.getMark2Position()); GPSCoordinate averageCoordinate = GPSCoordinate.calculateAverageCoordinate(this.getMark1Position(), this.getMark2Position());

@ -0,0 +1,9 @@
package shared.model;
/**
* Created by cbt24 on 16/08/17.
*/
public interface Locatable {
GPSCoordinate getPosition();
void setPosition(GPSCoordinate position);
}

@ -1,10 +1,13 @@
package shared.model; package shared.model;
import mock.model.collider.Collider;
import mock.model.collider.Collision;
/** /**
* Represents an individual mark. * Represents an individual mark.
* Has a source ID, name, and position. * Has a source ID, name, and position.
*/ */
public class Mark { public class Mark extends Collider {
/** /**
* The source ID of the mark. * The source ID of the mark.
@ -21,6 +24,10 @@ public class Mark {
*/ */
private GPSCoordinate position; private GPSCoordinate position;
/**
* Repulsion radius of the mark
*/
private double repulsionRadius = 50;
/** /**
* Constructs a mark with a given source ID, name, and position. * Constructs a mark with a given source ID, name, and position.
@ -75,4 +82,14 @@ public class Mark {
public void setPosition(GPSCoordinate position) { public void setPosition(GPSCoordinate position) {
this.position = position; this.position = position;
} }
@Override
public boolean rayCast(Boat boat) {
return rayCast(boat, repulsionRadius);
}
@Override
public void onCollisionEnter(Boat collider, Collision e) {
collider.bounce(repulsionRadius);
}
} }

@ -4,108 +4,87 @@ import javafx.beans.property.IntegerProperty;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import mock.model.collider.ColliderRegistry;
import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceStatusEnum;
import network.Messages.Enums.RaceTypeEnum; import network.Messages.Enums.RaceTypeEnum;
import shared.dataInput.BoatDataSource; import shared.dataInput.BoatDataSource;
import shared.dataInput.RaceDataSource; import shared.dataInput.RaceDataSource;
import shared.dataInput.RegattaDataSource; import shared.dataInput.RegattaDataSource;
import visualiser.model.VisualiserRaceEvent;
import java.util.List; import java.util.List;
/** /**
* Represents a yacht race. * Represents a yacht race.
* This is a base class inherited by {@link mock.model.MockRace} and {@link VisualiserRaceEvent}.
* Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}. * Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}.
*/ */
public abstract class Race { public abstract class Race {
/** /**
* The source of race related data. * The source of race related data.
*/ */
protected RaceDataSource raceDataSource; protected RaceDataSource raceDataSource;
/** /**
* The source of boat related data. * The source of boat related data.
*/ */
protected BoatDataSource boatDataSource; protected BoatDataSource boatDataSource;
/** /**
* The source of regatta related data. * The source of regatta related data.
*/ */
protected RegattaDataSource regattaDataSource; protected RegattaDataSource regattaDataSource;
/** /**
* A list of compound marks in the race. * A list of compound marks in the race.
*/ */
protected List<CompoundMark> compoundMarks; protected List<CompoundMark> compoundMarks;
/** /**
* A list of legs in the race. * A list of legs in the race.
*/ */
protected List<Leg> legs; protected List<Leg> legs;
/** /**
* A list of coordinates describing the boundary of the course. * A list of coordinates describing the boundary of the course.
*/ */
protected List<GPSCoordinate> boundary; protected List<GPSCoordinate> boundary;
/** /**
* The clock which tracks the race's start time, current time, and elapsed duration. * The clock which tracks the race's start time, current time, and elapsed duration.
*/ */
protected RaceClock raceClock; protected RaceClock raceClock;
/** /**
* The race ID of the course. * The race ID of the course.
*/ */
protected int raceId; protected int raceId;
/** /**
* The name of the regatta. * The name of the regatta.
*/ */
protected String regattaName; protected String regattaName;
/** /**
* The current status of the race. * The current status of the race.
*/ */
protected RaceStatusEnum raceStatusEnum; protected RaceStatusEnum raceStatusEnum;
/** /**
* The type of race this is. * The type of race this is.
*/ */
protected RaceTypeEnum raceType; protected RaceTypeEnum raceType;
/** /**
* The race's wind. * The race's wind.
*/ */
protected Property<Wind> raceWind = new SimpleObjectProperty<>(); protected Property<Wind> raceWind = new SimpleObjectProperty<>();
/**
* Registry for all collider object in this race
*/
protected ColliderRegistry colliderRegistry;
/** /**
* The number of frames per second. * The number of frames per second.
* We essentially track the number of frames generated per second, over a one second period. When {@link #lastFpsResetTime} reaches 1 second, {@link #currentFps} is reset. * We essentially track the number of frames generated per second, over a one second period. When {@link #lastFpsResetTime} reaches 1 second, currentFps is reset.
*/ */
private int currentFps = 0; private int currentFps = 0;
/** /**
* The number of frames per second we generated over the last 1 second period. * The number of frames per second we generated over the last 1 second period.
*/ */
private IntegerProperty lastFps = new SimpleIntegerProperty(0); private IntegerProperty lastFps = new SimpleIntegerProperty(0);
/** /**
* The time, in milliseconds, since we last reset our {@link #currentFps} counter. * The time, in milliseconds, since we last reset our {@link #currentFps} counter.
*/ */
private long lastFpsResetTime; private long lastFpsResetTime;
/** /**
* Constructs a race object with a given BoatDataSource, RaceDataSource, and RegattaDataSource. * Constructs a race object with a given BoatDataSource, RaceDataSource, and RegattaDataSource.
* @param boatDataSource Data source for boat related data (yachts and marker boats). * @param boatDataSource Data source for boat related data (yachts and marker boats).
@ -119,39 +98,36 @@ public abstract class Race {
this.boatDataSource = boatDataSource; this.boatDataSource = boatDataSource;
this.regattaDataSource = regattaDataSource; this.regattaDataSource = regattaDataSource;
//Marks. //Marks.
this.compoundMarks = raceDataSource.getCompoundMarks(); this.compoundMarks = raceDataSource.getCompoundMarks();
//Boundaries. //Boundaries.
this.boundary = raceDataSource.getBoundary(); this.boundary = raceDataSource.getBoundary();
//Legs. //Legs.
this.useLegsList(raceDataSource.getLegs()); this.useLegsList(raceDataSource.getLegs());
//Race ID. //Race ID.
this.raceId = raceDataSource.getRaceId(); this.raceId = raceDataSource.getRaceId();
//Regatta name. //Regatta name.
this.regattaName = regattaDataSource.getRegattaName(); this.regattaName = regattaDataSource.getRegattaName();
//Race clock. //Race clock.
this.raceClock = new RaceClock(this.raceDataSource.getStartDateTime()); this.raceClock = new RaceClock(this.raceDataSource.getStartDateTime());
//Race status. //Race status.
this.setRaceStatusEnum(RaceStatusEnum.NOT_ACTIVE); this.setRaceStatusEnum(RaceStatusEnum.NOT_ACTIVE);
//Race type. //Race type.
this.raceType = raceDataSource.getRaceType(); this.raceType = raceDataSource.getRaceType();
//Wind. //Wind.
this.setWind(Bearing.fromDegrees(0), 0); this.setWind(Bearing.fromDegrees(0), 0);
// Set up colliders
this.colliderRegistry = new ColliderRegistry();
for(CompoundMark mark: compoundMarks) {
colliderRegistry.addCollider(mark.getMark1());
if(mark.getMark2() != null) colliderRegistry.addCollider(mark.getMark2());
}
} }
public ColliderRegistry getColliderRegistry() {
return colliderRegistry;
}
/** /**
* Initialise the boats in the race. * Initialise the boats in the race.
@ -159,7 +135,6 @@ public abstract class Race {
*/ */
protected abstract void initialiseBoats(); protected abstract void initialiseBoats();
/** /**
* Updates the race to use a new list of legs, and adds a dummy "Finish" leg at the end. * Updates the race to use a new list of legs, and adds a dummy "Finish" leg at the end.
* @param legs The new list of legs to use. * @param legs The new list of legs to use.
@ -191,10 +166,6 @@ public abstract class Race {
return legID == lastLegID; return legID == lastLegID;
} }
/** /**
* Returns the current race status. * Returns the current race status.
* @return The current race status. * @return The current race status.
@ -211,7 +182,6 @@ public abstract class Race {
this.raceStatusEnum = raceStatusEnum; this.raceStatusEnum = raceStatusEnum;
} }
/** /**
* Returns the type of race this is. * Returns the type of race this is.
* @return The type of race this is. * @return The type of race this is.
@ -228,13 +198,12 @@ public abstract class Race {
return regattaName; return regattaName;
} }
/** /**
* Updates the race to have a specified wind bearing and speed. * Updates the race to have a specified wind bearing and speed.
* @param windBearing New wind bearing. * @param windBearing New wind bearing.
* @param windSpeedKnots New wind speed, in knots. * @param windSpeedKnots New wind speed, in knots.
*/ */
public void setWind(Bearing windBearing, double windSpeedKnots) { protected void setWind(Bearing windBearing, double windSpeedKnots) {
Wind wind = new Wind(windBearing, windSpeedKnots); Wind wind = new Wind(windBearing, windSpeedKnots);
setWind(wind); setWind(wind);
} }
@ -243,11 +212,10 @@ public abstract class Race {
* Updates the race to have a specified wind (bearing and speed). * Updates the race to have a specified wind (bearing and speed).
* @param wind New wind. * @param wind New wind.
*/ */
public void setWind(Wind wind) { protected void setWind(Wind wind) {
this.raceWind.setValue(wind); this.raceWind.setValue(wind);
} }
/** /**
* Returns the wind bearing. * Returns the wind bearing.
* @return The wind bearing. * @return The wind bearing.
@ -265,14 +233,6 @@ public abstract class Race {
return raceWind.getValue().getWindSpeed(); return raceWind.getValue().getWindSpeed();
} }
/**
* Returns the race's wind.
* @return The race's wind.
*/
public Property<Wind> windProperty() {
return raceWind;
}
/** /**
* Returns the RaceClock for this race. * Returns the RaceClock for this race.
* This is used to track the start time, current time, and elapsed duration of the race. * This is used to track the start time, current time, and elapsed duration of the race.
@ -282,7 +242,6 @@ public abstract class Race {
return raceClock; return raceClock;
} }
/** /**
* Returns the RaceDataSource used for the race. * Returns the RaceDataSource used for the race.
* @return The RaceDataSource used for the race. * @return The RaceDataSource used for the race.
@ -300,7 +259,6 @@ public abstract class Race {
return legs.size() - 1; return legs.size() - 1;
} }
/** /**
* Returns the race boundary. * Returns the race boundary.
* @return The race boundary. * @return The race boundary.
@ -326,14 +284,6 @@ public abstract class Race {
return legs; return legs;
} }
/**
* Returns the number of frames generated per second.
* @return Frames per second.
*/
public int getFps() {
return lastFps.getValue();
}
/** /**
* Returns the fps property. * Returns the fps property.
* @return The fps property. * @return The fps property.
@ -342,8 +292,6 @@ public abstract class Race {
return lastFps; return lastFps;
} }
/** /**
* Increments the FPS counter, and adds timePeriod milliseconds to our FPS reset timer. * Increments the FPS counter, and adds timePeriod milliseconds to our FPS reset timer.
* @param timePeriod Time, in milliseconds, to add to {@link #lastFpsResetTime}. * @param timePeriod Time, in milliseconds, to add to {@link #lastFpsResetTime}.

@ -8,7 +8,6 @@ import shared.exceptions.MarkNotFoundException;
import shared.model.GPSCoordinate; import shared.model.GPSCoordinate;
import shared.model.Mark; import shared.model.Mark;
import visualiser.model.VisualiserBoat; import visualiser.model.VisualiserBoat;
import visualiser.model.VisualiserRaceEvent;
import visualiser.model.VisualiserRaceState; import visualiser.model.VisualiserRaceState;
import java.util.logging.Level; import java.util.logging.Level;
@ -68,7 +67,7 @@ public class BoatLocationCommand implements Command {
boatLocation.getLatitude(), boatLocation.getLatitude(),
boatLocation.getLongitude()); boatLocation.getLongitude());
boat.setCurrentPosition(gpsCoordinate); boat.setPosition(gpsCoordinate);
//Bearing. //Bearing.
boat.setBearing(boatLocation.getHeading()); boat.setBearing(boatLocation.getHeading());
@ -96,7 +95,7 @@ public class BoatLocationCommand implements Command {
*/ */
private void attemptAddTrackPoint(VisualiserBoat boat) { private void attemptAddTrackPoint(VisualiserBoat boat) {
if (boat.getStatus() == BoatStatusEnum.RACING) { if (boat.getStatus() == BoatStatusEnum.RACING) {
boat.addTrackPoint(boat.getCurrentPosition(), visualiserRace.getRaceClock().getCurrentTime()); boat.addTrackPoint(boat.getPosition(), visualiserRace.getRaceClock().getCurrentTime());
} }
} }

@ -67,7 +67,7 @@ public class FinishController extends Controller {
boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty()); boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
//Rank/position. //Rank/position.
boatRankColumn.setCellValueFactory(cellData -> cellData.getValue().positionProperty()); boatRankColumn.setCellValueFactory(cellData -> cellData.getValue().placingProperty());
//Winner label. //Winner label.

@ -23,7 +23,6 @@ import visualiser.gameController.ControllerClient;
import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.ControlKey;
import visualiser.gameController.Keys.KeyFactory; import visualiser.gameController.Keys.KeyFactory;
import visualiser.model.*; import visualiser.model.*;
import visualiser.network.ServerConnection;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -293,7 +292,7 @@ public class RaceController extends Controller {
//Current place within race. //Current place within race.
boatPlacingColumn.setCellValueFactory( boatPlacingColumn.setCellValueFactory(
cellData -> cellData.getValue().positionProperty() ); cellData -> cellData.getValue().placingProperty() );
} }

@ -272,7 +272,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
boat.getName(), boat.getName(),
boat.getCountry(), boat.getCountry(),
boat.getCurrentSpeed(), boat.getCurrentSpeed(),
this.map.convertGPS(boat.getCurrentPosition()), this.map.convertGPS(boat.getPosition()),
boat.getTimeToNextMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()), boat.getTimeToNextMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()),
boat.getTimeSinceLastMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()), boat.getTimeSinceLastMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()),
Color.BLACK, Color.BLACK,
@ -349,7 +349,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
} }
//Convert position to graph coordinate. //Convert position to graph coordinate.
GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition()); GraphCoordinate pos = this.map.convertGPS(boat.getPosition());
//The x coordinates of each vertex of the boat. //The x coordinates of each vertex of the boat.
double[] x = { double[] x = {
@ -385,7 +385,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
private void drawClientBoat(VisualiserBoat boat) { private void drawClientBoat(VisualiserBoat boat) {
//Convert position to graph coordinate. //Convert position to graph coordinate.
GraphCoordinate pos = this.map.convertGPS(boat.getCurrentPosition()); GraphCoordinate pos = this.map.convertGPS(boat.getPosition());
//The x coordinates of each vertex of the boat. //The x coordinates of each vertex of the boat.
double[] x = { double[] x = {
@ -421,7 +421,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
private void drawWake(VisualiserBoat boat) { private void drawWake(VisualiserBoat boat) {
//Calculate either end of wake line. //Calculate either end of wake line.
GraphCoordinate wakeFrom = this.map.convertGPS(boat.getCurrentPosition()); GraphCoordinate wakeFrom = this.map.convertGPS(boat.getPosition());
GraphCoordinate wakeTo = this.map.convertGPS(boat.getWake()); GraphCoordinate wakeTo = this.map.convertGPS(boat.getWake());
double lineWidth = 4; double lineWidth = 4;

@ -100,7 +100,7 @@ public class VisualiserBoat extends Boat {
//Calculate the new coordinate. //Calculate the new coordinate.
GPSCoordinate wakeCoordinate = GPSCoordinate.calculateNewPosition(getCurrentPosition(), wakeDistanceMeters, reverseAzimuth); GPSCoordinate wakeCoordinate = GPSCoordinate.calculateNewPosition(getPosition(), wakeDistanceMeters, reverseAzimuth);
return wakeCoordinate; return wakeCoordinate;
} }

@ -1,7 +1,6 @@
package visualiser.model; package visualiser.model;
import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@ -249,10 +248,10 @@ public class VisualiserRaceState extends RaceState {
if ((boat.getStatus() == BoatStatusEnum.DNF) || (boat.getStatus() == BoatStatusEnum.PRESTART) || (boat.getCurrentLeg().getLegNumber() < 0)) { if ((boat.getStatus() == BoatStatusEnum.DNF) || (boat.getStatus() == BoatStatusEnum.PRESTART) || (boat.getCurrentLeg().getLegNumber() < 0)) {
boat.setPosition("-"); boat.setPlacing("-");
} else { } else {
boat.setPosition(Integer.toString(i + 1)); boat.setPlacing(Integer.toString(i + 1));
} }
} }

@ -1,174 +1,35 @@
package mock.model; package mock.model;
import mock.dataInput.PolarParser;
import mock.exceptions.InvalidPolarFileException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import shared.model.Bearing; import shared.model.Bearing;
import shared.model.CompoundMark;
import shared.model.GPSCoordinate; import shared.model.GPSCoordinate;
import shared.model.Mark; import shared.model.Mark;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.fail;
public class MockBoatTest { public class MockBoatTest {
private MockBoat boat;
private Mark near;
private Mark far;
/**
* boat made for testing
*/
private MockBoat firstTestBoat;
private Mark markToTest;
private Mark markToTest2;
private GPSCoordinate highGPS;
private GPSCoordinate middleGPS;
private GPSCoordinate lowGPS;
/**
* Creates the Polars object for the tests.
*/
@Before @Before
public void setUp() { public void setUp() {
//Read in polars. boat = new MockBoat(0, "Bob", "NZ", null);
try { boat.setPosition(new GPSCoordinate(0,0));
//Parse data file. boat.setBearing(Bearing.fromDegrees(180));
Polars polars = PolarParser.parse("mock/polars/acc_polars.csv");
firstTestBoat = new MockBoat(1, "test", "NZ", polars);
highGPS = new GPSCoordinate(32.296577, -64.854000);
middleGPS = new GPSCoordinate(32.292500, -64.854000);
lowGPS = new GPSCoordinate(32.290000, -64.854000);
markToTest = new Mark(1, "test MARK", middleGPS);
markToTest2 = new Mark(2, "test MARK2", middleGPS);
}
catch (InvalidPolarFileException e) {
fail("Couldn't parse polar file.");
}
}
//////////////////////////////Mark Higher////////////////////////////////
/**
* Tests if the boat is lower than the mark that the port side method works if
* boat is facing east
*/
@Test
public void testIsPortSide() {
firstTestBoat.setBearing(Bearing.fromDegrees(90));
firstTestBoat.setCurrentPosition(lowGPS);
markToTest.setPosition(highGPS);
assertEquals(firstTestBoat.isPortSide(markToTest), true);
}
/**
* Tests if the boat is lower than the mark that the port side method works if
* boat is facing west
*/
@Test
public void testIsPortSideWrong() {
firstTestBoat.setBearing(Bearing.fromDegrees(270));
firstTestBoat.setCurrentPosition(lowGPS);
markToTest.setPosition(highGPS);
assertEquals(firstTestBoat.isPortSide(markToTest), false);
}
/**
* Tests if the boat is lower than the mark that the starboard side method works if
* boat is facing east
*/
@Test
public void testIsStarboardSideWrong() {
firstTestBoat.setBearing(Bearing.fromDegrees(90));
firstTestBoat.setCurrentPosition(lowGPS);
markToTest.setPosition(highGPS);
assertEquals(firstTestBoat.isStarboardSide(markToTest), false);
}
/**
* Tests if the boat is lower than the mark that the starboard side method works if
* boat is facing west
*/
@Test
public void testIsStarboardSide() {
firstTestBoat.setBearing(Bearing.fromDegrees(270));
firstTestBoat.setCurrentPosition(lowGPS);
markToTest.setPosition(highGPS);
assertEquals(firstTestBoat.isStarboardSide(markToTest), true);
}
//////////////////////////////Mark Lower////////////////////////////////
/** near = new Mark(0, "Near", new GPSCoordinate(-.0001, 0));
* Tests if the boat is higher than the mark that the port side method works if far = new Mark(0, "Far", new GPSCoordinate(.001, 0));
* boat is facing east
*/
@Test
public void testIsPortSideHigherWrong() {
firstTestBoat.setBearing(Bearing.fromDegrees(90));
firstTestBoat.setCurrentPosition(highGPS);
markToTest.setPosition(lowGPS);
assertEquals(firstTestBoat.isPortSide(markToTest), false);
} }
/**
* Tests if the boat is higher than the mark that the port side method works if
* boat is facing west
*/
@Test @Test
public void testIsPortSideHigher() { public void nearMarkWithin100m() {
firstTestBoat.setBearing(Bearing.fromDegrees(270)); assertTrue(near.rayCast(boat, 100));
firstTestBoat.setCurrentPosition(highGPS);
markToTest.setPosition(lowGPS);
assertEquals(firstTestBoat.isPortSide(markToTest), true);
} }
/**
* Tests if the boat is higher than the mark that the starboard side method works if
* boat is facing east
*/
@Test @Test
public void testIsStarboardSideHigher() { public void farMarkBeyond100m() {
firstTestBoat.setBearing(Bearing.fromDegrees(90)); assertFalse(far.rayCast(boat, 100));
firstTestBoat.setCurrentPosition(highGPS);
markToTest.setPosition(lowGPS);
assertEquals(firstTestBoat.isStarboardSide(markToTest), true);
}
/**
* Tests if the boat is higher than the mark that the starboard side method works if
* boat is facing west
*/
@Test
public void testIsStarboardSideHigherWrong() {
firstTestBoat.setBearing(Bearing.fromDegrees(270));
firstTestBoat.setCurrentPosition(highGPS);
markToTest.setPosition(lowGPS);
assertEquals(firstTestBoat.isStarboardSide(markToTest), false);
}
/**
* Tests if a boat is between a gate
*/
@Test
public void testIsBetweenGate(){
markToTest.setPosition(highGPS);
markToTest2.setPosition(lowGPS);
CompoundMark testGate = new CompoundMark(1, "test GATE", markToTest, markToTest2);
firstTestBoat.setCurrentPosition(middleGPS);
assertEquals(firstTestBoat.isBetweenGate(testGate), true);
} }
} }

@ -0,0 +1,47 @@
package network.MessageDecoders;
import network.MessageEncoders.RaceVisionByteEncoder;
import network.Messages.Enums.YachtEventEnum;
import network.Messages.YachtEvent;
import org.junit.Before;
import org.junit.Test;
import static org.testng.Assert.*;
/**
* Tests for the YachtEvent decoder and encoder
*/
public class YachtEventCodeDecoderTest {
private YachtEvent decodedMessage;
private YachtEvent originalMessage;
@Before
public void setUp() throws Exception {
long timestamp = System.currentTimeMillis();
originalMessage = new YachtEvent(
timestamp,
55,
35,
0,
1,
YachtEventEnum.COLLISION
);
byte[] encodedMessage = RaceVisionByteEncoder.encode(originalMessage);
YachtEventCodeDecoder testDecoder = new YachtEventCodeDecoder();
testDecoder.decode(encodedMessage);
decodedMessage = testDecoder.getMessage();
}
@Test
public void decodingEqualsOriginal() {
assertEquals(originalMessage.getCurrentTime(), decodedMessage.getCurrentTime());
assertEquals(originalMessage.getAckNum(), decodedMessage.getAckNum());
assertEquals(originalMessage.getRaceID(), decodedMessage.getRaceID());
assertEquals(originalMessage.getSourceID(), decodedMessage.getSourceID());
assertEquals(originalMessage.getIncidentID(), decodedMessage.getIncidentID());
assertEquals(originalMessage.getYachtEvent(), decodedMessage.getYachtEvent());
}
}

@ -19,7 +19,7 @@ public class BoatTest {
public void setUp() { public void setUp() {
ORIGIN_COORDS = new GPSCoordinate(0, 0); ORIGIN_COORDS = new GPSCoordinate(0, 0);
TEST_BOAT = new Boat(1, "Test", "tt"); TEST_BOAT = new Boat(1, "Test", "tt");
TEST_BOAT.setCurrentPosition(ORIGIN_COORDS); TEST_BOAT.setPosition(ORIGIN_COORDS);
} }
//TODO these bearing tests could be tidied up to reduce code repetition. //TODO these bearing tests could be tidied up to reduce code repetition.
@ -113,7 +113,7 @@ public class BoatTest {
Leg start = new Leg("Start", startMarker, endMarker, 0); Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start); TEST_BOAT.setCurrentLeg(start);
assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getCurrentPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 0, 1e-8); assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 0, 1e-8);
} }
@ -131,7 +131,7 @@ public class BoatTest {
Leg start = new Leg("Start", startMarker, endMarker, 0); Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start); TEST_BOAT.setCurrentLeg(start);
assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getCurrentPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 90, 1e-8); assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 90, 1e-8);
} }
@Test @Test
@ -148,7 +148,7 @@ public class BoatTest {
Leg start = new Leg("Start", startMarker, endMarker, 0); Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start); TEST_BOAT.setCurrentLeg(start);
assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getCurrentPosition(), endMarker.getAverageGPSCoordinate()).degrees(), -180, 1e-8); assertEquals(GPSCoordinate.calculateAzimuth(TEST_BOAT.getPosition(), endMarker.getAverageGPSCoordinate()).degrees(), -180, 1e-8);
} }
@Test @Test
@ -165,7 +165,7 @@ public class BoatTest {
Leg start = new Leg("Start", startMarker, endMarker, 0); Leg start = new Leg("Start", startMarker, endMarker, 0);
TEST_BOAT.setCurrentLeg(start); TEST_BOAT.setCurrentLeg(start);
assertEquals(GPSCoordinate.calculateBearing(TEST_BOAT.getCurrentPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 270, 1e-8); assertEquals(GPSCoordinate.calculateBearing(TEST_BOAT.getPosition(), endMarker.getAverageGPSCoordinate()).degrees(), 270, 1e-8);
} }

Loading…
Cancel
Save