mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Removed unneeded files, also fixed heading calculation
Tags #story[829]
This commit is contained in:
@@ -6,7 +6,6 @@ import javafx.scene.Parent;
|
|||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import seng302.server.ServerThread;
|
import seng302.server.ServerThread;
|
||||||
import seng302.server.simulator.Simulator;
|
|
||||||
|
|
||||||
public class App extends Application
|
public class App extends Application
|
||||||
{
|
{
|
||||||
@@ -15,13 +14,9 @@ public class App extends Application
|
|||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new ServerThread("Racevision Test Server");
|
new ServerThread("Racevision Test Server");
|
||||||
//new Thread(new Simulator(1000)).run();
|
|
||||||
//launch(args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
package seng302.controllers;
|
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.Group;
|
|
||||||
import javafx.scene.canvas.Canvas;
|
|
||||||
import javafx.scene.canvas.GraphicsContext;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import seng302.models.Boat;
|
|
||||||
import seng302.models.Course;
|
|
||||||
import seng302.models.Race;
|
|
||||||
import seng302.models.mark.Mark;
|
|
||||||
import seng302.models.mark.MarkType;
|
|
||||||
import seng302.models.parsers.ConfigParser;
|
|
||||||
import seng302.models.parsers.CourseParser;
|
|
||||||
import seng302.models.parsers.TeamsParser;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller for main window for RaceVision
|
|
||||||
* Created by Kusal on 3/22/2017.
|
|
||||||
*/
|
|
||||||
public class Controller implements Initializable {
|
|
||||||
|
|
||||||
private static final int MARKER_WIDTH = 10;
|
|
||||||
private static final int MARKER_HEIGHT = 10;
|
|
||||||
private static final double ORIGINAL_LAT = 32.321504;
|
|
||||||
private static final double ORIGINAL_LON = -64.857063;
|
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Canvas courseCanvas;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Group boatGroup;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Button playPauseButton;
|
|
||||||
|
|
||||||
|
|
||||||
private Course thisCourse;
|
|
||||||
private ArrayList<Boat> startingBoats;
|
|
||||||
private int raceDuration;
|
|
||||||
private Race race;
|
|
||||||
private boolean raceRunning = false;
|
|
||||||
|
|
||||||
private CourseParser cp;
|
|
||||||
private TeamsParser tp;
|
|
||||||
private ConfigParser cop;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
|
||||||
cp = new CourseParser("/config/course.xml");
|
|
||||||
tp = new TeamsParser("/config/teams.xml");
|
|
||||||
cop = new ConfigParser("/config/config.xml");
|
|
||||||
|
|
||||||
thisCourse = new Course(cp.getCourse());
|
|
||||||
startingBoats = tp.getBoats();
|
|
||||||
race = new Race(thisCourse.getMarks(), startingBoats, cop.getTimeScale(), this);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialises a race on the screen after it has been loaded
|
|
||||||
*/
|
|
||||||
private void init() {
|
|
||||||
initMap();
|
|
||||||
initBoats();
|
|
||||||
playPauseButton.setDisable(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise the map by drawing it onto courseCanvas.
|
|
||||||
*/
|
|
||||||
private void initMap() {
|
|
||||||
//Create the boundary of the course displayed on the map
|
|
||||||
drawCourse();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the markers and gates onto the courseCanvas.
|
|
||||||
*/
|
|
||||||
private void drawCourse() {
|
|
||||||
GraphicsContext gc = courseCanvas.getGraphicsContext2D();
|
|
||||||
gc.save();
|
|
||||||
|
|
||||||
for(Mark rp : thisCourse.getMarks()) {
|
|
||||||
if (rp.getMarkType().equals(MarkType.SINGLE_MARK)) {
|
|
||||||
gc.setFill(Color.GRAY);
|
|
||||||
gc.fillOval(convertLongToX(rp.getLongitude()), convertLatToY(rp.getLatitude()), MARKER_WIDTH, MARKER_HEIGHT);
|
|
||||||
} else if (rp.getMarkType().equals(MarkType.GATE_MARK)) {
|
|
||||||
gc.setFill(Color.GRAY);
|
|
||||||
gc.fillOval(convertLongToX(rp.getLongitude()), convertLatToY(rp.getLatitude()), MARKER_WIDTH, MARKER_HEIGHT);
|
|
||||||
// gc.fillOval(((OpenGate) rp).getDrawX2(), ((OpenGate) rp).getDrawY2(), MARKER_WIDTH, MARKER_HEIGHT);
|
|
||||||
|
|
||||||
gc.setLineWidth(2);
|
|
||||||
gc.setFill(Color.GREEN);
|
|
||||||
gc.setStroke(Color.GREEN);
|
|
||||||
}
|
|
||||||
gc.fillOval(convertLongToX(rp.getLongitude()), convertLatToY(rp.getLatitude()), MARKER_WIDTH, MARKER_HEIGHT);
|
|
||||||
// gc.fillOval(((ClosedGate) rp).getDrawX2(), ((ClosedGate) rp).getDrawY2(), MARKER_WIDTH, MARKER_HEIGHT);
|
|
||||||
// gc.strokeLine(convertLongToX(rp.getLongitude()) + 5, convertLatToY(rp.getLatitude()) + 5, ((ClosedGate) rp).getDrawX2() + 5, ((ClosedGate) rp).getDrawY2() + 5);
|
|
||||||
}
|
|
||||||
gc.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Places boats at starting line
|
|
||||||
*/
|
|
||||||
private void initBoats() {
|
|
||||||
|
|
||||||
// int startingX = (convertLongToX(thisCourse.getMarks().get(0).getLongitude())).intValue();
|
|
||||||
// int startingY = (convertLatToY(thisCourse.getMarks().get(0).getLongitude())).intValue();
|
|
||||||
|
|
||||||
int startingX = 50;
|
|
||||||
int startingY = 100;
|
|
||||||
|
|
||||||
for(Boat boat : startingBoats) {
|
|
||||||
boat.moveBoatTo(startingX, startingY);
|
|
||||||
boatGroup.getChildren().add(boat.getBoatObject());
|
|
||||||
boat.setCurrentLeg(race.getRaceLegs().get(0));
|
|
||||||
boat.setHeading(race.getRaceLegs().get(0).getHeading());
|
|
||||||
boat.setLegDistance(0d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts and stops the race depending on whether or not it is already running
|
|
||||||
*/
|
|
||||||
public void playPause() {
|
|
||||||
if (!raceRunning) {
|
|
||||||
play();
|
|
||||||
} else {
|
|
||||||
pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plays the race and updates the play / pause button
|
|
||||||
*/
|
|
||||||
private void play() {
|
|
||||||
race.run();
|
|
||||||
raceRunning = true;
|
|
||||||
playPauseButton.setText("Pause");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pauses the race and updates the play / pause button
|
|
||||||
*/
|
|
||||||
private void pause() {
|
|
||||||
race.pause();
|
|
||||||
raceRunning = false;
|
|
||||||
playPauseButton.setText("Play");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Double convertLongToX(Double lon) {
|
|
||||||
return (lon - ORIGINAL_LON) * thisCourse.getDistanceScaleFactor();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Double convertLatToY(Double lat) {
|
|
||||||
return (ORIGINAL_LAT - lat) * thisCourse.getDistanceScaleFactor();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Button getPlayPauseButton() {
|
|
||||||
return playPauseButton;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.shape.Polygon;
|
|
||||||
import javafx.scene.text.Text;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a boat in the race.
|
|
||||||
*/
|
|
||||||
public class Boat {
|
|
||||||
|
|
||||||
private static final double BOAT_HEIGHT = 15d;
|
|
||||||
private static final double BOAT_WIDTH = 10d;
|
|
||||||
private static final double VELOCITY_WAKE_RATIO = 1/2d; //Ratio for deciding how long the wake will be wrt velocity
|
|
||||||
|
|
||||||
private String teamName; // The name of the team, this is also the name of the boat
|
|
||||||
private Double velocity; // In meters/second
|
|
||||||
private Double lat; // Boats position
|
|
||||||
private Double lon; // -
|
|
||||||
private Double legDistance;
|
|
||||||
private Color color;
|
|
||||||
private Leg currentLeg;
|
|
||||||
private Double heading;
|
|
||||||
private String shortName;
|
|
||||||
|
|
||||||
private Polygon boatObject = new Polygon();
|
|
||||||
|
|
||||||
public Boat(String teamName) {
|
|
||||||
this.teamName = teamName;
|
|
||||||
this.velocity = 10d; // Default velocity
|
|
||||||
this.lat = 0.0;
|
|
||||||
this.lon = 0.0;
|
|
||||||
this.legDistance = 0.0;
|
|
||||||
this.shortName = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a boat in the race.
|
|
||||||
*
|
|
||||||
* @param teamName The name of the team sailing the boat
|
|
||||||
* @param boatVelocity The speed of the boat in meters/second
|
|
||||||
* @param shortName A shorter version of the teams name
|
|
||||||
*/
|
|
||||||
public Boat(String teamName, double boatVelocity, String shortName) {
|
|
||||||
this.teamName = teamName;
|
|
||||||
this.velocity = boatVelocity;
|
|
||||||
this.legDistance = 0.0;
|
|
||||||
this.color = Colors.getColor();
|
|
||||||
this.shortName = shortName;
|
|
||||||
this.boatObject.getPoints().addAll(BOAT_WIDTH /2,0.0,
|
|
||||||
BOAT_WIDTH, BOAT_HEIGHT,
|
|
||||||
0.0, BOAT_HEIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the team sailing the boat
|
|
||||||
*
|
|
||||||
* @return The name of the team
|
|
||||||
*/
|
|
||||||
public String getTeamName() {
|
|
||||||
return this.teamName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the name of the team sailing the boat
|
|
||||||
*
|
|
||||||
* @param teamName The name of the team
|
|
||||||
*/
|
|
||||||
public void setTeamName(String teamName) {
|
|
||||||
this.teamName = teamName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets velocity of the boat
|
|
||||||
*
|
|
||||||
* @return a float number of the boat velocity
|
|
||||||
*/
|
|
||||||
public double getVelocity() {
|
|
||||||
return this.velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets velocity of the boat
|
|
||||||
*
|
|
||||||
* @param velocity The velocity of boat
|
|
||||||
*/
|
|
||||||
public void setVelocity(double velocity) {
|
|
||||||
this.velocity = velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the boats location
|
|
||||||
*
|
|
||||||
* @param lat, the boats latitude
|
|
||||||
* @param lon, the boats longitude
|
|
||||||
*/
|
|
||||||
public void setLocation(double lat, double lon) {
|
|
||||||
this.lat = lat;
|
|
||||||
this.lon = lon;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getLegDistance() {
|
|
||||||
return legDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLegDistance(double legDistance){
|
|
||||||
this.legDistance = legDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLatitude(){
|
|
||||||
return this.lat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLongitude(){
|
|
||||||
return this.lon;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color getColor() {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getSpeedInKnots(){
|
|
||||||
return Math.round((this.velocity * 1.94384) * 100d) / 100d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Leg getCurrentLeg() {
|
|
||||||
return currentLeg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrentLeg(Leg currentLeg) {
|
|
||||||
this.currentLeg = currentLeg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHeading(double heading){
|
|
||||||
this.heading = heading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getHeading(){
|
|
||||||
return this.heading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getShortName(){
|
|
||||||
return this.shortName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the boat and its children annotations from its current coordinates by specified amounts.
|
|
||||||
* @param x The amount to move the X coordinate by
|
|
||||||
* @param y The amount to move the Y coordinate by
|
|
||||||
*/
|
|
||||||
void moveBoatBy(Double x, Double y) {
|
|
||||||
boatObject.setLayoutX(boatObject.getLayoutX() + x);
|
|
||||||
boatObject.setLayoutY(boatObject.getLayoutY() + y);
|
|
||||||
boatObject.relocate(boatObject.getLayoutX(), boatObject.getLayoutY());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 moveBoatTo(int x, int y) {
|
|
||||||
boatObject.setLayoutX(x);
|
|
||||||
boatObject.setLayoutY(y);
|
|
||||||
boatObject.relocate(boatObject.getLayoutX(), boatObject.getLayoutY());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Polygon getBoatObject() {
|
|
||||||
return boatObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by ryan_ on 16/03/2017.
|
|
||||||
*/
|
|
||||||
public enum Colors {
|
|
||||||
RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE;
|
|
||||||
|
|
||||||
static Integer index = 0;
|
|
||||||
|
|
||||||
public static Color getColor() {
|
|
||||||
index++;
|
|
||||||
if (index > 6) {
|
|
||||||
index = 1;
|
|
||||||
}
|
|
||||||
return Color.valueOf(values()[index-1].toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by wmu16 on 4/8/17.
|
|
||||||
*/
|
|
||||||
import javafx.scene.canvas.Canvas;
|
|
||||||
import javafx.util.Pair;
|
|
||||||
import seng302.models.mark.Mark;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class for describing the course information for the canvas
|
|
||||||
* Created by wmu16 on 22/03/17.
|
|
||||||
*/
|
|
||||||
public class Course {
|
|
||||||
|
|
||||||
private ArrayList<Leg> Legs;
|
|
||||||
private ArrayList<Mark> marks;
|
|
||||||
public static final Integer SCALE = 160000;
|
|
||||||
|
|
||||||
|
|
||||||
public Course(ArrayList<Mark> marks) {
|
|
||||||
this.marks = marks;
|
|
||||||
this.Legs = makeLegs();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the race legs out of all the marker marks for the course
|
|
||||||
* @return ArrayList of Legs
|
|
||||||
*/
|
|
||||||
private ArrayList<Leg> makeLegs() {
|
|
||||||
ArrayList<Leg> Legs = new ArrayList<>();
|
|
||||||
for (int i = 0; i < marks.size()-1; i++) {
|
|
||||||
Legs.add(new Leg(marks.get(i), marks.get(i+1)));
|
|
||||||
}
|
|
||||||
return Legs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ArrayList<Mark> getMarks() {
|
|
||||||
return marks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getDistanceScaleFactor() {
|
|
||||||
return SCALE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<Leg> getLegs() {
|
|
||||||
return Legs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
|
|
||||||
import seng302.models.mark.Mark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class for defining the leg of a race between two markers
|
|
||||||
* Created by cir27 on 3/03/17.
|
|
||||||
*/
|
|
||||||
public class Leg {
|
|
||||||
|
|
||||||
private final double ORIGIN_LAT = 32.320504;
|
|
||||||
private final double ORIGIN_LON = -64.857063;
|
|
||||||
private final double SCALE = 16000;
|
|
||||||
|
|
||||||
private Double distance;
|
|
||||||
private Double heading;
|
|
||||||
private Mark end;
|
|
||||||
private Mark start;
|
|
||||||
|
|
||||||
Leg(Mark start, Mark end) {
|
|
||||||
this.distance = calculateMarkerDistance(start, end);
|
|
||||||
this.heading = angleFromCoordinate(start, end);
|
|
||||||
this.start = start;
|
|
||||||
this.end = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the euclidian distance between two markers on the canvas using xy coordinates
|
|
||||||
*
|
|
||||||
* @param geoPointOne first geographical point
|
|
||||||
* @param geoPointTwo second geographical point
|
|
||||||
* @return the distance between two points in meters
|
|
||||||
*/
|
|
||||||
private Double calculateMarkerDistance(Mark geoPointOne, Mark geoPointTwo) {
|
|
||||||
|
|
||||||
double earth_radius = 6378.137;
|
|
||||||
double dLat = geoPointTwo.getLatitude() * Math.PI / 180 - geoPointOne.getLatitude() * Math.PI / 180;
|
|
||||||
double dLon = geoPointTwo.getLongitude() * Math.PI / 180 - geoPointOne.getLongitude() * Math.PI / 180;
|
|
||||||
|
|
||||||
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(geoPointOne.getLatitude() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|
||||||
|
|
||||||
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
||||||
double d = earth_radius * c;
|
|
||||||
|
|
||||||
return d * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the angle between to angular co-ordinates on a sphere.
|
|
||||||
*
|
|
||||||
* @param geoPointOne first geographical location
|
|
||||||
* @param geoPointTwo second geographical location
|
|
||||||
* @return the angle from point one to point two
|
|
||||||
*/
|
|
||||||
private Double angleFromCoordinate(Mark geoPointOne, Mark geoPointTwo) {
|
|
||||||
|
|
||||||
if (geoPointTwo == null){
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double x1 = (geoPointOne.getLongitude() - ORIGIN_LON) * SCALE;
|
|
||||||
double y1 = (ORIGIN_LAT - geoPointOne.getLatitude()) * SCALE;
|
|
||||||
double x2 = (geoPointTwo.getLongitude() - ORIGIN_LON) * SCALE;
|
|
||||||
double y2 = (ORIGIN_LAT - geoPointTwo.getLatitude()) * SCALE;
|
|
||||||
|
|
||||||
double headingRadians = Math.atan2(y2-y1, x2-x1);
|
|
||||||
|
|
||||||
if (headingRadians < 0){
|
|
||||||
headingRadians += 2 * Math.PI;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert back to degrees, and flip 180 degrees
|
|
||||||
// return ((headingRadians) * 180) / Math.PI;
|
|
||||||
return (Math.toDegrees(headingRadians) + 90) % 360;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Double getDistance()
|
|
||||||
{
|
|
||||||
return this.distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mark getEnd()
|
|
||||||
{
|
|
||||||
return this.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mark getStart() {
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getHeading()
|
|
||||||
{
|
|
||||||
return this.heading;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,236 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
import javafx.animation.AnimationTimer;
|
|
||||||
import seng302.controllers.Controller;
|
|
||||||
import seng302.models.mark.Mark;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Race class containing the boats and legs in the race
|
|
||||||
* Created by mra106 on 8/3/2017.
|
|
||||||
*/
|
|
||||||
public class Race extends Thread {
|
|
||||||
|
|
||||||
private static final double UPDATE_TIME = 0.016666; // 1 / 60 ie 60fps
|
|
||||||
|
|
||||||
|
|
||||||
private ArrayList<Boat> boats; // The boats in the race
|
|
||||||
private ArrayList<Boat> finishingOrder; // The order in which the boats finish the race
|
|
||||||
private List<Mark> markers; // Marks in the race
|
|
||||||
private List<Leg> raceLegs;
|
|
||||||
private boolean raceFinished = false; // Race is finished
|
|
||||||
private int raceTime = -2; // Current time in the race
|
|
||||||
private Double timeScale = null;
|
|
||||||
private boolean raceStarted = false;
|
|
||||||
private Controller controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Race class containing the boats and legs in the race
|
|
||||||
*/
|
|
||||||
public Race(List<Mark> markers, ArrayList<Boat> boats, Double timescale, Controller controller) {
|
|
||||||
this.boats = boats;
|
|
||||||
this.markers = markers;
|
|
||||||
this.raceLegs = makeRaceLegs();
|
|
||||||
this.controller = controller;
|
|
||||||
|
|
||||||
this.timeScale = timescale;
|
|
||||||
this.finishingOrder = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the race legs out of all the marker points for the course
|
|
||||||
* @return ArrayList of raceLegs
|
|
||||||
*/
|
|
||||||
private ArrayList<Leg> makeRaceLegs() {
|
|
||||||
ArrayList<Leg> raceLegs = new ArrayList<>();
|
|
||||||
for (int i=0; i < markers.size()-1; i++) {
|
|
||||||
raceLegs.add(new Leg(markers.get(i), markers.get(i+1)));
|
|
||||||
}
|
|
||||||
return raceLegs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A timer that is called every frame to call the action of moving the boats
|
|
||||||
*/
|
|
||||||
private AnimationTimer at = new AnimationTimer() {
|
|
||||||
@Override
|
|
||||||
public void handle(long now) {
|
|
||||||
|
|
||||||
//Updating Boat positions
|
|
||||||
if(finishingOrder.size() != boats.size()) {
|
|
||||||
// update the time
|
|
||||||
boats.stream().filter(boat -> !finishingOrder.contains(boat)).forEach(boat -> {
|
|
||||||
updateBoatPosition(boat);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
at.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begins the race simulation
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!raceStarted) {
|
|
||||||
// controller.getPlayPauseButton().setDisable(true);
|
|
||||||
at.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the coordinates of the boats.
|
|
||||||
* @param boat The boat to update the position of
|
|
||||||
*/
|
|
||||||
private void updateBoatPosition(Boat boat) {
|
|
||||||
Double thisHeading = boat.getHeading();
|
|
||||||
// TODO: 4/8/17 wmu16 - Add a distance scale factor from lat long distance in Metres to xy equivalent
|
|
||||||
Double hypMove = boat.getVelocity() * UPDATE_TIME * timeScale; //* distanceScaleFactor
|
|
||||||
boat.setLegDistance(boat.getLegDistance() + hypMove);
|
|
||||||
moveBoat(boat, thisHeading, hypMove);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves a boat along coordinates by breaking down the distance moved along the hypotenuse into x and y components
|
|
||||||
* @param boat The Boat to move
|
|
||||||
* @param heading The heading the boat is moving at
|
|
||||||
* @param hypMove The distance moved along the hypotenuse (absolute distance)
|
|
||||||
*/
|
|
||||||
private void moveBoat(Boat boat, Double heading, Double hypMove) {
|
|
||||||
//If the boat has not yet passed the marker at the end of the leg increase its (x,y) as per normal
|
|
||||||
// TODO: 4/8/17 wmu16 - Initialising boat positions and legs and headings etc.
|
|
||||||
if(boat.getLegDistance() <= boat.getCurrentLeg().getDistance()) {
|
|
||||||
Double xMove = hypMove * Math.sin(Math.toRadians(heading));
|
|
||||||
Double yMove = - hypMove * Math.cos(Math.toRadians(heading));
|
|
||||||
boat.moveBoatBy(xMove, yMove);
|
|
||||||
|
|
||||||
//If the boat has finished...
|
|
||||||
} else if (getNextRaceLeg(boat.getCurrentLeg()).equals(boat.getCurrentLeg())) {
|
|
||||||
finishingOrder.add(boat);
|
|
||||||
//Otherwise apply the overflow distance of the leg to the next leg
|
|
||||||
} else {
|
|
||||||
Double overflowDistance = boat.getLegDistance() - boat.getCurrentLeg().getDistance();
|
|
||||||
boat.setCurrentLeg(getNextRaceLeg(boat.getCurrentLeg()));
|
|
||||||
boat.setHeading(boat.getCurrentLeg().getHeading());
|
|
||||||
boat.setLegDistance(overflowDistance);
|
|
||||||
moveBoat(boat, boat.getHeading(), overflowDistance);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next leg in the race
|
|
||||||
* @param currentRaceLeg The leg that you are currently on
|
|
||||||
* @return The next race leg or the same race leg if it has reached the end
|
|
||||||
*/
|
|
||||||
private Leg getNextRaceLeg(Leg currentRaceLeg) {
|
|
||||||
Leg nextRaceLeg = currentRaceLeg;
|
|
||||||
for(int i = 0; i< raceLegs.size() - 1; i++) {
|
|
||||||
if (raceLegs.get(i).equals(currentRaceLeg)) {
|
|
||||||
nextRaceLeg = raceLegs.get(i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nextRaceLeg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of boats in the order that they
|
|
||||||
* finished the race (position 0 is first place)
|
|
||||||
*
|
|
||||||
* @return a list of boats
|
|
||||||
*/
|
|
||||||
public Boat[] getFinishedBoats() {
|
|
||||||
return this.finishingOrder.toArray(new Boat[this.finishingOrder.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of boats in the race
|
|
||||||
*
|
|
||||||
* @return a list of the boats competing in the race
|
|
||||||
*/
|
|
||||||
public Boat[] getBoats() {
|
|
||||||
return boats.toArray(new Boat[boats.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a race and generates all events for the race.
|
|
||||||
*/
|
|
||||||
public void startRace() {
|
|
||||||
// record start time.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void pause() {
|
|
||||||
at.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of marks in the markers
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<Mark> getMarkers() {
|
|
||||||
return markers;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a boat as finished
|
|
||||||
* @param boat The boat that has finished the race
|
|
||||||
*/
|
|
||||||
public void setBoatFinished(Boat boat){
|
|
||||||
this.finishingOrder.add(boat);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the race as finished
|
|
||||||
*/
|
|
||||||
public void setRaceFinished(){
|
|
||||||
this.raceFinished = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether or not the race is finished
|
|
||||||
* @return true if the race is finished
|
|
||||||
*/
|
|
||||||
public boolean isRaceFinished(){
|
|
||||||
return this.raceFinished;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the race time
|
|
||||||
* @param raceTime the race time in seconds
|
|
||||||
*/
|
|
||||||
public void setRaceTime(int raceTime){
|
|
||||||
this.raceTime = raceTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the race time
|
|
||||||
* @return the race time in seconds
|
|
||||||
*/
|
|
||||||
public int getRaceTime(){
|
|
||||||
return this.raceTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increment the race time by one second
|
|
||||||
*/
|
|
||||||
public void incrementRaceTime() {
|
|
||||||
this.raceTime += this.timeScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Leg> getRaceLegs() {
|
|
||||||
return raceLegs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package seng302.models.mark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To represent a gate mark which contains two single marks.
|
|
||||||
* Created by ptg19 on 16/03/17.
|
|
||||||
* Modified by Haoming Yin (hyi25) on 17/3/2017.
|
|
||||||
*/
|
|
||||||
public class GateMark extends Mark {
|
|
||||||
|
|
||||||
private SingleMark singleMark1;
|
|
||||||
private SingleMark singleMark2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of Gate Mark which contains two single mark
|
|
||||||
* @param name the name of the gate mark
|
|
||||||
* @param singleMark1 one single mark inside of the gate mark
|
|
||||||
* @param singleMark2 the second mark inside of the gate mark
|
|
||||||
*/
|
|
||||||
public GateMark(String name, SingleMark singleMark1, SingleMark singleMark2, double latitude, double longitude) {
|
|
||||||
super(name, MarkType.GATE_MARK, latitude, longitude);
|
|
||||||
this.singleMark1 = singleMark1;
|
|
||||||
this.singleMark2 = singleMark2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SingleMark getSingleMark1() {
|
|
||||||
return singleMark1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSingleMark1(SingleMark singleMark1) {
|
|
||||||
this.singleMark1 = singleMark1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SingleMark getSingleMark2() {
|
|
||||||
return singleMark2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSingleMark2(SingleMark singleMark2) {
|
|
||||||
this.singleMark2 = singleMark2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLatitude(){
|
|
||||||
//return (this.getSingleMark1().getLatitude() + this.getSingleMark2().getLatitude()) / 2;
|
|
||||||
return (this.getSingleMark1().getLatitude());
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLongitude(){
|
|
||||||
//return (this.getSingleMark1().getLongitude() + this.getSingleMark2().getLongitude()) / 2;
|
|
||||||
return (this.getSingleMark1().getLongitude());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package seng302.models.mark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An abstract class to represent general marks
|
|
||||||
* Created by Haoming Yin (hyi25) on 17/3/17.
|
|
||||||
*/
|
|
||||||
public abstract class Mark {
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
private MarkType markType;
|
|
||||||
private double latitude;
|
|
||||||
private double longitude;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a mark instance by passing its name and type
|
|
||||||
* @param name the name of the mark
|
|
||||||
* @param markType the type of mark. either GATE_MARK or SINGLE_MARK.
|
|
||||||
*/
|
|
||||||
public Mark (String name, MarkType markType) {
|
|
||||||
this.name = name;
|
|
||||||
this.markType = markType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mark(String name, MarkType markType, double latitude, double longitude) {
|
|
||||||
this.name = name;
|
|
||||||
this.markType = markType;
|
|
||||||
this.latitude = latitude;
|
|
||||||
this.longitude = longitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MarkType getMarkType() {
|
|
||||||
return markType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMarkType(MarkType markType) {
|
|
||||||
this.markType = markType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLatitude() {
|
|
||||||
return latitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLongitude() {
|
|
||||||
return longitude;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package seng302.models.mark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To represent two types of mark
|
|
||||||
* Created by Haoming Yin (hyi25) on 17/3/17.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public enum MarkType {
|
|
||||||
|
|
||||||
UNKNOWN(0),
|
|
||||||
ROUNDING_MARK(1),
|
|
||||||
GATE_MARK(2),
|
|
||||||
// above mark types are from AC35 spec.
|
|
||||||
|
|
||||||
// more specific types for gate mark
|
|
||||||
WINDWARD(201),
|
|
||||||
LEEWARD(202),
|
|
||||||
START(203),
|
|
||||||
FINISH(204),
|
|
||||||
|
|
||||||
// single_mark is from old team-13 code base, for compatibility, it has not
|
|
||||||
// been removed yet
|
|
||||||
SINGLE_MARK(5);
|
|
||||||
|
|
||||||
private int type;
|
|
||||||
|
|
||||||
MarkType(int markType) {
|
|
||||||
this.type = markType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getType() {
|
|
||||||
return this.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package seng302.models.mark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the marker as a single mark
|
|
||||||
*
|
|
||||||
* Created by Haoming Yin (hyi25) on 17/3/2017
|
|
||||||
*/
|
|
||||||
public class SingleMark extends Mark {
|
|
||||||
private double lat;
|
|
||||||
private double lon;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a marker
|
|
||||||
*
|
|
||||||
* @param name, the name of the marker*
|
|
||||||
* @param lat, the latitude of the marker
|
|
||||||
* @param lon, the longitude of the marker
|
|
||||||
*/
|
|
||||||
public SingleMark(String name, double lat, double lon) {
|
|
||||||
super(name, MarkType.SINGLE_MARK);
|
|
||||||
this.lat = lat;
|
|
||||||
this.lon = lon;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the marker at the beginning of a leg
|
|
||||||
*
|
|
||||||
* @param name, the name of the marker
|
|
||||||
*/
|
|
||||||
public SingleMark(String name) {
|
|
||||||
super(name, MarkType.SINGLE_MARK);
|
|
||||||
this.lat = 0;
|
|
||||||
this.lon = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLatitude() {
|
|
||||||
return this.lat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLongitude() {
|
|
||||||
return this.lon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package seng302.models.parsers;
|
|
||||||
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
|
|
||||||
import java.util.DoubleSummaryStatistics;
|
|
||||||
|
|
||||||
public class ConfigParser extends FileParser {
|
|
||||||
|
|
||||||
private Document doc;
|
|
||||||
|
|
||||||
public ConfigParser(String path) {
|
|
||||||
super(path);
|
|
||||||
this.doc = this.parseFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets wind direction from config file.
|
|
||||||
*
|
|
||||||
* @return a double type degree, or 0 if no value or invalid value is found
|
|
||||||
*/
|
|
||||||
public double getWindDirection() {
|
|
||||||
return getDoubleByTagName("wind-direction", 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a non negative time scale for the race
|
|
||||||
*
|
|
||||||
* @return a double type scale, or 0 if no scale or invalid scale is found
|
|
||||||
*/
|
|
||||||
public double getTimeScale() {
|
|
||||||
return getDoubleByTagName("time-scale", 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a double type number by given tag name found in xml file
|
|
||||||
*
|
|
||||||
* @param tagName a string of tag name
|
|
||||||
* @param defaultVal value returned if no value or invalid value is found
|
|
||||||
* @return value found
|
|
||||||
*/
|
|
||||||
public double getDoubleByTagName(String tagName, double defaultVal) {
|
|
||||||
double val = defaultVal;
|
|
||||||
try {
|
|
||||||
Node node = this.doc.getElementsByTagName(tagName).item(0);
|
|
||||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
|
||||||
Element element = (Element) node;
|
|
||||||
val = Double.valueOf(element.getTextContent());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
} finally {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a string by given tag name found in xml file
|
|
||||||
*
|
|
||||||
* @param tagName a string of tag name
|
|
||||||
* @param defaultVal a string returned if no value or invalid value is found
|
|
||||||
* @return string found
|
|
||||||
*/
|
|
||||||
public String getStringByTagName(String tagName, String defaultVal) {
|
|
||||||
String string = defaultVal;
|
|
||||||
try {
|
|
||||||
Node node = this.doc.getElementsByTagName(tagName).item(0);
|
|
||||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
|
||||||
Element element = (Element) node;
|
|
||||||
string = element.getTextContent();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
} finally {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package seng302.models.parsers;
|
|
||||||
|
|
||||||
import org.w3c.dom.*;
|
|
||||||
import seng302.models.mark.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* parse a course xml file
|
|
||||||
* Created by Haoming Yin (hyi25) on 16/3/2017
|
|
||||||
*/
|
|
||||||
public class CourseParser extends FileParser {
|
|
||||||
|
|
||||||
private Document doc;
|
|
||||||
private HashMap<String, Mark> marks = new HashMap<>();
|
|
||||||
|
|
||||||
public CourseParser(String path) {
|
|
||||||
super(path);
|
|
||||||
this.doc = this.parseFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a mark by given node
|
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* @return a mark, or null if fails to create a mark
|
|
||||||
*/
|
|
||||||
private SingleMark generateSingleMark(Node node) {
|
|
||||||
try {
|
|
||||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
|
||||||
Element element = (Element) node;
|
|
||||||
String name = element.getElementsByTagName("name").item(0).getTextContent();
|
|
||||||
double lat = Double.valueOf(element.getElementsByTagName("latitude").item(0).getTextContent());
|
|
||||||
double lon = Double.valueOf(element.getElementsByTagName("longitude").item(0).getTextContent());
|
|
||||||
SingleMark singleMark = new SingleMark(name, lat, lon);
|
|
||||||
return singleMark;
|
|
||||||
} else {
|
|
||||||
throw new NoSuchElementException("Cannot generate a mark by given node.");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* generate an arrayList of gates
|
|
||||||
*
|
|
||||||
* @return an arrayList of gates, or null if no gate has been found.
|
|
||||||
*/
|
|
||||||
private void generateGateMarks() {
|
|
||||||
ArrayList<GateMark> gateMarks = new ArrayList<>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
NodeList nodes = doc.getElementsByTagName("gate");
|
|
||||||
|
|
||||||
for (int i = 0; i < nodes.getLength(); i++) {
|
|
||||||
Node node = nodes.item(i);
|
|
||||||
|
|
||||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
|
||||||
Element element = (Element) node;
|
|
||||||
String name = element.getElementsByTagName("name").item(0).getTextContent();
|
|
||||||
SingleMark mark1 = generateSingleMark(element.getElementsByTagName("mark").item(0));
|
|
||||||
SingleMark mark2 = generateSingleMark(element.getElementsByTagName("mark").item(1));
|
|
||||||
GateMark gateMark = new GateMark(name, mark1, mark2, mark1.getLatitude(), mark1.getLongitude());
|
|
||||||
marks.put(name, gateMark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* generate an arrayList of marks
|
|
||||||
*
|
|
||||||
* @return an arrayList of marks, or null if no gate has been found.
|
|
||||||
*/
|
|
||||||
private void generateSingleMarks() {
|
|
||||||
ArrayList<SingleMark> singleMarks = new ArrayList<>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// find the "marks" tag
|
|
||||||
Node node = doc.getElementsByTagName("marks").item(0);
|
|
||||||
// iterate all "marks"'s children
|
|
||||||
for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {
|
|
||||||
// if node's tag name is "mark"
|
|
||||||
if (n.getNodeType() == Node.ELEMENT_NODE) {
|
|
||||||
Element element = (Element) n;
|
|
||||||
if (element.getNodeName() == "mark") {
|
|
||||||
Mark mark = generateSingleMark(n);
|
|
||||||
marks.put(mark.getName(), mark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the order of all the marks along a course
|
|
||||||
*
|
|
||||||
* @return an arrayList of the names of ordered course marks
|
|
||||||
*/
|
|
||||||
private ArrayList<String> getOrder() {
|
|
||||||
ArrayList<String> markOrder = new ArrayList<>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Node orderNode = doc.getElementsByTagName("order").item(0);
|
|
||||||
for (Node node = orderNode.getFirstChild(); node != null; node = node.getNextSibling()) {
|
|
||||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
|
||||||
Element element = (Element) node;
|
|
||||||
String name = element.getTextContent();
|
|
||||||
markOrder.add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return markOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<Mark> getCourse() {
|
|
||||||
generateSingleMarks();
|
|
||||||
generateGateMarks();
|
|
||||||
ArrayList<Mark> course = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
for (String mark : getOrder()) {
|
|
||||||
course.add(marks.get(mark));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return course;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package seng302.models.parsers;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Haoming Yin (hyi25) on 16/3/2017
|
|
||||||
*/
|
|
||||||
public abstract class FileParser {
|
|
||||||
|
|
||||||
private String filePath;
|
|
||||||
|
|
||||||
public FileParser(String path) {
|
|
||||||
this.filePath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Document parseFile() {
|
|
||||||
try {
|
|
||||||
InputStream is = getClass().getResourceAsStream(this.filePath);
|
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
|
||||||
Document doc = builder.parse(is);
|
|
||||||
// optional, in order to recover info from broken line.
|
|
||||||
doc.getDocumentElement().normalize();
|
|
||||||
return doc;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package seng302.models.parsers;
|
|
||||||
|
|
||||||
import org.w3c.dom.*;
|
|
||||||
import seng302.models.Boat;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
public class TeamsParser extends FileParser {
|
|
||||||
|
|
||||||
private Document doc;
|
|
||||||
|
|
||||||
public TeamsParser(String path) {
|
|
||||||
super(path);
|
|
||||||
this.doc = this.parseFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a boat instance by a given team node
|
|
||||||
* @param node a boat node containing name, alias and velocity
|
|
||||||
* @return an instance of Boat
|
|
||||||
*/
|
|
||||||
private Boat parseBoat(Node node) {
|
|
||||||
try {
|
|
||||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
|
||||||
Element element = (Element) node;
|
|
||||||
String name = element.getElementsByTagName("name").item(0).getTextContent();
|
|
||||||
String alias = element.getElementsByTagName("alias").item(0).getTextContent();
|
|
||||||
double velocity = Double.valueOf(element.getElementsByTagName("velocity").item(0).getTextContent());
|
|
||||||
Boat boat = new Boat(name, velocity, alias);
|
|
||||||
return boat;
|
|
||||||
} else {
|
|
||||||
throw new NoSuchElementException("Cannot generate a boat by given node");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an arraylist of boats instance.
|
|
||||||
* @return an arraylist of boats in teams file
|
|
||||||
*/
|
|
||||||
public ArrayList<Boat> getBoats() {
|
|
||||||
ArrayList<Boat> boats = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
NodeList nodes = this.doc.getElementsByTagName("team");
|
|
||||||
for (int i = 0; i < nodes.getLength(); i++) {
|
|
||||||
Node node = nodes.item(i);
|
|
||||||
|
|
||||||
boats.add(parseBoat(node));
|
|
||||||
}
|
|
||||||
return boats;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -17,14 +17,13 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
private StreamingServerSocket server;
|
private StreamingServerSocket server;
|
||||||
private long startTime;
|
private long startTime;
|
||||||
boolean raceStarted = false;
|
boolean raceStarted = false;
|
||||||
boolean raceFinished = false;
|
|
||||||
Map<Integer,Boolean> boatsFinished = new HashMap<>();
|
Map<Integer,Boolean> boatsFinished = new HashMap<>();
|
||||||
private List<Boat> boats;
|
private List<Boat> boats;
|
||||||
private Simulator raceSimulator;
|
private Simulator raceSimulator;
|
||||||
|
|
||||||
private final int HEARTBEAT_PERIOD = 5000;
|
private final int HEARTBEAT_PERIOD = 5000;
|
||||||
private final int RACE_STATUS_PERIOD = 1000/2;
|
private final int RACE_STATUS_PERIOD = 1000;
|
||||||
private final int RACE_START_STATUS_PERIOD = 1000/2;
|
private final int RACE_START_STATUS_PERIOD = 1000;
|
||||||
private final int BOAT_LOCATION_PERIOD = 1000/5;
|
private final int BOAT_LOCATION_PERIOD = 1000/5;
|
||||||
private final int PORT_NUMBER = 8085;
|
private final int PORT_NUMBER = 8085;
|
||||||
private final int TIME_TILL_RACE_START = 20*1000;
|
private final int TIME_TILL_RACE_START = 20*1000;
|
||||||
@@ -188,6 +187,7 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
* Start sending race start status messages until race starts
|
* Start sending race start status messages until race starts
|
||||||
*/
|
*/
|
||||||
private void startSendingRaceStatusMessages(){
|
private void startSendingRaceStatusMessages(){
|
||||||
|
serverLog("Sending race status messages", 0);
|
||||||
Timer t = new Timer();
|
Timer t = new Timer();
|
||||||
t.schedule(new TimerTask() {
|
t.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
@@ -248,9 +248,6 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
sendXml();
|
sendXml();
|
||||||
startSendingRaceStartStatusMessages();
|
startSendingRaceStartStatusMessages();
|
||||||
startSendingRaceStatusMessages();
|
startSendingRaceStatusMessages();
|
||||||
|
|
||||||
//serverLog("Sending Race Status Messages", 0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -267,16 +264,15 @@ public class ServerThread implements Runnable, Observer {
|
|||||||
|
|
||||||
for (Boat b : ((Simulator) o).getBoats()){
|
for (Boat b : ((Simulator) o).getBoats()){
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Message m = new BoatLocationMessage(b.getSourceID(), 1, b.getLat(),
|
Message m = new BoatLocationMessage(b.getSourceID(), 1, b.getLat(),
|
||||||
b.getLng(), b.getHeadingCorner().getBearingToNextCorner(),
|
b.getLng(), b.getHeadingCorner().getBearingToNextCorner(),
|
||||||
((long) b.getSpeed()));
|
((long) b.getSpeed()));
|
||||||
server.send(m);
|
server.send(m);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
serverLog("Couldn't send a boat status message", 1);
|
serverLog("Couldn't send a boat status message", 3);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (NullPointerException e){
|
catch (NullPointerException e){
|
||||||
//raceFinished = true;
|
|
||||||
serverLog("Boat " + b.getSourceID() + " finished the race", 1);
|
serverLog("Boat " + b.getSourceID() + " finished the race", 1);
|
||||||
boatsFinished.put(b.getSourceID(), true);
|
boatsFinished.put(b.getSourceID(), true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ import java.util.List;
|
|||||||
class StreamingServerSocket {
|
class StreamingServerSocket {
|
||||||
private ServerSocketChannel socket;
|
private ServerSocketChannel socket;
|
||||||
private SocketChannel client;
|
private SocketChannel client;
|
||||||
private List<Socket> clients;
|
|
||||||
private short seqNum;
|
private short seqNum;
|
||||||
private boolean isServerStarted;
|
private boolean isServerStarted;
|
||||||
|
|
||||||
StreamingServerSocket(int port) throws IOException{
|
StreamingServerSocket(int port) throws IOException{
|
||||||
socket = ServerSocketChannel.open();
|
socket = ServerSocketChannel.open();
|
||||||
socket.socket().bind(new InetSocketAddress("localhost", port));
|
socket.socket().bind(new InetSocketAddress("localhost", port));
|
||||||
clients = new ArrayList<>();
|
|
||||||
//socket.setSoTimeout(10000);
|
//socket.setSoTimeout(10000);
|
||||||
seqNum = 0;
|
seqNum = 0;
|
||||||
isServerStarted = false;
|
isServerStarted = false;
|
||||||
@@ -50,11 +48,8 @@ class StreamingServerSocket {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//DataOutputStream outputStream = new DataOutputStream(client.getOutputStream());
|
|
||||||
//System.out.println(client);
|
|
||||||
message.send(client);
|
message.send(client);
|
||||||
|
|
||||||
|
|
||||||
seqNum++;
|
seqNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,9 +133,7 @@ public class BoatLocationMessage extends Message {
|
|||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
heading = (heading + 180.0) % 360.0;
|
long headingToSend = (long)((heading/360.0) * 65535.0);
|
||||||
|
|
||||||
long headingToSend = (long)((heading/360.0)*49152.0);
|
|
||||||
|
|
||||||
putByte((byte) messageVersionNumber);
|
putByte((byte) messageVersionNumber);
|
||||||
putInt(time, 6);
|
putInt(time, 6);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package seng302.server.messages;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
@@ -170,7 +171,6 @@ public abstract class Message {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rewind the buffer to the beginning
|
* Rewind the buffer to the beginning
|
||||||
*/
|
*/
|
||||||
@@ -185,11 +185,13 @@ public abstract class Message {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static byte[] intToByteArray(long val, int len){
|
public static byte[] intToByteArray(long val, int len){
|
||||||
|
long vor = val;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
byte[] data = new byte[len];
|
byte[] data = new byte[len];
|
||||||
|
|
||||||
for (int i = 0; i < len; i++){
|
for (int i = 0; i < len; i++){
|
||||||
data[len - index - 1] = (byte) ((val >>> (8 * index)));
|
data[len - index - 1] = (byte) (val & 0xFF);
|
||||||
|
val >>>= 8;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,9 +204,9 @@ public abstract class Message {
|
|||||||
*/
|
*/
|
||||||
public static void reverse(byte[] data) {
|
public static void reverse(byte[] data) {
|
||||||
for (int left = 0, right = data.length - 1; left < right; left++, right--) {
|
for (int left = 0, right = data.length - 1; left < right; left++, right--) {
|
||||||
byte temp = data[left];
|
byte temp = (byte) (data[left] & 0xff);
|
||||||
data[left] = data[right];
|
data[left] = (byte) (data[right] & 0xff);
|
||||||
data[right] = temp;
|
data[right] = (byte) (temp & 0xff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.Channels;
|
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.nio.channels.WritableByteChannel;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import seng302.server.simulator.parsers.RaceParser;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
public class Simulator extends Observable implements Runnable {
|
public class Simulator extends Observable implements Runnable {
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ public class Simulator extends Observable implements Runnable {
|
|||||||
boat.setLng(startLng);
|
boat.setLng(startLng);
|
||||||
boat.setLastPassedCorner(course.get(0));
|
boat.setLastPassedCorner(course.get(0));
|
||||||
boat.setHeadingCorner(course.get(1));
|
boat.setHeadingCorner(course.get(1));
|
||||||
boat.setSpeed(50000);
|
boat.setSpeed(ThreadLocalRandom.current().nextInt(40000, 60000 + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user