Merge remote-tracking branch 'origin/develop' into develop

# Conflicts:
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java
This commit is contained in:
Michael Rausch
2017-09-28 16:02:04 +13:00
37 changed files with 347 additions and 1421 deletions
+1 -1
View File
@@ -103,7 +103,7 @@ public class App extends Application {
public void run() { public void run() {
System.gc(); System.gc();
} }
}, 0, 1200); }, 0, 1_000);
try { try {
parseArgs(args); parseArgs(args);
@@ -238,7 +238,7 @@ public class GameState implements Runnable {
if (System.currentTimeMillis() > startTime) { if (System.currentTimeMillis() > startTime) {
startSpawningTokens(); startSpawningTokens();
startUpdatingWind(); startUpdatingWind();
GameState.setCurrentStage(GameStages.RACING); GameState.currentStage = GameStages.RACING;
} }
} }
if (currentStage == GameStages.RACING) { if (currentStage == GameStages.RACING) {
@@ -299,8 +299,8 @@ public class GameState implements Runnable {
windSpeed += random.nextInt(500); windSpeed += random.nextInt(500);
} }
GameState.setWindSpeed(Double.valueOf(windSpeed)); GameState.windSpeed = Double.valueOf(windSpeed);
GameState.setWindDirection(direction.doubleValue()); GameState.windDirection = direction.doubleValue();
} }
@@ -5,7 +5,6 @@ import java.net.ServerSocket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -19,12 +18,6 @@ import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
/** /**
* A class describing the overall server, which creates and collects server threads for each client * A class describing the overall server, which creates and collects server threads for each client
@@ -32,23 +25,32 @@ import java.util.TimerTask;
*/ */
public class MainServerThread implements Runnable, ClientConnectionDelegate { public class MainServerThread implements Runnable, ClientConnectionDelegate {
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
private static final int PORT = 4942; private static final int PORT = 4942;
private static int selectedPort = PORT; private static int selectedPort = PORT;
private static final Integer CLIENT_UPDATES_PER_SECOND = 60; private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
private boolean terminated; private boolean terminated;
private Thread thread;
private boolean hasStarted = false; private boolean hasStarted = false;
private ServerSocket serverSocket = null; private ServerSocket serverSocket = null;
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>(); private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
private static Integer capacity;
private RaceXMLData raceXMLData; private RaceXMLData raceXMLData;
private RegattaXMLData regattaXMLData; private RegattaXMLData regattaXMLData;
private boolean serverStarted = false;
public MainServerThread() {
new GameState();
try {
serverSocket = new ServerSocket(0);
selectedPort = serverSocket.getLocalPort();
} catch (IOException e) {
logger.trace("IO error in server thread handler upon trying to make new server socket",
0);
}
terminated = false;
Thread thread = new Thread(this, "MainServer");
thread.start();
}
private void startAdvertisingServer() { private void startAdvertisingServer() {
Integer capacity = GameState.getCapacity(); Integer capacity = GameState.getCapacity();
@@ -72,22 +74,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} }
} }
public MainServerThread() {
new GameState();
try {
serverSocket = new ServerSocket(0);
selectedPort = serverSocket.getLocalPort();
System.out.println("selectedPort = " + selectedPort);
} catch (IOException e) {
logger.trace("IO error in server thread handler upon trying to make new server socket",
0);
}
terminated = false;
thread = new Thread(this, "MainServer");
thread.start();
}
private void startServer() { private void startServer() {
PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv")); PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData); MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
@@ -126,7 +112,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1); logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
} }
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) { if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
.getCustomizationFlag()) {
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values())); MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
sendSetupMessages(); sendSetupMessages();
GameState.resetCustomizationFlag(); GameState.resetCustomizationFlag();
@@ -145,7 +132,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
else if (GameState.getCurrentStage() == GameStages.FINISHED) { else if (GameState.getCurrentStage() == GameStages.FINISHED) {
broadcastMessage(MessageFactory.getRaceStatusMessage()); broadcastMessage(MessageFactory.getRaceStatusMessage());
try { try {
Thread.sleep(1000); //Hackish fix to make sure all threads have sent closing RaceStatus Thread.sleep(
1000); //Hackish fix to make sure all threads have sent closing RaceStatus
terminate(); terminate();
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
logger.trace("Thread interrupted while waiting to terminate clients", 1); logger.trace("Thread interrupted while waiting to terminate clients", 1);
@@ -153,7 +141,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} }
} }
try { try {
synchronized (this){ synchronized (this) {
for (ServerToClientThread serverToClientThread : serverToClientThreads) { for (ServerToClientThread serverToClientThread : serverToClientThreads) {
serverToClientThread.terminate(); serverToClientThread.terminate();
} }
@@ -209,9 +197,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
startServer(); startServer();
} }
}); });
} else {
//serverToClientThread.addConnectionListener(this::sendSetupMessages);
} }
serverToClientThreads.add(serverToClientThread); serverToClientThreads.add(serverToClientThread);
try { try {
@@ -220,7 +207,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
logger.warn("Couldn't update advertisement"); logger.warn("Couldn't update advertisement");
} }
while (regattaXMLData == null && raceXMLData == null){ while (regattaXMLData == null && raceXMLData == null) {
try { try {
Thread.sleep(50); Thread.sleep(50);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -246,7 +233,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
for (ServerToClientThread serverToClientThread : serverToClientThreads) { for (ServerToClientThread serverToClientThread : serverToClientThreads) {
if (serverToClientThread.getSocket() == player.getSocket()) { if (serverToClientThread.getSocket() == player.getSocket()) {
closedConnection = serverToClientThread; closedConnection = serverToClientThread;
} else if (GameState.getCurrentStage() != GameStages.RACING){ } else if (GameState.getCurrentStage() != GameStages.RACING) {
serverToClientThread.sendSetupMessages(); serverToClientThread.sendSetupMessages();
} }
} }
@@ -259,7 +246,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
logger.warn("Couldn't update advertisement"); logger.warn("Couldn't update advertisement");
} }
closedConnection.terminate(); if (closedConnection != null) {
closedConnection.terminate();
}
} }
public void startGame() { public void startGame() {
@@ -277,16 +266,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
public void run() { public void run() {
broadcastMessage(MessageFactory.getRaceStatusMessage()); broadcastMessage(MessageFactory.getRaceStatusMessage());
if (GameState.getCurrentStage() == GameStages.PRE_RACE if (GameState.getCurrentStage() == GameStages.PRE_RACE
|| GameState.getCurrentStage() == GameStages.LOBBYING) { || GameState.getCurrentStage() == GameStages.LOBBYING) {
broadcastMessage(MessageFactory.getRaceStartStatusMessage()); broadcastMessage(MessageFactory.getRaceStartStatusMessage());
} }
} }
}, 0, 500); }, 0, 500);
// if (GameState.getCurrentStage() == GameStages.LOBBYING) {
// sendSetupMessages();
// }
} }
public void terminate() { public void terminate() {
@@ -297,108 +282,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
* Initialise boats to specific spaced out geopoints behind starting line. * Initialise boats to specific spaced out geopoints behind starting line.
*/ */
private void initialiseBoatPositions() { private void initialiseBoatPositions() {
// CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0);
// GeoPoint startMark1 = cm.getSubMark(1);
// GeoPoint startMark2 = cm.getSubMark(2);
//
// // Calculating midpoint
// Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2);
// Double length = GeoUtility.getDistance(startMark1, startMark2);
// GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2);
//
// // Setting each boats position side by side
// final double SEPARATION = 50.0; // distance apart in meters
//
// int boatIndex = 0;
// for (ServerYacht yacht : GameState.getYachts().values()) {
// int distanceApart = boatIndex / 2;
//
// if (boatIndex % 2 == 1 && boatIndex != 0) {
// distanceApart++;
// distanceApart *= -1;
// }
//
// GeoPoint spawnMark = GeoUtility
// .getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * SEPARATION);
//
// if (yacht.getHeading() < perpendicularAngle) {
// spawnMark = GeoUtility
// .getGeoCoordinate(spawnMark, perpendicularAngle + 90, SEPARATION);
// } else {
// spawnMark = GeoUtility
// .getGeoCoordinate(spawnMark, perpendicularAngle + 270, SEPARATION);
// }
//
// yacht.setLocation(spawnMark);
// boatIndex++;
// }
// final double SEPARATION = 50.0; // distance apart in meters
//
// //Reverse of the angle from start to first mark
// double angleToFirstMark = 360 - GeoUtility.getBearing(
// GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
// GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
// );
//
// //Length of start line
// double startLineLength = GeoUtility.getDistance(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
// );
//
// //Angle of start line
// double startMarkToMarkAngle = GeoUtility.getBearing(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
// );
//
// //How many yachts can fit along the start line
// int spacesAlongLine = (int) Math.round(startLineLength / SEPARATION);
// //The free space left by the boats.
// double buffer = (startLineLength % SEPARATION) / 2;
//
// //Randomize starting order.
// List<ServerYacht> serverYachtList = new ArrayList<>(GameState.getYachts().values());
// Collections.shuffle(serverYachtList);
//
// //set the starting point away from start line.
// GeoPoint startingPoint = GeoUtility.getGeoCoordinate(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// angleToFirstMark, SEPARATION
// );
//
// //Move it along the start line
// startingPoint = GeoUtility.getGeoCoordinate(
// startingPoint, startMarkToMarkAngle, buffer
// );
//
// int yachtCount = 0;
// int repeats = 0;
//
// GeoPoint yachtLocation;
//
// for (ServerYacht serverYacht : serverYachtList) {
//
// //Move away from start line
// yachtLocation = GeoUtility.getGeoCoordinate(
// startingPoint, angleToFirstMark,repeats * SEPARATION
// );
// //Move along start line
// yachtLocation = GeoUtility.getGeoCoordinate(
// yachtLocation, startMarkToMarkAngle, yachtCount * SEPARATION
// );
// serverYacht.setLocation(yachtLocation);
// serverYacht.setHeading(GeoUtility.getBearing(
// yachtLocation, GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
// ));
// //Set location for next yacht
// yachtCount++;
// if (yachtCount > spacesAlongLine) {
// yachtCount = 0;
// repeats++;
// }
// }
final double DISTANCE_TO_START = 75d; final double DISTANCE_TO_START = 75d;
final double YACHT_SEPARATION = 20d; final double YACHT_SEPARATION = 20d;
@@ -438,14 +321,16 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
Collections.shuffle(randomisedYachts); Collections.shuffle(randomisedYachts);
while (randomisedYachts.size() > 0) { while (randomisedYachts.size() > 0) {
int numYachtsInLine = spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size() : spacesAlongLine; int numYachtsInLine =
spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size()
: spacesAlongLine;
double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2; double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2;
GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate( GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate(
startingPoint, startMarkToMarkAngle + 180, yachtSpace startingPoint, startMarkToMarkAngle + 180, yachtSpace
); );
for (int i=0; i<numYachtsInLine; i++){ for (int i = 0; i < numYachtsInLine; i++) {
randomisedYachts.get(0).setHeading(angleFromStart); randomisedYachts.get(0).setHeading(angleFromStart);
randomisedYachts.get(0).setLocation(firstYachtPoint); randomisedYachts.get(0).setLocation(firstYachtPoint);
firstYachtPoint = GeoUtility.getGeoCoordinate( firstYachtPoint = GeoUtility.getGeoCoordinate(
@@ -1,6 +1,5 @@
package seng302.gameServer; package seng302.gameServer;
import seng302.gameServer.messages.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import seng302.gameServer.messages.BoatLocationMessage; import seng302.gameServer.messages.BoatLocationMessage;
@@ -25,9 +24,6 @@ import seng302.model.token.Token;
import seng302.model.token.TokenType; import seng302.model.token.TokenType;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
import java.util.ArrayList;
import java.util.List;
/** /**
* A Class for interfacing between the data we have in the GameState to the messages we need to send * A Class for interfacing between the data we have in the GameState to the messages we need to send
* through the MainServerThread. * through the MainServerThread.
@@ -77,9 +73,6 @@ public class MessageFactory {
} }
public static void updateBoats(List<ServerYacht> yachts) { public static void updateBoats(List<ServerYacht> yachts) {
// for (ServerYacht serverYacht : yachts) {
// System.out.println(serverYacht);
// }
xmlGenerator.getRace().setBoats(yachts); xmlGenerator.getRace().setBoats(yachts);
String xmlStr = xmlGenerator.getBoatsAsXml(); String xmlStr = xmlGenerator.getBoatsAsXml();
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length()); MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
@@ -1,14 +1,5 @@
package seng302.visualiser; package seng302.visualiser;
import javafx.application.Platform;
import javafx.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.*;
import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
import seng302.utilities.XMLParser;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -43,7 +34,7 @@ import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.model.stream.xml.generator.RegattaXMLTemplate; import seng302.model.stream.xml.generator.RegattaXMLTemplate;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser; import seng302.utilities.XMLParser;
import seng302.visualiser.controllers.ViewManager;
/** /**
* A class describing a single connection to a Server for the purposes of sending and receiving on * A class describing a single connection to a Server for the purposes of sending and receiving on
@@ -5,9 +5,7 @@ import java.text.SimpleDateFormat;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.Timer; import java.util.Timer;
@@ -17,7 +15,6 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.util.Pair; import javafx.util.Pair;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
@@ -49,19 +46,12 @@ import seng302.visualiser.controllers.RaceViewController;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.controllers.dialogs.PopupDialogController; import seng302.visualiser.controllers.dialogs.PopupDialogController;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
/** /**
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated * This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
* with a JavaFX Pane to insert itself into. * with a JavaFX Pane to insert itself into.
*/ */
public class GameClient { public class GameClient {
private Pane holderPane;
private ClientToServerThread socketThread; private ClientToServerThread socketThread;
private MainServerThread server; private MainServerThread server;
@@ -83,10 +73,8 @@ public class GameClient {
/** /**
* Create an instance of the game client. Does not do anything until run with runAsClient() * Create an instance of the game client. Does not do anything until run with runAsClient()
* runAsHost(). * runAsHost().
* @param holder The JavaFX Pane that the visual elements for the race will be inserted into.
*/ */
public GameClient(Pane holder) { public GameClient() {
this.holderPane = holder;
this.gameKeyBind = GameKeyBind.getInstance(); this.gameKeyBind = GameKeyBind.getInstance();
} }
@@ -124,10 +112,7 @@ public class GameClient {
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName()); ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName()); ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
getServerThread().setConnectionErrorListener((eMessage) -> { getServerThread().setConnectionErrorListener((eMessage) -> ViewManager.getInstance().showErrorSnackBar(eMessage));
ViewManager.getInstance().showErrorSnackBar(eMessage);
//destroyClientToServerThread();
});
this.lobbyController = ViewManager.getInstance().goToLobby(true); this.lobbyController = ViewManager.getInstance().goToLobby(true);
@@ -138,18 +123,11 @@ public class GameClient {
return true; return true;
} }
private void destroyClientToServerThread() {
socketThread.closeSocket();
socketThread = null;
}
/** /**
* Connect to a game as the host at the given address and starts the visualiser. * Connect to a game as the host at the given address and starts the visualiser.
* @param ipAddress IP to connect to.
* @param portNumber Port to connect to.
*/ */
public ServerDescription runAsHost( public ServerDescription runAsHost(
String ipAddress, Integer portNumber, String serverName, Integer maxPlayers, String race, String serverName, Integer maxPlayers, String race,
Integer numLegs, Boolean tokensEnabled Integer numLegs, Boolean tokensEnabled
) { ) {
XMLGenerator.setDefaultRaceName(serverName); XMLGenerator.setDefaultRaceName(serverName);
@@ -165,7 +143,7 @@ public class GameClient {
} }
try { try {
startClientToServerThread(ipAddress, server.getPortNumber()); startClientToServerThread("localhost", server.getPortNumber());
} catch (IOException e) { } catch (IOException e) {
showConnectionError("Cannot connect to server as host"); showConnectionError("Cannot connect to server as host");
} }
@@ -202,7 +180,8 @@ public class GameClient {
lobbyController.setPortNumber(""+server.getPortNumber()); lobbyController.setPortNumber(""+server.getPortNumber());
ViewManager.getInstance().setPlayerList(clientLobbyList); ViewManager.getInstance().setPlayerList(clientLobbyList);
return new ServerDescription(serverName, regattaData.getCourseName(), GameState.getNumberOfPlayers(), GameState.getCapacity(), ipAddress, server.getPortNumber()); return new ServerDescription(serverName, regattaData.getCourseName(), GameState.getNumberOfPlayers(), GameState.getCapacity(),
"localhost", server.getPortNumber());
} }
private void tearDownConnection() { private void tearDownConnection() {
@@ -305,10 +284,12 @@ public class GameClient {
case CHATTER_TEXT: case CHATTER_TEXT:
Pair<Integer, String> playerIdMessagePair = StreamParser Pair<Integer, String> playerIdMessagePair = StreamParser
.extractChatterText(packet); .extractChatterText(packet);
raceView.updateChatHistory( if (playerIdMessagePair != null) {
allBoatsMap.get(playerIdMessagePair.getKey()).getColour(), raceView.updateChatHistory(
playerIdMessagePair.getValue() allBoatsMap.get(playerIdMessagePair.getKey()).getColour(),
); playerIdMessagePair.getValue()
);
}
} }
} }
} }
@@ -325,6 +306,7 @@ public class GameClient {
formatAndSendChatMessage(raceView.readChatInput()); formatAndSendChatMessage(raceView.readChatInput());
} }
}); });
gameKeyBind.toggleTurningMode();
sendToggleTurningModePacket(); // notify the server about player's steering mode sendToggleTurningModePacket(); // notify the server about player's steering mode
} }
} }
@@ -344,8 +326,6 @@ public class GameClient {
positionData.getLon(), positionData.getHeading(), positionData.getLon(), positionData.getHeading(),
positionData.getGroundSpeed()); positionData.getGroundSpeed());
} }
} else if (positionData.getType() == DeviceType.MARK_TYPE) {
//CompoundMark mark = courseData.getCompoundMarks().get(positionData.getDeviceId());
} }
} }
@@ -383,21 +363,17 @@ public class GameClient {
ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]); ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]);
clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]); clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
clientYacht.setEstimateTimeAtFinish(boatData[2]); clientYacht.setEstimateTimeAtFinish(boatData[2]);
// int legNumber = (int) boatData[3];
clientYacht.setBoatStatus((int) boatData[4]); clientYacht.setBoatStatus((int) boatData[4]);
// if (legNumber != clientYacht.getLegNumber()) {
// clientYacht.setLegNumber(legNumber);
// }
} }
if (raceFinished) { if (raceFinished && !raceState.getRaceFinished()) {
raceViewController.showFinishDialog(finishedBoats); raceState.setRaceFinished();
Sounds.playFinishSound(); Sounds.playFinishSound();
close(); raceViewController.showFinishDialog(finishedBoats);
ViewManager.getInstance().getGameClient().stopGame(); // close();
// ViewManager.getInstance().getGameClient().stopGame();
//loadFinishScreenView(); //loadFinishScreenView();
} }
raceState.setRaceFinished();
} }
} }
@@ -408,10 +384,6 @@ public class GameClient {
} }
} }
private void close() {
socketThread.setSocketToClose();
}
/** /**
* Handle the key-pressed event from the text field. * Handle the key-pressed event from the text field.
* @param e The key event triggering this call * @param e The key event triggering this call
@@ -538,10 +510,6 @@ public class GameClient {
return socketThread; return socketThread;
} }
public List<String> getPlayerNames(){
return Collections.unmodifiableList(clientLobbyList.sorted());
}
public void stopGame() { public void stopGame() {
GameState.setCurrentStage(GameStages.CANCELLED); GameState.setCurrentStage(GameStages.CANCELLED);
if (server != null) server.terminate(); if (server != null) server.terminate();
@@ -51,7 +51,7 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
* Collection of animated3D assets that displays a race. * Collection of animated3D assets that displays a race.
*/ */
public class GameView3D extends GameView{ public class GameView3D extends GameView {
private final double FOV = 60; private final double FOV = 60;
private final double DEFAULT_CAMERA_X = 0; private final double DEFAULT_CAMERA_X = 0;
@@ -350,18 +350,19 @@ public class GameView3D extends GameView{
for (ObservableValue o : Arrays for (ObservableValue o : Arrays
.asList(playerBoat.layoutXProperty(), playerBoat.layoutXProperty())) { .asList(playerBoat.layoutXProperty(), playerBoat.layoutXProperty())) {
o.addListener((obs, oldVal, newVal) -> { o.addListener((obs, oldVal, newVal) -> {
if (playerYacht.getLegNumber() < course.size()) {
List<Mark> marks = course.get(playerYacht.getLegNumber()).getMarks();
Point2D midPoint = new Point2D(0, 0);
if (marks.size() == 1) {
midPoint = scaledPoint.findScaledXY(marks.get(0));
} else if (marks.size() == 2) {
midPoint = (scaledPoint.findScaledXY(marks.get(0)))
.midpoint(scaledPoint.findScaledXY(marks.get(1)));
}
List<Mark> marks = course.get(playerYacht.getLegNumber()).getMarks(); if (midPoint != null) {
Point2D midPoint = new Point2D(0, 0); playerBoat.updateMarkIndicator(midPoint);
if (marks.size() == 1) { }
midPoint = scaledPoint.findScaledXY(marks.get(0));
} else if (marks.size() == 2) {
midPoint = (scaledPoint.findScaledXY(marks.get(0)))
.midpoint(scaledPoint.findScaledXY(marks.get(1)));
}
if (midPoint != null) {
playerBoat.updateMarkIndicator(midPoint);
} }
}); });
@@ -35,7 +35,7 @@ public class MapMaker {
private XMLGenerator xmlGenerator = new XMLGenerator(); private XMLGenerator xmlGenerator = new XMLGenerator();
private List<String> maps = new ArrayList<>( private List<String> maps = new ArrayList<>(
Arrays.asList("default.xml", "horseshoe.xml", "madagascar.xml", "loop.xml")); Arrays.asList("default.xml", "horseshoe.xml", "loop.xml", "madagascar.xml"));
public static MapMaker getInstance() { public static MapMaker getInstance() {
if (instance == null) { if (instance == null) {
@@ -108,10 +108,6 @@ public class MapMaker {
return mapPreviews.get(index).getAssets(); return mapPreviews.get(index).getAssets();
} }
public RaceXMLData getCurrentRace() {
return races.get(index);
}
public RegattaXMLData getCurrentRegatta() { public RegattaXMLData getCurrentRegatta() {
return regattas.get(index); return regattas.get(index);
} }
@@ -29,7 +29,7 @@ import seng302.visualiser.fxObjects.assets_2D.Marker2D;
public class MapPreview extends GameView { public class MapPreview extends GameView {
private Polygon raceBorder = new CourseBoundary(); private Polygon raceBorder = new CourseBoundary();
private Map<Mark, Marker2D> markerObjects; protected Map<Mark, Marker2D> markerObjects;
public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) { public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) {
this.compoundMarks = marks; this.compoundMarks = marks;
@@ -0,0 +1,86 @@
package seng302.visualiser;
import java.util.HashMap;
import java.util.List;
import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate;
import seng302.model.ClientYacht;
import seng302.model.Limit;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner;
import seng302.model.mark.Mark;
import seng302.utilities.Sounds;
/**
* Class converts a map preview to a minimap by adding boats.
*/
public class MiniMap extends MapPreview {
private HashMap<ClientYacht, Polygon> boatIcons = new HashMap<>();
private Polygon playerBoat;
private double playerRotation;
private List<ClientYacht> boats;
private ClientYacht player;
public MiniMap (List<CompoundMark> marks, List<Corner> course, List<Limit> border, List<ClientYacht> boats, ClientYacht player) {
super(marks, course, border);
this.boats = boats;
this.player = player;
setBoats(boats);
player.addMarkRoundingListener(this::updateMarkArrows);
}
public void setBoats(List<ClientYacht> yachts) {
for (ClientYacht yacht : yachts) {
Polygon boatIcon = new Polygon(0, -3.5, 3.5, 3.5, -3.5, 3.5);
boatIcon.setStroke(Color.BLACK);
boatIcon.setFill(Color.GRAY);
boatIcon.setFill(yacht.getColour());
boatIcon.setFill(yacht.getColour());
boatIcons.put(yacht, boatIcon);
boatIcon.getTransforms().add(new Rotate(0));
yacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
Platform.runLater(() -> {
Polygon bi = boatIcons.get(boat);
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
bi.setLayoutX(p2d.getX());
bi.setLayoutY(p2d.getY());
((Rotate) bi.getTransforms().get(0)).setAngle(heading);
});
});
}
Platform.runLater(() -> {
gameObjects.getChildren().addAll(boatIcons.values());
});
}
private void updateMarkArrows (ClientYacht yacht, int legNumber) {
CompoundMark compoundMark;
if (legNumber - 1 >= 0) {
Sounds.playMarkRoundingSound();
compoundMark = course.get(legNumber-1);
for (Mark mark : compoundMark.getMarks()) {
markerObjects.get(mark).showNextExitArrow();
}
}
CompoundMark nextMark = null;
if (legNumber < course.size() - 1) {
Sounds.playMarkRoundingSound();
nextMark = course.get(legNumber);
for (Mark mark : nextMark.getMarks()) {
markerObjects.get(mark).showNextEnterArrow();
}
}
if (legNumber - 2 >= 0) {
CompoundMark lastMark = course.get(Math.max(0, legNumber - 2));
if (lastMark != nextMark) {
for (Mark mark : lastMark.getMarks()) {
markerObjects.get(mark).hideAllArrows();
}
}
}
}
}
@@ -1,17 +1,17 @@
package seng302.visualiser; package seng302.visualiser;
import seng302.gameServer.ServerAdvertiser; import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
import seng302.gameServer.ServerDescription;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import javax.jmdns.JmDNS; import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent; import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceListener; import javax.jmdns.ServiceListener;
import javax.jmdns.impl.JmDNSImpl; import seng302.gameServer.ServerAdvertiser;
import java.io.IOException; import seng302.gameServer.ServerDescription;
import java.net.InetAddress;
import java.util.*;
import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
/** /**
* Listens for servers on the local network * Listens for servers on the local network
@@ -58,7 +58,7 @@ public class ServerListener{
servers.remove(toRemove); servers.remove(toRemove);
} }
delegate.serverRemoved(new ArrayList<ServerDescription>(servers)); delegate.serverRemoved(new ArrayList<>(servers));
// Get all other servers with the same name to respond if they are up // Get all other servers with the same name to respond if they are up
jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverName); jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverName);
@@ -94,13 +94,6 @@ public class ServerListener{
listener = new GameServeMonitor(); listener = new GameServeMonitor();
jmdns.addServiceListener(ServerAdvertiser.SERVICE_TYPE, listener); jmdns.addServiceListener(ServerAdvertiser.SERVICE_TYPE, listener);
/*new Timer().schedule(new TimerTask() {
@Override
public void run() {
refresh();
}
}, 50, SERVICE_REFRESH_INTERVAL);*/
} }
public static ServerListener getInstance() throws IOException { public static ServerListener getInstance() throws IOException {
@@ -134,7 +127,7 @@ public class ServerListener{
for (ServerDescription server : servers){ for (ServerDescription server : servers){
if (server.serverShouldBeRemoved()){ if (server.serverShouldBeRemoved()){
listener.servers.remove(server); listener.servers.remove(server);
delegate.serverRemoved(new ArrayList<ServerDescription>(listener.servers)); delegate.serverRemoved(new ArrayList<>(listener.servers));
} }
} }
@@ -1,97 +0,0 @@
package seng302.visualiser.controllers;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import seng302.model.ClientYacht;
import seng302.utilities.Sounds;
public class FinishScreenViewController implements Initializable {
@FXML
private GridPane finishScreenGridPane;
@FXML
private TableView<ClientYacht> finishOrderTable;
@FXML
private TableColumn<ClientYacht, String> posCol;
@FXML
private TableColumn<ClientYacht, String> boatNameCol;
@FXML
private TableColumn<ClientYacht, String> shortNameCol;
@FXML
private TableColumn<ClientYacht, String> countryCol;
ObservableList<ClientYacht> data = FXCollections.observableArrayList();
@Override
public void initialize(URL location, ResourceBundle resources) {
finishScreenGridPane.getStylesheets()
.add(getClass().getResource("/css/Master.css").toString());
finishOrderTable.getStylesheets().add(getClass().getResource("/css/Master.css").toString());
// set up data for table
finishOrderTable.setItems(data);
// setting table col data
posCol.setCellValueFactory(
new PropertyValueFactory<>("position")
);
boatNameCol.setCellValueFactory(
new PropertyValueFactory<>("boatName")
);
shortNameCol.setCellValueFactory(
new PropertyValueFactory<>("shortName")
);
countryCol.setCellValueFactory(
new PropertyValueFactory<>("country")
);
finishOrderTable.refresh();
}
public void setFinishers(Collection<ClientYacht> participants) {
List<ClientYacht> sorted = new ArrayList<>(participants);
sorted.sort(Comparator.comparingInt(ClientYacht::getPlacing));
finishOrderTable.getItems().setAll(sorted);
}
private void setContentPane(String jfxUrl) {
try {
// get the main controller anchor pane (FinishView -> MainView)
AnchorPane contentPane = (AnchorPane) finishScreenGridPane.getParent();
contentPane.getChildren().removeAll();
contentPane.getChildren().clear();
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
contentPane.getChildren()
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
} catch (javafx.fxml.LoadException e) {
System.out.println("[Controller] FXML load exception");
} catch (IOException e) {
System.out.println("[Controller] IO exception");
}
}
public void switchToStartScreenView() {
Sounds.playButtonClick();
setContentPane("/views/StartScreenView.fxml");
}
public void playButtonHoverSound(MouseEvent mouseEvent) {
Sounds.playHoverSound();
}
}
@@ -4,67 +4,38 @@ import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialog;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import javafx.animation.RotateTransition; import javafx.animation.RotateTransition;
import javafx.animation.Timeline;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.SubScene; import javafx.scene.SubScene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint; import javafx.scene.paint.Paint;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polyline;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration; import javafx.util.Duration;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.RaceState; import seng302.model.RaceState;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.token.TokenType; import seng302.model.token.TokenType;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.GameView3D; import seng302.visualiser.GameView3D;
import seng302.visualiser.controllers.annotations.ImportantAnnotationController; import seng302.visualiser.MiniMap;
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
import seng302.visualiser.controllers.dialogs.FinishDialogController; import seng302.visualiser.controllers.dialogs.FinishDialogController;
import seng302.visualiser.fxObjects.ChatHistory; import seng302.visualiser.fxObjects.ChatHistory;
import seng302.visualiser.fxObjects.assets_2D.WindArrow;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
/** /**
* Controller class that manages the display of a race * Controller class that manages the display of a race
*/ */
public class RaceViewController extends Thread implements ImportantAnnotationDelegate { public class RaceViewController extends Thread {
private final int CHAT_LIMIT = 128; private final int CHAT_LIMIT = 128;
private static final Double ICON_BLINK_TIMEOUT_RATIO = 0.6; private static final Double ICON_BLINK_TIMEOUT_RATIO = 0.6;
@@ -75,39 +46,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
@FXML @FXML
private ImageView loadingScreen; private ImageView loadingScreen;
@FXML @FXML
private Pane basePane;
@FXML
private JFXButton chatSend; private JFXButton chatSend;
@FXML @FXML
private Pane chatHistoryHolder; private Pane chatHistoryHolder;
@FXML @FXML
private TextField chatInput; private TextField chatInput;
@FXML @FXML
private LineChart<String, Double> raceSparkLine;
@FXML
private NumberAxis sparklineYAxis;
@FXML
private VBox positionVbox;
@FXML
private CheckBox toggleFps;
@FXML
private Label timerLabel; private Label timerLabel;
@FXML @FXML
private StackPane contentStackPane; private StackPane contentStackPane;
private GridPane contentGridPane;
@FXML @FXML
private AnchorPane rvAnchorPane; private Pane miniMapPane;
@FXML
private AnchorPane windArrowHolder;
@FXML
private Slider annotationSlider;
@FXML
private Button selectAnnotationBtn;
@FXML
private ComboBox<ClientYacht> yachtSelectionComboBox;
@FXML
private Text fpsDisplay;
@FXML @FXML
private ImageView windImageView; private ImageView windImageView;
@FXML @FXML
@@ -118,33 +67,24 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private Label positionLabel, boatSpeedLabel, boatHeadingLabel; private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
@FXML @FXML
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon; private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon;
@FXML
private JFXButton miniMapButton;
//Race Data
private Map<Integer, ClientYacht> participants;
private Map<Integer, CompoundMark> markers;
private RaceXMLData courseData;
private GameView3D gameView; private GameView3D gameView;
private RaceState raceState; private RaceState raceState;
private ChatHistory chatHistory; private ChatHistory chatHistory;
private Timeline timerTimeline;
private Timer timer = new Timer(); private Timer timer = new Timer();
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
private ImportantAnnotationsState importantAnnotations;
private Polyline windArrow = new WindArrow(Color.LIGHTGRAY);
private ObservableList<ClientYacht> selectionComboBoxList = FXCollections.observableArrayList();
private ClientYacht player; private ClientYacht player;
private JFXDialog finishScreenDialog; private JFXDialog finishScreenDialog;
private FinishDialogController finishDialogController; private FinishDialogController finishDialogController;
//Icon stuff
private Timer blinkingTimer = new Timer(); private Timer blinkingTimer = new Timer();
private ImageView iconToDisplay; private ImageView iconToDisplay;
private Double lastWindDirection; private Double lastWindDirection;
private MiniMap miniMap;
public void initialize() { public void initialize() {
miniMapPane.setVisible(false);
miniMapButton.setVisible(false);
contentStackPane.setVisible(false); contentStackPane.setVisible(false);
Image loadingImage = new Image("PP.png"); Image loadingImage = new Image("PP.png");
loadingScreen.setImage(loadingImage); loadingScreen.setImage(loadingImage);
@@ -204,13 +144,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
public void showView(){ public void showView(){
loadingScreenPane.setVisible(false); loadingScreenPane.setVisible(false);
contentStackPane.setVisible(true); contentStackPane.setVisible(true);
miniMapPane.setVisible(true);
Platform.runLater(new Runnable() { miniMapButton.setVisible(true);
@Override Platform.runLater(() -> contentStackPane.requestFocus());
public void run() {
contentStackPane.requestFocus();
}
});
} }
/** /**
@@ -238,31 +174,36 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState, Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState,
ClientYacht player) { ClientYacht player) {
this.participants = participants;
this.courseData = raceData;
this.markers = raceData.getCompoundMarks();
this.raceState = raceState; this.raceState = raceState;
this.player = player; this.player = player;
raceState.getPlayerPositions().addListener((ListChangeListener<ClientYacht>) c -> {
while (c.next()) {
if (c.wasPermutated()) {
updateOrder(raceState.getPlayerPositions());
}
}
});
player.addPowerUpListener(this::displayPowerUpIcon); player.addPowerUpListener(this::displayPowerUpIcon);
player.addPowerDownListener(this::removeIcon); player.addPowerDownListener(this::removeIcon);
updateOrder(raceState.getPlayerPositions());
gameView = new GameView3D(); gameView = new GameView3D();
miniMap = new MiniMap(
new ArrayList<>(raceData.getCompoundMarks().values()),
raceData.getMarkSequence(), raceData.getCourseLimit(),
new ArrayList<>(participants.values()), player
);
miniMapButton.setOnMouseClicked((event) -> {
if (miniMapPane.visibleProperty().get()) {
miniMapPane.setVisible(false);
miniMapButton.setText("");
} else {
miniMapPane.setVisible(true);
miniMapButton.setText("");
}
});
Platform.runLater(() -> { Platform.runLater(() -> {
contentStackPane.getChildren().add(0, gameView.getAssets()); contentStackPane.getChildren().add(0, gameView.getAssets());
((SubScene) gameView.getAssets()).widthProperty() ((SubScene) gameView.getAssets()).widthProperty()
.bind(ViewManager.getInstance().getStage().widthProperty()); .bind(ViewManager.getInstance().getStage().widthProperty());
((SubScene) gameView.getAssets()).heightProperty() ((SubScene) gameView.getAssets()).heightProperty()
.bind(ViewManager.getInstance().getStage().heightProperty()); .bind(ViewManager.getInstance().getStage().heightProperty());
miniMapPane.getChildren().add(miniMap.getAssets());
}); });
gameView.setBoats(new ArrayList<>(participants.values())); gameView.setBoats(new ArrayList<>(participants.values()));
gameView.updateBorder(raceData.getCourseLimit()); gameView.updateBorder(raceData.getCourseLimit());
@@ -342,7 +283,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
} }
public void removeIcon(ClientYacht yacht) { private void removeIcon(ClientYacht yacht) {
if (yacht == player) { if (yacht == player) {
blinkingTimer.cancel(); blinkingTimer.cancel();
iconToDisplay.setVisible(false); iconToDisplay.setVisible(false);
@@ -350,45 +291,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
} }
/**
* The important annotations have been changed, update this view
*
* @param importantAnnotationsState The current state of the selected annotations
*/
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
this.importantAnnotations = importantAnnotationsState;
setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
}
/**
* Loads the "select annotations" view in a new window
*/
private void loadSelectAnnotationView() {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
Stage stage = new Stage();
// Set controller
ImportantAnnotationController controller = new ImportantAnnotationController(
this, stage
);
fxmlLoader.setController(controller);
// Load FXML and set CSS
fxmlLoader.setLocation(
getClass().getResource("/views/importantAnnotationSelectView.fxml")
);
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
stage.show();
controller.loadState(importantAnnotations);
} catch (IOException e) {
e.printStackTrace();
}
}
/** /**
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht * Initialises a timer which updates elements of the RaceView such as wind direction, yacht
* orderings etc.. which are dependent on the info from the stream parser constantly. * orderings etc.. which are dependent on the info from the stream parser constantly.
@@ -406,35 +308,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}, 0, 1000); }, 0, 1000);
} }
/**
* Iterates over all corners until ones SeqID matches with the yachts current leg number.
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
* Returns null if no next mark found.
* @param bg The BoatGroup to find the next mark of
* @return The next Mark or null if none found
*/
private Mark getNextMark(BoatObject bg) {
// TODO: 1/08/17 Move to GameView
//
// Integer legNumber = bg.getClientYacht().getLegNumber();
// List<Corner> markSequence = courseData.getMarkSequence();
//
// if (legNumber == 0) {
// return null;
// } else if (legNumber == markSequence.size() - 1) {
// return null;
// }
//
// for (Corner corner : markSequence) {
// if (legNumber + 2 == corner.getSeqID()) {
// return courseData.getCompoundMarks().get(corner.getCompoundMarkID());
// }
// }
// return null;
return null;
}
/** /**
* Updates the wind direction arrow and text as from info from the StreamParser * Updates the wind direction arrow and text as from info from the StreamParser
* @param direction the from north angle of the wind. * @param direction the from north angle of the wind.
@@ -516,226 +389,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
boatHeadingLabel.setText(String.format("Boat Heading:\n%.1f°", player.getHeading())); boatHeadingLabel.setText(String.format("Boat Heading:\n%.1f°", player.getHeading()));
} }
/**
* Updates the order of the yachts as from the StreamParser and sets them in the yacht order
* section
*/
private void updateOrder(ObservableList<ClientYacht> yachts) {
// List<Text> vboxEntries = new ArrayList<>();
//
// for (int i = 0; i < yachts.size(); i++) {
//// System.out.println("yacht == null " + String.valueOf(yacht == null));
// if (yachts.get(i).getBoatStatus() == BoatStatus.FINISHED
// .getCode()) { // 3 is finish status
// Text textToAdd = new Text(i + 1 + ". " +
// yachts.get(i).getShortName() + " (Finished)");
// textToAdd.setFill(Paint.valueOf("#d3d3d3"));
// vboxEntries.add(textToAdd);
//
// } else {
// Text textToAdd = new Text(i + 1 + ". " +
// yachts.get(i).getShortName() + " ");
// textToAdd.setFill(Paint.valueOf("#d3d3d3"));
// textToAdd.setStyle("");
// vboxEntries.add(textToAdd);
// }
// }
// Platform.runLater(() ->
// positionVbox.getChildren().setAll(vboxEntries)
// );
}
private void updateLaylines(BoatObject bg) {
// TODO: 1/08/17 move to GameView
//
// Mark nextMark = getNextMark(bg);
// Boolean isUpwind = null;
// // Can only calc leg direction if there is a next mark and it is a gate mark
// if (nextMark != null) {
// if (nextMark instanceof GateMark) {
// if (bg.isUpwindLeg(gameViewController, nextMark)) {
// isUpwind = true;
// } else {
// isUpwind = false;
// }
//
// for(MarkObject mg : gameViewController.getMarkGroups()) {
//
// mg.removeLaylines();
//
// if (mg.getMainMark().getId() == nextMark.getId()) {
//
// SingleMark singleMark1 = ((GateMark) nextMark).getSingleMark1();
// SingleMark singleMark2 = ((GateMark) nextMark).getSingleMark2();
// Point2D markPoint1 = gameViewController
// .findScaledXY(singleMark1.getLatitude(), singleMark1.getLongitude());
// Point2D markPoint2 = gameViewController
// .findScaledXY(singleMark2.getLatitude(), singleMark2.getLongitude());
// HashMap<Double, Double> angleAndSpeed;
// if (isUpwind) {
// angleAndSpeed = PolarTable.getOptimalUpwindVMG(StreamParser.getWindSpeed());
// } else {
// angleAndSpeed = PolarTable.getOptimalDownwindVMG(StreamParser.getWindSpeed());
// }
//
// Double resultingAngle = angleAndSpeed.keySet().iterator().next();
//
//
// Point2D yachtCurrentPos = new Point2D(bg.getBoatLayoutX(), bg.getBoatLayoutY());
// Point2D gateMidPoint = markPoint1.midpoint(markPoint2);
// Integer lineFuncResult = GeoUtility.lineFunction(yachtCurrentPos, gateMidPoint, markPoint2);
// Line rightLayline = new Line();
// Line leftLayline = new Line();
// if (lineFuncResult == 1) {
// rightLayline = makeRightLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
// leftLayline = makeLeftLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
// } else if (lineFuncResult == -1) {
// rightLayline = makeRightLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
// leftLayline = makeLeftLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
// }
//
// leftLayline.setStrokeWidth(0.5);
// leftLayline.setStroke(bg.getBoat().getColour());
//
// rightLayline.setStrokeWidth(0.5);
// rightLayline.setStroke(bg.getBoat().getColour());
//
// bg.setLaylines(leftLayline, rightLayline);
// mg.addLaylines(leftLayline, rightLayline);
//
// }
// }
// }
// }
}
private Point2D getPointRotation(Point2D ref, Double distance, Double angle) {
Double newX = ref.getX() + (ref.getX() + distance - ref.getX()) * Math.cos(angle)
- (ref.getY() + distance - ref.getY()) * Math.sin(angle);
Double newY = ref.getY() + (ref.getX() + distance - ref.getX()) * Math.sin(angle)
+ (ref.getY() + distance - ref.getY()) * Math.cos(angle);
return new Point2D(newX, newY);
}
public Line makeLeftLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle);
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
return line;
}
public Line makeRightLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle - layLineAngle);
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
return line;
}
/**
* Initialised the combo box with any yachts currently in the race and adds the required listener
* for the combobox to take action upon selection
*/
private void initialiseBoatSelectionComboBox() {
// yachtSelectionComboBox.setItems(
// FXCollections.observableArrayList(participants.values())
// );
// //Null check is if the listener is fired but nothing selected
// yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
// if (selectedBoat != null) {
// gameView.selectBoat(selectedBoat);
// }
// });
//TODO uncomment out
// selectionComboBoxList.setAll(participants.values());
// yachtSelectionComboBox.setItems(selectionComboBoxList);
// yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
// if (selectedBoat != null) {
// gameView.selectBoat(selectedBoat);
// }
// });
}
/**
* Display the list of yachts in the order they finished the race
*/
private void loadRaceResultView() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
try {
contentGridPane.getChildren().removeAll();
contentGridPane.getChildren().clear();
contentGridPane.getChildren().addAll((Pane) loader.load());
} catch (javafx.fxml.LoadException e) {
System.err.println(e.getCause().toString());
} catch (IOException e) {
System.err.println(e.toString());
}
}
private String getMillisToFormattedTime(long milliseconds) {
return String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(milliseconds),
TimeUnit.MILLISECONDS.toMinutes(milliseconds) % 60, //Modulus 60 minutes per hour
TimeUnit.MILLISECONDS.toSeconds(milliseconds) % 60 //Modulus 60 seconds per minute
);
}
private void setAnnotations(Integer annotationLevel) {
// switch (annotationLevel) {
// // No Annotations
// case 0:
// gameView.setAnnotationVisibilities(
// false, false, false, false, false, false
// );
// break;
// // Important Annotations
// case 1:
// gameView.setAnnotationVisibilities(
// importantAnnotations.getAnnotationState(Annotation.NAME),
// importantAnnotations.getAnnotationState(Annotation.SPEED),
// importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK),
// importantAnnotations.getAnnotationState(Annotation.LEGTIME),
// importantAnnotations.getAnnotationState(Annotation.TRACK),
// importantAnnotations.getAnnotationState(Annotation.WAKE)
// );
// break;
// // All Annotations
// case 2:
// gameView.setAnnotationVisibilities(
// true, true, true, true, true, true
// );
// break;
// }
}
/**
* Sets all the annotations of the selected yacht to be visible and all others to be hidden
*
* @param yacht The yacht for which we want to view all annotations
*/
private void setSelectedBoat(ClientYacht yacht) {
// for (BoatObject bg : gameViewController.getBoatGroups()) {
// //We need to iterate over all race groups to get the matching yacht group belonging to this yacht if we
// //are to toggle its annotations, there is no other backwards knowledge of a yacht to its yachtgroup.
// if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
//// updateLaylines(bg);
// bg.setIsSelected(true);
//// selectedBoat = yacht;
// } else {
// bg.setIsSelected(false);
// }
// }
}
public void updateTokens(RaceXMLData raceData) { public void updateTokens(RaceXMLData raceData) {
gameView.updateTokens(raceData.getTokens()); gameView.updateTokens(raceData.getTokens());
@@ -9,6 +9,7 @@ import javafx.scene.layout.StackPane;
import javafx.stage.Stage; import javafx.stage.Stage;
/** /**
* The pre loading screen before launch the start view
* Created by Kusal on 26-Sep-17. * Created by Kusal on 26-Sep-17.
*/ */
public class SplashScreenController implements Initializable{ public class SplashScreenController implements Initializable{
@@ -26,17 +27,14 @@ public class SplashScreenController implements Initializable{
public void run(){ public void run(){
try { try {
Thread.sleep(3000); Thread.sleep(3000);
Platform.runLater(new Runnable() { Platform.runLater(() -> {
@Override try {
public void run() { Stage stage = new Stage();
try { ViewManager.getInstance().initialStartView(stage);
Stage stage = new Stage(); } catch (Exception e) {
ViewManager.getInstance().initialStartView(stage); e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
rootPane.getScene().getWindow().hide();
} }
rootPane.getScene().getWindow().hide();
}); });
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
@@ -79,7 +79,7 @@ public class ViewManager {
decorator.applyCss(); decorator.applyCss();
decorator.getStylesheets() decorator.getStylesheets()
.add(getClass().getResource("/css/Master.css").toExternalForm()); .add(getClass().getResource("/css/Master.css").toExternalForm());
gameClient = new GameClient(decorator); gameClient = new GameClient();
setDecorator(decorator); setDecorator(decorator);
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png"))); stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
@@ -404,7 +404,9 @@ public class ViewManager {
.add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm()); .add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm());
JFXSnackbar bar = new JFXSnackbar(decorator); JFXSnackbar bar = new JFXSnackbar(decorator);
bar.enqueue(new JFXSnackbar.SnackbarEvent(msg)); Platform.runLater(() -> {
bar.enqueue(new JFXSnackbar.SnackbarEvent(msg));
});
} }
public Stage getStage() { public Stage getStage() {
@@ -116,6 +116,7 @@ public class ServerCreationController implements Initializable {
private void createServer() { private void createServer() {
ServerDescription serverDescription = ViewManager.getInstance().getGameClient() ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
.runAsHost("localhost", 0, serverName.getText(), (int) maxPlayersSlider .runAsHost("localhost", 0, serverName.getText(), (int) maxPlayersSlider
.runAsHost(serverName.getText(), (int) maxPlayersSlider
.getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected()); .getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected());
if (serverDescription == null){ if (serverDescription == null){
@@ -29,11 +29,11 @@ public class MarkArrowFactory {
STARBOARD, STARBOARD,
} }
public static final double MARK_ARROW_SEPARATION = 15; public static final double MARK_ARROW_SEPARATION = 8;
public static final double ARROW_LENGTH = 75; public static final double ARROW_LENGTH = 20;
public static final double ARROW_HEAD_DEPTH = 10; public static final double ARROW_HEAD_DEPTH = 5;
public static final double ARROW_HEAD_WIDTH = 6; public static final double ARROW_HEAD_WIDTH = 3;
public static final double STROKE_WIDTH = 3; public static final double STROKE_WIDTH = 1;
public static Model constructEntryArrow3D ( public static Model constructEntryArrow3D (
RoundingSide roundingSide, double angle, ModelType type) { RoundingSide roundingSide, double angle, ModelType type) {
@@ -106,7 +106,7 @@ public class MarkArrowFactory {
Arc roundSection = new Arc( Arc roundSection = new Arc(
0, 0, MARK_ARROW_SEPARATION, MARK_ARROW_SEPARATION, 0, 0, MARK_ARROW_SEPARATION, MARK_ARROW_SEPARATION,
//Where to start drawing arc from //Where to start drawing arc from
(roundingSide == RoundingSide.PORT ? 0 : angleOfEntry), (roundingSide == RoundingSide.PORT ? 180 + angleOfEntry : angleOfEntry),
//Which way to go around the mark. (clockwise vs anticlockwise) //Which way to go around the mark. (clockwise vs anticlockwise)
roundingSide == RoundingSide.PORT ? Math.abs(angleOfExit - angleOfEntry) : -Math.abs(angleOfEntry - angleOfExit) roundingSide == RoundingSide.PORT ? Math.abs(angleOfExit - angleOfEntry) : -Math.abs(angleOfEntry - angleOfExit)
); );
@@ -1,230 +0,0 @@
package seng302.visualiser.fxObjects.assets_2D;
import java.util.HashMap;
import java.util.Map;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
/**
* Grouping of string objects over a semi transparent background.
*/
public class AnnotationBox extends Group {
@FunctionalInterface
public interface AnnotationFormatter<T> {
String transformString (T input);
}
/**
* Class stores a text object and relationship for updating the text object if needed
*
* @param <T> The type of observable value passed to the annotation, if there is one.
*/
public class Annotation<T> {
private Text text;
private ObservableValue<T> source;
private AnnotationFormatter<T> format;
/**
* Constructor for observing annotation
* @param textObject the javaFX text object the annotation is displayed in
* @param source observable value that the annotation is taken from
* @param formatter interface describing how to format the source data if needed
*/
public Annotation (Text textObject, ObservableValue<T> source, AnnotationFormatter<T> formatter) {
this.text = textObject;
this.source = source;
this.format = formatter;
source.addListener((obs, oldVal, newVal) ->
Platform.runLater(() -> text.setText(format.transformString(newVal)))
);
}
/**
* Constructor for a static annotation
* @param textObject the javaFX text object the annotation is displayed in
* @param annotationText the static value of the test object
*/
public Annotation (Text textObject, String annotationText) {
textObject.setText(annotationText);
text = textObject;
}
private Text getText () {
return text;
}
}
//Text offset constants
private static final double X_OFFSET_TEXT = 20d;
private static final double Y_OFFSET_TEXT_INIT = -35d;
private static final double Y_OFFSET_PER_TEXT = 12d;
//Background constants
private static final double TEXT_BUFFER = 3;
private static final double BACKGROUND_X = X_OFFSET_TEXT - TEXT_BUFFER;
private static final double BACKGROUND_Y = Y_OFFSET_TEXT_INIT - TEXT_BUFFER;
private static final double BACKGROUND_H_PER_TEXT = 9.5d;
private static final double BACKGROUND_ARC_SIZE = 10;
private int visibleAnnotations = 0;
private double backgroundWidth = 145d;
private Rectangle background = new Rectangle();
private Paint theme = Color.BLACK;
private Map<String, Annotation> annotationsByName = new HashMap<>();
/**
* Creates an empty annotation box. The box is offset from (0,0) by (17, -38).
*/
public AnnotationBox() {
this.setCache(true);
background.setX(BACKGROUND_X);
background.setY(BACKGROUND_Y);
background.setWidth(backgroundWidth);
background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * 4);
background.setArcHeight(BACKGROUND_ARC_SIZE);
background.setArcWidth(BACKGROUND_ARC_SIZE);
background.setFill(new Color(1, 1, 1, 0.75));
background.setStroke(theme);
background.setStrokeWidth(2);
background.setCache(true);
background.setCacheHint(CacheHint.SCALE);
this.getChildren().add(background);
}
/**
* Adds an annotation to the box. Use the name to reference the annotation for removal or\
* changing visibility.
* @param annotationName the name of the annotation.
* @param annotation the annotation.
*/
public void addAnnotation (String annotationName, Annotation annotation) {
annotationsByName.put(annotationName, annotation);
Platform.runLater(() -> {
this.getChildren().add(annotation.getText());
visibleAnnotations++;
update();
});
}
/**
* Adds an annotation with a constant text.
* @param annotationName The name of the annotation. Will be used to reference it later.
* @param annotationText The desired text.
*/
public void addAnnotation (String annotationName, String annotationText) {
Text text = getTextObject();
addAnnotation(annotationName, new Annotation(text, annotationText));
}
/**
* Adds an annotation with the given name. The annotation will contain the value of the given
* ObservableValue. The formatter should return a String and takes an object of the same type as
* the ObservableValue as a parameter. The String is how you want the annotation to look.
* @param annotationName The annotation name.
* @param observable The observable value the annotation will display.
* @param formatter A formatting function for the observable value.
* @param <E> The type of ObservableValue.
*/
public <E> void addAnnotation (String annotationName, ObservableValue<E> observable,
AnnotationFormatter<E> formatter) {
Text newText = getTextObject();
addAnnotation(annotationName, new Annotation<>(newText, observable, formatter));
}
/**
* Sets the visibility of the annotation with the given name if it exists.
* @param annotationName The name of the annotation
* @param visibility the desired visibility
*/
public void setAnnotationVisibility (String annotationName, boolean visibility) {
if (annotationsByName.containsKey(annotationName)) {
Text textField = annotationsByName.get(annotationName).text;
boolean currentState = textField.visibleProperty().get();
if (visibility != currentState) {
if (visibility)
visibleAnnotations++;
else
visibleAnnotations--;
}
textField.setVisible(visibility);
update();
}
}
/**
* Removes the annotation with the given name if it exits.
* @param annotationName The name given when the annotation was created.
*/
public void removeAnnotation (String annotationName) {
if (annotationName.contains(annotationName)) {
Platform.runLater(() -> {
this.getChildren().remove(annotationsByName.remove(annotationName).getText());
visibleAnnotations--;
update();
});
annotationsByName.remove(annotationName);
}
}
/**
* Moves the annotation.
* @param x x location
* @param y y location
*/
public void setLocation (double x, double y) {
Platform.runLater(()-> this.relocate(x + BACKGROUND_X, y + BACKGROUND_Y));
}
/**
* Changes the width of the annotation box. Default is 145.
* @param width new width.
*/
public void setWidth (double width) {
backgroundWidth = width;
Platform.runLater(() -> background.setWidth(backgroundWidth));
}
private void update () {
background.setVisible(visibleAnnotations != 0);
background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * visibleAnnotations);
for (int i = 1; i <= visibleAnnotations; i++) {
Text text = (Text) this.getChildren().get(i);
if (text.visibleProperty().get()) {
text.setX(X_OFFSET_TEXT);
text.setY(Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * i);
// });
}
}
}
/**
* Returns a text object for an annotation.
* @return The text object
*/
private Text getTextObject() {
Text text = new Text();
text.setFill(theme);
text.setStrokeWidth(2);
// text.setCacheHint(CacheHint.QUALITY);
text.setCache(true);
return text;
}
/**
* Set the colour of the annotation box's border and text colour.
* @param value desired colour.
*/
public void setFill (Paint value) {
theme = value;
background.setStroke(theme);
annotationsByName.forEach((name, annotation) -> annotation.getText().setFill(theme));
}
}
@@ -28,8 +28,7 @@ public class Marker2D extends Group {
mark.setRadius(5); mark.setRadius(5);
mark.setCenterX(0); mark.setCenterX(0);
mark.setCenterY(0); mark.setCenterY(0);
Platform.runLater(() -> this.getChildren() Platform.runLater(() -> this.getChildren().add(mark));
.addAll(mark, new Group())); //Empty group placeholder or arrows.
} }
/** /**
@@ -82,13 +81,9 @@ public class Marker2D extends Group {
private void showArrow(List<Group> arrowList, int arrowListIndex) { private void showArrow(List<Group> arrowList, int arrowListIndex) {
if (arrowListIndex < arrowList.size()) { if (arrowListIndex < arrowList.size()) {
if (arrowListIndex == 1) { Platform.runLater(() ->
; this.getChildren().setAll(mark, arrowList.get(arrowListIndex))
} );
Platform.runLater(() -> {
this.getChildren().remove(1);
this.getChildren().add(arrowList.get(arrowListIndex));
});
} }
} }
@@ -16,10 +16,6 @@ public class Wake extends Group {
//The number of wakes //The number of wakes
private int numWakes = 8; private int numWakes = 8;
//The total possible difference between the first wake and the last. Increasing/Decreasing this will make wakes fan out more/less.
private final double MAX_DIFF = 75;
//Increasing/decreasing this will alter the speed that wakes converge when the heading stop changing. Anything over about 1500 may cause oscillation.
private final int UNIFICATION_SPEED = 45;
private Arc[] arcs = new Arc[numWakes]; private Arc[] arcs = new Arc[numWakes];
@@ -69,34 +65,6 @@ public class Wake extends Group {
rad += (14 / numWakes) + (velocity / 2.5); rad += (14 / numWakes) + (velocity / 2.5);
} }
}); });
// } else {
// rotations[0] = rotation;
// ((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation);
// for (int i = 1; i < numWakes; i++) {
// double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]);
// double shortestDistance = Math.atan2(
// Math.sin(wakeSeparationRad),
// Math.cos(wakeSeparationRad)
// );
// double distDeg = Math.toDegrees(shortestDistance);
// if (rotationalVelocities[i - 1] < 0.01 && rotationalVelocities[i - 1] > -0.01) {
// rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * 2 * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
//
// } else {
// if (distDeg < (MAX_DIFF / numWakes)) {
// rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
// } else
// rotationalVelocities[i] = rotationalVelocities[i - 1];
// }
// }
// }
// double rad = (14 / numWakes) + velocity;
// for (Arc arc : arcs) {
// arc.setRadiusX(rad);
// arc.setRadiusY(rad);
// rad += (14 / numWakes) + (velocity / 2.5);
// }
} }
/** /**
@@ -1,25 +0,0 @@
package seng302.visualiser.fxObjects.assets_2D;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
/**
* Created by cir27 on 5/09/17.
*/
public class WindArrow extends Polyline {
public WindArrow(Paint fill) {
this.getPoints().addAll(
-10d, 15d,
0d, 25d,
0d, -25d,
0d, 25d,
10d, 15d
);
this.setStrokeLineCap(StrokeLineCap.ROUND);
this.setStroke(fill);
this.setStrokeWidth(5);
this.setStrokeLineJoin(StrokeLineJoin.ROUND);
}
}
@@ -60,7 +60,9 @@ public class BoatModel extends Model {
*/ */
public void changeColour(Color newColour) { public void changeColour(Color newColour) {
changeColourChild(HULL_INDEX, newColour); changeColourChild(HULL_INDEX, newColour);
changeColourChild(MAST_INDEX, newColour); if (meshType != BoatMeshType.PARROT) {
changeColourChild(MAST_INDEX, newColour);
}
} }
private void changeColourChild(int index, Color newColour) { private void changeColourChild(int index, Color newColour) {
@@ -1,44 +0,0 @@
package seng302.visualiser.map;
/**
* The Boundary class represents a rectangle territorial boundary on a map. It
* contains four extremity double values(N, E, S, W). N and S are represented as
* latitudes in radians. E and W are represented as longitudes in radians.
*
* Created by Haoming on 10/5/17
*/
public class Boundary {
private double northLat, eastLng, southLat, westLng;
public Boundary(double northLat, double eastLng, double southLat, double westLng) {
this.northLat = northLat;
this.eastLng = eastLng;
this.southLat = southLat;
this.westLng = westLng;
}
double getCentreLat() {
return (northLat + southLat) / 2;
}
double getCentreLng() {
return (eastLng + westLng) / 2;
}
double getNorthLat() {
return northLat;
}
double getEastLng() {
return eastLng;
}
double getSouthLat() {
return southLat;
}
double getWestLng() {
return westLng;
}
}
@@ -1,103 +0,0 @@
package seng302.visualiser.map;
import java.net.URL;
import javafx.geometry.Point2D;
import javafx.scene.image.Image;
import javax.net.ssl.HttpsURLConnection;
import seng302.model.GeoPoint;
/**
* CanvasMap retrieves a map image with given geo boundary from Google Map server.
* By passing a rectangle like geo boundary, it returns a map image with the
* highest resolution. However, due to free quote account usage limit, the maximum
* resolution is only 1280 * 1280.
*
* Created by Haoming on 15/5/2017
*/
public class CanvasMap {
private Boundary boundary;
private long width, height; // desired image size
private int zoom;
private String KEY = "AIzaSyC-5oOShMCY5Oy_9L7guYMPUPFHDMr37wE";
public CanvasMap(Boundary boundary) {
this.boundary = boundary;
calculateOptimalMapSize();
}
public Image getMapImage() {
try {
URL url = new URL(getRequest());
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
return new Image(connection.getInputStream());
} catch (Exception e) {
System.out.println("[CanvasMap] Exception");
return null;
}
}
private String getRequest() {
StringBuilder sb = new StringBuilder();
sb.append("https://maps.googleapis.com/maps/api/staticmap?");
sb.append(String.format("center=%f,%f", boundary.getCentreLat(), boundary.getCentreLng()));
sb.append(String.format("&zoom=%d", zoom));
sb.append(String.format("&size=%dx%d&scale=2", width, height));
sb.append("&style=feature:all|element:labels|visibility:off"); // hide all labels on map
// sb.append(String.format("&markers=%f,%f", boundary.getSouthLat(), boundary.getWestLng()));
// sb.append(String.format("&key=%s", KEY));
return sb.toString();
}
private void calculateOptimalMapSize() {
for (int z = 20; z > 0; z--) {
MapSize mapSize = getMapSize(z, boundary);
zoom = z;
width = mapSize.width;
height = mapSize.height;
// if map size is valid, exit the loop as we have the highest resolution
if (mapSize.isValid()) break;
}
}
private MapSize getMapSize(int zoom, Boundary boundary) {
double scale = Math.pow(2, zoom);
GeoPoint geoSW = new GeoPoint(boundary.getSouthLat(), boundary.getWestLng());
GeoPoint geoNE = new GeoPoint(boundary.getNorthLat(), boundary.getEastLng());
Point2D pointSW = MercatorProjection.toMapPoint(geoSW);
Point2D pointNE = MercatorProjection.toMapPoint(geoNE);
return new MapSize(Math.abs(pointNE.getX() - pointSW.getX()) * scale,
Math.abs(pointNE.getY() - pointSW.getY()) * scale);
}
class MapSize {
long width, height;
MapSize(double width, double height) {
this.width = Math.round(width);
this.height = Math.round(height);
}
/**
* Map size is valid when width and height are both less than 640 pixels
* @return true if both dimensions are less than 640px
*/
boolean isValid() {
return Math.max(width, height) <= 640;
}
}
public long getWidth() {
return width;
}
public long getHeight() {
return height;
}
public int getZoom() {
return zoom;
}
}
@@ -1,55 +0,0 @@
package seng302.visualiser.map;
import javafx.geometry.Point2D;
import seng302.model.GeoPoint;
/**
* An utility class useful to convert between Geo locations and Mercator projection
* planar coordinates.
* Created by Haoming on 15/5/2017
*/
public class MercatorProjection {
private static final double MERCATOR_RANGE = 256;
private static final double pixelsPerLngDegree = MERCATOR_RANGE / 360.0;
private static final double pixelsPerLngRadian = MERCATOR_RANGE / (2 * Math.PI);
/**
* A help function keeps the value in bound between -0.9999 and 0.9999.
* @param value in bound value
* @return the value in bound
*/
private static double bound(double value) {
return Math.min(Math.max(value, -0.9999), 0.9999);
}
/**
* Projects a Geo Location (lat, lng) on a planar
* @param geo GeoPoint (lat, lng) location to be projected
* @return the projection Point2D (x, y) on planar
*/
public static Point2D toMapPoint(GeoPoint geo) {
double x, y;
Point2D origin = new Point2D(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0);
x = (origin.getX() + geo.getLng() * pixelsPerLngDegree);
// NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
// 89.189. This is about a third of a tile past the edge of the world tile.
double sinY = bound(Math.sin(Math.toRadians(geo.getLat())));
y = origin.getY() + 0.5 * Math.log((1 + sinY) / (1 - sinY)) * (-pixelsPerLngRadian);
return new Point2D(x, y);
}
/**
* Converts the planar projection (x, y) back to Geo Location (lat, lng)
* @param point Point2D (x, y) to be converted back
* @return the original Geo location converted from the given projection point
*/
public static GeoPoint toMapGeo(Point2D point) {
Point2D origin = new Point2D(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0);
double lng = (point.getX() - origin.getX()) / pixelsPerLngDegree;
double latRadians = (point.getY() - origin.getY()) / (-pixelsPerLngRadian);
double lat = Math.toDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2.0);
return new GeoPoint(lat, lng);
}
}
@@ -1,22 +0,0 @@
package seng302.visualiser.map;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
public class TestMapController implements Initializable{
@FXML
private Canvas mapCanvas;
@Override
public void initialize(URL location, ResourceBundle resources) {
GraphicsContext gc = mapCanvas.getGraphicsContext2D();
Boundary bound = new Boundary(57.662943, 11.848501, 57.673945, 11.824966);
CanvasMap canvasMap = new CanvasMap(bound);
gc.drawImage(canvasMap.getMapImage(), 0, 0, canvasMap.getWidth(), canvasMap.getHeight());
}
}
+8 -3
View File
@@ -15,7 +15,6 @@
</CompoundMark> </CompoundMark>
<CompoundMark CompoundMarkID="2"> <CompoundMark CompoundMarkID="2">
<Mark Lat="57.670914" Lng="11.835263"/> <Mark Lat="57.670914" Lng="11.835263"/>
<Mark Lat="57.6699024" Lng="11.8353195"/>
</CompoundMark> </CompoundMark>
<CompoundMark CompoundMarkID="3"> <CompoundMark CompoundMarkID="3">
<Mark Lat="57.6674596" Lng="11.8417500"/> <Mark Lat="57.6674596" Lng="11.8417500"/>
@@ -29,21 +28,27 @@
<Mark Lat="57.667311" Lng="11.828857"/> <Mark Lat="57.667311" Lng="11.828857"/>
<Mark Lat="57.667334" Lng="11.825853"/> <Mark Lat="57.667334" Lng="11.825853"/>
</CompoundMark> </CompoundMark>
<CompoundMark CompoundMarkID="6">
<Mark Lat="57.6675700" Lng="11.8359880"/>
<Mark Lat="57.667610" Lng="11.833473"/>
</CompoundMark>
</Marks> </Marks>
<Course> <Course>
<OpeningSegment> <OpeningSegment>
<Corner CompoundMarkID="1" Rounding="PS"/> <Corner CompoundMarkID="1" Rounding="PS"/>
<Corner CompoundMarkID="2" Rounding="P"/> <Corner CompoundMarkID="2" Rounding="S"/>
</OpeningSegment> </OpeningSegment>
<RepeatingSegment> <RepeatingSegment>
<Corner CompoundMarkID="3" Rounding="SP"/> <Corner CompoundMarkID="3" Rounding="SP"/>
<Corner CompoundMarkID="4" Rounding="PS"/> <Corner CompoundMarkID="4" Rounding="PS"/>
<Corner CompoundMarkID="5" Rounding="PS"/>
<Corner CompoundMarkID="2" Rounding="S"/>
</RepeatingSegment> </RepeatingSegment>
<ClosingSegment> <ClosingSegment>
<Corner CompoundMarkID="5" Rounding="PS"/> <Corner CompoundMarkID="6" Rounding="PS"/>
</ClosingSegment> </ClosingSegment>
</Course> </Course>
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<GridPane fx:id="finishScreenGridPane" maxHeight="837.0" maxWidth="837.0" minHeight="837.0" minWidth="837.0" nodeOrientation="LEFT_TO_RIGHT" prefHeight="837.0" prefWidth="837.0" style="-fx-background-color: #2C2c36;" 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.visualiser.controllers.FinishScreenViewController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="259.0" minHeight="259.0" prefHeight="259.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="64.0" minHeight="64.0" prefHeight="64.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="257.0" minHeight="257.0" prefHeight="257.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="257.0" minHeight="257.0" prefHeight="257.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label alignment="CENTER" text="Race Finished!" textFill="WHITE" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<font>
<Font size="40.0" />
</font>
</Label>
<Label alignment="CENTER" text="Race Result:" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<font>
<Font size="28.0" />
</font>
</Label>
<TableView fx:id="finishOrderTable" maxWidth="661.0" prefHeight="324.0" prefWidth="629.0" styleClass="ui-table" GridPane.halignment="CENTER" GridPane.rowIndex="2">
<columns>
<TableColumn fx:id="posCol" editable="false" maxWidth="74.0" minWidth="74.0" prefWidth="74.0" resizable="false" sortable="false" text="Position" />
<TableColumn fx:id="boatNameCol" editable="false" maxWidth="171.0" minWidth="171.0" prefWidth="171.0" resizable="false" sortable="false" text="Boat Name" />
<TableColumn fx:id="shortNameCol" editable="false" maxWidth="155.18472290039062" minWidth="107.0" prefWidth="155.18472290039062" resizable="false" sortable="false" text="Short Name" />
<TableColumn fx:id="countryCol" editable="false" maxWidth="258.9999694824219" minWidth="147.0" prefWidth="258.9999694824219" resizable="false" sortable="false" text="Country" />
</columns>
<GridPane.margin>
<Insets bottom="50.0" />
</GridPane.margin>
</TableView>
<Button mnemonicParsing="false" onAction="#switchToStartScreenView" onMouseEntered="#playButtonHoverSound" styleClass="blue-ui-btn" text="Return to Start Screen" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="TOP" />
</children>
</GridPane>
+15 -4
View File
@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.shape.*?>
<?import com.jfoenix.controls.*?> <?import com.jfoenix.controls.*?>
<?import java.lang.*?> <?import java.lang.*?>
<?import javafx.geometry.*?> <?import javafx.geometry.*?>
@@ -294,13 +292,26 @@
</GridPane> </GridPane>
</children> </children>
</StackPane> </StackPane>
<Pane fx:id="miniMapPane" maxHeight="200.0" maxWidth="200.0" minHeight="200.0" minWidth="200.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: white; -fx-opacity: 0.45; -fx-background-radius: 10;" StackPane.alignment="TOP_RIGHT">
<StackPane.margin>
<Insets right="15.0" top="15.0" />
</StackPane.margin>
</Pane>
<JFXButton fx:id="miniMapButton" style="-fx-background-color: white; -fx-opacity: 0.45; -fx-background-radius: 10;" text="✕" StackPane.alignment="TOP_RIGHT">
<font>
<Font size="15.0" />
</font>
<StackPane.margin>
<Insets right="15.0" top="15.0" />
</StackPane.margin>
</JFXButton>
<AnchorPane fx:id="loadingScreenPane"> <AnchorPane fx:id="loadingScreenPane">
<ImageView fx:id="loadingScreen" fitHeight="672.0" fitWidth="1200.0" pickOnBounds="true" preserveRatio="true" /> <ImageView fx:id="loadingScreen" fitHeight="672.0" fitWidth="1200.0" pickOnBounds="true" preserveRatio="true" />
<JFXSpinner layoutX="566.0" layoutY="692.0" radius="30.0" /> <JFXSpinner layoutX="566.0" layoutY="692.0" radius="30.0" />
</AnchorPane> </AnchorPane>
</children> </children>
<stylesheets> <stylesheets>
<String fx:value="/css/Master.css"/> <String fx:value="/css/Master.css" />
<String fx:value="/css/RaceView.css"/> <String fx:value="/css/RaceView.css" />
</stylesheets> </stylesheets>
</StackPane> </StackPane>
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import com.jfoenix.controls.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialogLayout?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="273.0" prefWidth="436.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.TokenInfoDialogController">
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="40.0" minHeight="30.0" prefHeight="40.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="80.0"
prefHeight="115.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="141.0" minHeight="34.0" prefHeight="73.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<JFXButton fx:id="optionButton" buttonType="RAISED" prefHeight="55.0"
prefWidth="150.0" text="Ok" GridPane.halignment="CENTER" GridPane.rowIndex="2"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</JFXButton>
<Label fx:id="headerLabel" text="Popup header" GridPane.halignment="CENTER">
<font>
<Font size="15.0"/>
</font>
</Label>
<GridPane GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="270.0" minWidth="10.0"
prefWidth="270.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="225.0" minWidth="-Infinity"
prefWidth="138.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="100.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<Pane fx:id="tokenPane" prefHeight="200.0" prefWidth="200.0"
GridPane.columnIndex="1"/>
<TextArea fx:id="contentText" nodeOrientation="RIGHT_TO_LEFT"
prefHeight="200.0" prefWidth="200.0" promptText="This is some text"
stylesheets="@../../css/TokenInfoDialog.css" wrapText="true">
<font>
<Font size="16.0"/>
</font>
</TextArea>
</children>
</GridPane>
</children>
</GridPane>
</children>
<stylesheets>
<URL value="@../../css/dialogs/Popup.css"/>
<URL value="@../../css/Master.css"/>
</stylesheets>
</JFXDialogLayout>
@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<AnchorPane fx:id="annotationSelectWindow" maxHeight="270.0" maxWidth="469.0" minHeight="270.0" minWidth="469.0" prefHeight="270.0" prefWidth="469.0" styleClass="background-blue" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Text fill="WHITE" layoutX="26.0" layoutY="52.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Select important annotations">
<font>
<Font size="24.0" />
</font>
</Text>
<CheckBox fx:id="boatWakeSelect" layoutX="26.0" layoutY="80.0" mnemonicParsing="false" style="-fx-border-width: 0; -fx-background-insets: 0;" text="Boat Wakes" textFill="#e7e7e7" />
<CheckBox fx:id="boatSpeedSelect" layoutX="26.0" layoutY="111.0" mnemonicParsing="false" text="Boat Speed" textFill="#e7e7e7" />
<CheckBox fx:id="boatTrackSelect" layoutX="26.0" layoutY="142.0" mnemonicParsing="false" text="Boat Tracks" textFill="#e7e7e7" />
<CheckBox fx:id="boatNameSelect" layoutX="26.0" layoutY="173.0" mnemonicParsing="false" text="Boat Name" textFill="#e7e7e7" />
<CheckBox fx:id="boatEstTimeToNextMarkSelect" layoutX="26.0" layoutY="204.0" mnemonicParsing="false" text="Boat Estimated Time To Next Mark" textFill="#e7e7e7" />
<Button fx:id="closeButton" layoutX="424.0" layoutY="-1.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="49.0" style=": 0;" text="X" textFill="#ffffff4e">
<font>
<Font size="24.0" />
</font>
<styleClass>
<String fx:value="background-blue" />
<String fx:value="clearExitButton" />
</styleClass>
</Button>
<CheckBox fx:id="boatElapsedTimeSelect" layoutX="26.0" layoutY="235.0" mnemonicParsing="false" text="Boat Elapsed Time Since Last Mark" textFill="#e7e7e7" />
</children>
</AnchorPane>
@@ -48,9 +48,10 @@ public class ServerTableTest {
serverTable.addServer(listing); serverTable.addServer(listing);
listing.decrementTtl();
listing.decrementTtl(); listing.decrementTtl();
Thread.sleep(1000); Thread.sleep(1500);
assertTrue(!serverTable.getAllServers().contains(listing)); assertTrue(!serverTable.getAllServers().contains(listing));
} }
@@ -1,43 +0,0 @@
package seng302.visualiser.map;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import seng302.model.GeoPoint;
/**
* Unit test for Mercator Project class.
* Created by hyi25 on 15/05/17.
*/
public class MercatorProjectionTest {
@Test
public void toMapPoint() throws Exception {
GeoPoint geo1 = new GeoPoint(12.485394, 19.38947);
javafx.geometry.Point2D actualPoint1 = MercatorProjection.toMapPoint(geo1);
javafx.geometry.Point2D expectedPoint1 = new javafx.geometry.Point2D(141.78806755555556, 119.0503853635612);
assertEquals(expectedPoint1.getX(), actualPoint1.getX(), 0.0001);
assertEquals(expectedPoint1.getY(), actualPoint1.getY(), 0.0001);
GeoPoint geo2 = new GeoPoint(77.456432, -23.456462);
javafx.geometry.Point2D actualPoint2 = MercatorProjection.toMapPoint(geo2);
javafx.geometry.Point2D expectedPoint2 = new javafx.geometry.Point2D(111.31984924444444, 38.03143323746788);
assertEquals(expectedPoint2.getX(), actualPoint2.getX(), 0.0001);
assertEquals(expectedPoint2.getY(), actualPoint2.getY(), 0.0001);
}
@Test
public void toMapGeo() throws Exception {
javafx.geometry.Point2D point1 = new javafx.geometry.Point2D(123.1234, 25.4565);
GeoPoint actualGeo1 = MercatorProjection.toMapGeo(point1);
GeoPoint expectedGeo1 = new GeoPoint(80.77043127275441, -6.857718749999995);
assertEquals(expectedGeo1.getLat(), actualGeo1.getLat(), 0.0001);
assertEquals(expectedGeo1.getLng(), actualGeo1.getLng(), 0.0001);
javafx.geometry.Point2D point2 = new javafx.geometry.Point2D(1.235, 255.4565);
GeoPoint actualGeo2 = MercatorProjection.toMapGeo(point2);
GeoPoint expectedGeo2 = new GeoPoint(-84.98475532898011, -178.26328125);
assertEquals(expectedGeo2.getLat(), actualGeo2.getLat(), 0.0001);
assertEquals(expectedGeo2.getLng(), actualGeo2.getLng(), 0.0001);
}
}
+5 -2
View File
@@ -3,6 +3,9 @@ package steps;
import cucumber.api.java.en.Given; import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then; import cucumber.api.java.en.Then;
import java.io.File; import java.io.File;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;
import org.junit.Assert; import org.junit.Assert;
import seng302.visualiser.MapMaker; import seng302.visualiser.MapMaker;
@@ -29,11 +32,11 @@ public class CustomMapsSteps {
@Then("^all of them can be seen$") @Then("^all of them can be seen$")
public void all_of_them_can_be_seen() throws Throwable { public void all_of_them_can_be_seen() throws Throwable {
File[] files = new File(this.getClass().getResource("/maps/").getPath()).listFiles(); File[] files = new File(this.getClass().getResource("/maps/").getPath()).listFiles();
Arrays.sort(files);
for (File file : files) { for (File file : files) {
if (file.isFile()) { if (file.isFile()) {
Assert.assertTrue(file.getAbsolutePath().equals(mapMaker.getCurrentRacePath())); Assert.assertTrue(file.getAbsolutePath().endsWith(mapMaker.getCurrentRacePath()));
mapMaker.next(); mapMaker.next();
System.out.println(file.getAbsolutePath());
} }
} }
} }