Created a simple red blink on a top of a yacht given source id.

Created and updated methods reading yacht event packet to translate to collision alert on visualiser.
WIP: sending yacht event packet to inform collision

#story[1117]
This commit is contained in:
Zhi You Tan
2017-08-09 01:26:59 +12:00
parent 5937f8b640
commit 8813d06010
5 changed files with 257 additions and 122 deletions
@@ -0,0 +1,34 @@
package seng302.model.stream.parser;
/**
* Stores parsed data from yacht event code packet
*/
public class YachtEventData {
private Long subjectId;
private Long incidentId;
private Integer eventId;
private Long timeStamp;
public YachtEventData(Long subjectId, Long incidentId, Integer eventId, Long timeStamp) {
this.subjectId = subjectId;
this.incidentId = incidentId;
this.eventId = eventId;
this.timeStamp = timeStamp;
}
public Long getSubjectId() {
return subjectId;
}
public Long getIncidentId() {
return incidentId;
}
public Integer getEventId() {
return eventId;
}
public Long getTimeStamp() {
return timeStamp;
}
}
@@ -13,15 +13,12 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.parser.MarkRoundingData; import seng302.model.stream.parser.*;
import seng302.model.stream.parser.PositionUpdateData;
import seng302.model.stream.parser.PositionUpdateData.DeviceType; import seng302.model.stream.parser.PositionUpdateData.DeviceType;
import seng302.model.stream.parser.RaceStartData;
import seng302.model.stream.parser.RaceStatusData;
/** /**
* StreamParser is a utilities class for taking byte data, formatted according to the AC35 * StreamParser is a utilities class for taking byte data, formatted according to the AC35 streaming
* streaming protocol, and parsing it into basic data types or collections. * protocol, and parsing it into basic data types or collections.
* *
* Created by kre39 on 23/04/17. * Created by kre39 on 23/04/17.
*/ */
@@ -34,8 +31,9 @@ public class StreamParser {
* @return the packet sequence number if the packet is of type HEARTBEAT, null otherwise. * @return the packet sequence number if the packet is of type HEARTBEAT, null otherwise.
*/ */
public static Long extractHeartBeat(StreamPacket packet) { public static Long extractHeartBeat(StreamPacket packet) {
if (packet.getType() != PacketType.HEARTBEAT) if (packet.getType() != PacketType.HEARTBEAT) {
return null; return null;
}
long heartbeat = bytesToLong(packet.getPayload()); long heartbeat = bytesToLong(packet.getPayload());
System.out.println("heartbeat = " + heartbeat); System.out.println("heartbeat = " + heartbeat);
return heartbeat; return heartbeat;
@@ -52,16 +50,17 @@ public class StreamParser {
* containing the parsed packet data. * containing the parsed packet data.
*/ */
public static RaceStatusData extractRaceStatus(StreamPacket packet) { public static RaceStatusData extractRaceStatus(StreamPacket packet) {
if (packet.getType() != PacketType.RACE_STATUS) if (packet.getType() != PacketType.RACE_STATUS) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11)); long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11));
int raceStatus = payload[11]; int raceStatus = payload[11];
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18)); long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload, 12, 18));
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20));
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22)); long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22));
// DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); // DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
// currentTime = format.format((new Date(currentTime))) // currentTime = format.format((new Date(currentTime)))
@@ -70,7 +69,6 @@ public class StreamParser {
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
); );
// long timeTillStart = // long timeTillStart =
// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000; // ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
// //
@@ -110,7 +108,7 @@ public class StreamParser {
// boat.setEstimateTimeAtFinish(estTimeAtFinish); // boat.setEstimateTimeAtFinish(estTimeAtFinish);
data.addBoatData(boatID, estTimeAtNextMark, estTimeAtFinish, leg, boatStatus); data.addBoatData(boatID, estTimeAtNextMark, estTimeAtFinish, leg, boatStatus);
} }
return data; return data;
} }
// private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){ // private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){
@@ -139,8 +137,9 @@ public class StreamParser {
* DISPLAY_TEXT_MESSAGE. * DISPLAY_TEXT_MESSAGE.
*/ */
public static List<String> extractDisplayMessage(StreamPacket packet) { public static List<String> extractDisplayMessage(StreamPacket packet) {
if (packet.getType() != PacketType.DISPLAY_TEXT_MESSAGE) if (packet.getType() != PacketType.DISPLAY_TEXT_MESSAGE) {
return null; return null;
}
List<String> message = new ArrayList<>(); List<String> message = new ArrayList<>();
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
@@ -166,10 +165,11 @@ public class StreamParser {
* XML_MESSAGE. * XML_MESSAGE.
*/ */
public static Document extractXmlMessage(StreamPacket packet) { public static Document extractXmlMessage(StreamPacket packet) {
if ( packet.getType() != PacketType.RACE_XML && if (packet.getType() != PacketType.RACE_XML &&
packet.getType() != PacketType.REGATTA_XML && packet.getType() != PacketType.REGATTA_XML &&
packet.getType() != PacketType.BOAT_XML ) packet.getType() != PacketType.BOAT_XML) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageType = payload[9]; int messageType = payload[9];
@@ -194,8 +194,8 @@ public class StreamParser {
* Extracts the race start status from the packet and returns it as a long array. * Extracts the race start status from the packet and returns it as a long array.
* *
* @param packet Packet parsed in to use the payload * @param packet Packet parsed in to use the payload
* @return An array of form [raceID, raceStartTime, notificationType, timeStamp] or null if * @return An array of form [raceID, raceStartTime, notificationType, timeStamp] or null if the
* the packet type is not of RACE_START_STATUS. * packet type is not of RACE_START_STATUS.
*/ */
public static RaceStartData extractRaceStartStatus(StreamPacket packet) { public static RaceStartData extractRaceStartStatus(StreamPacket packet) {
if (packet.getType() != PacketType.RACE_START_STATUS) { if (packet.getType() != PacketType.RACE_START_STATUS) {
@@ -212,23 +212,25 @@ public class StreamParser {
/** /**
* Parses the the byte array in a StreamPacket for yacht events to retrieve the necessary info * Parses the the byte array in a StreamPacket for yacht events to retrieve the necessary info
* and returns it a an array of longs. * and returns it as YachtEventData.
* *
* @param packet Packet parsed in to use the payload * @param packet Packet parsed in to use the payload
* @return the event data in the form [boatID, incidentID, eventID, timeStamp]. Returns null if * @return the event data in the form of YachtEventData. Returns null if the packet is not of
* the packet is not of type YACHT_EVENT_CODE. * type YACHT_EVENT_CODE.
*/ */
public static long[] extractYachtEventCode(StreamPacket packet) { public static YachtEventData extractYachtEventCode(StreamPacket packet) {
if (packet.getType() != PacketType.YACHT_EVENT_CODE) if (packet.getType() != PacketType.YACHT_EVENT_CODE) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
long ackNumber = bytesToLong(Arrays.copyOfRange(payload, 7, 9));
long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21)); long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21));
int eventId = payload[21]; int eventId = payload[21];
return new long[] {subjectId, incidentId, eventId, timeStamp}; return new YachtEventData(subjectId, incidentId, eventId, timeStamp);
} }
/** /**
@@ -239,15 +241,16 @@ public class StreamParser {
* Returns null if the packet is not of type YACHT_ACTION_CODE. * Returns null if the packet is not of type YACHT_ACTION_CODE.
*/ */
public static long[] extractYachtActionCode(StreamPacket packet) { public static long[] extractYachtActionCode(StreamPacket packet) {
if (packet.getType() != PacketType.YACHT_ACTION_CODE) if (packet.getType() != PacketType.YACHT_ACTION_CODE) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
int eventId = payload[17]; int eventId = payload[17];
return new long[] {subjectId, incidentId, eventId, timeStamp}; return new long[]{subjectId, incidentId, eventId, timeStamp};
} }
/** /**
@@ -258,8 +261,9 @@ public class StreamParser {
* CHATTER_TEXT. * CHATTER_TEXT.
*/ */
public static String extractChatterText(StreamPacket packet) { public static String extractChatterText(StreamPacket packet) {
if (packet.getType() != PacketType.CHATTER_TEXT) if (packet.getType() != PacketType.CHATTER_TEXT) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
int messageType = payload[1]; int messageType = payload[1];
@@ -276,8 +280,9 @@ public class StreamParser {
* is not of type BOAT_LOCATION. * is not of type BOAT_LOCATION.
*/ */
public static PositionUpdateData extractBoatLocation(StreamPacket packet) { public static PositionUpdateData extractBoatLocation(StreamPacket packet) {
if (packet.getType() != PacketType.BOAT_LOCATION) if (packet.getType() != PacketType.BOAT_LOCATION) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int deviceType = (int) payload[15]; int deviceType = (int) payload[15];
long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
@@ -293,10 +298,11 @@ public class StreamParser {
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0; double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0;
DeviceType type; DeviceType type;
if (deviceType == 1) if (deviceType == 1) {
type = DeviceType.YACHT_TYPE; type = DeviceType.YACHT_TYPE;
else } else {
type = DeviceType.MARK_TYPE; type = DeviceType.MARK_TYPE;
}
return new PositionUpdateData((int) boatId, type, lat, lon, heading, groundSpeed); return new PositionUpdateData((int) boatId, type, lat, lon, heading, groundSpeed);
} }
@@ -309,8 +315,9 @@ public class StreamParser {
* if packet is not of type MARK_ROUNDING. * if packet is not of type MARK_ROUNDING.
*/ */
public static MarkRoundingData extractMarkRounding(StreamPacket packet) { public static MarkRoundingData extractMarkRounding(StreamPacket packet) {
if (packet.getType() != PacketType.MARK_ROUNDING) if (packet.getType() != PacketType.MARK_ROUNDING) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
@@ -325,16 +332,17 @@ public class StreamParser {
} }
/** /**
* Returns a list containing the string value of data within the given stream packet for * Returns a list containing the string value of data within the given stream packet for course
* course wind. * wind.
* *
* @param packet The packet containing the payload * @param packet The packet containing the payload
* @return the string values of the wind packet. Returns null if the packet is not of type * @return the string values of the wind packet. Returns null if the packet is not of type
* COURSE_WIND. * COURSE_WIND.
*/ */
public static List<String> extractCourseWind(StreamPacket packet) { public static List<String> extractCourseWind(StreamPacket packet) {
if (packet.getType() != PacketType.COURSE_WIND) if (packet.getType() != PacketType.COURSE_WIND) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
int selectedWindId = payload[1]; int selectedWindId = payload[1];
@@ -366,13 +374,13 @@ public class StreamParser {
* Returns the parsed data from a StreamPacket for average wind data. * Returns the parsed data from a StreamPacket for average wind data.
* *
* @param packet The packet containing the payload * @param packet The packet containing the payload
* @return The wind data in the form * @return The wind data in the form [rawPeriod, rawSamplePeriod, period2, speed2, period3,
* [rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timestamp] * speed3, period4, speed4, timestamp] or null if the packet is not of type AVG_WIND.
* or null if the packet is not of type AVG_WIND.
*/ */
public static long[] extractAvgWind(StreamPacket packet) { public static long[] extractAvgWind(StreamPacket packet) {
if (packet.getType() != PacketType.AVG_WIND) if (packet.getType() != PacketType.AVG_WIND) {
return null; return null;
}
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
@@ -384,7 +392,7 @@ public class StreamParser {
long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19)); long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19));
long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21)); long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21));
long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23)); long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23));
return new long[] { return new long[]{
rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timeStamp rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timeStamp
}; };
} }
@@ -410,8 +418,7 @@ public class StreamParser {
} }
/** /**
* takes an array of up to 7 bytes and returns a positive * takes an array of up to 7 bytes and returns a positive long constructed from the input bytes
* long constructed from the input bytes
* *
* @param bytes the byte array to conver to Long * @param bytes the byte array to conver to Long
* @return a positive long if there is less than 7 bytes -1 otherwise * @return a positive long if there is less than 7 bytes -1 otherwise
@@ -20,6 +20,7 @@ import seng302.model.stream.parser.MarkRoundingData;
import seng302.model.stream.parser.PositionUpdateData; import seng302.model.stream.parser.PositionUpdateData;
import seng302.model.stream.parser.PositionUpdateData.DeviceType; import seng302.model.stream.parser.PositionUpdateData.DeviceType;
import seng302.model.stream.parser.RaceStatusData; import seng302.model.stream.parser.RaceStatusData;
import seng302.model.stream.parser.YachtEventData;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.gameServer.server.messages.BoatActionMessage; import seng302.gameServer.server.messages.BoatActionMessage;
@@ -117,7 +118,8 @@ public class GameClient {
* @return the lobby controller. * @return the lobby controller.
*/ */
private LobbyController loadLobby() { private LobbyController loadLobby() {
FXMLLoader fxmlLoader = new FXMLLoader(GameClient.class.getResource("/views/LobbyView.fxml")); FXMLLoader fxmlLoader = new FXMLLoader(
GameClient.class.getResource("/views/LobbyView.fxml"));
try { try {
holderPane.getChildren().clear(); holderPane.getChildren().clear();
holderPane.getChildren().add(fxmlLoader.load()); holderPane.getChildren().add(fxmlLoader.load());
@@ -200,13 +202,18 @@ public class GameClient {
case MARK_ROUNDING: case MARK_ROUNDING:
updateMarkRounding(StreamParser.extractMarkRounding(packet)); updateMarkRounding(StreamParser.extractMarkRounding(packet));
break; break;
case YACHT_EVENT_CODE:
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
break;
} }
} }
} }
private void startRaceIfAllDataReceived() { private void startRaceIfAllDataReceived() {
if (allXMLReceived() && raceView == null) if (allXMLReceived() && raceView == null) {
loadRaceView(); loadRaceView();
}
} }
private boolean allXMLReceived() { private boolean allXMLReceived() {
@@ -263,8 +270,9 @@ public class GameClient {
int placing = 1; int placing = 1;
for (Yacht otherYacht : allBoatsMap.values()) { for (Yacht otherYacht : allBoatsMap.values()) {
if (otherYacht.getSourceId() != boatData[0] && if (otherYacht.getSourceId() != boatData[0] &&
yacht.getLegNumber() <= otherYacht.getLegNumber()) yacht.getLegNumber() <= otherYacht.getLegNumber()) {
placing++; placing++;
}
} }
yacht.setPositionInteger(placing); yacht.setPositionInteger(placing);
} }
@@ -279,6 +287,7 @@ public class GameClient {
/** /**
* Handle the key-pressed event from the text field. * Handle the key-pressed event from the text field.
*
* @param e The key event triggering this call * @param e The key event triggering this call
*/ */
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
@@ -328,4 +337,14 @@ public class GameClient {
public RaceXMLData getCourseData() { public RaceXMLData getCourseData() {
return courseData; return courseData;
} }
/**
* Tells race view to show a collision animation.
*/
private void showCollisionAlert(YachtEventData yachtEventData) {
// 1 is used by team 28 to show collision
if (yachtEventData.getEventId() == 1) {
raceView.showCollision(yachtEventData.getSubjectId());
}
}
} }
+103 -48
View File
@@ -6,9 +6,14 @@ import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javafx.animation.Animation;
import javafx.animation.AnimationTimer; import javafx.animation.AnimationTimer;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.Node; import javafx.scene.Node;
@@ -17,8 +22,10 @@ import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Paint; import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon; import javafx.scene.shape.Polygon;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.util.Duration;
import seng302.model.Colors; import seng302.model.Colors;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.Limit; import seng302.model.Limit;
@@ -40,10 +47,10 @@ import seng302.visualiser.map.CanvasMap;
*/ */
public class GameView extends Pane { public class GameView extends Pane {
private double bufferSize = 50; private double bufferSize = 50;
private double panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias. private double panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias.
private double panelHeight = 960; private double panelHeight = 960;
private double canvasWidth = 1100; private double canvasWidth = 1100;
private double canvasHeight = 920; private double canvasHeight = 920;
private boolean horizontalInversion = false; private boolean horizontalInversion = false;
@@ -86,7 +93,7 @@ public class GameView extends Pane {
VERTICAL VERTICAL
} }
public GameView () { public GameView() {
gameObjects = this.getChildren(); gameObjects = this.getChildren();
// create image view for map, bind panel size to image // create image view for map, bind panel size to image
gameObjects.add(mapImage); gameObjects.add(mapImage);
@@ -99,7 +106,7 @@ public class GameView extends Pane {
initializeTimer(); initializeTimer();
} }
private void initializeTimer () { private void initializeTimer() {
Arrays.fill(frameTimes, 1_000_000_000 / 60); Arrays.fill(frameTimes, 1_000_000_000 / 60);
timer = new AnimationTimer() { timer = new AnimationTimer() {
private long lastTime = 0; private long lastTime = 0;
@@ -114,7 +121,8 @@ public class GameView extends Pane {
if (lastTime == 0) { if (lastTime == 0) {
lastTime = now; lastTime = now;
} else { } else {
if (now - lastTime >= (1e8 / 60)) { //Fix for framerate going above 60 when minimized if (now - lastTime >= (1e8
/ 60)) { //Fix for framerate going above 60 when minimized
long oldFrameTime = frameTimes[frameTimeIndex]; long oldFrameTime = frameTimes[frameTimeIndex];
frameTimes[frameTimeIndex] = now; frameTimes[frameTimeIndex] = now;
frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length; frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length;
@@ -142,8 +150,8 @@ public class GameView extends Pane {
} }
/** /**
* First find the top right and bottom left points' geo locations, then retrieve * First find the top right and bottom left points' geo locations, then retrieve map from google
* map from google to display on image view. - Haoming 22/5/2017 * to display on image view. - Haoming 22/5/2017
*/ */
private void drawGoogleMap() { private void drawGoogleMap() {
findMetersPerPixel(); findMetersPerPixel();
@@ -207,7 +215,7 @@ public class GameView extends Pane {
gates.add( gates.add(
makeAndBindGate( makeAndBindGate(
markerObjects.get(cMark.getSubMark(i)), markerObjects.get(cMark.getSubMark(i)),
markerObjects.get(cMark.getSubMark(i+1)), markerObjects.get(cMark.getSubMark(i + 1)),
colour colour
) )
); );
@@ -270,7 +278,7 @@ public class GameView extends Pane {
gate.endYProperty().bind( gate.endYProperty().bind(
m2.centerYProperty() m2.centerYProperty()
); );
return gate; return gate;
} }
/** /**
@@ -308,7 +316,8 @@ public class GameView extends Pane {
/** /**
* Draws all the boats. * Draws all the boats.
* @param yachts The yachts to set in the race *
* @param yachts The yachts to set in the race
*/ */
public void setBoats(List<Yacht> yachts) { public void setBoats(List<Yacht> yachts) {
BoatObject newBoat; BoatObject newBoat;
@@ -324,7 +333,7 @@ public class GameView extends Pane {
boatObjectGroup.getChildren().add(newBoat); boatObjectGroup.getChildren().add(newBoat);
trails.getChildren().add(newBoat.getTrail()); trails.getChildren().add(newBoat.getTrail());
// TODO: 1/08/17 Make this less vile to look at. // TODO: 1/08/17 Make this less vile to look at.
yacht.addLocationListener((boat, lat, lon, heading, velocity) ->{ yacht.addLocationListener((boat, lat, lon, heading, velocity) -> {
BoatObject bo = boatObjects.get(boat); BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon); Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity); bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity);
@@ -348,7 +357,7 @@ public class GameView extends Pane {
}); });
} }
private void createAndBindAnnotationBox (Yacht yacht, Paint colour) { private void createAndBindAnnotationBox(Yacht yacht, Paint colour) {
AnnotationBox newAnnotation = new AnnotationBox(); AnnotationBox newAnnotation = new AnnotationBox();
newAnnotation.setFill(colour); newAnnotation.setFill(colour);
newAnnotation.addAnnotation( newAnnotation.addAnnotation(
@@ -378,25 +387,25 @@ public class GameView extends Pane {
annotations.put(yacht, newAnnotation); annotations.put(yacht, newAnnotation);
} }
private void drawFps(Double fps){ private void drawFps(Double fps) {
Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps)))); Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps))));
} }
/** /**
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point * Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
* with the leftmost point, rightmost point, southern most point and northern most point * the leftmost point, rightmost point, southern most point and northern most point
* respectively. * respectively.
*/ */
private void findMinMaxPoint(List<GeoPoint> points) { private void findMinMaxPoint(List<GeoPoint> points) {
List<GeoPoint> sortedPoints = new ArrayList<>(points); List<GeoPoint> sortedPoints = new ArrayList<>(points);
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat)); sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng()); minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
GeoPoint maxLat = sortedPoints.get(sortedPoints.size()-1); GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng()); maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng)); sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng()); minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
GeoPoint maxLon = sortedPoints.get(sortedPoints.size()-1); GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng()); maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) { if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
horizontalInversion = true; horizontalInversion = true;
@@ -416,15 +425,19 @@ public class GameView extends Pane {
if (scaleDirection == ScaleDirection.HORIZONTAL) { if (scaleDirection == ScaleDirection.HORIZONTAL) {
referenceAngle = Math.abs( referenceAngle = Math.abs(
GeoUtility.getBearingRad(referencePoint, minLonPoint) GeoUtility.getBearingRad(referencePoint, minLonPoint)
); );
referencePointX = bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint); referencePointX =
bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
.getDistance(referencePoint, minLonPoint);
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint)); referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
referencePointY = canvasHeight - (bufferSize + bufferSize); referencePointY = canvasHeight - (bufferSize + bufferSize);
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint); referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
referencePointY = referencePointY / 2; .getDistance(referencePoint, maxLatPoint);
referencePointY = referencePointY / 2;
referencePointY += bufferSize; referencePointY += bufferSize;
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint); referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
.getDistance(referencePoint, maxLatPoint);
} else { } else {
referencePointY = canvasHeight - bufferSize; referencePointY = canvasHeight - bufferSize;
referenceAngle = Math.abs( referenceAngle = Math.abs(
@@ -432,11 +445,14 @@ public class GameView extends Pane {
GeoUtility.getDistance(referencePoint, minLonPoint) GeoUtility.getDistance(referencePoint, minLonPoint)
) )
); );
referencePointX = bufferSize; referencePointX = bufferSize;
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint); referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
referencePointX += ((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor)) / 2; .getDistance(referencePoint, minLonPoint);
referencePointX +=
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
/ 2;
} }
if(horizontalInversion) { if (horizontalInversion) {
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize); referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
} }
} }
@@ -449,12 +465,12 @@ public class GameView extends Pane {
private double scaleRaceExtremities() { private double scaleRaceExtremities() {
double vertAngle = Math.abs( double vertAngle = Math.abs(
GeoUtility.getBearingRad(minLatPoint, maxLatPoint) GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
); );
double vertDistance = double vertDistance =
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint); Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
double horiAngle = Math.abs( double horiAngle = Math.abs(
GeoUtility.getBearingRad(minLonPoint, maxLonPoint) GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
); );
if (horiAngle <= (Math.PI / 2)) { if (horiAngle <= (Math.PI / 2)) {
horiAngle = (Math.PI / 2) - horiAngle; horiAngle = (Math.PI / 2) - horiAngle;
@@ -480,36 +496,44 @@ public class GameView extends Pane {
return findScaledXY(unscaled.getLat(), unscaled.getLng()); return findScaledXY(unscaled.getLat(), unscaled.getLng());
} }
private Point2D findScaledXY (double unscaledLat, double unscaledLon) { private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
double distanceFromReference; double distanceFromReference;
double angleFromReference; double angleFromReference;
double xAxisLocation = referencePointX; double xAxisLocation = referencePointX;
double yAxisLocation = referencePointY; double yAxisLocation = referencePointY;
angleFromReference = GeoUtility.getBearingRad( angleFromReference = GeoUtility.getBearingRad(
minLatPoint, new GeoPoint(unscaledLat, unscaledLon) minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
); );
distanceFromReference = GeoUtility.getDistance( distanceFromReference = GeoUtility.getDistance(
minLatPoint, new GeoPoint(unscaledLat, unscaledLon) minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
); );
// System.out.println("distanceFromReference = " + distanceFromReference); // System.out.println("distanceFromReference = " + distanceFromReference);
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) { if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
xAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); xAxisLocation += Math
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); .round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
yAxisLocation -= Math
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
} else if (angleFromReference >= 0) { } else if (angleFromReference >= 0) {
angleFromReference = angleFromReference - Math.PI / 2; angleFromReference = angleFromReference - Math.PI / 2;
xAxisLocation += Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); xAxisLocation += Math
yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); .round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
yAxisLocation += Math
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) { } else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
angleFromReference = Math.abs(angleFromReference); angleFromReference = Math.abs(angleFromReference);
xAxisLocation -= Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); xAxisLocation -= Math
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); .round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
yAxisLocation -= Math
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
} else { } else {
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2; angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
xAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); xAxisLocation -= Math
yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); .round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
yAxisLocation += Math
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
} }
if(horizontalInversion) { if (horizontalInversion) {
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize); xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
} }
// System.out.println("yAxisLocation = " + yAxisLocation + " " + unscaledLat); // System.out.println("yAxisLocation = " + yAxisLocation + " " + unscaledLat);
@@ -538,7 +562,7 @@ public class GameView extends Pane {
metersPerPixelY = dVertical / dy; metersPerPixelY = dVertical / dy;
} }
public void setAnnotationVisibilities (boolean teamName, boolean velocity, boolean estTime, public void setAnnotationVisibilities(boolean teamName, boolean velocity, boolean estTime,
boolean legTime, boolean trail, boolean wake) { boolean legTime, boolean trail, boolean wake) {
for (BoatObject boatObject : boatObjects.values()) { for (BoatObject boatObject : boatObjects.values()) {
boatObject.setVisibility(teamName, velocity, estTime, legTime, trail, wake); boatObject.setVisibility(teamName, velocity, estTime, legTime, trail, wake);
@@ -551,25 +575,25 @@ public class GameView extends Pane {
} }
} }
public void setFPSVisibility (boolean visibility) { public void setFPSVisibility(boolean visibility) {
fpsDisplay.setVisible(visibility); fpsDisplay.setVisible(visibility);
} }
public void selectBoat (Yacht selectedYacht) { public void selectBoat(Yacht selectedYacht) {
boatObjects.forEach((boat, group) -> boatObjects.forEach((boat, group) ->
group.setIsSelected(boat == selectedYacht) group.setIsSelected(boat == selectedYacht)
); );
} }
public void pauseRace () { public void pauseRace() {
timer.stop(); timer.stop();
} }
public void startRace () { public void startRace() {
timer.start(); timer.start();
} }
public void setBoatAsPlayer (Yacht playerYacht) { public void setBoatAsPlayer(Yacht playerYacht) {
boatObjects.get(playerYacht).setAsPlayer(); boatObjects.get(playerYacht).setAsPlayer();
annotations.get(playerYacht).addAnnotation( annotations.get(playerYacht).addAnnotation(
"velocity", "velocity",
@@ -583,4 +607,35 @@ public class GameView extends Pane {
gameObjects.add(annotations.get(playerYacht)); gameObjects.add(annotations.get(playerYacht));
}); });
} }
/**
* Given yacht geopoint by race view controller, drawCollision will calculate canvas X and Y and
* display a flashing red circle on collision point.
*
* @param collisionPoint yacht collision point
*/
public void drawCollision(GeoPoint collisionPoint) {
System.out.println("ran");
Point2D point = findScaledXY(collisionPoint);
Circle circle = new Circle(point.getX(), point.getY(), 10.0, Color.RED);
gameObjects.add(circle);
Timeline timeline = new Timeline();
timeline.setCycleCount(1);
EventHandler<ActionEvent> blink = (ActionEvent event) -> {
if (circle.getFill() == Color.RED) {
circle.setFill(Color.TRANSPARENT);
} else {
circle.setFill(Color.RED);
}
System.out.println("beep boop");
};
KeyFrame keyframe = new KeyFrame(Duration.millis(200), blink);
timeline.getKeyFrames().add(keyframe);
timeline.play();
// gameObjects.remove(circle);
}
} }
@@ -100,7 +100,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView()); selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
} }
public void loadRace ( public void loadRace(
Map<Integer, Yacht> participants, RaceXMLData raceData, RaceState raceState, Yacht player Map<Integer, Yacht> participants, RaceXMLData raceData, RaceState raceState, Yacht player
) { ) {
this.participants = participants; this.participants = participants;
@@ -208,9 +208,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* Used to add any new yachts into the race that may have started late or not have had data received yet * Used to add any new yachts into the race that may have started late or not have had data
* received yet
*/ */
private void updateSparkLine(){ private void updateSparkLine() {
// TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed. // TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed.
// Collect the racing yachts that aren't already in the chart // Collect the racing yachts that aren't already in the chart
sparkLineData.clear(); sparkLineData.clear();
@@ -228,14 +229,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
1.0 + participants.size() - yacht.getPositionInteger() 1.0 + participants.size() - yacht.getPositionInteger()
) )
); );
sparkLineData.add(yachtData); sparkLineData.add(yachtData);
}); });
// Lambda function to sort the series in order of leg (later legs shown more to the right) // Lambda function to sort the series in order of leg (later legs shown more to the right)
sparkLineData.sort((o1, o2) -> { sparkLineData.sort((o1, o2) -> {
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue()); Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size() - 1).getXValue());
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue()); Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size() - 1).getXValue());
if (leg2 < leg1){ if (leg2 < leg1) {
return 1; return 1;
} else { } else {
return -1; return -1;
@@ -248,7 +249,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
.filter(spark -> !raceSparkLine.getData().contains(spark)) .filter(spark -> !raceSparkLine.getData().contains(spark))
.forEach(spark -> { .forEach(spark -> {
raceSparkLine.getData().add(spark); raceSparkLine.getData().add(spark);
spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName())); spark.getNode().lookup(".chart-series-line")
.setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
}); });
}); });
} }
@@ -260,10 +262,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* Updates the yachts sparkline of the desired yacht and using the new leg number * Updates the yachts sparkline of the desired yacht and using the new leg number
*
* @param yacht The yacht to be updated on the sparkline * @param yacht The yacht to be updated on the sparkline
* @param legNumber the leg number that the position will be assigned to * @param legNumber the leg number that the position will be assigned to
*/ */
void updateYachtPositionSparkline(Yacht yacht, Integer legNumber){ void updateYachtPositionSparkline(Yacht yacht, Integer legNumber) {
for (XYChart.Series<String, Double> positionData : sparkLineData) { for (XYChart.Series<String, Double> positionData : sparkLineData) {
positionData.getData().add( positionData.getData().add(
new Data<>( new Data<>(
@@ -284,26 +287,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* gets the rgb string of the yachts colour to use for the chart via css * gets the rgb string of the yachts colour to use for the chart via css
*
* @param yachtId id of yacht passed in to get the yachts colour * @param yachtId id of yacht passed in to get the yachts colour
* @return the colour as an rgb string * @return the colour as an rgb string
*/ */
private String getBoatColorAsRGB(String yachtId){ private String getBoatColorAsRGB(String yachtId) {
Color color = participants.get(Integer.valueOf(yachtId)).getColour(); Color color = participants.get(Integer.valueOf(yachtId)).getColour();
if (color == null){ if (color == null) {
return String.format("#%02X%02X%02X",255,255,255); return String.format("#%02X%02X%02X", 255, 255, 255);
} }
return String.format( "#%02X%02X%02X", return String.format("#%02X%02X%02X",
(int)( color.getRed() * 255 ), (int) (color.getRed() * 255),
(int)( color.getGreen() * 255 ), (int) (color.getGreen() * 255),
(int)( color.getBlue() * 255 ) (int) (color.getBlue() * 255)
); );
} }
/** /**
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht * Initialises a timer which updates elements of the RaceView such as wind direction, yacht
* orderings etc.. which are dependent on the info from the stream parser constantly. * orderings etc.. which are dependent on the info from the stream parser constantly. Updates of
* Updates of each of these attributes are called ONCE EACH SECOND * each of these attributes are called ONCE EACH SECOND
*/ */
private void initializeUpdateTimer() { private void initializeUpdateTimer() {
timer.scheduleAtFixedRate(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() {
@@ -318,9 +322,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
/** /**
* Iterates over all corners until ones SeqID matches with the yachts current leg number. * Iterates over all corners until ones SeqID matches with the yachts current leg number. Then
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark * it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark Returns
* Returns null if no next mark found. * null if no next mark found.
*
* @param bg The BoatGroup to find the next mark of * @param bg The BoatGroup to find the next mark of
* @return The next Mark or null if none found * @return The next Mark or null if none found
*/ */
@@ -475,15 +480,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
private Point2D getPointRotation(Point2D ref, Double distance, Double angle){ private Point2D getPointRotation(Point2D ref, Double distance, Double angle) {
Double newX = ref.getX() + (ref.getX() + distance -ref.getX())*Math.cos(angle) - (ref.getY() + distance -ref.getY())*Math.sin(angle); Double newX = ref.getX() + (ref.getX() + distance - ref.getX()) * Math.cos(angle)
Double newY = ref.getY() + (ref.getX() + distance -ref.getX())*Math.sin(angle) + (ref.getY() + distance -ref.getY())*Math.cos(angle); - (ref.getY() + distance - ref.getY()) * Math.sin(angle);
Double newY = ref.getY() + (ref.getX() + distance - ref.getX()) * Math.sin(angle)
+ (ref.getY() + distance - ref.getY()) * Math.cos(angle);
return new Point2D(newX, newY); return new Point2D(newX, newY);
} }
public Line makeLeftLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) { public Line makeLeftLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle); Point2D ep = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle);
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY()); Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
@@ -502,8 +509,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* Initialised the combo box with any yachts currently in the race and adds the required listener * Initialised the combo box with any yachts currently in the race and adds the required
* for the combobox to take action upon selection * listener for the combobox to take action upon selection
*/ */
private void initialiseBoatSelectionComboBox() { private void initialiseBoatSelectionComboBox() {
yachtSelectionComboBox.setItems( yachtSelectionComboBox.setItems(
@@ -540,7 +547,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
TimeUnit.MILLISECONDS.toHours(milliseconds), TimeUnit.MILLISECONDS.toHours(milliseconds),
TimeUnit.MILLISECONDS.toMinutes(milliseconds) % 60, //Modulus 60 minutes per hour TimeUnit.MILLISECONDS.toMinutes(milliseconds) % 60, //Modulus 60 minutes per hour
TimeUnit.MILLISECONDS.toSeconds(milliseconds) % 60 //Modulus 60 seconds per minute TimeUnit.MILLISECONDS.toSeconds(milliseconds) % 60 //Modulus 60 seconds per minute
); );
} }
private void setAnnotations(Integer annotationLevel) { private void setAnnotations(Integer annotationLevel) {
@@ -591,8 +598,21 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// } // }
} }
public void updateRaceData (RaceXMLData raceData) { public void updateRaceData(RaceXMLData raceData) {
this.courseData = raceData; this.courseData = raceData;
gameView.updateBorder(raceData.getCourseLimit()); gameView.updateBorder(raceData.getCourseLimit());
} }
/**
* Called by game client after receiving yacht event packet. Parameter subject id is the
* offending yacht. This function in turn will pass the yacht location to game view to display a
* collision alert.
*
* @param subjectId source id of offending yacht
*/
public void showCollision(Long subjectId) {
System.out.println("showcollision " + subjectId);
System.out.println(participants.get((int) (long) subjectId).getLocation());
gameView.drawCollision(participants.get((int) (long) subjectId).getLocation());
}
} }