mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge remote-tracking branch 'origin/develop' into issue#5_fix_pre-race_boats_on_leaderboard
# Conflicts: # src/main/java/seng302/controllers/RaceController.java # src/main/java/seng302/controllers/StartScreenController.java
This commit is contained in:
@@ -5,8 +5,8 @@ import javafx.fxml.FXMLLoader;
|
|||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import seng302.models.parsers.StreamParser;
|
import seng302.models.stream.StreamParser;
|
||||||
import seng302.models.parsers.StreamReceiver;
|
import seng302.models.stream.StreamReceiver;
|
||||||
import seng302.server.ServerThread;
|
import seng302.server.ServerThread;
|
||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
@@ -62,7 +62,7 @@ public class App extends Application {
|
|||||||
}
|
}
|
||||||
//Change the StreamReceiver in this else block to change the default data source.
|
//Change the StreamReceiver in this else block to change the default data source.
|
||||||
else{
|
else{
|
||||||
//sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
// sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
||||||
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
package seng302.controllers;
|
package seng302.controllers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
import javafx.beans.property.SimpleDoubleProperty;
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
@@ -12,21 +17,17 @@ import javafx.scene.paint.Color;
|
|||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
import seng302.models.BoatGroup;
|
import seng302.models.BoatGroup;
|
||||||
import seng302.models.Colors;
|
import seng302.models.Colors;
|
||||||
import seng302.models.RaceObject;
|
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
import seng302.models.mark.*;
|
import seng302.models.mark.GateMark;
|
||||||
import seng302.models.parsers.StreamParser;
|
import seng302.models.mark.Mark;
|
||||||
import seng302.models.parsers.XMLParser;
|
import seng302.models.mark.MarkGroup;
|
||||||
import seng302.models.parsers.XMLParser.RaceXMLObject.CompoundMark;
|
import seng302.models.mark.MarkType;
|
||||||
import seng302.models.parsers.XMLParser.RaceXMLObject.Limit;
|
import seng302.models.mark.SingleMark;
|
||||||
import seng302.models.parsers.packets.BoatPositionPacket;
|
import seng302.models.stream.StreamParser;
|
||||||
|
import seng302.models.stream.XMLParser;
|
||||||
import java.text.DecimalFormat;
|
import seng302.models.stream.XMLParser.RaceXMLObject.Limit;
|
||||||
import java.util.ArrayList;
|
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
|
||||||
import java.util.Comparator;
|
import seng302.models.stream.packets.BoatPositionPacket;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.PriorityBlockingQueue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by ptg19 on 15/03/17.
|
* Created by ptg19 on 15/03/17.
|
||||||
@@ -50,6 +51,7 @@ public class CanvasController {
|
|||||||
private final int RHS_BUFFER = BUFFER_SIZE + MARK_SIZE / 2;
|
private final int RHS_BUFFER = BUFFER_SIZE + MARK_SIZE / 2;
|
||||||
private final int TOP_BUFFER = BUFFER_SIZE;
|
private final int TOP_BUFFER = BUFFER_SIZE;
|
||||||
private final int BOT_BUFFER = TOP_BUFFER + MARK_SIZE / 2;
|
private final int BOT_BUFFER = TOP_BUFFER + MARK_SIZE / 2;
|
||||||
|
private boolean horizontalInversion = false;
|
||||||
|
|
||||||
private double distanceScaleFactor;
|
private double distanceScaleFactor;
|
||||||
private ScaleDirection scaleDirection;
|
private ScaleDirection scaleDirection;
|
||||||
@@ -59,16 +61,15 @@ public class CanvasController {
|
|||||||
private Mark maxLonPoint;
|
private Mark maxLonPoint;
|
||||||
private double referencePointX;
|
private double referencePointX;
|
||||||
private double referencePointY;
|
private double referencePointY;
|
||||||
private double metersToPixels;
|
|
||||||
private List<RaceObject> raceObjects = new ArrayList<>();
|
private List<MarkGroup> markGroups = new ArrayList<>();
|
||||||
private List<Mark> raceMarks = new ArrayList<>();
|
private List<BoatGroup> boatGroups = new ArrayList<>();
|
||||||
|
|
||||||
//FRAME RATE
|
//FRAME RATE
|
||||||
private static final double UPDATE_TIME = 0.016666; // 1 / 60 ie 60fps
|
private Double frameRate = 60.0;
|
||||||
private final long[] frameTimes = new long[30];
|
private final long[] frameTimes = new long[30];
|
||||||
private int frameTimeIndex = 0;
|
private int frameTimeIndex = 0;
|
||||||
private boolean arrayFilled = false;
|
private boolean arrayFilled = false;
|
||||||
private DecimalFormat decimalFormat2dp = new DecimalFormat("0.00");
|
|
||||||
|
|
||||||
public AnimationTimer timer;
|
public AnimationTimer timer;
|
||||||
|
|
||||||
@@ -91,8 +92,6 @@ public class CanvasController {
|
|||||||
// Bind canvas size to stack pane size.
|
// Bind canvas size to stack pane size.
|
||||||
canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH));
|
canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH));
|
||||||
canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT));
|
canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT));
|
||||||
//group.minWidth(CANVAS_WIDTH);
|
|
||||||
//group.minHeight(CANVAS_HEIGHT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeCanvas (){
|
public void initializeCanvas (){
|
||||||
@@ -106,7 +105,8 @@ public class CanvasController {
|
|||||||
|
|
||||||
|
|
||||||
// TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml
|
// TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml
|
||||||
drawBoats();
|
initializeBoats();
|
||||||
|
initializeMarks();
|
||||||
timer = new AnimationTimer() {
|
timer = new AnimationTimer() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -123,13 +123,13 @@ public class CanvasController {
|
|||||||
if (arrayFilled) {
|
if (arrayFilled) {
|
||||||
elapsedNanos = now - oldFrameTime ;
|
elapsedNanos = now - oldFrameTime ;
|
||||||
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
|
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
|
||||||
Double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
|
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.
|
// TODO: 1/05/17 cir27 - Make the RaceObjects update on the actual delay.
|
||||||
elapsedNanos = 1000 / 60;
|
elapsedNanos = 1000 / 60;
|
||||||
updateRaceObjects();
|
updateGroups();
|
||||||
if (StreamParser.isRaceFinished()) {
|
if (StreamParser.isRaceFinished()) {
|
||||||
this.stop();
|
this.stop();
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ public class CanvasController {
|
|||||||
Point2D borderPoint1 = findScaledXY(thisMark1);
|
Point2D borderPoint1 = findScaledXY(thisMark1);
|
||||||
Point2D borderPoint2 = findScaledXY(thisMark2);
|
Point2D borderPoint2 = findScaledXY(thisMark2);
|
||||||
gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(),
|
gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(),
|
||||||
borderPoint2.getX(), borderPoint2.getY());
|
borderPoint2.getX(), borderPoint2.getY());
|
||||||
xBoundaryPoints[i] = borderPoint1.getX();
|
xBoundaryPoints[i] = borderPoint1.getX();
|
||||||
yBoundaryPoints[i] = borderPoint1.getY();
|
yBoundaryPoints[i] = borderPoint1.getY();
|
||||||
}
|
}
|
||||||
@@ -171,72 +171,28 @@ public class CanvasController {
|
|||||||
Point2D borderPoint1 = findScaledXY(thisMark1);
|
Point2D borderPoint1 = findScaledXY(thisMark1);
|
||||||
Point2D borderPoint2 = findScaledXY(thisMark2);
|
Point2D borderPoint2 = findScaledXY(thisMark2);
|
||||||
gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(),
|
gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(),
|
||||||
borderPoint2.getX(), borderPoint2.getY());
|
borderPoint2.getX(), borderPoint2.getY());
|
||||||
xBoundaryPoints[courseLimits.size()-1] = borderPoint1.getX();
|
xBoundaryPoints[courseLimits.size()-1] = borderPoint1.getX();
|
||||||
yBoundaryPoints[courseLimits.size()-1] = borderPoint1.getY();
|
yBoundaryPoints[courseLimits.size()-1] = borderPoint1.getY();
|
||||||
gc.setFill(Color.LIGHTBLUE);
|
gc.setFill(Color.LIGHTBLUE);
|
||||||
gc.fillPolygon(xBoundaryPoints,yBoundaryPoints,yBoundaryPoints.length);
|
gc.fillPolygon(xBoundaryPoints,yBoundaryPoints,yBoundaryPoints.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateGroups(){
|
||||||
/**
|
for (BoatGroup boatGroup : boatGroups) {
|
||||||
* Adds the course marks to the canvas, taken from the XMl file
|
// some raceObjects will have multiple ID's (for instance gate marks)
|
||||||
*
|
//checking if the current "ID" has any updates associated with it
|
||||||
* NOTE: This is quite confusing as objects are grabbed from the XMLParser such as Mark and CompoundMark which are
|
if (StreamParser.boatPositions.containsKey(boatGroup.getRaceId())) {
|
||||||
* named the same as those in the model package but are, however not the same, so they do not have things such as
|
if (boatGroup.isStopped()) {
|
||||||
* a type and must be derived from the number of marks in a compound mark etc..
|
updateBoatGroup(boatGroup);
|
||||||
*/
|
}
|
||||||
private void addCourseMarks() {
|
|
||||||
XMLParser.RaceXMLObject raceXMLObject = StreamParser.getXmlObject().getRaceXML();
|
|
||||||
ArrayList<CompoundMark> compoundMarks = raceXMLObject.getCompoundMarks();
|
|
||||||
RaceObject markGroup;
|
|
||||||
|
|
||||||
for (CompoundMark compoundMark : compoundMarks) {
|
|
||||||
|
|
||||||
//If the compound mark has 2 marks then its a gate mark
|
|
||||||
if (compoundMark.getMarks().size() == 2) {
|
|
||||||
CompoundMark.Mark mark1 = compoundMark.getMarks().get(0);
|
|
||||||
CompoundMark.Mark mark2 = compoundMark.getMarks().get(1);
|
|
||||||
SingleMark singleMark1 = new SingleMark(mark1.getMarkName(), mark1.getTargetLat(), mark1.getTargetLng(), mark1.getSourceID());
|
|
||||||
SingleMark singleMark2 = new SingleMark(mark1.getMarkName(), mark2.getTargetLat(), mark2.getTargetLng(), mark2.getSourceID());
|
|
||||||
GateMark thisGateMark = new GateMark(compoundMark.getcMarkName(),
|
|
||||||
(compoundMark.getMarkID().equals(1)) ? MarkType.OPEN_GATE : MarkType.CLOSED_GATE,
|
|
||||||
singleMark1,
|
|
||||||
singleMark2,
|
|
||||||
singleMark1.getLatitude(),
|
|
||||||
singleMark1.getLongitude());
|
|
||||||
|
|
||||||
markGroup = new MarkGroup(thisGateMark,
|
|
||||||
findScaledXY(thisGateMark.getSingleMark1()),
|
|
||||||
findScaledXY(thisGateMark.getSingleMark2()));
|
|
||||||
|
|
||||||
raceObjects.add(markGroup);
|
|
||||||
raceMarks.add(thisGateMark);
|
|
||||||
|
|
||||||
//Otherwise its a single mark
|
|
||||||
} else {
|
|
||||||
CompoundMark.Mark singleMark = compoundMark.getMarks().get(0);
|
|
||||||
Mark thisSingleMark = new SingleMark(singleMark.getMarkName(),
|
|
||||||
singleMark.getTargetLat(),
|
|
||||||
singleMark.getTargetLng(),
|
|
||||||
singleMark.getSourceID());
|
|
||||||
|
|
||||||
markGroup = new MarkGroup(thisSingleMark, findScaledXY(thisSingleMark));
|
|
||||||
raceObjects.add(markGroup);
|
|
||||||
raceMarks.add(thisSingleMark);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
boatGroup.move();
|
||||||
}
|
}
|
||||||
}
|
for (MarkGroup markGroup : markGroups) {
|
||||||
|
for (Long id : markGroup.getRaceIds()) {
|
||||||
private void updateRaceObjects(){
|
if (StreamParser.markPositions.containsKey(id)) {
|
||||||
for (RaceObject raceObject : raceObjects) {
|
updateMarkGroup(id, markGroup);
|
||||||
raceObject.updatePosition(1000 / 60);
|
|
||||||
// some raceObjects will have multiply ID's (for instance gate marks)
|
|
||||||
for (long id : raceObject.getRaceIds()) {
|
|
||||||
//checking if the current "ID" has any updates associated with it
|
|
||||||
if (StreamParser.boatPositions.containsKey(id)) {
|
|
||||||
move(id, raceObject);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,33 +209,78 @@ public class CanvasController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void move(long id, RaceObject raceObject){
|
private void updateBoatGroup(BoatGroup boatGroup) {
|
||||||
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.boatPositions.get(id);
|
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.boatPositions.get(boatGroup.getRaceId());
|
||||||
|
// giving the movementQueue a 5 packet buffer to account for slightly out of order packets
|
||||||
if (movementQueue.size() > 0){
|
if (movementQueue.size() > 0){
|
||||||
BoatPositionPacket positionPacket = movementQueue.peek();
|
try {
|
||||||
|
BoatPositionPacket positionPacket = movementQueue.take();
|
||||||
//this code adds a delay to reading from the movementQueue
|
Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon());
|
||||||
//in case things being put into the movement queue are slightly
|
double heading = 360.0 / 0xffff * positionPacket.getHeading();
|
||||||
//out of order
|
boatGroup.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), positionPacket.getTimeValid(), frameRate, boatGroup.getRaceId());
|
||||||
int delayTime = 1000;
|
} catch (InterruptedException e){
|
||||||
int loopTime = delayTime * 10;
|
e.printStackTrace();
|
||||||
long timeDiff = (System.currentTimeMillis()%loopTime - positionPacket.getTimeValid()%loopTime);
|
|
||||||
if (timeDiff < 0){
|
|
||||||
timeDiff = loopTime + timeDiff;
|
|
||||||
}
|
}
|
||||||
if (timeDiff > delayTime) {
|
// }
|
||||||
try {
|
}
|
||||||
positionPacket = movementQueue.take();
|
}
|
||||||
Point2D p2d = latLonToXY(positionPacket.getLat(), positionPacket.getLon());
|
|
||||||
double heading = 360.0 / 0xffff * positionPacket.getHeading();
|
void updateMarkGroup (long raceId, MarkGroup markGroup) {
|
||||||
raceObject.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), (int) id);
|
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.markPositions.get(raceId);
|
||||||
} catch (InterruptedException e){
|
if (movementQueue.size() > 0){
|
||||||
e.printStackTrace();
|
try {
|
||||||
}
|
BoatPositionPacket positionPacket = movementQueue.take();
|
||||||
|
Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon());
|
||||||
|
markGroup.moveMarkTo(p2d.getX(), p2d.getY(), raceId);
|
||||||
|
} catch (InterruptedException e){
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws all the boats.
|
||||||
|
*/
|
||||||
|
private void initializeBoats() {
|
||||||
|
Map<Integer, Yacht> boats = StreamParser.getBoats();
|
||||||
|
Group boatAnnotations = new Group();
|
||||||
|
|
||||||
|
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML().getParticipants();
|
||||||
|
ArrayList<Integer> participantIDs = new ArrayList<>();
|
||||||
|
for (Participant p : participants) {
|
||||||
|
participantIDs.add(p.getsourceID());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Yacht boat : boats.values()) {
|
||||||
|
if (participantIDs.contains(boat.getSourceID())) {
|
||||||
|
boat.setColour(Colors.getColor());
|
||||||
|
BoatGroup boatGroup = new BoatGroup(boat, boat.getColour());
|
||||||
|
boatGroups.add(boatGroup);
|
||||||
|
boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group.getChildren().add(boatAnnotations);
|
||||||
|
group.getChildren().addAll(boatGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeMarks() {
|
||||||
|
ArrayList<Mark> allMarks = StreamParser.getXmlObject().getRaceXML().getCompoundMarks();
|
||||||
|
for (Mark mark : allMarks) {
|
||||||
|
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
||||||
|
SingleMark sMark = (SingleMark) mark;
|
||||||
|
|
||||||
|
MarkGroup markGroup = new MarkGroup(sMark, findScaledXY(sMark));
|
||||||
|
markGroups.add(markGroup);
|
||||||
|
} else {
|
||||||
|
GateMark gMark = (GateMark) mark;
|
||||||
|
|
||||||
|
MarkGroup markGroup = new MarkGroup(gMark, findScaledXY(gMark.getSingleMark1()), findScaledXY(gMark.getSingleMark2())); //should be 2 objects in the list.
|
||||||
|
markGroups.add(markGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group.getChildren().addAll(markGroups);
|
||||||
|
}
|
||||||
|
|
||||||
class ResizableCanvas extends Canvas {
|
class ResizableCanvas extends Canvas {
|
||||||
|
|
||||||
ResizableCanvas() {
|
ResizableCanvas() {
|
||||||
@@ -305,11 +306,11 @@ public class CanvasController {
|
|||||||
public double prefWidth(double height) {
|
public double prefWidth(double height) {
|
||||||
return getWidth();
|
return getWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double prefHeight(double width) {
|
public double prefHeight(double width) {
|
||||||
return getHeight();
|
return getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawFps(int fps){
|
private void drawFps(int fps){
|
||||||
@@ -328,30 +329,6 @@ public class CanvasController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws all the boats.
|
|
||||||
*/
|
|
||||||
private void drawBoats() {
|
|
||||||
// Map<Boat, TimelineInfo> timelineInfos = raceViewController.getTimelineInfos();
|
|
||||||
// List<Boat> boats = raceViewController.getStartingBoats();
|
|
||||||
Map<Integer, Yacht> boats = StreamParser.getBoats();
|
|
||||||
Double startingX = raceObjects.get(0).getLayoutX();
|
|
||||||
Double startingY = raceObjects.get(0).getLayoutY();
|
|
||||||
Group boatAnnotations = new Group();
|
|
||||||
|
|
||||||
for (Yacht boat : boats.values()) {
|
|
||||||
// for (Boat boat : boats) {
|
|
||||||
boat.setColour(Colors.getColor());
|
|
||||||
BoatGroup boatGroup = new BoatGroup(boat, boat.getColour());
|
|
||||||
boatGroup.moveTo(startingX, startingY, 0d);
|
|
||||||
//boatGroup.setStage(raceViewController.getStage());
|
|
||||||
raceObjects.add(boatGroup);
|
|
||||||
boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations());
|
|
||||||
}
|
|
||||||
group.getChildren().add(boatAnnotations);
|
|
||||||
group.getChildren().addAll(raceObjects);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
@@ -361,9 +338,8 @@ public class CanvasController {
|
|||||||
findMinMaxPoint();
|
findMinMaxPoint();
|
||||||
double minLonToMaxLon = scaleRaceExtremities();
|
double minLonToMaxLon = scaleRaceExtremities();
|
||||||
calculateReferencePointLocation(minLonToMaxLon);
|
calculateReferencePointLocation(minLonToMaxLon);
|
||||||
givePointsXY();
|
//givePointsXY();
|
||||||
addRaceBorder();
|
addRaceBorder();
|
||||||
findMetersToPixels();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -386,16 +362,11 @@ public class CanvasController {
|
|||||||
//If the course is on a point on the earth where longitudes wrap around.
|
//If the course is on a point on the earth where longitudes wrap around.
|
||||||
Limit minLonMark = sortedPoints.get(0);
|
Limit minLonMark = sortedPoints.get(0);
|
||||||
Limit maxLonMark = sortedPoints.get(sortedPoints.size()-1);
|
Limit maxLonMark = sortedPoints.get(sortedPoints.size()-1);
|
||||||
SingleMark thisMinLon = new SingleMark(minLonMark.toString(), minLonMark.getLat(), minLonMark.getLng(), minLonMark.getSeqID());
|
minLonPoint = new SingleMark(minLonMark.toString(), minLonMark.getLat(), minLonMark.getLng(), minLonMark.getSeqID());
|
||||||
SingleMark thisMaxLon = new SingleMark(maxLonMark.toString(), maxLonMark.getLat(), maxLonMark.getLng(), maxLonMark.getSeqID());
|
maxLonPoint = new SingleMark(maxLonMark.toString(), maxLonMark.getLat(), maxLonMark.getLng(), maxLonMark.getSeqID());
|
||||||
// TODO: 30/03/17 cir27 - Correctly account for longitude wrapping around.
|
if (maxLonPoint.getLongitude() - minLonPoint.getLongitude() > 180) {
|
||||||
if (thisMaxLon.getLongitude() - thisMinLon.getLongitude() > 180) {
|
horizontalInversion = true;
|
||||||
SingleMark temp = thisMinLon;
|
|
||||||
thisMinLon = thisMaxLon;
|
|
||||||
thisMaxLon = temp;
|
|
||||||
}
|
}
|
||||||
minLonPoint = thisMinLon;
|
|
||||||
maxLonPoint = thisMaxLon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -426,8 +397,12 @@ public class CanvasController {
|
|||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
|
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint);
|
||||||
referencePointX += ((CANVAS_WIDTH - (LHS_BUFFER + RHS_BUFFER)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
referencePointX += ((CANVAS_WIDTH - (LHS_BUFFER + RHS_BUFFER)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
||||||
}
|
}
|
||||||
|
if(horizontalInversion) {
|
||||||
|
referencePointX = CANVAS_WIDTH - RHS_BUFFER - (referencePointX - LHS_BUFFER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns it to distanceScaleFactor
|
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns it to distanceScaleFactor
|
||||||
* Returns the max horizontal distance of the map.
|
* Returns the max horizontal distance of the map.
|
||||||
@@ -456,43 +431,18 @@ public class CanvasController {
|
|||||||
return horiDistance;
|
return horiDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Give all markers in the course an x,y location relative to a given reference with a known x,y location. Distances
|
|
||||||
* are scaled according to the distanceScaleFactor variable.
|
|
||||||
*/
|
|
||||||
private void givePointsXY() {
|
|
||||||
List<Mark> allPoints = new ArrayList<>(raceViewController.getRace().getCourse());
|
|
||||||
List<Mark> processed = new ArrayList<>();
|
|
||||||
RaceObject markGroup;
|
|
||||||
|
|
||||||
for (Mark mark : allPoints) {
|
|
||||||
if (!processed.contains(mark)) {
|
|
||||||
if (mark.getMarkType() != MarkType.SINGLE_MARK) {
|
|
||||||
GateMark gateMark = (GateMark) mark;
|
|
||||||
markGroup = new MarkGroup(mark, findScaledXY(gateMark.getSingleMark1()), findScaledXY(gateMark.getSingleMark2()));
|
|
||||||
raceObjects.add(markGroup);
|
|
||||||
} else {
|
|
||||||
markGroup = new MarkGroup(mark, findScaledXY(mark));
|
|
||||||
raceObjects.add(markGroup);
|
|
||||||
}
|
|
||||||
processed.add(mark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point2D findScaledXY (Mark unscaled) {
|
private Point2D findScaledXY (Mark unscaled) {
|
||||||
return findScaledXY (minLatPoint.getLatitude(), minLatPoint.getLongitude(),
|
return findScaledXY (unscaled.getLatitude(), unscaled.getLongitude());
|
||||||
unscaled.getLatitude(), unscaled.getLongitude());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Point2D findScaledXY (double latA, double lonA, double latB, double lonB) {
|
private Point2D findScaledXY (double unscaledLat, double unscaledLon) {
|
||||||
double distanceFromReference;
|
double distanceFromReference;
|
||||||
double angleFromReference;
|
double angleFromReference;
|
||||||
int xAxisLocation = (int) referencePointX;
|
int xAxisLocation = (int) referencePointX;
|
||||||
int yAxisLocation = (int) referencePointY;
|
int yAxisLocation = (int) referencePointY;
|
||||||
|
|
||||||
angleFromReference = Mark.calculateHeadingRad(latA, lonA, latB, lonB);
|
angleFromReference = Mark.calculateHeadingRad(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon);
|
||||||
distanceFromReference = Mark.calculateDistance(latA, lonA, latB, lonB);
|
distanceFromReference = Mark.calculateDistance(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon);
|
||||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
||||||
xAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
xAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
@@ -509,44 +459,13 @@ public class CanvasController {
|
|||||||
xAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
xAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
yAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
yAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
}
|
}
|
||||||
|
if(horizontalInversion) {
|
||||||
|
xAxisLocation = CANVAS_WIDTH - RHS_BUFFER - (xAxisLocation - LHS_BUFFER);
|
||||||
|
}
|
||||||
return new Point2D(xAxisLocation, yAxisLocation);
|
return new Point2D(xAxisLocation, yAxisLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<BoatGroup> getBoatGroups() {
|
||||||
|
return boatGroups;
|
||||||
/**
|
|
||||||
* Find the number of meters per pixel.
|
|
||||||
*/
|
|
||||||
private void findMetersToPixels () {
|
|
||||||
Double angularDistance;
|
|
||||||
Double angle;
|
|
||||||
Double straightLineDistance;
|
|
||||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
|
||||||
angularDistance = Mark.calculateDistance(minLonPoint, maxLonPoint);
|
|
||||||
angle = Mark.calculateHeadingRad(minLonPoint, maxLonPoint);
|
|
||||||
if (angle > Math.PI / 2) {
|
|
||||||
straightLineDistance = Math.cos(angle - Math.PI) * angularDistance;
|
|
||||||
} else {
|
|
||||||
straightLineDistance = Math.cos(angle) * angularDistance;
|
|
||||||
}
|
|
||||||
metersToPixels = (CANVAS_WIDTH - RHS_BUFFER - LHS_BUFFER) / straightLineDistance;
|
|
||||||
} else {
|
|
||||||
angularDistance = Mark.calculateDistance(minLatPoint, maxLatPoint);
|
|
||||||
angle = Mark.calculateHeadingRad(minLatPoint, maxLatPoint);
|
|
||||||
if (angle < Math.PI / 2) {
|
|
||||||
straightLineDistance = Math.cos(angle) * angularDistance;
|
|
||||||
} else {
|
|
||||||
straightLineDistance = Math.cos(-angle + Math.PI * 2) * angularDistance;
|
|
||||||
}
|
|
||||||
metersToPixels = (CANVAS_HEIGHT - TOP_BUFFER - BOT_BUFFER) / straightLineDistance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point2D latLonToXY (double latitude, double longitude) {
|
|
||||||
return findScaledXY(minLatPoint.getLatitude(), minLatPoint.getLongitude(), latitude, longitude);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<RaceObject> getRaceObjects() {
|
|
||||||
return raceObjects;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ import javafx.scene.layout.Pane;
|
|||||||
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 seng302.models.stream.StreamParser;
|
||||||
|
|
||||||
public class Controller implements Initializable {
|
public class Controller implements Initializable {
|
||||||
|
|
||||||
@@ -33,5 +34,6 @@ public class Controller implements Initializable {
|
|||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
setContentPane("/views/StartScreenView.fxml");
|
setContentPane("/views/StartScreenView.fxml");
|
||||||
|
StreamParser.boatPositions.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
package seng302.controllers;
|
|
||||||
|
|
||||||
import seng302.models.Race;
|
|
||||||
import seng302.models.Yacht;
|
|
||||||
import seng302.models.parsers.CourseParser;
|
|
||||||
import seng302.models.parsers.StreamParser;
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by zyt10 on 17/03/17.
|
|
||||||
* run before CanvasController to initialize race events
|
|
||||||
* the CanvasController then uses the event data to make the animations
|
|
||||||
*/
|
|
||||||
public class RaceController {
|
|
||||||
|
|
||||||
Race race = null;
|
|
||||||
|
|
||||||
public void initializeRace() {
|
|
||||||
String raceConfigFile = "/config/config.xml";
|
|
||||||
String teamsConfigFile = "/config/teams.xml";
|
|
||||||
|
|
||||||
try {
|
|
||||||
race = createRace(raceConfigFile, teamsConfigFile); //These config files arent actually used
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println("There was an error creating the race.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (race != null) {
|
|
||||||
race.startRace();
|
|
||||||
} else {
|
|
||||||
System.out.println("There was an error creating the race. Exiting.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Race createRace(String configFile, String teamsConfigFile) throws Exception {
|
|
||||||
Race race = new Race();
|
|
||||||
|
|
||||||
ArrayList<String> boatNames = new ArrayList<>();
|
|
||||||
Map<Long, Yacht> teams = StreamParser.getBoatsPos();
|
|
||||||
|
|
||||||
//get race size
|
|
||||||
int numberOfBoats = teams.size();
|
|
||||||
|
|
||||||
for (Yacht boat : teams.values()) {
|
|
||||||
boatNames.add(boat.getBoatName());
|
|
||||||
race.addBoat(boat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shuffle team names
|
|
||||||
long seed = System.nanoTime();
|
|
||||||
Collections.shuffle(boatNames, new Random(seed));
|
|
||||||
|
|
||||||
if (numberOfBoats > Array.getLength(boatNames.toArray())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
CourseParser course = new CourseParser("/config/course.xml");
|
|
||||||
race.addCourse(course.getCourse());
|
|
||||||
|
|
||||||
return race;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Race getRace() {
|
|
||||||
return race;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
package seng302.controllers;
|
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.scene.text.Text;
|
|
||||||
import seng302.models.Race;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by ptg19 on 20/03/17.
|
|
||||||
*/
|
|
||||||
public class RaceResultController implements Initializable{
|
|
||||||
@FXML private AnchorPane window;
|
|
||||||
@FXML private VBox resultsVBox;
|
|
||||||
private Race race;
|
|
||||||
|
|
||||||
RaceResultController(Race race){
|
|
||||||
this.race = race;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
|
||||||
int boatPosition = this.race.getFinishedBoats().length;
|
|
||||||
|
|
||||||
for (int i = this.race.getFinishedBoats().length - 1; i >= 0; i--){
|
|
||||||
resultsVBox.getChildren().add(0, new Text(boatPosition + ": " + this.race.getFinishedBoats()[i].getBoatName()));
|
|
||||||
boatPosition--;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,7 @@ import seng302.controllers.annotations.ImportantAnnotationController;
|
|||||||
import seng302.controllers.annotations.ImportantAnnotationDelegate;
|
import seng302.controllers.annotations.ImportantAnnotationDelegate;
|
||||||
import seng302.controllers.annotations.ImportantAnnotationsState;
|
import seng302.controllers.annotations.ImportantAnnotationsState;
|
||||||
import seng302.models.*;
|
import seng302.models.*;
|
||||||
import seng302.models.parsers.StreamParser;
|
import seng302.models.stream.StreamParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -58,7 +58,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private ArrayList<Yacht> startingBoats = new ArrayList<>();
|
private ArrayList<Yacht> startingBoats = new ArrayList<>();
|
||||||
private boolean displayFps;
|
private boolean displayFps;
|
||||||
private Timeline timerTimeline;
|
private Timeline timerTimeline;
|
||||||
private Race race;
|
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
|
|
||||||
private ImportantAnnotationsState importantAnnotations;
|
private ImportantAnnotationsState importantAnnotations;
|
||||||
@@ -68,13 +67,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
// Load a default important annotation state
|
// Load a default important annotation state
|
||||||
importantAnnotations = new ImportantAnnotationsState();
|
importantAnnotations = new ImportantAnnotationsState();
|
||||||
|
|
||||||
//Initialise race controller
|
|
||||||
RaceController raceController = new RaceController();
|
|
||||||
raceController.initializeRace();
|
|
||||||
race = raceController.getRace();
|
|
||||||
|
|
||||||
startingBoats = new ArrayList<>(Arrays.asList(race.getBoats()));
|
|
||||||
|
|
||||||
includedCanvasController.setup(this);
|
includedCanvasController.setup(this);
|
||||||
includedCanvasController.initializeCanvas();
|
includedCanvasController.initializeCanvas();
|
||||||
initializeUpdateTimer();
|
initializeUpdateTimer();
|
||||||
@@ -113,7 +105,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
// Load FXML and set CSS
|
// Load FXML and set CSS
|
||||||
fxmlLoader
|
fxmlLoader
|
||||||
.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
|
.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml"));
|
||||||
Scene scene = new Scene(fxmlLoader.load(), 469, 248);
|
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
|
||||||
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
stage.initStyle(StageStyle.UNDECORATED);
|
stage.initStyle(StageStyle.UNDECORATED);
|
||||||
|
|
||||||
@@ -292,7 +284,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
*/
|
*/
|
||||||
private void loadRaceResultView() {
|
private void loadRaceResultView() {
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
|
||||||
loader.setController(new RaceResultController(race));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
contentAnchorPane.getChildren().removeAll();
|
contentAnchorPane.getChildren().removeAll();
|
||||||
@@ -345,11 +336,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
return displayFps;
|
return displayFps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Race getRace() {
|
|
||||||
return race;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the important annotations for a specific BoatGroup
|
* Display the important annotations for a specific BoatGroup
|
||||||
* @param bg The boat group to set the annotations for
|
* @param bg The boat group to set the annotations for
|
||||||
@@ -378,7 +364,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
} else {
|
} else {
|
||||||
bg.setWakeVisible(false);
|
bg.setWakeVisible(false);
|
||||||
}
|
}
|
||||||
|
//TODO fix boat annotations with new boatgroup
|
||||||
if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) {
|
if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) {
|
||||||
bg.setEstTimeToNextMarkObjectVisible(true);
|
bg.setEstTimeToNextMarkObjectVisible(true);
|
||||||
} else {
|
} else {
|
||||||
@@ -396,39 +382,30 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
switch (annotationLevel) {
|
switch (annotationLevel) {
|
||||||
// No Annotations
|
// No Annotations
|
||||||
case 0:
|
case 0:
|
||||||
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
||||||
if (ro instanceof BoatGroup) {
|
bg.setTeamNameObjectVisible(false);
|
||||||
BoatGroup bg = (BoatGroup) ro;
|
bg.setVelocityObjectVisible(false);
|
||||||
bg.setTeamNameObjectVisible(false);
|
bg.setEstTimeToNextMarkObjectVisible(false);
|
||||||
bg.setVelocityObjectVisible(false);
|
bg.setLegTimeObjectVisible(false);
|
||||||
bg.setEstTimeToNextMarkObjectVisible(false);
|
bg.setLineGroupVisible(false);
|
||||||
bg.setLegTimeObjectVisible(false);
|
bg.setWakeVisible(false);
|
||||||
bg.setLineGroupVisible(false);
|
|
||||||
bg.setWakeVisible(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Important Annotations
|
// Important Annotations
|
||||||
case 1:
|
case 1:
|
||||||
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
||||||
if (ro instanceof BoatGroup) {
|
setBoatGroupImportantAnnotations(bg);
|
||||||
BoatGroup bg = (BoatGroup) ro;
|
|
||||||
setBoatGroupImportantAnnotations(bg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// All Annotations
|
// All Annotations
|
||||||
case 2:
|
case 2:
|
||||||
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
||||||
if (ro instanceof BoatGroup) {
|
bg.setTeamNameObjectVisible(true);
|
||||||
BoatGroup bg = (BoatGroup) ro;
|
bg.setVelocityObjectVisible(true);
|
||||||
bg.setTeamNameObjectVisible(true);
|
bg.setEstTimeToNextMarkObjectVisible(true);
|
||||||
bg.setVelocityObjectVisible(true);
|
bg.setLegTimeObjectVisible(true);
|
||||||
bg.setEstTimeToNextMarkObjectVisible(true);
|
bg.setLineGroupVisible(true);
|
||||||
bg.setLegTimeObjectVisible(true);
|
bg.setWakeVisible(true);
|
||||||
bg.setLineGroupVisible(true);
|
|
||||||
bg.setWakeVisible(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -441,17 +418,14 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
* @param yacht The yacht for which we want to view all annotations
|
* @param yacht The yacht for which we want to view all annotations
|
||||||
*/
|
*/
|
||||||
private void setSelectedBoat(Yacht yacht) {
|
private void setSelectedBoat(Yacht yacht) {
|
||||||
for (RaceObject ro : includedCanvasController.getRaceObjects()) {
|
for (BoatGroup bg : includedCanvasController.getBoatGroups()) {
|
||||||
if (ro instanceof BoatGroup) {
|
//We need to iterate over all race groups to get the matching boat group belonging to this boat if we
|
||||||
BoatGroup bg = (BoatGroup) ro;
|
//are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup.
|
||||||
//We need to iterate over all race groups to get the matching boat group belonging to this boat if we
|
if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
|
||||||
//are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup.
|
bg.setIsSelected(true);
|
||||||
if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
|
selectedBoat = yacht;
|
||||||
bg.setIsSelected(true);
|
} else {
|
||||||
selectedBoat = yacht;
|
bg.setIsSelected(false);
|
||||||
} else {
|
|
||||||
bg.setIsSelected(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import javafx.scene.layout.GridPane;
|
|||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
import seng302.models.parsers.StreamParser;
|
import seng302.models.stream.StreamParser;
|
||||||
|
|
||||||
public class StartScreenController implements Initializable {
|
public class StartScreenController implements Initializable {
|
||||||
|
|
||||||
@@ -56,12 +56,13 @@ public class StartScreenController implements Initializable {
|
|||||||
contentPane.getChildren().removeAll();
|
contentPane.getChildren().removeAll();
|
||||||
contentPane.getChildren().clear();
|
contentPane.getChildren().clear();
|
||||||
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
contentPane.getChildren()
|
contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
|
||||||
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
|
}
|
||||||
} catch (javafx.fxml.LoadException e) {
|
catch(javafx.fxml.LoadException e){
|
||||||
System.err.println(e.getCause());
|
e.printStackTrace();
|
||||||
} catch (IOException e) {
|
}
|
||||||
System.err.println(e);
|
catch(IOException e){
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +138,7 @@ public class StartScreenController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void switchToRaceView() {
|
public void switchToRaceView() {
|
||||||
|
StreamParser.boatPositions.clear();
|
||||||
switchedToRaceView = true;
|
switchedToRaceView = true;
|
||||||
setContentPane("/views/RaceView.fxml");
|
setContentPane("/views/RaceView.fxml");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
package seng302.models;
|
package seng302.models;
|
||||||
|
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.scene.CacheHint;
|
import javafx.scene.CacheHint;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.input.MouseDragEvent;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
import javafx.scene.shape.Line;
|
import javafx.scene.shape.Line;
|
||||||
import javafx.scene.shape.Polygon;
|
import javafx.scene.shape.Polygon;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.scene.transform.Rotate;
|
import javafx.scene.transform.Rotate;
|
||||||
import javafx.stage.Stage;
|
import seng302.models.stream.StreamParser;
|
||||||
import seng302.models.parsers.StreamParser;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2
|
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2
|
||||||
@@ -24,7 +25,7 @@ import java.util.List;
|
|||||||
* minimized in which case it attempts to store animations and apply them when the window is
|
* minimized in which case it attempts to store animations and apply them when the window is
|
||||||
* maximised.
|
* maximised.
|
||||||
*/
|
*/
|
||||||
public class BoatGroup extends RaceObject {
|
public class BoatGroup extends Group {
|
||||||
|
|
||||||
//Constants for drawing
|
//Constants for drawing
|
||||||
private static final double TEAMNAME_X_OFFSET = 10d;
|
private static final double TEAMNAME_X_OFFSET = 10d;
|
||||||
@@ -38,9 +39,12 @@ public class BoatGroup extends RaceObject {
|
|||||||
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;
|
||||||
//Variables for boat logic.
|
//Variables for boat logic.
|
||||||
private Point2D lastPoint;
|
private boolean isStopped = true;
|
||||||
private int wakeGenerationDelay = 10;
|
private double xIncrement;
|
||||||
private double distanceTravelled;
|
private double yIncrement;
|
||||||
|
private long lastTimeValid = 0;
|
||||||
|
private Double lastRotation = 0.0;
|
||||||
|
private long framesToMove;
|
||||||
//Graphical objects
|
//Graphical objects
|
||||||
private Yacht boat;
|
private Yacht boat;
|
||||||
private Group lineGroup = new Group();
|
private Group lineGroup = new Group();
|
||||||
@@ -50,51 +54,69 @@ public class BoatGroup extends RaceObject {
|
|||||||
private Text estTimeToNextMarkObject;
|
private Text estTimeToNextMarkObject;
|
||||||
private Text legTimeObject;
|
private Text legTimeObject;
|
||||||
private Wake wake;
|
private Wake wake;
|
||||||
private boolean isSelected = true; //Boats annotations are visible by default at the start
|
private Double distanceTravelled = 0.0;
|
||||||
//Handles boat moving when connecting to a stream
|
private Point2D lastPoint;
|
||||||
private boolean setToInitialLocation = false;
|
|
||||||
private boolean destinationSet;
|
private boolean destinationSet;
|
||||||
//Variables for handling minimization
|
private Color textColor = Color.RED;
|
||||||
private Stage stage;
|
|
||||||
private boolean isMaximized = true;
|
private Boolean isSelected = true; //All boats are initalised as selected
|
||||||
private List<Line> lineStorage = new ArrayList<>();
|
|
||||||
private int setCallCount = 5;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a BoatGroup with the default triangular boat polygon.
|
* Creates a BoatGroup with the default triangular boat polygon.
|
||||||
*
|
*
|
||||||
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
|
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
|
||||||
* to tell which BoatGroup to update.
|
* to tell which BoatGroup to update.
|
||||||
* @param color The colour of the boat polygon and the trailing line.
|
* @param color The colour of the boat polygon and the trailing line.
|
||||||
*/
|
*/
|
||||||
public BoatGroup(Yacht boat, Color color) {
|
public BoatGroup(Yacht boat, Color color) {
|
||||||
this.boat = boat;
|
this.boat = boat;
|
||||||
initChildren(color);
|
initChildren(color);
|
||||||
|
this.textColor = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a BoatGroup with the boat being the default polygon. The head of the boat should be
|
* Creates a BoatGroup with the boat being the default polygon. The head of the boat should be
|
||||||
* at point (0,0).
|
* at point (0,0).
|
||||||
*
|
*
|
||||||
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
|
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used
|
||||||
* to tell which BoatGroup to update.
|
* to tell which BoatGroup to update.
|
||||||
* @param color The colour of the boat polygon and the trailing line.
|
* @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
|
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
|
||||||
* polygon.
|
* polygon.
|
||||||
*/
|
*/
|
||||||
public BoatGroup(Yacht boat, Color color, double... points) {
|
public BoatGroup(Yacht boat, Color color, double... points) {
|
||||||
this.boat = boat;
|
this.boat = boat;
|
||||||
initChildren(color, points);
|
initChildren(color, points);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a text object with caching and a color applied
|
||||||
|
*
|
||||||
|
* @param defaultText The default text to display
|
||||||
|
* @param fill The text fill color
|
||||||
|
* @return The text object
|
||||||
|
*/
|
||||||
|
private Text getTextObject(String defaultText, Color fill) {
|
||||||
|
Text text = new Text(defaultText);
|
||||||
|
|
||||||
|
text.setFill(fill);
|
||||||
|
text.setCacheHint(CacheHint.SPEED);
|
||||||
|
text.setCache(true);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the javafx objects that will be the in the group by default.
|
* 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 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
|
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
|
||||||
* polygon.
|
* polygon.
|
||||||
*/
|
*/
|
||||||
private void initChildren(Color color, double... points) {
|
private void initChildren(Color color, double... points) {
|
||||||
|
textColor = color;
|
||||||
|
destinationSet = false;
|
||||||
|
|
||||||
boatPoly = new Polygon(points);
|
boatPoly = new Polygon(points);
|
||||||
boatPoly.setFill(color);
|
boatPoly.setFill(color);
|
||||||
boatPoly.setOnMouseEntered(event -> boatPoly.setFill(Color.FLORALWHITE));
|
boatPoly.setOnMouseEntered(event -> boatPoly.setFill(Color.FLORALWHITE));
|
||||||
@@ -103,24 +125,8 @@ public class BoatGroup extends RaceObject {
|
|||||||
boatPoly.setCache(true);
|
boatPoly.setCache(true);
|
||||||
boatPoly.setCacheHint(CacheHint.SPEED);
|
boatPoly.setCacheHint(CacheHint.SPEED);
|
||||||
|
|
||||||
|
teamNameObject = getTextObject(boat.getShortName(), textColor);
|
||||||
teamNameObject = new Text(boat.getShortName());
|
velocityObject = getTextObject(boat.getVelocity().toString(), textColor);
|
||||||
teamNameObject.setCache(true);
|
|
||||||
teamNameObject.setCacheHint(CacheHint.SPEED);
|
|
||||||
velocityObject = new Text(String.valueOf(boat.getVelocity()));
|
|
||||||
DateFormat format = new SimpleDateFormat("mm:ss");
|
|
||||||
String timeToNextMark = format
|
|
||||||
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
|
|
||||||
estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark);
|
|
||||||
if (boat.getMarkRoundingTime() != null) {
|
|
||||||
String elapsedTime = format
|
|
||||||
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
|
|
||||||
legTimeObject = new Text("Last mark: " + elapsedTime);
|
|
||||||
} else {
|
|
||||||
legTimeObject = new Text("Last mark: -");
|
|
||||||
}
|
|
||||||
velocityObject.setCache(true);
|
|
||||||
velocityObject.setCacheHint(CacheHint.SPEED);
|
|
||||||
|
|
||||||
teamNameObject.setX(TEAMNAME_X_OFFSET);
|
teamNameObject.setX(TEAMNAME_X_OFFSET);
|
||||||
teamNameObject.setY(TEAMNAME_Y_OFFSET);
|
teamNameObject.setY(TEAMNAME_Y_OFFSET);
|
||||||
@@ -129,21 +135,28 @@ public class BoatGroup extends RaceObject {
|
|||||||
velocityObject.setX(VELOCITY_X_OFFSET);
|
velocityObject.setX(VELOCITY_X_OFFSET);
|
||||||
velocityObject.setY(VELOCITY_Y_OFFSET);
|
velocityObject.setY(VELOCITY_Y_OFFSET);
|
||||||
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
||||||
destinationSet = false;
|
|
||||||
|
|
||||||
estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET);
|
updateLastMarkRoundingTime();
|
||||||
estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET);
|
updateTimeTillNextMark();
|
||||||
estTimeToNextMarkObject
|
|
||||||
|
if (estTimeToNextMarkObject != null) {
|
||||||
|
estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET);
|
||||||
|
estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET);
|
||||||
|
estTimeToNextMarkObject
|
||||||
.relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY());
|
.relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY());
|
||||||
|
}
|
||||||
|
|
||||||
legTimeObject.setX(LEGTIME_X_OFFSET);
|
if (legTimeObject != null) {
|
||||||
legTimeObject.setY(LEGTIME_Y_OFFSET);
|
legTimeObject.setX(LEGTIME_X_OFFSET);
|
||||||
legTimeObject.relocate(legTimeObject.getX(), legTimeObject.getY());
|
legTimeObject.setY(LEGTIME_Y_OFFSET);
|
||||||
|
legTimeObject.relocate(legTimeObject.getX(), legTimeObject.getY());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
wake = new Wake(0, -BOAT_HEIGHT);
|
wake = new Wake(0, -BOAT_HEIGHT);
|
||||||
super.getChildren()
|
super.getChildren()
|
||||||
.addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject,
|
.addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject,
|
||||||
legTimeObject);
|
legTimeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -153,9 +166,9 @@ public class BoatGroup extends RaceObject {
|
|||||||
*/
|
*/
|
||||||
private void initChildren(Color color) {
|
private void initChildren(Color color) {
|
||||||
initChildren(color,
|
initChildren(color,
|
||||||
-BOAT_WIDTH / 2, BOAT_HEIGHT / 2,
|
-BOAT_WIDTH / 2, BOAT_HEIGHT / 2,
|
||||||
0.0, -BOAT_HEIGHT / 2,
|
0.0, -BOAT_HEIGHT / 2,
|
||||||
BOAT_WIDTH / 2, BOAT_HEIGHT / 2);
|
BOAT_WIDTH / 2, BOAT_HEIGHT / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,7 +178,7 @@ public class BoatGroup extends RaceObject {
|
|||||||
* @param dx The amount to move the X coordinate by
|
* @param dx The amount to move the X coordinate by
|
||||||
* @param dy The amount to move the Y coordinate by
|
* @param dy The amount to move the Y coordinate by
|
||||||
*/
|
*/
|
||||||
public void moveGroupBy(double dx, double dy, double rotation) {
|
private void moveGroupBy(double dx, double dy) {
|
||||||
boatPoly.setLayoutX(boatPoly.getLayoutX() + dx);
|
boatPoly.setLayoutX(boatPoly.getLayoutX() + dx);
|
||||||
boatPoly.setLayoutY(boatPoly.getLayoutY() + dy);
|
boatPoly.setLayoutY(boatPoly.getLayoutY() + dy);
|
||||||
teamNameObject.setLayoutX(teamNameObject.getLayoutX() + dx);
|
teamNameObject.setLayoutX(teamNameObject.getLayoutX() + dx);
|
||||||
@@ -178,20 +191,8 @@ public class BoatGroup extends RaceObject {
|
|||||||
legTimeObject.setLayoutY(legTimeObject.getLayoutY() + dy);
|
legTimeObject.setLayoutY(legTimeObject.getLayoutY() + dy);
|
||||||
wake.setLayoutX(wake.getLayoutX() + dx);
|
wake.setLayoutX(wake.getLayoutX() + dx);
|
||||||
wake.setLayoutY(wake.getLayoutY() + dy);
|
wake.setLayoutY(wake.getLayoutY() + dy);
|
||||||
rotateTo(rotation + currentRotation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
* @param rotation The heading in degrees from north the boat should rotate to.
|
|
||||||
*/
|
|
||||||
public void moveTo(double x, double y, double rotation) {
|
|
||||||
rotateTo(rotation);
|
|
||||||
moveTo(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the boat and its children annotations to coordinates specified
|
* Moves the boat and its children annotations to coordinates specified
|
||||||
@@ -199,7 +200,8 @@ public class BoatGroup extends RaceObject {
|
|||||||
* @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
|
||||||
*/
|
*/
|
||||||
public void moveTo(double x, double y) {
|
private void moveTo(double x, double y, double rotation) {
|
||||||
|
rotateTo(rotation);
|
||||||
boatPoly.setLayoutX(x);
|
boatPoly.setLayoutX(x);
|
||||||
boatPoly.setLayoutY(y);
|
boatPoly.setLayoutY(y);
|
||||||
teamNameObject.setLayoutX(x);
|
teamNameObject.setLayoutX(x);
|
||||||
@@ -212,40 +214,109 @@ public class BoatGroup extends RaceObject {
|
|||||||
legTimeObject.setLayoutY(y);
|
legTimeObject.setLayoutY(y);
|
||||||
wake.setLayoutX(x);
|
wake.setLayoutX(x);
|
||||||
wake.setLayoutY(y);
|
wake.setLayoutY(y);
|
||||||
wake.rotate(currentRotation);
|
wake.rotate(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rotateTo(double rotation) {
|
||||||
|
boatPoly.getTransforms().setAll(new Rotate(rotation));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the position of all graphics in the BoatGroup based off of the given time interval.
|
* Updates the time until next mark label, will create a label if one doesn't exist
|
||||||
*
|
|
||||||
* @param timeInterval The interval, in milliseconds, the boat should update it's position based
|
|
||||||
* on.
|
|
||||||
*/
|
*/
|
||||||
public void updatePosition(long timeInterval) {
|
private void updateTimeTillNextMark() {
|
||||||
double dx = pixelVelocityX * timeInterval;
|
if (estTimeToNextMarkObject == null) {
|
||||||
double dy = pixelVelocityY * timeInterval;
|
estTimeToNextMarkObject = getTextObject("Next mark: -", textColor);
|
||||||
double rotation = rotationalVelocity * timeInterval;
|
}
|
||||||
|
if (boat.getEstimateTimeAtNextMark() != null) {
|
||||||
|
DateFormat format = new SimpleDateFormat("mm:ss");
|
||||||
|
String timeToNextMark = format
|
||||||
|
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
|
||||||
|
estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark);
|
||||||
|
} else {
|
||||||
|
estTimeToNextMarkObject.setText("Next mark: -");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the time since last mark rounding, will create a label if one doesn't exist
|
||||||
|
*/
|
||||||
|
private void updateLastMarkRoundingTime() {
|
||||||
|
if (legTimeObject == null) {
|
||||||
|
legTimeObject = getTextObject("Last mark: -", textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boat.getMarkRoundingTime() != null) {
|
||||||
|
DateFormat format = new SimpleDateFormat("mm:ss");
|
||||||
|
String elapsedTime = format
|
||||||
|
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
|
||||||
|
legTimeObject.setText("Last mark: " + elapsedTime);
|
||||||
|
} else {
|
||||||
|
legTimeObject.setText("Last mark: -");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move() {
|
||||||
|
double dx = xIncrement * framesToMove;
|
||||||
|
double dy = yIncrement * framesToMove;
|
||||||
|
|
||||||
distanceTravelled += Math.abs(dx) + Math.abs(dy);
|
distanceTravelled += Math.abs(dx) + Math.abs(dy);
|
||||||
moveGroupBy(dx, dy, rotation);
|
moveGroupBy(xIncrement, yIncrement);
|
||||||
//Draw a new section of the trail every 20 pixels of movement.
|
framesToMove = framesToMove - 1;
|
||||||
if (distanceTravelled > 20) {
|
|
||||||
distanceTravelled = 0;
|
if (framesToMove <= 0) {
|
||||||
|
isStopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceTravelled > 70) {
|
||||||
|
distanceTravelled = 0d;
|
||||||
|
|
||||||
if (lastPoint != null) {
|
if (lastPoint != null) {
|
||||||
Line l = new Line(
|
Line l = new Line(
|
||||||
lastPoint.getX(),
|
lastPoint.getX(),
|
||||||
lastPoint.getY(),
|
lastPoint.getY(),
|
||||||
boatPoly.getLayoutX(),
|
boatPoly.getLayoutX(),
|
||||||
boatPoly.getLayoutY()
|
boatPoly.getLayoutY()
|
||||||
);
|
);
|
||||||
l.getStrokeDashArray().setAll(3d, 7d);
|
l.getStrokeDashArray().setAll(3d, 7d);
|
||||||
l.setStroke(boat.getColour());
|
l.setStroke(boat.getColour());
|
||||||
|
l.setCache(true);
|
||||||
|
l.setCacheHint(CacheHint.SPEED);
|
||||||
lineGroup.getChildren().add(l);
|
lineGroup.getChildren().add(l);
|
||||||
}
|
}
|
||||||
if (destinationSet) { //Only begin drawing after the first destination is set
|
|
||||||
|
if (destinationSet) {
|
||||||
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wake.updatePosition(timeInterval);
|
|
||||||
|
wake.updatePosition(1000 / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the rotational velocity required to reach the rotationalGoal from the
|
||||||
|
* currentRotation.
|
||||||
|
*/
|
||||||
|
protected Double calculateRotationalVelocity(Double rotationalGoal) {
|
||||||
|
Double rotationalVelocity = 0.0;
|
||||||
|
|
||||||
|
if (Math.abs(rotationalGoal - lastRotation) > 180) {
|
||||||
|
if (rotationalGoal - lastRotation >= 0.0) {
|
||||||
|
rotationalVelocity = ((rotationalGoal - lastRotation) - 360) / 200;
|
||||||
|
} else {
|
||||||
|
rotationalVelocity = (360 + (rotationalGoal - lastRotation)) / 200;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rotationalVelocity = (rotationalGoal - lastRotation) / 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sometimes the rotation is too large to be realistic. In that case just do it instantly.
|
||||||
|
if (Math.abs(rotationalVelocity) > 1) {
|
||||||
|
rotationalVelocity = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rotationalVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -253,82 +324,55 @@ public class BoatGroup extends RaceObject {
|
|||||||
*
|
*
|
||||||
* @param newXValue The X co-ordinate the boat needs to move to.
|
* @param newXValue The X co-ordinate the boat needs to move to.
|
||||||
* @param newYValue The Y co-ordinate the boat needs to move to.
|
* @param newYValue The Y co-ordinate the boat needs to move to.
|
||||||
* @param rotation Rotation to move graphics to.
|
* @param rotation Rotation to move graphics to.
|
||||||
* @param raceIds RaceID of the object to move.
|
* @param timeValid the time the position values are valid for
|
||||||
*/
|
*/
|
||||||
public void setDestination(double newXValue, double newYValue, double rotation,
|
public void setDestination(double newXValue, double newYValue, double rotation,
|
||||||
double groundSpeed, int... raceIds) {
|
double groundSpeed, long timeValid, double frameRate, long id) {
|
||||||
if (hasRaceId(raceIds)) {
|
if (lastTimeValid == 0) {
|
||||||
if (setToInitialLocation) {
|
lastTimeValid = timeValid - 200;
|
||||||
destinationSet = true;
|
moveTo(newXValue, newYValue, rotation);
|
||||||
boat.setVelocity(groundSpeed);
|
|
||||||
double dx = newXValue - boatPoly.getLayoutX();
|
|
||||||
double dy = newYValue - boatPoly.getLayoutY();
|
|
||||||
|
|
||||||
|
|
||||||
pixelVelocityX = dx / expectedUpdateInterval;
|
|
||||||
pixelVelocityY = dy / expectedUpdateInterval;
|
|
||||||
rotationalGoal = rotation;
|
|
||||||
calculateRotationalVelocity();
|
|
||||||
|
|
||||||
if (Math.abs(rotationalVelocity) > 0.075) {
|
|
||||||
rotationalVelocity = 0;
|
|
||||||
rotateTo(rotationalGoal);
|
|
||||||
wake.rotate(rotationalGoal);
|
|
||||||
}
|
|
||||||
wake.setRotationalVelocity(rotationalVelocity, boat.getVelocity());
|
|
||||||
velocityObject.setText(String.format("%.2f m/s", boat.getVelocity()));
|
|
||||||
DateFormat format = new SimpleDateFormat("mm:ss");
|
|
||||||
// estimate time to next mark
|
|
||||||
String timeToNextMark = format
|
|
||||||
.format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong());
|
|
||||||
estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark);
|
|
||||||
// elapsed time
|
|
||||||
if (boat.getMarkRoundingTime() != null) {
|
|
||||||
String elapsedTime = format
|
|
||||||
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime());
|
|
||||||
legTimeObject.setText("Last mark: " + elapsedTime);
|
|
||||||
} else {
|
|
||||||
legTimeObject.setText("Last mark: -");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setToInitialLocation = true;
|
|
||||||
rotationalGoal = rotation;
|
|
||||||
moveTo(newXValue, newYValue, rotation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//If minimized generate lines every 5 calls to set destination.
|
framesToMove = Math.round((frameRate / (1000.0f / (timeValid - lastTimeValid))));
|
||||||
}
|
double dx = newXValue - boatPoly.getLayoutX();
|
||||||
|
double dy = newYValue - boatPoly.getLayoutY();
|
||||||
|
|
||||||
|
xIncrement = dx / framesToMove;
|
||||||
|
yIncrement = dy / framesToMove;
|
||||||
|
|
||||||
public void setDestination(double newXValue, double newYValue, double groundSpeed,
|
|
||||||
int... raceIDs) {
|
|
||||||
destinationSet = true;
|
destinationSet = true;
|
||||||
|
|
||||||
if (hasRaceId(raceIDs)) {
|
Double rotationalVelocity = calculateRotationalVelocity(rotation);
|
||||||
double rotation = Math.abs(
|
|
||||||
Math.toDegrees(
|
updateTimeTillNextMark();
|
||||||
Math.atan(
|
updateLastMarkRoundingTime();
|
||||||
(newYValue - boatPoly.getLayoutY()) / (newXValue - boatPoly.getLayoutX())
|
|
||||||
)
|
if (Math.abs(rotationalVelocity) > 0.075) {
|
||||||
)
|
rotationalVelocity = 0.0;
|
||||||
);
|
wake.rotate(rotation);
|
||||||
setDestination(newXValue, newYValue, rotation, groundSpeed, raceIDs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rotateTo(rotation);
|
||||||
|
wake.setRotationalVelocity(rotationalVelocity, groundSpeed);
|
||||||
|
|
||||||
|
velocityObject.setText(String.format("%.2f m/s", groundSpeed));
|
||||||
|
lastTimeValid = timeValid;
|
||||||
|
isStopped = false;
|
||||||
|
|
||||||
|
lastRotation = rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rotateTo(double rotation) {
|
|
||||||
currentRotation = rotation;
|
public void setIsSelected(Boolean isSelected) {
|
||||||
boatPoly.getTransforms().setAll(new Rotate(rotation));
|
this.isSelected = isSelected;
|
||||||
|
setTeamNameObjectVisible(isSelected);
|
||||||
|
setVelocityObjectVisible(isSelected);
|
||||||
|
setLineGroupVisible(isSelected);
|
||||||
|
setWakeVisible(isSelected);
|
||||||
|
setEstTimeToNextMarkObjectVisible(isSelected);
|
||||||
|
setLegTimeObjectVisible(isSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forceRotation() {
|
|
||||||
rotateTo(rotationalGoal);
|
|
||||||
wake.rotate(rotationalGoal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void paintBoat(Color color) {
|
|
||||||
boatPoly.setFill(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTeamNameObjectVisible(Boolean visible) {
|
public void setTeamNameObjectVisible(Boolean visible) {
|
||||||
teamNameObject.setVisible(visible);
|
teamNameObject.setVisible(visible);
|
||||||
@@ -358,46 +402,13 @@ public class BoatGroup extends RaceObject {
|
|||||||
return boat;
|
return boat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This function sets the boats isSelected property AS WELL as actually acting upon the value of
|
|
||||||
* that selection. (Painting or not painting annotations)
|
|
||||||
*
|
|
||||||
* @param isSelected A Boolean indicating whether or not the boat is selected
|
|
||||||
*/
|
|
||||||
public void setIsSelected(Boolean isSelected) {
|
|
||||||
this.isSelected = isSelected;
|
|
||||||
setTeamNameObjectVisible(isSelected);
|
|
||||||
setVelocityObjectVisible(isSelected);
|
|
||||||
setLineGroupVisible(isSelected);
|
|
||||||
setWakeVisible(isSelected);
|
|
||||||
setEstTimeToNextMarkObjectVisible(isSelected);
|
|
||||||
setLegTimeObjectVisible(isSelected);
|
|
||||||
// TODO: 17/05/17 wmu16 - this should iterate over some list of annotations which we should make to easily make extensible
|
|
||||||
// paintBoat((isSelected) ? Color.WHITE : boat.getColour());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
for (int id : raceIds) {
|
|
||||||
if (id == boat.getSourceID()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all raceIds associated with this group. For BoatGroups the ID's are for the boat.
|
* Returns all raceIds associated with this group. For BoatGroups the ID's are for the boat.
|
||||||
*
|
*
|
||||||
* @return An array containing all ID's associated with this RaceObject.
|
* @return An array containing all ID's associated with this RaceObject.
|
||||||
*/
|
*/
|
||||||
public int[] getRaceIds() {
|
public long getRaceId() {
|
||||||
return new int[]{boat.getSourceID()};
|
return boat.getSourceID();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -413,30 +424,12 @@ public class BoatGroup extends RaceObject {
|
|||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public boolean isStopped() {
|
||||||
* Use this function to let the BoatGroup know about the stage it is in. If it knows about it's
|
return isStopped;
|
||||||
* stage then it will listen to the iconified property of that stage and change it's behaviour
|
|
||||||
* upon minimization. Without setting the Stage there is guarantee that the BoatGroup will draw
|
|
||||||
* properly when the stage is minimized.
|
|
||||||
*
|
|
||||||
* @param stage The stage that the BoatGroup is added to.
|
|
||||||
*/
|
|
||||||
public void setStage(Stage stage) {
|
|
||||||
/* TODO: 4/05/17 cir27 - Find a way to get the stage to this point. Need to pass it through multiple controllers.
|
|
||||||
App.start() -> Controller.setContentPane -> RaceViewController -> CanvasController
|
|
||||||
*/
|
|
||||||
this.stage = stage;
|
|
||||||
this.stage.iconifiedProperty().addListener(e -> {
|
|
||||||
isMaximized = !stage.isIconified();
|
|
||||||
if (!lineStorage.isEmpty()) {
|
|
||||||
lineGroup.getChildren().addAll(lineStorage);
|
|
||||||
lineStorage.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return boat.toString();
|
return boat.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ import javafx.scene.paint.Color;
|
|||||||
* Created by ryan_ on 16/03/2017.
|
* Created by ryan_ on 16/03/2017.
|
||||||
*/
|
*/
|
||||||
public enum Colors {
|
public enum Colors {
|
||||||
RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE;
|
RED, PERU, SEAGREEN, GREEN, BLUE, PURPLE;
|
||||||
|
|
||||||
static Integer index = 0;
|
static Integer index = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -1,198 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
private ArrayList<Yacht> boats; // The boats in the race
|
|
||||||
private ArrayList<Yacht> finishingOrder; // The order in which the boats finish the race
|
|
||||||
private HashMap<Yacht, List> events = new HashMap<>(); // The events that occur in the race
|
|
||||||
private List<Mark> course; // Marks in the race
|
|
||||||
private long startTime = 0;
|
|
||||||
private double timeScale = 1;
|
|
||||||
private boolean raceFinished = false; // Race is finished
|
|
||||||
private int raceTime = -2; // Current time in the race
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Race class containing the boats and legs in the race
|
|
||||||
*/
|
|
||||||
public Race() {
|
|
||||||
this.boats = new ArrayList<>();
|
|
||||||
this.finishingOrder = new ArrayList<>();
|
|
||||||
this.course = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a boat to the race
|
|
||||||
*
|
|
||||||
* @param boat, the boat to add
|
|
||||||
*/
|
|
||||||
public void addBoat(Yacht boat) {
|
|
||||||
boats.add(boat);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of boats in a random order
|
|
||||||
*
|
|
||||||
* @return a list of boats
|
|
||||||
*/
|
|
||||||
public Yacht[] getShuffledBoats() {
|
|
||||||
// Shuffle the list of boats
|
|
||||||
long seed = System.nanoTime();
|
|
||||||
Collections.shuffle(this.boats, new Random(seed));
|
|
||||||
|
|
||||||
return boats.toArray(new Yacht[boats.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of boats in the order that they
|
|
||||||
* finished the race (position 0 is first place)
|
|
||||||
*
|
|
||||||
* @return a list of boats
|
|
||||||
*/
|
|
||||||
public Yacht[] getFinishedBoats() {
|
|
||||||
return this.finishingOrder.toArray(new Yacht[this.finishingOrder.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of boats in the race
|
|
||||||
*
|
|
||||||
* @return a list of the boats competing in the race
|
|
||||||
*/
|
|
||||||
public Yacht[] getBoats() {
|
|
||||||
return boats.toArray(new Yacht[boats.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets time scale
|
|
||||||
*
|
|
||||||
* @param timeScale
|
|
||||||
*/
|
|
||||||
public void setTimeScale(double timeScale) {
|
|
||||||
this.timeScale = timeScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate all events that will happen during the race.
|
|
||||||
*/
|
|
||||||
private void generateEvents() {
|
|
||||||
|
|
||||||
for (Yacht boat : this.boats) {
|
|
||||||
double totalDistance = 0;
|
|
||||||
int numberOfMarks = this.course.size();
|
|
||||||
|
|
||||||
for (int i = 0; i < numberOfMarks; i++) {
|
|
||||||
Double time = (totalDistance / boat.getVelocity() / timeScale);
|
|
||||||
|
|
||||||
// If there are singleMarks after this event
|
|
||||||
if (i < numberOfMarks - 1) {
|
|
||||||
Event event = new Event(time, boat, course.get(i), course.get(i + 1), i);
|
|
||||||
|
|
||||||
try {
|
|
||||||
events.get(boat).add(event);
|
|
||||||
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
events.put(boat, new ArrayList<>(Arrays.asList(event)));
|
|
||||||
}
|
|
||||||
totalDistance += event.getDistanceBetweenMarks();
|
|
||||||
//System.out.println(totalDistance);
|
|
||||||
//System.out.println(boat.getVelocity());
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are no more marks after this event
|
|
||||||
|
|
||||||
else{
|
|
||||||
Event event = new Event(time, boat, course.get(i), i);
|
|
||||||
events.get(boat).add(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a race and generates all events for the race.
|
|
||||||
*/
|
|
||||||
public void startRace() {
|
|
||||||
// record start time.
|
|
||||||
this.startTime = System.currentTimeMillis();
|
|
||||||
generateEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the race course
|
|
||||||
* @param course a list of marks in the course
|
|
||||||
*/
|
|
||||||
public void addCourse(List<Mark> course) {
|
|
||||||
this.course = course;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of marks in the course
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<Mark> getCourse() {
|
|
||||||
return course;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a map of the events in the race
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public HashMap<Yacht, List> getEvents() {
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a boat as finished
|
|
||||||
* @param boat The boat that has finished the race/home/cosc/student/wmu16
|
|
||||||
*/
|
|
||||||
public void setBoatFinished(Yacht 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package seng302.models;
|
|
||||||
|
|
||||||
import javafx.geometry.Point2D;
|
|
||||||
import javafx.scene.Group;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RaceObject defines the behaviour that animated objects whose position is updated from a yacht race data stream must
|
|
||||||
* adhere to.
|
|
||||||
*/
|
|
||||||
public abstract class RaceObject extends Group {
|
|
||||||
|
|
||||||
//Time between sections of race
|
|
||||||
protected static double expectedUpdateInterval = 200;
|
|
||||||
|
|
||||||
protected double rotationalGoal;
|
|
||||||
protected double currentRotation;
|
|
||||||
protected double rotationalVelocity;
|
|
||||||
protected double pixelVelocityX;
|
|
||||||
protected double pixelVelocityY;
|
|
||||||
|
|
||||||
public Point2D getPosition () {
|
|
||||||
return new Point2D(super.getLayoutX(), getLayoutY());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getExpectedUpdateInterval() {
|
|
||||||
return expectedUpdateInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static void setExpectedUpdateInterval(double expectedUpdateInterval) {
|
|
||||||
RaceObject.expectedUpdateInterval = expectedUpdateInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the rotational velocity required to reach the rotationalGoal from the currentRotation.
|
|
||||||
*/
|
|
||||||
protected void calculateRotationalVelocity () {
|
|
||||||
if (Math.abs(rotationalGoal - currentRotation) > 180) {
|
|
||||||
if (rotationalGoal - currentRotation >= 0) {
|
|
||||||
this.rotationalVelocity = ((rotationalGoal - currentRotation) - 360) / expectedUpdateInterval;
|
|
||||||
} else {
|
|
||||||
this.rotationalVelocity = (360 + (rotationalGoal - currentRotation)) / expectedUpdateInterval;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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
|
|
||||||
* set to the co-ordinates (x, y) with the given rotation.
|
|
||||||
* @param x X co-ordinate to move the graphics to.
|
|
||||||
* @param y Y co-ordinate to move the graphics to.
|
|
||||||
* @param rotation Rotation to move graphics to.
|
|
||||||
* @param raceIds RaceID of the object to move.
|
|
||||||
*/
|
|
||||||
public abstract void setDestination (double x, double y, double rotation, double groundSpeed, 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, double groundSpeed, int... raceIds);
|
|
||||||
|
|
||||||
public abstract void updatePosition (long timeInterval);
|
|
||||||
|
|
||||||
public abstract void moveTo (double x, double y, double rotation);
|
|
||||||
|
|
||||||
public abstract void moveTo (double x, double y);
|
|
||||||
|
|
||||||
public abstract void moveGroupBy(double x, double y, double rotation);
|
|
||||||
|
|
||||||
public abstract void rotateTo (double rotation);
|
|
||||||
|
|
||||||
public abstract boolean hasRaceId (int... raceIds);
|
|
||||||
|
|
||||||
public abstract int[] getRaceIds ();
|
|
||||||
}
|
|
||||||
@@ -63,8 +63,8 @@ class Wake extends Group {
|
|||||||
for (int i = 1; i < numWakes; i++) {
|
for (int i = 1; i < numWakes; i++) {
|
||||||
double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]);
|
double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]);
|
||||||
double shortestDistance = Math.atan2(
|
double shortestDistance = Math.atan2(
|
||||||
Math.sin(wakeSeparationRad),
|
Math.sin(wakeSeparationRad),
|
||||||
Math.cos(wakeSeparationRad)
|
Math.cos(wakeSeparationRad)
|
||||||
);
|
);
|
||||||
double distDeg = Math.toDegrees(shortestDistance);
|
double distDeg = Math.toDegrees(shortestDistance);
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ public class Yacht {
|
|||||||
this.colour = colour;
|
this.colour = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getVelocity() {
|
public Double getVelocity() {
|
||||||
return velocity;
|
return velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,12 +39,10 @@ public class GateMark extends Mark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public double getLatitude(){
|
public double getLatitude(){
|
||||||
//return (this.getSingleMark1().getLatitude() + this.getSingleMark2().getLatitude()) / 2;
|
|
||||||
return (this.getSingleMark1().getLatitude());
|
return (this.getSingleMark1().getLatitude());
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getLongitude(){
|
public double getLongitude(){
|
||||||
//return (this.getSingleMark1().getLongitude() + this.getSingleMark2().getLongitude()) / 2;
|
|
||||||
return (this.getSingleMark1().getLongitude());
|
return (this.getSingleMark1().getLongitude());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public abstract class Mark {
|
|||||||
private MarkType markType;
|
private MarkType markType;
|
||||||
private double latitude;
|
private double latitude;
|
||||||
private double longitude;
|
private double longitude;
|
||||||
private int id;
|
private long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mark instance by passing its name and type
|
* Create a mark instance by passing its name and type
|
||||||
@@ -125,12 +125,11 @@ public abstract class Mark {
|
|||||||
return longitude;
|
return longitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(int id) {
|
public void setId(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
package seng302.models.mark;
|
package seng302.models.mark;
|
||||||
|
|
||||||
import javafx.geometry.Point2D;
|
|
||||||
import javafx.scene.CacheHint;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.shape.Circle;
|
|
||||||
import javafx.scene.shape.Line;
|
|
||||||
import javafx.scene.transform.Rotate;
|
|
||||||
import seng302.models.RaceObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
import javafx.scene.shape.Line;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by CJIRWIN on 26/04/2017.
|
* Created by CJIRWIN on 26/04/2017.
|
||||||
*/
|
*/
|
||||||
public class MarkGroup extends RaceObject {
|
public class MarkGroup extends Group {
|
||||||
|
|
||||||
private static int MARK_RADIUS = 5;
|
private static int MARK_RADIUS = 5;
|
||||||
private static int LINE_THICKNESS = 2;
|
private static int LINE_THICKNESS = 2;
|
||||||
@@ -24,14 +20,13 @@ public class MarkGroup extends RaceObject {
|
|||||||
|
|
||||||
private List<Mark> marks = new ArrayList<>();
|
private List<Mark> marks = new ArrayList<>();
|
||||||
private Mark mainMark;
|
private Mark mainMark;
|
||||||
private double[] nodePixelVelocitiesX;
|
|
||||||
private double[] nodePixelVelocitiesY;
|
|
||||||
private Point2D[] nodeDestinations;
|
|
||||||
|
|
||||||
public MarkGroup (Mark mark, Point2D... points) {
|
/**
|
||||||
nodePixelVelocitiesX = new double[points.length];
|
* Constructor for singleMark groups
|
||||||
nodePixelVelocitiesY = new double[points.length];
|
* @param mark
|
||||||
nodeDestinations = new Point2D[points.length];
|
* @param points
|
||||||
|
*/
|
||||||
|
public MarkGroup (SingleMark mark, Point2D points) {
|
||||||
marks.add(mark);
|
marks.add(mark);
|
||||||
mainMark = mark;
|
mainMark = mark;
|
||||||
Color color = Color.BLACK;
|
Color color = Color.BLACK;
|
||||||
@@ -41,192 +36,94 @@ public class MarkGroup extends RaceObject {
|
|||||||
color = Color.RED;
|
color = Color.RED;
|
||||||
}
|
}
|
||||||
Circle markCircle;
|
Circle markCircle;
|
||||||
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
markCircle = new Circle(
|
||||||
markCircle = new Circle(
|
points.getX(),
|
||||||
points[0].getX(),
|
points.getY(),
|
||||||
points[0].getY(),
|
MARK_RADIUS,
|
||||||
MARK_RADIUS,
|
color
|
||||||
color
|
);
|
||||||
);
|
super.getChildren().add(markCircle);
|
||||||
nodeDestinations = new Point2D[]{
|
}
|
||||||
new Point2D(markCircle.getCenterX(), markCircle.getCenterY()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
super.getChildren().add(markCircle);
|
|
||||||
} else {
|
|
||||||
marks.add(((GateMark) mark).getSingleMark1());
|
|
||||||
marks.add(((GateMark) mark).getSingleMark2());
|
|
||||||
nodePixelVelocitiesX = new double[]{0d,0d};
|
|
||||||
nodePixelVelocitiesY = new double[]{0d,0d};
|
|
||||||
nodeDestinations = new Point2D[2];
|
|
||||||
|
|
||||||
markCircle = new Circle(
|
public MarkGroup(GateMark mark, Point2D points1, Point2D points2) {
|
||||||
points[0].getX(),
|
marks.add(mark.getSingleMark1());
|
||||||
points[0].getY(),
|
marks.add(mark.getSingleMark2());
|
||||||
MARK_RADIUS,
|
mainMark = mark;
|
||||||
color
|
Color color = Color.BLACK;
|
||||||
);
|
if (mark.getName().equals("Start")){
|
||||||
nodeDestinations[0] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY());
|
color = Color.GREEN;
|
||||||
super.getChildren().add(markCircle);
|
} else if (mark.getName().equals("Finish")){
|
||||||
|
color = Color.RED;
|
||||||
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(
|
|
||||||
points[0].getX(),
|
|
||||||
points[0].getY(),
|
|
||||||
points[1].getX(),
|
|
||||||
points[1].getY()
|
|
||||||
);
|
|
||||||
line.setStrokeWidth(LINE_THICKNESS);
|
|
||||||
line.setStroke(color);
|
|
||||||
if (mark.getMarkType() == MarkType.OPEN_GATE) {
|
|
||||||
line.getStrokeDashArray().addAll(DASHED_GAP_LEN, DASHED_LINE_LEN);
|
|
||||||
}
|
|
||||||
super.getChildren().add(line);
|
|
||||||
}
|
}
|
||||||
}
|
Circle markCircle;
|
||||||
|
markCircle = new Circle(
|
||||||
|
points1.getX(),
|
||||||
|
points1.getY(),
|
||||||
|
MARK_RADIUS,
|
||||||
|
color
|
||||||
|
);
|
||||||
|
super.getChildren().add(markCircle);
|
||||||
|
|
||||||
public void setDestination (double x, double y, double rotation, double groundSpeed, int... raceIds) {
|
markCircle = new Circle(
|
||||||
setDestination(x, y, 0, raceIds);
|
points2.getX(),
|
||||||
this.rotationalGoal = rotation;
|
points2.getY(),
|
||||||
calculateRotationalVelocity();
|
MARK_RADIUS,
|
||||||
}
|
color
|
||||||
|
);
|
||||||
public void setDestination (double x, double y, double groundSpeed, int... raceIds) {
|
super.getChildren().add(markCircle);
|
||||||
for (int i = 0; i < marks.size(); i++)
|
Line line = new Line(
|
||||||
for (int id : raceIds)
|
points1.getX(),
|
||||||
if (id == marks.get(i).getId())
|
points1.getY(),
|
||||||
setDestinationChild(x, y, 0, Math.max(0, i-1));
|
points2.getX(),
|
||||||
}
|
points2.getY()
|
||||||
|
);
|
||||||
|
line.setStrokeWidth(LINE_THICKNESS);
|
||||||
private void setDestinationChild (double x, double y, double speed, int childIndex) {
|
line.setStroke(color);
|
||||||
//double relativeX = x - super.getLayoutX();
|
if (mark.getMarkType() == MarkType.OPEN_GATE) {
|
||||||
//double relativeY = y - super.getLayoutY();
|
line.getStrokeDashArray().addAll(DASHED_GAP_LEN, DASHED_LINE_LEN);
|
||||||
Circle markCircle = (Circle) super.getChildren().get(childIndex);
|
|
||||||
this.nodeDestinations[childIndex] = new Point2D(x, y);
|
|
||||||
//if (Math.abs(relativeX - markCircle.getCenterX()) > 30 && Math.abs(relativeY - markCircle.getCenterY()) > 30) {
|
|
||||||
this.nodePixelVelocitiesX[childIndex] = (x - markCircle.getCenterX()) / expectedUpdateInterval;
|
|
||||||
this.nodePixelVelocitiesY[childIndex] = (y - markCircle.getCenterY()) / expectedUpdateInterval;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void rotateTo (double rotation) {
|
|
||||||
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
|
|
||||||
Line line = (Line) super.getChildren().get(2);
|
|
||||||
double xCenter = Math.abs(line.getEndX() - line.getStartX());
|
|
||||||
double yCenter = Math.abs(line.getEndY() - line.getStartY());
|
|
||||||
super.getTransforms().setAll(new Rotate(rotation, xCenter, yCenter));
|
|
||||||
}
|
}
|
||||||
|
super.getChildren().add(line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePosition (long timeInterval) {
|
public void moveMarkTo (double x, double y, long raceId)
|
||||||
Circle markCircle = (Circle) super.getChildren().get(0);
|
{
|
||||||
|
if (mainMark.getMarkType() == MarkType.SINGLE_MARK) {
|
||||||
|
Circle markCircle = (Circle) super.getChildren().get(0);
|
||||||
|
|
||||||
if (nodePixelVelocitiesX[0] > 0 && markCircle.getCenterX() > nodeDestinations[0].getX() ||
|
|
||||||
nodePixelVelocitiesX[0] < 0 && markCircle.getCenterX() < nodeDestinations[0].getY())
|
|
||||||
nodePixelVelocitiesX[0] = 0;
|
|
||||||
else if (nodePixelVelocitiesX[0] != 0)
|
|
||||||
markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[0] * timeInterval);
|
|
||||||
|
|
||||||
if (nodePixelVelocitiesY[0] > 0 && markCircle.getCenterY() > nodeDestinations[0].getY() ||
|
|
||||||
nodePixelVelocitiesY[0] < 0 && markCircle.getCenterY() < nodeDestinations[0].getY())
|
|
||||||
nodePixelVelocitiesY[0] = 0;
|
|
||||||
else if (nodePixelVelocitiesY[0] != 0)
|
|
||||||
markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[0] * timeInterval);
|
|
||||||
|
|
||||||
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
|
|
||||||
|
|
||||||
Line line = (Line) super.getChildren().get(2);
|
|
||||||
line.setStartX(markCircle.getCenterX());
|
|
||||||
line.setStartY(markCircle.getCenterY());
|
|
||||||
|
|
||||||
markCircle = (Circle) super.getChildren().get(1);
|
|
||||||
|
|
||||||
if (nodePixelVelocitiesX[1] > 0 && markCircle.getCenterX() >= nodeDestinations[1].getX() ||
|
|
||||||
nodePixelVelocitiesX[1] < 0 && markCircle.getCenterX() <= nodeDestinations[1].getX())
|
|
||||||
nodePixelVelocitiesX[1] = 0;
|
|
||||||
else if (nodePixelVelocitiesX[1] != 0)
|
|
||||||
markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[1] * timeInterval);
|
|
||||||
|
|
||||||
if (nodePixelVelocitiesY[1] > 0 && markCircle.getCenterY() > nodeDestinations[1].getY() ||
|
|
||||||
nodePixelVelocitiesY[1] < 0 && markCircle.getCenterY() < nodeDestinations[1].getY())
|
|
||||||
nodePixelVelocitiesY[1] = 0;
|
|
||||||
else if (nodePixelVelocitiesY[1] != 0)
|
|
||||||
markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[1] * timeInterval);
|
|
||||||
line.setEndX(markCircle.getCenterX());
|
|
||||||
line.setEndY(markCircle.getCenterY());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void moveGroupBy (double x, double y, double rotation) {
|
|
||||||
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
|
|
||||||
Line line = (Line) super.getChildren().get(2);
|
|
||||||
for (int childIndex = 0; childIndex < 2; childIndex++){
|
|
||||||
Circle mark = (Circle) super.getChildren().get(childIndex);
|
|
||||||
mark.setCenterY(mark.getCenterY() + y);
|
|
||||||
mark.setCenterX(mark.getCenterX() + x);
|
|
||||||
}
|
|
||||||
line.setStartX(line.getStartX() + x);
|
|
||||||
line.setStartY(line.getStartY() + y);
|
|
||||||
line.setEndX(line.getEndX() + x);
|
|
||||||
line.setEndY(line.getEndY() + y);
|
|
||||||
} else {
|
|
||||||
Circle mark = (Circle) super.getChildren().get(0);
|
|
||||||
mark.setCenterY(mark.getCenterY() + y);
|
|
||||||
mark.setCenterX(mark.getCenterX() + x);
|
|
||||||
}
|
|
||||||
rotateTo(currentRotation + rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void moveTo (double x, double y, double rotation) {
|
|
||||||
moveTo(x, y);
|
|
||||||
rotateTo(rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void moveTo (double x, double y) {
|
|
||||||
Circle markCircle = (Circle) super.getChildren().get(0);
|
|
||||||
markCircle.setCenterX(x);
|
|
||||||
markCircle.setCenterY(y);
|
|
||||||
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
|
|
||||||
markCircle = (Circle) super.getChildren().get(1);
|
|
||||||
markCircle.setCenterX(x);
|
markCircle.setCenterX(x);
|
||||||
markCircle.setCenterY(y);
|
markCircle.setCenterY(y);
|
||||||
Line line = (Line) super.getChildren().get(2);
|
} else {
|
||||||
line.setStartX(x);
|
Circle markCircle1 = (Circle) super.getChildren().get(0);
|
||||||
line.setStartY(y);
|
Circle markCircle2 = (Circle) super.getChildren().get(1);
|
||||||
line.setEndX(x);
|
Line connectingLine = (Line) super.getChildren().get(2);
|
||||||
line.setEndY(y);
|
if (marks.get(0).getId() == raceId) {
|
||||||
|
markCircle1.setCenterX(x);
|
||||||
|
markCircle1.setCenterY(y);
|
||||||
|
connectingLine.setStartX(markCircle1.getCenterX());
|
||||||
|
connectingLine.setStartY(markCircle1.getCenterY());
|
||||||
|
} else if (marks.get(1).getId() == raceId) {
|
||||||
|
markCircle2.setCenterX(x);
|
||||||
|
markCircle2.setCenterY(y);
|
||||||
|
connectingLine.setEndX(markCircle2.getCenterX());
|
||||||
|
connectingLine.setEndY(markCircle2.getCenterY());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRaceId (int... raceIds) {
|
public boolean hasRaceId (int... raceIds) {
|
||||||
for (int id : raceIds)
|
for (int id : raceIds)
|
||||||
for (Mark mark : marks)
|
for (Mark mark : marks)
|
||||||
if (id == mark.getId())
|
if (id == mark.getId())
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMarkRadius() {
|
public long[] getRaceIds () {
|
||||||
return MARK_RADIUS;
|
long[] idArray = new long[marks.size()];
|
||||||
}
|
|
||||||
|
|
||||||
public static void setMarkRadius(int markRadius) {
|
|
||||||
MARK_RADIUS = markRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getRaceIds () {
|
|
||||||
int[] idArray = new int[marks.size()];
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Mark mark : marks)
|
for (Mark mark : marks)
|
||||||
idArray[i++] = mark.getId();
|
idArray[i++] = mark.getId();
|
||||||
return idArray;
|
return idArray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,6 @@ public class SingleMark extends Mark {
|
|||||||
private String name;
|
private String name;
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a marker
|
* Represents a marker
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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,145 +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());
|
|
||||||
int id = Integer.valueOf(element.getElementsByTagName("id").item(0).getTextContent());
|
|
||||||
SingleMark singleMark = new SingleMark(name, lat, lon, id);
|
|
||||||
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;
|
|
||||||
if (name.equals("Start") || name.equals("Finish"))
|
|
||||||
gateMark = new GateMark(name, MarkType.CLOSED_GATE, mark1, mark2, mark1.getLatitude(), mark1.getLongitude());
|
|
||||||
else
|
|
||||||
gateMark = new GateMark(name, MarkType.OPEN_GATE, 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,54 +0,0 @@
|
|||||||
package seng302.models.parsers;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.StringReader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Haoming Yin (hyi25) on 16/3/2017
|
|
||||||
*/
|
|
||||||
public abstract class FileParser {
|
|
||||||
|
|
||||||
private String filePath;
|
|
||||||
|
|
||||||
public FileParser() {}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
//package seng302.models.parsers;
|
|
||||||
//
|
|
||||||
//import org.w3c.dom.*;
|
|
||||||
//import seng302.models.Yacht;
|
|
||||||
//
|
|
||||||
//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 Yacht 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());
|
|
||||||
// int id = Integer.valueOf(element.getElementsByTagName("id").item(0).getTextContent());
|
|
||||||
// Yacht boat = new Yacht(name, velocity, alias, id);
|
|
||||||
// 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<Yacht> getBoats() {
|
|
||||||
// ArrayList<Yacht> 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;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
+38
-35
@@ -1,24 +1,29 @@
|
|||||||
package seng302.models.parsers;
|
package seng302.models.stream;
|
||||||
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import seng302.models.Yacht;
|
|
||||||
import seng302.models.parsers.packets.BoatPositionPacket;
|
|
||||||
import seng302.models.parsers.packets.StreamPacket;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentSkipListMap;
|
import java.util.concurrent.ConcurrentSkipListMap;
|
||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import seng302.models.Yacht;
|
||||||
|
import seng302.models.stream.packets.BoatPositionPacket;
|
||||||
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The purpose of this class is to take in the stream of divided packets so they can be read
|
* The purpose of this class is to take in the stream of divided packets so they can be read
|
||||||
@@ -28,6 +33,7 @@ import java.util.concurrent.PriorityBlockingQueue;
|
|||||||
*/
|
*/
|
||||||
public class StreamParser extends Thread{
|
public class StreamParser extends Thread{
|
||||||
|
|
||||||
|
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> markPositions = new ConcurrentHashMap<>();
|
||||||
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatPositions = new ConcurrentHashMap<>();
|
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatPositions = new ConcurrentHashMap<>();
|
||||||
private String threadName;
|
private String threadName;
|
||||||
private Thread t;
|
private Thread t;
|
||||||
@@ -68,24 +74,10 @@ public class StreamParser extends Thread{
|
|||||||
Thread.sleep(1);
|
Thread.sleep(1);
|
||||||
}
|
}
|
||||||
while (appRunning){
|
while (appRunning){
|
||||||
StreamPacket packet = StreamReceiver.packetBuffer.peek();
|
StreamPacket packet = StreamReceiver.packetBuffer.take();
|
||||||
//this code adds a delay to reading from the packetBuffer so
|
|
||||||
//out of order packets have time to order themselves in the queue
|
|
||||||
int delayTime = 1000;
|
|
||||||
int loopTime = delayTime * 10;
|
|
||||||
long transitTime = (System.currentTimeMillis()%loopTime - packet.getTimeStamp()%loopTime);
|
|
||||||
if (transitTime < 0){
|
|
||||||
transitTime = loopTime + transitTime;
|
|
||||||
}
|
|
||||||
if (transitTime < delayTime) {
|
|
||||||
long sleepTime = delayTime - (transitTime);
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
}
|
|
||||||
packet = StreamReceiver.packetBuffer.take();
|
|
||||||
parsePacket(packet);
|
parsePacket(packet);
|
||||||
Thread.sleep(1);
|
Thread.sleep(1);
|
||||||
while (StreamReceiver.packetBuffer.peek() == null) {
|
while (StreamReceiver.packetBuffer.peek() == null) {
|
||||||
Thread.sleep(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
@@ -224,7 +216,6 @@ public class StreamParser extends Thread{
|
|||||||
raceFinished = false;
|
raceFinished = false;
|
||||||
System.out.println("[CLIENT] Race has started");
|
System.out.println("[CLIENT] Race has started");
|
||||||
}
|
}
|
||||||
//System.out.println("Time since start: " + -1 * timeTillStart + " Seconds");
|
|
||||||
timeSinceStart = timeTillStart;
|
timeSinceStart = timeTillStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,11 +224,10 @@ public class StreamParser extends Thread{
|
|||||||
|
|
||||||
int noBoats = payload[22];
|
int noBoats = payload[22];
|
||||||
int raceType = payload[23];
|
int raceType = payload[23];
|
||||||
// ArrayList<String> boatStatuses = new ArrayList<>();
|
|
||||||
boatsPos = new TreeMap<>();
|
boatsPos = new TreeMap<>();
|
||||||
for (int i = 0; i < noBoats; i++){
|
for (int i = 0; i < noBoats; i++){
|
||||||
Long boatStatusSourceID = bytesToLong(Arrays.copyOfRange(payload,24 + (i * 20),28+ (i * 20)));
|
long boatStatusSourceID = bytesToLong(Arrays.copyOfRange(payload,24 + (i * 20),28+ (i * 20)));
|
||||||
Yacht boat = boats.get((int)(long) boatStatusSourceID);
|
Yacht boat = boats.get((int) boatStatusSourceID);
|
||||||
boat.setBoatStatus((int)payload[28 + (i * 20)]);
|
boat.setBoatStatus((int)payload[28 + (i * 20)]);
|
||||||
boat.setLegNumber((int)payload[29 + (i * 20)]);
|
boat.setLegNumber((int)payload[29 + (i * 20)]);
|
||||||
boat.setPenaltiesAwarded((int)payload[30 + (i * 20)]);
|
boat.setPenaltiesAwarded((int)payload[30 + (i * 20)]);
|
||||||
@@ -317,6 +307,7 @@ public class StreamParser extends Thread{
|
|||||||
boats = xmlObject.getBoatXML().getCompetingBoats();
|
boats = xmlObject.getBoatXML().getCompetingBoats();
|
||||||
}
|
}
|
||||||
if (messageType == 6) { //6 is race info xml
|
if (messageType == 6) { //6 is race info xml
|
||||||
|
|
||||||
newRaceXmlReceived = true;
|
newRaceXmlReceived = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,7 +356,6 @@ public class StreamParser extends Thread{
|
|||||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload,9,13));
|
long subjectId = bytesToLong(Arrays.copyOfRange(payload,9,13));
|
||||||
long incidentId = bytesToLong(Arrays.copyOfRange(payload,13,17));
|
long incidentId = bytesToLong(Arrays.copyOfRange(payload,13,17));
|
||||||
int eventId = payload[17];
|
int eventId = payload[17];
|
||||||
// System.out.println("eventId = " + eventId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -403,20 +393,33 @@ public class StreamParser extends Thread{
|
|||||||
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload,38,40))/1000.0;
|
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload,38,40))/1000.0;
|
||||||
|
|
||||||
//type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat
|
//type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat
|
||||||
if (deviceType == 1 || deviceType == 3){
|
if (deviceType == 1){
|
||||||
BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed);
|
BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed);
|
||||||
|
|
||||||
//add a new priority que to the boatPositions HashMap
|
//add a new priority que to the boatPositions HashMap
|
||||||
if (!boatPositions.containsKey(boatId)){
|
if (!boatPositions.containsKey(boatId)){
|
||||||
boatPositions.put(boatId, new PriorityBlockingQueue<BoatPositionPacket>(256, new Comparator<BoatPositionPacket>() {
|
boatPositions.put(boatId, new PriorityBlockingQueue<>(256, new Comparator<BoatPositionPacket>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(BoatPositionPacket p1, BoatPositionPacket p2) {
|
public int compare(BoatPositionPacket p1, BoatPositionPacket p2) {
|
||||||
return (int) (p1.getTimeValid() - p2.getTimeValid());
|
return (int) (p1.getTimeValid() - p2.getTimeValid());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
//Adding the boatPacket to the priority que
|
|
||||||
boatPositions.get(boatId).put(boatPacket);
|
boatPositions.get(boatId).put(boatPacket);
|
||||||
|
} else if (deviceType == 3){
|
||||||
|
BoatPositionPacket markPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed);
|
||||||
|
|
||||||
|
//add a new priority que to the boatPositions HashMap
|
||||||
|
if (!markPositions.containsKey(boatId)) {
|
||||||
|
markPositions.put(boatId,
|
||||||
|
new PriorityBlockingQueue<>(256, new Comparator<BoatPositionPacket>() {
|
||||||
|
@Override
|
||||||
|
public int compare(BoatPositionPacket p1, BoatPositionPacket p2) {
|
||||||
|
return (int) (p1.getTimeValid() - p2.getTimeValid());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
markPositions.get(boatId).put(markPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+2
-4
@@ -1,13 +1,11 @@
|
|||||||
package seng302.models.parsers;
|
package seng302.models.stream;
|
||||||
|
|
||||||
import seng302.models.parsers.packets.StreamPacket;
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
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;
|
||||||
+246
-143
@@ -1,27 +1,29 @@
|
|||||||
package seng302.models.parsers;
|
package seng302.models.stream;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import seng302.models.Yacht;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
import seng302.models.Yacht;
|
||||||
|
import seng302.models.mark.GateMark;
|
||||||
|
import seng302.models.mark.Mark;
|
||||||
|
import seng302.models.mark.MarkType;
|
||||||
|
import seng302.models.mark.SingleMark;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to create an XML object from the XML Packet Messages.
|
* Class to create an XML object from the XML Packet Messages.
|
||||||
*
|
*
|
||||||
* Example usage:
|
* Example usage:
|
||||||
*
|
*
|
||||||
* Document doc; // some xml document
|
* Document doc; // some xml document
|
||||||
* Integer xmlMessageType; // an Integer of value 5, 6, 7
|
* Integer xmlMessageType; // an Integer of value 5, 6, 7
|
||||||
*
|
|
||||||
* xmlP = new XMLParser(doc, xmlMessageType);
|
|
||||||
* RegattaXMLObject rXmlObj = xmlP.createRegattaXML(); // creates a regattaXML object.
|
|
||||||
*
|
*
|
||||||
|
* xmlP = new XMLParser(doc, xmlMessageType);
|
||||||
|
* RegattaXMLObject rXmlObj = xmlP.createRegattaXML(); // creates a regattaXML object.
|
||||||
*/
|
*/
|
||||||
public class XMLParser {
|
public class XMLParser {
|
||||||
|
|
||||||
@@ -31,10 +33,12 @@ public class XMLParser {
|
|||||||
private RegattaXMLObject regattaXML;
|
private RegattaXMLObject regattaXML;
|
||||||
private BoatXMLObject boatXML;
|
private BoatXMLObject boatXML;
|
||||||
|
|
||||||
public XMLParser() {}
|
public XMLParser() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for XMLParser
|
* Constructor for XMLParser
|
||||||
|
*
|
||||||
* @param doc Document to create XML object.
|
* @param doc Document to create XML object.
|
||||||
* @param messageType Defines if a message is a RegattaXML(5), RaceXML(6), BoatXML(7).
|
* @param messageType Defines if a message is a RegattaXML(5), RaceXML(6), BoatXML(7).
|
||||||
*/
|
*/
|
||||||
@@ -53,13 +57,22 @@ public class XMLParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RaceXMLObject getRaceXML() { return raceXML; }
|
public RaceXMLObject getRaceXML() {
|
||||||
public RegattaXMLObject getRegattaXML() { return regattaXML; }
|
return raceXML;
|
||||||
public BoatXMLObject getBoatXML() { return boatXML; }
|
}
|
||||||
|
|
||||||
|
public RegattaXMLObject getRegattaXML() {
|
||||||
|
return regattaXML;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoatXMLObject getBoatXML() {
|
||||||
|
return boatXML;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text content of a given child element tag, assuming it exists, as an Integer.
|
* Returns the text content of a given child element tag, assuming it exists, as an Integer.
|
||||||
|
*
|
||||||
* @param ele Document Element with child elements.
|
* @param ele Document Element with child elements.
|
||||||
* @param tag Tag to find in document elements child elements.
|
* @param tag Tag to find in document elements child elements.
|
||||||
* @return Text content from tag if found, null otherwise.
|
* @return Text content from tag if found, null otherwise.
|
||||||
@@ -75,6 +88,7 @@ public class XMLParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text content of a given child element tag, assuming it exists, as an String.
|
* Returns the text content of a given child element tag, assuming it exists, as an String.
|
||||||
|
*
|
||||||
* @param ele Document Element with child elements.
|
* @param ele Document Element with child elements.
|
||||||
* @param tag Tag to find in document elements child elements.
|
* @param tag Tag to find in document elements child elements.
|
||||||
* @return Text content from tag if found, null otherwise.
|
* @return Text content from tag if found, null otherwise.
|
||||||
@@ -90,6 +104,7 @@ public class XMLParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text content of a given child element tag, assuming it exists, as a Double.
|
* Returns the text content of a given child element tag, assuming it exists, as a Double.
|
||||||
|
*
|
||||||
* @param ele Document Element with child elements.
|
* @param ele Document Element with child elements.
|
||||||
* @param tag Tag to find in document elements child elements.
|
* @param tag Tag to find in document elements child elements.
|
||||||
* @return Text content from tag if found, null otherwise.
|
* @return Text content from tag if found, null otherwise.
|
||||||
@@ -105,9 +120,11 @@ public class XMLParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text content of an attribute of a given Node, assuming it exists, as a String.
|
* 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 n A node object that should have some attributes
|
||||||
* @param attr The attribute you want to get from the given node.
|
* @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.
|
* @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) {
|
private static String getNodeAttributeString(Node n, String attr) {
|
||||||
Node attrItem = n.getAttributes().getNamedItem(attr);
|
Node attrItem = n.getAttributes().getNamedItem(attr);
|
||||||
@@ -120,9 +137,11 @@ public class XMLParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text content of an attribute of a given Node, assuming it exists, as an Integer.
|
* 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 n A node object that should have some attributes
|
||||||
* @param attr The attribute you want to get from the given node.
|
* @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.
|
* @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) {
|
private static Integer getNodeAttributeInt(Node n, String attr) {
|
||||||
Node attrItem = n.getAttributes().getNamedItem(attr);
|
Node attrItem = n.getAttributes().getNamedItem(attr);
|
||||||
@@ -135,9 +154,11 @@ public class XMLParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text content of an attribute of a given Node, assuming it exists, as a Double.
|
* 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 n A node object that should have some attributes
|
||||||
* @param attr The attribute you want to get from the given node.
|
* @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.
|
* @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) {
|
private static Double getNodeAttributeDouble(Node n, String attr) {
|
||||||
Node attrItem = n.getAttributes().getNamedItem(attr);
|
Node attrItem = n.getAttributes().getNamedItem(attr);
|
||||||
@@ -149,6 +170,7 @@ public class XMLParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class RegattaXMLObject {
|
public class RegattaXMLObject {
|
||||||
|
|
||||||
//Regatta Info
|
//Regatta Info
|
||||||
private Integer regattaID;
|
private Integer regattaID;
|
||||||
private String regattaName;
|
private String regattaName;
|
||||||
@@ -160,6 +182,7 @@ public class XMLParser {
|
|||||||
/**
|
/**
|
||||||
* Constructor for a RegattaXMLObject.
|
* Constructor for a RegattaXMLObject.
|
||||||
* Takes the information from a Document object and creates a more usable format.
|
* Takes the information from a Document object and creates a more usable format.
|
||||||
|
*
|
||||||
* @param doc XML Document Object
|
* @param doc XML Document Object
|
||||||
*/
|
*/
|
||||||
RegattaXMLObject(Document doc) {
|
RegattaXMLObject(Document doc) {
|
||||||
@@ -173,12 +196,29 @@ public class XMLParser {
|
|||||||
this.utcOffset = getElementInt(docEle, "UtcOffset");
|
this.utcOffset = getElementInt(docEle, "UtcOffset");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getRegattaID() { return regattaID; }
|
public Integer getRegattaID() {
|
||||||
public String getRegattaName() { return regattaName; }
|
return regattaID;
|
||||||
public String getCourseName() { return courseName; }
|
}
|
||||||
public Double getCentralLat() { return centralLat; }
|
|
||||||
public Double getCentralLng() { return centralLng; }
|
public String getRegattaName() {
|
||||||
public Integer getUtcOffset() { return utcOffset; }
|
return regattaName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCourseName() {
|
||||||
|
return courseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getCentralLat() {
|
||||||
|
return centralLat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getCentralLng() {
|
||||||
|
return centralLng;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUtcOffset() {
|
||||||
|
return utcOffset;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,13 +235,17 @@ public class XMLParser {
|
|||||||
|
|
||||||
//Non atomic race attributes
|
//Non atomic race attributes
|
||||||
private ArrayList<Participant> participants;
|
private ArrayList<Participant> participants;
|
||||||
private ArrayList<CompoundMark> course;
|
private ArrayList<Mark> course;
|
||||||
private ArrayList<Corner> compoundMarkSequence;
|
private ArrayList<Corner> compoundMarkSequence;
|
||||||
private ArrayList<Limit> courseLimit;
|
private ArrayList<Limit> courseLimit;
|
||||||
|
|
||||||
|
// ensures there's no duplicate marks.
|
||||||
|
private List<Long> seenSourceIDs = new ArrayList<Long>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a RaceXMLObject.
|
* Constructor for a RaceXMLObject.
|
||||||
* Takes the information from a Document object and creates a more usable format.
|
* Takes the information from a Document object and creates a more usable format.
|
||||||
|
*
|
||||||
* @param doc XML Document Object
|
* @param doc XML Document Object
|
||||||
*/
|
*/
|
||||||
RaceXMLObject(Document doc) {
|
RaceXMLObject(Document doc) {
|
||||||
@@ -213,8 +257,9 @@ public class XMLParser {
|
|||||||
this.creationTimeDate = getElementString(docEle, "CreationTimeDate");
|
this.creationTimeDate = getElementString(docEle, "CreationTimeDate");
|
||||||
|
|
||||||
Node raceStart = docEle.getElementsByTagName("RaceStartTime").item(0);
|
Node raceStart = docEle.getElementsByTagName("RaceStartTime").item(0);
|
||||||
this.raceStartTime = getNodeAttributeString(raceStart, "Start") ;
|
this.raceStartTime = getNodeAttributeString(raceStart, "Start");
|
||||||
this.postponeStatus = Boolean.parseBoolean(getNodeAttributeString(raceStart, "Postpone"));
|
this.postponeStatus = Boolean
|
||||||
|
.parseBoolean(getNodeAttributeString(raceStart, "Postpone"));
|
||||||
|
|
||||||
//Participants
|
//Participants
|
||||||
participants = new ArrayList<>();
|
participants = new ArrayList<>();
|
||||||
@@ -238,21 +283,13 @@ public class XMLParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Course
|
//Course
|
||||||
course = new ArrayList<>();
|
course = createCompoundMarks(docEle);
|
||||||
|
|
||||||
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
|
//Course Mark Sequence
|
||||||
compoundMarkSequence = new ArrayList<>();
|
compoundMarkSequence = new ArrayList<>();
|
||||||
|
|
||||||
NodeList cornerList = docEle.getElementsByTagName("CompoundMarkSequence").item(0).getChildNodes();
|
NodeList cornerList = docEle.getElementsByTagName("CompoundMarkSequence").item(0)
|
||||||
|
.getChildNodes();
|
||||||
for (int i = 0; i < cornerList.getLength(); i++) {
|
for (int i = 0; i < cornerList.getLength(); i++) {
|
||||||
Node cornerNode = cornerList.item(i);
|
Node cornerNode = cornerList.item(i);
|
||||||
if (cornerNode.getNodeName().equals("Corner")) {
|
if (cornerNode.getNodeName().equals("Corner")) {
|
||||||
@@ -274,18 +311,104 @@ public class XMLParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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; }
|
private ArrayList<Mark> createCompoundMarks(Element docEle) {
|
||||||
public ArrayList<CompoundMark> getCompoundMarks() { return course; }
|
ArrayList<Mark> cMarks = new ArrayList<>();
|
||||||
public ArrayList<Corner> getCompoundMarkSequence() { return compoundMarkSequence; }
|
|
||||||
public ArrayList<Limit> getCourseLimit() { return courseLimit; }
|
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")) {
|
||||||
|
Mark mark = createMark(cMarkNode);
|
||||||
|
if (mark != null) {
|
||||||
|
cMarks.add(mark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cMarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Mark createMark(Node compoundMark) {
|
||||||
|
|
||||||
|
List<SingleMark> marksList = new ArrayList<>();
|
||||||
|
String 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")) {
|
||||||
|
|
||||||
|
Integer sourceID = getNodeAttributeInt(markNode, "SourceID");
|
||||||
|
String markName = getNodeAttributeString(markNode, "Name");
|
||||||
|
Double targetLat = getNodeAttributeDouble(markNode, "TargetLat");
|
||||||
|
Double targetLng = getNodeAttributeDouble(markNode, "TargetLng");
|
||||||
|
|
||||||
|
SingleMark mark = new SingleMark(markName, targetLat, targetLng, sourceID);
|
||||||
|
marksList.add(mark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SingleMark mark : marksList) {
|
||||||
|
if (seenSourceIDs.contains(mark.getId())) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
seenSourceIDs.add(mark.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (marksList.size() == 1) {
|
||||||
|
return marksList.get(0);
|
||||||
|
} else if (marksList.size() == 2) {
|
||||||
|
return new GateMark(cMarkName, MarkType.OPEN_GATE, marksList.get(0),
|
||||||
|
marksList.get(1), marksList.get(0).getLatitude(),
|
||||||
|
marksList.get(0).getLongitude());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Mark> getCompoundMarks() {
|
||||||
|
return course;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Corner> getCompoundMarkSequence() {
|
||||||
|
return compoundMarkSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Limit> getCourseLimit() {
|
||||||
|
return courseLimit;
|
||||||
|
}
|
||||||
|
|
||||||
public class Participant {
|
public class Participant {
|
||||||
|
|
||||||
Integer sourceID;
|
Integer sourceID;
|
||||||
String entry;
|
String entry;
|
||||||
|
|
||||||
@@ -294,57 +417,17 @@ public class XMLParser {
|
|||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getsourceID() { return sourceID; }
|
public Integer getsourceID() {
|
||||||
public String getEntry() { return entry; }
|
return sourceID;
|
||||||
}
|
|
||||||
|
|
||||||
public 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 getEntry() {
|
||||||
public String getcMarkName() { return cMarkName; }
|
return entry;
|
||||||
public ArrayList<Mark> getMarks() { return marks; }
|
|
||||||
|
|
||||||
public 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; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Corner {
|
public class Corner {
|
||||||
|
|
||||||
private Integer seqID;
|
private Integer seqID;
|
||||||
private Integer compoundMarkID;
|
private Integer compoundMarkID;
|
||||||
private String rounding;
|
private String rounding;
|
||||||
@@ -357,13 +440,25 @@ public class XMLParser {
|
|||||||
this.zoneSize = getNodeAttributeInt(cornerNode, "ZoneSize");
|
this.zoneSize = getNodeAttributeInt(cornerNode, "ZoneSize");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getSeqID() { return seqID; }
|
public Integer getSeqID() {
|
||||||
public Integer getCompoundMarkID() { return compoundMarkID; }
|
return seqID;
|
||||||
public String getRounding() { return rounding; }
|
}
|
||||||
public Integer getZoneSize() { return zoneSize; }
|
|
||||||
|
public Integer getCompoundMarkID() {
|
||||||
|
return compoundMarkID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRounding() {
|
||||||
|
return rounding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getZoneSize() {
|
||||||
|
return zoneSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Limit {
|
public class Limit {
|
||||||
|
|
||||||
private Integer seqID;
|
private Integer seqID;
|
||||||
private Double lat;
|
private Double lat;
|
||||||
private Double lng;
|
private Double lng;
|
||||||
@@ -374,9 +469,17 @@ public class XMLParser {
|
|||||||
this.lng = getNodeAttributeDouble(limitNode, "Lon");
|
this.lng = getNodeAttributeDouble(limitNode, "Lon");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getSeqID() { return seqID; }
|
public Integer getSeqID() {
|
||||||
public Double getLat() { return lat; }
|
return seqID;
|
||||||
public Double getLng() { return lng; }
|
}
|
||||||
|
|
||||||
|
public Double getLat() {
|
||||||
|
return lat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getLng() {
|
||||||
|
return lng;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -402,6 +505,7 @@ public class XMLParser {
|
|||||||
/**
|
/**
|
||||||
* Constructor for a BoatXMLObject.
|
* Constructor for a BoatXMLObject.
|
||||||
* Takes the information from a Document object and creates a more usable format.
|
* Takes the information from a Document object and creates a more usable format.
|
||||||
|
*
|
||||||
* @param doc XML Document Object
|
* @param doc XML Document Object
|
||||||
*/
|
*/
|
||||||
BoatXMLObject(Document doc) {
|
BoatXMLObject(Document doc) {
|
||||||
@@ -421,7 +525,7 @@ public class XMLParser {
|
|||||||
Node zoneLimitsList = settingsList.item(7);
|
Node zoneLimitsList = settingsList.item(7);
|
||||||
this.zoneLimits = new ArrayList<>();
|
this.zoneLimits = new ArrayList<>();
|
||||||
for (int i = 0; i < zoneLimitsList.getAttributes().getLength(); i++) {
|
for (int i = 0; i < zoneLimitsList.getAttributes().getLength(); i++) {
|
||||||
String tag = String.format("Limit%d", i+1);
|
String tag = String.format("Limit%d", i + 1);
|
||||||
this.zoneLimits.add(getNodeAttributeDouble(zoneLimitsList, tag));
|
this.zoneLimits.add(getNodeAttributeDouble(zoneLimitsList, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,61 +536,60 @@ public class XMLParser {
|
|||||||
if (currentBoat.getNodeName().equals("Boat")) {
|
if (currentBoat.getNodeName().equals("Boat")) {
|
||||||
// Boat boat = new Boat(currentBoat);
|
// Boat boat = new Boat(currentBoat);
|
||||||
Yacht boat = new Yacht(getNodeAttributeString(currentBoat, "Type"),
|
Yacht boat = new Yacht(getNodeAttributeString(currentBoat, "Type"),
|
||||||
getNodeAttributeInt(currentBoat, "SourceID"),
|
getNodeAttributeInt(currentBoat, "SourceID"),
|
||||||
getNodeAttributeString(currentBoat, "HullNum"),
|
getNodeAttributeString(currentBoat, "HullNum"),
|
||||||
getNodeAttributeString(currentBoat, "ShortName"),
|
getNodeAttributeString(currentBoat, "ShortName"),
|
||||||
getNodeAttributeString(currentBoat, "BoatName"),
|
getNodeAttributeString(currentBoat, "BoatName"),
|
||||||
getNodeAttributeString(currentBoat, "Country"));
|
getNodeAttributeString(currentBoat, "Country"));
|
||||||
this.boats.add(boat);
|
this.boats.add(boat);
|
||||||
if (boat.getBoatType().equals("Yacht")) {
|
if (boat.getBoatType().equals("Yacht")) {
|
||||||
competingBoats.put(boat.getSourceID(), boat);
|
competingBoats.put(boat.getSourceID(), boat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//System.out.println(this.getBoats());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLastModified() { return lastModified; }
|
public String getLastModified() {
|
||||||
public Integer getVersion() { return version; }
|
return lastModified;
|
||||||
public String getBoatType() { return boatType; }
|
}
|
||||||
public Double getBoatLength() { return boatLength; }
|
|
||||||
public Double getHullLength() { return hullLength; }
|
public Integer getVersion() {
|
||||||
public Double getMarkZoneSize() { return markZoneSize; }
|
return version;
|
||||||
public Double getCourseZoneSize() { return courseZoneSize; }
|
}
|
||||||
public ArrayList<Double> getZoneLimits() { return zoneLimits; }
|
|
||||||
public ArrayList<Yacht> getBoats() { return boats; }
|
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<Yacht> getBoats() {
|
||||||
|
return boats;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Integer, Yacht> getCompetingBoats() {
|
public Map<Integer, Yacht> getCompetingBoats() {
|
||||||
return competingBoats;
|
return competingBoats;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public 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; }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package seng302.models.parsers.packets;
|
package seng302.models.stream.packets;
|
||||||
|
|
||||||
public class BoatPositionPacket {
|
public class BoatPositionPacket {
|
||||||
private long boatId;
|
private long boatId;
|
||||||
+1
-3
@@ -1,4 +1,4 @@
|
|||||||
package seng302.models.parsers.packets;
|
package seng302.models.stream.packets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Kusal on 4/24/2017.
|
* Created by Kusal on 4/24/2017.
|
||||||
@@ -48,6 +48,4 @@ public enum PacketType {
|
|||||||
}
|
}
|
||||||
return OTHER;
|
return OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package seng302.models.parsers.packets;
|
package seng302.models.stream.packets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by kre39 on 23/04/17.
|
* Created by kre39 on 23/04/17.
|
||||||
@@ -1,21 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import java.lang.*?>
|
|
||||||
<?import javafx.scene.control.*?>
|
<?import javafx.scene.control.*?>
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.scene.shape.*?>
|
<?import javafx.scene.shape.*?>
|
||||||
<?import javafx.scene.text.*?>
|
<?import javafx.scene.text.*?>
|
||||||
<?import javafx.scene.control.CheckBox?>
|
|
||||||
<?import javafx.scene.control.Label?>
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
|
||||||
<?import javafx.scene.layout.GridPane?>
|
|
||||||
<?import javafx.scene.layout.Pane?>
|
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
|
||||||
<?import javafx.scene.shape.Circle?>
|
|
||||||
<?import javafx.scene.text.Font?>
|
|
||||||
<?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" 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>
|
||||||
|
|||||||
@@ -8,14 +8,11 @@ import seng302.models.Colors;
|
|||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by ryan_ on 16/03/2017.
|
|
||||||
*/
|
|
||||||
public class ColorsTest {
|
public class ColorsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNextColor() {
|
public void testNextColor() {
|
||||||
Color expectedColors[] = {Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.PURPLE};
|
Color expectedColors[] = {Color.RED, Color.PERU, Color.SEAGREEN, Color.GREEN, Color.BLUE, Color.PURPLE};
|
||||||
for (int i = 0; i<6; i++)
|
for (int i = 0; i<6; i++)
|
||||||
{
|
{
|
||||||
Assert.assertEquals(expectedColors[i], Colors.getColor());
|
Assert.assertEquals(expectedColors[i], Colors.getColor());
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
package seng302;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import seng302.models.Race;
|
|
||||||
import seng302.models.Yacht;
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit test for the Race class.
|
|
||||||
*/
|
|
||||||
public class RaceTest {
|
|
||||||
/**
|
|
||||||
* Test that all boats were added to the race
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAddingBoatsToRace() {
|
|
||||||
Yacht boat1 = new Yacht("Team 1");
|
|
||||||
Yacht boat2 = new Yacht("Team 2");
|
|
||||||
|
|
||||||
Race race = new Race();
|
|
||||||
race.addBoat(boat1);
|
|
||||||
race.addBoat(boat2);
|
|
||||||
|
|
||||||
assertEquals(Array.getLength(race.getBoats()), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetShuffledBoats(){
|
|
||||||
Yacht boat1 = new Yacht("Team 1");
|
|
||||||
Yacht boat2 = new Yacht("Team 2");
|
|
||||||
|
|
||||||
Race race = new Race();
|
|
||||||
race.addBoat(boat1);
|
|
||||||
race.addBoat(boat2);
|
|
||||||
|
|
||||||
assertEquals(Array.getLength(race.getShuffledBoats()), 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package seng302.models.parsers;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Haoming on 23/03/17.
|
|
||||||
*/
|
|
||||||
public class ConfigParserTest {
|
|
||||||
|
|
||||||
private ConfigParser cp;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void initializeParser() throws Exception {
|
|
||||||
cp = new ConfigParser("/config/config.xml");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getWindDirection() throws Exception {
|
|
||||||
assertEquals(135, cp.getWindDirection(), 1e-10);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getTimeScale() throws Exception {
|
|
||||||
assertEquals(10.0, cp.getTimeScale(), 1e-10);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDoubleByTagName() throws Exception {
|
|
||||||
assertEquals(6, cp.getDoubleByTagName("race-size", 0), 1e-10);
|
|
||||||
assertEquals(100, cp.getDoubleByTagName("noTag", 100), 1e-10);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getStringByTagName() throws Exception {
|
|
||||||
assertEquals("AC35", cp.getStringByTagName("race-name", "11"));
|
|
||||||
assertEquals("oops", cp.getStringByTagName("noTag", "oops"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package seng302.models.parsers;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import seng302.models.mark.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To test if course parser works as expected.
|
|
||||||
* Created by Haoming on 17/03/17.
|
|
||||||
*/
|
|
||||||
public class CourseParserTest {
|
|
||||||
|
|
||||||
private CourseParser cp;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void initializeParser() throws Exception {
|
|
||||||
cp = new CourseParser("/config/course.xml");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getGates() throws Exception {
|
|
||||||
ArrayList<Mark> course = cp.getCourse();
|
|
||||||
|
|
||||||
|
|
||||||
GateMark gateMark1 = (GateMark) course.get(0);
|
|
||||||
assertEquals(57.670633, gateMark1.getSingleMark2().getLatitude(), 0.00000001);
|
|
||||||
assertEquals(11.8281330, gateMark1.getSingleMark2().getLongitude(), 0.00000001);
|
|
||||||
|
|
||||||
GateMark gateMark2 = (GateMark) course.get(5);
|
|
||||||
|
|
||||||
assertEquals("Finish1", gateMark2.getSingleMark1().getName());
|
|
||||||
assertEquals("Finish2", gateMark2.getSingleMark2().getName());
|
|
||||||
assertEquals(57.671824, gateMark2.getSingleMark2().getLatitude(), 0.00000001);
|
|
||||||
assertEquals(11.844795, gateMark2.getSingleMark2().getLongitude(), 0.00000001);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getMarks() throws Exception {
|
|
||||||
ArrayList<Mark> course = cp.getCourse();
|
|
||||||
assertEquals("Mid Mark", course.get(1).getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getOrder() {
|
|
||||||
ArrayList<Mark> course = cp.getCourse();
|
|
||||||
assertEquals(6, course.size());
|
|
||||||
assertEquals("Start", course.get(0).getName());
|
|
||||||
assertEquals("Mid Mark", course.get(1).getName());
|
|
||||||
assertEquals("Leeward Gate", course.get(2).getName());
|
|
||||||
assertEquals("Windward Gate", course.get(3).getName());
|
|
||||||
assertEquals("Leeward Gate", course.get(4).getName());
|
|
||||||
assertEquals("Finish", course.get(5).getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
package seng302.models.parsers;
|
package seng302.models.stream;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -8,7 +8,7 @@ import java.lang.reflect.Method;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
import seng302.models.parsers.packets.StreamPacket;
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
Reference in New Issue
Block a user