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().
main
fjc40 9 years ago
parent 3a0b81834f
commit 8e18ad62ca

@ -3,6 +3,7 @@ package mock.app;
import mock.model.MockRace; import mock.model.MockRace;
import mock.model.Polars; import mock.model.Polars;
import network.Messages.Enums.MessageType; import network.Messages.Enums.MessageType;
import network.Messages.LatestMessages;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import shared.dataInput.*; import shared.dataInput.*;
import shared.exceptions.InvalidBoatDataException; import shared.exceptions.InvalidBoatDataException;
@ -28,6 +29,8 @@ public class Event {
private String boatXML; private String boatXML;
private Polars boatPolars; private Polars boatPolars;
private MockOutput mockOutput; private MockOutput mockOutput;
private LatestMessages latestMessages;
public Event(String raceXML, String regattaXML, String boatXML, Polars boatPolars) { public Event(String raceXML, String regattaXML, String boatXML, Polars boatPolars) {
@ -36,9 +39,13 @@ public class Event {
this.regattaXML = regattaXML; this.regattaXML = regattaXML;
this.boatPolars = boatPolars; this.boatPolars = boatPolars;
this.latestMessages = new LatestMessages();
try { try {
mockOutput = new MockOutput(); this.mockOutput = new MockOutput(this.latestMessages);
new Thread(mockOutput).start(); new Thread(mockOutput).start();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -57,7 +64,7 @@ public class Event {
RegattaDataSource regattaDataSource = new RegattaXMLReader(this.regattaXML); RegattaDataSource regattaDataSource = new RegattaXMLReader(this.regattaXML);
//Create and start race. //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(); new Thread(newRace).start();

@ -7,6 +7,7 @@ import network.MessageEncoders.RaceVisionByteEncoder;
import network.MessageEncoders.XMLMessageEncoder; import network.MessageEncoders.XMLMessageEncoder;
import network.Messages.BoatLocation; import network.Messages.BoatLocation;
import network.Messages.Enums.MessageType; import network.Messages.Enums.MessageType;
import network.Messages.LatestMessages;
import network.Messages.RaceStatus; import network.Messages.RaceStatus;
import network.Messages.XMLMessage; import network.Messages.XMLMessage;
@ -37,8 +38,14 @@ public class MockOutput implements Runnable
///Output stream which wraps around mockSocket outstream. ///Output stream which wraps around mockSocket outstream.
private DataOutputStream outToVisualiser; 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. ///Sequence numbers used in messages.
private short messageNumber = 1; private short messageNumber = 1;
@ -56,11 +63,15 @@ public class MockOutput implements Runnable
/** /**
* Ctor. * Ctor.
* @param latestMessages The collection of messages to send to connected clients.
* @throws IOException if server socket cannot be opened. * @throws IOException if server socket cannot be opened.
*/ */
public MockOutput() throws IOException { public MockOutput(LatestMessages latestMessages) throws IOException {
lastHeartbeatTime = System.currentTimeMillis();
serverSocket = new ServerSocket(serverPort); this.lastHeartbeatTime = System.currentTimeMillis();
this.serverSocket = new ServerSocket(serverPort);
this.latestMessages = latestMessages;
} }
/** /**
@ -91,78 +102,93 @@ public class MockOutput implements Runnable
* @param xmlString the xml string to send * @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) * @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){ public synchronized byte[] parseXMLString(String xmlString, int messageType) {
XMLMessageEncoder encoder = new XMLMessageEncoder(messageNumber, System.currentTimeMillis(), messageType, xmlSequenceNumber,(short) xmlString.length(), xmlString);
XMLMessageEncoder encoder = new XMLMessageEncoder(
messageNumber,
System.currentTimeMillis(),
messageType,
xmlSequenceNumber,
(short) xmlString.length(),
xmlString);
//iterates the sequence numbers //iterates the sequence numbers
xmlSequenceNumber++; xmlSequenceNumber++;
byte[] encodedXML = encoder.encode(); 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 //iterates the message number
messageNumber++; messageNumber++;
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage()); return binaryMessageEncoder.getFullMessage();
} }
/** /**
* Used to give the mocOutput information about boat location to be made into a message and sent * Encodes/serialises a BoatLocation message, and returns it.
* @param sourceID id of the boat * @param boatLocation The BoatLocation message to serialise.
* @param lat latitude of boat * @return The BoatLocation message in a serialised form.
* @param lon longitude of boat
* @param heading heading of boat
* @param speed speed of boat
* @param time historical time of race
*/ */
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); byte[] encodedBoatLoc = RaceVisionByteEncoder.boatLocation(boatLocation);
//encodeds the full message with header //Encodes the full message with header.
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.BOATLOCATION, System.currentTimeMillis(), messageNumber, (short)encodedBoatLoc.length, BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
encodedBoatLoc); MessageType.BOATLOCATION,
System.currentTimeMillis(),
messageNumber,
(short) encodedBoatLoc.length,
encodedBoatLoc );
//iterates the message number //iterates the message number
messageNumber++; messageNumber++;
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage()); return binaryMessageEncoder.getFullMessage();
} }
/** /**
* Parse the race status data and add it to the buffer to be sent * Encodes/serialises a RaceStatus message, and returns it.
* @param raceStatus race status to parses * @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 //iterates the sequence number
raceStatusSequenceNumber++; raceStatusSequenceNumber++;
//encodeds the messages //Encodes the messages.
byte[] encodedRaceStatus = RaceVisionByteEncoder.raceStatus(raceStatus); byte[] encodedRaceStatus = RaceVisionByteEncoder.raceStatus(raceStatus);
//encodeds the full message with header //Encodes the full message with header.
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.RACESTATUS, System.currentTimeMillis(), messageNumber, (short)encodedRaceStatus.length, BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
encodedRaceStatus); MessageType.RACESTATUS,
System.currentTimeMillis(),
messageNumber,
(short) encodedRaceStatus.length,
encodedRaceStatus );
//iterates the message number //iterates the message number
messageNumber++; 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 * Sending loop of the Server
*/ */
@ -175,7 +201,7 @@ public class MockOutput implements Runnable
outToVisualiser = new DataOutputStream(mockSocket.getOutputStream()); outToVisualiser = new DataOutputStream(mockSocket.getOutputStream());
if (boatsXml == null || regattaXml == null || raceXml == null){ if (boatsXml == null || regattaXml == null || raceXml == null) {
try { try {
Thread.sleep(500); Thread.sleep(500);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -184,34 +210,91 @@ public class MockOutput implements Runnable
continue; continue;
} }
parseXMLString(raceXml, XMLMessage.XMLTypeRace); //Encode xml files. We send them inside the loop, depending on the sentXMLs boolean.
parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta); byte[] raceXMLBlob = parseXMLString(raceXml, XMLMessage.XMLTypeRace);
parseXMLString(boatsXml, XMLMessage.XMLTypeBoat); byte[] regattaXMLBlob = parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta);
byte[] boatsXMLBlob = parseXMLString(boatsXml, XMLMessage.XMLTypeBoat);
long previousFrameTime = System.currentTimeMillis();
boolean sentXMLs = false;
while(true) { while(true) {
try { try {
//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. long currentFrameTime = System.currentTimeMillis();
while (messagesToSendQueue.size() > 0) {
//Grabs message from head of queue. //This is the time elapsed, in milliseconds, since the last server "frame".
byte[] binaryMessage = messagesToSendQueue.remove(); 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();
}
//Send XML messages.
if (!sentXMLs) {
outToVisualiser.write(raceXMLBlob);
outToVisualiser.write(regattaXMLBlob);
outToVisualiser.write(boatsXMLBlob);
sentXMLs = true;
}
//Sens the RaceStatus message.
if (this.latestMessages.getRaceStatus() != null) {
byte[] raceStatusBlob = this.parseRaceStatus(this.latestMessages.getRaceStatus());
this.outToVisualiser.write(raceStatusBlob);
}
//sends the message to the visualiser //Send all of the BoatLocation messages.
outToVisualiser.write(binaryMessage); 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);
}
}
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){
} catch (SocketException e) {
break; break;
} }
} }
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -247,7 +330,7 @@ public class MockOutput implements Runnable
public static void main(String argv[]) throws Exception public static void main(String argv[]) throws Exception
{ {
MockOutput client = new MockOutput(); MockOutput client = new MockOutput(new LatestMessages());
client.run(); client.run();
} }

