Added LatestMessages to network.Messages. This is an object that encapsulates the latest up to date set of race messages.
Race stores a reference to it. MockRace writes to it, and eventually, VisualiserRace will read from it. Updated MockRace, MockOutput, Event to use it. Angle now implements hashCode().
This commit is contained in:
@@ -3,6 +3,7 @@ package mock.app;
|
||||
import mock.model.MockRace;
|
||||
import mock.model.Polars;
|
||||
import network.Messages.Enums.MessageType;
|
||||
import network.Messages.LatestMessages;
|
||||
import org.xml.sax.SAXException;
|
||||
import shared.dataInput.*;
|
||||
import shared.exceptions.InvalidBoatDataException;
|
||||
@@ -28,6 +29,8 @@ public class Event {
|
||||
private String boatXML;
|
||||
private Polars boatPolars;
|
||||
private MockOutput mockOutput;
|
||||
private LatestMessages latestMessages;
|
||||
|
||||
|
||||
public Event(String raceXML, String regattaXML, String boatXML, Polars boatPolars) {
|
||||
|
||||
@@ -36,9 +39,13 @@ public class Event {
|
||||
this.regattaXML = regattaXML;
|
||||
this.boatPolars = boatPolars;
|
||||
|
||||
this.latestMessages = new LatestMessages();
|
||||
|
||||
|
||||
try {
|
||||
mockOutput = new MockOutput();
|
||||
this.mockOutput = new MockOutput(this.latestMessages);
|
||||
new Thread(mockOutput).start();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -57,7 +64,7 @@ public class Event {
|
||||
RegattaDataSource regattaDataSource = new RegattaXMLReader(this.regattaXML);
|
||||
|
||||
//Create and start race.
|
||||
MockRace newRace = new MockRace(boatDataSource, raceDataSource, regattaDataSource, this.boatPolars, this.mockOutput);
|
||||
MockRace newRace = new MockRace(boatDataSource, raceDataSource, regattaDataSource, this.boatPolars, this.latestMessages);
|
||||
|
||||
new Thread(newRace).start();
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import network.MessageEncoders.RaceVisionByteEncoder;
|
||||
import network.MessageEncoders.XMLMessageEncoder;
|
||||
import network.Messages.BoatLocation;
|
||||
import network.Messages.Enums.MessageType;
|
||||
import network.Messages.LatestMessages;
|
||||
import network.Messages.RaceStatus;
|
||||
import network.Messages.XMLMessage;
|
||||
|
||||
@@ -37,8 +38,14 @@ public class MockOutput implements Runnable
|
||||
///Output stream which wraps around mockSocket outstream.
|
||||
private DataOutputStream outToVisualiser;
|
||||
|
||||
///A queue that contains items that are waiting to be sent.
|
||||
private ArrayBlockingQueue<byte[]> messagesToSendQueue = new ArrayBlockingQueue<>(99999999);
|
||||
|
||||
/**
|
||||
* An object containing the set of latest messages to send.
|
||||
* Every server frame, MockOutput reads messages from this, and send them.
|
||||
*/
|
||||
private LatestMessages latestMessages;
|
||||
|
||||
|
||||
|
||||
///Sequence numbers used in messages.
|
||||
private short messageNumber = 1;
|
||||
@@ -56,11 +63,15 @@ public class MockOutput implements Runnable
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
* @param latestMessages The collection of messages to send to connected clients.
|
||||
* @throws IOException if server socket cannot be opened.
|
||||
*/
|
||||
public MockOutput() throws IOException {
|
||||
lastHeartbeatTime = System.currentTimeMillis();
|
||||
serverSocket = new ServerSocket(serverPort);
|
||||
public MockOutput(LatestMessages latestMessages) throws IOException {
|
||||
|
||||
this.lastHeartbeatTime = System.currentTimeMillis();
|
||||
this.serverSocket = new ServerSocket(serverPort);
|
||||
|
||||
this.latestMessages = latestMessages;
|
||||
|
||||
}
|
||||
/**
|
||||
@@ -91,77 +102,92 @@ public class MockOutput implements Runnable
|
||||
* @param xmlString the xml string to send
|
||||
* @param messageType the kind of xml string, values given in AC35 spec (5 regatta, 6 race, 7 boat)
|
||||
*/
|
||||
public synchronized void parseXMLString(String xmlString, int messageType){
|
||||
XMLMessageEncoder encoder = new XMLMessageEncoder(messageNumber, System.currentTimeMillis(), messageType, xmlSequenceNumber,(short) xmlString.length(), xmlString);
|
||||
public synchronized byte[] parseXMLString(String xmlString, int messageType) {
|
||||
|
||||
XMLMessageEncoder encoder = new XMLMessageEncoder(
|
||||
messageNumber,
|
||||
System.currentTimeMillis(),
|
||||
messageType,
|
||||
xmlSequenceNumber,
|
||||
(short) xmlString.length(),
|
||||
xmlString);
|
||||
|
||||
|
||||
//iterates the sequence numbers
|
||||
xmlSequenceNumber++;
|
||||
|
||||
byte[] encodedXML = encoder.encode();
|
||||
|
||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.XMLMESSAGE, System.currentTimeMillis(), messageNumber, (short)encodedXML.length, encodedXML);
|
||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
|
||||
MessageType.XMLMESSAGE,
|
||||
System.currentTimeMillis(),
|
||||
messageNumber,
|
||||
(short)encodedXML.length,
|
||||
encodedXML);
|
||||
|
||||
|
||||
//iterates the message number
|
||||
messageNumber++;
|
||||
|
||||
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage());
|
||||
return binaryMessageEncoder.getFullMessage();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to give the mocOutput information about boat location to be made into a message and sent
|
||||
* @param sourceID id of the boat
|
||||
* @param lat latitude of boat
|
||||
* @param lon longitude of boat
|
||||
* @param heading heading of boat
|
||||
* @param speed speed of boat
|
||||
* @param time historical time of race
|
||||
* Encodes/serialises a BoatLocation message, and returns it.
|
||||
* @param boatLocation The BoatLocation message to serialise.
|
||||
* @return The BoatLocation message in a serialised form.
|
||||
*/
|
||||
public synchronized void parseBoatLocation(int sourceID, double lat, double lon, double heading, double speed, long time){
|
||||
private synchronized byte[] parseBoatLocation(BoatLocation boatLocation){
|
||||
|
||||
BoatLocation boatLocation = new BoatLocation(sourceID, lat, lon, boatLocationSequenceNumber, heading, speed, time);
|
||||
//iterates the sequence number
|
||||
boatLocationSequenceNumber++;
|
||||
|
||||
//encodeds the messages
|
||||
//Encodes the message.
|
||||
byte[] encodedBoatLoc = RaceVisionByteEncoder.boatLocation(boatLocation);
|
||||
|
||||
//encodeds the full message with header
|
||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.BOATLOCATION, System.currentTimeMillis(), messageNumber, (short)encodedBoatLoc.length,
|
||||
encodedBoatLoc);
|
||||
//Encodes the full message with header.
|
||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
|
||||
MessageType.BOATLOCATION,
|
||||
System.currentTimeMillis(),
|
||||
messageNumber,
|
||||
(short) encodedBoatLoc.length,
|
||||
encodedBoatLoc );
|
||||
|
||||
//iterates the message number
|
||||
messageNumber++;
|
||||
|
||||
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage());
|
||||
return binaryMessageEncoder.getFullMessage();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the race status data and add it to the buffer to be sent
|
||||
* @param raceStatus race status to parses
|
||||
* Encodes/serialises a RaceStatus message, and returns it.
|
||||
* @param raceStatus The RaceStatus message to serialise.
|
||||
* @return The RaceStatus message in a serialised form.
|
||||
*/
|
||||
public synchronized void parseRaceStatus(RaceStatus raceStatus){
|
||||
private synchronized byte[] parseRaceStatus(RaceStatus raceStatus){
|
||||
|
||||
//iterates the sequence number
|
||||
raceStatusSequenceNumber++;
|
||||
|
||||
//encodeds the messages
|
||||
//Encodes the messages.
|
||||
byte[] encodedRaceStatus = RaceVisionByteEncoder.raceStatus(raceStatus);
|
||||
|
||||
//encodeds the full message with header
|
||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.RACESTATUS, System.currentTimeMillis(), messageNumber, (short)encodedRaceStatus.length,
|
||||
encodedRaceStatus);
|
||||
//Encodes the full message with header.
|
||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
|
||||
MessageType.RACESTATUS,
|
||||
System.currentTimeMillis(),
|
||||
messageNumber,
|
||||
(short) encodedRaceStatus.length,
|
||||
encodedRaceStatus );
|
||||
|
||||
//iterates the message number
|
||||
messageNumber++;
|
||||
|
||||
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage());
|
||||
return binaryMessageEncoder.getFullMessage();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a message to the buffer to be sent
|
||||
* @param messagesToSendBuffer message to add to the buffer
|
||||
*/
|
||||
private synchronized void addMessageToBufferToSend(byte[] messagesToSendBuffer) {
|
||||
this.messagesToSendQueue.add(messagesToSendBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sending loop of the Server
|
||||
@@ -175,7 +201,7 @@ public class MockOutput implements Runnable
|
||||
|
||||
outToVisualiser = new DataOutputStream(mockSocket.getOutputStream());
|
||||
|
||||
if (boatsXml == null || regattaXml == null || raceXml == null){
|
||||
if (boatsXml == null || regattaXml == null || raceXml == null) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
@@ -184,34 +210,91 @@ public class MockOutput implements Runnable
|
||||
continue;
|
||||
}
|
||||
|
||||
parseXMLString(raceXml, XMLMessage.XMLTypeRace);
|
||||
parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta);
|
||||
parseXMLString(boatsXml, XMLMessage.XMLTypeBoat);
|
||||
//Encode xml files. We send them inside the loop, depending on the sentXMLs boolean.
|
||||
byte[] raceXMLBlob = parseXMLString(raceXml, XMLMessage.XMLTypeRace);
|
||||
byte[] regattaXMLBlob = parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta);
|
||||
byte[] boatsXMLBlob = parseXMLString(boatsXml, XMLMessage.XMLTypeBoat);
|
||||
|
||||
|
||||
long previousFrameTime = System.currentTimeMillis();
|
||||
boolean sentXMLs = false;
|
||||
|
||||
|
||||
while(true) {
|
||||
try {
|
||||
|
||||
long currentFrameTime = System.currentTimeMillis();
|
||||
|
||||
//This is the time elapsed, in milliseconds, since the last server "frame".
|
||||
long framePeriod = currentFrameTime - previousFrameTime;
|
||||
|
||||
//We only attempt to send packets every X milliseconds.
|
||||
long minimumFramePeriod = 16;
|
||||
if (framePeriod >= minimumFramePeriod) {
|
||||
|
||||
//Sends a heartbeat every so often.
|
||||
if (timeSinceHeartbeat() >= heartbeatPeriod) {
|
||||
outToVisualiser.write(heartbeat());
|
||||
lastHeartbeatTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
//Checks the buffer to see if there is anything to send.
|
||||
while (messagesToSendQueue.size() > 0) {
|
||||
//Grabs message from head of queue.
|
||||
byte[] binaryMessage = messagesToSendQueue.remove();
|
||||
//Send XML messages.
|
||||
if (!sentXMLs) {
|
||||
outToVisualiser.write(raceXMLBlob);
|
||||
outToVisualiser.write(regattaXMLBlob);
|
||||
outToVisualiser.write(boatsXMLBlob);
|
||||
sentXMLs = true;
|
||||
}
|
||||
|
||||
//sends the message to the visualiser
|
||||
outToVisualiser.write(binaryMessage);
|
||||
//Sens the RaceStatus message.
|
||||
if (this.latestMessages.getRaceStatus() != null) {
|
||||
byte[] raceStatusBlob = this.parseRaceStatus(this.latestMessages.getRaceStatus());
|
||||
|
||||
this.outToVisualiser.write(raceStatusBlob);
|
||||
}
|
||||
|
||||
//Send all of the BoatLocation messages.
|
||||
for (int sourceID : this.latestMessages.getBoatLocationMap().keySet()) {
|
||||
|
||||
//Get the message.
|
||||
BoatLocation boatLocation = this.latestMessages.getBoatLocation(sourceID);
|
||||
if (boatLocation != null) {
|
||||
|
||||
//Encode.
|
||||
byte[] boatLocationBlob = this.parseBoatLocation(boatLocation);
|
||||
|
||||
//Write it.
|
||||
this.outToVisualiser.write(boatLocationBlob);
|
||||
|
||||
}
|
||||
}catch(SocketException e){
|
||||
}
|
||||
|
||||
previousFrameTime = currentFrameTime;
|
||||
|
||||
|
||||
} else {
|
||||
//Wait until the frame period will be large enough.
|
||||
long timeToWait = minimumFramePeriod - framePeriod;
|
||||
|
||||
try {
|
||||
Thread.sleep(timeToWait);
|
||||
} catch (InterruptedException e) {
|
||||
//If we get interrupted, exit the function.
|
||||
e.printStackTrace();
|
||||
//Re-set the interrupt flag.
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch (SocketException e) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -247,7 +330,7 @@ public class MockOutput implements Runnable
|
||||
|
||||
public static void main(String argv[]) throws Exception
|
||||
{
|
||||
MockOutput client = new MockOutput();
|
||||
MockOutput client = new MockOutput(new LatestMessages());
|
||||
client.run();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package mock.model;
|
||||
|
||||
import javafx.animation.AnimationTimer;
|
||||
import mock.app.MockOutput;
|
||||
import network.Messages.BoatLocation;
|
||||
import network.Messages.BoatStatus;
|
||||
import network.Messages.Enums.BoatStatusEnum;
|
||||
import network.Messages.LatestMessages;
|
||||
import network.Messages.RaceStatus;
|
||||
import network.Utils.AC35UnitConverter;
|
||||
import shared.dataInput.BoatDataSource;
|
||||
@@ -52,12 +54,6 @@ public class MockRace extends Race {
|
||||
private int dnfChance = 0;
|
||||
|
||||
|
||||
/**
|
||||
* The mockOutput to send messages to.
|
||||
*/
|
||||
private MockOutput mockOutput;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used to generate random numbers when changing the wind direction.
|
||||
@@ -88,13 +84,12 @@ public class MockRace extends Race {
|
||||
* @param raceDataSource Data source for race related data (participating boats, legs, etc...).
|
||||
* @param regattaDataSource Data source for race related data (course name, location, timezone, etc...).
|
||||
* @param polars The polars table to be used for boat simulation.
|
||||
* @param mockOutput The mockOutput to send events to.
|
||||
* @param latestMessages The LatestMessages to send events to.
|
||||
*/
|
||||
public MockRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, Polars polars, MockOutput mockOutput) {
|
||||
public MockRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, Polars polars, LatestMessages latestMessages) {
|
||||
|
||||
super(boatDataSource, raceDataSource, regattaDataSource);
|
||||
super(boatDataSource, raceDataSource, regattaDataSource, latestMessages);
|
||||
|
||||
this.mockOutput = mockOutput;
|
||||
|
||||
this.boats = this.generateMockBoats(boatDataSource.getBoats(), raceDataSource.getParticipants(), polars);
|
||||
|
||||
@@ -175,14 +170,20 @@ public class MockRace extends Race {
|
||||
*/
|
||||
private void parseIndividualMark(Mark mark) {
|
||||
|
||||
this.mockOutput.parseBoatLocation(
|
||||
//Create message.
|
||||
BoatLocation boatLocation = new BoatLocation(
|
||||
mark.getSourceID(),
|
||||
mark.getPosition().getLatitude(),
|
||||
mark.getPosition().getLongitude(),
|
||||
0,
|
||||
0,
|
||||
this.totalTimeElapsed + this.startTime
|
||||
);
|
||||
boatLocationSequenceNumber,
|
||||
0, 0,
|
||||
totalTimeElapsed + startTime);
|
||||
|
||||
//Iterates the sequence number.
|
||||
boatLocationSequenceNumber++;
|
||||
|
||||
this.latestMessages.setBoatLocation(boatLocation);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -206,14 +207,19 @@ public class MockRace extends Race {
|
||||
*/
|
||||
private void parseIndividualBoatLocation(MockBoat boat) {
|
||||
|
||||
this.mockOutput.parseBoatLocation(
|
||||
BoatLocation boatLocation = new BoatLocation(
|
||||
boat.getSourceID(),
|
||||
boat.getCurrentPosition().getLatitude(),
|
||||
boat.getCurrentPosition().getLongitude(),
|
||||
boatLocationSequenceNumber,
|
||||
boat.getBearing().degrees(),
|
||||
boat.getCurrentSpeed(),
|
||||
startTime + totalTimeElapsed
|
||||
);
|
||||
startTime + totalTimeElapsed);
|
||||
|
||||
//Iterates the sequence number.
|
||||
boatLocationSequenceNumber++;
|
||||
|
||||
this.latestMessages.setBoatLocation(boatLocation);
|
||||
|
||||
}
|
||||
|
||||
@@ -272,7 +278,6 @@ public class MockRace extends Race {
|
||||
boatStatuses.add(boatStatus);
|
||||
}
|
||||
|
||||
//TODO REFACTOR for consistency, could send parameters to mockOutput instead of the whole racestatus. This will also fix the sequence number issue.
|
||||
|
||||
//Convert wind direction and speed to ints. //TODO this conversion should be done inside the racestatus class.
|
||||
int windDirectionInt = AC35UnitConverter.encodeHeading(this.windDirection.degrees());
|
||||
@@ -283,12 +288,14 @@ public class MockRace extends Race {
|
||||
System.currentTimeMillis(),
|
||||
this.raceId,
|
||||
this.getRaceStatusEnum().getValue(),
|
||||
this.startTime, windDirectionInt,
|
||||
this.startTime,
|
||||
windDirectionInt,
|
||||
windSpeedInt,
|
||||
this.getRaceType().getValue(),
|
||||
boatStatuses );
|
||||
boatStatuses);
|
||||
|
||||
mockOutput.parseRaceStatus(raceStatus);
|
||||
|
||||
this.latestMessages.setRaceStatus(raceStatus);
|
||||
|
||||
|
||||
}
|
||||
@@ -427,7 +434,6 @@ public class MockRace extends Race {
|
||||
parseRaceStatus();
|
||||
|
||||
if (iters > 500) {
|
||||
mockOutput.stop();
|
||||
stop();
|
||||
}
|
||||
iters++;
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package network.Messages;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class contains a set of the latest messages received (e.g., the latest RaceStatus, the latest BoatLocation for each boat, etc...).
|
||||
*/
|
||||
public class LatestMessages {
|
||||
|
||||
/**
|
||||
* The latest RaceStatus message.
|
||||
*/
|
||||
private RaceStatus raceStatus;
|
||||
|
||||
/**
|
||||
* A map of the last BoatStatus message received, for each boat.
|
||||
*/
|
||||
private final Map<Integer, BoatStatus> boatStatusMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A map of the last BoatLocation message received, for each boat.
|
||||
*/
|
||||
private final Map<Integer, BoatLocation> boatLocationMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The last AverageWind message received.
|
||||
*/
|
||||
private AverageWind averageWind;
|
||||
|
||||
/**
|
||||
* The last CourseWinds message received.
|
||||
*/
|
||||
private CourseWinds courseWinds;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
*/
|
||||
public LatestMessages() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the latest RaceStatus message received.
|
||||
* @return The latest RaceStatus message received.
|
||||
*/
|
||||
public RaceStatus getRaceStatus() {
|
||||
return raceStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the latest RaceStatus message received.
|
||||
* @param raceStatus The new RaceStatus message to store.
|
||||
*/
|
||||
public void setRaceStatus(RaceStatus raceStatus) {
|
||||
this.raceStatus = raceStatus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the latest BoatStatus message received for a given boat.
|
||||
* @param sourceID Source ID of the boat.
|
||||
* @return The latest BoatStatus message for the specified boat.
|
||||
*/
|
||||
public BoatStatus getBoatStatus(int sourceID) {
|
||||
return boatStatusMap.get(sourceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a BoatStatus message for a given boat.
|
||||
* @param boatStatus The BoatStatus message to set.
|
||||
*/
|
||||
public void setBoatStatus(BoatStatus boatStatus) {
|
||||
boatStatusMap.put(boatStatus.getSourceID(), boatStatus);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the latest BoatLocation message received for a given boat.
|
||||
* @param sourceID Source ID of the boat.
|
||||
* @return The latest BoatLocation message for the specified boat.
|
||||
*/
|
||||
public BoatLocation getBoatLocation(int sourceID) {
|
||||
return boatLocationMap.get(sourceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a BoatLocation message for a given boat.
|
||||
* @param boatLocation The BoatLocation message to set.
|
||||
*/
|
||||
public void setBoatLocation(BoatLocation boatLocation) {
|
||||
//TODO should compare the sequence number of the new boatLocation with the existing boatLocation for this boat (if it exists), and use the newer one.
|
||||
boatLocationMap.put(boatLocation.getSourceID(), boatLocation);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the latest AverageWind message received.
|
||||
* @return The latest AverageWind message received.
|
||||
*/
|
||||
public AverageWind getAverageWind() {
|
||||
return averageWind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the latest AverageWind message received.
|
||||
* @param averageWind The new AverageWind message to store.
|
||||
*/
|
||||
public void setAverageWind(AverageWind averageWind) {
|
||||
this.averageWind = averageWind;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the latest CourseWinds message received.
|
||||
* @return The latest CourseWinds message received.
|
||||
*/
|
||||
public CourseWinds getCourseWinds() {
|
||||
return courseWinds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the latest CourseWinds message received.
|
||||
* @param courseWinds The new CourseWinds message to store.
|
||||
*/
|
||||
public void setCourseWinds(CourseWinds courseWinds) {
|
||||
this.courseWinds = courseWinds;
|
||||
}
|
||||
|
||||
|
||||
public Map<Integer, BoatLocation> getBoatLocationMap() {
|
||||
return boatLocationMap;
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,13 @@ public class Angle implements Comparable<Angle> {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Double.hashCode(this.degrees);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns an int describing the ordering between this angle object, and another.
|
||||
* @param o Other angle to compare to.
|
||||
|
||||
@@ -335,12 +335,12 @@ public class GPSCoordinate {
|
||||
//Get the bearing between two adjacent points.
|
||||
Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint);
|
||||
|
||||
//Calculate angle perpendicular to bearing.
|
||||
Bearing perpendicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor));
|
||||
//Calculate angle perpindicular to bearing.
|
||||
Bearing perpindicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor));
|
||||
|
||||
//Translate both first and second point by 50m, using this bearing. These form our inwards shifted edge.
|
||||
GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
|
||||
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
|
||||
GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing));
|
||||
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing));
|
||||
|
||||
//Add edge to list.
|
||||
shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated));
|
||||
@@ -355,12 +355,12 @@ public class GPSCoordinate {
|
||||
//Get the bearing between two adjacent points.
|
||||
Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint);
|
||||
|
||||
//Calculate angle perpendicular to bearing.
|
||||
Bearing perpendicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor));
|
||||
//Calculate angle perpindicular to bearing.
|
||||
Bearing perpindicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor));
|
||||
|
||||
//Translate both first and second point by 50m, using this bearing. These form our inwards shifted edge.
|
||||
GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
|
||||
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing));
|
||||
GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing));
|
||||
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing));
|
||||
|
||||
//Add edge to list.
|
||||
shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated));
|
||||
|
||||
@@ -5,6 +5,7 @@ import javafx.collections.FXCollections;
|
||||
import mock.model.VMG;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
import network.Messages.Enums.RaceTypeEnum;
|
||||
import network.Messages.LatestMessages;
|
||||
import shared.dataInput.BoatDataSource;
|
||||
import shared.dataInput.RaceDataSource;
|
||||
import shared.dataInput.RegattaDataSource;
|
||||
@@ -40,6 +41,18 @@ public abstract class Race implements Runnable {
|
||||
*/
|
||||
protected RegattaDataSource regattaDataSource;
|
||||
|
||||
/**
|
||||
* The collection of latest race messages.
|
||||
* Can be either read from or written to.
|
||||
*/
|
||||
protected LatestMessages latestMessages;
|
||||
|
||||
/**
|
||||
* The sequence number of the latest boatLocation message sent or received.
|
||||
*/
|
||||
protected int boatLocationSequenceNumber = 1;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A list of compound marks in the race.
|
||||
@@ -102,14 +115,17 @@ public abstract class Race implements Runnable {
|
||||
* @param boatDataSource Data source for boat related data (yachts and marker boats).
|
||||
* @param raceDataSource Data source for race related data (participating boats, legs, etc...).
|
||||
* @param regattaDataSource Data source for race related data (course name, location, timezone, etc...).
|
||||
* @param latestMessages The collection of latest messages, which can be written to, or read from.
|
||||
*/
|
||||
public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource) {
|
||||
public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, LatestMessages latestMessages) {
|
||||
|
||||
//Keep a reference to data sources.
|
||||
this.raceDataSource = raceDataSource;
|
||||
this.boatDataSource = boatDataSource;
|
||||
this.regattaDataSource = regattaDataSource;
|
||||
|
||||
this.latestMessages = latestMessages;
|
||||
|
||||
|
||||
this.compoundMarks = raceDataSource.getCompoundMarks();
|
||||
|
||||
|
||||
@@ -11,10 +11,9 @@ import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import seng302.Mock.StreamedCourse;
|
||||
import seng302.Model.Boat;
|
||||
import seng302.Model.RaceClock;
|
||||
import seng302.VisualiserInput;
|
||||
import visualiser.app.VisualiserInput;
|
||||
import visualiser.model.RaceClock;
|
||||
import visualiser.model.VisualiserBoat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
@@ -35,18 +34,16 @@ public class StartController extends Controller implements Observer {
|
||||
@FXML private Label raceTitleLabel;
|
||||
@FXML private Label raceStartLabel;
|
||||
|
||||
@FXML private TableView<Boat> boatNameTable;
|
||||
@FXML private TableColumn<Boat, String> boatNameColumn;
|
||||
@FXML private TableColumn<Boat, String> boatCodeColumn;
|
||||
@FXML private TableView<VisualiserBoat> boatNameTable;
|
||||
@FXML private TableColumn<VisualiserBoat, String> boatNameColumn;
|
||||
@FXML private TableColumn<VisualiserBoat, String> boatCodeColumn;
|
||||
@FXML private Label timeZoneTime;
|
||||
@FXML private Label timer;
|
||||
@FXML private Label raceStatusLabel;
|
||||
|
||||
//@FXML Button fifteenMinButton;
|
||||
|
||||
private RaceClock raceClock;
|
||||
|
||||
private StreamedCourse raceData;
|
||||
private int raceStat;
|
||||
|
||||
private VisualiserInput visualiserInput;
|
||||
@@ -80,8 +77,8 @@ public class StartController extends Controller implements Observer {
|
||||
* Initiliases the tables that are to be shown on the pane
|
||||
*/
|
||||
private void initialiseTables() {
|
||||
List<Boat> boats = raceData.getBoats();
|
||||
ObservableList<Boat> observableBoats = FXCollections.observableArrayList(boats);
|
||||
List<VisualiserBoat> boats = raceData.getBoats();
|
||||
ObservableList<VisualiserBoat> observableBoats = FXCollections.observableArrayList(boats);
|
||||
|
||||
boatNameTable.setItems(observableBoats);
|
||||
boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().getName());
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package visualiser.app;
|
||||
import javafx.application.Platform;
|
||||
import network.Messages.*;
|
||||
import org.xml.sax.SAXException;
|
||||
import seng302.Networking.BinaryMessageDecoder;
|
||||
import seng302.Networking.Exceptions.InvalidMessageException;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.DataInputStream;
|
||||
@@ -13,12 +12,9 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static seng302.Networking.Utils.ByteConverter.bytesToShort;
|
||||
|
||||
/**
|
||||
* TCP client which receives packets/messages from a race data source
|
||||
* (e.g., mock source, official source), and exposes them to any observers.
|
||||
* @see seng302.Mock.StreamedCourse
|
||||
*/
|
||||
public class VisualiserInput implements Runnable {
|
||||
|
||||
@@ -30,8 +26,6 @@ public class VisualiserInput implements Runnable {
|
||||
///The socket that we have connected to.
|
||||
private Socket connectionSocket;
|
||||
|
||||
///Object to store parsed course data. //TODO comment?
|
||||
private StreamedCourse course;
|
||||
|
||||
///The last RaceStatus message received.
|
||||
private RaceStatus raceStatus;
|
||||
|
||||
Reference in New Issue
Block a user