Stripped down the boatgroup to the basic movement components and then tried to adjust how position updates are being dealt with to make everything more logically understandable. I made some progress in terms of understanding but the position update is still not as reliable as I would like. I will be explaining to other team members how this part of the code is working so the time I have spent is not completely wasted #story[923]

This commit is contained in:
Peter Galloway
2017-05-15 23:17:36 +12:00
parent fc3ca70e5d
commit 9e3036e134
7 changed files with 250 additions and 640 deletions
@@ -10,24 +10,13 @@ import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.text.Font; import javafx.scene.text.Font;
import seng302.models.BoatGroup;
import seng302.models.Colors;
import seng302.models.RaceObject;
import seng302.models.Yacht;
import seng302.models.*; import seng302.models.*;
import seng302.models.mark.*; import seng302.models.mark.*;
import seng302.models.parsers.StreamParser;
import seng302.models.parsers.XMLParser;
import seng302.models.parsers.XMLParser.RaceXMLObject.CompoundMark;
import seng302.models.parsers.XMLParser.RaceXMLObject.Limit;
import seng302.models.parsers.packets.BoatPositionPacket;
import seng302.models.stream.StreamParser; import seng302.models.stream.StreamParser;
import seng302.models.stream.packets.BoatPositionPacket; import seng302.models.stream.packets.BoatPositionPacket;
import seng302.models.stream.XMLParser; import seng302.models.stream.XMLParser;
import seng302.models.stream.XMLParser.RaceXMLObject.Limit; import seng302.models.stream.XMLParser.RaceXMLObject.Limit;
import seng302.models.mark.Mark; import seng302.models.mark.Mark;
import java.text.DecimalFormat;
import java.util.*; import java.util.*;
import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.PriorityBlockingQueue;
@@ -62,16 +51,13 @@ public class CanvasController {
private Mark maxLonPoint; private Mark maxLonPoint;
private double referencePointX; private double referencePointX;
private double referencePointY; private double referencePointY;
private List<RaceObject> raceObjects = new ArrayList<>(); private List<MarkGroup> markGroups = new ArrayList<>();
private List<Mark> raceMarks = new ArrayList<>(); private List<BoatGroup> boatGroups = new ArrayList<>();
//FRAME RATE //FRAME RATE
private static final double UPDATE_TIME = 0.016666; // 1 / 60 ie 60fps
private final long[] frameTimes = new long[30]; private final long[] frameTimes = new long[30];
private int frameTimeIndex = 0; private int frameTimeIndex = 0;
private boolean arrayFilled = false; private boolean arrayFilled = false;
private DecimalFormat decimalFormat2dp = new DecimalFormat("0.00");
private double lastPacketTime = 0;
public AnimationTimer timer; public AnimationTimer timer;
@@ -94,8 +80,6 @@ public class CanvasController {
// Bind canvas size to stack pane size. // Bind canvas size to stack pane size.
canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH)); canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH));
canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT)); canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT));
//group.minWidth(CANVAS_WIDTH);
//group.minHeight(CANVAS_HEIGHT);
} }
public void initializeCanvas (){ public void initializeCanvas (){
@@ -109,7 +93,7 @@ public class CanvasController {
// TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml // TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml
initializeBoats(); drawBoats();
timer = new AnimationTimer() { timer = new AnimationTimer() {
@Override @Override
@@ -132,7 +116,7 @@ public class CanvasController {
// TODO: 1/05/17 cir27 - Make the RaceObjects update on the actual delay. // TODO: 1/05/17 cir27 - Make the RaceObjects update on the actual delay.
elapsedNanos = 1000 / 60; elapsedNanos = 1000 / 60;
updateRaceObjects(); updateGroups();
if (StreamParser.isRaceFinished()) { if (StreamParser.isRaceFinished()) {
this.stop(); this.stop();
} }
@@ -160,8 +144,8 @@ public class CanvasController {
SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID()); SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID());
Limit thisPoint2 = courseLimits.get(i+1); Limit thisPoint2 = courseLimits.get(i+1);
SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID()); SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID());
Point2D borderPoint1 = latLonToXY(thisMark1.getLatitude(), thisMark1.getLongitude()); Point2D borderPoint1 = findScaledXY(thisMark1);
Point2D borderPoint2 = latLonToXY(thisMark2.getLatitude(), thisMark2.getLongitude()); Point2D borderPoint2 = findScaledXY(thisMark2);
gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(), gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(),
borderPoint2.getX(), borderPoint2.getY()); borderPoint2.getX(), borderPoint2.getY());
xBoundaryPoints[i] = borderPoint1.getX(); xBoundaryPoints[i] = borderPoint1.getX();
@@ -171,8 +155,8 @@ public class CanvasController {
SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID()); SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID());
Limit thisPoint2 = courseLimits.get(0); Limit thisPoint2 = courseLimits.get(0);
SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID()); SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID());
Point2D borderPoint1 = latLonToXY(thisMark1.getLatitude(), thisMark1.getLongitude()); Point2D borderPoint1 = findScaledXY(thisMark1);
Point2D borderPoint2 = latLonToXY(thisMark2.getLatitude(), thisMark2.getLongitude()); Point2D borderPoint2 = findScaledXY(thisMark2);
gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(), gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(),
borderPoint2.getX(), borderPoint2.getY()); borderPoint2.getX(), borderPoint2.getY());
xBoundaryPoints[courseLimits.size()-1] = borderPoint1.getX(); xBoundaryPoints[courseLimits.size()-1] = borderPoint1.getX();
@@ -181,42 +165,32 @@ public class CanvasController {
gc.fillPolygon(xBoundaryPoints,yBoundaryPoints,yBoundaryPoints.length); gc.fillPolygon(xBoundaryPoints,yBoundaryPoints,yBoundaryPoints.length);
} }
private void updateRaceObjects(){ private void updateGroups(){
for (RaceObject raceObject : raceObjects) { for (BoatGroup boatGroup : boatGroups) {
raceObject.updatePosition(1000 / 60); boatGroup.updatePosition();
// some raceObjects will have multiply ID's (for instance gate marks) // some raceObjects will have multiple ID's (for instance gate marks)
for (long id : raceObject.getRaceIds()) {
//checking if the current "ID" has any updates associated with it //checking if the current "ID" has any updates associated with it
if (StreamParser.boatPositions.containsKey(boatGroup.getRaceId())) {
moveBoatGroup(boatGroup);
}
}
for (MarkGroup markGroup : markGroups) {
for (int id : markGroup.getRaceIds()) {
if (StreamParser.boatPositions.containsKey(id)) { if (StreamParser.boatPositions.containsKey(id)) {
move(id, raceObject); moveMarkGroup(id, markGroup);
} }
} }
} }
} }
private void move(long id, RaceObject raceObject){ private void moveBoatGroup(BoatGroup boatGroup) {
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.boatPositions.get(id); PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.boatPositions.get(boatGroup.getRaceId());
if (movementQueue.size() > 0){ if (movementQueue.size() > 0){
// BoatPositionPacket positionPacket = movementQueue.peek();
//
// //this code adds a delay to reading from the movementQueue
// //in case things being put into the movement queue are slightly
// //out of order
// int delayTime = 1000;
// int loopTime = delayTime * 10;
// long timeDiff = (System.currentTimeMillis()%loopTime - positionPacket.getTimeValid()%loopTime);
// if (timeDiff < 0){
// timeDiff = loopTime + timeDiff;
// }
// if (timeDiff > delayTime) {
try { try {
BoatPositionPacket positionPacket = movementQueue.take(); BoatPositionPacket positionPacket = movementQueue.take();
if (id == 104){ Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon());
System.out.println(positionPacket.getTimeValid());
}
Point2D p2d = latLonToXY(positionPacket.getLat(), positionPacket.getLon());
double heading = 360.0 / 0xffff * positionPacket.getHeading(); double heading = 360.0 / 0xffff * positionPacket.getHeading();
raceObject.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), (int) id); boatGroup.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), boatGroup.getRaceId());
} catch (InterruptedException e){ } catch (InterruptedException e){
e.printStackTrace(); e.printStackTrace();
} }
@@ -224,6 +198,19 @@ public class CanvasController {
} }
} }
void moveMarkGroup (int raceId, MarkGroup markGroup) {
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.boatPositions.get(raceId);
if (movementQueue.size() > 0){
try {
BoatPositionPacket positionPacket = movementQueue.take();
Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon());
markGroup.moveMarkTo(p2d.getX(), p2d.getY(), raceId);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
class ResizableCanvas extends Canvas { class ResizableCanvas extends Canvas {
ResizableCanvas() { ResizableCanvas() {
@@ -275,18 +262,18 @@ public class CanvasController {
/** /**
* Draws all the boats. * Draws all the boats.
*/ */
private void initializeBoats() { private void drawBoats() {
Map<Integer, Yacht> boats = StreamParser.getBoats(); Map<Integer, Yacht> boats = StreamParser.getBoats();
Group boatAnnotations = new Group(); Group boatAnnotations = new Group();
for (Yacht boat : boats.values()) { for (Yacht boat : boats.values()) {
boat.setColour(Colors.getColor()); boat.setColour(Colors.getColor());
BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); BoatGroup boatGroup = new BoatGroup(boat, boat.getColour());
raceObjects.add(boatGroup); boatGroups.add(boatGroup);
boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations());
} }
group.getChildren().add(boatAnnotations); group.getChildren().add(boatAnnotations);
group.getChildren().addAll(raceObjects); group.getChildren().addAll(boatGroups);
} }
/** /**
@@ -362,6 +349,7 @@ public class CanvasController {
} }
} }
/** /**
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns it to distanceScaleFactor * Finds the scale factor necessary to fit all race markers within the onscreen map and assigns it to distanceScaleFactor
* Returns the max horizontal distance of the map. * Returns the max horizontal distance of the map.
@@ -395,36 +383,37 @@ public class CanvasController {
* are scaled according to the distanceScaleFactor variable. * are scaled according to the distanceScaleFactor variable.
*/ */
private void givePointsXY() { private void givePointsXY() {
List<XMLParser.RaceXMLObject.CompoundMark> allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); // List<XMLParser.RaceXMLObject.CompoundMark> allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks();
List<XMLParser.RaceXMLObject.CompoundMark> processed = new ArrayList<>(); // List<XMLParser.RaceXMLObject.CompoundMark> processed = new ArrayList<>();
RaceObject markGroup; // MarkGroup markGroup;
//
for (XMLParser.RaceXMLObject.CompoundMark mark : allPoints) { // for (XMLParser.RaceXMLObject.CompoundMark mark : allPoints) {
if (!processed.contains(mark)) { // if (!processed.contains(mark)) {
if (mark.getMarkType() != MarkType.SINGLE_MARK) { // if (mark.getMarkType() != MarkType.SINGLE_MARK) {
markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)), findScaledXY(mark.getMarks().get(1))); // markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)), findScaledXY(mark.getMarks().get(1)));
raceObjects.add(markGroup); // markGroups.add(markGroup);
} else { // } else {
markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0))); // markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)));
raceObjects.add(markGroup); // markGroups.add(markGroup);
} // }
processed.add(mark); // processed.add(mark);
} // }
} // }
group.getChildren().addAll(boatGroups);
} }
private Point2D findScaledXY (Mark unscaled) {
return findScaledXY (unscaled.getLatitude(), unscaled.getLongitude());
}
private Point2D findScaledXY (double unscaledLat, double unscaledLon) {
private Point2D latLonToXY (double latitude, double longitude){
double distanceFromReference; double distanceFromReference;
double angleFromReference; double angleFromReference;
int xAxisLocation = (int) referencePointX; int xAxisLocation = (int) referencePointX;
int yAxisLocation = (int) referencePointY; int yAxisLocation = (int) referencePointY;
double minLat = minLatPoint.getLatitude(); angleFromReference = Mark.calculateHeadingRad(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon);
double minLon = minLatPoint.getLongitude(); distanceFromReference = Mark.calculateDistance(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon);
angleFromReference = Mark.calculateHeadingRad(minLat, minLon, latitude, longitude);
distanceFromReference = Mark.calculateDistance(minLat, minLon, latitude, longitude);
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) { if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
xAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); xAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
@@ -444,12 +433,7 @@ public class CanvasController {
return new Point2D(xAxisLocation, yAxisLocation); return new Point2D(xAxisLocation, yAxisLocation);
} }
List<BoatGroup> getBoatGroups() {
private Point2D latLonToXY (double latitude, double longitude) { return boatGroups;
return findScaledXY(minLatPoint.getLatitude(), minLatPoint.getLongitude(), latitude, longitude);
}
List<RaceObject> getRaceObjects() {
return raceObjects;
} }
} }
@@ -15,14 +15,13 @@ 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 seng302.models.Yacht; import seng302.models.Yacht;
import seng302.models.parsers.StreamParser;
import seng302.models.parsers.XMLParser;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import seng302.models.stream.StreamParser;
public class Controller implements Initializable { public class Controller implements Initializable {
@FXML @FXML
@@ -1,6 +1,6 @@
package seng302.controllers; package seng302.controllers;
import javafx.animation.Animation; import java.io.IOException;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
@@ -12,7 +12,6 @@ import javafx.scene.control.Button;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
import javafx.scene.control.Slider; import javafx.scene.control.Slider;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Paint; import javafx.scene.paint.Paint;
@@ -25,16 +24,16 @@ import seng302.controllers.annotations.Annotation;
import seng302.controllers.annotations.ImportantAnnotationController; import seng302.controllers.annotations.ImportantAnnotationController;
import seng302.controllers.annotations.ImportantAnnotationDelegate; import seng302.controllers.annotations.ImportantAnnotationDelegate;
import seng302.controllers.annotations.ImportantAnnotationsState; import seng302.controllers.annotations.ImportantAnnotationsState;
import seng302.models.*; import seng302.models.BoatGroup;
import seng302.models.parsers.StreamParser; import seng302.models.RaceObject;
import seng302.models.Yacht;
import java.io.IOException; import seng302.models.stream.StreamParser;
import java.util.*;
/** /**
* Created by ptg19 on 29/03/17. * Created by ptg19 on 29/03/17.
*/ */
public class RaceViewController extends Thread implements ImportantAnnotationDelegate{ public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
@FXML @FXML
private VBox positionVbox; private VBox positionVbox;
@FXML @FXML
@@ -52,12 +51,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
@FXML @FXML
private CanvasController includedCanvasController; private CanvasController includedCanvasController;
private ArrayList<Yacht> startingBoats = new ArrayList<>();
private boolean displayFps; private boolean displayFps;
private Timeline timerTimeline; private Timeline timerTimeline;
private Map<Yacht, TimelineInfo> timelineInfos = new HashMap<>();
private ArrayList<Yacht> boatOrder = new ArrayList<>();
private Race race;
private Stage stage; private Stage stage;
private ImportantAnnotationsState importantAnnotations; private ImportantAnnotationsState importantAnnotations;
@@ -65,24 +60,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// Load a default important annotation state // Load a default important annotation state
importantAnnotations = new ImportantAnnotationsState(); importantAnnotations = new ImportantAnnotationsState();
RaceController raceController = new RaceController();
raceController.initializeRace();
race = raceController.getRace();
for (Yacht boat : race.getBoats()) {
startingBoats.add(boat);
}
includedCanvasController.setup(this); includedCanvasController.setup(this);
includedCanvasController.initializeCanvas(); includedCanvasController.initializeCanvas();
initializeTimer(); initializeTimer();
initializeSettings(); initializeSettings();
initialiseWindDirection(); initialiseWindDirection();
initialisePositionVBox(); initialisePositionVBox();
//set wind direction!!!!!!! can't find another place to put my code --haoming
// double windDirection = new ConfigParser("/config/config.xml").getWindDirection();
// windDirectionText.setText(String.format("%.1f°", windDirection));
// windArrowText.setRotate(windDirection);
includedCanvasController.timer.start(); includedCanvasController.timer.start();
selectAnnotationBtn.setOnAction(event -> { selectAnnotationBtn.setOnAction(event -> {
@@ -92,11 +75,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* The important annotations have been changed, update this view * The important annotations have been changed, update this view
*
* @param importantAnnotationsState The current state of the selected annotations * @param importantAnnotationsState The current state of the selected annotations
*/ */
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState){ public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
this.importantAnnotations = importantAnnotationsState; this.importantAnnotations = importantAnnotationsState;
setAnnotations((int)annotationSlider.getValue()); // Refresh the displayed annotations setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
} }
/** /**
@@ -108,11 +92,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
Stage stage = new Stage(); Stage stage = new Stage();
// Set controller // Set controller
ImportantAnnotationController controller = new ImportantAnnotationController(this, stage); ImportantAnnotationController controller = new ImportantAnnotationController(this,
stage);
fxmlLoader.setController(controller); fxmlLoader.setController(controller);
// Load FXML and set CSS // Load FXML and set CSS
fxmlLoader.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml")); fxmlLoader
.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 469, 248); Scene scene = new Scene(fxmlLoader.load(), 469, 248);
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString()); scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
stage.initStyle(StageStyle.UNDECORATED); stage.initStyle(StageStyle.UNDECORATED);
@@ -132,7 +118,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
toggleFps.selectedProperty().addListener(new ChangeListener<Boolean>() { toggleFps.selectedProperty().addListener(new ChangeListener<Boolean>() {
@Override @Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
Boolean newValue) {
displayFps = !displayFps; displayFps = !displayFps;
} }
}); });
@@ -141,10 +128,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
annotationSlider.setLabelFormatter(new StringConverter<Double>() { annotationSlider.setLabelFormatter(new StringConverter<Double>() {
@Override @Override
public String toString(Double n) { public String toString(Double n) {
if (n == 0) return "None"; if (n == 0) {
if (n == 1) return "Low"; return "None";
if (n == 2) return "Important"; }
if (n == 3) return "All"; if (n == 1) {
return "Low";
}
if (n == 2) {
return "Important";
}
if (n == 3) {
return "All";
}
return "All"; return "All";
} }
@@ -168,12 +163,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}); });
annotationSlider.valueProperty().addListener((obs, oldval, newVal) -> annotationSlider.valueProperty().addListener((obs, oldval, newVal) ->
setAnnotations((int)annotationSlider.getValue())); setAnnotations((int) annotationSlider.getValue()));
annotationSlider.setValue(3); annotationSlider.setValue(3);
} }
private void initializeTimer(){ private void initializeTimer() {
timerTimeline = new Timeline(); timerTimeline = new Timeline();
timerTimeline.setCycleCount(Timeline.INDEFINITE); timerTimeline.setCycleCount(Timeline.INDEFINITE);
// Run timer update every second // Run timer update every second
@@ -199,7 +194,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
windDirTimeline.getKeyFrames().add( windDirTimeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1), new KeyFrame(Duration.seconds(1),
event -> { event -> {
windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection())); windDirectionText
.setText(String.format("%.1f°", StreamParser.getWindDirection()));
windArrowText.setRotate(StreamParser.getWindDirection()); windArrowText.setRotate(StreamParser.getWindDirection());
}) })
); );
@@ -217,131 +213,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}) })
); );
posVBoxTimeline.playFromStart(); posVBoxTimeline.playFromStart();
}
/**
* Generates time line for each boat, and stores time time into timelineInfos hash map
*/
private void initializeTimelines() {
HashMap<Yacht, List> boat_events = race.getEvents();
for (Yacht boat : boat_events.keySet()) {
startingBoats.add(boat);
// // x, y are the real time coordinates
// DoubleProperty x = new SimpleDoubleProperty();
// DoubleProperty y = new SimpleDoubleProperty();
//
// List<KeyFrame> keyFrames = new ArrayList<>();
// List<Event> events = boat_events.get(boat);
//
// // iterates all events and convert each event to keyFrame, then add them into a list
// for (Event event : events) {
// if (event.getIsFinishingEvent()) {
// keyFrames.add(
// new KeyFrame(Duration.seconds(event.getTime()),
// onFinished -> {race.setBoatFinished(boat); handleEvent(event);},
// new KeyValue(x, event.getThisMark().getLatitude()),
// new KeyValue(y, event.getThisMark().getLongitude())
// )
// );
// } else {
// keyFrames.add(
// new KeyFrame(Duration.seconds(event.getTime()),
// onFinished ->{
// handleEvent(event);
// boat.setHeading(event.getBoatHeading());
// },
// new KeyValue(x, event.getThisMark().getLatitude()),
// new KeyValue(y, event.getThisMark().getLongitude())
// )
// );
// }
// }
// timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y));
}
setRaceDuration();
}
private void setRaceDuration(){
Double maxDuration = 0.0;
Timeline maxTimeline = null;
for (TimelineInfo timelineInfo : timelineInfos.values()) {
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getTotalDuration().toMillis() >= maxDuration) {
maxDuration = timeline.getTotalDuration().toMillis();
maxTimeline = timeline;
}
// Timelines are paused by default
timeline.play();
timeline.pause();
}
maxTimeline.setOnFinished(event -> {
race.setRaceFinished();
loadRaceResultView();
});
}
/**
* Play each boats timerTimeline
*/
public void playTimelines(){
for (TimelineInfo timelineInfo : timelineInfos.values()){
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getStatus() == Animation.Status.PAUSED){
timeline.play();
}
}
}
/**
* Pause each boats timerTimeline
*/
public void pauseTimelines(){
for (TimelineInfo timelineInfo : timelineInfos.values()){
Timeline timeline = timelineInfo.getTimeline();
if (timeline.getStatus() == Animation.Status.RUNNING){
timeline.pause();
}
}
}
/**
* Display the list of boats in the order they finished the race
*/
private void loadRaceResultView() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
loader.setController(new RaceResultController(race));
try {
contentAnchorPane.getChildren().removeAll();
contentAnchorPane.getChildren().clear();
contentAnchorPane.getChildren().addAll((Pane) loader.load());
} catch (javafx.fxml.LoadException e) {
System.err.println(e.getCause());
} catch (IOException e) {
System.err.println(e);
}
}
public void handleEvent(Event event) {
Yacht boat = event.getBoat();
boatOrder.remove(boat);
boat.setMarkLastPast(event.getMarkPosInRace());
boatOrder.add(boat);
boatOrder.sort(new Comparator<Yacht>() {
@Override
public int compare(Yacht b1, Yacht b2) {
return b2.getMarkLastPast() - b1.getMarkLastPast();
}
});
showOrder();
} }
private void showOrder() { private void showOrder() {
@@ -349,10 +220,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
positionVbox.getChildren().removeAll(); positionVbox.getChildren().removeAll();
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// for (Boat boat : boatOrder) {
// positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots"));
// }
for (Yacht boat : StreamParser.getBoatsPos().values()) { for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (boat.getBoatStatus() == 3) { // 3 is finish status if (boat.getBoatStatus() == 3) { // 3 is finish status
Text textToAdd = new Text(boat.getPosition() + ". " + Text textToAdd = new Text(boat.getPosition() + ". " +
@@ -404,118 +271,83 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
return timerString; return timerString;
} }
public void stopTimer() {
timerTimeline.stop();
}
public void startTimer() {
timerTimeline.play();
}
public boolean isDisplayFps() { public boolean isDisplayFps() {
return displayFps; return displayFps;
} }
public Race getRace() {
return race;
}
public Map<Yacht, TimelineInfo> getTimelineInfos() {
return timelineInfos;
}
public ArrayList<Yacht> getStartingBoats(){
return startingBoats;
}
/** /**
* Display the important annotations for a specific BoatGroup * Display the important annotations for a specific BoatGroup
*
* @param bg The boat group to set the annotations for * @param bg The boat group to set the annotations for
*/ */
private void setBoatGroupImportantAnnotations(BoatGroup bg){ private void setBoatGroupImportantAnnotations(BoatGroup bg) {
if (importantAnnotations.getAnnotationState(Annotation.NAME)){ if (importantAnnotations.getAnnotationState(Annotation.NAME)) {
bg.setTeamNameObjectVisible(true); bg.setTeamNameObjectVisible(true);
} } else {
else{
bg.setTeamNameObjectVisible(false); bg.setTeamNameObjectVisible(false);
} }
if (importantAnnotations.getAnnotationState(Annotation.SPEED)){ if (importantAnnotations.getAnnotationState(Annotation.SPEED)) {
bg.setVelocityObjectVisible(true); bg.setVelocityObjectVisible(true);
} } else {
else{
bg.setVelocityObjectVisible(false); bg.setVelocityObjectVisible(false);
} }
if (importantAnnotations.getAnnotationState(Annotation.TRACK)){ if (importantAnnotations.getAnnotationState(Annotation.TRACK)) {
bg.setLineGroupVisible(true); bg.setLineGroupVisible(true);
} } else {
else{
bg.setLineGroupVisible(false); bg.setLineGroupVisible(false);
} }
if (importantAnnotations.getAnnotationState(Annotation.WAKE)){ if (importantAnnotations.getAnnotationState(Annotation.WAKE)) {
bg.setWakeVisible(true); bg.setWakeVisible(true);
} } else {
else{
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
} }
private void setAnnotations(Integer annotationLevel) { private void setAnnotations(Integer annotationLevel) {
switch (annotationLevel) { switch (annotationLevel) {
// No Annotations
case 0: case 0:
for (RaceObject ro : includedCanvasController.getRaceObjects()) { for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
if(ro instanceof BoatGroup) {
BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(false); bg.setTeamNameObjectVisible(false);
bg.setVelocityObjectVisible(false); bg.setVelocityObjectVisible(false);
bg.setLineGroupVisible(false); bg.setLineGroupVisible(false);
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
}
break; break;
// Low Annotations
case 1: case 1:
for (RaceObject ro : includedCanvasController.getRaceObjects()) { for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
if(ro instanceof BoatGroup) {
BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(true); bg.setTeamNameObjectVisible(true);
bg.setVelocityObjectVisible(false); bg.setVelocityObjectVisible(false);
bg.setLineGroupVisible(false); bg.setLineGroupVisible(false);
bg.setWakeVisible(false); bg.setWakeVisible(false);
} }
}
break; break;
// Important Annotations
case 2: case 2:
for (RaceObject ro : includedCanvasController.getRaceObjects()) { for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
if(ro instanceof BoatGroup) { bg.setTeamNameObjectVisible(true);
BoatGroup bg = (BoatGroup) ro; bg.setVelocityObjectVisible(false);
setBoatGroupImportantAnnotations(bg); bg.setLineGroupVisible(true);
} bg.setWakeVisible(false);
} }
break; break;
// All Annotations
case 3: case 3:
for (RaceObject ro : includedCanvasController.getRaceObjects()) { for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
if(ro instanceof BoatGroup) {
BoatGroup bg = (BoatGroup) ro;
bg.setTeamNameObjectVisible(true); bg.setTeamNameObjectVisible(true);
bg.setVelocityObjectVisible(true); bg.setVelocityObjectVisible(true);
bg.setLineGroupVisible(true); bg.setLineGroupVisible(true);
bg.setWakeVisible(true); bg.setWakeVisible(true);
} }
}
break; break;
} }
} }
void setStage (Stage stage) { void setStage(Stage stage) {
this.stage = stage; this.stage = stage;
} }
Stage getStage () { Stage getStage() {
return stage; return stage;
} }
} }
+49 -136
View File
@@ -19,7 +19,7 @@ import java.util.List;
* UpdatePosition is called unless the window is minimized in which case it attempts to store animations and apply them * UpdatePosition is called unless the window is minimized in which case it attempts to store animations and apply them
* when the window is maximised. * when the window is maximised.
*/ */
public class BoatGroup extends RaceObject{ public class BoatGroup extends Group{
//Constants for drawing //Constants for drawing
private static final double TEAMNAME_X_OFFSET = 10d; private static final double TEAMNAME_X_OFFSET = 10d;
@@ -30,8 +30,15 @@ public class BoatGroup extends RaceObject{
private static final double BOAT_WIDTH = 10d; private static final double BOAT_WIDTH = 10d;
//Variables for boat logic. //Variables for boat logic.
private Point2D lastPoint; private Point2D lastPoint;
private int wakeGenerationDelay = 10; double oldTime;
private double distanceTravelled; double newTime;
double lastYValue = 0;
double lastXValue = 0;
private double dx;
private double dy;
private double pixelVelocityX;
private double pixelVelocityY;
private static final int expectedUpdateInterval = 200;
//Graphical objects //Graphical objects
private Yacht boat; private Yacht boat;
private Group lineGroup = new Group(); private Group lineGroup = new Group();
@@ -39,14 +46,6 @@ public class BoatGroup extends RaceObject{
private Text teamNameObject; private Text teamNameObject;
private Text velocityObject; private Text velocityObject;
private Wake wake; private Wake wake;
//Handles boat moving when connecting to a stream
private boolean setToInitialLocation = false;
private boolean destinationSet;
//Variables for handling minimization
private Stage stage;
private boolean isMaximized= true;
private List<Line> lineStorage = new ArrayList<>();
private int setCallCount = 5;
/** /**
* Creates a BoatGroup with the default triangular boat polygon. * Creates a BoatGroup with the default triangular boat polygon.
@@ -91,7 +90,6 @@ public class BoatGroup extends RaceObject{
velocityObject.setX(VELOCITY_X_OFFSET); velocityObject.setX(VELOCITY_X_OFFSET);
velocityObject.setY(VELOCITY_Y_OFFSET); velocityObject.setY(VELOCITY_Y_OFFSET);
velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
destinationSet = false;
wake = new Wake(0, -BOAT_HEIGHT); wake = new Wake(0, -BOAT_HEIGHT);
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly); super.getChildren().addAll(teamNameObject, velocityObject, boatPoly);
@@ -113,7 +111,7 @@ public class BoatGroup extends RaceObject{
* @param dx The amount to move the X coordinate by * @param dx The amount to move the X coordinate by
* @param dy The amount to move the Y coordinate by * @param dy The amount to move the Y coordinate by
*/ */
public void moveGroupBy(double dx, double dy, double rotation) { public void moveGroupBy(double dx, double dy) {
boatPoly.setLayoutX(boatPoly.getLayoutX() + dx); boatPoly.setLayoutX(boatPoly.getLayoutX() + dx);
boatPoly.setLayoutY(boatPoly.getLayoutY() + dy); boatPoly.setLayoutY(boatPoly.getLayoutY() + dy);
teamNameObject.setLayoutX(teamNameObject.getLayoutX() + dx); teamNameObject.setLayoutX(teamNameObject.getLayoutX() + dx);
@@ -122,19 +120,16 @@ public class BoatGroup extends RaceObject{
velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); velocityObject.setLayoutY(velocityObject.getLayoutY() + dy);
wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutX(wake.getLayoutX() + dx);
wake.setLayoutY(wake.getLayoutY() + dy); wake.setLayoutY(wake.getLayoutY() + dy);
currentRotation = rotation + currentRotation;
boatPoly.getTransforms().setAll(new Rotate(rotation));
} }
/** /**
* Moves the boat and its children annotations to coordinates specified * Moves the boat and its children annotations to coordinates specified
* @param x The X coordinate to move the boat to * @param x The X coordinate to move the boat to
* @param y The Y coordinate to move the boat to * @param y The Y coordinate to move the boat to
* @param rotation The heading in degrees from north the boat should rotate to.
*/ */
public void moveTo (double x, double y, double rotation) { public void moveTo (double x, double y, double rotation) {
currentRotation = rotation; rotateTo(rotation);
boatPoly.getTransforms().setAll(new Rotate(rotation));
boatPoly.setLayoutX(x); boatPoly.setLayoutX(x);
boatPoly.setLayoutY(y); boatPoly.setLayoutY(y);
teamNameObject.setLayoutX(x); teamNameObject.setLayoutX(x);
@@ -143,42 +138,14 @@ public class BoatGroup extends RaceObject{
velocityObject.setLayoutY(y); velocityObject.setLayoutY(y);
wake.setLayoutX(x); wake.setLayoutX(x);
wake.setLayoutY(y); wake.setLayoutY(y);
wake.rotate(currentRotation);
} }
/** public void rotateTo (double rotation) {
* Updates the position of all graphics in the BoatGroup based off of the given time interval. boatPoly.getTransforms().setAll(new Rotate(rotation));
* @param timeInterval The interval, in milliseconds, the boat should update it's position based on. }
*/
public void updatePosition (long timeInterval) {
//Calculate the movement of the boat.
if (isMaximized) {
double dx = pixelVelocityX * timeInterval;
double dy = pixelVelocityY * timeInterval;
double rotation = rotationalVelocity * timeInterval;
distanceTravelled += Math.abs(dx) + Math.abs(dy);
moveGroupBy(dx, dy, rotation);
//Draw a new section of the trail every 20 pixels of movement. public void updatePosition () {
if (distanceTravelled > 20) { moveGroupBy(dx, dy);
distanceTravelled = 0;
if (lastPoint != null) {
Line l = new Line(
lastPoint.getX(),
lastPoint.getY(),
boatPoly.getLayoutX(),
boatPoly.getLayoutY()
);
l.getStrokeDashArray().setAll(3d, 7d);
l.setStroke(boatPoly.getFill());
lineGroup.getChildren().add(l);
}
if (destinationSet) { //Only begin drawing after the first destination is set
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
}
}
wake.updatePosition(timeInterval);
}
} }
/** /**
@@ -188,59 +155,26 @@ public class BoatGroup extends RaceObject{
* @param rotation Rotation to move graphics to. * @param rotation Rotation to move graphics to.
* @param raceIds RaceID of the object to move. * @param raceIds RaceID of the object to move.
*/ */
public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, int... raceIds) { public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, long raceIds) {
if (hasRaceId(raceIds)) { System.currentTimeMillis();
if (setToInitialLocation) { moveTo(lastXValue, lastYValue, rotation);
destinationSet = true;
dx = (newXValue - lastXValue)/12;
dy = (newYValue - lastYValue)/12;
lastXValue = newXValue;
lastYValue = newYValue;
boat.setVelocity(groundSpeed); boat.setVelocity(groundSpeed);
if (currentRotation < 0)
currentRotation = 360 - currentRotation;
double dx = newXValue - boatPoly.getLayoutX();
double dy = newYValue - boatPoly.getLayoutY();
pixelVelocityX = dx / expectedUpdateInterval;
pixelVelocityY = dy / expectedUpdateInterval;
rotationalGoal = rotation;
calculateRotationalVelocity();
if (wakeGenerationDelay > 0) {
wake.rotate(rotationalGoal);
rotationalVelocity = 0;
wakeGenerationDelay--;
} else {
wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, boat.getVelocity());
}
velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); velocityObject.setText(String.format("%.2f m/s", boat.getVelocity()));
} else {
setToInitialLocation = true;
rotationalGoal = rotation;
moveTo(newXValue, newYValue, rotation);
}
}
//If minimized generate lines every 5 calls to set destination.
if (!isMaximized) {
setToInitialLocation = false;
wakeGenerationDelay = 2;
if(setCallCount-- == 0) {
setCallCount = 5;
if (lastPoint != null) {
Line l = new Line(
lastPoint.getX(),
lastPoint.getY(),
newXValue,
newYValue
);
l.getStrokeDashArray().setAll(3d, 7d);
l.setStroke(boatPoly.getFill());
lineStorage.add(l);
}
if (destinationSet) { //Only begin drawing after the first destination is set
lastPoint = new Point2D(newXValue, newYValue);
}
}
}
} }
public void setTeamNameObjectVisible(Boolean visible) { public void setTeamNameObjectVisible(Boolean visible) {
teamNameObject.setVisible(visible); teamNameObject.setVisible(visible);
} }
@@ -261,27 +195,27 @@ public class BoatGroup extends RaceObject{
return boat; return boat;
} }
/** // /**
* Returns true if this BoatGroup contains at least one of the given IDs. // * Returns true if this BoatGroup contains at least one of the given IDs.
* // *
* @param raceIds The ID's to check the BoatGroup for. // * @param raceIds The ID's to check the BoatGroup for.
* @return True if the BoatGroup contains at east one of the given IDs, false otherwise. // * @return True if the BoatGroup contains at east one of the given IDs, false otherwise.
*/ // */
public boolean hasRaceId (int... raceIds) { // public boolean hasRaceId (long... raceIds) {
for (int id : raceIds) { // for (long id : raceIds) {
if (id == boat.getSourceID()) // if (id == boat.getSourceID())
return true; // return true;
} // }
return false; // return false;
} // }
/** /**
* Returns all raceIds associated with this group. For BoatGroups the ID's are for the boat. * Returns all raceIds associated with this group. For BoatGroups the ID's are for the boat.
* *
* @return An array containing all ID's associated with this RaceObject. * @return An array containing all ID's associated with this RaceObject.
*/ */
public int[] getRaceIds () { public long getRaceId() {
return new int[] {boat.getSourceID()}; return boat.getSourceID();
} }
/** /**
@@ -296,25 +230,4 @@ public class BoatGroup extends RaceObject{
group.getChildren().addAll(wake, lineGroup); group.getChildren().addAll(wake, lineGroup);
return group; return group;
} }
/**
* Use this function to let the BoatGroup know about the stage it is in. If it knows about it's stage then it will
* listen to the iconified property of that stage and change it's behaviour upon minimization. Without setting the
* Stage there is guarantee that the BoatGroup will draw properly when the stage is minimized.
*
* @param stage The stage that the BoatGroup is added to.
*/
public void setStage (Stage stage) {
/* TODO: 4/05/17 cir27 - Find a way to get the stage to this point. Need to pass it through multiple controllers.
App.start() -> Controller.setContentPane -> RaceViewController -> CanvasController
*/
this.stage = stage;
this.stage.iconifiedProperty().addListener(e -> {
isMaximized = !stage.isIconified();
if (!lineStorage.isEmpty()) {
lineGroup.getChildren().addAll(lineStorage);
lineStorage.clear();
}
});
}
} }
+20 -133
View File
@@ -1,12 +1,11 @@
package seng302.models.mark; package seng302.models.mark;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.Node; import javafx.scene.Group;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.shape.Circle; import javafx.scene.shape.Circle;
import javafx.scene.shape.Line; import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
import seng302.models.RaceObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -14,7 +13,7 @@ import java.util.List;
/** /**
* Created by CJIRWIN on 26/04/2017. * Created by CJIRWIN on 26/04/2017.
*/ */
public class MarkGroup extends RaceObject { public class MarkGroup extends Group {
private static int MARK_RADIUS = 5; private static int MARK_RADIUS = 5;
private static int LINE_THICKNESS = 2; private static int LINE_THICKNESS = 2;
@@ -23,14 +22,8 @@ public class MarkGroup extends RaceObject {
private List<Mark> marks = new ArrayList<>(); private List<Mark> marks = new ArrayList<>();
private Mark mainMark; private Mark mainMark;
private double[] nodePixelVelocitiesX;
private double[] nodePixelVelocitiesY;
private Point2D[] nodeDestinations;
public MarkGroup (Mark mark, Point2D... points) { public MarkGroup (Mark mark, Point2D... points) {
nodePixelVelocitiesX = new double[points.length];
nodePixelVelocitiesY = new double[points.length];
nodeDestinations = new Point2D[points.length];
marks.add(mark); marks.add(mark);
mainMark = mark; mainMark = mark;
Color color = Color.BLACK; Color color = Color.BLACK;
@@ -47,25 +40,14 @@ public class MarkGroup extends RaceObject {
MARK_RADIUS, MARK_RADIUS,
color color
); );
nodeDestinations = new Point2D[]{
new Point2D(markCircle.getCenterX(), markCircle.getCenterY()
)
};
super.getChildren().add(markCircle); super.getChildren().add(markCircle);
} else { } else {
// marks.add(((GateMark) mark).getSingleMark1());
// marks.add(((GateMark) mark).getSingleMark2());
nodePixelVelocitiesX = new double[]{0d,0d};
nodePixelVelocitiesY = new double[]{0d,0d};
nodeDestinations = new Point2D[2];
markCircle = new Circle( markCircle = new Circle(
points[0].getX(), points[0].getX(),
points[0].getY(), points[0].getY(),
MARK_RADIUS, MARK_RADIUS,
color color
); );
nodeDestinations[0] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY());
super.getChildren().add(markCircle); super.getChildren().add(markCircle);
markCircle = new Circle( markCircle = new Circle(
@@ -74,7 +56,6 @@ public class MarkGroup extends RaceObject {
MARK_RADIUS, MARK_RADIUS,
color color
); );
nodeDestinations[1] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY());
super.getChildren().add(markCircle); super.getChildren().add(markCircle);
Line line = new Line( Line line = new Line(
points[0].getX(), points[0].getX(),
@@ -91,113 +72,27 @@ public class MarkGroup extends RaceObject {
} }
} }
public void setDestination (double x, double y, double rotation, double groundSpeed, int... raceIds) { public void moveMarkTo (double x, double y, int raceId)
for (int i = 0; i < marks.size(); i++) {
for (int id : raceIds) if (mainMark.getMarkType() == MarkType.SINGLE_MARK) {
if (id == marks.get(i).getId())
setDestinationChild(x, y, 0, Math.max(0, i-1));
this.rotationalGoal = rotation;
calculateRotationalVelocity();
}
private void setDestinationChild (double x, double y, double speed, int childIndex) {
//double relativeX = x - super.getLayoutX();
//double relativeY = y - super.getLayoutY();
Circle markCircle = (Circle) super.getChildren().get(childIndex);
this.nodeDestinations[childIndex] = new Point2D(x, y);
//if (Math.abs(relativeX - markCircle.getCenterX()) > 30 && Math.abs(relativeY - markCircle.getCenterY()) > 30) {
this.nodePixelVelocitiesX[childIndex] = (x - markCircle.getCenterX()) / expectedUpdateInterval;
this.nodePixelVelocitiesY[childIndex] = (y - markCircle.getCenterY()) / expectedUpdateInterval;
//}
}
public void rotateTo (double rotation) {
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
Line line = (Line) super.getChildren().get(2);
double xCenter = Math.abs(line.getEndX() - line.getStartX());
double yCenter = Math.abs(line.getEndY() - line.getStartY());
super.getTransforms().setAll(new Rotate(rotation, xCenter, yCenter));
}
}
public void updatePosition (long timeInterval) {
Circle markCircle = (Circle) super.getChildren().get(0); Circle markCircle = (Circle) super.getChildren().get(0);
markCircle.setCenterX(x);
if (nodePixelVelocitiesX[0] > 0 && markCircle.getCenterX() > nodeDestinations[0].getX() || markCircle.setCenterY(y);
nodePixelVelocitiesX[0] < 0 && markCircle.getCenterX() < nodeDestinations[0].getY())
nodePixelVelocitiesX[0] = 0;
else if (nodePixelVelocitiesX[0] != 0)
markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[0] * timeInterval);
if (nodePixelVelocitiesY[0] > 0 && markCircle.getCenterY() > nodeDestinations[0].getY() ||
nodePixelVelocitiesY[0] < 0 && markCircle.getCenterY() < nodeDestinations[0].getY())
nodePixelVelocitiesY[0] = 0;
else if (nodePixelVelocitiesY[0] != 0)
markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[0] * timeInterval);
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
Line line = (Line) super.getChildren().get(2);
line.setStartX(markCircle.getCenterX());
line.setStartY(markCircle.getCenterY());
markCircle = (Circle) super.getChildren().get(1);
if (nodePixelVelocitiesX[1] > 0 && markCircle.getCenterX() >= nodeDestinations[1].getX() ||
nodePixelVelocitiesX[1] < 0 && markCircle.getCenterX() <= nodeDestinations[1].getX())
nodePixelVelocitiesX[1] = 0;
else if (nodePixelVelocitiesX[1] != 0)
markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[1] * timeInterval);
if (nodePixelVelocitiesY[1] > 0 && markCircle.getCenterY() > nodeDestinations[1].getY() ||
nodePixelVelocitiesY[1] < 0 && markCircle.getCenterY() < nodeDestinations[1].getY())
nodePixelVelocitiesY[1] = 0;
else if (nodePixelVelocitiesY[1] != 0)
markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[1] * timeInterval);
line.setEndX(markCircle.getCenterX());
line.setEndY(markCircle.getCenterY());
}
}
public void moveGroupBy (double x, double y, double rotation) {
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
Line line = (Line) super.getChildren().get(2);
for (int childIndex = 0; childIndex < 2; childIndex++){
Circle mark = (Circle) super.getChildren().get(childIndex);
mark.setCenterY(mark.getCenterY() + y);
mark.setCenterX(mark.getCenterX() + x);
}
line.setStartX(line.getStartX() + x);
line.setStartY(line.getStartY() + y);
line.setEndX(line.getEndX() + x);
line.setEndY(line.getEndY() + y);
} else { } else {
Circle mark = (Circle) super.getChildren().get(0); Circle markCircle1 = (Circle) super.getChildren().get(0);
mark.setCenterY(mark.getCenterY() + y); Circle markCircle2 = (Circle) super.getChildren().get(1);
mark.setCenterX(mark.getCenterX() + x); Line connectingLine = (Line) super.getChildren().get(2);
if (marks.get(1).getId() == raceId) {
markCircle1.setCenterX(x);
markCircle1.setCenterY(y);
connectingLine.setStartX(markCircle1.getCenterX());
connectingLine.setStartY(markCircle1.getCenterY());
} else if (marks.get(2).getId() == raceId) {
markCircle2.setCenterX(x);
markCircle2.setCenterY(y);
connectingLine.setEndX(markCircle2.getCenterX());
connectingLine.setEndY(markCircle2.getCenterY());
} }
rotateTo(currentRotation + rotation);
}
public void moveTo (double x, double y, double rotation) {
moveTo(x, y);
rotateTo(rotation);
}
public void moveTo (double x, double y) {
Circle markCircle = (Circle) super.getChildren().get(0);
markCircle.setCenterX(x);
markCircle.setCenterY(y);
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
markCircle = (Circle) super.getChildren().get(1);
markCircle.setCenterX(x);
markCircle.setCenterY(y);
Line line = (Line) super.getChildren().get(2);
line.setStartX(x);
line.setStartY(y);
line.setEndX(x);
line.setEndY(y);
} }
} }
@@ -209,14 +104,6 @@ public class MarkGroup extends RaceObject {
return false; return false;
} }
public static int getMarkRadius() {
return MARK_RADIUS;
}
public static void setMarkRadius(int markRadius) {
MARK_RADIUS = markRadius;
}
public int[] getRaceIds () { public int[] getRaceIds () {
int[] idArray = new int[marks.size()]; int[] idArray = new int[marks.size()];
int i = 0; int i = 0;
@@ -205,7 +205,6 @@ public class StreamParser extends Thread{
raceFinished = false; raceFinished = false;
System.out.println("[CLIENT] Race has started"); System.out.println("[CLIENT] Race has started");
} }
//System.out.println("Time since start: " + -1 * timeTillStart + " Seconds");
timeSinceStart = timeTillStart; timeSinceStart = timeTillStart;
} }
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
@@ -214,11 +213,10 @@ public class StreamParser extends Thread{
long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22)); long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22));
int noBoats = payload[22]; int noBoats = payload[22];
int raceType = payload[23]; int raceType = payload[23];
// ArrayList<String> boatStatuses = new ArrayList<>();
boatsPos = new TreeMap<>(); boatsPos = new TreeMap<>();
for (int i = 0; i < noBoats; i++){ for (int i = 0; i < noBoats; i++){
Long boatStatusSourceID = bytesToLong(Arrays.copyOfRange(payload,24 + (i * 20),28+ (i * 20))); long boatStatusSourceID = bytesToLong(Arrays.copyOfRange(payload,24 + (i * 20),28+ (i * 20)));
Yacht boat = boats.get((int)(long) boatStatusSourceID); Yacht boat = boats.get((int) boatStatusSourceID);
boat.setBoatStatus((int)payload[28 + (i * 20)]); boat.setBoatStatus((int)payload[28 + (i * 20)]);
boat.setLegNumber((int)payload[29 + (i * 20)]); boat.setLegNumber((int)payload[29 + (i * 20)]);
boat.setPenaltiesAwarded((int)payload[29 + (i * 20)]); boat.setPenaltiesAwarded((int)payload[29 + (i * 20)]);
@@ -281,7 +279,6 @@ public class StreamParser extends Thread{
int messageType = payload[9]; int messageType = payload[9];
long messagelength = bytesToLong(Arrays.copyOfRange(payload,12,14)); long messagelength = bytesToLong(Arrays.copyOfRange(payload,12,14));
String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messagelength)))).trim(); String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messagelength)))).trim();
//System.out.println("xmlMessage2 = " + xmlMessage);
//Create XML document Object //Create XML document Object
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
@@ -344,7 +341,6 @@ public class StreamParser extends Thread{
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];
// System.out.println("eventId = " + eventId);
} }
/** /**
@@ -382,19 +378,18 @@ public class StreamParser extends Thread{
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload,38,40))/1000.0; double groundSpeed = bytesToLong(Arrays.copyOfRange(payload,38,40))/1000.0;
//type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat //type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat
if (deviceType == 1 || deviceType == 3){ if (deviceType == 1){
BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed); BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed);
//add a new priority que to the boatPositions HashMap //add a new priority que to the boatPositions HashMap
if (!boatPositions.containsKey(boatId)){ if (!boatPositions.containsKey(boatId)){
boatPositions.put(boatId, new PriorityBlockingQueue<BoatPositionPacket>(256, new Comparator<BoatPositionPacket>() { boatPositions.put(boatId, new PriorityBlockingQueue<>(256, new Comparator<BoatPositionPacket>() {
@Override @Override
public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { public int compare(BoatPositionPacket p1, BoatPositionPacket p2) {
return (int) (p1.getTimeValid() - p2.getTimeValid()); return (int) (p1.getTimeValid() - p2.getTimeValid());
} }
})); }));
} }
//Adding the boatPacket to the priority que
boatPositions.get(boatId).put(boatPacket); boatPositions.get(boatId).put(boatPacket);
} }
} }
@@ -2,13 +2,13 @@ package seng302.models.stream;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import seng302.models.parsers.packets.StreamPacket;
import java.io.*; import java.io.*;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.Socket; import java.net.Socket;
import java.util.Comparator; import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.PriorityBlockingQueue;
import seng302.models.stream.packets.StreamPacket;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;