@ -2,8 +2,10 @@ package mock.model;
import javafx.animation.AnimationTimer; import javafx.animation.AnimationTimer;
import mock.app.MockOutput; import mock.app.MockOutput;
import network.Messages.BoatLocation;
import network.Messages.BoatStatus; import network.Messages.BoatStatus;
import network.Messages.Enums.BoatStatusEnum; import network.Messages.Enums.BoatStatusEnum;
import network.Messages.LatestMessages;
import network.Messages.RaceStatus; import network.Messages.RaceStatus;
import network.Utils.AC35UnitConverter; import network.Utils.AC35UnitConverter;
import shared.dataInput.BoatDataSource; import shared.dataInput.BoatDataSource;
@ -52,12 +54,6 @@ public class MockRace extends Race {
private int dnfChance = 0; private int dnfChance = 0;
/**
* The mockOutput to send messages to.
*/
private MockOutput mockOutput;
/** /**
* Used to generate random numbers when changing the wind direction. * 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 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 regattaDataSource Data source for race related data (course name, location, timezone, etc...).
* @param polars The polars table to be used for boat simulation. * @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); this.boats = this.generateMockBoats(boatDataSource.getBoats(), raceDataSource.getParticipants(), polars);
@ -175,14 +170,20 @@ public class MockRace extends Race {
*/ */
private void parseIndividualMark(Mark mark) { private void parseIndividualMark(Mark mark) {
this.mockOutput.parseBoatLocation( //Create message.
BoatLocation boatLocation = new BoatLocation(
mark.getSourceID(), mark.getSourceID(),
mark.getPosition().getLatitude(), mark.getPosition().getLatitude(),
mark.getPosition().getLongitude(), mark.getPosition().getLongitude(),
0, boatLocationSequenceNumber,
0, 0, 0,
this.totalTimeElapsed + this.startTime 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) { private void parseIndividualBoatLocation(MockBoat boat) {
this.mockOutput.parseBoatLocation( BoatLocation boatLocation = new BoatLocation(
boat.getSourceID(), boat.getSourceID(),
boat.getCurrentPosition().getLatitude(), boat.getCurrentPosition().getLatitude(),
boat.getCurrentPosition().getLongitude(), boat.getCurrentPosition().getLongitude(),
boatLocationSequenceNumber,
boat.getBearing().degrees(), boat.getBearing().degrees(),
boat.getCurrentSpeed(), 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); 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. //Convert wind direction and speed to ints. //TODO this conversion should be done inside the racestatus class.
int windDirectionInt = AC35UnitConverter.encodeHeading(this.windDirection.degrees()); int windDirectionInt = AC35UnitConverter.encodeHeading(this.windDirection.degrees());
@ -283,12 +288,14 @@ public class MockRace extends Race {
System.currentTimeMillis(), System.currentTimeMillis(),
this.raceId, this.raceId,
this.getRaceStatusEnum().getValue(), this.getRaceStatusEnum().getValue(),
this.startTime, windDirectionInt, this.startTime,
windDirectionInt,
windSpeedInt, windSpeedInt,
this.getRaceType().getValue(), this.getRaceType().getValue(),
boatStatuses ); boatStatuses);
mockOutput.parseRaceStatus(raceStatus); this.latestMessages.setRaceStatus(raceStatus);
} }
@ -427,7 +434,6 @@ public class MockRace extends Race {
parseRaceStatus(); parseRaceStatus();
if (iters > 500) { if (iters > 500) {
mockOutput.stop();
stop(); stop();
} }
iters++; 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. * Returns an int describing the ordering between this angle object, and another.
* @param o Other angle to compare to. * @param o Other angle to compare to.

@ -335,12 +335,12 @@ public class GPSCoordinate {
//Get the bearing between two adjacent points. //Get the bearing between two adjacent points.
Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint); Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint);
//Calculate angle perpendicular to bearing. //Calculate angle perpindicular to bearing.
Bearing perpendicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor)); 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. //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 firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing));
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing)); GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing));
//Add edge to list. //Add edge to list.
shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated)); shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated));
@ -355,12 +355,12 @@ public class GPSCoordinate {
//Get the bearing between two adjacent points. //Get the bearing between two adjacent points.
Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint); Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint);
//Calculate angle perpendicular to bearing. //Calculate angle perpindicular to bearing.
Bearing perpendicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor)); 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. //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 firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing));
GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing)); GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing));
//Add edge to list. //Add edge to list.
shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated)); shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated));

