Merge branch 'Story47CourseLimits' into 'develop'

Story47 course limits

The idea was to have the course canvas update whenever we receive a new xml packet for the race data. Specifically for a few seconds after the race where the course boundaries change, going from a boundary which contains the start line to cutting off the start line as soon as the boats start.

See merge request !30
This commit is contained in:
Michael Rausch
2017-05-15 18:43:49 +12:00
9 changed files with 175 additions and 113 deletions
+2 -6
View File
@@ -9,8 +9,8 @@ import seng302.models.parsers.StreamParser;
import seng302.models.parsers.StreamReceiver;
import seng302.server.ServerThread;
public class App extends Application
{
public class App extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/views/MainView.fxml"));
@@ -62,8 +62,6 @@ public class App extends Application
}
//Change the StreamReceiver in this else block to change the default data source.
else{
// sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
sr = new StreamReceiver("localhost", 4949, "RaceStream");
}
@@ -73,8 +71,6 @@ public class App extends Application
launch(args);
}
}
@@ -240,6 +240,17 @@ public class CanvasController {
}
}
}
checkForCourseChanges();
}
private void checkForCourseChanges() {
if (StreamParser.isNewRaceXmlReceived()){
gc.setFill(Color.SKYBLUE);
gc.fillRect(0,0, CANVAS_WIDTH, CANVAS_HEIGHT);
gc.restore();
addRaceBorder();
canvas.toBack();
}
}
private void move(long id, RaceObject raceObject){
@@ -345,6 +356,8 @@ public class CanvasController {
* Calculates x and y location for every marker that fits it to the canvas the race will be drawn on.
*/
private void fitMarksToCanvas() {
//Check is called once to avoid unnecessarily change the course limits once the race is running
StreamParser.isNewRaceXmlReceived();
findMinMaxPoint();
double minLonToMaxLon = scaleRaceExtremities();
calculateReferencePointLocation(minLonToMaxLon);
@@ -1,53 +0,0 @@
package seng302.models.parsers;
/**
* Created by Kusal on 4/24/2017.
*/
public enum PacketType {
HEARTBEAT,
RACE_STATUS,
DISPLAY_TEXT_MESSAGE,
XML_MESSAGE,
RACE_START_STATUS,
YACHT_EVENT_CODE,
YACHT_ACTION_CODE,
CHATTER_TEXT,
BOAT_LOCATION,
MARK_ROUNDING,
COURSE_WIND,
AVG_WIND,
OTHER;
static PacketType assignPacketType(int packetType){
switch(packetType){
case 1:
return HEARTBEAT;
case 12:
return RACE_STATUS;
case 20:
return DISPLAY_TEXT_MESSAGE;
case 26:
return XML_MESSAGE;
case 27:
return RACE_START_STATUS;
case 29:
return YACHT_EVENT_CODE;
case 31:
return YACHT_ACTION_CODE;
case 36:
return CHATTER_TEXT;
case 37:
return BOAT_LOCATION;
case 38:
return MARK_ROUNDING;
case 44:
return COURSE_WIND;
case 47:
return AVG_WIND;
default:
}
return OTHER;
}
}
@@ -1,44 +0,0 @@
package seng302.models.parsers;
/**
* Created by kre39 on 23/04/17.
*/
public class StreamPacket {
//Change int to an ENUM for the type
private PacketType type;
private long messageLength;
private long timeStamp;
private byte[] payload;
StreamPacket(int type, long messageLength, long timeStamp, byte[] payload) {
this.type = PacketType.assignPacketType(type);
this.messageLength = messageLength;
this.timeStamp = timeStamp;
this.payload = payload;
// System.out.println("type = " + this.type.toString());
//switch the packet type to deal with what ever specific packet you want to deal with
// if (this.type == PacketType.XML_MESSAGE){
// //System.out.println("--------");
// System.out.println(new String(payload));
// //StreamParser.parsePacket(this);
// }
}
PacketType getType() {
return type;
}
public long getMessageLength() {
return messageLength;
}
byte[] getPayload() {
return payload;
}
long getTimeStamp() {
return timeStamp;
}
}
@@ -31,6 +31,7 @@ public class StreamParser extends Thread{
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatPositions = new ConcurrentHashMap<>();
private String threadName;
private Thread t;
private static boolean newRaceXmlReceived = false;
private static boolean raceStarted = false;
private static XMLParser xmlObject;
private static boolean raceFinished = false;
@@ -123,6 +124,7 @@ public class StreamParser extends Thread{
extractDisplayMessage(packet);
break;
case XML_MESSAGE:
newRaceXmlReceived = true;
extractXmlMessage(packet);
break;
case RACE_START_STATUS:
@@ -296,9 +298,8 @@ public class StreamParser extends Thread{
byte[] payload = packet.getPayload();
int messageType = payload[9];
long messagelength = bytesToLong(Arrays.copyOfRange(payload,12,14));
String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messagelength)))).trim();
//System.out.println("xmlMessage2 = " + xmlMessage);
long messageLength = bytesToLong(Arrays.copyOfRange(payload,12,14));
String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messageLength)))).trim();
//Create XML document Object
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
@@ -315,6 +316,9 @@ public class StreamParser extends Thread{
if (messageType == 7) { //7 is the boat XML
boats = xmlObject.getBoatXML().getCompetingBoats();
}
if (messageType == 6) { //6 is race info xml
newRaceXmlReceived = true;
}
}
/**
@@ -593,5 +597,20 @@ public class StreamParser extends Thread{
appRunning = false;
System.out.println("[CLIENT] Shutting down stream parser");
}
/**
* Used to check if a new un-processed xml has been found, if so will return true before
* toggling off so that the next check will return false.
*
* @return the status of if new xml has been received
*/
public static boolean isNewRaceXmlReceived(){
if (newRaceXmlReceived){
newRaceXmlReceived = false;
return true;
} else {
return false;
}
}
}
+25 -2
View File
@@ -235,6 +235,28 @@ public class ServerThread implements Runnable, Observer {
}
}
/**
* Send the post-start race course information
*/
private void sendPostStartCourseXml(){
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
try {
Message raceData = getXmlMessage("/server_config/courseLimits.xml", XMLMessageSubType.RACE);
if (raceData != null) {
server.send(raceData);
serverLog("Sending race data", 0);
}
}catch (IOException e) {
serverLog("Couldn't send an XML Message: " + e.getMessage(), 0);
}
}
},25000);
//Delays the new course xml data for 25 seconds so the boats are able to pass the starting line
}
public void run() {
try{
server = new StreamingServerSocket(PORT_NUMBER);
@@ -252,12 +274,13 @@ public class ServerThread implements Runnable, Observer {
sendXml();
startSendingRaceStartStatusMessages();
startSendingRaceStatusMessages();
sendPostStartCourseXml();
}
/**
* Start sending static boat position updates when race has finished
*/
private void startSendingRaceFinishedBoatPostions(){
private void startSendingRaceFinishedBoatPositions(){
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
@@ -316,7 +339,7 @@ public class ServerThread implements Runnable, Observer {
}
if (numOfBoatsFinished == ((List<Boat>) arg).size()) {
startSendingRaceFinishedBoatPostions();
startSendingRaceFinishedBoatPositions();
}
}
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Race>
<CreationTimeDate>2015-08-29T13:12:40+02:00</CreationTimeDate>
<RaceStartTime Start="2015-08-29T13:10:00+02:00" Postpone="False"/>
<RaceID>15082901</RaceID>
<RaceType>Fleet</RaceType>
<Participants>
<Yacht SourceID="101"/>
<Yacht SourceID="102"/>
<Yacht SourceID="103"/>
<Yacht SourceID="104"/>
<Yacht SourceID="105"/>
<Yacht SourceID="106"/>
</Participants>
<Course>
<CompoundMark CompoundMarkID="1" Name="Mark0">
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.6703330" TargetLng="11.8278330"
SourceID="122"/>
<Mark SeqID="2" Name="Start Line 2" TargetLat="57.6703330" TargetLng="11.8278330"
SourceID="123"/>
</CompoundMark>
<CompoundMark CompoundMarkID="2" Name="Mark1">
<Mark SeqID="1" Name="Mark1" TargetLat="57.6675700" TargetLng="11.8359880" SourceID="131"/>
</CompoundMark>
<CompoundMark CompoundMarkID="3" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="124"/>
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="125"/>
</CompoundMark>
<CompoundMark CompoundMarkID="4" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="126"/>
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="127"/>
</CompoundMark>
<CompoundMark CompoundMarkID="5" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="124"/>
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="125"/>
</CompoundMark>
<CompoundMark CompoundMarkID="6" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="126"/>
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="127"/>
</CompoundMark>
<CompoundMark CompoundMarkID="7" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="124"/>
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="125"/>
</CompoundMark>
<CompoundMark CompoundMarkID="8" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="126"/>
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="127"/>
</CompoundMark>
<CompoundMark CompoundMarkID="9" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="124"/>
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="125"/>
</CompoundMark>
<CompoundMark CompoundMarkID="10" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="126"/>
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="127"/>
</CompoundMark>
<CompoundMark CompoundMarkID="11" Name="Mark4">
<Mark SeqID="1" Name="Finish Line 1" TargetLat="57.6715240" TargetLng="11.8444950"
SourceID="128"/>
<Mark SeqID="2" Name="Finish Line 2" TargetLat="57.6715240" TargetLng="11.8444950"
SourceID="129"/>
</CompoundMark>
</Course>
<CompoundMarkSequence>
<Corner SeqID="1" CompoundMarkID="1" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3"/>
<Corner SeqID="3" CompoundMarkID="3" Rounding="SP" ZoneSize="3"/>
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="5" CompoundMarkID="5" Rounding="SP" ZoneSize="3"/>
<Corner SeqID="6" CompoundMarkID="6" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="7" CompoundMarkID="7" Rounding="SP" ZoneSize="3"/>
<Corner SeqID="8" CompoundMarkID="8" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="9" CompoundMarkID="9" Rounding="SP" ZoneSize="3"/>
<Corner SeqID="10" CompoundMarkID="10" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="11" CompoundMarkID="11" Rounding="PS" ZoneSize="3"/>
</CompoundMarkSequence>
<CourseLimit>
<Limit SeqID="1" Lat="57.6739450" Lon="11.8417100"/>
<Limit SeqID="2" Lat="57.6709520" Lon="11.8485010"/>
<Limit SeqID="3" Lat="57.6690260" Lon="11.8472790"/>
<Limit SeqID="4" Lat="57.6693140" Lon="11.8457610"/>
<Limit SeqID="5" Lat="57.6665370" Lon="11.8432910"/>
<Limit SeqID="6" Lat="57.6641400" Lon="11.8385840"/>
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030"/>
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660"/>
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920"/>
<Limit SeqID="10" Lat="57.6708220" Lon="11.8321340"/>
</CourseLimit>
</Race>
+4 -2
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Race>
<CreationTimeDate>2015-08-29T13:12:40+02:00</CreationTimeDate>
<CreationTimeDate>2015-08-29T11:27:15+02:00</CreationTimeDate>
<RaceStartTime Start="2015-08-29T13:10:00+02:00" Postpone="False" />
<RaceID>15082901</RaceID>
<RaceType>Fleet</RaceType>
@@ -80,6 +80,8 @@
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030" />
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660" />
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920" />
<Limit SeqID="10" Lat="57.6708220" Lon="11.8321340" />
<Limit SeqID="10" Lat="57.6692230" Lon="11.8231430" />
<Limit SeqID="11" Lat="57.6725370" Lon="11.8272480" />
<Limit SeqID="12" Lat="57.6708220" Lon="11.8321340" />
</CourseLimit>
</Race>
@@ -8,6 +8,7 @@ import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;
import seng302.models.parsers.packets.StreamPacket;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;