mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge branch 'wake_remake' into Story30b_correcting_boat_movement
# Conflicts: # src/main/java/seng302/controllers/CanvasController.java # src/main/java/seng302/models/BoatGroup.java # src/main/java/seng302/models/parsers/StreamParser.java
This commit is contained in:
@@ -12,21 +12,28 @@ public class App extends Application
|
|||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception {
|
public void start(Stage primaryStage) throws Exception {
|
||||||
|
|
||||||
Parent root = FXMLLoader.load(getClass().getResource("/views/MainView.fxml"));
|
Parent root = FXMLLoader.load(getClass().getResource("/views/MainView.fxml"));
|
||||||
primaryStage.setTitle("RaceVision");
|
primaryStage.setTitle("RaceVision");
|
||||||
primaryStage.setScene(new Scene(root));
|
primaryStage.setScene(new Scene(root));
|
||||||
|
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
// StreamReceiver sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941,"TestThread1");
|
}
|
||||||
StreamReceiver sr = new StreamReceiver("livedata.americascup.com", 4941, "TestThread1");
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
StreamReceiver sr;
|
||||||
|
|
||||||
|
if (args.length > 1){
|
||||||
|
sr = new StreamReceiver("localhost", 8085, "TestThread1");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941,"TestThread1");
|
||||||
|
sr = new StreamReceiver("livedata.americascup.com", 4941, "TestThread1");
|
||||||
|
}
|
||||||
|
|
||||||
sr.start();
|
sr.start();
|
||||||
StreamParser streamParser = new StreamParser("TestThread2");
|
StreamParser streamParser = new StreamParser("TestThread2");
|
||||||
streamParser.start();
|
streamParser.start();
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
launch(args);
|
launch(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import seng302.models.parsers.StreamPacket;
|
|||||||
import seng302.models.parsers.StreamParser;
|
import seng302.models.parsers.StreamParser;
|
||||||
import seng302.models.parsers.packets.BoatPositionPacket;
|
import seng302.models.parsers.packets.BoatPositionPacket;
|
||||||
|
|
||||||
|
import java.sql.Time;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
@@ -102,9 +103,6 @@ public class CanvasController {
|
|||||||
fitMarksToCanvas();
|
fitMarksToCanvas();
|
||||||
drawBoats();
|
drawBoats();
|
||||||
timer = new AnimationTimer() {
|
timer = new AnimationTimer() {
|
||||||
private int countdown = 60;
|
|
||||||
private int[] currentRaceMarker = {1, 1, 1, 1, 1, 1};
|
|
||||||
List<Mark> marks = raceViewController.getRace().getCourse();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(long now) {
|
public void handle(long now) {
|
||||||
@@ -116,19 +114,22 @@ public class CanvasController {
|
|||||||
if (frameTimeIndex == 0) {
|
if (frameTimeIndex == 0) {
|
||||||
arrayFilled = true ;
|
arrayFilled = true ;
|
||||||
}
|
}
|
||||||
|
long elapsedNanos;
|
||||||
if (arrayFilled) {
|
if (arrayFilled) {
|
||||||
long elapsedNanos = now - oldFrameTime ;
|
elapsedNanos = now - oldFrameTime ;
|
||||||
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
|
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
|
||||||
Double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
|
Double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
|
||||||
drawFps(frameRate.intValue());
|
drawFps(frameRate.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: 1/05/17 cir27 - Make the RaceObjects update on the actual delay.
|
||||||
|
elapsedNanos = 1000 / 60;
|
||||||
updateRaceObjects();
|
updateRaceObjects();
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (Mark m : raceViewController.getRace().getCourse()) {
|
for (Mark m : raceViewController.getRace().getCourse()) {
|
||||||
// System.out.println(m.getName());
|
System.out.println(m.getName());
|
||||||
}
|
}
|
||||||
//timer.start();
|
//timer.start();
|
||||||
}
|
}
|
||||||
@@ -175,7 +176,7 @@ public class CanvasController {
|
|||||||
|
|
||||||
class ResizableCanvas extends Canvas {
|
class ResizableCanvas extends Canvas {
|
||||||
|
|
||||||
public ResizableCanvas() {
|
ResizableCanvas() {
|
||||||
// Redraw canvas when size changes.
|
// Redraw canvas when size changes.
|
||||||
widthProperty().addListener(evt -> draw());
|
widthProperty().addListener(evt -> draw());
|
||||||
heightProperty().addListener(evt -> draw());
|
heightProperty().addListener(evt -> draw());
|
||||||
@@ -232,39 +233,14 @@ public class CanvasController {
|
|||||||
for (Boat boat : boats) {
|
for (Boat boat : boats) {
|
||||||
BoatGroup boatGroup = new BoatGroup(boat, Colors.getColor());
|
BoatGroup boatGroup = new BoatGroup(boat, Colors.getColor());
|
||||||
boatGroup.moveTo(startingX, startingY, 0d);
|
boatGroup.moveTo(startingX, startingY, 0d);
|
||||||
// boatGroup.setDestination(firstMarkX, firstMarkY);
|
|
||||||
boatGroup.forceRotation();
|
boatGroup.forceRotation();
|
||||||
//group.getChildren().add(boatGroup);
|
|
||||||
raceObjects.add(boatGroup);
|
raceObjects.add(boatGroup);
|
||||||
boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations());
|
boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations());
|
||||||
// drawBoat(boat.getLongitude(), boat.getLatitude(), boat.getColor(), boat.getShortName(), boat.getSpeedInKnots(), boat.getHeading());
|
|
||||||
}
|
}
|
||||||
group.getChildren().add(boatAnnotations);
|
group.getChildren().add(boatAnnotations);
|
||||||
group.getChildren().addAll(raceObjects);
|
group.getChildren().addAll(raceObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inner class for creating point so that you can rotate it around origin point.
|
|
||||||
*/
|
|
||||||
class Point {
|
|
||||||
|
|
||||||
double x, y;
|
|
||||||
|
|
||||||
Point (double x, double y) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rotate(double angle) {
|
|
||||||
double oldX = x;
|
|
||||||
double oldY = y;
|
|
||||||
this.x = oldX * Math.cos(angle) - oldY * Math.sin(angle);
|
|
||||||
this.y = oldX * Math.sin(angle) + oldY * Math.cos(angle);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates x and y location for every marker that fits it to the canvas the race will be drawn on.
|
* Calculates x and y location for every marker that fits it to the canvas the race will be drawn on.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,14 +1,29 @@
|
|||||||
package seng302.controllers;
|
package seng302.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import seng302.models.Boat;
|
||||||
|
import seng302.models.parsers.StreamParser;
|
||||||
|
|
||||||
|
|
||||||
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.TimerTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by michaelrausch on 21/03/17.
|
* Created by michaelrausch on 21/03/17.
|
||||||
@@ -16,6 +31,20 @@ import java.util.ResourceBundle;
|
|||||||
public class Controller implements Initializable {
|
public class Controller implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
private AnchorPane contentPane;
|
private AnchorPane contentPane;
|
||||||
|
@FXML
|
||||||
|
private Label timeTillLive;
|
||||||
|
@FXML
|
||||||
|
private Button streamButton;
|
||||||
|
@FXML
|
||||||
|
private Button switchToRaceViewButton;
|
||||||
|
@FXML
|
||||||
|
private TableView teamList;
|
||||||
|
@FXML
|
||||||
|
private TableColumn boatNameCol;
|
||||||
|
@FXML
|
||||||
|
private TableColumn shortNameCol;
|
||||||
|
@FXML
|
||||||
|
private TableColumn countryCol;
|
||||||
|
|
||||||
private void setContentPane(String jfxUrl){
|
private void setContentPane(String jfxUrl){
|
||||||
try{
|
try{
|
||||||
@@ -33,5 +62,71 @@ public class Controller implements Initializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Running a timer to update the livestream status on welcome screen. Update interval is 500 miliseconds.
|
||||||
|
*/
|
||||||
|
public void startStream() {
|
||||||
|
if (StreamParser.isStreamStatus()) {
|
||||||
|
streamButton.setVisible(false);
|
||||||
|
timeTillLive.setVisible(true);
|
||||||
|
timeTillLive.setTextFill(Color.GREEN);
|
||||||
|
timeTillLive.setText("Connecting...");
|
||||||
|
Timer timer = new Timer();
|
||||||
|
timer.scheduleAtFixedRate(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (StreamParser.isRaceFinished()) {
|
||||||
|
timeTillLive.setTextFill(Color.RED);
|
||||||
|
timeTillLive.setText("Race finished! Waiting for new race...");
|
||||||
|
switchToRaceViewButton.setDisable(true);
|
||||||
|
} else if (StreamParser.getTimeSinceStart() > 0 && StreamParser.getTimeSinceStart() % 10 == 0) {
|
||||||
|
updateTeamList();
|
||||||
|
timeTillLive.setTextFill(Color.RED);
|
||||||
|
switchToRaceViewButton.setDisable(false);
|
||||||
|
Long timerMinute = StreamParser.getTimeSinceStart() / 60;
|
||||||
|
Long timerSecond = StreamParser.getTimeSinceStart() % 60;
|
||||||
|
String timerString = "-" + timerMinute + "." + timerSecond + " minutes";
|
||||||
|
timeTillLive.setText(timerString);
|
||||||
|
} else if (StreamParser.getTimeSinceStart() % 10 == 0) {
|
||||||
|
updateTeamList();
|
||||||
|
timeTillLive.setTextFill(Color.BLACK);
|
||||||
|
switchToRaceViewButton.setDisable(false);
|
||||||
|
Long timerMinute = -1 * StreamParser.getTimeSinceStart() / 60;
|
||||||
|
Long timerSecond = -1 * StreamParser.getTimeSinceStart() % 60;
|
||||||
|
String timerString = timerMinute + "." + timerSecond + " minutes";
|
||||||
|
timeTillLive.setText(timerString);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 0, 500);
|
||||||
|
} else {
|
||||||
|
timeTillLive.setText("Stream not available.");
|
||||||
|
timeTillLive.setTextFill(Color.RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void switchToRaceView() {
|
||||||
|
setContentPane("/views/RaceView.fxml");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTeamList() {
|
||||||
|
ObservableList<Boat> data = FXCollections.observableArrayList();
|
||||||
|
teamList.setItems(data);
|
||||||
|
boatNameCol.setCellValueFactory(
|
||||||
|
new PropertyValueFactory<Boat,String>("boatName")
|
||||||
|
);
|
||||||
|
shortNameCol.setCellValueFactory(
|
||||||
|
new PropertyValueFactory<Boat,String>("shortName")
|
||||||
|
);
|
||||||
|
countryCol.setCellValueFactory(
|
||||||
|
new PropertyValueFactory<Boat,String>("country")
|
||||||
|
);
|
||||||
|
for (Boat boat : StreamParser.getBoats()) {
|
||||||
|
data.add(boat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,17 @@ import javafx.event.ActionEvent;
|
|||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
|
import javafx.scene.control.Slider;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import javafx.util.StringConverter;
|
||||||
import seng302.models.*;
|
import seng302.models.*;
|
||||||
import seng302.models.parsers.ConfigParser;
|
import seng302.models.parsers.ConfigParser;
|
||||||
|
import seng302.models.parsers.StreamParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -27,7 +31,7 @@ public class RaceViewController extends Thread{
|
|||||||
@FXML
|
@FXML
|
||||||
private VBox positionVbox;
|
private VBox positionVbox;
|
||||||
@FXML
|
@FXML
|
||||||
private CheckBox toggleAnnotation, toggleFps;
|
private CheckBox toggleFps;
|
||||||
@FXML
|
@FXML
|
||||||
private Text timerLabel;
|
private Text timerLabel;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -35,10 +39,11 @@ public class RaceViewController extends Thread{
|
|||||||
@FXML
|
@FXML
|
||||||
private Text windArrowText, windDirectionText;
|
private Text windArrowText, windDirectionText;
|
||||||
@FXML
|
@FXML
|
||||||
|
private Slider annotationSlider;
|
||||||
|
@FXML
|
||||||
private CanvasController includedCanvasController;
|
private CanvasController includedCanvasController;
|
||||||
|
|
||||||
private ArrayList<Boat> startingBoats = new ArrayList<>();
|
private ArrayList<Boat> startingBoats = new ArrayList<>();
|
||||||
private boolean displayAnnotations;
|
|
||||||
private boolean displayFps;
|
private boolean displayFps;
|
||||||
private Timeline timerTimeline;
|
private Timeline timerTimeline;
|
||||||
private Map<Boat, TimelineInfo> timelineInfos = new HashMap<>();
|
private Map<Boat, TimelineInfo> timelineInfos = new HashMap<>();
|
||||||
@@ -62,7 +67,7 @@ public class RaceViewController extends Thread{
|
|||||||
|
|
||||||
includedCanvasController.setup(this);
|
includedCanvasController.setup(this);
|
||||||
includedCanvasController.initializeCanvas();
|
includedCanvasController.initializeCanvas();
|
||||||
//initializeTimer();
|
initializeTimer();
|
||||||
initializeSettings();
|
initializeSettings();
|
||||||
|
|
||||||
//set wind direction!!!!!!! can't find another place to put my code --haoming
|
//set wind direction!!!!!!! can't find another place to put my code --haoming
|
||||||
@@ -74,22 +79,50 @@ public class RaceViewController extends Thread{
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void initializeSettings(){
|
private void initializeSettings() {
|
||||||
displayAnnotations = true;
|
|
||||||
displayFps = true;
|
displayFps = true;
|
||||||
|
|
||||||
toggleAnnotation.selectedProperty().addListener(new ChangeListener<Boolean>() {
|
|
||||||
@Override
|
|
||||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
|
|
||||||
displayAnnotations = !displayAnnotations;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//SLIFER STUFF BELOW
|
||||||
|
annotationSlider.setLabelFormatter(new StringConverter<Double>() {
|
||||||
|
@Override
|
||||||
|
public String toString(Double n) {
|
||||||
|
if (n == 0) return "None";
|
||||||
|
if (n == 1) return "Low";
|
||||||
|
if (n == 2) return "Medium";
|
||||||
|
if (n == 3) return "All";
|
||||||
|
|
||||||
|
return "All";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double fromString(String s) {
|
||||||
|
switch (s) {
|
||||||
|
case "None":
|
||||||
|
return 0d;
|
||||||
|
case "Low":
|
||||||
|
return 1d;
|
||||||
|
case "Medium":
|
||||||
|
return 2d;
|
||||||
|
case "All":
|
||||||
|
return 3d;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 3d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
annotationSlider.valueProperty().addListener((obs, oldval, newVal) ->
|
||||||
|
setAnnotations((int)annotationSlider.getValue()));
|
||||||
|
|
||||||
|
annotationSlider.setValue(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTimer(){
|
private void initializeTimer(){
|
||||||
@@ -99,12 +132,11 @@ public class RaceViewController extends Thread{
|
|||||||
timerTimeline.getKeyFrames().add(
|
timerTimeline.getKeyFrames().add(
|
||||||
new KeyFrame(Duration.seconds(1),
|
new KeyFrame(Duration.seconds(1),
|
||||||
event -> {
|
event -> {
|
||||||
// Stop timer if race is finished
|
if (StreamParser.isRaceFinished()) {
|
||||||
if (this.race.isRaceFinished()) {
|
timerLabel.setFill(Color.RED);
|
||||||
this.timerTimeline.stop();
|
timerLabel.setText("Race Finished!");
|
||||||
} else {
|
} else {
|
||||||
timerLabel.setText(convertTimeToMinutesSeconds(race.getRaceTime()));
|
timerLabel.setText(currentTimer());
|
||||||
this.race.incrementRaceTime();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -259,6 +291,20 @@ public class RaceViewController extends Thread{
|
|||||||
return String.format("%02d:%02d", time / 60, time % 60);
|
return String.format("%02d:%02d", time / 60, time % 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String currentTimer() {
|
||||||
|
String timerString = "0:00 minutes";
|
||||||
|
if (StreamParser.getTimeSinceStart() > 0 && StreamParser.getTimeSinceStart() % 10 == 0) {
|
||||||
|
Long timerMinute = StreamParser.getTimeSinceStart() / 60;
|
||||||
|
Long timerSecond = StreamParser.getTimeSinceStart() % 60;
|
||||||
|
timerString = "-" + timerMinute + "." + timerSecond + " minutes";
|
||||||
|
} else if (StreamParser.getTimeSinceStart() % 10 == 0) {
|
||||||
|
Long timerMinute = -1 * StreamParser.getTimeSinceStart() / 60;
|
||||||
|
Long timerSecond = -1 * StreamParser.getTimeSinceStart() % 60;
|
||||||
|
timerString = timerMinute + "." + timerSecond + " minutes";
|
||||||
|
}
|
||||||
|
return timerString;
|
||||||
|
}
|
||||||
|
|
||||||
public void stopTimer() {
|
public void stopTimer() {
|
||||||
timerTimeline.stop();
|
timerTimeline.stop();
|
||||||
}
|
}
|
||||||
@@ -270,10 +316,6 @@ public class RaceViewController extends Thread{
|
|||||||
return displayFps;
|
return displayFps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDisplayAnnotations() {
|
|
||||||
return displayAnnotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Race getRace() {
|
public Race getRace() {
|
||||||
return race;
|
return race;
|
||||||
}
|
}
|
||||||
@@ -286,10 +328,54 @@ public class RaceViewController extends Thread{
|
|||||||
return startingBoats;
|
return startingBoats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void toggleAnnotations () {
|
private void setAnnotations(Integer annotationLevel) {
|
||||||
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
switch (annotationLevel) {
|
||||||
ro.toggleAnnotations();
|
case 0:
|
||||||
|
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
||||||
|
if(ro instanceof BoatGroup) {
|
||||||
|
BoatGroup bg = (BoatGroup) ro;
|
||||||
|
bg.setTeamNameObjectVisible(false);
|
||||||
|
bg.setVelocityObjectVisible(false);
|
||||||
|
bg.setLineGroupVisible(false);
|
||||||
|
bg.setWakeVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
||||||
|
if(ro instanceof BoatGroup) {
|
||||||
|
BoatGroup bg = (BoatGroup) ro;
|
||||||
|
bg.setTeamNameObjectVisible(true);
|
||||||
|
bg.setVelocityObjectVisible(false);
|
||||||
|
bg.setLineGroupVisible(false);
|
||||||
|
bg.setWakeVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
||||||
|
if(ro instanceof BoatGroup) {
|
||||||
|
BoatGroup bg = (BoatGroup) ro;
|
||||||
|
bg.setTeamNameObjectVisible(true);
|
||||||
|
bg.setVelocityObjectVisible(false);
|
||||||
|
bg.setLineGroupVisible(true);
|
||||||
|
bg.setWakeVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
||||||
|
if(ro instanceof BoatGroup) {
|
||||||
|
BoatGroup bg = (BoatGroup) ro;
|
||||||
|
bg.setTeamNameObjectVisible(true);
|
||||||
|
bg.setVelocityObjectVisible(true);
|
||||||
|
bg.setLineGroupVisible(true);
|
||||||
|
bg.setWakeVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,10 @@ public class Boat {
|
|||||||
private int markLastPast;
|
private int markLastPast;
|
||||||
private String shortName;
|
private String shortName;
|
||||||
private int id;
|
private int id;
|
||||||
|
// new attributes to boat
|
||||||
|
private int sourceID;
|
||||||
|
private String boatName;
|
||||||
|
private String country;
|
||||||
|
|
||||||
public Boat(String teamName) {
|
public Boat(String teamName) {
|
||||||
this.teamName = teamName;
|
this.teamName = teamName;
|
||||||
@@ -45,6 +49,21 @@ public class Boat {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New instance created by BoatsParser.
|
||||||
|
*
|
||||||
|
* @param sourceID source ID of the boat
|
||||||
|
* @param boatName full name of the boat
|
||||||
|
* @param shortName short name of the boat
|
||||||
|
* @param country country of the boat
|
||||||
|
*/
|
||||||
|
public Boat(int sourceID, String boatName, String shortName, String country) {
|
||||||
|
this.sourceID = sourceID;
|
||||||
|
this.boatName = boatName;
|
||||||
|
this.shortName = shortName;
|
||||||
|
this.country = country;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the team sailing the boat
|
* Returns the name of the team sailing the boat
|
||||||
*
|
*
|
||||||
@@ -141,4 +160,15 @@ public class Boat {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSourceID() {
|
||||||
|
return sourceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBoatName() {
|
||||||
|
return boatName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCountry() {
|
||||||
|
return country;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,9 @@ import javafx.scene.transform.Rotate;
|
|||||||
import seng302.models.parsers.StreamParser;
|
import seng302.models.parsers.StreamParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by CJIRWIN on 25/04/2017.
|
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 dimensional boat.
|
||||||
|
* It contains a single polygon for the boat, a group of lines to show it's path, a wake object and two text labels to
|
||||||
|
* annotate the boat teams name and the boats velocity.
|
||||||
*/
|
*/
|
||||||
public class BoatGroup extends RaceObject{
|
public class BoatGroup extends RaceObject{
|
||||||
|
|
||||||
@@ -18,37 +20,50 @@ public class BoatGroup extends RaceObject{
|
|||||||
private static final double TEAMNAME_Y_OFFSET = -15d;
|
private static final double TEAMNAME_Y_OFFSET = -15d;
|
||||||
private static final double VELOCITY_X_OFFSET = 10d;
|
private static final double VELOCITY_X_OFFSET = 10d;
|
||||||
private static final double VELOCITY_Y_OFFSET = -5d;
|
private static final double VELOCITY_Y_OFFSET = -5d;
|
||||||
private static final double VELOCITY_WAKE_RATIO = 2d;
|
|
||||||
private static final double BOAT_HEIGHT = 15d;
|
private static final double BOAT_HEIGHT = 15d;
|
||||||
private static final double BOAT_WIDTH = 10d;
|
private static final double BOAT_WIDTH = 10d;
|
||||||
private static final int LINE_INTERVAL = 180;
|
|
||||||
private static double expectedUpdateInterval = 200;
|
private static double expectedUpdateInterval = 200;
|
||||||
private static int WAKE_FRAME_INTERVAL = 30;
|
|
||||||
private double framesForNewLine = 0;
|
|
||||||
private boolean destinationSet;
|
private boolean destinationSet;
|
||||||
private Point2D lastPoint;
|
private Point2D lastPoint;
|
||||||
private int wakeGenerationDelay;
|
private int wakeGenerationDelay = 10;
|
||||||
|
private double distanceTravelled;
|
||||||
|
|
||||||
private Boat boat;
|
private Boat boat;
|
||||||
private int wakeCounter = WAKE_FRAME_INTERVAL;
|
|
||||||
private Group lineGroup = new Group();
|
private Group lineGroup = new Group();
|
||||||
private Group wakeGroup = new Group();
|
|
||||||
private Polygon boatPoly;
|
private Polygon boatPoly;
|
||||||
private Polygon wakePoly;
|
|
||||||
private Text teamNameObject;
|
private Text teamNameObject;
|
||||||
private Text velocityObject;
|
private Text velocityObject;
|
||||||
private Wake wake;
|
private Wake wake;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BoatGroup with the default triangular boat polygon.
|
||||||
|
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which
|
||||||
|
* BoatGroup to update.
|
||||||
|
* @param color The colour of the boat polygon and the trailing line.
|
||||||
|
*/
|
||||||
public BoatGroup (Boat boat, Color color){
|
public BoatGroup (Boat boat, Color color){
|
||||||
this.boat = boat;
|
this.boat = boat;
|
||||||
initChildren(color);
|
initChildren(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BoatGroup with the boat being the default polygon. The head of the boat should be at point (0,0).
|
||||||
|
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which
|
||||||
|
* BoatGroup to update.
|
||||||
|
* @param color The colour of the boat polygon and the trailing line.
|
||||||
|
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon.
|
||||||
|
*/
|
||||||
public BoatGroup (Boat boat, Color color, double... points)
|
public BoatGroup (Boat boat, Color color, double... points)
|
||||||
{
|
{
|
||||||
|
this.boat = boat;
|
||||||
initChildren(color, points);
|
initChildren(color, points);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the javafx objects that will be the in the group by default.
|
||||||
|
* @param color The colour of the boat polygon and the trailing line.
|
||||||
|
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon.
|
||||||
|
*/
|
||||||
private void initChildren (Color color, double... points) {
|
private void initChildren (Color color, double... points) {
|
||||||
boatPoly = new Polygon(points);
|
boatPoly = new Polygon(points);
|
||||||
boatPoly.setFill(color);
|
boatPoly.setFill(color);
|
||||||
@@ -65,16 +80,19 @@ public class BoatGroup extends RaceObject{
|
|||||||
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
||||||
destinationSet = false;
|
destinationSet = false;
|
||||||
|
|
||||||
wake = new Wake(0, 0);
|
wake = new Wake(0, -BOAT_HEIGHT);
|
||||||
wakeGenerationDelay = wake.numWakes;
|
|
||||||
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly);
|
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the javafx objects that will be the in the group by default.
|
||||||
|
* @param color The colour of the boat polygon and the trailing line.
|
||||||
|
*/
|
||||||
private void initChildren (Color color) {
|
private void initChildren (Color color) {
|
||||||
initChildren(color,
|
initChildren(color,
|
||||||
-BOAT_WIDTH / 2, BOAT_HEIGHT,
|
-BOAT_WIDTH / 2, BOAT_HEIGHT / 2,
|
||||||
0.0, 0.0,
|
0.0, -BOAT_HEIGHT / 2,
|
||||||
BOAT_WIDTH / 2, BOAT_HEIGHT);
|
BOAT_WIDTH / 2, BOAT_HEIGHT / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,12 +116,18 @@ public class BoatGroup extends RaceObject{
|
|||||||
* 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) {
|
||||||
rotateTo(rotation);
|
rotateTo(rotation);
|
||||||
moveTo(x, y);
|
moveTo(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the boat and its children annotations to coordinates specified
|
||||||
|
* @param x The X coordinate to move the boat to
|
||||||
|
* @param y The Y coordinate to move the boat to
|
||||||
|
*/
|
||||||
public void moveTo (double x, double y) {
|
public void moveTo (double x, double y) {
|
||||||
boatPoly.setLayoutX(x);
|
boatPoly.setLayoutX(x);
|
||||||
boatPoly.setLayoutY(y);
|
boatPoly.setLayoutY(y);
|
||||||
@@ -116,15 +140,20 @@ public class BoatGroup extends RaceObject{
|
|||||||
wake.rotate(currentRotation);
|
wake.rotate(currentRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the position of all graphics in the BoatGroup based off of the given time interval.
|
||||||
|
* @param timeInterval The interval, in milliseconds, the boat should update it's position based on.
|
||||||
|
*/
|
||||||
public void updatePosition (long timeInterval) {
|
public void updatePosition (long timeInterval) {
|
||||||
|
//Calculate the movement of the boat.
|
||||||
double dx = pixelVelocityX * timeInterval;
|
double dx = pixelVelocityX * timeInterval;
|
||||||
double dy = pixelVelocityY * timeInterval;
|
double dy = pixelVelocityY * timeInterval;
|
||||||
double rotation = 0d;
|
double rotation = rotationalVelocity * timeInterval;
|
||||||
|
distanceTravelled += Math.abs(dx) + Math.abs(dy);
|
||||||
moveGroupBy(dx, dy, rotation);
|
moveGroupBy(dx, dy, rotation);
|
||||||
|
//Draw a new section of the trail every 20 pixels of movement.
|
||||||
if (framesForNewLine-- == 0) {
|
if (distanceTravelled > 20) {
|
||||||
framesForNewLine = LINE_INTERVAL;
|
distanceTravelled = 0;
|
||||||
if (lastPoint != null) {
|
if (lastPoint != null) {
|
||||||
Line l = new Line(
|
Line l = new Line(
|
||||||
lastPoint.getX(),
|
lastPoint.getX(),
|
||||||
@@ -132,37 +161,69 @@ public class BoatGroup extends RaceObject{
|
|||||||
boatPoly.getLayoutX(),
|
boatPoly.getLayoutX(),
|
||||||
boatPoly.getLayoutY()
|
boatPoly.getLayoutY()
|
||||||
);
|
);
|
||||||
l.getStrokeDashArray().setAll(4d, 6d);
|
l.getStrokeDashArray().setAll(3d, 7d);
|
||||||
l.setStroke(boatPoly.getFill());
|
l.setStroke(boatPoly.getFill());
|
||||||
lineGroup.getChildren().add(l);
|
lineGroup.getChildren().add(l);
|
||||||
}
|
}
|
||||||
if (destinationSet){
|
if (destinationSet){ //Only begin drawing after the first destination is set
|
||||||
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
||||||
}
|
}
|
||||||
if (lineGroup.getChildren().size() > 100)
|
|
||||||
lineGroup.getChildren().remove(0);
|
|
||||||
}
|
}
|
||||||
wake.updatePosition(timeInterval);
|
wake.updatePosition(timeInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the destination of the boat and the headng it should have once it reaches
|
||||||
|
* @param newXValue
|
||||||
|
* @param newYValue
|
||||||
|
* @param rotation Rotation to move graphics to.
|
||||||
|
* @param raceIds RaceID of the object to move.
|
||||||
|
*/
|
||||||
public void setDestination (double newXValue, double newYValue, double rotation, int... raceIds) {
|
public void setDestination (double newXValue, double newYValue, double rotation, int... raceIds) {
|
||||||
moveGroupBy(newXValue - boatPoly.getLayoutX(), newYValue - boatPoly.getLayoutY(), rotation);
|
if (hasRaceId(raceIds)) {
|
||||||
|
destinationSet = true;
|
||||||
// destinationSet = true;
|
boat.setVelocity(StreamParser.boatSpeeds.get((long)boat.getId()));
|
||||||
// boat.setVelocity(StreamParser.boatSpeeds.get((long)boat.getId()));
|
if (currentRotation < 0)
|
||||||
// if (hasRaceId(raceIds)) {
|
currentRotation = 360 - currentRotation;
|
||||||
// this.pixelVelocityX = (newXValue - boatPoly.getLayoutX()) / expectedUpdateInterval;
|
double dx = newXValue - boatPoly.getLayoutX();
|
||||||
// this.pixelVelocityY = (newYValue - boatPoly.getLayoutY()) / expectedUpdateInterval;
|
if ((dx > 0 && pixelVelocityX < 0) || (dx < 0 && pixelVelocityX > 0)) {
|
||||||
// this.rotationalGoal = rotation;
|
pixelVelocityX = 0;
|
||||||
// calculateRotationalVelocity();
|
} else {
|
||||||
// rotateTo(rotation);
|
pixelVelocityX = dx / expectedUpdateInterval;
|
||||||
// if (wakeGenerationDelay > 0) {
|
}
|
||||||
// wake.rotate(rotationalGoal);
|
double dy = newYValue - boatPoly.getLayoutY();
|
||||||
// wakeGenerationDelay--;
|
//Check movement is reasonable. Assumes a 1000 * 1000 canvas
|
||||||
|
if (Math.abs(dx) > 50 || Math.abs(dy) > 50) {
|
||||||
|
// System.out.println("dx = " + dx);
|
||||||
|
// System.out.println("dy = " + dy);
|
||||||
|
dx = 0;
|
||||||
|
dy = 0;
|
||||||
|
moveTo(newXValue, newYValue);
|
||||||
|
}
|
||||||
|
//Slight delay on changing X/Y direction that could help jitter. Disabled since there was an issue with
|
||||||
|
//packets that might be causing it.
|
||||||
|
// if ((dx > 0 && pixelVelocityX < 0) || (dx < 0 && pixelVelocityX > 0)) {
|
||||||
|
// pixelVelocityX = 0;
|
||||||
// } else {
|
// } else {
|
||||||
// wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, pixelVelocityX, pixelVelocityY);
|
// pixelVelocityX = dx / expectedUpdateInterval;
|
||||||
// }
|
// }
|
||||||
// }
|
// if ((dy > 0 && pixelVelocityY < 0) || (dy < 0 && pixelVelocityY > 0)) {
|
||||||
|
// pixelVelocityY = 0;
|
||||||
|
// } else {
|
||||||
|
// pixelVelocityY = dy / expectedUpdateInterval;
|
||||||
|
// }
|
||||||
|
pixelVelocityX = dx / expectedUpdateInterval;
|
||||||
|
pixelVelocityY = dy / expectedUpdateInterval;
|
||||||
|
rotationalGoal = rotation;
|
||||||
|
calculateRotationalVelocity();
|
||||||
|
if (wakeGenerationDelay > 0) {
|
||||||
|
wake.rotate(rotationalGoal);
|
||||||
|
wakeGenerationDelay--;
|
||||||
|
} else {
|
||||||
|
wake.setRotationalVelocity(rotationalVelocity, currentRotation, boat.getVelocity());
|
||||||
|
}
|
||||||
|
velocityObject.setText(String.format("%.2f m/s", boat.getVelocity()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDestination (double newXValue, double newYValue, int... raceIDs) {
|
public void setDestination (double newXValue, double newYValue, int... raceIDs) {
|
||||||
@@ -180,45 +241,43 @@ public class BoatGroup extends RaceObject{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resizeWake(){
|
|
||||||
velocityObject.setText(String.valueOf(boat.getVelocity()));
|
|
||||||
super.getChildren().remove(wakePoly);
|
|
||||||
wakePoly = new Polygon(
|
|
||||||
5.0,0.0,
|
|
||||||
10.0, boat.getVelocity() * VELOCITY_WAKE_RATIO,
|
|
||||||
0.0, boat.getVelocity() * VELOCITY_WAKE_RATIO
|
|
||||||
);
|
|
||||||
wakePoly.setLayoutX(boatPoly.getLayoutX());
|
|
||||||
wakePoly.setLayoutY(boatPoly.getLayoutY());
|
|
||||||
wakePoly.setFill(Color.DARKBLUE);
|
|
||||||
super.getChildren().add(wakePoly);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void rotateTo (double rotation) {
|
public void rotateTo (double rotation) {
|
||||||
currentRotation = rotation;
|
currentRotation = rotation;
|
||||||
boatPoly.getTransforms().clear();
|
boatPoly.getTransforms().clear();
|
||||||
boatPoly.getTransforms().add(new Rotate(rotation));
|
boatPoly.getTransforms().add(new Rotate(rotation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void forceRotation () {
|
public void forceRotation () {
|
||||||
rotateTo (rotationalGoal);
|
rotateTo (rotationalGoal);
|
||||||
wake.rotate(rotationalGoal);
|
wake.rotate(rotationalGoal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleAnnotations () {
|
public void setTeamNameObjectVisible(Boolean visible) {
|
||||||
teamNameObject.setVisible(!teamNameObject.isVisible());
|
teamNameObject.setVisible(visible);
|
||||||
velocityObject.setVisible(!velocityObject.isVisible());
|
}
|
||||||
lineGroup.setVisible(!lineGroup.isVisible());
|
|
||||||
wake.setVisible(!wake.isVisible());
|
public void setVelocityObjectVisible(Boolean visible) {
|
||||||
|
velocityObject.setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLineGroupVisible(Boolean visible) {
|
||||||
|
lineGroup.setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWakeVisible(Boolean visible) {
|
||||||
|
wake.setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boat getBoat() {
|
public Boat getBoat() {
|
||||||
return boat;
|
return boat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this BoatGroup contains at least one of the given IDs.
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
public boolean hasRaceId (int... raceIds) {
|
public boolean hasRaceId (int... raceIds) {
|
||||||
for (int id : raceIds) {
|
for (int id : raceIds) {
|
||||||
if (id == boat.getId())
|
if (id == boat.getId())
|
||||||
@@ -227,10 +286,22 @@ public class BoatGroup extends RaceObject{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
public int[] getRaceIds () {
|
public int[] getRaceIds () {
|
||||||
return new int[] {boat.getId()};
|
return new int[] {boat.getId()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Due to javaFX limitations annotations associated with a boat that you want to appear below all boats in the
|
||||||
|
* Z-axis need to be pulled out of the BoatGroup and added to the parent group of the BoatGroups. This function
|
||||||
|
* returns these annotations as a group.
|
||||||
|
*
|
||||||
|
* @return A group containing low priority annotations.
|
||||||
|
*/
|
||||||
public Group getLowPriorityAnnotations () {
|
public Group getLowPriorityAnnotations () {
|
||||||
Group group = new Group();
|
Group group = new Group();
|
||||||
group.getChildren().addAll(wake, lineGroup);
|
group.getChildren().addAll(wake, lineGroup);
|
||||||
|
|||||||
@@ -26,10 +26,16 @@ public abstract class RaceObject extends Group {
|
|||||||
return expectedUpdateInterval;
|
return expectedUpdateInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
public static void setExpectedUpdateInterval(double expectedUpdateInterval) {
|
public static void setExpectedUpdateInterval(double expectedUpdateInterval) {
|
||||||
RaceObject.expectedUpdateInterval = expectedUpdateInterval;
|
RaceObject.expectedUpdateInterval = expectedUpdateInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the rotational velocity required to reach the rotationalGoal from the currentRotation.
|
||||||
|
*/
|
||||||
protected void calculateRotationalVelocity () {
|
protected void calculateRotationalVelocity () {
|
||||||
if (Math.abs(rotationalGoal - currentRotation) > 180) {
|
if (Math.abs(rotationalGoal - currentRotation) > 180) {
|
||||||
if (rotationalGoal - currentRotation >= 0) {
|
if (rotationalGoal - currentRotation >= 0) {
|
||||||
@@ -40,18 +46,29 @@ public abstract class RaceObject extends Group {
|
|||||||
} else {
|
} else {
|
||||||
this.rotationalVelocity = (rotationalGoal - currentRotation) / expectedUpdateInterval;
|
this.rotationalVelocity = (rotationalGoal - currentRotation) / expectedUpdateInterval;
|
||||||
}
|
}
|
||||||
|
//Sometimes the rotation is too large to be realistic. In that case just do it instantly.
|
||||||
|
if (Math.abs(rotationalVelocity) > 1) {
|
||||||
|
rotationalVelocity = 0;
|
||||||
|
rotateTo(rotationalGoal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the destination of everything within the RaceObject that has an ID in the array raceIds. The destination is
|
* Sets the destination of everything within the RaceObject that has an ID in the array raceIds. The destination is
|
||||||
* set to the co-ordinates (x, y) with the given rotation.
|
* set to the co-ordinates (x, y) with the given rotation.
|
||||||
* @param x
|
* @param x X co-ordinate to move the graphics to.
|
||||||
* @param y
|
* @param y Y co-ordinate to move the graphics to.
|
||||||
* @param rotation
|
* @param rotation Rotation to move graphics to.
|
||||||
* @param raceIds
|
* @param raceIds RaceID of the object to move.
|
||||||
*/
|
*/
|
||||||
public abstract void setDestination (double x, double y, double rotation, int... raceIds);
|
public abstract void setDestination (double x, double y, double rotation, int... raceIds);
|
||||||
|
/**
|
||||||
|
* Sets the destination of everything within the RaceObject that has an ID in the array raceIds. The destination is
|
||||||
|
* set to the co-ordinates (x, y).
|
||||||
|
* @param x X co-ordinate to move the graphic to.
|
||||||
|
* @param y Y co-ordinate to move the graphic to.
|
||||||
|
* @param raceIds RaceID to the object to move.
|
||||||
|
*/
|
||||||
public abstract void setDestination (double x, double y, int... raceIds);
|
public abstract void setDestination (double x, double y, int... raceIds);
|
||||||
|
|
||||||
public abstract void updatePosition (long timeInterval);
|
public abstract void updatePosition (long timeInterval);
|
||||||
@@ -67,6 +84,4 @@ public abstract class RaceObject extends Group {
|
|||||||
public abstract boolean hasRaceId (int... raceIds);
|
public abstract boolean hasRaceId (int... raceIds);
|
||||||
|
|
||||||
public abstract int[] getRaceIds ();
|
public abstract int[] getRaceIds ();
|
||||||
|
|
||||||
public abstract void toggleAnnotations ();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ import javafx.scene.transform.Rotate;
|
|||||||
*/
|
*/
|
||||||
class Wake extends Group {
|
class Wake extends Group {
|
||||||
|
|
||||||
final int numWakes = 5;
|
private int numWakes = 5;
|
||||||
private double[] velocities = new double[13];
|
private double[] velocities = new double[13];
|
||||||
private Arc[] arcs = new Arc[numWakes];
|
private Arc[] arcs = new Arc[numWakes];
|
||||||
private double[] rotations = new double[numWakes];
|
private double[] rotations = new double[numWakes];
|
||||||
private int[] velocityIndices = new int[numWakes];
|
private int[] velocityIndices = new int[numWakes];
|
||||||
private double sum = 0;
|
private double sum = 0;
|
||||||
|
private static double max;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a wake at the given location.
|
* Create a wake at the given location.
|
||||||
@@ -46,11 +47,19 @@ class Wake extends Group {
|
|||||||
* Sets the rotationalVelocity of each arc. Each arc is 3 velocities behind the next smallest arc. The smallest uses
|
* Sets the rotationalVelocity of each arc. Each arc is 3 velocities behind the next smallest arc. The smallest uses
|
||||||
* the latest given velocity.
|
* the latest given velocity.
|
||||||
* @param rotationalVelocity The rotationalVelocity the wake should move at.
|
* @param rotationalVelocity The rotationalVelocity the wake should move at.
|
||||||
|
* @param rotationGoal Where the wake will rotate to if the wake is calculated to be on a straight section. This is
|
||||||
|
* used to prevent desynchronisation with the Boat polygon.
|
||||||
|
* @param velocity The real world velocity of the boat in m/s.
|
||||||
*/
|
*/
|
||||||
void setRotationalVelocity (double rotationalVelocity, double rotationGoal, double velocityX, double velocityY) {
|
void setRotationalVelocity (double rotationalVelocity, double rotationGoal, double velocity) {
|
||||||
sum -= Math.abs(velocities[velocityIndices[0]]);
|
// if (Math.abs(rotationalVelocity) > 0.5) {
|
||||||
|
// rotationalVelocity = 0;
|
||||||
|
// }
|
||||||
|
sum -= Math.abs(velocities[(velocityIndices[0] + 10) % 13]);
|
||||||
sum += Math.abs(rotationalVelocity);
|
sum += Math.abs(rotationalVelocity);
|
||||||
if (sum < 0.0001)
|
// System.out.println("sum = " + sum);
|
||||||
|
max = Math.max(max, rotationalVelocity);
|
||||||
|
if (sum < max)
|
||||||
rotate (rotationGoal); //In relatively straight segments the wake snaps to match the boats current position.
|
rotate (rotationGoal); //In relatively straight segments the wake snaps to match the boats current position.
|
||||||
//This stops the wake from eventually becoming out of sync with the boat.
|
//This stops the wake from eventually becoming out of sync with the boat.
|
||||||
|
|
||||||
@@ -61,14 +70,14 @@ class Wake extends Group {
|
|||||||
for (int i = 1; i < numWakes; i++)
|
for (int i = 1; i < numWakes; i++)
|
||||||
velocityIndices[i] = (velocityIndices[0] + 3 * i) % 13;
|
velocityIndices[i] = (velocityIndices[0] + 3 * i) % 13;
|
||||||
|
|
||||||
//Scale wakes based on velocity. Assumes boats are always moving at a decent pace.
|
//Scale wakes based on velocity.
|
||||||
double scaleFactor = Math.abs(Math.log10(Math.abs(velocityX) + Math.abs(velocityY)));
|
double baseRad = 20;
|
||||||
double baseRad = 30;
|
double rad;
|
||||||
for (Arc arc :arcs) {
|
for (Arc arc :arcs) {
|
||||||
double rad = Math.min(baseRad + 4 * scaleFactor, baseRad + 12);
|
rad = baseRad + velocity;
|
||||||
arc.setRadiusX(rad);
|
arc.setRadiusX(rad);
|
||||||
arc.setRadiusY(rad);
|
arc.setRadiusY(rad);
|
||||||
baseRad += 10;
|
baseRad += 5 + (velocity / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ public abstract class Mark {
|
|||||||
* @param name the name of the mark
|
* @param name the name of the mark
|
||||||
* @param markType the type of mark. either GATE_MARK or SINGLE_MARK.
|
* @param markType the type of mark. either GATE_MARK or SINGLE_MARK.
|
||||||
*/
|
*/
|
||||||
public Mark (String name, MarkType markType) {
|
public Mark (String name, MarkType markType, int id) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.markType = markType;
|
this.markType = markType;
|
||||||
id = 0;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mark(String name, MarkType markType, double latitude, double longitude) {
|
public Mark(String name, MarkType markType, double latitude, double longitude) {
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ public class MarkGroup extends RaceObject {
|
|||||||
private Point2D[] nodeDestinations;
|
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;
|
||||||
@@ -36,33 +39,58 @@ public class MarkGroup extends RaceObject {
|
|||||||
} else if (mark.getName().equals("Finish")){
|
} else if (mark.getName().equals("Finish")){
|
||||||
color = Color.RED;
|
color = Color.RED;
|
||||||
}
|
}
|
||||||
System.out.println("HERE ARE THE CHILDREN LOL");
|
Circle markCircle;
|
||||||
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
||||||
super.getChildren().add(new Circle(0, 0, MARK_RADIUS, color));
|
markCircle = new Circle(
|
||||||
|
points[0].getX(),
|
||||||
|
points[0].getY(),
|
||||||
|
MARK_RADIUS,
|
||||||
|
color
|
||||||
|
);
|
||||||
|
nodeDestinations = new Point2D[]{
|
||||||
|
new Point2D(markCircle.getCenterX(), markCircle.getCenterY()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
super.getChildren().add(markCircle);
|
||||||
} else {
|
} else {
|
||||||
marks.add(((GateMark) mark).getSingleMark1());
|
marks.add(((GateMark) mark).getSingleMark1());
|
||||||
marks.add(((GateMark) mark).getSingleMark2());
|
marks.add(((GateMark) mark).getSingleMark2());
|
||||||
super.getChildren().add(
|
nodePixelVelocitiesX = new double[]{0d,0d};
|
||||||
new Circle(
|
nodePixelVelocitiesY = new double[]{0d,0d};
|
||||||
(points[1].getX() - points[0].getX()) / 2d,
|
nodeDestinations = new Point2D[2];
|
||||||
(points[1].getY() - points[0].getY()) / 2d,
|
// markCircle = new Circle(
|
||||||
MARK_RADIUS,
|
// (points[1].getX() - points[0].getX()) / 2d,
|
||||||
color
|
// (points[1].getY() - points[0].getY()) / 2d,
|
||||||
)
|
// MARK_RADIUS,
|
||||||
|
// color
|
||||||
|
//
|
||||||
|
markCircle = new Circle(
|
||||||
|
points[0].getX(),
|
||||||
|
points[0].getY(),
|
||||||
|
MARK_RADIUS,
|
||||||
|
color
|
||||||
);
|
);
|
||||||
super.getChildren().add(
|
nodeDestinations[0] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY());
|
||||||
new Circle(
|
super.getChildren().add(markCircle);
|
||||||
-(points[1].getX() - points[0].getX()) / 2d,
|
// markCircle = new Circle(
|
||||||
-(points[1].getY() - points[0].getY()) / 2d,
|
// -(points[1].getX() - points[0].getX()) / 2d,
|
||||||
MARK_RADIUS,
|
// -(points[1].getY() - points[0].getY()) / 2d,
|
||||||
color
|
// MARK_RADIUS,
|
||||||
)
|
// color
|
||||||
|
// );
|
||||||
|
markCircle = new Circle(
|
||||||
|
points[1].getX(),
|
||||||
|
points[1].getY(),
|
||||||
|
MARK_RADIUS,
|
||||||
|
color
|
||||||
);
|
);
|
||||||
|
nodeDestinations[1] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY());
|
||||||
|
super.getChildren().add(markCircle);
|
||||||
Line line = new Line(
|
Line line = new Line(
|
||||||
(points[1].getX() - points[0].getX()) / 2d,
|
points[0].getX(),
|
||||||
(points[1].getY() - points[0].getY()) / 2d,
|
points[0].getY(),
|
||||||
-(points[1].getX() - points[0].getX()) / 2d,
|
points[1].getX(),
|
||||||
-(points[1].getY() - points[0].getY()) / 2d
|
points[1].getY()
|
||||||
);
|
);
|
||||||
line.setStrokeWidth(LINE_THICKNESS);
|
line.setStrokeWidth(LINE_THICKNESS);
|
||||||
line.setStroke(color);
|
line.setStroke(color);
|
||||||
@@ -70,14 +98,8 @@ public class MarkGroup extends RaceObject {
|
|||||||
line.getStrokeDashArray().addAll(DASHED_GAP_LEN, DASHED_LINE_LEN);
|
line.getStrokeDashArray().addAll(DASHED_GAP_LEN, DASHED_LINE_LEN);
|
||||||
}
|
}
|
||||||
super.getChildren().add(line);
|
super.getChildren().add(line);
|
||||||
nodePixelVelocitiesX = new double[]{0d,0d};
|
|
||||||
nodePixelVelocitiesY = new double[]{0d,0d};
|
|
||||||
nodeDestinations = new Point2D[]{
|
|
||||||
new Point2D(super.getChildren().get(0).getLayoutX(), super.getChildren().get(0).getLayoutY()),
|
|
||||||
new Point2D(super.getChildren().get(1).getLayoutX(), super.getChildren().get(1).getLayoutY())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
moveTo(points[0].getX(), points[0].getY());
|
//moveTo(points[0].getX(), points[0].getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDestination (double x, double y, double rotation, int... raceIds) {
|
public void setDestination (double x, double y, double rotation, int... raceIds) {
|
||||||
@@ -87,88 +109,90 @@ public class MarkGroup extends RaceObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setDestination (double x, double y, int... raceIds) {
|
public void setDestination (double x, double y, int... raceIds) {
|
||||||
int childrenIndex = -1;
|
for (int i = 0; i < marks.size(); i++)
|
||||||
for (Mark mark : marks) {
|
|
||||||
for (int id : raceIds)
|
for (int id : raceIds)
|
||||||
if (id == mark.getId() && childrenIndex != -1)
|
if (id == marks.get(i).getId())
|
||||||
setDestinationChild(x, y, childrenIndex);
|
setDestinationChild(x, y, Math.max(0, i-1));
|
||||||
else if (id == mark.getId())
|
|
||||||
setDestinationGroup(x, y);
|
|
||||||
childrenIndex++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setDestinationChild (double x, double y, int childIndex) {
|
private void setDestinationChild (double x, double y, int childIndex) {
|
||||||
double relativeX = x - super.getLayoutX();
|
//double relativeX = x - super.getLayoutX();
|
||||||
double relativeY = y - super.getLayoutY();
|
//double relativeY = y - super.getLayoutY();
|
||||||
this.nodeDestinations[childIndex] = new Point2D(relativeX, relativeY);
|
Circle markCircle = (Circle) super.getChildren().get(childIndex);
|
||||||
this.nodePixelVelocitiesX[childIndex] = (relativeX - super.getChildren().get(childIndex).getLayoutX()) / expectedUpdateInterval;
|
this.nodeDestinations[childIndex] = new Point2D(x, y);
|
||||||
this.nodePixelVelocitiesY[childIndex] = (relativeY - super.getChildren().get(childIndex).getLayoutY()) / expectedUpdateInterval;
|
//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;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDestinationGroup (double x, double y) {
|
|
||||||
pixelVelocityX = (x - super.getLayoutX()) / expectedUpdateInterval;
|
|
||||||
pixelVelocityY = (y - super.getLayoutY()) / expectedUpdateInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void rotateTo (double rotation) {
|
public void rotateTo (double rotation) {
|
||||||
super.getTransforms().clear();
|
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
|
||||||
super.getTransforms().add(new Rotate(rotation));
|
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) {
|
public void updatePosition (long timeInterval) {
|
||||||
double x = pixelVelocityX * timeInterval;
|
Circle markCircle = (Circle) super.getChildren().get(0);
|
||||||
double y = pixelVelocityY * timeInterval;
|
|
||||||
double rotation = rotationalVelocity * timeInterval;
|
if (nodePixelVelocitiesX[0] > 0 && markCircle.getCenterX() > nodeDestinations[0].getX() ||
|
||||||
moveGroupBy(x, y, rotation);
|
nodePixelVelocitiesX[0] < 0 && markCircle.getCenterX() < nodeDestinations[0].getY())
|
||||||
updateChildren(timeInterval);
|
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) {
|
public void moveGroupBy (double x, double y, double rotation) {
|
||||||
super.setLayoutX(super.getLayoutX() + x);
|
|
||||||
super.setLayoutY(super.getLayoutY() + y);
|
|
||||||
rotateTo(rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateChildren (double timeInterval) {
|
|
||||||
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
|
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 {
|
||||||
Circle mark = (Circle) super.getChildren().get(0);
|
Circle mark = (Circle) super.getChildren().get(0);
|
||||||
if (nodePixelVelocitiesX[0] > 0 && mark.getLayoutX() >= nodeDestinations[0].getX()) {
|
mark.setCenterY(mark.getCenterY() + y);
|
||||||
nodePixelVelocitiesX[0] = 0;
|
mark.setCenterX(mark.getCenterX() + x);
|
||||||
} else if (nodePixelVelocitiesX[0] < 0 && mark.getLayoutX() <= nodeDestinations[0].getX()) {
|
|
||||||
nodePixelVelocitiesX[0] = 0;
|
|
||||||
} else {
|
|
||||||
mark.setLayoutX(mark.getLayoutX() + nodePixelVelocitiesX[0] * timeInterval);
|
|
||||||
mark.setLayoutY(mark.getLayoutY() + nodePixelVelocitiesY[0] * timeInterval);
|
|
||||||
}
|
|
||||||
if (nodePixelVelocitiesY[0] >= 0 && mark.getLayoutY() > nodeDestinations[0].getY()) {
|
|
||||||
nodePixelVelocitiesY[0] = 0;
|
|
||||||
} else if (nodePixelVelocitiesY[0] < 0 && mark.getLayoutY() <= nodeDestinations[0].getY()) {
|
|
||||||
nodePixelVelocitiesY[0] = 0;
|
|
||||||
} else {
|
|
||||||
mark.setLayoutX(mark.getLayoutX() + nodePixelVelocitiesX[0] * timeInterval);
|
|
||||||
mark.setLayoutY(mark.getLayoutY() + nodePixelVelocitiesY[0] * timeInterval);
|
|
||||||
}
|
|
||||||
mark = (Circle) super.getChildren().get(1);
|
|
||||||
if (nodePixelVelocitiesX[1] > 0 && mark.getLayoutX() >= nodeDestinations[1].getX()) {
|
|
||||||
nodePixelVelocitiesX[1] = 0;
|
|
||||||
} else if (nodePixelVelocitiesX[1] < 0 && mark.getLayoutX() <= nodeDestinations[1].getX()) {
|
|
||||||
nodePixelVelocitiesX[1] = 0;
|
|
||||||
} else {
|
|
||||||
mark.setLayoutX(mark.getLayoutX() + nodePixelVelocitiesX[1] * timeInterval);
|
|
||||||
mark.setLayoutY(mark.getLayoutY() + nodePixelVelocitiesY[1] * timeInterval);
|
|
||||||
}
|
|
||||||
if (nodePixelVelocitiesY[1] >= 0 && mark.getLayoutY() > nodeDestinations[1].getY()) {
|
|
||||||
nodePixelVelocitiesY[1] = 0;
|
|
||||||
} else if (nodePixelVelocitiesY[1] < 0 && mark.getLayoutY() <= nodeDestinations[1].getY()) {
|
|
||||||
nodePixelVelocitiesY[1] = 0;
|
|
||||||
} else {
|
|
||||||
mark.setLayoutX(mark.getLayoutX() + nodePixelVelocitiesX[1] * timeInterval);
|
|
||||||
mark.setLayoutY(mark.getLayoutY() + nodePixelVelocitiesY[1] * timeInterval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
rotateTo(currentRotation + rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveTo (double x, double y, double rotation) {
|
public void moveTo (double x, double y, double rotation) {
|
||||||
@@ -177,8 +201,19 @@ public class MarkGroup extends RaceObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void moveTo (double x, double y) {
|
public void moveTo (double x, double y) {
|
||||||
super.setLayoutX(x);
|
Circle markCircle = (Circle) super.getChildren().get(0);
|
||||||
super.setLayoutY(y);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRaceId (int... raceIds) {
|
public boolean hasRaceId (int... raceIds) {
|
||||||
@@ -188,9 +223,6 @@ public class MarkGroup extends RaceObject {
|
|||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public void toggleAnnotations () {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getMarkRadius() {
|
public static int getMarkRadius() {
|
||||||
return MARK_RADIUS;
|
return MARK_RADIUS;
|
||||||
@@ -207,5 +239,4 @@ public class MarkGroup extends RaceObject {
|
|||||||
idArray[i++] = mark.getId();
|
idArray[i++] = mark.getId();
|
||||||
return idArray;
|
return idArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public class SingleMark extends Mark {
|
|||||||
private double lat;
|
private double lat;
|
||||||
private double lon;
|
private double lon;
|
||||||
private String name;
|
private String name;
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,10 +19,11 @@ public class SingleMark extends Mark {
|
|||||||
* @param lat, the latitude of the marker
|
* @param lat, the latitude of the marker
|
||||||
* @param lon, the longitude of the marker
|
* @param lon, the longitude of the marker
|
||||||
*/
|
*/
|
||||||
public SingleMark(String name, double lat, double lon) {
|
public SingleMark(String name, double lat, double lon, int id) {
|
||||||
super(name, MarkType.SINGLE_MARK);
|
super(name, MarkType.SINGLE_MARK, id);
|
||||||
this.lat = lat;
|
this.lat = lat;
|
||||||
this.lon = lon;
|
this.lon = lon;
|
||||||
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,9 +32,10 @@ public class SingleMark extends Mark {
|
|||||||
* @param name, the name of the marker
|
* @param name, the name of the marker
|
||||||
*/
|
*/
|
||||||
public SingleMark(String name) {
|
public SingleMark(String name) {
|
||||||
super(name, MarkType.SINGLE_MARK);
|
super(name, MarkType.SINGLE_MARK, 0);
|
||||||
this.lat = 0;
|
this.lat = 0;
|
||||||
this.lon = 0;
|
this.lon = 0;
|
||||||
|
this.id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getLatitude() {
|
public double getLatitude() {
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package seng302.models.parsers;
|
||||||
|
|
||||||
|
import org.w3c.dom.*;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import seng302.models.Boat;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.StringBufferInputStream;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ryan_ on 30/04/2017.
|
||||||
|
*/
|
||||||
|
public class BoatsParser extends FileParser {
|
||||||
|
private Document doc;
|
||||||
|
|
||||||
|
public BoatsParser(String xmlString) {
|
||||||
|
this.doc = this.parseFile(xmlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a boat instance from a given node if 'Type' is 'Yacht'
|
||||||
|
*
|
||||||
|
* @param node a boat node
|
||||||
|
* @return an instance of Boat
|
||||||
|
*/
|
||||||
|
private Boat parseBoat(Node node) {
|
||||||
|
try {
|
||||||
|
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||||
|
Element element = (Element) node;
|
||||||
|
if (element.getAttribute("Type").equals("Yacht")) {
|
||||||
|
String sourceID = element.getAttribute("SourceID");
|
||||||
|
String boatName = element.getAttribute("BoatName");
|
||||||
|
String shortName = element.getAttribute("ShortName");
|
||||||
|
String stoweName = element.getAttribute("StoweName");
|
||||||
|
String country = element.getAttribute("Country");
|
||||||
|
Boat boat = new Boat(Integer.parseInt(sourceID), boatName, shortName, country);
|
||||||
|
return boat;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new NoSuchElementException("Cannot generate a boat by given node");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of boats from the xml.
|
||||||
|
*
|
||||||
|
* @return a list of boats
|
||||||
|
*/
|
||||||
|
public List<Boat> getBoats() {
|
||||||
|
ArrayList<Boat> boats = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
NodeList nodes = this.doc.getElementsByTagName("Boat");
|
||||||
|
for (int i = 0; i < nodes.getLength(); i++) {
|
||||||
|
Node node = nodes.item(i);
|
||||||
|
Boat boat = parseBoat(node);
|
||||||
|
if (!(boat == null)) {
|
||||||
|
boats.add(boat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return boats;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,8 @@ public class CourseParser extends FileParser {
|
|||||||
String name = element.getElementsByTagName("name").item(0).getTextContent();
|
String name = element.getElementsByTagName("name").item(0).getTextContent();
|
||||||
double lat = Double.valueOf(element.getElementsByTagName("latitude").item(0).getTextContent());
|
double lat = Double.valueOf(element.getElementsByTagName("latitude").item(0).getTextContent());
|
||||||
double lon = Double.valueOf(element.getElementsByTagName("longitude").item(0).getTextContent());
|
double lon = Double.valueOf(element.getElementsByTagName("longitude").item(0).getTextContent());
|
||||||
SingleMark singleMark = new SingleMark(name, lat, lon);
|
int id = Integer.valueOf(element.getElementsByTagName("id").item(0).getTextContent());
|
||||||
|
SingleMark singleMark = new SingleMark(name, lat, lon, id);
|
||||||
return singleMark;
|
return singleMark;
|
||||||
} else {
|
} else {
|
||||||
throw new NoSuchElementException("Cannot generate a mark by given node.");
|
throw new NoSuchElementException("Cannot generate a mark by given node.");
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package seng302.models.parsers;
|
package seng302.models.parsers;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Haoming Yin (hyi25) on 16/3/2017
|
* Created by Haoming Yin (hyi25) on 16/3/2017
|
||||||
@@ -15,6 +17,8 @@ public abstract class FileParser {
|
|||||||
|
|
||||||
private String filePath;
|
private String filePath;
|
||||||
|
|
||||||
|
public FileParser() {}
|
||||||
|
|
||||||
public FileParser(String path) {
|
public FileParser(String path) {
|
||||||
this.filePath = path;
|
this.filePath = path;
|
||||||
}
|
}
|
||||||
@@ -32,6 +36,19 @@ public abstract class FileParser {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Document parseFile(String xmlString) {
|
||||||
|
try {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
|
||||||
|
// optional, in order to recover info from broken line.
|
||||||
|
doc.getDocumentElement().normalize();
|
||||||
|
return doc;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public class StreamPacket {
|
|||||||
// if (this.type == PacketType.XML_MESSAGE){
|
// if (this.type == PacketType.XML_MESSAGE){
|
||||||
// //System.out.println("--------");
|
// //System.out.println("--------");
|
||||||
// System.out.println(new String(payload));
|
// System.out.println(new String(payload));
|
||||||
// StreamParser.parsePacket(this);
|
// //StreamParser.parsePacket(this);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ public class StreamParser extends Thread{
|
|||||||
private String threadName;
|
private String threadName;
|
||||||
private Thread t;
|
private Thread t;
|
||||||
private static boolean raceStarted = false;
|
private static boolean raceStarted = false;
|
||||||
|
private static boolean raceFinished = false;
|
||||||
|
private static boolean streamStatus = false;
|
||||||
|
private static long timeSinceStart = -1;
|
||||||
|
private static List<Boat> boats = new ArrayList<>();
|
||||||
|
|
||||||
public StreamParser(String threadName){
|
public StreamParser(String threadName){
|
||||||
this.threadName = threadName;
|
this.threadName = threadName;
|
||||||
@@ -48,6 +48,7 @@ public class StreamParser extends Thread{
|
|||||||
public void run(){
|
public void run(){
|
||||||
try {
|
try {
|
||||||
System.out.println("START OF STREAM");
|
System.out.println("START OF STREAM");
|
||||||
|
streamStatus = true;
|
||||||
while (StreamReceiver.packetBuffer == null || StreamReceiver.packetBuffer.size() < 1) {
|
while (StreamReceiver.packetBuffer == null || StreamReceiver.packetBuffer.size() < 1) {
|
||||||
Thread.sleep(1);
|
Thread.sleep(1);
|
||||||
}
|
}
|
||||||
@@ -158,16 +159,21 @@ public class StreamParser extends Thread{
|
|||||||
format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
long timeTillStart = ((new Date (expectedStartTime)).getTime() - (new Date (currentTime)).getTime())/1000;
|
long timeTillStart = ((new Date (expectedStartTime)).getTime() - (new Date (currentTime)).getTime())/1000;
|
||||||
if (timeTillStart > 0 && timeTillStart % 10 == 0) {
|
if (timeTillStart > 0 && timeTillStart % 10 == 0) {
|
||||||
|
timeSinceStart = timeTillStart;
|
||||||
System.out.println("Time till start: " + timeTillStart + " Seconds");
|
System.out.println("Time till start: " + timeTillStart + " Seconds");
|
||||||
} else {
|
} else {
|
||||||
if (raceStatus == 4 || raceStatus == 8){
|
if (raceStatus == 4 || raceStatus == 8){
|
||||||
|
raceFinished = true;
|
||||||
|
raceStarted = false;
|
||||||
System.out.println("RACE HAS FINISHED");
|
System.out.println("RACE HAS FINISHED");
|
||||||
} else if (!raceStarted){
|
} else if (!raceStarted){
|
||||||
raceStarted = true;
|
raceStarted = true;
|
||||||
|
raceFinished = false;
|
||||||
System.out.println("RACE HAS STARTED");
|
System.out.println("RACE HAS STARTED");
|
||||||
}
|
}
|
||||||
if (timeTillStart % 10 == 0){
|
if (timeTillStart % 10 == 0){
|
||||||
//System.out.println("Time since start: " + -1 * timeTillStart + " Seconds");
|
System.out.println("Time since start: " + -1 * timeTillStart + " Seconds");
|
||||||
|
timeSinceStart = timeTillStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
|
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
|
||||||
@@ -184,7 +190,6 @@ public class StreamParser extends Thread{
|
|||||||
boatStatus += "\nEstTimeAtNextMark: " + extractTimeStamp(Arrays.copyOfRange(payload,31 + (i * 20),37+ (i * 20)), 6);
|
boatStatus += "\nEstTimeAtNextMark: " + extractTimeStamp(Arrays.copyOfRange(payload,31 + (i * 20),37+ (i * 20)), 6);
|
||||||
boatStatus += "\nEstTimeAtFinish: " + extractTimeStamp(Arrays.copyOfRange(payload,37 + (i * 20),43+ (i * 20)), 6);
|
boatStatus += "\nEstTimeAtFinish: " + extractTimeStamp(Arrays.copyOfRange(payload,37 + (i * 20),43+ (i * 20)), 6);
|
||||||
boatStatuses.add(boatStatus);
|
boatStatuses.add(boatStatus);
|
||||||
// System.out.println("boatStatus = " + boatStatus);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,19 +233,25 @@ public class StreamParser extends Thread{
|
|||||||
//Converts XML message to string to be parsed
|
//Converts XML message to string to be parsed
|
||||||
int currentChar;
|
int currentChar;
|
||||||
while (payloadStream.available() > 0 && (currentChar = payloadStream.read()) != 0) {
|
while (payloadStream.available() > 0 && (currentChar = payloadStream.read()) != 0) {
|
||||||
xmlMessage += (char)currentChar;
|
xmlMessage += (char)currentChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse boat xml from server
|
||||||
|
if (xmlMessageSubType == 7) {
|
||||||
|
BoatsParser boatsParser = new BoatsParser(xmlMessage);
|
||||||
|
boats = boatsParser.getBoats();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create XML document Object
|
//Create XML document Object
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
// DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder db = null;
|
// DocumentBuilder db = null;
|
||||||
try {
|
// try {
|
||||||
db = dbf.newDocumentBuilder();
|
// db = dbf.newDocumentBuilder();
|
||||||
Document doc = db.parse(new InputSource(new StringReader(xmlMessage)));
|
// Document doc = db.parse(new InputSource(new StringReader(xmlMessage)));
|
||||||
// TODO: 25/04/17 ajm412: Check that the object matches expected structure and return Document object.
|
// // TODO: 25/04/17 ajm412: Check that the object matches expected structure and return Document object.
|
||||||
} catch (ParserConfigurationException | IOException | SAXException e) {
|
// } catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
e.printStackTrace();
|
// e.printStackTrace();
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,5 +428,50 @@ public class StreamParser extends Thread{
|
|||||||
}
|
}
|
||||||
return partialLong;
|
return partialLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns false if race not started, true otherwise
|
||||||
|
*
|
||||||
|
* @return race started status
|
||||||
|
*/
|
||||||
|
public static boolean isRaceStarted() {
|
||||||
|
return raceStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns false if stream not connected, true otherwise
|
||||||
|
*
|
||||||
|
* @return stream started status
|
||||||
|
*/
|
||||||
|
public static boolean isStreamStatus() {
|
||||||
|
return streamStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns race timer
|
||||||
|
*
|
||||||
|
* @return race timer in long
|
||||||
|
*/
|
||||||
|
public static long getTimeSinceStart() {
|
||||||
|
return timeSinceStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return false if race not finished, true otherwise
|
||||||
|
*
|
||||||
|
* @return race finished status
|
||||||
|
*/
|
||||||
|
public static boolean isRaceFinished() {
|
||||||
|
return raceFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return list of boats from the server
|
||||||
|
*
|
||||||
|
* @return list of boats
|
||||||
|
*/
|
||||||
|
public static List<Boat> getBoats() {
|
||||||
|
return boats;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
@@ -15,8 +17,8 @@ import java.util.zip.Checksum;
|
|||||||
public class StreamReceiver extends Thread {
|
public class StreamReceiver extends Thread {
|
||||||
private InputStream stream;
|
private InputStream stream;
|
||||||
private Socket host;
|
private Socket host;
|
||||||
private ByteArrayOutputStream crcBuffer;
|
private ByteArrayOutputStream crcBuffer;
|
||||||
private Thread thread;
|
private Thread t;
|
||||||
private String threadName;
|
private String threadName;
|
||||||
public static PriorityBlockingQueue<StreamPacket> packetBuffer;
|
public static PriorityBlockingQueue<StreamPacket> packetBuffer;
|
||||||
|
|
||||||
@@ -31,24 +33,31 @@ public class StreamReceiver extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void run(){
|
public void run(){
|
||||||
packetBuffer = new PriorityBlockingQueue<>(256, new Comparator<StreamPacket>() {
|
PriorityBlockingQueue<StreamPacket> pq = new PriorityBlockingQueue<>(256, new Comparator<StreamPacket>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(StreamPacket s1, StreamPacket s2) {
|
public int compare(StreamPacket s1, StreamPacket s2) {
|
||||||
return (int) (s1.getTimeStamp() - s2.getTimeStamp());
|
return (int) (s1.getTimeStamp() - s2.getTimeStamp());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
packetBuffer = pq;
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start () {
|
public void start () {
|
||||||
System.out.println("Starting " + threadName );
|
System.out.println("Starting " + threadName );
|
||||||
if (thread == null) {
|
if (t == null) {
|
||||||
thread = new Thread (this, threadName);
|
t = new Thread (this, threadName);
|
||||||
thread.start ();
|
t.start ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public StreamReceiver(Socket host, PriorityBlockingQueue packetBuffer){
|
||||||
|
this.host=host;
|
||||||
|
this.packetBuffer = packetBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void connect(){
|
public void connect(){
|
||||||
try {
|
try {
|
||||||
stream = host.getInputStream();
|
stream = host.getInputStream();
|
||||||
@@ -120,8 +129,8 @@ public class StreamReceiver extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* takes an array of up to 7 bytes and returns a positive
|
* takes an array of up to 7 bytes in little endian format and
|
||||||
* long constructed from the input bytes
|
* returns a positive long constructed from the input bytes
|
||||||
*
|
*
|
||||||
* @return a positive long if there is less than 8 bytes -1 otherwise
|
* @return a positive long if there is less than 8 bytes -1 otherwise
|
||||||
*/
|
*/
|
||||||
@@ -137,4 +146,13 @@ public class StreamReceiver extends Thread {
|
|||||||
}
|
}
|
||||||
return partialLong;
|
return partialLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
StreamReceiver sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941,"TestThread1");
|
||||||
|
//StreamReceiver sr = new StreamReceiver("livedata.americascup.com", 4941, "TestThread2");
|
||||||
|
sr.start();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,461 @@
|
|||||||
|
package seng302.models.parsers;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to create an XML object from the XML Packet Messages.
|
||||||
|
*/
|
||||||
|
class XMLParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Regatta XML Object from the data in a Regatta XML Message
|
||||||
|
* @param doc XML Document Object
|
||||||
|
* @return A new RegattaXMLObject from the input Document.
|
||||||
|
*/
|
||||||
|
RegattaXMLObject createRegattaXML(Document doc) {
|
||||||
|
return new RegattaXMLObject(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Race XML Object from the data in a Regatta XML Message
|
||||||
|
* @param doc XML Document Object
|
||||||
|
* @return A new RaceXMLObject from the input Document.
|
||||||
|
*/
|
||||||
|
RaceXMLObject createRaceXML(Document doc) {
|
||||||
|
return new RaceXMLObject(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Boat XML Object from the data in a Regatta XML Message
|
||||||
|
* @param doc XML Document Object
|
||||||
|
* @return A new BoatXMLObject from the input Document.
|
||||||
|
*/
|
||||||
|
BoatXMLObject createBoatXML(Document doc) {
|
||||||
|
return new BoatXMLObject(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text content of a given child element tag, assuming it exists, as an Integer.
|
||||||
|
* @param ele Document Element with child elements.
|
||||||
|
* @param tag Tag to find in document elements child elements.
|
||||||
|
* @return Text content from tag if found, null otherwise.
|
||||||
|
*/
|
||||||
|
private static Integer getElementInt(Element ele, String tag) {
|
||||||
|
NodeList tagList = ele.getElementsByTagName(tag);
|
||||||
|
if (tagList.getLength() > 0) {
|
||||||
|
return Integer.parseInt(tagList.item(0).getTextContent());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text content of a given child element tag, assuming it exists, as an String.
|
||||||
|
* @param ele Document Element with child elements.
|
||||||
|
* @param tag Tag to find in document elements child elements.
|
||||||
|
* @return Text content from tag if found, null otherwise.
|
||||||
|
*/
|
||||||
|
private static String getElementString(Element ele, String tag) {
|
||||||
|
NodeList tagList = ele.getElementsByTagName(tag);
|
||||||
|
if (tagList.getLength() > 0) {
|
||||||
|
return tagList.item(0).getTextContent();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text content of a given child element tag, assuming it exists, as a Double.
|
||||||
|
* @param ele Document Element with child elements.
|
||||||
|
* @param tag Tag to find in document elements child elements.
|
||||||
|
* @return Text content from tag if found, null otherwise.
|
||||||
|
*/
|
||||||
|
private static Double getElementDouble(Element ele, String tag) {
|
||||||
|
NodeList tagList = ele.getElementsByTagName(tag);
|
||||||
|
if (tagList.getLength() > 0) {
|
||||||
|
return Double.parseDouble(tagList.item(0).getTextContent());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text content of an attribute of a given Node, assuming it exists, as a String.
|
||||||
|
* @param n A node object that should have some attributes
|
||||||
|
* @param attr The attribute you want to get from the given node.
|
||||||
|
* @return The String representation of the text content of an attribute in the given node, else returns null.
|
||||||
|
*/
|
||||||
|
private static String getNodeAttributeString(Node n, String attr) {
|
||||||
|
Node attrItem = n.getAttributes().getNamedItem(attr);
|
||||||
|
if (attrItem != null) {
|
||||||
|
return attrItem.getTextContent();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text content of an attribute of a given Node, assuming it exists, as an Integer.
|
||||||
|
* @param n A node object that should have some attributes
|
||||||
|
* @param attr The attribute you want to get from the given node.
|
||||||
|
* @return The Integer representation of the text content of an attribute in the given node, else returns null.
|
||||||
|
*/
|
||||||
|
private static Integer getNodeAttributeInt(Node n, String attr) {
|
||||||
|
Node attrItem = n.getAttributes().getNamedItem(attr);
|
||||||
|
if (attrItem != null) {
|
||||||
|
return Integer.parseInt(attrItem.getTextContent());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text content of an attribute of a given Node, assuming it exists, as a Double.
|
||||||
|
* @param n A node object that should have some attributes
|
||||||
|
* @param attr The attribute you want to get from the given node.
|
||||||
|
* @return The Double representation of the text content of an attribute in the given node, else returns null.
|
||||||
|
*/
|
||||||
|
private static Double getNodeAttributeDouble(Node n, String attr) {
|
||||||
|
Node attrItem = n.getAttributes().getNamedItem(attr);
|
||||||
|
if (attrItem != null) {
|
||||||
|
return Double.parseDouble(attrItem.getTextContent());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RegattaXMLObject {
|
||||||
|
//Regatta Info
|
||||||
|
private Integer regattaID;
|
||||||
|
private String regattaName;
|
||||||
|
private String courseName;
|
||||||
|
private Double centralLat;
|
||||||
|
private Double centralLng;
|
||||||
|
private Integer utcOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a RegattaXMLObject.
|
||||||
|
* Takes the information from a Document object and creates a more usable format.
|
||||||
|
* @param doc XML Document Object
|
||||||
|
*/
|
||||||
|
RegattaXMLObject(Document doc) {
|
||||||
|
Element docEle = doc.getDocumentElement();
|
||||||
|
|
||||||
|
this.regattaID = getElementInt(docEle, "RegattaID");
|
||||||
|
this.regattaName = getElementString(docEle, "RegattaName");
|
||||||
|
this.courseName = getElementString(docEle, "CourseName");
|
||||||
|
this.centralLat = getElementDouble(docEle, "CentralLatitude");
|
||||||
|
this.centralLng = getElementDouble(docEle, "CentralLongitude");
|
||||||
|
this.utcOffset = getElementInt(docEle, "UtcOffset");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRegattaID() { return regattaID; }
|
||||||
|
public String getRegattaName() { return regattaName; }
|
||||||
|
public String getCourseName() { return courseName; }
|
||||||
|
public Double getCentralLat() { return centralLat; }
|
||||||
|
public Double getCentralLng() { return centralLng; }
|
||||||
|
public Integer getUtcOffset() { return utcOffset; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class RaceXMLObject {
|
||||||
|
|
||||||
|
// Race Info
|
||||||
|
private Integer raceID;
|
||||||
|
private String raceType;
|
||||||
|
private String creationTimeDate; // XML Creation Time
|
||||||
|
|
||||||
|
//Race Start Details
|
||||||
|
private String raceStartTime;
|
||||||
|
private Boolean postponeStatus;
|
||||||
|
|
||||||
|
//Non atomic race attributes
|
||||||
|
private ArrayList<Participant> participants;
|
||||||
|
private ArrayList<CompoundMark> course;
|
||||||
|
private ArrayList<Corner> compoundMarkSequence;
|
||||||
|
private ArrayList<Limit> courseLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a RaceXMLObject.
|
||||||
|
* Takes the information from a Document object and creates a more usable format.
|
||||||
|
* @param doc XML Document Object
|
||||||
|
*/
|
||||||
|
RaceXMLObject(Document doc) {
|
||||||
|
Element docEle = doc.getDocumentElement();
|
||||||
|
|
||||||
|
//Atomic and Semi-Atomic Elements
|
||||||
|
this.raceID = getElementInt(docEle, "RaceID");
|
||||||
|
this.raceType = getElementString(docEle, "RaceType");
|
||||||
|
this.creationTimeDate = getElementString(docEle, "CreationTimeDate");
|
||||||
|
|
||||||
|
Node raceStart = docEle.getElementsByTagName("RaceStartTime").item(0);
|
||||||
|
this.raceStartTime = getNodeAttributeString(raceStart, "Start") ;
|
||||||
|
this.postponeStatus = Boolean.parseBoolean(getNodeAttributeString(raceStart, "Postpone"));
|
||||||
|
|
||||||
|
//Participants
|
||||||
|
participants = new ArrayList<>();
|
||||||
|
|
||||||
|
NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes();
|
||||||
|
for (int i = 0; i < pList.getLength(); i++) {
|
||||||
|
Node pNode = pList.item(i);
|
||||||
|
String entry;
|
||||||
|
if (pNode.getNodeName().equals("Yacht")) {
|
||||||
|
Integer sourceID = getNodeAttributeInt(pNode, "SourceID");
|
||||||
|
|
||||||
|
if (pNode.getAttributes().getLength() == 2) {
|
||||||
|
entry = getNodeAttributeString(pNode, "Entry");
|
||||||
|
} else {
|
||||||
|
entry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Participant pa = new Participant(sourceID, entry);
|
||||||
|
participants.add(pa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Course
|
||||||
|
course = new ArrayList<>();
|
||||||
|
|
||||||
|
NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes();
|
||||||
|
for (int i = 0; i < cMarkList.getLength(); i++) {
|
||||||
|
Node cMarkNode = cMarkList.item(i);
|
||||||
|
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
||||||
|
CompoundMark cMark = new CompoundMark(cMarkNode);
|
||||||
|
course.add(cMark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Course Mark Sequence
|
||||||
|
compoundMarkSequence = new ArrayList<>();
|
||||||
|
|
||||||
|
NodeList cornerList = docEle.getElementsByTagName("CompoundMarkSequence").item(0).getChildNodes();
|
||||||
|
for (int i = 0; i < cornerList.getLength(); i++) {
|
||||||
|
Node cornerNode = cornerList.item(i);
|
||||||
|
if (cornerNode.getNodeName().equals("Corner")) {
|
||||||
|
Corner corner = new Corner(cornerNode);
|
||||||
|
compoundMarkSequence.add(corner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Course Limits
|
||||||
|
courseLimit = new ArrayList<>();
|
||||||
|
|
||||||
|
NodeList limitList = docEle.getElementsByTagName("CourseLimit").item(0).getChildNodes();
|
||||||
|
for (int i = 0; i < limitList.getLength(); i++) {
|
||||||
|
Node limitNode = limitList.item(i);
|
||||||
|
if (limitNode.getNodeName().equals("Limit")) {
|
||||||
|
Limit limit = new Limit(limitNode);
|
||||||
|
courseLimit.add(limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRaceID() { return raceID; }
|
||||||
|
public String getRaceType() { return raceType; }
|
||||||
|
public String getCreationTimeDate() { return creationTimeDate; }
|
||||||
|
public String getRaceStartTime() { return raceStartTime; }
|
||||||
|
public Boolean getPostponeStatus() { return postponeStatus; }
|
||||||
|
|
||||||
|
public ArrayList<Participant> getParticipants() { return participants; }
|
||||||
|
public ArrayList<CompoundMark> getCompoundMarks() { return course; }
|
||||||
|
public ArrayList<Corner> getCompoundMarkSequence() { return compoundMarkSequence; }
|
||||||
|
public ArrayList<Limit> getCourseLimit() { return courseLimit; }
|
||||||
|
|
||||||
|
class Participant {
|
||||||
|
Integer sourceID;
|
||||||
|
String entry;
|
||||||
|
|
||||||
|
Participant(Integer sourceID, String entry) {
|
||||||
|
this.sourceID = sourceID;
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getsourceID() { return sourceID; }
|
||||||
|
public String getEntry() { return entry; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompoundMark {
|
||||||
|
private Integer markID;
|
||||||
|
private String cMarkName;
|
||||||
|
private ArrayList<Mark> marks;
|
||||||
|
|
||||||
|
CompoundMark(Node compoundMark) {
|
||||||
|
marks = new ArrayList<>();
|
||||||
|
this.markID = getNodeAttributeInt(compoundMark, "CompoundMarkID");
|
||||||
|
this.cMarkName = getNodeAttributeString(compoundMark, "Name");
|
||||||
|
NodeList childMarks = compoundMark.getChildNodes();
|
||||||
|
for (int i = 0; i < childMarks.getLength(); i++) {
|
||||||
|
Node markNode = childMarks.item(i);
|
||||||
|
if (markNode.getNodeName().equals("Mark")) {
|
||||||
|
Mark mark = new Mark(markNode);
|
||||||
|
marks.add(mark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMarkID() { return markID; }
|
||||||
|
public String getcMarkName() { return cMarkName; }
|
||||||
|
public ArrayList<Mark> getMarks() { return marks; }
|
||||||
|
|
||||||
|
class Mark {
|
||||||
|
private Integer seqID;
|
||||||
|
private Integer sourceID;
|
||||||
|
private String markName;
|
||||||
|
private Double targetLat;
|
||||||
|
private Double targetLng;
|
||||||
|
|
||||||
|
Mark(Node markNode) {
|
||||||
|
|
||||||
|
this.seqID = getNodeAttributeInt(markNode, "SeqID");
|
||||||
|
this.sourceID = getNodeAttributeInt(markNode, "SourceID");
|
||||||
|
this.markName = getNodeAttributeString(markNode, "Name");
|
||||||
|
this.targetLat = getNodeAttributeDouble(markNode, "TargetLat");
|
||||||
|
this.targetLng = getNodeAttributeDouble(markNode, "TargetLng");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSeqID() { return seqID; }
|
||||||
|
public Integer getSourceID() { return sourceID; }
|
||||||
|
public String getMarkName() { return markName; }
|
||||||
|
public Double getTargetLat() { return targetLat; }
|
||||||
|
public Double getTargetLng() { return targetLng; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Corner {
|
||||||
|
private Integer seqID;
|
||||||
|
private Integer compoundMarkID;
|
||||||
|
private String rounding;
|
||||||
|
private Integer zoneSize;
|
||||||
|
|
||||||
|
Corner(Node cornerNode) {
|
||||||
|
this.seqID = getNodeAttributeInt(cornerNode, "SeqID");
|
||||||
|
this.compoundMarkID = getNodeAttributeInt(cornerNode, "CompoundMarkID");
|
||||||
|
this.rounding = getNodeAttributeString(cornerNode, "Rounding");
|
||||||
|
this.zoneSize = getNodeAttributeInt(cornerNode, "ZoneSize");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSeqID() { return seqID; }
|
||||||
|
public Integer getCompoundMarkID() { return compoundMarkID; }
|
||||||
|
public String getRounding() { return rounding; }
|
||||||
|
public Integer getZoneSize() { return zoneSize; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Limit {
|
||||||
|
private Integer seqID;
|
||||||
|
private Double lat;
|
||||||
|
private Double lng;
|
||||||
|
|
||||||
|
Limit(Node limitNode) {
|
||||||
|
this.seqID = getNodeAttributeInt(limitNode, "SeqID");
|
||||||
|
this.lat = getNodeAttributeDouble(limitNode, "Lat");
|
||||||
|
this.lng = getNodeAttributeDouble(limitNode, "Lon");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSeqID() { return seqID; }
|
||||||
|
public Double getLat() { return lat; }
|
||||||
|
public Double getLng() { return lng; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class BoatXMLObject {
|
||||||
|
|
||||||
|
private String lastModified;
|
||||||
|
private Integer version;
|
||||||
|
|
||||||
|
//Settings for the boat type in the race. This may end up having to be reworked if multiple boat types compete.
|
||||||
|
private String boatType;
|
||||||
|
private Double boatLength;
|
||||||
|
private Double hullLength;
|
||||||
|
private Double markZoneSize;
|
||||||
|
private Double courseZoneSize;
|
||||||
|
private ArrayList<Double> zoneLimits;// will only contain 5 elements. Limits 1-5
|
||||||
|
|
||||||
|
//Boats
|
||||||
|
ArrayList<Boat> boats;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a BoatXMLObject.
|
||||||
|
* Takes the information from a Document object and creates a more usable format.
|
||||||
|
* @param doc XML Document Object
|
||||||
|
*/
|
||||||
|
BoatXMLObject(Document doc) {
|
||||||
|
|
||||||
|
Element docEle = doc.getDocumentElement();
|
||||||
|
|
||||||
|
this.lastModified = getElementString(docEle, "Modified");
|
||||||
|
this.version = getElementInt(docEle, "Version");
|
||||||
|
|
||||||
|
NodeList settingsList = docEle.getElementsByTagName("Settings").item(0).getChildNodes();
|
||||||
|
this.boatType = getNodeAttributeString(settingsList.item(1), "Type");
|
||||||
|
this.boatLength = getNodeAttributeDouble(settingsList.item(3), "BoatLength");
|
||||||
|
this.hullLength = getNodeAttributeDouble(settingsList.item(3), "HullLength");
|
||||||
|
this.markZoneSize = getNodeAttributeDouble(settingsList.item(5), "MarkZoneSize");
|
||||||
|
this.courseZoneSize = getNodeAttributeDouble(settingsList.item(5), "CourseZoneSize");
|
||||||
|
|
||||||
|
Node zoneLimitsList = settingsList.item(7);
|
||||||
|
this.zoneLimits = new ArrayList<>();
|
||||||
|
for (int i = 0; i < zoneLimitsList.getAttributes().getLength(); i++) {
|
||||||
|
String tag = String.format("Limit%d", i+1);
|
||||||
|
this.zoneLimits.add(getNodeAttributeDouble(zoneLimitsList, tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.boats = new ArrayList<>();
|
||||||
|
NodeList boatsList = docEle.getElementsByTagName("Boats").item(0).getChildNodes();
|
||||||
|
for (int i = 0; i < boatsList.getLength(); i++) {
|
||||||
|
Node currentBoat = boatsList.item(i);
|
||||||
|
if (currentBoat.getNodeName().equals("Boat")) {
|
||||||
|
Boat boat = new Boat(currentBoat);
|
||||||
|
this.boats.add(boat);
|
||||||
|
}
|
||||||
|
//System.out.println(this.getBoats());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastModified() { return lastModified; }
|
||||||
|
public Integer getVersion() { return version; }
|
||||||
|
public String getBoatType() { return boatType; }
|
||||||
|
public Double getBoatLength() { return boatLength; }
|
||||||
|
public Double getHullLength() { return hullLength; }
|
||||||
|
public Double getMarkZoneSize() { return markZoneSize; }
|
||||||
|
public Double getCourseZoneSize() { return courseZoneSize; }
|
||||||
|
public ArrayList<Double> getZoneLimits() { return zoneLimits; }
|
||||||
|
public ArrayList<Boat> getBoats() { return boats; }
|
||||||
|
|
||||||
|
class Boat {
|
||||||
|
|
||||||
|
private String boatType;
|
||||||
|
private Integer sourceID;
|
||||||
|
private String hullID; //matches HullNum in the XML spec.
|
||||||
|
private String shortName;
|
||||||
|
private String boatName;
|
||||||
|
private String country;
|
||||||
|
|
||||||
|
Boat(Node boatNode) {
|
||||||
|
this.boatType = getNodeAttributeString(boatNode, "Type");
|
||||||
|
this.sourceID = getNodeAttributeInt(boatNode, "SourceID");
|
||||||
|
this.hullID = getNodeAttributeString(boatNode, "HullNum");
|
||||||
|
this.shortName = getNodeAttributeString(boatNode, "ShortName");
|
||||||
|
this.boatName = getNodeAttributeString(boatNode, "BoatName");
|
||||||
|
this.country = getNodeAttributeString(boatNode, "Country");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBoatType() { return boatType; }
|
||||||
|
public Integer getSourceID() { return sourceID; }
|
||||||
|
public String getHullID() { return hullID; }
|
||||||
|
public String getShortName() { return shortName; }
|
||||||
|
public String getBoatName() { return boatName; }
|
||||||
|
public String getCountry() { return country; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,17 +8,20 @@
|
|||||||
<name>Start1</name>
|
<name>Start1</name>
|
||||||
<latitude>57.6703330</latitude>
|
<latitude>57.6703330</latitude>
|
||||||
<longitude>11.8278330</longitude>
|
<longitude>11.8278330</longitude>
|
||||||
|
<id>122</id>
|
||||||
</mark>
|
</mark>
|
||||||
<mark>
|
<mark>
|
||||||
<name>Start2</name>
|
<name>Start2</name>
|
||||||
<latitude>57.6706330</latitude>
|
<latitude>57.6706330</latitude>
|
||||||
<longitude>11.8281330</longitude>
|
<longitude>11.8281330</longitude>
|
||||||
|
<id>123</id>
|
||||||
</mark>
|
</mark>
|
||||||
</gate>
|
</gate>
|
||||||
<mark>
|
<mark>
|
||||||
<name>Mid Mark</name>
|
<name>Mid Mark</name>
|
||||||
<latitude>57.6675700</latitude>
|
<latitude>57.6675700</latitude>
|
||||||
<longitude>11.8359880</longitude>
|
<longitude>11.8359880</longitude>
|
||||||
|
<id>131</id>
|
||||||
</mark>
|
</mark>
|
||||||
<gate>
|
<gate>
|
||||||
<name>Leeward Gate</name>
|
<name>Leeward Gate</name>
|
||||||
@@ -26,11 +29,13 @@
|
|||||||
<name>Leeward Gate1</name>
|
<name>Leeward Gate1</name>
|
||||||
<latitude>57.6708220</latitude>
|
<latitude>57.6708220</latitude>
|
||||||
<longitude>11.8433900</longitude>
|
<longitude>11.8433900</longitude>
|
||||||
|
<id>124</id>
|
||||||
</mark>
|
</mark>
|
||||||
<mark>
|
<mark>
|
||||||
<name>Leeward Gate2</name>
|
<name>Leeward Gate2</name>
|
||||||
<latitude>57.6711220</latitude>
|
<latitude>57.6711220</latitude>
|
||||||
<longitude>11.8436900</longitude>
|
<longitude>11.8436900</longitude>
|
||||||
|
<id>125</id>
|
||||||
</mark>
|
</mark>
|
||||||
</gate>
|
</gate>
|
||||||
<gate>
|
<gate>
|
||||||
@@ -39,11 +44,13 @@
|
|||||||
<name>Windward Gate1</name>
|
<name>Windward Gate1</name>
|
||||||
<latitude>57.6650170</latitude>
|
<latitude>57.6650170</latitude>
|
||||||
<longitude>11.8279170</longitude>
|
<longitude>11.8279170</longitude>
|
||||||
|
<id>126</id>
|
||||||
</mark>
|
</mark>
|
||||||
<mark>
|
<mark>
|
||||||
<name>Windward Gate2</name>
|
<name>Windward Gate2</name>
|
||||||
<latitude>57.6653170</latitude>
|
<latitude>57.6653170</latitude>
|
||||||
<longitude>11.8282170</longitude>
|
<longitude>11.8282170</longitude>
|
||||||
|
<id>127</id>
|
||||||
</mark>
|
</mark>
|
||||||
</gate>
|
</gate>
|
||||||
<gate type="finish-line">
|
<gate type="finish-line">
|
||||||
@@ -52,11 +59,13 @@
|
|||||||
<name>Finish1</name>
|
<name>Finish1</name>
|
||||||
<latitude>57.6715240</latitude>
|
<latitude>57.6715240</latitude>
|
||||||
<longitude>11.8444950</longitude>
|
<longitude>11.8444950</longitude>
|
||||||
|
<id>128</id>
|
||||||
</mark>
|
</mark>
|
||||||
<mark>
|
<mark>
|
||||||
<name>Finish2</name>
|
<name>Finish2</name>
|
||||||
<latitude>57.6718240</latitude>
|
<latitude>57.6718240</latitude>
|
||||||
<longitude>11.8447950</longitude>
|
<longitude>11.8447950</longitude>
|
||||||
|
<id>129</id>
|
||||||
</mark>
|
</mark>
|
||||||
</gate>
|
</gate>
|
||||||
</marks>
|
</marks>
|
||||||
|
|||||||
@@ -1,11 +1,62 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.geometry.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
<?import javafx.scene.canvas.*?>
|
<?import javafx.scene.canvas.*?>
|
||||||
<?import java.lang.*?>
|
<?import java.lang.*?>
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
<AnchorPane fx:id="contentPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="1080.0" prefWidth="1920.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.Controller">
|
<AnchorPane fx:id="contentPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="1080.0" prefWidth="1920.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.Controller">
|
||||||
<children>
|
<children>
|
||||||
<fx:include source="RaceView.fxml" fx:id="raceView"/>
|
<GridPane alignment="CENTER" prefHeight="1080.0" prefWidth="1920.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="403.0" minHeight="0.0" prefHeight="170.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="444.0" minHeight="0.0" prefHeight="52.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="432.0" minHeight="2.0" prefHeight="102.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="635.0" minHeight="0.0" prefHeight="60.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="635.0" minHeight="10.0" prefHeight="365.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="635.0" minHeight="10.0" prefHeight="93.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="599.0" minHeight="10.0" prefHeight="262.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Label alignment="CENTER" text="Welcome to Race Vision" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
|
||||||
|
<font>
|
||||||
|
<Font size="40.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<Label text="Your live AC35 livestream" GridPane.halignment="CENTER" GridPane.rowIndex="1">
|
||||||
|
<font>
|
||||||
|
<Font size="20.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<Label text="Livestream Status:" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
|
||||||
|
<font>
|
||||||
|
<Font size="28.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="timeTillLive" text="0:00 minutes" visible="false" GridPane.halignment="CENTER" GridPane.rowIndex="3">
|
||||||
|
<font>
|
||||||
|
<Font size="27.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<Button fx:id="streamButton" mnemonicParsing="false" onAction="#startStream" text="Click to stream" GridPane.halignment="CENTER" GridPane.rowIndex="3" />
|
||||||
|
<Button fx:id="switchToRaceViewButton" disable="true" mnemonicParsing="false" onAction="#switchToRaceView" text="Watch Race" GridPane.halignment="CENTER" GridPane.rowIndex="6" />
|
||||||
|
<TableView fx:id="teamList" maxWidth="500.0" prefHeight="200.0" prefWidth="200.0" GridPane.halignment="CENTER" GridPane.rowIndex="4">
|
||||||
|
<columns>
|
||||||
|
<TableColumn fx:id="boatNameCol" editable="false" prefWidth="250.0" sortable="false" text="Boat Name" />
|
||||||
|
<TableColumn fx:id="shortNameCol" editable="false" prefWidth="125.0" sortable="false" text="Short Name" />
|
||||||
|
<TableColumn fx:id="countryCol" editable="false" prefWidth="125.0" sortable="false" text="Country" />
|
||||||
|
</columns>
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets />
|
||||||
|
</GridPane.margin>
|
||||||
|
</TableView>
|
||||||
|
<Label text="*Team position in table do not correspond to race position" GridPane.halignment="CENTER" GridPane.rowIndex="5" GridPane.valignment="TOP" />
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.scene.shape.*?>
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
<?import javafx.scene.control.CheckBox?>
|
<?import javafx.scene.control.CheckBox?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
@@ -12,7 +17,7 @@
|
|||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
<?import javafx.scene.text.Text?>
|
<?import javafx.scene.text.Text?>
|
||||||
|
|
||||||
<GridPane prefHeight="1080.0" prefWidth="1920.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.RaceViewController">
|
<GridPane prefHeight="1080.0" prefWidth="1920.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.RaceViewController">
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints maxWidth="246.0" minWidth="246.0" prefWidth="246.0" />
|
<ColumnConstraints maxWidth="246.0" minWidth="246.0" prefWidth="246.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="1034.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="1034.0" />
|
||||||
@@ -40,8 +45,7 @@
|
|||||||
<Font name="System Bold" size="13.0" />
|
<Font name="System Bold" size="13.0" />
|
||||||
</font>
|
</font>
|
||||||
</Text>
|
</Text>
|
||||||
<CheckBox fx:id="toggleAnnotation" layoutX="27.0" layoutY="462.0" mnemonicParsing="false" onAction="#toggleAnnotations" selected="true" text="Show annotations" />
|
<CheckBox fx:id="toggleFps" layoutX="21.0" layoutY="453.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="143.0" selected="true" text="Show FPS" />
|
||||||
<CheckBox fx:id="toggleFps" layoutX="27.0" layoutY="488.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="143.0" selected="true" text="Show FPS" />
|
|
||||||
<VBox fx:id="positionVbox" layoutX="12.0" layoutY="280.0" prefHeight="140.0" prefWidth="200.0" />
|
<VBox fx:id="positionVbox" layoutX="12.0" layoutY="280.0" prefHeight="140.0" prefWidth="200.0" />
|
||||||
<Pane layoutX="11.0" layoutY="30.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="193.0">
|
<Pane layoutX="11.0" layoutY="30.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="193.0">
|
||||||
<children>
|
<children>
|
||||||
@@ -52,6 +56,8 @@
|
|||||||
</Text>
|
</Text>
|
||||||
</children>
|
</children>
|
||||||
</Pane>
|
</Pane>
|
||||||
|
<Slider fx:id="annotationSlider" blockIncrement="1.0" layoutX="38.0" layoutY="527.0" majorTickUnit="1.0" max="3.0" minorTickCount="0" prefHeight="51.0" prefWidth="170.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" />
|
||||||
|
<Label layoutX="10.0" layoutY="499.0" text="Annotations" />
|
||||||
</children>
|
</children>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
<AnchorPane fx:id="contentAnchorPane" prefHeight="960.0" prefWidth="1280.0" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2147483647" GridPane.valignment="TOP">
|
<AnchorPane fx:id="contentAnchorPane" prefHeight="960.0" prefWidth="1280.0" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2147483647" GridPane.valignment="TOP">
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class EventTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testBoatHeading() throws Exception {
|
public void testBoatHeading() throws Exception {
|
||||||
Boat boat = new Boat("testBoat");
|
Boat boat = new Boat("testBoat");
|
||||||
Event event = new Event(1231242.2, boat, new SingleMark("mark1", 142.5, 122.1), new SingleMark("mark2", 121.9,99.2), 0);
|
Event event = new Event(1231242.2, boat, new SingleMark("mark1", 142.5, 122.1, 1), new SingleMark("mark2", 121.9,99.2, 2), 0);
|
||||||
|
|
||||||
assertEquals(event.getBoatHeading(), 228.0266137055349, 1e-15);
|
assertEquals(event.getBoatHeading(), 228.0266137055349, 1e-15);
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ public class EventTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testDistanceBetweenMarks() throws Exception {
|
public void testDistanceBetweenMarks() throws Exception {
|
||||||
Boat boat = new Boat("testBoat");
|
Boat boat = new Boat("testBoat");
|
||||||
Event event = new Event(1231242.2, boat, new SingleMark("mark1", 142.5, 122.1), new SingleMark("mark2", 121.9,99.2), 0);
|
Event event = new Event(1231242.2, boat, new SingleMark("mark1", 142.5, 122.1, 1), new SingleMark("mark2", 121.9,99.2, 2), 0);
|
||||||
|
|
||||||
assertEquals(event.getDistanceBetweenMarks(), 339059.653830461, 1e-15);
|
assertEquals(event.getDistanceBetweenMarks(), 339059.653830461, 1e-15);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ public class MarkTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
this.singleMark1 = new SingleMark("testMark_SM1", 12.23234, -34.342);
|
this.singleMark1 = new SingleMark("testMark_SM1", 12.23234, -34.342, 1);
|
||||||
this.singleMark2 = new SingleMark("testMark_SM2", 12.23239, -34.352);
|
this.singleMark2 = new SingleMark("testMark_SM2", 12.23239, -34.352, 2);
|
||||||
this.gateMark = new GateMark("testMark_GM", MarkType.OPEN_GATE, singleMark1, singleMark2, singleMark1.getLatitude(), singleMark2.getLongitude());
|
this.gateMark = new GateMark("testMark_GM", MarkType.OPEN_GATE, singleMark1, singleMark2, singleMark1.getLatitude(), singleMark2.getLongitude());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,18 +25,17 @@ public class CourseParserTest {
|
|||||||
public void getGates() throws Exception {
|
public void getGates() throws Exception {
|
||||||
ArrayList<Mark> course = cp.getCourse();
|
ArrayList<Mark> course = cp.getCourse();
|
||||||
|
|
||||||
assertTrue(MarkType.OPEN_GATE == course.get(0).getMarkType());
|
|
||||||
|
|
||||||
GateMark gateMark1 = (GateMark) course.get(0);
|
GateMark gateMark1 = (GateMark) course.get(0);
|
||||||
assertEquals(32.293771, gateMark1.getSingleMark2().getLatitude(), 0.00000001);
|
assertEquals(57.670633, gateMark1.getSingleMark2().getLatitude(), 0.00000001);
|
||||||
assertEquals(-64.855242, gateMark1.getSingleMark2().getLongitude(), 0.00000001);
|
assertEquals(11.8281330, gateMark1.getSingleMark2().getLongitude(), 0.00000001);
|
||||||
|
|
||||||
GateMark gateMark2 = (GateMark) course.get(5);
|
GateMark gateMark2 = (GateMark) course.get(5);
|
||||||
|
|
||||||
assertEquals("Finish1", gateMark2.getSingleMark1().getName());
|
assertEquals("Finish1", gateMark2.getSingleMark1().getName());
|
||||||
assertEquals("Finish2", gateMark2.getSingleMark2().getName());
|
assertEquals("Finish2", gateMark2.getSingleMark2().getName());
|
||||||
assertEquals(32.317257, gateMark2.getSingleMark2().getLatitude(), 0.00000001);
|
assertEquals(57.671824, gateMark2.getSingleMark2().getLatitude(), 0.00000001);
|
||||||
assertEquals(-64.83626, gateMark2.getSingleMark2().getLongitude(), 0.00000001);
|
assertEquals(11.844795, gateMark2.getSingleMark2().getLongitude(), 0.00000001);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package seng302.models.parsers;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ptg19 on 26/04/17.
|
||||||
|
*/
|
||||||
|
public class StreamReceiverTest {
|
||||||
|
|
||||||
|
private PriorityBlockingQueue pq;
|
||||||
|
private byte[] brokenPacket = {0x47, (byte) 0x83, 37, // sync1 sync2 and message type
|
||||||
|
0b00000000, 0b01000000, 0b00100010, 0b00100100, 0b00011000, 0b00000000, //timestamp
|
||||||
|
0b00000000, 0b00010000, 0b01000000, 0b00000000, //source id
|
||||||
|
0b00100010, 0b00101000, // message length
|
||||||
|
0b00010010, 0b00010010, 0b00010010}; //random start of payload
|
||||||
|
|
||||||
|
private byte[] workingPacket = {0x47, (byte) 0x83, 37, // sync1 sync2 and message type
|
||||||
|
0b00000000, 0b01000000, 0b00100010, 0b00100100, 0b00011000, 0b00000000, //timestamp
|
||||||
|
0b00000000, 0b00010000, 0b01000000, 0b00000000, //source id
|
||||||
|
0b00000010, 0b00000000, // message length
|
||||||
|
0b00010010, 0b00010010, // payload
|
||||||
|
0b00100110, (byte)0b10000111, 0b00110101, 0b01111000}; //crc
|
||||||
|
|
||||||
|
private byte[] crcMismatchPacket = {0x47, (byte) 0x83, 37, // sync1 sync2 and message type
|
||||||
|
0b00000000, 0b01000000, 0b00100010, 0b00100100, 0b00011000, 0b00000000, //timestamp
|
||||||
|
0b00000000, 0b00000000, 0b01000000, 0b00000000, //source id
|
||||||
|
0b00000010, 0b00000000, // message length
|
||||||
|
0b00010010, 0b00010010, // payload
|
||||||
|
0b00100110, (byte)0b10000111, 0b00110101, 0b01111000}; //crc
|
||||||
|
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup(){
|
||||||
|
pq = new PriorityBlockingQueue<>(256, new Comparator<StreamPacket>() {
|
||||||
|
@Override
|
||||||
|
public int compare(StreamPacket s1, StreamPacket s2) {
|
||||||
|
return (int) (s1.getTimeStamp() - s2.getTimeStamp());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void connectExitsOnUnexpectedStreamEnd() throws Exception {
|
||||||
|
Socket host=mock(Socket.class);
|
||||||
|
InputStream stream = new ByteArrayInputStream(brokenPacket);
|
||||||
|
when(host.getInputStream()).thenReturn(stream);
|
||||||
|
StreamReceiver streamReceiver = new StreamReceiver(host, pq);
|
||||||
|
|
||||||
|
streamReceiver.connect();
|
||||||
|
assert pq.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void connectReadsAPacket() throws Exception {
|
||||||
|
Socket host=mock(Socket.class);
|
||||||
|
InputStream stream = new ByteArrayInputStream(workingPacket);
|
||||||
|
when(host.getInputStream()).thenReturn(stream);
|
||||||
|
StreamReceiver streamReceiver = new StreamReceiver(host, pq);
|
||||||
|
|
||||||
|
streamReceiver.connect();
|
||||||
|
assert pq.size() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void connectDropsAMismatchedCrc() throws Exception {
|
||||||
|
Socket host=mock(Socket.class);
|
||||||
|
InputStream stream = new ByteArrayInputStream(crcMismatchPacket);
|
||||||
|
when(host.getInputStream()).thenReturn(stream);
|
||||||
|
StreamReceiver streamReceiver = new StreamReceiver(host, pq);
|
||||||
|
|
||||||
|
streamReceiver.connect();
|
||||||
|
assert pq.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bytestoLongTest() {
|
||||||
|
Socket host=mock(Socket.class);
|
||||||
|
StreamReceiver streamReceiver = new StreamReceiver(host, pq);
|
||||||
|
try {
|
||||||
|
Class[] args = new Class[1];
|
||||||
|
args[0] = byte[].class;
|
||||||
|
Method bytesToLong = streamReceiver.getClass().getDeclaredMethod("bytesToLong", args);
|
||||||
|
bytesToLong.setAccessible(true);
|
||||||
|
byte[] sevenBtyeNumber = {0b01100100, 0b00110100, 0b00010100, 0b00000000, 0b00000000, 0b00000000, (byte)0b10000000};
|
||||||
|
assert bytesToLong.invoke(streamReceiver, sevenBtyeNumber).equals(36028797020288100L);
|
||||||
|
byte[] eightByteNumber = {0b01100100, 0b00110100, 0b00010100, 0b00000000, 0b00000000, 0b00000000, (byte)0b10000000, 0b00100101};
|
||||||
|
assert bytesToLong.invoke(streamReceiver, eightByteNumber).equals(-1L);
|
||||||
|
byte[] emptyArray = {};
|
||||||
|
assert bytesToLong.invoke(streamReceiver, emptyArray).equals(0L);
|
||||||
|
} catch (Exception e){
|
||||||
|
System.out.println("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user