@ -5,6 +5,7 @@ import javafx.collections.FXCollections;
import mock.model.VMG; import mock.model.VMG;
import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceStatusEnum;
import network.Messages.Enums.RaceTypeEnum; import network.Messages.Enums.RaceTypeEnum;
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;
@ -40,6 +41,18 @@ public abstract class Race implements Runnable {
*/ */
protected RegattaDataSource regattaDataSource; 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. * 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 boatDataSource Data source for boat related data (yachts and marker boats).
* @param raceDataSource Data source for race related data (participating boats, legs, etc...). * @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 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. //Keep a reference to data sources.
this.raceDataSource = raceDataSource; this.raceDataSource = raceDataSource;
this.boatDataSource = boatDataSource; this.boatDataSource = boatDataSource;
this.regattaDataSource = regattaDataSource; this.regattaDataSource = regattaDataSource;
this.latestMessages = latestMessages;
this.compoundMarks = raceDataSource.getCompoundMarks(); this.compoundMarks = raceDataSource.getCompoundMarks();

@ -11,10 +11,9 @@ import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import seng302.Mock.StreamedCourse; import visualiser.app.VisualiserInput;
import seng302.Model.Boat; import visualiser.model.RaceClock;
import seng302.Model.RaceClock; import visualiser.model.VisualiserBoat;
import seng302.VisualiserInput;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
@ -35,18 +34,16 @@ public class StartController extends Controller implements Observer {
@FXML private Label raceTitleLabel; @FXML private Label raceTitleLabel;
@FXML private Label raceStartLabel; @FXML private Label raceStartLabel;
@FXML private TableView<Boat> boatNameTable; @FXML private TableView<VisualiserBoat> boatNameTable;
@FXML private TableColumn<Boat, String> boatNameColumn; @FXML private TableColumn<VisualiserBoat, String> boatNameColumn;
@FXML private TableColumn<Boat, String> boatCodeColumn; @FXML private TableColumn<VisualiserBoat, String> boatCodeColumn;
@FXML private Label timeZoneTime; @FXML private Label timeZoneTime;
@FXML private Label timer; @FXML private Label timer;
@FXML private Label raceStatusLabel; @FXML private Label raceStatusLabel;
//@FXML Button fifteenMinButton;
private RaceClock raceClock; private RaceClock raceClock;
private StreamedCourse raceData;
private int raceStat; private int raceStat;
private VisualiserInput visualiserInput; 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 * Initiliases the tables that are to be shown on the pane
*/ */
private void initialiseTables() { private void initialiseTables() {
List<Boat> boats = raceData.getBoats(); List<VisualiserBoat> boats = raceData.getBoats();
ObservableList<Boat> observableBoats = FXCollections.observableArrayList(boats); ObservableList<VisualiserBoat> observableBoats = FXCollections.observableArrayList(boats);
boatNameTable.setItems(observableBoats); boatNameTable.setItems(observableBoats);
boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().getName()); boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().getName());

@ -1,8 +1,7 @@
package visualiser.app; package visualiser.app;
import javafx.application.Platform; import javafx.application.Platform;
import network.Messages.*;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import seng302.Networking.BinaryMessageDecoder;
import seng302.Networking.Exceptions.InvalidMessageException;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import java.io.DataInputStream; import java.io.DataInputStream;
@ -13,12 +12,9 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static seng302.Networking.Utils.ByteConverter.bytesToShort;
/** /**
* TCP client which receives packets/messages from a race data source * TCP client which receives packets/messages from a race data source
* (e.g., mock source, official source), and exposes them to any observers. * (e.g., mock source, official source), and exposes them to any observers.
* @see seng302.Mock.StreamedCourse
*/ */
public class VisualiserInput implements Runnable { public class VisualiserInput implements Runnable {
@ -30,8 +26,6 @@ public class VisualiserInput implements Runnable {
///The socket that we have connected to. ///The socket that we have connected to.
private Socket connectionSocket; private Socket connectionSocket;
///Object to store parsed course data. //TODO comment?
private StreamedCourse course;
///The last RaceStatus message received. ///The last RaceStatus message received.
private RaceStatus raceStatus; private RaceStatus raceStatus;

Loading…
Cancel
Save