Merge branch 'splitIntoTwoModules' of https://eng-git.canterbury.ac.nz/seng302-2017/team-7 into splitIntoTwoModules

main
Erika Savell 9 years ago
commit 984617ce57

@ -49,4 +49,7 @@ public class MarkRounding extends AC35Data{
this.markID = markID; this.markID = markID;
} }
public int getSourceID() {
return sourceID;
}
} }

@ -3,6 +3,7 @@ package seng302.Controllers;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import seng302.RaceDataSource; import seng302.RaceDataSource;
import seng302.VisualiserInput;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -16,8 +17,8 @@ public class MainController extends Controller {
@FXML @FXML
RaceController raceController; RaceController raceController;
public void beginRace(int scaleFactor, RaceDataSource raceData) { public void beginRace(VisualiserInput visualiserInput) {
raceController.startRace(scaleFactor, raceData); raceController.startRace(visualiserInput);
} }

@ -13,6 +13,7 @@ import seng302.Mock.StreamedRace;
import seng302.Model.*; import seng302.Model.*;
import seng302.RaceDataSource; import seng302.RaceDataSource;
import seng302.RaceXMLReader; import seng302.RaceXMLReader;
import seng302.VisualiserInput;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException; import java.io.IOException;
@ -114,13 +115,13 @@ public class RaceController extends Controller {
* Initializes and runs the race, based on the user's chosen scale factor * Initializes and runs the race, based on the user's chosen scale factor
* Currently uses an example racecourse * Currently uses an example racecourse
* *
* @param scaleFactor scale value of race * @param visualiserInput
*/ */
public void startRace(int scaleFactor, RaceDataSource raceData) { public void startRace(VisualiserInput visualiserInput) {
StreamedRace newRace = new StreamedRace(raceData, this, scaleFactor); StreamedRace newRace = new StreamedRace(visualiserInput, this);
//newRace.initialiseBoats(); //newRace.initialiseBoats();
raceMap = new ResizableRaceCanvas(raceData); raceMap = new ResizableRaceCanvas(visualiserInput.getCourse());
raceMap.setMouseTransparent(true); raceMap.setMouseTransparent(true);
raceMap.widthProperty().bind(canvasBase.widthProperty()); raceMap.widthProperty().bind(canvasBase.widthProperty());
raceMap.heightProperty().bind(canvasBase.heightProperty()); raceMap.heightProperty().bind(canvasBase.heightProperty());
@ -133,8 +134,8 @@ public class RaceController extends Controller {
//Initialize save annotation array, fps listener, and annotation listeners //Initialize save annotation array, fps listener, and annotation listeners
//timezone //timezone
RaceClock raceClock = new RaceClock(raceData.getZonedDateTime()); // RaceClock raceClock = new RaceClock(visualiserInput.getCourse().getZonedDateTime());
timeZone.setText(raceClock.getTimeZone()); // timeZone.setText(raceClock.getTimeZone());
initializeFPS(); initializeFPS();
initializeAnnotations(); initializeAnnotations();

@ -21,6 +21,8 @@ import seng302.RaceDataSource;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.text.ParseException; import java.text.ParseException;
import java.util.List; import java.util.List;
@ -53,6 +55,8 @@ public class StartController extends Controller implements Observer {
private StreamedCourse raceData; private StreamedCourse raceData;
private long timeLeft = 1; private long timeLeft = 1;
private VisualiserInput visualiserInput;
/** /**
* Begins the race with a scale factor of 15 * Begins the race with a scale factor of 15
*/ */
@ -88,7 +92,7 @@ public class StartController extends Controller implements Observer {
try { try {
raceData = new StreamedCourse(); raceData = new StreamedCourse();
raceData.addObserver(this); raceData.addObserver(this);
VisualiserInput visualiserInput = new VisualiserInput(raceData); visualiserInput = new VisualiserInput(new Socket("livedata.americascup.com", 4941), raceData);
new Thread(visualiserInput).start(); new Thread(visualiserInput).start();
// StreamedCourse streamedCourse = new StreamedCourse(new BoatXMLReader("mockXML/boatXML/boatTest.xml")); // StreamedCourse streamedCourse = new StreamedCourse(new BoatXMLReader("mockXML/boatXML/boatTest.xml"));
// streamedCourse.setStreamedCourseXMLReader(new StreamedCourseXMLReader("mockXML/raceXML/raceTest.xml")); // streamedCourse.setStreamedCourseXMLReader(new StreamedCourseXMLReader("mockXML/raceXML/raceTest.xml"));
@ -150,7 +154,7 @@ public class StartController extends Controller implements Observer {
if (timeLeft <= 0) { if (timeLeft <= 0) {
updateTime("Race is starting..."); updateTime("Race is starting...");
stop(); stop();
parent.beginRace(scaleFactor, raceData); parent.beginRace(visualiserInput);
startWrapper.setVisible(false); startWrapper.setVisible(false);
} else { } else {

@ -80,12 +80,15 @@ public class StreamedCourseXMLReader extends XMLReader {
private void readRace() throws ParseException { private void readRace() throws ParseException {
DateTimeFormatter dateFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME; DateTimeFormatter dateFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
Element settings = (Element) doc.getElementsByTagName("Race").item(0); Element settings = (Element) doc.getElementsByTagName("Race").item(0);
NamedNodeMap raceTimeTag = doc.getElementsByTagName("RaceStartTime").item(0).getAttributes();
if (raceTimeTag.getNamedItem("Time") != null) dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
System.out.println(getTextValueOfNode(settings, "CreationTimeDate"));
raceID = Integer.parseInt(getTextValueOfNode(settings, "RaceID")); raceID = Integer.parseInt(getTextValueOfNode(settings, "RaceID"));
raceType = getTextValueOfNode(settings, "RaceType"); raceType = getTextValueOfNode(settings, "RaceType");
creationTimeDate = ZonedDateTime.parse(getTextValueOfNode(settings, "CreationTimeDate"), dateFormat); creationTimeDate = ZonedDateTime.parse(getTextValueOfNode(settings, "CreationTimeDate"), dateFormat);
NamedNodeMap raceTimeTag = doc.getElementsByTagName("RaceStartTime").item(0).getAttributes();
if (raceTimeTag.getNamedItem("Time") != null) raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Time").getTextContent(), dateFormat); if (raceTimeTag.getNamedItem("Time") != null) raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Time").getTextContent(), dateFormat);
else raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Start").getTextContent(), dateFormat); else raceStartTime = ZonedDateTime.parse(raceTimeTag.getNamedItem("Start").getTextContent(), dateFormat);
postpone = Boolean.parseBoolean(raceTimeTag.getNamedItem("Postpone").getTextContent()); postpone = Boolean.parseBoolean(raceTimeTag.getNamedItem("Postpone").getTextContent());
@ -180,10 +183,11 @@ public class StreamedCourseXMLReader extends XMLReader {
private void readCompoundMarkSequence() throws StreamedCourseXMLException { private void readCompoundMarkSequence() throws StreamedCourseXMLException {
Element nCompoundMarkSequence = (Element) doc.getElementsByTagName("CompoundMarkSequence").item(0); Element nCompoundMarkSequence = (Element) doc.getElementsByTagName("CompoundMarkSequence").item(0);
NodeList nCorners = nCompoundMarkSequence.getElementsByTagName("Corner"); NodeList nCorners = nCompoundMarkSequence.getElementsByTagName("Corner");
Marker lastMarker = getMarker(getCompoundMarkID((Element)nCorners.item(0))); Element markXML = (Element)nCorners.item(0);
String legName = getCompoundMarkName(getCompoundMarkID((Element)nCorners.item(0))); Marker lastMarker = getMarker(getCompoundMarkID(markXML));
String legName = getCompoundMarkName(getCompoundMarkID(markXML));
for(int i = 1; i < nCorners.getLength(); i++) { for(int i = 1; i < nCorners.getLength(); i++) {
Element markXML = (Element)nCorners.item(i); markXML = (Element)nCorners.item(i);
Marker currentMarker = getMarker(getCompoundMarkID(markXML)); Marker currentMarker = getMarker(getCompoundMarkID(markXML));
legs.add(new Leg(legName, lastMarker, currentMarker, i-1)); legs.add(new Leg(legName, lastMarker, currentMarker, i-1));
lastMarker = currentMarker; lastMarker = currentMarker;

@ -6,7 +6,13 @@ import seng302.Constants;
import seng302.Controllers.RaceController; import seng302.Controllers.RaceController;
import seng302.GPSCoordinate; import seng302.GPSCoordinate;
import seng302.Model.*; import seng302.Model.*;
import seng302.Networking.MessageDecoders.BoatLocationDecoder;
import seng302.Networking.Utils.BoatStatusMessage;
import seng302.Networking.Utils.ByteConverter;
import seng302.Networking.Utils.Enums.BoatStatus;
import seng302.Networking.Utils.BoatLocationMessage;
import seng302.RaceDataSource; import seng302.RaceDataSource;
import seng302.VisualiserInput;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.util.*; import java.util.*;
@ -15,12 +21,12 @@ import java.util.*;
* Created by jjg64 on 21/04/17. * Created by jjg64 on 21/04/17.
*/ */
public class StreamedRace extends Race { public class StreamedRace extends Race {
private RaceDataSource raceData; private VisualiserInput visualiserInput;
private double MMPS_TO_KN = 0.001944;
public StreamedRace(RaceDataSource raceData, RaceController controller, int scaleFactor) { public StreamedRace(VisualiserInput visualiserInput, RaceController controller) {
super(raceData.getBoats(), raceData.getLegs(), controller, scaleFactor); super(visualiserInput.getCourse(), controller, 1);
this.raceData = raceData; this.visualiserInput = visualiserInput;
this.scaleFactor = 1; // There will be no scaling in a live streamed race
} }
public void initialiseBoats() { public void initialiseBoats() {
@ -48,18 +54,26 @@ public class StreamedRace extends Race {
} }
/** /**
* Checks the position of the boat, this updates the boats current position. * Checks the position of the boat.
* *
* @param boat Boat that the position is to be updated for. * @param boat Boat that the position is to be updated for.
* @param timeElapsed Time that has elapse since the start of the the race. * @param timeElapsed Time that has elapse since the start of the the race.
* @see BoatInRace * @see BoatInRace
*/ */
protected void checkPosition(Boat boat, long timeElapsed) { protected void checkPosition(Boat boat, long timeElapsed) {
if (boat.getCurrentLeg().getName().toLowerCase().contains("finish")) { StreamedCourse raceData = visualiserInput.getCourse();
//boat has finished BoatStatusMessage boatStatusMessage = visualiserInput.getBoatStatus().get(boat.getSourceID());
BoatStatus boatStatus = BoatStatus.valueOf(boatStatusMessage.getBoatStatus());
int legNumber = boatStatusMessage.getLegNumber();
if (boatStatus == BoatStatus.DNF) {
boat.setDnf(true);
} else if (boatStatus == BoatStatus.FINISHED || legNumber > raceData.getLegs().size()) {
boatsFinished++; boatsFinished++;
boat.setFinished(true);
boat.setTimeFinished(timeElapsed); boat.setTimeFinished(timeElapsed);
boat.setFinished(true);
} else {
boat.setCurrentLeg(raceData.getLegs().get(legNumber));
} }
//Update the boat display table in the GUI to reflect the leg change //Update the boat display table in the GUI to reflect the leg change
updatePositions(); updatePositions();
@ -72,8 +86,16 @@ public class StreamedRace extends Race {
* @param millisecondsElapsed time since last update * @param millisecondsElapsed time since last update
*/ */
protected void updatePosition(Boat boat, int millisecondsElapsed) { protected void updatePosition(Boat boat, int millisecondsElapsed) {
//TODO Grab info from network int sourceID = boat.getSourceID();
// setPosition(boat, coordinate); BoatLocationMessage boatLocationMessage = visualiserInput.getBoatLocationMessage(sourceID);
if(boatLocationMessage != null) {
System.out.println(sourceID);
double lat = boatLocationMessage.getLatitudeDouble();
double lon = boatLocationMessage.getLongitudeDouble();
boat.setCurrentPosition(new GPSCoordinate(lat, lon));
boat.setHeading(boatLocationMessage.getHeadingDegrees());
boat.setVelocity(boatLocationMessage.getBoatSpeed() * MMPS_TO_KN);
}
} }
protected void setPosition(Boat boat, GPSCoordinate coordinate) { protected void setPosition(Boat boat, GPSCoordinate coordinate) {

@ -27,6 +27,7 @@ public class Boat {
protected long timeFinished; protected long timeFinished;
protected StringProperty position; protected StringProperty position;
protected boolean started = false; protected boolean started = false;
protected boolean dnf = false;
private double wakeScale = 1 / 50; private double wakeScale = 1 / 50;
private int sourceID; private int sourceID;
@ -234,4 +235,12 @@ public class Boat {
public int getSourceID() { public int getSourceID() {
return this.sourceID; return this.sourceID;
} }
public boolean isDnf() {
return dnf;
}
public void setDnf(boolean dnf) {
this.dnf = dnf;
}
} }

@ -9,6 +9,7 @@ import org.geotools.referencing.GeodeticCalculator;
import seng302.Controllers.RaceController; import seng302.Controllers.RaceController;
import seng302.GPSCoordinate; import seng302.GPSCoordinate;
import seng302.RaceDataSource; import seng302.RaceDataSource;
import seng302.VisualiserInput;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.util.ArrayList; import java.util.ArrayList;
@ -31,7 +32,7 @@ public abstract class Race implements Runnable {
protected int scaleFactor; protected int scaleFactor;
protected int PRERACE_TIME = 120000; //time in milliseconds to pause during pre-race protected int PRERACE_TIME = 0; //time in milliseconds to pause during pre-race
private boolean timerEnabled = true; //boolean to determine if timer is ran private boolean timerEnabled = true; //boolean to determine if timer is ran
/** /**
@ -69,6 +70,10 @@ public abstract class Race implements Runnable {
this(Arrays.asList(startingBoats), legs, controller, scaleFactor); this(Arrays.asList(startingBoats), legs, controller, scaleFactor);
} }
public void setController(RaceController controller) {
this.controller = controller;
}
public abstract void initialiseBoats(); public abstract void initialiseBoats();
/** /**

@ -1,4 +1,5 @@
package seng302; package seng302;
import org.opengis.style.Mark;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import seng302.Mock.*; import seng302.Mock.*;
import seng302.Networking.BinaryMessageDecoder; import seng302.Networking.BinaryMessageDecoder;
@ -41,14 +42,23 @@ public class VisualiserInput implements Runnable
private Map<Integer, BoatStatusMessage> boatStatus; private Map<Integer, BoatStatusMessage> boatStatus;
public VisualiserInput(StreamedCourse course) throws IOException{ private AverageWind averageWind;
this.connectionSocket = new Socket(InetAddress.getLocalHost(), 4942); private CourseWinds courseWinds;
private Map<Integer, MarkRounding> markRounding;
private RaceStartStatus raceStartStatus;
public VisualiserInput(Socket socket, StreamedCourse course) throws IOException{
this.connectionSocket = socket;
// this.connectionSocket = new Socket("livedata.americascup.com",4941); // this.connectionSocket = new Socket("livedata.americascup.com",4941);
this.course = course; this.course = course;
this.boatLocation = new HashMap<>(); this.boatLocation = new HashMap<>();
this.boatStatus = new HashMap<>(); this.boatStatus = new HashMap<>();
this.markRounding = new HashMap<>();
//start Time //start Time
@ -106,6 +116,30 @@ public class VisualiserInput implements Runnable
return boatStatus; return boatStatus;
} }
/**
* Returns the average wind of the race
* @return average wind in the race
*/
public AverageWind getAverageWind() {
return averageWind;
}
/**
* Returns winds in the course
* @return winds that are in the course
*/
public CourseWinds getCourseWinds() {
return courseWinds;
}
/**
* Returns get Mark Rounding Boat Source ID, MarkRound
* @return
*/
public Map<Integer, MarkRounding> getMarkRounding() {
return markRounding;
}
/** /**
* Takes an inputStream and reads the first 15 bytes (the header) and gets the message length * Takes an inputStream and reads the first 15 bytes (the header) and gets the message length
* for the whole message then reads that and returns the byte array * for the whole message then reads that and returns the byte array
@ -154,7 +188,7 @@ public class VisualiserInput implements Runnable
lastHeartbeatTime = System.currentTimeMillis(); lastHeartbeatTime = System.currentTimeMillis();
//note: if the program runs for over 340 years, this will crash. //note: if the program runs for over 340 years, this will crash.
heartbeatSeqNum = ByteConverter.bytesToLong(testDecoder.getMessage()); heartbeatSeqNum = ByteConverter.bytesToLong(testDecoder.getMessage());
System.out.println("HeartBeat Message! " + heartbeatSeqNum); // System.out.println("HeartBeat Message! " + heartbeatSeqNum);
break; break;
case RACESTATUS: case RACESTATUS:
System.out.println("Race Status Message"); System.out.println("Race Status Message");
@ -193,6 +227,8 @@ public class VisualiserInput implements Runnable
break; break;
case RACESTARTSTATUS: case RACESTARTSTATUS:
//System.out.println("Race Start Status Message"); //System.out.println("Race Start Status Message");
RaceStartStatus rSS = (RaceStartStatus) data;
raceStartStatus = rSS;
break; break;
case YACHTEVENTCODE: case YACHTEVENTCODE:
// System.out.println("Yacht Action Code!"); // System.out.println("Yacht Action Code!");
@ -207,6 +243,7 @@ public class VisualiserInput implements Runnable
//no decoder //no decoder
break; break;
case BOATLOCATION: case BOATLOCATION:
System.out.println("Boat Location!");
BoatLocationMessage msg = (BoatLocationMessage) data; BoatLocationMessage msg = (BoatLocationMessage) data;
if (boatLocation.containsKey(msg.getSourceID())){ if (boatLocation.containsKey(msg.getSourceID())){
if (msg.getTime() > boatLocation.get(msg.getSourceID()).getTime()){ if (msg.getTime() > boatLocation.get(msg.getSourceID()).getTime()){
@ -219,12 +256,17 @@ public class VisualiserInput implements Runnable
break; break;
case MARKROUNDING: case MARKROUNDING:
// System.out.println("Mark Rounding Message!"); // System.out.println("Mark Rounding Message!");
MarkRounding mkrounding = (MarkRounding) data;
markRounding.put(mkrounding.getSourceID(), mkrounding);
break; break;
case COURSEWIND: case COURSEWIND:
// System.out.println("Course Wind Message!"); // System.out.println("Course Wind Message!");
courseWinds = (CourseWinds) data;
break; break;
case AVGWIND: case AVGWIND:
// System.out.println("Average Wind Message!"); // System.out.println("Average Wind Message!");
AverageWind avgWind = (AverageWind) data;
averageWind = avgWind;
break; break;
default: default:
System.out.println("Broken Message!"); System.out.println("Broken Message!");
@ -245,7 +287,8 @@ public class VisualiserInput implements Runnable
public static void main(String argv[]) throws Exception public static void main(String argv[]) throws Exception
{ {
VisualiserInput receiver = new VisualiserInput(new StreamedCourse()); Socket socket = new Socket(InetAddress.getLocalHost(), 4942);
VisualiserInput receiver = new VisualiserInput(socket, new StreamedCourse());
receiver.run(); receiver.run();
} }

@ -76,7 +76,9 @@ public class StreamedRaceTest {
"M2", "M2",
"Gate" "Gate"
}; };
for(int i = 0; i < legs.size(); i++) assertEquals(expectedNames[i], legs.get(i).getName()); for(int i = 0; i < legs.size(); i++) {
assertEquals(expectedNames[i], legs.get(i).getName());
}
} }
/** /**

Loading…
Cancel
Save