Fixed and enables the old wakes. Enabled the fps counter by implementing the team-27s fps counter from their code, fixed trails from starting at the start of the startline no matter at what point in the race the stream is connected to (this is means the map starts a lot cleaner). Added live tracked speeds which are taken from the boat location packet. Linked the speeds coming in to their specified boats and allowed the onscreen speed tracker to keep up with the speeds. Linked the current speeds to the wakes so the wakes are redrawn for each change in speed and size to match the speed. Also added the toggle functionality back to the fps counter so they can be toggled on an off.

#story[818]
This commit is contained in:
Kusal Ekanayake
2017-04-28 16:41:35 +12:00
parent d1289b0de1
commit 0f4ad48de0
8 changed files with 110 additions and 39 deletions
@@ -22,6 +22,7 @@ import seng302.models.parsers.StreamParser;
import seng302.models.parsers.StreamReceiver; import seng302.models.parsers.StreamReceiver;
import java.sql.Time; import java.sql.Time;
import java.text.DecimalFormat;
import java.util.*; import java.util.*;
/** /**
@@ -59,6 +60,13 @@ public class CanvasController {
private double metersToPixels; private double metersToPixels;
private List<RaceObject> raceObjects = new ArrayList<>(); private List<RaceObject> raceObjects = new ArrayList<>();
//FRAME RATE
private static final double UPDATE_TIME = 0.016666; // 1 / 60 ie 60fps
private final long[] frameTimes = new long[30];
private int frameTimeIndex = 0;
private boolean arrayFilled = false;
private DecimalFormat decimalFormat2dp = new DecimalFormat("0.00");
public AnimationTimer timer; public AnimationTimer timer;
private enum ScaleDirection { private enum ScaleDirection {
@@ -138,6 +146,8 @@ public class CanvasController {
timer = new AnimationTimer() { timer = new AnimationTimer() {
private int countdown = 60; private int countdown = 60;
private int[] currentRaceMarker = {1, 1, 1, 1, 1, 1}; private int[] currentRaceMarker = {1, 1, 1, 1, 1, 1};
List<Mark> marks = raceViewController.getRace().getCourse(); List<Mark> marks = raceViewController.getRace().getCourse();
@@ -150,6 +160,20 @@ public class CanvasController {
int boatIndex = 0; int boatIndex = 0;
Mark nextMark; Mark nextMark;
long oldFrameTime = frameTimes[frameTimeIndex] ;
frameTimes[frameTimeIndex] = now ;
frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length ;
if (frameTimeIndex == 0) {
arrayFilled = true ;
}
if (arrayFilled) {
long elapsedNanos = now - oldFrameTime ;
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
Double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
drawFps(frameRate.intValue());
}
//if (countdown == 0) { //if (countdown == 0) {
//System.out.println("called the at"); //System.out.println("called the at");
for (RaceObject raceObject : raceObjects) { for (RaceObject raceObject : raceObjects) {
@@ -163,8 +187,6 @@ public class CanvasController {
//descending = nextMark.getY() > boatGroup.getLayoutY(); //descending = nextMark.getY() > boatGroup.getLayoutY();
//leftToRight = nextMark.getX() < boatGroup.getLayoutX(); //leftToRight = nextMark.getX() < boatGroup.getLayoutX();
raceObject.updatePosition(1000 / 60); raceObject.updatePosition(1000 / 60);
for (int id : raceObject.getRaceIds()) { for (int id : raceObject.getRaceIds()) {
//System.out.println("id = " + id); //System.out.println("id = " + id);
@@ -285,10 +307,15 @@ public class CanvasController {
private void drawFps(int fps){ private void drawFps(int fps){
if (raceViewController.isDisplayFps()){ if (raceViewController.isDisplayFps()){
gc.clearRect(5,5,50,20);
gc.setFill(Color.BLACK); gc.setFill(Color.BLACK);
gc.setFont(new Font(14)); gc.setFont(new Font(14));
gc.setLineWidth(3); gc.setLineWidth(3);
gc.fillText(fps + " FPS", 5, 20); gc.fillText(fps + " FPS", 5, 20);
} else {
gc.clearRect(5,5,50,20);
gc.setFill(Color.SKYBLUE);
gc.fillRect(4,4,51,21);
} }
} }
@@ -307,7 +334,7 @@ public class CanvasController {
for (Boat boat : boats) { for (Boat boat : boats) {
BoatGroup boatGroup = new BoatGroup(boat, Colors.getColor()); BoatGroup boatGroup = new BoatGroup(boat, Colors.getColor());
boatGroup.moveTo(startingX, startingY, 0d); boatGroup.moveTo(startingX, startingY, 0d);
boatGroup.setDestination(firstMarkX, firstMarkY); // boatGroup.setDestination(firstMarkX, firstMarkY);
boatGroup.forceRotation(); boatGroup.forceRotation();
group.getChildren().add(boatGroup); group.getChildren().add(boatGroup);
raceObjects.add(boatGroup); raceObjects.add(boatGroup);
@@ -5,6 +5,7 @@ import javafx.animation.KeyFrame;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
+1
View File
@@ -140,4 +140,5 @@ public class Boat {
public int getId() { public int getId() {
return id; return id;
} }
} }
+45 -20
View File
@@ -8,6 +8,7 @@ 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.scene.transform.Translate; import javafx.scene.transform.Translate;
import seng302.models.parsers.StreamParser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -28,6 +29,7 @@ public class BoatGroup extends RaceObject{
private static double expectedUpdateInterval = 200; private static double expectedUpdateInterval = 200;
private static int WAKE_FRAME_INTERVAL = 30; private static int WAKE_FRAME_INTERVAL = 30;
private double framesForNewLine = 0; private double framesForNewLine = 0;
private boolean destinationSet;
private Point2D lastPoint; private Point2D lastPoint;
private Boat boat; private Boat boat;
@@ -35,7 +37,7 @@ public class BoatGroup extends RaceObject{
private List<Wake> wakes = new ArrayList<>(); private List<Wake> wakes = new ArrayList<>();
private List<Line> lines = new ArrayList<>(); private List<Line> lines = new ArrayList<>();
private Polygon boatPoly; private Polygon boatPoly;
// private Polygon wakePoly; private Polygon wakePoly;
private Text teamNameObject; private Text teamNameObject;
private Text velocityObject; private Text velocityObject;
@@ -56,12 +58,12 @@ public class BoatGroup extends RaceObject{
// boatPoly.setLayoutY(0); // boatPoly.setLayoutY(0);
// boatPoly.relocate(boatPoly.getLayoutX(), boatPoly.getLayoutY()); // boatPoly.relocate(boatPoly.getLayoutX(), boatPoly.getLayoutY());
// //
// wakePoly = new Polygon( wakePoly = new Polygon(
// 5.0,0.0, 5.0,0.0,
// 10.0, boat.getVelocity() * VELOCITY_WAKE_RATIO, 10.0, boat.getVelocity() * VELOCITY_WAKE_RATIO,
// 0.0, boat.getVelocity() * VELOCITY_WAKE_RATIO 0.0, boat.getVelocity() * VELOCITY_WAKE_RATIO
// ); );
// wakePoly.setFill(Color.DARKBLUE); wakePoly.setFill(Color.DARKBLUE);
teamNameObject = new Text(boat.getShortName()); teamNameObject = new Text(boat.getShortName());
velocityObject = new Text(String.valueOf(boat.getVelocity())); velocityObject = new Text(String.valueOf(boat.getVelocity()));
@@ -73,9 +75,8 @@ 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;
// super.getChildren().addAll(wakePoly, boatPoly, teamNameObject, velocityObject); super.getChildren().addAll(wakePoly, boatPoly, teamNameObject, velocityObject);
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly);
} }
private void initChildren (Color color) { private void initChildren (Color color) {
@@ -97,8 +98,8 @@ public class BoatGroup extends RaceObject{
teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy); teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy);
velocityObject.setLayoutX(velocityObject.getLayoutX() + dx); velocityObject.setLayoutX(velocityObject.getLayoutX() + dx);
velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); velocityObject.setLayoutY(velocityObject.getLayoutY() + dy);
// wakePoly.setLayoutX(wakePoly.getLayoutX() + dx); wakePoly.setLayoutX(wakePoly.getLayoutX() + dx);
// wakePoly.setLayoutY(wakePoly.getLayoutY() + dy); wakePoly.setLayoutY(wakePoly.getLayoutY() + dy);
rotateTo(currentRotation); rotateTo(currentRotation);
} }
@@ -119,8 +120,8 @@ public class BoatGroup extends RaceObject{
teamNameObject.setLayoutY(y); teamNameObject.setLayoutY(y);
velocityObject.setLayoutX(x); velocityObject.setLayoutX(x);
velocityObject.setLayoutY(y); velocityObject.setLayoutY(y);
// wakePoly.setLayoutX(x); wakePoly.setLayoutX(x);
// wakePoly.setLayoutY(y); wakePoly.setLayoutY(y);
} }
public void updatePosition (double timeInterval) { public void updatePosition (double timeInterval) {
@@ -158,9 +159,8 @@ public class BoatGroup extends RaceObject{
boatPoly.getLayoutX(), boatPoly.getLayoutX(),
boatPoly.getLayoutY(), boatPoly.getLayoutY(),
pixelVelocityX, pixelVelocityX,
pixelVelocityY, rotation); pixelVelocityY,
// wake.getTransforms().clear(); rotation);
// wake.getTransforms().add(new Rotate(rotation, 0, 0));
super.getChildren().add(wake); super.getChildren().add(wake);
wakes.add(wake); wakes.add(wake);
} }
@@ -174,13 +174,18 @@ public class BoatGroup extends RaceObject{
lines.add(l); lines.add(l);
super.getChildren().add(l); super.getChildren().add(l);
} }
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY()); if (destinationSet){
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
}
} }
framesForNewLine -= 1; framesForNewLine -= 1;
} }
public void setDestination (double newXValue, double newYValue, double rotation, int... raceIds) { public void setDestination (double newXValue, double newYValue, double rotation, int... raceIds) {
//System.out.println("MADE IT"); //System.out.println("MADE IT");
destinationSet = true;
boat.setVelocity(StreamParser.boatSpeeds.get((long)boat.getId()));
resizeWake();
if (hasRaceId(raceIds)) { if (hasRaceId(raceIds)) {
this.pixelVelocityX = (newXValue - boatPoly.getLayoutX()) / expectedUpdateInterval; this.pixelVelocityX = (newXValue - boatPoly.getLayoutX()) / expectedUpdateInterval;
this.pixelVelocityY = (newYValue - boatPoly.getLayoutY()) / expectedUpdateInterval; this.pixelVelocityY = (newYValue - boatPoly.getLayoutY()) / expectedUpdateInterval;
@@ -191,6 +196,8 @@ public class BoatGroup extends RaceObject{
} }
public void setDestination (double newXValue, double newYValue, int... raceIDs) { public void setDestination (double newXValue, double newYValue, int... raceIDs) {
destinationSet = true;
if (hasRaceId(raceIDs)) { if (hasRaceId(raceIDs)) {
double rotation = Math.abs( double rotation = Math.abs(
Math.toDegrees( Math.toDegrees(
@@ -212,16 +219,34 @@ public class BoatGroup extends RaceObject{
} }
} }
void resizeWake(){
velocityObject.setText(String.valueOf(boat.getVelocity()));
super.getChildren().remove(wakePoly);
wakePoly = new Polygon(
5.0,0.0,
10.0, boat.getVelocity() * VELOCITY_WAKE_RATIO,
0.0, boat.getVelocity() * VELOCITY_WAKE_RATIO
);
wakePoly.setLayoutX(boatPoly.getLayoutX());
wakePoly.setLayoutY(boatPoly.getLayoutY());
wakePoly.setFill(Color.DARKBLUE);
super.getChildren().add(wakePoly);
}
public void rotateTo (double rotation) { public void rotateTo (double rotation) {
if(rotation != 0) { if(rotation != 0) {
rotationalGoal = rotation; rotationalGoal = rotation;
boatPoly.getTransforms().clear(); boatPoly.getTransforms().clear();
boatPoly.getTransforms().add(new Rotate(rotation, BOAT_WIDTH / 2, 0)); boatPoly.getTransforms().add(new Rotate(rotation, BOAT_WIDTH / 2, 0));
wakePoly.getTransforms().clear();
wakePoly.getTransforms().add(new Translate(0, BOAT_HEIGHT));
wakePoly.getTransforms().add(new Rotate(rotation, BOAT_WIDTH/2, -BOAT_HEIGHT));
} }
// wakePoly.getTransforms().clear();
// wakePoly.getTransforms().add(new Rotate(rotation, 0, 0));
} }
public void forceRotation () { public void forceRotation () {
rotateTo (rotationalGoal); rotateTo (rotationalGoal);
} }
+1 -1
View File
@@ -29,7 +29,7 @@ class Wake extends Arc {
super.setType(ArcType.OPEN); super.setType(ArcType.OPEN);
super.setFill(new Color(0, 0, 0 ,0)); super.setFill(new Color(0, 0, 0 ,0));
super.setStrokeWidth(2.0); super.setStrokeWidth(2.0);
super.getTransforms().add(new Rotate(rotation, 5, -15)); super.getTransforms().add(new Rotate(rotation - 270, startingX + 20, startingY + 20));
// this.velocityX = -velocityX; // this.velocityX = -velocityX;
// this.velocityY = -velocityY; // this.velocityY = -velocityY;
this.velocityX = 0; this.velocityX = 0;
@@ -14,6 +14,8 @@ import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
@@ -25,6 +27,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class StreamParser extends Thread{ public class StreamParser extends Thread{
public static ConcurrentHashMap<Long,Point3D> boatPositions = new ConcurrentHashMap<>(); public static ConcurrentHashMap<Long,Point3D> boatPositions = new ConcurrentHashMap<>();
public static ConcurrentHashMap<Long,Double> boatSpeeds = new ConcurrentHashMap<>();
private static ArrayList<Long> boat_IDS = new ArrayList<>(); private static ArrayList<Long> boat_IDS = new ArrayList<>();
private String threadName; private String threadName;
private Thread t; private Thread t;
@@ -253,6 +256,8 @@ public class StreamParser extends Thread{
byte[] lonBytes = Arrays.copyOfRange(payload,20,24); byte[] lonBytes = Arrays.copyOfRange(payload,20,24);
byte[] boatIdBytes = Arrays.copyOfRange(payload,7,11); byte[] boatIdBytes = Arrays.copyOfRange(payload,7,11);
byte[] headingBytes = Arrays.copyOfRange(payload,28,30); byte[] headingBytes = Arrays.copyOfRange(payload,28,30);
byte[] speedBytes = Arrays.copyOfRange(payload,38,40);
long timeStamp = extractTimeStamp(Arrays.copyOfRange(payload,1,7), 6); long timeStamp = extractTimeStamp(Arrays.copyOfRange(payload,1,7), 6);
// int boatSeq = ByteBuffer.wrap(seqBytes).getInt(); // int boatSeq = ByteBuffer.wrap(seqBytes).getInt();
long seq = bytesToLong(seqBytes); long seq = bytesToLong(seqBytes);
@@ -260,7 +265,13 @@ public class StreamParser extends Thread{
long lat = bytesToLong(latBytes); long lat = bytesToLong(latBytes);
long lon = bytesToLong(lonBytes); long lon = bytesToLong(lonBytes);
long heading = bytesToLong(headingBytes); long heading = bytesToLong(headingBytes);
// long speed = extractTimeStamp(speedBytes, 2);
ByteBuffer bb = ByteBuffer.allocate(2);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.put(speedBytes[0]);
bb.put(speedBytes[1]);
double speed = bb.getShort(0)/1000.0;
short s = (short) ((speedBytes[1] & 0xFF) << 8 | (speedBytes[0] & 0xFF));
if ((int)deviceType == 1 || (int)deviceType == 4){ if ((int)deviceType == 1 || (int)deviceType == 4){
// System.out.println("boatId = " + boatId); // System.out.println("boatId = " + boatId);
// System.out.println("deviceType = " + (long)deviceType); // System.out.println("deviceType = " + (long)deviceType);
@@ -268,13 +279,16 @@ public class StreamParser extends Thread{
//needs to be validated //needs to be validated
Point3D point = new Point3D(((180d * (double)lat)/Math.pow(2,31)),((180d *(double)lon)/Math.pow(2,31)),(double)heading); Point3D point = new Point3D(((180d * (double)lat)/Math.pow(2,31)),((180d *(double)lon)/Math.pow(2,31)),(double)heading);
boatPositions.putIfAbsent(boatId, point); boatPositions.putIfAbsent(boatId, point);
boatSpeeds.putIfAbsent(boatId, speed);
boatPositions.replace(boatId, point); boatPositions.replace(boatId, point);
boatSpeeds.replace(boatId, speed);
// System.out.println("lon = " + ((180d * (double)lon)/Math.pow(2,31))); // System.out.println("lon = " + ((180d * (double)lon)/Math.pow(2,31)));
// System.out.println("lat = " + ((180d *(double)lat)/Math.pow(2,31))); // System.out.println("lat = " + ((180d *(double)lat)/Math.pow(2,31)));
} }
} }
private static void extractMarkRounding(StreamPacket packet){ private static void extractMarkRounding(StreamPacket packet){
byte[] payload = packet.getPayload(); byte[] payload = packet.getPayload();
int messageVersionNo = payload[0]; int messageVersionNo = payload[0];
+6 -6
View File
@@ -4,37 +4,37 @@
<team> <team>
<name>Oracle Team USA</name> <name>Oracle Team USA</name>
<alias>USA</alias> <alias>USA</alias>
<velocity>12.9</velocity> <velocity>0.0</velocity>
<id>102</id> <id>102</id>
</team> </team>
<team> <team>
<name>Artemis Racing</name> <name>Artemis Racing</name>
<alias>ART</alias> <alias>ART</alias>
<velocity>13.1</velocity> <velocity>0.0</velocity>
<id>101</id> <id>101</id>
</team> </team>
<team> <team>
<name>Emirates Team New Zealand</name> <name>Emirates Team New Zealand</name>
<alias>NZL</alias> <alias>NZL</alias>
<velocity>15.6</velocity> <velocity>0.0</velocity>
<id>103</id> <id>103</id>
</team> </team>
<team> <team>
<name>Land Rover BAR</name> <name>Land Rover BAR</name>
<alias>BAR</alias> <alias>BAR</alias>
<velocity>13.3</velocity> <velocity>0.0</velocity>
<id>104</id> <id>104</id>
</team> </team>
<team> <team>
<name>SoftBank Team Japan</name> <name>SoftBank Team Japan</name>
<alias>JAP</alias> <alias>JAP</alias>
<velocity>14.7</velocity> <velocity>0.0</velocity>
<id>105</id> <id>105</id>
</team> </team>
<team> <team>
<name>Groupama Team France</name> <name>Groupama Team France</name>
<alias>FRC</alias> <alias>FRC</alias>
<velocity>11.4</velocity> <velocity>0.0</velocity>
<id>106</id> <id>106</id>
</team> </team>
</teams> </teams>
+11 -8
View File
@@ -1,15 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?> <?import javafx.scene.control.CheckBox?>
<?import javafx.scene.shape.*?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.layout.AnchorPane?> <?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.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.RaceViewController">
<columnConstraints> <columnConstraints>
<ColumnConstraints maxWidth="246.0" minWidth="246.0" prefWidth="246.0" /> <ColumnConstraints maxWidth="246.0" minWidth="246.0" prefWidth="246.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="1034.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="1034.0" />