Merge remote-tracking branch 'remotes/origin/master' into wind_(story53)
# Conflicts: # racevisionGame/src/main/java/mock/app/Event.java # racevisionGame/src/main/java/mock/model/MockRace.java
This commit is contained in:
@@ -61,12 +61,7 @@ public class ConnectionAcceptor implements Runnable {
|
||||
*/
|
||||
private SourceIdAllocator sourceIdAllocator;
|
||||
|
||||
//race xml sequence number
|
||||
private short raceXMLSequenceNumber;
|
||||
//boat xml sequence number
|
||||
private short boatXMLSequenceNumber;
|
||||
//regatta xml sequence number
|
||||
private short regattaXMLSequenceNumber;
|
||||
|
||||
//
|
||||
private RaceLogic raceLogic = null;
|
||||
|
||||
@@ -209,77 +204,6 @@ public class ConnectionAcceptor implements Runnable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Race XML to send.
|
||||
* @param raceXml XML to send to the Client.
|
||||
*/
|
||||
public void setRaceXml(String raceXml) {
|
||||
//Create the message.
|
||||
XMLMessage message = this.createXMLMessage(raceXml, XMLMessageType.RACE);
|
||||
|
||||
//Place it in LatestMessages.
|
||||
this.latestMessages.setRaceXMLMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Regatta XMl to send.
|
||||
* @param regattaXml XML to send to Client.
|
||||
*/
|
||||
public void setRegattaXml(String regattaXml) {
|
||||
//Create the message.
|
||||
XMLMessage message = this.createXMLMessage(regattaXml, XMLMessageType.REGATTA);
|
||||
|
||||
//Place it in LatestMessages.
|
||||
this.latestMessages.setRegattaXMLMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Boats XML to send.
|
||||
* @param boatsXml XMl to send to the Client.
|
||||
*/
|
||||
public void setBoatsXml(String boatsXml) {
|
||||
//Create the message.
|
||||
XMLMessage message = this.createXMLMessage(boatsXml, XMLMessageType.BOAT);
|
||||
|
||||
//Place it in LatestMessages.
|
||||
this.latestMessages.setBoatXMLMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an XMLMessage of a specified subtype using the xml contents string.
|
||||
* @param xmlString The contents of the xml file.
|
||||
* @param messageType The subtype of xml message (race, regatta, boat).
|
||||
* @return The created XMLMessage object.
|
||||
*/
|
||||
private XMLMessage createXMLMessage(String xmlString, XMLMessageType messageType) {
|
||||
|
||||
//Get the correct sequence number to use, and increment it.
|
||||
short sequenceNumber = 0;
|
||||
if (messageType == XMLMessageType.RACE) {
|
||||
sequenceNumber = this.raceXMLSequenceNumber;
|
||||
this.raceXMLSequenceNumber++;
|
||||
|
||||
} else if (messageType == XMLMessageType.BOAT) {
|
||||
sequenceNumber = this.boatXMLSequenceNumber;
|
||||
this.boatXMLSequenceNumber++;
|
||||
|
||||
} else if (messageType == XMLMessageType.REGATTA) {
|
||||
sequenceNumber = this.regattaXMLSequenceNumber;
|
||||
this.regattaXMLSequenceNumber++;
|
||||
|
||||
}
|
||||
|
||||
//Create the message.
|
||||
XMLMessage message = new XMLMessage(
|
||||
XMLMessage.currentVersionNumber,
|
||||
AckSequencer.getNextAckNum(),
|
||||
System.currentTimeMillis(),
|
||||
messageType,
|
||||
sequenceNumber,
|
||||
xmlString);
|
||||
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
@@ -115,18 +120,10 @@ public class Event {
|
||||
|
||||
}
|
||||
|
||||
this.sourceIdAllocator = new SourceIdAllocator(raceDataSource.getParticipants());
|
||||
|
||||
this.compositeCommand = new CompositeCommand();
|
||||
this.latestMessages = new LatestMessages();
|
||||
|
||||
//Create and start race.
|
||||
// WindGenerator windGenerator = new RandomWindGenerator(
|
||||
// Bearing.fromDegrees(225),
|
||||
// Bearing.fromDegrees(215),
|
||||
// Bearing.fromDegrees(235),
|
||||
// 12d,
|
||||
// 8d,
|
||||
// 16d );
|
||||
WindGenerator windGenerator = new ShiftingWindGenerator(
|
||||
Bearing.fromDegrees(225),
|
||||
12
|
||||
@@ -147,6 +144,7 @@ public class Event {
|
||||
|
||||
|
||||
//Create connection acceptor.
|
||||
this.sourceIdAllocator = new SourceIdAllocator(newRace.getRace());
|
||||
|
||||
try {
|
||||
this.connectionAcceptor = new ConnectionAcceptor(latestMessages, compositeCommand, sourceIdAllocator, newRace);
|
||||
@@ -159,8 +157,6 @@ public class Event {
|
||||
this.connectionThread = new Thread(connectionAcceptor, "Event.Start()->ConnectionAcceptor thread");
|
||||
connectionThread.start();
|
||||
|
||||
sendXMLs();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -173,18 +169,6 @@ public class Event {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sends out each xml string, via the mock output
|
||||
*/
|
||||
private void sendXMLs() {
|
||||
|
||||
connectionAcceptor.setRegattaXml(regattaXML);
|
||||
|
||||
connectionAcceptor.setRaceXml(raceXML);
|
||||
|
||||
connectionAcceptor.setBoatsXml(boatXML);
|
||||
}
|
||||
|
||||
|
||||
//TODO remove this after demo on 18th august!
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,12 @@ public class MockOutput implements RunnableWithFramePeriod {
|
||||
*/
|
||||
private LatestMessages latestMessages;
|
||||
|
||||
//These sequence number track the last race/boat/regatta xml message we've sent.
|
||||
private int lastSentRaceNumber = -1;
|
||||
|
||||
private int lastSentBoatNumber = -1;
|
||||
|
||||
private int lastSentRegattaNumber = -1;
|
||||
|
||||
|
||||
|
||||
@@ -69,7 +74,6 @@ public class MockOutput implements RunnableWithFramePeriod {
|
||||
|
||||
|
||||
long previousFrameTime = System.currentTimeMillis();
|
||||
boolean sentXMLs = false;
|
||||
|
||||
|
||||
|
||||
@@ -82,16 +86,26 @@ public class MockOutput implements RunnableWithFramePeriod {
|
||||
previousFrameTime = currentFrameTime;
|
||||
|
||||
|
||||
//Send XML messages.
|
||||
if (!sentXMLs) {
|
||||
|
||||
//Send XML messages if needed.
|
||||
|
||||
if (lastSentRaceNumber != latestMessages.getRaceXMLMessage().getSequenceNumber()) {
|
||||
lastSentRaceNumber = latestMessages.getRaceXMLMessage().getSequenceNumber();
|
||||
outgoingMessages.put(latestMessages.getRaceXMLMessage());
|
||||
outgoingMessages.put(latestMessages.getRegattaXMLMessage());
|
||||
outgoingMessages.put(latestMessages.getBoatXMLMessage());
|
||||
|
||||
sentXMLs = true;
|
||||
}
|
||||
|
||||
if (lastSentBoatNumber != latestMessages.getBoatXMLMessage().getSequenceNumber()) {
|
||||
lastSentBoatNumber = latestMessages.getBoatXMLMessage().getSequenceNumber();
|
||||
outgoingMessages.put(latestMessages.getBoatXMLMessage());
|
||||
}
|
||||
|
||||
if (lastSentRegattaNumber != latestMessages.getRegattaXMLMessage().getSequenceNumber()) {
|
||||
lastSentRegattaNumber = latestMessages.getRegattaXMLMessage().getSequenceNumber();
|
||||
outgoingMessages.put(latestMessages.getRegattaXMLMessage());
|
||||
}
|
||||
|
||||
|
||||
|
||||
List<AC35Data> snapshot = latestMessages.getSnapshot();
|
||||
for (AC35Data message : snapshot) {
|
||||
outgoingMessages.put(message);
|
||||
|
||||
@@ -109,6 +109,11 @@ public class ClientConnection implements Runnable {
|
||||
*/
|
||||
private ConnectionStateEnum connectionState = ConnectionStateEnum.UNKNOWN;
|
||||
|
||||
/**
|
||||
* The source ID that has been allocated to the client.
|
||||
* 0 means not allocated.
|
||||
*/
|
||||
private int allocatedSourceID = 0;
|
||||
|
||||
|
||||
|
||||
@@ -178,7 +183,7 @@ public class ClientConnection implements Runnable {
|
||||
|
||||
RequestToJoin requestToJoin = waitForRequestToJoin();
|
||||
|
||||
int allocatedSourceID = 0;
|
||||
allocatedSourceID = 0;
|
||||
|
||||
//If they want to participate, give them a source ID number.
|
||||
if (requestToJoin.getRequestType() == RequestToJoinEnum.PARTICIPANT) {
|
||||
@@ -283,6 +288,10 @@ public class ClientConnection implements Runnable {
|
||||
if (this.controllerServerThread != null) {
|
||||
this.controllerServerThread.interrupt();
|
||||
}
|
||||
|
||||
if (allocatedSourceID != 0) {
|
||||
sourceIdAllocator.returnSourceID(allocatedSourceID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package mock.model;
|
||||
|
||||
import mock.model.wind.WindGenerator;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import mock.model.collider.ColliderRegistry;
|
||||
import mock.xml.*;
|
||||
import network.Messages.BoatLocation;
|
||||
import network.Messages.BoatStatus;
|
||||
import network.Messages.Enums.BoatStatusEnum;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
import shared.dataInput.BoatDataSource;
|
||||
@@ -10,7 +15,6 @@ import shared.exceptions.BoatNotFoundException;
|
||||
import shared.enums.RoundingType;
|
||||
import shared.model.*;
|
||||
import shared.model.Bearing;
|
||||
import shared.model.Race;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
@@ -24,7 +28,7 @@ import static java.lang.Math.cos;
|
||||
* Has a course, boats, boundaries, etc...
|
||||
* Is responsible for simulating the race, and sending messages to a MockOutput instance.
|
||||
*/
|
||||
public class MockRace extends Race {
|
||||
public class MockRace extends RaceState {
|
||||
|
||||
/**
|
||||
* An observable list of boats in the race.
|
||||
@@ -37,6 +41,12 @@ public class MockRace extends Race {
|
||||
private List<GPSCoordinate> shrinkBoundary;
|
||||
|
||||
|
||||
/**
|
||||
* Registry for all collider object in this race
|
||||
*/
|
||||
private ColliderRegistry colliderRegistry;
|
||||
|
||||
|
||||
/**
|
||||
* The scale factor of the race.
|
||||
* See {@link Constants#RaceTimeScale}.
|
||||
@@ -48,6 +58,14 @@ public class MockRace extends Race {
|
||||
*/
|
||||
private WindGenerator windGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* The polars file to use for each boat.
|
||||
*/
|
||||
private Polars polars;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a race object with a given RaceDataSource, BoatDataSource, and RegattaDataSource and sends events to the given mockOutput.
|
||||
* @param boatDataSource Data source for boat related data (yachts and marker boats).
|
||||
@@ -59,13 +77,16 @@ public class MockRace extends Race {
|
||||
*/
|
||||
public MockRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, Polars polars, int timeScale, WindGenerator windGenerator) {
|
||||
|
||||
super(boatDataSource, raceDataSource, regattaDataSource);
|
||||
this.setBoatDataSource(boatDataSource);
|
||||
this.setRaceDataSource(raceDataSource);
|
||||
this.setRegattaDataSource(regattaDataSource);
|
||||
|
||||
this.polars = polars;
|
||||
this.scaleFactor = timeScale;
|
||||
|
||||
this.boats = this.generateMockBoats(boatDataSource.getBoats(), raceDataSource.getParticipants(), polars);
|
||||
this.boats = new ArrayList<>();
|
||||
|
||||
this.shrinkBoundary = GPSCoordinate.getShrinkBoundary(this.boundary);
|
||||
this.shrinkBoundary = GPSCoordinate.getShrinkBoundary(this.getBoundary());
|
||||
|
||||
|
||||
this.windGenerator = windGenerator;
|
||||
@@ -73,35 +94,53 @@ public class MockRace extends Race {
|
||||
//Wind.
|
||||
this.setWind(windGenerator.generateBaselineWind());
|
||||
|
||||
|
||||
// Set up colliders
|
||||
this.colliderRegistry = new ColliderRegistry();
|
||||
|
||||
for(CompoundMark mark: this.getCompoundMarks()) {
|
||||
colliderRegistry.addCollider(mark.getMark1());
|
||||
if(mark.getMark2() != null) colliderRegistry.addCollider(mark.getMark2());
|
||||
}
|
||||
|
||||
this.colliderRegistry.addAllColliders(boats);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a list of MockBoats given a list of Boats, and a list of participating boats.
|
||||
* @param boats The map of Boats describing boats that are potentially in the race. Maps boat sourceID to boat.
|
||||
* @param sourceIDs The list of boat sourceIDs describing which specific boats are actually participating.
|
||||
* @param polars The polars table to be used for boat simulation.
|
||||
* @return A list of MockBoats that are participating in the race.
|
||||
* Generates a MockBoat from the BoatDataSource, given a source ID. Also adds it to the participant list.
|
||||
* @param sourceID The source ID to assign the boat.
|
||||
*/
|
||||
private List<MockBoat> generateMockBoats(Map<Integer, Boat> boats, List<Integer> sourceIDs, Polars polars) {
|
||||
public void generateMockBoat(Integer sourceID) {
|
||||
|
||||
List<MockBoat> mockBoats = new ArrayList<>(sourceIDs.size());
|
||||
//Get the boat associated with the sourceID.
|
||||
Boat boat = getBoatDataSource().getBoats().get(sourceID);
|
||||
|
||||
//For each sourceID participating...
|
||||
for (int sourceID : sourceIDs) {
|
||||
//Construct a MockBoat using the Boat and Polars.
|
||||
MockBoat mockBoat = new MockBoat(boat, polars);
|
||||
mockBoat.setCurrentLeg(this.getLegs().get(0));
|
||||
|
||||
//Get the boat associated with the sourceID.
|
||||
Boat boat = boats.get(sourceID);
|
||||
//Update participant list.
|
||||
getRaceDataSource().getParticipants().add(sourceID);
|
||||
|
||||
//Construct a MockBoat using the Boat and Polars.
|
||||
MockBoat mockBoat = new MockBoat(boat, polars);
|
||||
this.boats.add(mockBoat);
|
||||
|
||||
mockBoats.add(mockBoat);
|
||||
getRaceDataSource().incrementSequenceNumber();
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Removes a MockBoat from the race, by sourceID. Also removes it from the participant list.
|
||||
* @param sourceID Source ID of boat to remove.
|
||||
*/
|
||||
public void removeMockBoat(Integer sourceID) {
|
||||
this.boats.removeIf(mockBoat -> mockBoat.getSourceID() == sourceID);
|
||||
getRaceDataSource().getParticipants().remove(sourceID);
|
||||
getRaceDataSource().incrementSequenceNumber();
|
||||
}
|
||||
|
||||
return mockBoats;
|
||||
|
||||
public ColliderRegistry getColliderRegistry() {
|
||||
return colliderRegistry;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +149,7 @@ public class MockRace extends Race {
|
||||
* @param currentTime Milliseconds since unix epoch.
|
||||
*/
|
||||
public void updateRaceTime(long currentTime) {
|
||||
this.raceClock.setUTCTime(currentTime);
|
||||
this.getRaceClock().setUTCTime(currentTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +159,7 @@ public class MockRace extends Race {
|
||||
public void updateRaceStatusEnum() {
|
||||
|
||||
//The millisecond duration of the race. Negative means it hasn't started, so we flip sign.
|
||||
long timeToStart = - this.raceClock.getDurationMilli();
|
||||
long timeToStart = - this.getRaceClock().getDurationMilli();
|
||||
|
||||
|
||||
if (timeToStart > Constants.RacePreStartTime) {
|
||||
@@ -191,7 +230,7 @@ public class MockRace extends Race {
|
||||
|
||||
|
||||
//The boat starts on the first leg of the race.
|
||||
boat.setCurrentLeg(this.legs.get(0));
|
||||
boat.setCurrentLeg(this.getLegs().get(0));
|
||||
|
||||
//Boats start with 0 knots speed.
|
||||
boat.setCurrentSpeed(0d);
|
||||
@@ -220,7 +259,7 @@ public class MockRace extends Race {
|
||||
private List<GPSCoordinate> getSpreadStartingPositions() {
|
||||
|
||||
//The first compound marker of the race - the starting gate.
|
||||
CompoundMark compoundMark = this.legs.get(0).getStartCompoundMark();
|
||||
CompoundMark compoundMark = this.getLegs().get(0).getStartCompoundMark();
|
||||
|
||||
//The position of the two markers from the compound marker.
|
||||
GPSCoordinate mark1Position = compoundMark.getMark1Position();
|
||||
@@ -482,7 +521,7 @@ public class MockRace extends Race {
|
||||
roundingChecks.get(0), boat.getPosition(), legBearing) &&
|
||||
gateCheck && boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) {
|
||||
boat.increaseRoundingStatus();
|
||||
if (boat.getCurrentLeg().getLegNumber() + 2 >= legs.size()){
|
||||
if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){
|
||||
//boat has finished race
|
||||
boat.increaseRoundingStatus();
|
||||
}
|
||||
@@ -500,7 +539,7 @@ public class MockRace extends Race {
|
||||
case 2://has traveled 180 degrees around the mark
|
||||
//Move boat on to next leg.
|
||||
boat.resetRoundingStatus();
|
||||
Leg nextLeg = this.legs.get(boat.getCurrentLeg().getLegNumber() + 1);
|
||||
Leg nextLeg = this.getLegs().get(boat.getCurrentLeg().getLegNumber() + 1);
|
||||
boat.setCurrentLeg(nextLeg);
|
||||
break;
|
||||
}
|
||||
@@ -527,7 +566,7 @@ public class MockRace extends Race {
|
||||
gateCheck &&
|
||||
boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) {
|
||||
boat.increaseRoundingStatus();
|
||||
if (boat.getCurrentLeg().getLegNumber() + 2 >= legs.size()){
|
||||
if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){
|
||||
//boat has finished race
|
||||
boat.increaseRoundingStatus();
|
||||
}
|
||||
@@ -544,7 +583,7 @@ public class MockRace extends Race {
|
||||
case 2://has traveled 180 degrees around the mark
|
||||
//Move boat on to next leg.
|
||||
boat.resetRoundingStatus();
|
||||
Leg nextLeg = this.legs.get(boat.getCurrentLeg().getLegNumber() + 1);
|
||||
Leg nextLeg = this.getLegs().get(boat.getCurrentLeg().getLegNumber() + 1);
|
||||
boat.setCurrentLeg(nextLeg);
|
||||
break;
|
||||
}
|
||||
@@ -582,7 +621,7 @@ public class MockRace extends Race {
|
||||
|
||||
GPSCoordinate roundCheck2;
|
||||
try{
|
||||
Leg nextLeg = legs.get(legs.indexOf(boat.getCurrentLeg()) + 1);
|
||||
Leg nextLeg = getLegs().get(getLegs().indexOf(boat.getCurrentLeg()) + 1);
|
||||
|
||||
GPSCoordinate startNextDirectionLinePoint = nextLeg.getStartCompoundMark().getMark1Position();
|
||||
GPSCoordinate endNextDirectionLinePoint = nextLeg.getEndCompoundMark().getMark1Position();
|
||||
@@ -678,7 +717,7 @@ public class MockRace extends Race {
|
||||
*/
|
||||
public void changeWindDirection() {
|
||||
|
||||
Wind nextWind = windGenerator.generateNextWind(raceWind.getValue());
|
||||
Wind nextWind = windGenerator.generateNextWind(windProperty().getValue());
|
||||
|
||||
setWind(nextWind);
|
||||
}
|
||||
@@ -699,13 +738,10 @@ public class MockRace extends Race {
|
||||
long timeFromNow = (long) (1000 * boat.calculateDistanceToNextMarker() / velocityToMark);
|
||||
|
||||
//Calculate time at which it will reach mark.
|
||||
ZonedDateTime timeAtMark = this.raceClock.getCurrentTime().plus(timeFromNow, ChronoUnit.MILLIS);
|
||||
ZonedDateTime timeAtMark = this.getRaceClock().getCurrentTime().plus(timeFromNow, ChronoUnit.MILLIS);
|
||||
boat.setEstimatedTimeAtNextMark(timeAtMark);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<CompoundMark> getCompoundMarks() {
|
||||
return compoundMarks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
prestartCountdown();
|
||||
|
||||
race.initialiseBoats();
|
||||
|
||||
countdown();
|
||||
@@ -60,6 +63,37 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The countdown timer until the prestart period is finished. This timer will stop 3 minutes before the race starts, and players can no longer start participating.
|
||||
*/
|
||||
private void prestartCountdown() {
|
||||
|
||||
long previousFrameTime = System.currentTimeMillis();
|
||||
|
||||
while (((race.getRaceStatusEnum() == RaceStatusEnum.PRESTART)
|
||||
|| (race.getRaceStatusEnum() == RaceStatusEnum.NOT_ACTIVE)
|
||||
|| (race.getRaceStatusEnum() == RaceStatusEnum.WARNING)) && loopBool) {
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
//Update race time.
|
||||
race.updateRaceTime(currentTime);
|
||||
|
||||
//Update the race status based on the current time.
|
||||
race.updateRaceStatusEnum();
|
||||
|
||||
//Provide boat's with an estimated time at next mark until the race starts.
|
||||
race.setBoatsTimeNextMark(race.getRaceClock().getCurrentTime());
|
||||
|
||||
//Parse the race snapshot.
|
||||
server.parseSnapshot();
|
||||
|
||||
|
||||
waitForFramePeriod(previousFrameTime, currentTime, 50);
|
||||
previousFrameTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Countdown timer until race starts.
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
package mock.model;
|
||||
|
||||
import network.AckSequencer;
|
||||
import network.Messages.*;
|
||||
import network.Messages.Enums.BoatLocationDeviceEnum;
|
||||
import network.Messages.Enums.XMLMessageType;
|
||||
import shared.model.Bearing;
|
||||
import shared.model.CompoundMark;
|
||||
import shared.model.Mark;
|
||||
import shared.xml.Race.RaceDataSourceToXML;
|
||||
import shared.xml.boats.BoatDataSourceToXML;
|
||||
import shared.xml.regatta.RegattaDataSourceToXML;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Created by connortaylorbrown on 2/08/17.
|
||||
@@ -22,6 +30,21 @@ public class RaceServer {
|
||||
*/
|
||||
private int boatLocationSequenceNumber = 1;
|
||||
|
||||
/**
|
||||
* The sequence number of race XML messages.
|
||||
*/
|
||||
private int raceXMLSeqNumber = -1;
|
||||
|
||||
/**
|
||||
* The sequence number of boat XML messages.
|
||||
*/
|
||||
private int boatXMLSeqNumber = -1;
|
||||
|
||||
/**
|
||||
* The sequence number of regatta XML messages.
|
||||
*/
|
||||
private int regattaXMLSeqNumber = -1;
|
||||
|
||||
|
||||
public RaceServer(MockRace race, LatestMessages latestMessages) {
|
||||
this.race = race;
|
||||
@@ -45,9 +68,78 @@ public class RaceServer {
|
||||
snapshotMessages.add(parseRaceStatus());
|
||||
|
||||
latestMessages.setSnapshot(snapshotMessages);
|
||||
|
||||
updateXMLFiles();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the race/boat/regatta data sources have changed, and if they have, update their xml representations.
|
||||
*/
|
||||
private void updateXMLFiles() {
|
||||
updateRaceXMLFile();
|
||||
updateBoatXMLFile();
|
||||
updateRegattaXMLFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the race data source has changed, and if it has, updates LatestMessages' race xml message.
|
||||
*/
|
||||
private void updateRaceXMLFile() {
|
||||
if (raceXMLSeqNumber != race.getRaceDataSource().getSequenceNumber()) {
|
||||
|
||||
raceXMLSeqNumber = race.getRaceDataSource().getSequenceNumber();
|
||||
try {
|
||||
String raceXMLString = RaceDataSourceToXML.toString(race.getRaceDataSource());
|
||||
XMLMessage message = createXMLMessage(raceXMLString, XMLMessageType.RACE);
|
||||
latestMessages.setXMLMessage(message);
|
||||
|
||||
} catch (JAXBException e) {
|
||||
Logger.getGlobal().log(Level.WARNING, "Could not serialise: " + race.getRaceDataSource(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the boat data source has changed, and if it has, updates LatestMessages' boat xml message.
|
||||
*/
|
||||
private void updateBoatXMLFile() {
|
||||
if (boatXMLSeqNumber != race.getBoatDataSource().getSequenceNumber()) {
|
||||
|
||||
boatXMLSeqNumber = race.getBoatDataSource().getSequenceNumber();
|
||||
try {
|
||||
String boatXMLString = BoatDataSourceToXML.toString(race.getBoatDataSource());
|
||||
XMLMessage message = createXMLMessage(boatXMLString, XMLMessageType.BOAT);
|
||||
latestMessages.setXMLMessage(message);
|
||||
|
||||
} catch (JAXBException e) {
|
||||
Logger.getGlobal().log(Level.WARNING, "Could not serialise: " + race.getBoatDataSource(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the regatta data source has changed, and if it has, updates LatestMessages' regatta xml message.
|
||||
*/
|
||||
private void updateRegattaXMLFile() {
|
||||
if (regattaXMLSeqNumber != race.getRegattaDataSource().getSequenceNumber()) {
|
||||
|
||||
regattaXMLSeqNumber = race.getRegattaDataSource().getSequenceNumber();
|
||||
|
||||
try {
|
||||
String regattaXMLString = RegattaDataSourceToXML.toString(race.getRegattaDataSource());
|
||||
XMLMessage message = createXMLMessage(regattaXMLString, XMLMessageType.REGATTA);
|
||||
latestMessages.setXMLMessage(message);
|
||||
|
||||
} catch (JAXBException e) {
|
||||
Logger.getGlobal().log(Level.WARNING, "Could not serialise: " + race.getRegattaDataSource(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an individual marker boat, and returns it.
|
||||
* @param mark The marker boat to parse.
|
||||
@@ -178,4 +270,41 @@ public class RaceServer {
|
||||
|
||||
return raceStatus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates an XMLMessage of a specified subtype using the xml contents string.
|
||||
* @param xmlString The contents of the xml file.
|
||||
* @param messageType The subtype of xml message (race, regatta, boat).
|
||||
* @return The created XMLMessage object.
|
||||
*/
|
||||
private XMLMessage createXMLMessage(String xmlString, XMLMessageType messageType) {
|
||||
|
||||
//Get the correct sequence number to use.
|
||||
int sequenceNumber = 0;
|
||||
if (messageType == XMLMessageType.RACE) {
|
||||
sequenceNumber = this.raceXMLSeqNumber;
|
||||
|
||||
} else if (messageType == XMLMessageType.BOAT) {
|
||||
sequenceNumber = this.boatXMLSeqNumber;
|
||||
|
||||
} else if (messageType == XMLMessageType.REGATTA) {
|
||||
sequenceNumber = this.regattaXMLSeqNumber;
|
||||
|
||||
}
|
||||
|
||||
//Create the message.
|
||||
XMLMessage message = new XMLMessage(
|
||||
XMLMessage.currentVersionNumber,
|
||||
AckSequencer.getNextAckNum(),
|
||||
System.currentTimeMillis(),
|
||||
messageType,
|
||||
sequenceNumber,
|
||||
xmlString);
|
||||
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package mock.model;
|
||||
|
||||
|
||||
import mock.exceptions.SourceIDAllocationException;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -13,24 +14,18 @@ public class SourceIdAllocator {
|
||||
|
||||
|
||||
/**
|
||||
* This list contains all unallocated source IDs.
|
||||
* The race we are allocating for.
|
||||
*/
|
||||
List<Integer> unallocatedIDs = new ArrayList<>();
|
||||
private MockRace mockRace;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This list contains all allocated source IDs.
|
||||
* Creates a SourceIdAllocator for a given race.
|
||||
* @param mockRace Race to allocate source IDs for.
|
||||
*/
|
||||
List<Integer> allocatedIDs = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Creates a source ID allocator, using the given list of unallocated source IDs.
|
||||
* @param unallocatedIDs List of unallocated source IDs.
|
||||
*/
|
||||
public SourceIdAllocator(List<Integer> unallocatedIDs) {
|
||||
//We need to copy the list.
|
||||
this.unallocatedIDs.addAll(unallocatedIDs);
|
||||
public SourceIdAllocator(MockRace mockRace) {
|
||||
this.mockRace = mockRace;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +36,24 @@ public class SourceIdAllocator {
|
||||
*/
|
||||
public synchronized int allocateSourceID() throws SourceIDAllocationException {
|
||||
|
||||
if (!((mockRace.getRaceStatusEnum() == RaceStatusEnum.PRESTART)
|
||||
|| (mockRace.getRaceStatusEnum() == RaceStatusEnum.WARNING))) {
|
||||
throw new SourceIDAllocationException("Could not allocate a source ID. Can only allocate during pre-start period. It is currently: " + mockRace.getRaceStatusEnum());
|
||||
}
|
||||
|
||||
List<Integer> allocatedIDs = mockRace.getRaceDataSource().getParticipants();
|
||||
List<Integer> allIDs = new ArrayList<>(mockRace.getBoatDataSource().getBoats().keySet());
|
||||
|
||||
//Get list of unallocated ids.
|
||||
List<Integer> unallocatedIDs = new ArrayList<>(allIDs);
|
||||
unallocatedIDs.removeAll(allocatedIDs);
|
||||
|
||||
|
||||
if (!unallocatedIDs.isEmpty()) {
|
||||
|
||||
int sourceID = unallocatedIDs.remove(0);
|
||||
|
||||
allocatedIDs.add(sourceID);
|
||||
mockRace.generateMockBoat(sourceID);
|
||||
|
||||
return sourceID;
|
||||
|
||||
@@ -61,10 +69,6 @@ public class SourceIdAllocator {
|
||||
* @param sourceID Source ID to return.
|
||||
*/
|
||||
public void returnSourceID(Integer sourceID) {
|
||||
|
||||
//We remove an Integer, not an int, so that we remove by value not by index.
|
||||
allocatedIDs.remove(sourceID);
|
||||
|
||||
unallocatedIDs.add(sourceID);
|
||||
mockRace.removeMockBoat(sourceID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,8 @@ public class RaceXMLCreator {
|
||||
public static String alterRaceToWind(String s, double degrees) throws XMLReaderException, InvalidRaceDataException, JAXBException, IOException, SAXException, ParserConfigurationException {
|
||||
RaceXMLReader reader = new RaceXMLReader(s, XMLFileType.ResourcePath);
|
||||
|
||||
XMLRace race = (XMLRace) XMLUtilities.xmlToClass(RaceXMLCreator.class.getClassLoader().getResourceAsStream(s),
|
||||
XMLRace race = XMLUtilities.xmlToClass(
|
||||
RaceXMLCreator.class.getClassLoader().getResourceAsStream(s),
|
||||
RaceXMLCreator.class.getClassLoader().getResource("mock/mockXML/schema/raceSchema.xsd"),
|
||||
XMLRace.class);
|
||||
|
||||
@@ -89,14 +90,7 @@ public class RaceXMLCreator {
|
||||
|
||||
alterRaceRotation(race, degreesToRotate);
|
||||
|
||||
JAXBContext context = JAXBContext.newInstance(XMLRace.class);
|
||||
Marshaller jaxbMarshaller = context.createMarshaller();
|
||||
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
|
||||
jaxbMarshaller.marshal(race, sw);
|
||||
return sw.toString();
|
||||
return XMLUtilities.classToXML(race);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,6 +71,8 @@ public enum RaceTypeEnum {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Stores a mapping between Byte values and RaceStatusEnum values.
|
||||
*/
|
||||
@@ -107,4 +109,14 @@ public enum RaceTypeEnum {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (fromByte(value) == FLEET_RACE) {
|
||||
return "fleet";
|
||||
} else if (fromByte(value) == MATCH_RACE) {
|
||||
return "match";
|
||||
} else {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ public class LatestMessages extends Observable {
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
*/
|
||||
|
||||
@@ -22,4 +22,16 @@ public interface BoatDataSource {
|
||||
* @return Map between source ID and mark.
|
||||
*/
|
||||
Map<Integer, Mark> getMarkerBoats();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sequence number associated with this data source. Used to indicate when it has changed.
|
||||
* @return Sequence number.
|
||||
*/
|
||||
int getSequenceNumber();
|
||||
|
||||
/**
|
||||
* Increments the sequence number for this data source. Used to indicate that it has changed.
|
||||
*/
|
||||
void incrementSequenceNumber();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public class BoatXMLReader extends XMLReader implements BoatDataSource {
|
||||
private final Map<Integer, Mark> markerMap = new HashMap<>();
|
||||
|
||||
|
||||
private int sequenceNumber = 0;
|
||||
|
||||
/**
|
||||
* Constructor for Boat XML using a file.
|
||||
*
|
||||
@@ -174,4 +176,15 @@ public class BoatXMLReader extends XMLReader implements BoatDataSource {
|
||||
public Map<Integer, Mark> getMarkerBoats() {
|
||||
return markerMap;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementSequenceNumber() {
|
||||
sequenceNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ public class EmptyBoatDataSource implements BoatDataSource {
|
||||
private final Map<Integer, Mark> markerMap = new HashMap<>();
|
||||
|
||||
|
||||
private int sequenceNumber = 0;
|
||||
|
||||
|
||||
public EmptyBoatDataSource() {
|
||||
}
|
||||
@@ -44,4 +46,15 @@ public class EmptyBoatDataSource implements BoatDataSource {
|
||||
public Map<Integer, Mark> getMarkerBoats() {
|
||||
return markerMap;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementSequenceNumber() {
|
||||
sequenceNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package shared.dataInput;
|
||||
|
||||
import network.Messages.Enums.RaceTypeEnum;
|
||||
import shared.model.CompoundMark;
|
||||
import shared.model.Corner;
|
||||
import shared.model.GPSCoordinate;
|
||||
import shared.model.Leg;
|
||||
import shared.xml.Race.XMLCorner;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
@@ -48,6 +50,12 @@ public class EmptyRaceDataSource implements RaceDataSource {
|
||||
*/
|
||||
private final List<Leg> legs = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Corners in race.
|
||||
*/
|
||||
private final List<Corner> corners = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The time that the race.xml file was created.
|
||||
@@ -76,6 +84,8 @@ public class EmptyRaceDataSource implements RaceDataSource {
|
||||
private RaceTypeEnum raceType = RaceTypeEnum.NOT_A_RACE_TYPE;
|
||||
|
||||
|
||||
private int sequenceNumber = 0;
|
||||
|
||||
|
||||
public EmptyRaceDataSource() {
|
||||
}
|
||||
@@ -98,6 +108,11 @@ public class EmptyRaceDataSource implements RaceDataSource {
|
||||
return legs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Corner> getCorners() {
|
||||
return corners;
|
||||
}
|
||||
|
||||
public List<CompoundMark> getCompoundMarks() {
|
||||
return new ArrayList<>(compoundMarkMap.values());
|
||||
}
|
||||
@@ -126,4 +141,14 @@ public class EmptyRaceDataSource implements RaceDataSource {
|
||||
public List<Integer> getParticipants() {
|
||||
return participants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementSequenceNumber() {
|
||||
sequenceNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ public class EmptyRegattaDataSource implements RegattaDataSource {
|
||||
|
||||
|
||||
|
||||
private int sequenceNumber = 0;
|
||||
|
||||
|
||||
public EmptyRegattaDataSource() {
|
||||
}
|
||||
@@ -119,4 +121,15 @@ public class EmptyRegattaDataSource implements RegattaDataSource {
|
||||
public GPSCoordinate getGPSCoordinate() {
|
||||
return new GPSCoordinate(centralLatitude, centralLongitude);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementSequenceNumber() {
|
||||
sequenceNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package shared.dataInput;
|
||||
|
||||
import network.Messages.Enums.RaceTypeEnum;
|
||||
import shared.model.CompoundMark;
|
||||
import shared.model.Corner;
|
||||
import shared.model.GPSCoordinate;
|
||||
import shared.model.Leg;
|
||||
import shared.xml.Race.XMLCorner;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
@@ -27,6 +29,12 @@ public interface RaceDataSource {
|
||||
*/
|
||||
List<Leg> getLegs();
|
||||
|
||||
/**
|
||||
* Returns the list of corners in the race - two adjacent corners form a leg.
|
||||
* @return List of corners in race.
|
||||
*/
|
||||
List<Corner> getCorners();
|
||||
|
||||
/**
|
||||
* Returns a list of coordinates representing the boundary of the race.
|
||||
* @return The boundary of the race.
|
||||
@@ -83,4 +91,16 @@ public interface RaceDataSource {
|
||||
* @return Bottom right GPS coordinate.
|
||||
*/
|
||||
GPSCoordinate getMapBottomRight();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sequence number associated with this data source. Used to indicate when it has changed.
|
||||
* @return Sequence number.
|
||||
*/
|
||||
int getSequenceNumber();
|
||||
|
||||
/**
|
||||
* Increments the sequence number for this data source. Used to indicate that it has changed.
|
||||
*/
|
||||
void incrementSequenceNumber();
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
private RaceTypeEnum raceType;
|
||||
|
||||
|
||||
private int sequenceNumber = 0;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -343,7 +345,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
|
||||
int cornerSeq = Integer.parseInt(getAttribute(cornerElement, "SeqID"));
|
||||
|
||||
cornersList.add(new Corner(cornerID, cornerSeq, "SP", 3));
|
||||
cornersList.add(new Corner(cornerID, cornerSeq, cornerRounding, 3));
|
||||
|
||||
//Gets the CompoundMark associated with this corner.
|
||||
CompoundMark lastCompoundMark = this.compoundMarkMap.get(cornerID);
|
||||
@@ -366,7 +368,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
|
||||
cornerSeq = Integer.parseInt(getAttribute(cornerElement, "SeqID"));
|
||||
|
||||
cornersList.add(new Corner(cornerID, cornerSeq, "Port", 3));
|
||||
cornersList.add(new Corner(cornerID, cornerSeq, getCompoundMarkRounding(cornerElement), 3));
|
||||
//gets the Rounding of this corner element
|
||||
cornerRounding = getCompoundMarkRounding(cornerElement);
|
||||
|
||||
@@ -488,7 +490,17 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
||||
return participants;
|
||||
}
|
||||
|
||||
public List<Corner> getCornersList() {
|
||||
public List<Corner> getCorners() {
|
||||
return cornersList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementSequenceNumber() {
|
||||
sequenceNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,5 +66,15 @@ public interface RegattaDataSource {
|
||||
float getMagneticVariation();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sequence number associated with this data source. Used to indicate when it has changed.
|
||||
* @return Sequence number.
|
||||
*/
|
||||
int getSequenceNumber();
|
||||
|
||||
/**
|
||||
* Increments the sequence number for this data source. Used to indicate that it has changed.
|
||||
*/
|
||||
void incrementSequenceNumber();
|
||||
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ public class RegattaXMLReader extends XMLReader implements RegattaDataSource {
|
||||
private float magneticVariation;
|
||||
|
||||
|
||||
private int sequenceNumber = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for Regatta XML using a file.
|
||||
@@ -209,4 +211,14 @@ public class RegattaXMLReader extends XMLReader implements RegattaDataSource {
|
||||
public GPSCoordinate getGPSCoordinate() {
|
||||
return new GPSCoordinate(centralLatitude, centralLongitude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementSequenceNumber() {
|
||||
sequenceNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,19 @@ public enum RoundingType {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getStringOf(RoundingType value) {
|
||||
switch (value) {
|
||||
case Port:
|
||||
return "Port";
|
||||
case Starboard:
|
||||
return "Starboard";
|
||||
case SP:
|
||||
return "SP";
|
||||
case PS:
|
||||
return "PS";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,20 +33,23 @@ public class Constants {
|
||||
* Frame periods are multiplied by this to get the amount of time a single frame represents.
|
||||
* E.g., frame period = 20ms, scale = 5, frame represents 20 * 5 = 100ms, and so boats are simulated for 100ms, even though only 20ms actually occurred.
|
||||
*/
|
||||
public static final int RaceTimeScale = 10;
|
||||
public static final int RaceTimeScale = 2;//10;
|
||||
|
||||
/**
|
||||
* The race pre-start time, in milliseconds. 3 minutes.
|
||||
*/
|
||||
public static final long RacePreStartTime = 1 * 10 * 1000;
|
||||
public static final long RacePreStartTime = 3 * 60 * 1000;
|
||||
|
||||
|
||||
/**
|
||||
* The race preparatory time, in milliseconds. 1 minutes.
|
||||
* The race preparatory time, in milliseconds. 1 minute.
|
||||
*/
|
||||
public static final long RacePreparatoryTime = 1 * 60 * 1000;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The number of milliseconds in one hour.
|
||||
* <br>
|
||||
|
||||
@@ -1,318 +0,0 @@
|
||||
package shared.model;
|
||||
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import mock.model.collider.ColliderRegistry;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
import network.Messages.Enums.RaceTypeEnum;
|
||||
import shared.dataInput.BoatDataSource;
|
||||
import shared.dataInput.RaceDataSource;
|
||||
import shared.dataInput.RegattaDataSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a yacht race.
|
||||
* Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}.
|
||||
*/
|
||||
public abstract class Race {
|
||||
/**
|
||||
* The source of race related data.
|
||||
*/
|
||||
protected RaceDataSource raceDataSource;
|
||||
/**
|
||||
* The source of boat related data.
|
||||
*/
|
||||
protected BoatDataSource boatDataSource;
|
||||
/**
|
||||
* The source of regatta related data.
|
||||
*/
|
||||
protected RegattaDataSource regattaDataSource;
|
||||
/**
|
||||
* A list of compound marks in the race.
|
||||
*/
|
||||
protected List<CompoundMark> compoundMarks;
|
||||
/**
|
||||
* A list of legs in the race.
|
||||
*/
|
||||
protected List<Leg> legs;
|
||||
/**
|
||||
* A list of coordinates describing the boundary of the course.
|
||||
*/
|
||||
protected List<GPSCoordinate> boundary;
|
||||
/**
|
||||
* The clock which tracks the race's start time, current time, and elapsed duration.
|
||||
*/
|
||||
protected RaceClock raceClock;
|
||||
/**
|
||||
* The race ID of the course.
|
||||
*/
|
||||
protected int raceId;
|
||||
/**
|
||||
* The name of the regatta.
|
||||
*/
|
||||
protected String regattaName;
|
||||
/**
|
||||
* The current status of the race.
|
||||
*/
|
||||
protected RaceStatusEnum raceStatusEnum;
|
||||
/**
|
||||
* The type of race this is.
|
||||
*/
|
||||
protected RaceTypeEnum raceType;
|
||||
/**
|
||||
* The race's wind.
|
||||
*/
|
||||
protected Property<Wind> raceWind = new SimpleObjectProperty<>();
|
||||
/**
|
||||
* Registry for all collider object in this race
|
||||
*/
|
||||
protected ColliderRegistry colliderRegistry;
|
||||
/**
|
||||
* The number of frames per second.
|
||||
* We essentially track the number of frames generated per second, over a one second period. When {@link #lastFpsResetTime} reaches 1 second, currentFps is reset.
|
||||
*/
|
||||
private int currentFps = 0;
|
||||
/**
|
||||
* The number of frames per second we generated over the last 1 second period.
|
||||
*/
|
||||
private IntegerProperty lastFps = new SimpleIntegerProperty(0);
|
||||
/**
|
||||
* The time, in milliseconds, since we last reset our {@link #currentFps} counter.
|
||||
*/
|
||||
private long lastFpsResetTime;
|
||||
|
||||
/**
|
||||
* Constructs a race object with a given BoatDataSource, RaceDataSource, and RegattaDataSource.
|
||||
* @param boatDataSource Data source for boat related data (yachts and marker boats).
|
||||
* @param raceDataSource Data source for race related data (participating boats, legs, etc...).
|
||||
* @param regattaDataSource Data source for race related data (course name, location, timezone, etc...).
|
||||
*/
|
||||
public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource) {
|
||||
|
||||
//Keep a reference to data sources.
|
||||
this.raceDataSource = raceDataSource;
|
||||
this.boatDataSource = boatDataSource;
|
||||
this.regattaDataSource = regattaDataSource;
|
||||
|
||||
//Marks.
|
||||
this.compoundMarks = raceDataSource.getCompoundMarks();
|
||||
//Boundaries.
|
||||
this.boundary = raceDataSource.getBoundary();
|
||||
//Legs.
|
||||
this.useLegsList(raceDataSource.getLegs());
|
||||
//Race ID.
|
||||
this.raceId = raceDataSource.getRaceId();
|
||||
//Regatta name.
|
||||
this.regattaName = regattaDataSource.getRegattaName();
|
||||
//Race clock.
|
||||
this.raceClock = new RaceClock(this.raceDataSource.getStartDateTime());
|
||||
//Race status.
|
||||
this.setRaceStatusEnum(RaceStatusEnum.NOT_ACTIVE);
|
||||
//Race type.
|
||||
this.raceType = raceDataSource.getRaceType();
|
||||
//Wind.
|
||||
this.setWind(Bearing.fromDegrees(0), 0);
|
||||
// Set up colliders
|
||||
this.colliderRegistry = new ColliderRegistry();
|
||||
|
||||
for(CompoundMark mark: compoundMarks) {
|
||||
colliderRegistry.addCollider(mark.getMark1());
|
||||
if(mark.getMark2() != null) colliderRegistry.addCollider(mark.getMark2());
|
||||
}
|
||||
}
|
||||
|
||||
public ColliderRegistry getColliderRegistry() {
|
||||
return colliderRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the boats in the race.
|
||||
* This sets their starting positions and current legs.
|
||||
*/
|
||||
protected abstract void initialiseBoats();
|
||||
|
||||
/**
|
||||
* Updates the race to use a new list of legs, and adds a dummy "Finish" leg at the end.
|
||||
* @param legs The new list of legs to use.
|
||||
*/
|
||||
protected void useLegsList(List<Leg> legs) {
|
||||
//We add a "dummy" leg at the end of the race.
|
||||
this.legs = legs;
|
||||
this.legs.add(new Leg("Finish", this.legs.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not a specific leg is the last leg in the race.
|
||||
* @param leg The leg to check.
|
||||
* @return Returns true if it is the last, false otherwise.
|
||||
*/
|
||||
protected boolean isLastLeg(Leg leg) {
|
||||
|
||||
//Get the last leg.
|
||||
Leg lastLeg = this.legs.get(this.legs.size() - 1);
|
||||
|
||||
//Check its ID.
|
||||
int lastLegID = lastLeg.getLegNumber();
|
||||
|
||||
//Get the specified leg's ID.
|
||||
int legID = leg.getLegNumber();
|
||||
|
||||
|
||||
//Check if they are the same.
|
||||
return legID == lastLegID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current race status.
|
||||
* @return The current race status.
|
||||
*/
|
||||
public RaceStatusEnum getRaceStatusEnum() {
|
||||
return raceStatusEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current race status.
|
||||
* @param raceStatusEnum The new status of the race.
|
||||
*/
|
||||
public void setRaceStatusEnum(RaceStatusEnum raceStatusEnum) {
|
||||
this.raceStatusEnum = raceStatusEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of race this is.
|
||||
* @return The type of race this is.
|
||||
*/
|
||||
public RaceTypeEnum getRaceType() {
|
||||
return raceType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the regatta.
|
||||
* @return The name of the regatta.
|
||||
*/
|
||||
public String getRegattaName() {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the race to have a specified wind bearing and speed.
|
||||
* @param windBearing New wind bearing.
|
||||
* @param windSpeedKnots New wind speed, in knots.
|
||||
*/
|
||||
protected void setWind(Bearing windBearing, double windSpeedKnots) {
|
||||
Wind wind = new Wind(windBearing, windSpeedKnots);
|
||||
setWind(wind);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the race to have a specified wind (bearing and speed).
|
||||
* @param wind New wind.
|
||||
*/
|
||||
protected void setWind(Wind wind) {
|
||||
this.raceWind.setValue(wind);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wind bearing.
|
||||
* @return The wind bearing.
|
||||
*/
|
||||
public Bearing getWindDirection() {
|
||||
return raceWind.getValue().getWindDirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wind speed.
|
||||
* Measured in knots.
|
||||
* @return The wind speed.
|
||||
*/
|
||||
public double getWindSpeed() {
|
||||
return raceWind.getValue().getWindSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RaceClock for this race.
|
||||
* This is used to track the start time, current time, and elapsed duration of the race.
|
||||
* @return The RaceClock for the race.
|
||||
*/
|
||||
public RaceClock getRaceClock() {
|
||||
return raceClock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RaceDataSource used for the race.
|
||||
* @return The RaceDataSource used for the race.
|
||||
*/
|
||||
public RaceDataSource getRaceDataSource() {
|
||||
return raceDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of legs in the race.
|
||||
* @return The number of legs in the race.
|
||||
*/
|
||||
public int getLegCount() {
|
||||
//We minus one, as we have added an extra "dummy" leg.
|
||||
return legs.size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the race boundary.
|
||||
* @return The race boundary.
|
||||
*/
|
||||
public List<GPSCoordinate> getBoundary() {
|
||||
return boundary;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the marks of the race.
|
||||
* @return Marks of the race.
|
||||
*/
|
||||
public List<CompoundMark> getCompoundMarks() {
|
||||
return compoundMarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the legs of the race.
|
||||
* @return Legs of the race.
|
||||
*/
|
||||
public List<Leg> getLegs() {
|
||||
return legs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fps property.
|
||||
* @return The fps property.
|
||||
*/
|
||||
public IntegerProperty fpsProperty() {
|
||||
return lastFps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the FPS counter, and adds timePeriod milliseconds to our FPS reset timer.
|
||||
* @param timePeriod Time, in milliseconds, to add to {@link #lastFpsResetTime}.
|
||||
*/
|
||||
protected void incrementFps(long timePeriod) {
|
||||
//Increment.
|
||||
this.currentFps++;
|
||||
|
||||
//Add period to timer.
|
||||
this.lastFpsResetTime += timePeriod;
|
||||
|
||||
//If we have reached 1 second period, snapshot the framerate and reset.
|
||||
if (this.lastFpsResetTime > 1000) {
|
||||
this.lastFps.set(this.currentFps);
|
||||
|
||||
this.currentFps = 0;
|
||||
this.lastFpsResetTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getRaceId() {
|
||||
return raceId;
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,20 @@ public abstract class RaceState {
|
||||
* @return List of mark boats.
|
||||
*/
|
||||
public List<Mark> getMarks() {
|
||||
return new ArrayList<>(boatDataSource.getMarkerBoats().values());
|
||||
//BoatDataSource contains a collection of Marks, and RaceDataSource contains a collection of Compound marks (which contain marks). RaceDataSource is the "definitive" source of mark data.
|
||||
List<Mark> marks = new ArrayList<>(getCompoundMarks().size() * 2);
|
||||
|
||||
for (CompoundMark compoundMark : getCompoundMarks()) {
|
||||
if (compoundMark.getMark1() != null) {
|
||||
marks.add(compoundMark.getMark1());
|
||||
}
|
||||
|
||||
if (compoundMark.getMark2() != null) {
|
||||
marks.add(compoundMark.getMark2());
|
||||
}
|
||||
}
|
||||
|
||||
return marks;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package shared.xml.Race;
|
||||
|
||||
import shared.dataInput.RaceDataSource;
|
||||
import shared.enums.RoundingType;
|
||||
import shared.model.CompoundMark;
|
||||
import shared.model.Corner;
|
||||
import shared.model.GPSCoordinate;
|
||||
import shared.model.Leg;
|
||||
import shared.xml.XMLUtilities;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Has functions to convert a {@link shared.dataInput.RaceDataSource} to an {@link XMLRace} object.
|
||||
*/
|
||||
public class RaceDataSourceToXML {
|
||||
|
||||
|
||||
/**
|
||||
* Converts a race data source to an XMLRace object.
|
||||
* @param raceDataSource The data source to convert.
|
||||
* @return The XMLRace file.
|
||||
*/
|
||||
public static XMLRace toXML(RaceDataSource raceDataSource) {
|
||||
|
||||
//Kind of ugly. Could be refactored/split up a bit.
|
||||
|
||||
|
||||
XMLRace race = new XMLRace();
|
||||
|
||||
|
||||
race.setRaceID(raceDataSource.getRaceId());
|
||||
race.setRaceType(raceDataSource.getRaceType().toString());
|
||||
|
||||
|
||||
race.setCreationTimeDate(raceDataSource.getCreationDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")));
|
||||
|
||||
|
||||
XMLRaceStartTime startTime = new XMLRaceStartTime();
|
||||
startTime.setPostpone(String.valueOf(raceDataSource.getPostponed()));
|
||||
startTime.setTime(raceDataSource.getStartDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")));
|
||||
race.setRaceStartTime(startTime);
|
||||
|
||||
|
||||
XMLParticipants participants = new XMLParticipants();
|
||||
participants.yacht = new ArrayList<>();
|
||||
for (int i : raceDataSource.getParticipants()) {
|
||||
XMLYacht yacht = new XMLYacht();
|
||||
yacht.setSourceID(i);
|
||||
participants.yacht.add(yacht);
|
||||
}
|
||||
race.setParticipants(participants);
|
||||
|
||||
|
||||
XMLCourseLimit courseLimit = new XMLCourseLimit();
|
||||
courseLimit.limit = new ArrayList<>();
|
||||
for (int i = 0; i < raceDataSource.getBoundary().size(); i++) {
|
||||
XMLLimit limit = new XMLLimit();
|
||||
limit.setLat(raceDataSource.getBoundary().get(i).getLatitude());
|
||||
limit.setLon(raceDataSource.getBoundary().get(i).getLongitude());
|
||||
limit.setSeqID(i + 1);
|
||||
courseLimit.limit.add(limit);
|
||||
}
|
||||
race.setCourseLimit(courseLimit);
|
||||
|
||||
|
||||
XMLCourse course = new XMLCourse();
|
||||
course.compoundMark = new ArrayList<>();
|
||||
for (CompoundMark compoundMark : raceDataSource.getCompoundMarks()) {
|
||||
XMLCompoundMark xmlCompoundMark = new XMLCompoundMark();
|
||||
xmlCompoundMark.setCompoundMarkID(compoundMark.getCompoundMarkID());
|
||||
xmlCompoundMark.setName(compoundMark.getName());
|
||||
|
||||
if (compoundMark.getMark1() != null) {
|
||||
XMLMark xmlMark = new XMLMark();
|
||||
xmlMark.setName(compoundMark.getMark1().getName());
|
||||
xmlMark.setSourceID(compoundMark.getMark1().getSourceID());
|
||||
xmlMark.setSeqId(1);
|
||||
xmlMark.setTargetLat(compoundMark.getMark1().getPosition().getLatitude());
|
||||
xmlMark.setTargetLng(compoundMark.getMark1().getPosition().getLongitude());
|
||||
|
||||
xmlCompoundMark.getMark().add(xmlMark);
|
||||
}
|
||||
if (compoundMark.getMark2() != null) {
|
||||
XMLMark xmlMark = new XMLMark();
|
||||
xmlMark.setName(compoundMark.getMark2().getName());
|
||||
xmlMark.setSourceID(compoundMark.getMark2().getSourceID());
|
||||
xmlMark.setSeqId(2);
|
||||
xmlMark.setTargetLat(compoundMark.getMark2().getPosition().getLatitude());
|
||||
xmlMark.setTargetLng(compoundMark.getMark2().getPosition().getLongitude());
|
||||
|
||||
xmlCompoundMark.getMark().add(xmlMark);
|
||||
}
|
||||
|
||||
course.compoundMark.add(xmlCompoundMark);
|
||||
}
|
||||
race.setCourse(course);
|
||||
|
||||
XMLCompoundMarkSequence compoundMarkSequence = new XMLCompoundMarkSequence();
|
||||
compoundMarkSequence.corner = new ArrayList<>();
|
||||
for (Corner corner : raceDataSource.getCorners()) {
|
||||
XMLCorner xmlCorner = new XMLCorner();
|
||||
xmlCorner.setZoneSize(corner.getZoneSize());
|
||||
xmlCorner.setSeqID(corner.getSeqID());
|
||||
xmlCorner.setCompoundMarkID(corner.getCompoundMarkID());
|
||||
xmlCorner.setRounding(corner.getRounding());
|
||||
|
||||
compoundMarkSequence.corner.add(xmlCorner);
|
||||
}
|
||||
race.setCompoundMarkSequence(compoundMarkSequence);
|
||||
|
||||
|
||||
return race;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a race data source to an xml string.
|
||||
* @param raceDataSource Data source to convert.
|
||||
* @return String containing xml file.
|
||||
* @throws JAXBException Thrown if it cannot be converted.
|
||||
*/
|
||||
public static String toString(RaceDataSource raceDataSource) throws JAXBException {
|
||||
XMLRace race = toXML(raceDataSource);
|
||||
return XMLUtilities.classToXML(race);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -20,10 +20,17 @@ import java.io.*;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Created by fwy13 on 13/08/17.
|
||||
* Contains utility functions to convert between xml files and xml class objects.
|
||||
*/
|
||||
public class XMLUtilities {
|
||||
|
||||
|
||||
/**
|
||||
* Converts an XML class object to an XML string.
|
||||
* @param o The XML class object to convert.
|
||||
* @return String containing the serialised XML data.
|
||||
* @throws JAXBException Thrown if the object is cannot be serialised to XML.
|
||||
*/
|
||||
public static String classToXML(Object o) throws JAXBException {
|
||||
JAXBContext context = JAXBContext.newInstance(o.getClass());
|
||||
Marshaller jaxbMarshaller = context.createMarshaller();
|
||||
@@ -49,14 +56,26 @@ public class XMLUtilities {
|
||||
return xmlToClass(document, schemaURL, c);
|
||||
}
|
||||
|
||||
public static Object xmlToClass(InputStream i, URL schemaURL, Class c) throws ParserConfigurationException, IOException, SAXException, JAXBException {
|
||||
/**
|
||||
* Converts an XML file to an XML class (e.g., {@link shared.xml.Race.XMLRace}).
|
||||
* @param i The input stream for the XML file.
|
||||
* @param schemaURL URL for the XML schema.
|
||||
* @param c The XML class to convert to.
|
||||
* @param <T> The XML class to convert to.
|
||||
* @return The XML class object.
|
||||
* @throws ParserConfigurationException
|
||||
* @throws IOException
|
||||
* @throws SAXException
|
||||
* @throws JAXBException
|
||||
*/
|
||||
public static <T> T xmlToClass(InputStream i, URL schemaURL, Class<T> c) throws ParserConfigurationException, IOException, SAXException, JAXBException {
|
||||
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
Document document = parser.parse(i);
|
||||
|
||||
return xmlToClass(document, schemaURL, c);
|
||||
}
|
||||
|
||||
public static Object xmlToClass(Document document, URL schemaURL, Class c) throws ParserConfigurationException, IOException, SAXException, JAXBException {
|
||||
public static <T> T xmlToClass(Document document, URL schemaURL, Class<T> c) throws ParserConfigurationException, IOException, SAXException, JAXBException {
|
||||
JAXBContext jc = JAXBContext.newInstance(c);
|
||||
Unmarshaller unmarshaller = jc.createUnmarshaller();
|
||||
|
||||
@@ -64,7 +83,7 @@ public class XMLUtilities {
|
||||
Schema schema = sf.newSchema(schemaURL);
|
||||
unmarshaller.setSchema(schema);
|
||||
|
||||
return unmarshaller.unmarshal(new DOMSource(document));
|
||||
return (T) unmarshaller.unmarshal(new DOMSource(document));
|
||||
}
|
||||
|
||||
public static boolean validateXML(String file, URL schemaURL){
|
||||
|
||||
@@ -0,0 +1,533 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2017.09.01 at 11:12:43 PM NZST
|
||||
//
|
||||
|
||||
|
||||
package shared.xml.boats;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for anonymous complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="Boats">
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="Boat" maxOccurs="unbounded">
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="GPSposition">
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <attribute name="X" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* <attribute name="Y" use="required" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* <attribute name="Z" use="required" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </element>
|
||||
* </sequence>
|
||||
* <attribute name="Type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="BoatName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="SourceID" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
|
||||
* <attribute name="HullNum" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="ShortName" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="ShapeID" type="{http://www.w3.org/2001/XMLSchema}int" />
|
||||
* <attribute name="StoweName" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </element>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </element>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "", propOrder = {
|
||||
"boats"
|
||||
})
|
||||
@XmlRootElement(name = "BoatConfig")
|
||||
public class BoatConfig {
|
||||
|
||||
@XmlElement(name = "Boats", required = true)
|
||||
protected BoatConfig.Boats boats;
|
||||
|
||||
/**
|
||||
* Gets the value of the boats property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link BoatConfig.Boats }
|
||||
*
|
||||
*/
|
||||
public BoatConfig.Boats getBoats() {
|
||||
return boats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the boats property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link BoatConfig.Boats }
|
||||
*
|
||||
*/
|
||||
public void setBoats(BoatConfig.Boats value) {
|
||||
this.boats = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for anonymous complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="Boat" maxOccurs="unbounded">
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="GPSposition">
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <attribute name="X" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* <attribute name="Y" use="required" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* <attribute name="Z" use="required" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </element>
|
||||
* </sequence>
|
||||
* <attribute name="Type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="BoatName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="SourceID" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
|
||||
* <attribute name="HullNum" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="ShortName" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="ShapeID" type="{http://www.w3.org/2001/XMLSchema}int" />
|
||||
* <attribute name="StoweName" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </element>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "", propOrder = {
|
||||
"boat"
|
||||
})
|
||||
public static class Boats {
|
||||
|
||||
@XmlElement(name = "Boat", required = true)
|
||||
protected List<BoatConfig.Boats.Boat> boat;
|
||||
|
||||
/**
|
||||
* Gets the value of the boat property.
|
||||
*
|
||||
* <p>
|
||||
* This accessor method returns a reference to the live list,
|
||||
* not a snapshot. Therefore any modification you make to the
|
||||
* returned list will be present inside the JAXB object.
|
||||
* This is why there is not a <CODE>set</CODE> method for the boat property.
|
||||
*
|
||||
* <p>
|
||||
* For example, to add a new item, do as follows:
|
||||
* <pre>
|
||||
* getBoat().add(newItem);
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Objects of the following type(s) are allowed in the list
|
||||
* {@link BoatConfig.Boats.Boat }
|
||||
*
|
||||
*
|
||||
*/
|
||||
public List<BoatConfig.Boats.Boat> getBoat() {
|
||||
if (boat == null) {
|
||||
boat = new ArrayList<BoatConfig.Boats.Boat>();
|
||||
}
|
||||
return this.boat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for anonymous complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="GPSposition">
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <attribute name="X" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* <attribute name="Y" use="required" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* <attribute name="Z" use="required" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </element>
|
||||
* </sequence>
|
||||
* <attribute name="Type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="BoatName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="SourceID" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
|
||||
* <attribute name="HullNum" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="ShortName" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="ShapeID" type="{http://www.w3.org/2001/XMLSchema}int" />
|
||||
* <attribute name="StoweName" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "", propOrder = {
|
||||
"gpSposition"
|
||||
})
|
||||
public static class Boat {
|
||||
|
||||
@XmlElement(name = "GPSposition", required = true)
|
||||
protected BoatConfig.Boats.Boat.GPSposition gpSposition;
|
||||
@XmlAttribute(name = "Type", required = true)
|
||||
protected String type;
|
||||
@XmlAttribute(name = "BoatName", required = true)
|
||||
protected String boatName;
|
||||
@XmlAttribute(name = "SourceID", required = true)
|
||||
protected int sourceID;
|
||||
@XmlAttribute(name = "HullNum")
|
||||
protected String hullNum;
|
||||
@XmlAttribute(name = "ShortName")
|
||||
protected String shortName;
|
||||
@XmlAttribute(name = "ShapeID")
|
||||
protected Integer shapeID;
|
||||
@XmlAttribute(name = "StoweName")
|
||||
protected String stoweName;
|
||||
|
||||
/**
|
||||
* Gets the value of the gpSposition property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link BoatConfig.Boats.Boat.GPSposition }
|
||||
*
|
||||
*/
|
||||
public BoatConfig.Boats.Boat.GPSposition getGPSposition() {
|
||||
return gpSposition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the gpSposition property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link BoatConfig.Boats.Boat.GPSposition }
|
||||
*
|
||||
*/
|
||||
public void setGPSposition(BoatConfig.Boats.Boat.GPSposition value) {
|
||||
this.gpSposition = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the type property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the type property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setType(String value) {
|
||||
this.type = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the boatName property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getBoatName() {
|
||||
return boatName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the boatName property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setBoatName(String value) {
|
||||
this.boatName = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the sourceID property.
|
||||
*
|
||||
*/
|
||||
public int getSourceID() {
|
||||
return sourceID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the sourceID property.
|
||||
*
|
||||
*/
|
||||
public void setSourceID(int value) {
|
||||
this.sourceID = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the hullNum property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getHullNum() {
|
||||
return hullNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the hullNum property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setHullNum(String value) {
|
||||
this.hullNum = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the shortName property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the shortName property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setShortName(String value) {
|
||||
this.shortName = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the shapeID property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link Integer }
|
||||
*
|
||||
*/
|
||||
public Integer getShapeID() {
|
||||
return shapeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the shapeID property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link Integer }
|
||||
*
|
||||
*/
|
||||
public void setShapeID(Integer value) {
|
||||
this.shapeID = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the stoweName property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getStoweName() {
|
||||
return stoweName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the stoweName property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setStoweName(String value) {
|
||||
this.stoweName = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for anonymous complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <attribute name="X" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* <attribute name="Y" use="required" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* <attribute name="Z" use="required" type="{http://www.w3.org/2001/XMLSchema}double" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "")
|
||||
public static class GPSposition {
|
||||
|
||||
@XmlAttribute(name = "X", required = true)
|
||||
protected Double x;
|
||||
@XmlAttribute(name = "Y", required = true)
|
||||
protected double y;
|
||||
@XmlAttribute(name = "Z", required = true)
|
||||
protected double z;
|
||||
|
||||
/**
|
||||
* Gets the value of the x property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link Double }
|
||||
*
|
||||
*/
|
||||
public Double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the x property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link Double }
|
||||
*
|
||||
*/
|
||||
public void setX(Double value) {
|
||||
this.x = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the y property.
|
||||
*
|
||||
*/
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the y property.
|
||||
*
|
||||
*/
|
||||
public void setY(double value) {
|
||||
this.y = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the z property.
|
||||
*
|
||||
*/
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the z property.
|
||||
*
|
||||
*/
|
||||
public void setZ(double value) {
|
||||
this.z = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package shared.xml.boats;
|
||||
|
||||
import shared.dataInput.BoatDataSource;
|
||||
import shared.dataInput.RaceDataSource;
|
||||
import shared.enums.RoundingType;
|
||||
import shared.model.Boat;
|
||||
import shared.model.CompoundMark;
|
||||
import shared.model.Leg;
|
||||
import shared.model.Mark;
|
||||
import shared.xml.Race.*;
|
||||
import shared.xml.XMLUtilities;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Has functions to convert a {@link shared.dataInput.BoatDataSource} to an {@link BoatConfig} object.
|
||||
*/
|
||||
public class BoatDataSourceToXML {
|
||||
|
||||
|
||||
/**
|
||||
* Converts a boat data source to an XMLRace object.
|
||||
* @param boatDataSource The data source to convert.
|
||||
* @return The XMLRace file.
|
||||
*/
|
||||
public static BoatConfig toXML(BoatDataSource boatDataSource) {
|
||||
BoatConfig boatConfig = new BoatConfig();
|
||||
|
||||
boatConfig.boats = new BoatConfig.Boats();
|
||||
boatConfig.boats.boat = new ArrayList<>();
|
||||
|
||||
|
||||
for (Boat boat : boatDataSource.getBoats().values()) {
|
||||
BoatConfig.Boats.Boat xmlBoat = new BoatConfig.Boats.Boat();
|
||||
|
||||
xmlBoat.setType("Yacht");
|
||||
xmlBoat.setBoatName(boat.getName());
|
||||
xmlBoat.setSourceID(boat.getSourceID());
|
||||
xmlBoat.setStoweName(boat.getCountry());
|
||||
xmlBoat.setShortName(boat.getCountry());
|
||||
|
||||
BoatConfig.Boats.Boat.GPSposition position = new BoatConfig.Boats.Boat.GPSposition();
|
||||
position.setX(boat.getPosition().getLongitude());
|
||||
position.setY(boat.getPosition().getLatitude());
|
||||
position.setZ(0);
|
||||
xmlBoat.setGPSposition(position);
|
||||
|
||||
boatConfig.boats.boat.add(xmlBoat);
|
||||
}
|
||||
|
||||
|
||||
for (Mark mark : boatDataSource.getMarkerBoats().values()) {
|
||||
BoatConfig.Boats.Boat xmlBoat = new BoatConfig.Boats.Boat();
|
||||
|
||||
xmlBoat.setType("Mark");
|
||||
xmlBoat.setBoatName(mark.getName());
|
||||
xmlBoat.setSourceID(mark.getSourceID());
|
||||
|
||||
BoatConfig.Boats.Boat.GPSposition position = new BoatConfig.Boats.Boat.GPSposition();
|
||||
position.setX(mark.getPosition().getLongitude());
|
||||
position.setY(mark.getPosition().getLatitude());
|
||||
position.setZ(0);
|
||||
xmlBoat.setGPSposition(position);
|
||||
|
||||
boatConfig.boats.boat.add(xmlBoat);
|
||||
}
|
||||
|
||||
return boatConfig;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a boat data source to an xml string.
|
||||
* @param boatDataSource Data source to convert.
|
||||
* @return String containing xml file.
|
||||
* @throws JAXBException Thrown if it cannot be converted.
|
||||
*/
|
||||
public static String toString(BoatDataSource boatDataSource) throws JAXBException {
|
||||
BoatConfig boats = toXML(boatDataSource);
|
||||
return XMLUtilities.classToXML(boats);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2017.09.01 at 11:12:43 PM NZST
|
||||
//
|
||||
|
||||
|
||||
package shared.xml.boats;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRegistry;
|
||||
|
||||
|
||||
/**
|
||||
* This object contains factory methods for each
|
||||
* Java content interface and Java element interface
|
||||
* generated in the aaa package.
|
||||
* <p>An ObjectFactory allows you to programatically
|
||||
* construct new instances of the Java representation
|
||||
* for XML content. The Java representation of XML
|
||||
* content can consist of schema derived interfaces
|
||||
* and classes representing the binding of schema
|
||||
* type definitions, element declarations and model
|
||||
* groups. Factory methods for each of these are
|
||||
* provided in this class.
|
||||
*
|
||||
*/
|
||||
@XmlRegistry
|
||||
public class ObjectFactory {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: aaa
|
||||
*
|
||||
*/
|
||||
public ObjectFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link BoatConfig }
|
||||
*
|
||||
*/
|
||||
public BoatConfig createBoatConfig() {
|
||||
return new BoatConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link BoatConfig.Boats }
|
||||
*
|
||||
*/
|
||||
public BoatConfig.Boats createBoatConfigBoats() {
|
||||
return new BoatConfig.Boats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link BoatConfig.Boats.Boat }
|
||||
*
|
||||
*/
|
||||
public BoatConfig.Boats.Boat createBoatConfigBoatsBoat() {
|
||||
return new BoatConfig.Boats.Boat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link BoatConfig.Boats.Boat.GPSposition }
|
||||
*
|
||||
*/
|
||||
public BoatConfig.Boats.Boat.GPSposition createBoatConfigBoatsBoatGPSposition() {
|
||||
return new BoatConfig.Boats.Boat.GPSposition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2017.09.01 at 10:37:23 PM NZST
|
||||
//
|
||||
|
||||
|
||||
package shared.xml.regatta;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRegistry;
|
||||
|
||||
|
||||
/**
|
||||
* This object contains factory methods for each
|
||||
* Java content interface and Java element interface
|
||||
* generated in the aaa package.
|
||||
* <p>An ObjectFactory allows you to programatically
|
||||
* construct new instances of the Java representation
|
||||
* for XML content. The Java representation of XML
|
||||
* content can consist of schema derived interfaces
|
||||
* and classes representing the binding of schema
|
||||
* type definitions, element declarations and model
|
||||
* groups. Factory methods for each of these are
|
||||
* provided in this class.
|
||||
*
|
||||
*/
|
||||
@XmlRegistry
|
||||
public class ObjectFactory {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: aaa
|
||||
*
|
||||
*/
|
||||
public ObjectFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link RegattaConfig }
|
||||
*
|
||||
*/
|
||||
public RegattaConfig createRegattaConfig() {
|
||||
return new RegattaConfig();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2017.09.01 at 10:37:23 PM NZST
|
||||
//
|
||||
|
||||
|
||||
package shared.xml.regatta;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for anonymous complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType>
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="RegattaID" type="{http://www.w3.org/2001/XMLSchema}int"/>
|
||||
* <element name="RegattaName" type="{http://www.w3.org/2001/XMLSchema}string"/>
|
||||
* <element name="CourseName" type="{http://www.w3.org/2001/XMLSchema}string"/>
|
||||
* <element name="CentralLatitude" type="{http://www.w3.org/2001/XMLSchema}double"/>
|
||||
* <element name="CentralLongitude" type="{http://www.w3.org/2001/XMLSchema}double"/>
|
||||
* <element name="CentralAltitude" type="{http://www.w3.org/2001/XMLSchema}double"/>
|
||||
* <element name="UtcOffset" type="{http://www.w3.org/2001/XMLSchema}double"/>
|
||||
* <element name="MagneticVariation" type="{http://www.w3.org/2001/XMLSchema}double"/>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "", propOrder = {
|
||||
"regattaID",
|
||||
"regattaName",
|
||||
"courseName",
|
||||
"centralLatitude",
|
||||
"centralLongitude",
|
||||
"centralAltitude",
|
||||
"utcOffset",
|
||||
"magneticVariation"
|
||||
})
|
||||
@XmlRootElement(name = "RegattaConfig")
|
||||
public class RegattaConfig {
|
||||
|
||||
@XmlElement(name = "RegattaID")
|
||||
protected int regattaID;
|
||||
@XmlElement(name = "RegattaName", required = true)
|
||||
protected String regattaName;
|
||||
@XmlElement(name = "CourseName", required = true)
|
||||
protected String courseName;
|
||||
@XmlElement(name = "CentralLatitude")
|
||||
protected double centralLatitude;
|
||||
@XmlElement(name = "CentralLongitude")
|
||||
protected double centralLongitude;
|
||||
@XmlElement(name = "CentralAltitude")
|
||||
protected double centralAltitude;
|
||||
@XmlElement(name = "UtcOffset")
|
||||
protected double utcOffset;
|
||||
@XmlElement(name = "MagneticVariation")
|
||||
protected double magneticVariation;
|
||||
|
||||
/**
|
||||
* Gets the value of the regattaID property.
|
||||
*
|
||||
*/
|
||||
public int getRegattaID() {
|
||||
return regattaID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the regattaID property.
|
||||
*
|
||||
*/
|
||||
public void setRegattaID(int value) {
|
||||
this.regattaID = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the regattaName property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getRegattaName() {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the regattaName property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setRegattaName(String value) {
|
||||
this.regattaName = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the courseName property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getCourseName() {
|
||||
return courseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the courseName property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setCourseName(String value) {
|
||||
this.courseName = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the centralLatitude property.
|
||||
*
|
||||
*/
|
||||
public double getCentralLatitude() {
|
||||
return centralLatitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the centralLatitude property.
|
||||
*
|
||||
*/
|
||||
public void setCentralLatitude(double value) {
|
||||
this.centralLatitude = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the centralLongitude property.
|
||||
*
|
||||
*/
|
||||
public double getCentralLongitude() {
|
||||
return centralLongitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the centralLongitude property.
|
||||
*
|
||||
*/
|
||||
public void setCentralLongitude(double value) {
|
||||
this.centralLongitude = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the centralAltitude property.
|
||||
*
|
||||
*/
|
||||
public double getCentralAltitude() {
|
||||
return centralAltitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the centralAltitude property.
|
||||
*
|
||||
*/
|
||||
public void setCentralAltitude(double value) {
|
||||
this.centralAltitude = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the utcOffset property.
|
||||
*
|
||||
*/
|
||||
public double getUtcOffset() {
|
||||
return utcOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the utcOffset property.
|
||||
*
|
||||
*/
|
||||
public void setUtcOffset(double value) {
|
||||
this.utcOffset = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the magneticVariation property.
|
||||
*
|
||||
*/
|
||||
public double getMagneticVariation() {
|
||||
return magneticVariation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the magneticVariation property.
|
||||
*
|
||||
*/
|
||||
public void setMagneticVariation(double value) {
|
||||
this.magneticVariation = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package shared.xml.regatta;
|
||||
|
||||
import shared.dataInput.RegattaDataSource;
|
||||
import shared.xml.Race.XMLRace;
|
||||
import shared.xml.XMLUtilities;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
/**
|
||||
* Has functions to convert a {@link shared.dataInput.RegattaDataSource} to an {@link RegattaConfig} object.
|
||||
*/
|
||||
public class RegattaDataSourceToXML {
|
||||
|
||||
|
||||
/**
|
||||
* Converts a regatta data source to an XMLRace object.
|
||||
* @param regattaDataSource The data source to convert.
|
||||
* @return The XMLRace file.
|
||||
*/
|
||||
public static RegattaConfig toXML(RegattaDataSource regattaDataSource) {
|
||||
|
||||
RegattaConfig regatta = new RegattaConfig();
|
||||
|
||||
regatta.setCentralAltitude(regattaDataSource.getCentralAltitude());
|
||||
regatta.setCentralLatitude(regattaDataSource.getCentralLatitude());
|
||||
regatta.setCentralLongitude(regattaDataSource.getCentralLongitude());
|
||||
|
||||
regatta.setCourseName(regattaDataSource.getCourseName());
|
||||
|
||||
regatta.setRegattaName(regattaDataSource.getRegattaName());
|
||||
|
||||
regatta.setMagneticVariation(regattaDataSource.getMagneticVariation());
|
||||
|
||||
regatta.setRegattaID(regattaDataSource.getRegattaID());
|
||||
|
||||
regatta.setUtcOffset(regattaDataSource.getUtcOffset());
|
||||
|
||||
return regatta;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a regatta data source to an xml string.
|
||||
* @param regattaDataSource Data source to convert.
|
||||
* @return String containing xml file.
|
||||
* @throws JAXBException Thrown if it cannot be converted.
|
||||
*/
|
||||
public static String toString(RegattaDataSource regattaDataSource) throws JAXBException {
|
||||
RegattaConfig regatta = toXML(regattaDataSource);
|
||||
return XMLUtilities.classToXML(regatta);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -71,8 +71,10 @@ public class FinishController extends Controller {
|
||||
|
||||
|
||||
//Winner label.
|
||||
raceWinnerLabel.setText("Winner: "+ boatNameColumn.getCellObservableValue(0).getValue());
|
||||
raceWinnerLabel.setWrapText(true);
|
||||
if (boats.size() > 0) {
|
||||
raceWinnerLabel.setText("Winner: " + boatNameColumn.getCellObservableValue(0).getValue());
|
||||
raceWinnerLabel.setWrapText(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
package visualiser.Controllers;
|
||||
|
||||
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.SplitPane;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.shape.Box;
|
||||
import javafx.scene.shape.Mesh;
|
||||
import javafx.scene.shape.MeshView;
|
||||
import javafx.scene.shape.Shape3D;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import mock.app.Event;
|
||||
import org.xml.sax.SAXException;
|
||||
import mock.exceptions.EventConstructionException;
|
||||
import shared.exceptions.InvalidBoatDataException;
|
||||
import shared.exceptions.InvalidRaceDataException;
|
||||
import shared.exceptions.InvalidRegattaDataException;
|
||||
import shared.exceptions.XMLReaderException;
|
||||
import visualiser.model.View3D;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -26,27 +34,70 @@ import java.util.logging.Logger;
|
||||
public class HostController extends Controller {
|
||||
|
||||
|
||||
@FXML
|
||||
TextField gameNameField;
|
||||
// @FXML
|
||||
// TextField gameNameField;
|
||||
//
|
||||
// @FXML
|
||||
// TextField hostNameField;
|
||||
|
||||
@FXML
|
||||
TextField hostNameField;
|
||||
private ImageView imageView;
|
||||
|
||||
@FXML
|
||||
AnchorPane hostWrapper;
|
||||
|
||||
@FXML
|
||||
AnchorPane imagePane;
|
||||
|
||||
@FXML
|
||||
SplitPane splitPane;
|
||||
|
||||
@FXML
|
||||
AnchorPane specPane;
|
||||
|
||||
@FXML
|
||||
GridPane playerContainer;
|
||||
|
||||
private Event game;
|
||||
|
||||
private View3D view3D;
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
ObservableList<Shape3D> shapes = FXCollections.observableArrayList();
|
||||
|
||||
view3D = new View3D();
|
||||
view3D.setItems(shapes);
|
||||
playerContainer.add(view3D, 0,0);
|
||||
|
||||
URL asset = HostController.class.getClassLoader().getResource("assets/V1.2 Complete Boat.stl");
|
||||
|
||||
StlMeshImporter importer = new StlMeshImporter();
|
||||
importer.read(asset);
|
||||
MeshView mesh = new MeshView(importer.getImport());
|
||||
shapes.add(mesh);
|
||||
|
||||
view3D.setPivot(mesh);
|
||||
view3D.setDistance(50);
|
||||
view3D.setYaw(45);
|
||||
view3D.setPitch(20);
|
||||
|
||||
Rotate rotation = new Rotate(0, Rotate.Y_AXIS);
|
||||
mesh.getTransforms().addAll(rotation, new Rotate(-90, Rotate.X_AXIS));
|
||||
|
||||
AnimationTimer rotate = new AnimationTimer() {
|
||||
@Override
|
||||
public void handle(long now) {
|
||||
rotation.setAngle(rotation.getAngle() + 0.1);
|
||||
}
|
||||
};
|
||||
rotate.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hosts a game
|
||||
* @throws IOException if socket cannot be connected to
|
||||
*/
|
||||
public void hostGamePressed() throws IOException{
|
||||
public void hostGamePressed() {
|
||||
try {
|
||||
this.game = new Event(false);
|
||||
connectSocket("localhost", 4942);
|
||||
@@ -81,12 +132,34 @@ public class HostController extends Controller {
|
||||
* Hosts a game.
|
||||
*/
|
||||
public void hostGame(){
|
||||
splitPane.setResizableWithParent(specPane, false);
|
||||
splitPane.lookupAll(".split-pane-divider").stream().forEach(div -> div.setMouseTransparent(true));
|
||||
imageView.fitWidthProperty().bind(imagePane.widthProperty());
|
||||
imageView.fitHeightProperty().bind(imagePane.heightProperty());
|
||||
hostWrapper.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu button pressed. Prompt alert then return to menu
|
||||
*/
|
||||
public void menuBtnPressed(){
|
||||
hostWrapper.setVisible(false);
|
||||
parent.enterTitle();
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setTitle("Quitting race");
|
||||
alert.setContentText("Do you wish to quit the race?");
|
||||
alert.setHeaderText("You are about to quit the race");
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
if(result.get() == ButtonType.OK){
|
||||
hostWrapper.setVisible(false);
|
||||
parent.enterTitle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start button pressed. Currently only prints out start
|
||||
*/
|
||||
public void startBtnPressed(){
|
||||
//System.out.println("Should start the race. This button is only visible for the host");
|
||||
hostGamePressed();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
package visualiser.Controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import visualiser.gameController.Keys.ControlKey;
|
||||
import visualiser.gameController.Keys.KeyFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static visualiser.app.App.keyFactory;
|
||||
|
||||
/**
|
||||
* Controller for the scene used to display and update current key bindings.
|
||||
*/
|
||||
public class KeyBindingsController {
|
||||
private @FXML Button btnSave;
|
||||
private @FXML Button btnCancel;
|
||||
private @FXML Button btnReset;
|
||||
private @FXML ListView lstControl;
|
||||
private @FXML ListView lstKey;
|
||||
private @FXML ListView lstDescription;
|
||||
private @FXML AnchorPane anchor;
|
||||
private KeyFactory newKeyFactory;
|
||||
private Boolean changed = false; // keyBindings have been modified
|
||||
private Button currentButton = null; // last button clicked
|
||||
|
||||
public void initialize(){
|
||||
// create new key factory to modify, keeping the existing one safe
|
||||
newKeyFactory = copyExistingFactory();
|
||||
initializeTable();
|
||||
populateTable();
|
||||
setKeyListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up table before populating it.
|
||||
* Set up includes headings, CSS styling and modifying default properties.
|
||||
*/
|
||||
public void initializeTable(){
|
||||
// set the headings for each column
|
||||
lstKey.getItems().add("Key");
|
||||
lstControl.getItems().add("Command");
|
||||
lstDescription.getItems().add("Description");
|
||||
lstKey.getSelectionModel().select(0);
|
||||
lstControl.getSelectionModel().select(0);
|
||||
lstDescription.getSelectionModel().select(0);
|
||||
|
||||
// add CSS stylesheet once the scene has been created
|
||||
lstKey.sceneProperty().addListener((obs, oldScene, newScene) -> {
|
||||
if (newScene != null) {
|
||||
newScene.getStylesheets().add("/css/keyBindings.css");
|
||||
}
|
||||
});
|
||||
|
||||
// stop the columns from being selectable, so only the buttons are
|
||||
lstKey.getSelectionModel().selectedItemProperty()
|
||||
.addListener((observable, oldvalue, newValue) ->
|
||||
Platform.runLater(() ->
|
||||
lstKey.getSelectionModel().select(0)));
|
||||
lstDescription.getSelectionModel().selectedItemProperty()
|
||||
.addListener((observable, oldvalue, newValue) ->
|
||||
Platform.runLater(() ->
|
||||
lstDescription.getSelectionModel().select(0)));
|
||||
lstControl.getSelectionModel().selectedItemProperty()
|
||||
.addListener((observable, oldvalue, newValue) ->
|
||||
Platform.runLater(() ->
|
||||
lstControl.getSelectionModel().select(0)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the table with commands and their key binding details.
|
||||
*/
|
||||
public void populateTable(){
|
||||
// add each command to the table
|
||||
for (Map.Entry<String, ControlKey> entry : newKeyFactory.getKeyState().entrySet()) {
|
||||
// create button for command
|
||||
Button button = new Button(entry.getKey());
|
||||
button.setMinWidth(120);
|
||||
button.setId(entry.getValue().toString());
|
||||
button.setOnAction(e -> currentButton = button);
|
||||
// display details for command in table
|
||||
lstControl.getItems().add(entry.getValue());
|
||||
lstKey.getItems().add(button);
|
||||
lstDescription.getItems().add(entry.getValue().getProtocolCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a copy of the {@link KeyFactory} that does not modify the original.
|
||||
* @return new keyfactory to be modified
|
||||
*/
|
||||
public KeyFactory copyExistingFactory(){
|
||||
newKeyFactory = new KeyFactory();
|
||||
Map<String, ControlKey> oldKeyState = keyFactory.getKeyState();
|
||||
Map<String, ControlKey> newKeyState = new HashMap<>();
|
||||
|
||||
// copy over commands and their keys
|
||||
for (Map.Entry<String, ControlKey> entry : oldKeyState.entrySet()){
|
||||
newKeyState.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
newKeyFactory.setKeyState(newKeyState);
|
||||
return newKeyFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a listener for the base anchorpane for key presses.
|
||||
* It updates the current key bindings of the {@link KeyFactory} if
|
||||
* required.
|
||||
*/
|
||||
public void setKeyListener(){
|
||||
anchor.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
// if esc, cancel current button click
|
||||
if (event.getCode() == KeyCode.ESCAPE){
|
||||
btnCancel.requestFocus();
|
||||
currentButton = null;
|
||||
}
|
||||
// if a button was clicked
|
||||
else if (currentButton != null) {
|
||||
// check if a button is already mapped to this key
|
||||
for (int i = 1; i < lstKey.getItems().size(); i++) {
|
||||
Button button = (Button)lstKey.getItems().get(i);
|
||||
// update buttons text and remove key binding from command
|
||||
if (button.getText().equals(event.getCode().toString())) {
|
||||
button.setText("");
|
||||
newKeyFactory.updateKey(button.getId(), button.getId());
|
||||
}
|
||||
}
|
||||
// update text on the button
|
||||
currentButton.setText(event.getCode().toString());
|
||||
// update the control key
|
||||
newKeyFactory.updateKey(event.getCode().toString(),
|
||||
currentButton.getId());
|
||||
// remove current button selection
|
||||
currentButton = null;
|
||||
changed = true;
|
||||
btnCancel.requestFocus();
|
||||
}
|
||||
event.consume();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel and exits the key bindings menu. Changes are not forced to be
|
||||
* saved or fixed if invalid, and instead are defaulted back to the last
|
||||
* successful saved state.
|
||||
*/
|
||||
public void cancel(){
|
||||
((Stage)btnCancel.getScene().getWindow()).close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all key bindings to the built-in defaults.
|
||||
*/
|
||||
public void reset(){
|
||||
lstKey.getItems().clear();
|
||||
lstControl.getItems().clear();
|
||||
lstDescription.getItems().clear();
|
||||
newKeyFactory = new KeyFactory();
|
||||
initializeTable();
|
||||
populateTable();
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace existing {@link KeyFactory} with the modified key bindings.
|
||||
*/
|
||||
public void save(){
|
||||
if (isFactoryValid()) {
|
||||
keyFactory = newKeyFactory;
|
||||
newKeyFactory = new KeyFactory();
|
||||
changed = false;
|
||||
keyFactory.save(); // save persistently
|
||||
loadNotification("Key bindings were successfully saved.", false);
|
||||
} else {
|
||||
loadNotification("One or more key bindings are missing. " +
|
||||
"Failed to save.", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the {@link KeyFactory} being modified is valid and that no
|
||||
* commands are missing a key binding.
|
||||
* @return True if valid, false if invalid
|
||||
*/
|
||||
public Boolean isFactoryValid(){
|
||||
for (Map.Entry<String, ControlKey> entry : newKeyFactory.getKeyState().entrySet
|
||||
()) {
|
||||
if (entry.getKey().toString()==entry.getValue().toString()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to stop a user from exiting key bindings without saving
|
||||
* their changes to the {@link KeyFactory}.
|
||||
* @param we {@link WindowEvent} close request to be consumed if settings
|
||||
* have not been successfully saved.
|
||||
*/
|
||||
public void onExit(WindowEvent we){
|
||||
// if modified KeyFactory hasn't been saved
|
||||
if (changed){
|
||||
loadNotification("Please cancel or save your changes before exiting" +
|
||||
".", true);
|
||||
we.consume();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a popup window giving confirmation/warning of user activity.
|
||||
* @param message the message to be displayed to the user
|
||||
* @param warning true if the message to be displayed is due to user error
|
||||
*/
|
||||
public void loadNotification(String message, Boolean warning){
|
||||
Parent root = null;
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource
|
||||
("/visualiser/scenes/notification.fxml"));
|
||||
try {
|
||||
root = loader.load();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
NotificationController controller = loader.getController();
|
||||
Stage stage = new Stage();
|
||||
stage.setScene(new Scene(root));
|
||||
stage.centerOnScreen();
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
stage.show();
|
||||
// displays given message in the window
|
||||
controller.setMessage(message, warning);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import java.util.ResourceBundle;
|
||||
public class LobbyController extends Controller {
|
||||
|
||||
@FXML
|
||||
AnchorPane lobbyWrapper;
|
||||
private AnchorPane lobbyWrapper;
|
||||
@FXML
|
||||
private TableView<RaceConnection> lobbyTable;
|
||||
@FXML
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package visualiser.Controllers;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* Controller for a popup notification regarding user activity.
|
||||
*/
|
||||
public class NotificationController {
|
||||
private @FXML Label lblDescription;
|
||||
private @FXML Text txtMessage;
|
||||
|
||||
/**
|
||||
* Closes the popup window once clicked.
|
||||
*/
|
||||
public void ok(){
|
||||
((Stage)lblDescription.getScene().getWindow()).close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the appropriate popup notification.
|
||||
* @param message message for the user
|
||||
* @param warning if true warning text shown, if false success text shown
|
||||
*/
|
||||
public void setMessage(String message, Boolean warning){
|
||||
lblDescription.setText(message);
|
||||
if (!warning){
|
||||
txtMessage.setText("Success!");
|
||||
txtMessage.setFill(Color.GREEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import javafx.collections.transformation.SortedList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.chart.LineChart;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
@@ -23,7 +22,6 @@ import shared.model.Leg;
|
||||
import visualiser.app.App;
|
||||
import visualiser.gameController.ControllerClient;
|
||||
import visualiser.gameController.Keys.ControlKey;
|
||||
import visualiser.gameController.Keys.KeyFactory;
|
||||
import visualiser.model.*;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -33,6 +31,7 @@ import java.util.ResourceBundle;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static visualiser.app.App.keyFactory;
|
||||
|
||||
|
||||
/**
|
||||
@@ -113,7 +112,7 @@ public class RaceController extends Controller {
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
KeyFactory keyFactory = KeyFactory.getFactory();
|
||||
// KeyFactory keyFactory = KeyFactory.getFactory();
|
||||
infoTableShow = true;
|
||||
|
||||
// Initialise keyboard handler
|
||||
@@ -356,7 +355,7 @@ public class RaceController extends Controller {
|
||||
private void initialiseRaceCanvas(VisualiserRaceEvent race) {
|
||||
|
||||
//Create canvas.
|
||||
raceCanvas = new ResizableRaceCanvas(race);
|
||||
raceCanvas = new ResizableRaceCanvas(race.getVisualiserRaceState());
|
||||
|
||||
//Set properties.
|
||||
raceCanvas.setMouseTransparent(true);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package visualiser.Controllers;
|
||||
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
@@ -9,6 +10,7 @@ import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import visualiser.app.App;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -81,25 +83,32 @@ public class TitleController extends Controller {
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when control button is pressed. New pop up window displaying controls
|
||||
*/
|
||||
public void controlBtnPressed(){
|
||||
FXMLLoader loader = new FXMLLoader();
|
||||
loader.setLocation(getClass().getResource("/visualiser/scenes/controls.fxml"));
|
||||
Parent layout;
|
||||
try {
|
||||
layout = loader.load();
|
||||
FXMLLoader loader = new FXMLLoader();
|
||||
loader.setLocation(getClass().getResource("/visualiser/scenes/keyBindings.fxml"));
|
||||
Parent layout = loader.load();
|
||||
Scene scene = new Scene(layout);
|
||||
Stage popupStage = new Stage();
|
||||
popupStage.setResizable(false);
|
||||
popupStage.setTitle("Game Controls");
|
||||
popupStage.initModality(Modality.WINDOW_MODAL);
|
||||
popupStage.centerOnScreen();
|
||||
popupStage.setScene(scene);
|
||||
popupStage.showAndWait();
|
||||
popupStage.show();
|
||||
KeyBindingsController controller = loader.getController();
|
||||
popupStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
|
||||
public void handle(WindowEvent we) {
|
||||
if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) {
|
||||
controller.onExit(we);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package visualiser.app;
|
||||
import javafx.animation.FadeTransition;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Task;
|
||||
@@ -15,7 +14,6 @@ import javafx.geometry.Rectangle2D;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.effect.DropShadow;
|
||||
import javafx.scene.image.Image;
|
||||
@@ -29,19 +27,17 @@ import javafx.stage.StageStyle;
|
||||
import javafx.stage.WindowEvent;
|
||||
import javafx.util.Duration;
|
||||
import visualiser.Controllers.MainController;
|
||||
|
||||
import java.io.IOException;
|
||||
import visualiser.gameController.Keys.KeyFactory;
|
||||
|
||||
public class App extends Application {
|
||||
|
||||
|
||||
private static Stage stage;
|
||||
private Pane splashLayout;
|
||||
private ProgressBar loadProgress;
|
||||
private Label progressText;
|
||||
private static final int SPLASH_WIDTH = 676;
|
||||
private static final int SPLASH_HEIGHT = 227;
|
||||
|
||||
public static KeyFactory keyFactory = new KeyFactory();
|
||||
public static App app;
|
||||
|
||||
/**
|
||||
@@ -55,6 +51,9 @@ public class App extends Application {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// load the user's personalised key bindings
|
||||
keyFactory.load();
|
||||
|
||||
ImageView splash = new ImageView(new Image(
|
||||
getClass().getClassLoader().getResourceAsStream("images/splashScreen.png")
|
||||
));
|
||||
@@ -96,15 +95,15 @@ public class App extends Application {
|
||||
);
|
||||
|
||||
updateMessage("Preparing ingredients . . .");
|
||||
Thread.sleep(1000);
|
||||
Thread.sleep(200);
|
||||
for (int i = 0; i < burgerFilling.size(); i++) {
|
||||
Thread.sleep(800);
|
||||
Thread.sleep(100);
|
||||
updateProgress(i + 1, burgerFilling.size());
|
||||
String nextFilling = burgerFilling.get(i);
|
||||
addedFilling.add(nextFilling);
|
||||
updateMessage("Adding the " + nextFilling + " . . .");
|
||||
}
|
||||
Thread.sleep(400);
|
||||
Thread.sleep(100);
|
||||
updateMessage("Burger's done!");
|
||||
|
||||
return addedFilling;
|
||||
|
||||
@@ -3,10 +3,11 @@ package visualiser.gameController;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.scene.Scene;
|
||||
import visualiser.gameController.Keys.ControlKey;
|
||||
import visualiser.gameController.Keys.KeyFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static visualiser.app.App.keyFactory;
|
||||
|
||||
/**
|
||||
* Class for checking what keys are currently being used
|
||||
*/
|
||||
@@ -18,7 +19,7 @@ public class InputChecker {
|
||||
* @param scene Scene the controller is to run in parallel with.
|
||||
*/
|
||||
public void runWithScene(Scene scene){
|
||||
KeyFactory keyFactory = KeyFactory.getFactory();
|
||||
// KeyFactory keyFactory = KeyFactory.getFactory();
|
||||
|
||||
scene.setOnKeyPressed(event -> {
|
||||
String codeString = event.getCode().toString();
|
||||
|
||||
@@ -9,11 +9,9 @@ public class DownWindKey extends ControlKey {
|
||||
|
||||
/**
|
||||
* Constructor for Control
|
||||
* @param name name of the key
|
||||
*
|
||||
*/
|
||||
public DownWindKey(String name) {
|
||||
super(name, BoatActionEnum.DOWNWIND);
|
||||
public DownWindKey() {
|
||||
super("Downwind", BoatActionEnum.DOWNWIND);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package visualiser.gameController.Keys;
|
||||
|
||||
import java.beans.XMLDecoder;
|
||||
import java.beans.XMLEncoder;
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -13,30 +16,17 @@ public class KeyFactory {
|
||||
private Map<String, ControlKey> keyState;
|
||||
|
||||
/**
|
||||
* Singleton instance to enforce consistent key state
|
||||
* Constructor for key state, set up initial state of each action.
|
||||
*/
|
||||
private static KeyFactory theFactory = new KeyFactory();
|
||||
|
||||
/**
|
||||
* Singleton constructor for key state, set up initial state of each action.
|
||||
*/
|
||||
private KeyFactory() {
|
||||
public KeyFactory() {
|
||||
this.keyState = new HashMap<>();
|
||||
keyState.put("Z", new ZoomInKey("Zoom In"));
|
||||
keyState.put("X", new ZoomOutKey("Zoom Out"));
|
||||
keyState.put("SPACE", new VMGKey("VMG"));
|
||||
keyState.put("SHIFT", new SailsToggleKey("Toggle Sails"));
|
||||
keyState.put("ENTER", new TackGybeKey("Tack/Gybe"));
|
||||
keyState.put("UP", new UpWindKey("Upwind"));
|
||||
keyState.put("DOWN", new DownWindKey("Downwind"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get singleton instance of KeyFactory to interact with key state
|
||||
* @return automatically constructed KeyFactory
|
||||
*/
|
||||
public static KeyFactory getFactory() {
|
||||
return theFactory;
|
||||
keyState.put("Z", new ZoomInKey());
|
||||
keyState.put("X", new ZoomOutKey());
|
||||
keyState.put("SPACE", new VMGKey());
|
||||
keyState.put("SHIFT", new SailsToggleKey());
|
||||
keyState.put("ENTER", new TackGybeKey());
|
||||
keyState.put("UP", new UpWindKey());
|
||||
keyState.put("DOWN", new DownWindKey());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,4 +38,86 @@ public class KeyFactory {
|
||||
return keyState.get(key);
|
||||
}
|
||||
|
||||
public Map<String, ControlKey> getKeyState() {
|
||||
return keyState;
|
||||
}
|
||||
|
||||
public void setKeyState(Map<String, ControlKey> keyState) {
|
||||
this.keyState = keyState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the key bound to a particular command in the keystate.
|
||||
* @param newKey the new key value for the command
|
||||
* @param command the command to be updated
|
||||
*/
|
||||
public void updateKey(String newKey, String command){
|
||||
ControlKey controlKey = null;
|
||||
String oldKey = null;
|
||||
for (Map.Entry<String, ControlKey> entry : keyState.entrySet()) {
|
||||
// if this is the correct command
|
||||
if (entry.getValue().toString()==command){
|
||||
controlKey = entry.getValue();
|
||||
oldKey = entry.getKey();
|
||||
}
|
||||
}
|
||||
keyState.remove(oldKey, controlKey);
|
||||
keyState.put(newKey, controlKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persistently saves the keybindings the user has set.
|
||||
*/
|
||||
public void save(){
|
||||
try {
|
||||
// open the filestream and write to it
|
||||
FileOutputStream fos = new FileOutputStream(
|
||||
System.getProperty("user.dir")+
|
||||
"/settings/keyBindings.xml");
|
||||
XMLEncoder xmlEncoder = new XMLEncoder(fos);
|
||||
xmlEncoder.writeObject(this.keyState);
|
||||
xmlEncoder.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the persistently saved keybindings the user has set.
|
||||
*/
|
||||
public void load(){
|
||||
try {
|
||||
// access settings folder, create if it doesn't exist
|
||||
File settingsFolder = new File(
|
||||
System.getProperty("user.dir")+"/settings");
|
||||
if (!settingsFolder.exists()){
|
||||
settingsFolder.mkdir();
|
||||
}
|
||||
|
||||
// access keybindings xml file, create if it doesn't exist
|
||||
File savedFile = new File(
|
||||
settingsFolder+"/keyBindings.xml");
|
||||
if (!savedFile.exists()){
|
||||
savedFile.createNewFile();
|
||||
FileOutputStream fos = new FileOutputStream(savedFile);
|
||||
XMLEncoder xmlEncoder = new XMLEncoder(fos);
|
||||
xmlEncoder.writeObject(this.keyState);
|
||||
xmlEncoder.close();
|
||||
}
|
||||
|
||||
// load the saved settings into the game
|
||||
InputStream is = new FileInputStream(savedFile);
|
||||
XMLDecoder xmlDecoder = new XMLDecoder(is);
|
||||
Map<String, ControlKey> savedKeyState
|
||||
= (Map<String, ControlKey>)xmlDecoder.readObject();
|
||||
xmlDecoder.close();
|
||||
this.keyState = savedKeyState;
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,11 +10,9 @@ public class SailsToggleKey extends ControlKey {
|
||||
|
||||
/**
|
||||
* Constructor for Control
|
||||
* @param name name of the key
|
||||
*
|
||||
*/
|
||||
public SailsToggleKey(String name) {
|
||||
super(name, BoatActionEnum.NOT_A_STATUS);
|
||||
public SailsToggleKey() {
|
||||
super("Toggle Sails", BoatActionEnum.NOT_A_STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,11 +9,9 @@ public class TackGybeKey extends ControlKey {
|
||||
|
||||
/**
|
||||
* Constructor for Control
|
||||
* @param name name of the key
|
||||
*
|
||||
*/
|
||||
public TackGybeKey(String name) {
|
||||
super(name, BoatActionEnum.TACK_GYBE);
|
||||
public TackGybeKey() {
|
||||
super("Tack/Gybe", BoatActionEnum.TACK_GYBE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,11 +9,9 @@ public class UpWindKey extends ControlKey {
|
||||
|
||||
/**
|
||||
* Constructor for Control
|
||||
* @param name name of the key
|
||||
*
|
||||
*/
|
||||
public UpWindKey(String name) {
|
||||
super(name, BoatActionEnum.UPWIND);
|
||||
public UpWindKey() {
|
||||
super("Upwind", BoatActionEnum.UPWIND);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package visualiser.gameController.Keys;
|
||||
|
||||
import javafx.scene.input.KeyCode;
|
||||
import network.Messages.Enums.BoatActionEnum;
|
||||
|
||||
/**
|
||||
@@ -10,11 +9,9 @@ public class VMGKey extends ControlKey{
|
||||
|
||||
/**
|
||||
* Constructor for Control
|
||||
*
|
||||
* @param name name of the key
|
||||
*/
|
||||
public VMGKey(String name) {
|
||||
super(name, BoatActionEnum.AUTO_PILOT);
|
||||
public VMGKey() {
|
||||
super("VMG", BoatActionEnum.AUTO_PILOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,8 +5,8 @@ package visualiser.gameController.Keys;
|
||||
*/
|
||||
public class ZoomInKey extends ControlKey {
|
||||
|
||||
public ZoomInKey(String name) {
|
||||
super(name);
|
||||
public ZoomInKey() {
|
||||
super("Zoom In");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,11 +7,9 @@ public class ZoomOutKey extends ControlKey{
|
||||
|
||||
/**
|
||||
* Constructor for Control
|
||||
* @param name name of the key
|
||||
*
|
||||
*/
|
||||
public ZoomOutKey(String name) {
|
||||
super(name);
|
||||
public ZoomOutKey() {
|
||||
super("Zoom Out");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package visualiser.model;
|
||||
|
||||
import com.interactivemesh.jfx.importer.Importer;
|
||||
import javafx.scene.layout.Pane;
|
||||
|
||||
/**
|
||||
* Created by fwy13 on 29/08/17.
|
||||
*/
|
||||
public class BoatDisplay3D extends Pane {
|
||||
|
||||
|
||||
public BoatDisplay3D(String filePath){
|
||||
super();
|
||||
// Shape3D
|
||||
// this.getChildren().add();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,9 +39,9 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
private Image sailsLuff = new Image("/images/sailsLuff.gif", 25, 10, false, false);
|
||||
|
||||
/**
|
||||
* The race we read data from and draw.
|
||||
* The race state we read data from and draw.
|
||||
*/
|
||||
private VisualiserRaceEvent visualiserRace;
|
||||
private VisualiserRaceState raceState;
|
||||
|
||||
|
||||
private boolean annoName = true;
|
||||
@@ -56,14 +56,14 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
|
||||
/**
|
||||
* Constructs a {@link ResizableRaceCanvas} using a given {@link VisualiserRaceEvent}.
|
||||
* @param visualiserRace The race that data is read from in order to be drawn.
|
||||
* @param raceState The race state to be drawn.
|
||||
*/
|
||||
public ResizableRaceCanvas(VisualiserRaceEvent visualiserRace) {
|
||||
public ResizableRaceCanvas(VisualiserRaceState raceState) {
|
||||
super();
|
||||
|
||||
this.visualiserRace = visualiserRace;
|
||||
this.raceState = raceState;
|
||||
|
||||
RaceDataSource raceData = visualiserRace.getVisualiserRaceState().getRaceDataSource();
|
||||
RaceDataSource raceData = raceState.getRaceDataSource();
|
||||
|
||||
double lat1 = raceData.getMapTopLeft().getLatitude();
|
||||
double long1 = raceData.getMapTopLeft().getLongitude();
|
||||
@@ -276,8 +276,8 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
boat.getCountry(),
|
||||
boat.getCurrentSpeed(),
|
||||
this.map.convertGPS(boat.getPosition()),
|
||||
boat.getTimeToNextMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()),
|
||||
boat.getTimeSinceLastMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()),
|
||||
boat.getTimeToNextMarkFormatted(raceState.getRaceClock().getCurrentTime()),
|
||||
boat.getTimeSinceLastMarkFormatted(raceState.getRaceClock().getCurrentTime()),
|
||||
Color.BLACK,
|
||||
20 );
|
||||
|
||||
@@ -291,7 +291,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
*/
|
||||
private void drawBoats() {
|
||||
|
||||
List<VisualiserBoat> boats = new ArrayList<>(visualiserRace.getVisualiserRaceState().getBoats());
|
||||
List<VisualiserBoat> boats = new ArrayList<>(raceState.getBoats());
|
||||
//Sort to ensure we draw boats in consistent order.
|
||||
boats.sort(Comparator.comparingInt(Boat::getSourceID));
|
||||
|
||||
@@ -510,7 +510,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
*/
|
||||
private void drawMarks() {
|
||||
|
||||
for (Mark mark : new ArrayList<>(visualiserRace.getVisualiserRaceState().getMarks())) {
|
||||
for (Mark mark : new ArrayList<>(raceState.getMarks())) {
|
||||
drawMark(mark);
|
||||
}
|
||||
}
|
||||
@@ -574,7 +574,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
|
||||
|
||||
//Calculate the screen coordinates of the boundary.
|
||||
List<GPSCoordinate> boundary = new ArrayList<>(visualiserRace.getVisualiserRaceState().getBoundary());
|
||||
List<GPSCoordinate> boundary = new ArrayList<>(raceState.getBoundary());
|
||||
double[] xpoints = new double[boundary.size()];
|
||||
double[] ypoints = new double[boundary.size()];
|
||||
|
||||
@@ -601,8 +601,8 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
public void drawRace() {
|
||||
|
||||
//Update RaceMap with new GPS values of race.
|
||||
this.map.setGPSTopLeft(visualiserRace.getVisualiserRaceState().getRaceDataSource().getMapTopLeft());
|
||||
this.map.setGPSBotRight(visualiserRace.getVisualiserRaceState().getRaceDataSource().getMapBottomRight());
|
||||
this.map.setGPSTopLeft(raceState.getRaceDataSource().getMapTopLeft());
|
||||
this.map.setGPSBotRight(raceState.getRaceDataSource().getMapBottomRight());
|
||||
|
||||
|
||||
clear();
|
||||
@@ -627,7 +627,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
||||
* draws a transparent line around the course that shows the paths boats must travel
|
||||
*/
|
||||
public void drawRaceLine(){
|
||||
List<Leg> legs = this.visualiserRace.getVisualiserRaceState().getLegs();
|
||||
List<Leg> legs = raceState.getLegs();
|
||||
GPSCoordinate legStartPoint = legs.get(0).getStartCompoundMark().getAverageGPSCoordinate();
|
||||
GPSCoordinate nextStartPoint;
|
||||
for (int i = 0; i < legs.size() -1; i++) {
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
package visualiser.model;
|
||||
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.PerspectiveCamera;
|
||||
import javafx.scene.SubScene;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Shape3D;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Translate;
|
||||
|
||||
/**
|
||||
* Control for rendering 3D objects visible through a PerspectiveCamera. Implements Adapter Pattern to
|
||||
* interface with camera, and allows clients to add shapes to the scene. All scenes contain sea plane and
|
||||
* sky box, whose textures are set with special methods.
|
||||
*/
|
||||
public class View3D extends Pane {
|
||||
/**
|
||||
* Observable list of renderable items
|
||||
*/
|
||||
private ObservableList<Shape3D> items;
|
||||
/**
|
||||
* Rendering container for shapes
|
||||
*/
|
||||
private Group world;
|
||||
/**
|
||||
* Near limit of view frustum
|
||||
*/
|
||||
private double nearClip;
|
||||
/**
|
||||
* Far limit of view frustum
|
||||
*/
|
||||
private double farClip;
|
||||
/**
|
||||
* Position camera pivots around
|
||||
*/
|
||||
private Translate pivot;
|
||||
/**
|
||||
* Distance of camera from pivot point
|
||||
*/
|
||||
private Translate distance;
|
||||
/**
|
||||
* Angle along ground between z-axis and camera
|
||||
*/
|
||||
private Rotate yaw;
|
||||
/**
|
||||
* Angle between ground plane and camera direction
|
||||
*/
|
||||
private Rotate pitch;
|
||||
|
||||
/**
|
||||
* Default constructor for View3D. Sets up Scene and PerspectiveCamera.
|
||||
*/
|
||||
public View3D() {
|
||||
world = new Group();
|
||||
|
||||
SubScene scene = new SubScene(world, 300, 300);
|
||||
scene.widthProperty().bind(this.widthProperty());
|
||||
scene.heightProperty().bind(this.heightProperty());
|
||||
scene.setFill(Color.BLACK);
|
||||
|
||||
scene.setCamera(buildCamera());
|
||||
|
||||
this.getChildren().add(scene);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up camera view frustum and binds transformations
|
||||
* @return perspective camera
|
||||
*/
|
||||
private PerspectiveCamera buildCamera() {
|
||||
PerspectiveCamera camera = new PerspectiveCamera(true);
|
||||
|
||||
// Set up view frustum
|
||||
nearClip = 0.1;
|
||||
farClip = 1000.0;
|
||||
camera.setNearClip(nearClip);
|
||||
camera.setFarClip(farClip);
|
||||
|
||||
// Set up transformations
|
||||
pivot = new Translate();
|
||||
distance = new Translate();
|
||||
yaw = new Rotate(0, Rotate.Y_AXIS);
|
||||
pitch = new Rotate(0, Rotate.X_AXIS);
|
||||
camera.getTransforms().addAll(pivot, yaw, pitch, distance);
|
||||
|
||||
return camera;
|
||||
}
|
||||
|
||||
public void setItems(ObservableList<Shape3D> items) {
|
||||
this.items = items;
|
||||
this.items.addListener((ListChangeListener<? super Shape3D>) c -> {
|
||||
while(c.next()) {
|
||||
if (c.wasRemoved() || c.wasAdded()) {
|
||||
for (Shape3D shape : c.getRemoved()) world.getChildren().remove(shape);
|
||||
for (Shape3D shape : c.getAddedSubList()) world.getChildren().add(shape);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setNearClip(double nearClip) {
|
||||
this.nearClip = nearClip;
|
||||
}
|
||||
|
||||
public void setFarClip(double farClip) {
|
||||
this.farClip = farClip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set object to centre on camera
|
||||
* @param pivot centred object
|
||||
*/
|
||||
public void setPivot(Shape3D pivot) {
|
||||
this.pivot.setX(pivot.getTranslateX());
|
||||
this.pivot.setY(pivot.getTranslateY());
|
||||
this.pivot.setZ(pivot.getTranslateZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set distance of camera from pivot
|
||||
* @param distance in units
|
||||
*/
|
||||
public void setDistance(double distance) {
|
||||
this.distance.setZ(-distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set angle of camera from z-axis along ground
|
||||
* @param yaw in degrees
|
||||
*/
|
||||
public void setYaw(double yaw) {
|
||||
this.yaw.setAngle(yaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set elevation of camera
|
||||
* @param pitch in degrees
|
||||
*/
|
||||
public void setPitch(double pitch) {
|
||||
this.pitch.setAngle(-pitch);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,45 @@
|
||||
.list-view .list-cell {
|
||||
-fx-cell-size: 40;
|
||||
-fx-font-family: "Tahoma";
|
||||
-fx-background-color: #fffff0;
|
||||
-fx-alignment: center;
|
||||
}
|
||||
|
||||
.list-view .list-cell:even {
|
||||
-fx-background-color: #ffffdc;
|
||||
}
|
||||
|
||||
.list-view .list-cell:selected {
|
||||
-fx-background-color: #f9e5c3;
|
||||
-fx-font-family: "Comic Sans MS";
|
||||
-fx-font-weight: bold;
|
||||
-fx-font-size: 18;
|
||||
}
|
||||
|
||||
.button {
|
||||
-fx-background-color: linear-gradient(#acdeff 50%, #a9c8ff 100%);
|
||||
-fx-background-radius: 4px;
|
||||
-fx-border-radius: 4px;
|
||||
-fx-text-fill: #242d35;
|
||||
-fx-font-size: 12px;
|
||||
-fx-font-family: "Courier New";
|
||||
-fx-border-color: #a9c8ff;
|
||||
}
|
||||
|
||||
.button:focused {
|
||||
-fx-background-color: white;
|
||||
-fx-border-color: #0056bd;
|
||||
}
|
||||
|
||||
#anchor {
|
||||
-fx-background-color: #fdfac3;
|
||||
}
|
||||
#menu{
|
||||
-fx-background-color: linear-gradient(#acdeff 50%, #a9c8ff 100%);
|
||||
-fx-background-radius: 4px;
|
||||
-fx-border-radius: 4px;
|
||||
-fx-text-fill: #242d35;
|
||||
-fx-font-size: 12px;
|
||||
-fx-font-family: "Verdana";
|
||||
-fx-border-color: #a9c8ff;
|
||||
}
|
||||
@@ -32,7 +32,6 @@
|
||||
<GPSposition X= "-64.83626" Y="32.317257" Z="0"/>
|
||||
</Boat>
|
||||
|
||||
<!--Participants-->
|
||||
<!--Participants-->
|
||||
<Boat BoatName="Emirates Team New Zealand" HullNum="RG01" ShapeID="0" ShortName="NZL" SourceID="121" StoweName="NZL" Type="Yacht">
|
||||
<GPSposition X="-64.854304" Y="32.296577" Z="0"/>
|
||||
|
||||
@@ -5,12 +5,7 @@
|
||||
<CreationTimeDate>RACE_CREATION_TIME</CreationTimeDate>
|
||||
<RaceStartTime Postpone="false" Time="RACE_START_TIME"/>
|
||||
<Participants>
|
||||
<Yacht SourceID="121"/>
|
||||
<Yacht SourceID="122"/>
|
||||
<Yacht SourceID="123"/>
|
||||
<Yacht SourceID="124"/>
|
||||
<Yacht SourceID="125"/>
|
||||
<Yacht SourceID="126"/>
|
||||
|
||||
</Participants>
|
||||
<CompoundMarkSequence>
|
||||
<Corner SeqID="1" CompoundMarkID="1" Rounding="SP" ZoneSize="3" />
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="BoatConfig">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Boats">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Boat" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="GPSposition" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="X" type="xs:double" use="required"/>
|
||||
<xs:attribute name="Y" type="xs:double" use="required"/>
|
||||
<xs:attribute name="Z" type="xs:double" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Type" type="xs:string" use="required"/>
|
||||
<xs:attribute name="BoatName" type="xs:string" use="required"/>
|
||||
<xs:attribute name="SourceID" type="xs:int" use="required"/>
|
||||
<xs:attribute name="HullNum" type="xs:string"/>
|
||||
<xs:attribute name="ShortName" type="xs:string"/>
|
||||
<xs:attribute name="ShapeID" type="xs:int"/>
|
||||
<xs:attribute name="StoweName" type="xs:string"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="RegattaConfig">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element type="xs:int" name="RegattaID" minOccurs="1"/>
|
||||
<xs:element type="xs:string" name="RegattaName" minOccurs="1"/>
|
||||
<xs:element type="xs:string" name="CourseName" minOccurs="1"/>
|
||||
<xs:element name="CentralLatitude" type="xs:double" minOccurs="1"/>
|
||||
<xs:element name="CentralLongitude" type="xs:double" minOccurs="1"/>
|
||||
<xs:element name="CentralAltitude" type="xs:double" minOccurs="1"/>
|
||||
<xs:element type="xs:double" name="UtcOffset" minOccurs="1"/>
|
||||
<xs:element name="MagneticVariation" type="xs:double" minOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -1,40 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--<?xml version="1.0" encoding="UTF-8"?>-->
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<AnchorPane fx:id="hostWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" visible="false" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.HostController">
|
||||
<children>
|
||||
<GridPane AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Button fx:id="hostGameBtn" mnemonicParsing="false" onAction="#hostGamePressed" text="Start Game" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2">
|
||||
<font>
|
||||
<Font size="20.0" />
|
||||
</font>
|
||||
</Button>
|
||||
<Label text="Address: 127.0.0.1" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
|
||||
<font>
|
||||
<Font size="17.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label text="Port: 4942" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1">
|
||||
<font>
|
||||
<Font size="17.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Button mnemonicParsing="false" onAction="#menuBtnPressed" text="Main Menu" GridPane.halignment="CENTER" />
|
||||
</children>
|
||||
</GridPane>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<!--<?import java.lang.*?>-->
|
||||
<!--<?import javafx.scene.control.*?>-->
|
||||
<!--<?import javafx.scene.text.*?>-->
|
||||
<!--<?import javafx.scene.control.Button?>-->
|
||||
<!--<?import javafx.scene.control.Label?>-->
|
||||
<!--<?import javafx.scene.layout.*?>-->
|
||||
<!--<?import javafx.scene.text.Font?>-->
|
||||
|
||||
<!--<AnchorPane fx:id="hostWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" visible="false" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">-->
|
||||
<!--<children>-->
|
||||
<!--<GridPane AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">-->
|
||||
<!--<columnConstraints>-->
|
||||
<!--<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />-->
|
||||
<!--<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />-->
|
||||
<!--<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />-->
|
||||
<!--</columnConstraints>-->
|
||||
<!--<rowConstraints>-->
|
||||
<!--<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />-->
|
||||
<!--<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />-->
|
||||
<!--<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />-->
|
||||
<!--</rowConstraints>-->
|
||||
<!--<children>-->
|
||||
<!--<Button fx:id="hostGameBtn" mnemonicParsing="false" onAction="#hostGamePressed" text="Start Game" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2">-->
|
||||
<!--<font>-->
|
||||
<!--<Font size="20.0" />-->
|
||||
<!--</font>-->
|
||||
<!--</Button>-->
|
||||
<!--<Label text="Address: 127.0.0.1" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">-->
|
||||
<!--<font>-->
|
||||
<!--<Font size="17.0" />-->
|
||||
<!--</font>-->
|
||||
<!--</Label>-->
|
||||
<!--<Label text="Port: 4942" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1">-->
|
||||
<!--<font>-->
|
||||
<!--<Font size="17.0" />-->
|
||||
<!--</font>-->
|
||||
<!--</Label>-->
|
||||
<!--<Button mnemonicParsing="false" onAction="#menuBtnPressed" text="Main Menu" GridPane.halignment="CENTER" />-->
|
||||
<!--</children>-->
|
||||
<!--</GridPane>-->
|
||||
<!--</children>-->
|
||||
<!--</AnchorPane>-->
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.SplitPane?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?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?>
|
||||
|
||||
<AnchorPane fx:id="hostWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.HostController">
|
||||
<children>
|
||||
<SplitPane fx:id="splitPane" dividerPositions="0.7724935732647815" layoutX="580.0" layoutY="129.0" prefHeight="160.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<items>
|
||||
<AnchorPane fx:id="imagePane" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
|
||||
<children>
|
||||
<ImageView fx:id="imageView" fitHeight="376.0" fitWidth="597.0" nodeOrientation="INHERIT" pickOnBounds="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<image>
|
||||
<Image url="@../images/lobby.gif" />
|
||||
</image></ImageView>
|
||||
<GridPane style="-fx-background-color: rgba(0, 0, 0, 0.5);" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="50.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="10.0" prefHeight="173.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="50.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Button mnemonicParsing="false" onAction="#menuBtnPressed" text="Quit" GridPane.rowIndex="2">
|
||||
<GridPane.margin>
|
||||
<Insets left="20.0" />
|
||||
</GridPane.margin>
|
||||
</Button>
|
||||
<Button alignment="CENTER_RIGHT" contentDisplay="RIGHT" mnemonicParsing="false" onAction="#startBtnPressed" text="Start Game" GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="2">
|
||||
<GridPane.margin>
|
||||
<Insets right="20.0" />
|
||||
</GridPane.margin>
|
||||
</Button>
|
||||
<Label alignment="CENTER" contentDisplay="CENTER" text="Map: MapNameHere" textFill="WHITE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2">
|
||||
<font>
|
||||
<Font size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<GridPane fx:id="playerContainer" GridPane.columnSpan="3" GridPane.rowIndex="1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
</GridPane>
|
||||
</children>
|
||||
</GridPane>
|
||||
<Label alignment="TOP_CENTER" text="Get Ready For The Next Race" textFill="#fffdfd" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="20.0">
|
||||
<font>
|
||||
<Font size="22.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane fx:id="specPane" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
|
||||
<children>
|
||||
<TableView prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: rgba(60, 60, 60, 1);" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<columns>
|
||||
<TableColumn prefWidth="173.0" text="Spectators" />
|
||||
</columns>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||
</columnResizePolicy>
|
||||
</TableView>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</items>
|
||||
</SplitPane>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ListView?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<AnchorPane id="anchor" fx:id="anchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="471.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.KeyBindingsController">
|
||||
<children>
|
||||
<Label fx:id="lblTitle" layoutX="172.0" layoutY="14.0" text="Key Bindings">
|
||||
<font>
|
||||
<Font name="Comic Sans MS" size="44.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Button id="menu" fx:id="btnCancel" layoutX="430.0" layoutY="428.0"
|
||||
mnemonicParsing="false" onAction="#cancel" prefWidth="160.0" text="Cancel" AnchorPane.bottomAnchor="18.0" AnchorPane.rightAnchor="20.0" />
|
||||
<ListView fx:id="lstControl" focusTraversable="false" layoutX="27.0" layoutY="88.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="322.0" prefWidth="150.0" />
|
||||
<ListView fx:id="lstKey" focusTraversable="false" layoutX="176.0" layoutY="88.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="322.0" prefWidth="150.0" />
|
||||
<ListView fx:id="lstDescription" focusTraversable="false" layoutX="325.0" layoutY="88.0" prefHeight="322.0" prefWidth="250.0" />
|
||||
<Button id="menu" fx:id="btnSave" layoutX="220.0" layoutY="428.0" mnemonicParsing="false" onAction="#save" prefWidth="160.0" text="Save" AnchorPane.bottomAnchor="18.0" />
|
||||
<Button id="menu" fx:id="btnReset" layoutX="20.0" layoutY="428.0" mnemonicParsing="false" onAction="#reset" prefWidth="160.0" text="Reset to Default" AnchorPane.bottomAnchor="18.0" AnchorPane.leftAnchor="20.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
@@ -7,7 +7,7 @@
|
||||
<fx:include fx:id="start" source="start.fxml" />
|
||||
<fx:include fx:id="connection" source="connect.fxml" />
|
||||
<fx:include fx:id="finish" source="finish.fxml" />
|
||||
<fx:include fx:id="host" source="hostgame.fxml" />
|
||||
<fx:include fx:id="host" source="hostlobby.fxml" />
|
||||
<fx:include fx:id="title" source="titleScreen.fxml" />
|
||||
<fx:include fx:id="lobby" source="lobby.fxml" />
|
||||
</children>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
|
||||
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.NotificationController">
|
||||
<children>
|
||||
<Button fx:id="btnOk" layoutX="110.0" layoutY="65.0" mnemonicParsing="false" onAction="#ok" prefWidth="80.0" text="Ok" />
|
||||
<Text fx:id="txtMessage" fill="RED" layoutY="23.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Warning!" textAlignment="CENTER" wrappingWidth="300.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="14.0" />
|
||||
</font>
|
||||
</Text>
|
||||
<Label fx:id="lblDescription" alignment="CENTER" layoutY="36.0" prefHeight="17.0" prefWidth="300.0" textAlignment="CENTER" />
|
||||
</children>
|
||||
</Pane>
|
||||
@@ -1,61 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--<?xml version="1.0" encoding="UTF-8"?>-->
|
||||
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<AnchorPane fx:id="connectionWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.ConnectionController">
|
||||
<children>
|
||||
<GridPane AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Button fx:id="hostGameTitleBtn" maxWidth="204.0" mnemonicParsing="false" text="Host Game" GridPane.halignment="LEFT" GridPane.rowIndex="1">
|
||||
<font>
|
||||
<Font size="20.0" />
|
||||
</font>
|
||||
<GridPane.margin>
|
||||
<Insets left="50.0" />
|
||||
</GridPane.margin>
|
||||
</Button>
|
||||
<Button fx:id="connectGameBtn" maxWidth="204.0" mnemonicParsing="false" text="Connect to Game" GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="1">
|
||||
<font>
|
||||
<Font size="20.0" />
|
||||
</font>
|
||||
<GridPane.margin>
|
||||
<Insets right="50.0" />
|
||||
</GridPane.margin>
|
||||
</Button>
|
||||
<RadioButton fx:id="nightRadioBtn" mnemonicParsing="false" text="Night Mode" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets bottom="-50.0" />
|
||||
</padding>
|
||||
<GridPane.margin>
|
||||
<Insets left="80.0" />
|
||||
</GridPane.margin>
|
||||
</RadioButton>
|
||||
<RadioButton fx:id="dayRadioBtn" mnemonicParsing="false" text="Day Mode" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets top="-50.0" />
|
||||
</padding>
|
||||
<GridPane.margin>
|
||||
<Insets left="80.0" />
|
||||
</GridPane.margin>
|
||||
</RadioButton>
|
||||
<Label text="Game" textAlignment="CENTER" GridPane.columnIndex="1" GridPane.halignment="CENTER">
|
||||
<font>
|
||||
<Font size="60.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</GridPane>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<!--<?import javafx.geometry.*?>-->
|
||||
<!--<?import javafx.scene.control.*?>-->
|
||||
<!--<?import javafx.scene.layout.*?>-->
|
||||
<!--<?import javafx.scene.text.Font?>-->
|
||||
<!--<AnchorPane fx:id="connectionWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.ConnectionController">-->
|
||||
<!--<children>-->
|
||||
<!--<GridPane AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">-->
|
||||
<!--<columnConstraints>-->
|
||||
<!--<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />-->
|
||||
<!--<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />-->
|
||||
<!--<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />-->
|
||||
<!--</columnConstraints>-->
|
||||
<!--<rowConstraints>-->
|
||||
<!--<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />-->
|
||||
<!--<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />-->
|
||||
<!--<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />-->
|
||||
<!--</rowConstraints>-->
|
||||
<!--<children>-->
|
||||
<!--<Button fx:id="hostGameTitleBtn" maxWidth="204.0" mnemonicParsing="false" text="Host Game" GridPane.halignment="LEFT" GridPane.rowIndex="1">-->
|
||||
<!--<font>-->
|
||||
<!--<Font size="20.0" />-->
|
||||
<!--</font>-->
|
||||
<!--<GridPane.margin>-->
|
||||
<!--<Insets left="50.0" />-->
|
||||
<!--</GridPane.margin>-->
|
||||
<!--</Button>-->
|
||||
<!--<Button fx:id="connectGameBtn" maxWidth="204.0" mnemonicParsing="false" text="Connect to Game" GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="1">-->
|
||||
<!--<font>-->
|
||||
<!--<Font size="20.0" />-->
|
||||
<!--</font>-->
|
||||
<!--<GridPane.margin>-->
|
||||
<!--<Insets right="50.0" />-->
|
||||
<!--</GridPane.margin>-->
|
||||
<!--</Button>-->
|
||||
<!--<RadioButton fx:id="nightRadioBtn" mnemonicParsing="false" text="Night Mode" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowIndex="2">-->
|
||||
<!--<padding>-->
|
||||
<!--<Insets bottom="-50.0" />-->
|
||||
<!--</padding>-->
|
||||
<!--<GridPane.margin>-->
|
||||
<!--<Insets left="80.0" />-->
|
||||
<!--</GridPane.margin>-->
|
||||
<!--</RadioButton>-->
|
||||
<!--<RadioButton fx:id="dayRadioBtn" mnemonicParsing="false" text="Day Mode" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowIndex="2">-->
|
||||
<!--<padding>-->
|
||||
<!--<Insets top="-50.0" />-->
|
||||
<!--</padding>-->
|
||||
<!--<GridPane.margin>-->
|
||||
<!--<Insets left="80.0" />-->
|
||||
<!--</GridPane.margin>-->
|
||||
<!--</RadioButton>-->
|
||||
<!--<Label text="Game" textAlignment="CENTER" GridPane.columnIndex="1" GridPane.halignment="CENTER">-->
|
||||
<!--<font>-->
|
||||
<!--<Font size="60.0" />-->
|
||||
<!--</font>-->
|
||||
<!--</Label>-->
|
||||
<!--</children>-->
|
||||
<!--</GridPane>-->
|
||||
<!--</children>-->
|
||||
<!--</AnchorPane>-->
|
||||
|
||||
@@ -3,6 +3,7 @@ package mock.model;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import shared.model.Bearing;
|
||||
import shared.model.Boat;
|
||||
import shared.model.GPSCoordinate;
|
||||
import shared.model.Mark;
|
||||
|
||||
@@ -13,6 +14,13 @@ public class MockBoatTest {
|
||||
private Mark near;
|
||||
private Mark far;
|
||||
|
||||
|
||||
public static MockBoat createMockBoat() {
|
||||
Boat boat = new Boat(121, "Test boat", "TS");
|
||||
MockBoat mockBoat = new MockBoat(boat, null);
|
||||
return mockBoat;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
boat = new MockBoat(0, "Bob", "NZ", null);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mock.model;
|
||||
|
||||
import mock.exceptions.SourceIDAllocationException;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -15,30 +16,16 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class SourceIdAllocatorTest {
|
||||
|
||||
/**
|
||||
* This is the list of source IDs that we start with.
|
||||
*/
|
||||
private List<Integer> originalSourceIDs;
|
||||
|
||||
/**
|
||||
* Used to allocate source IDs.
|
||||
*/
|
||||
private MockRace mockRace;
|
||||
private SourceIdAllocator sourceIdAllocator;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
originalSourceIDs = new ArrayList<>();
|
||||
originalSourceIDs.add(120);
|
||||
originalSourceIDs.add(121);
|
||||
originalSourceIDs.add(122);
|
||||
originalSourceIDs.add(123);
|
||||
originalSourceIDs.add(124);
|
||||
originalSourceIDs.add(125);
|
||||
mockRace = MockRaceTest.createMockRace();
|
||||
|
||||
|
||||
sourceIdAllocator = new SourceIdAllocator(originalSourceIDs);
|
||||
sourceIdAllocator = new SourceIdAllocator(mockRace);
|
||||
|
||||
}
|
||||
|
||||
@@ -49,11 +36,12 @@ public class SourceIdAllocatorTest {
|
||||
@Test
|
||||
public void emptyAllocationTest() {
|
||||
|
||||
SourceIdAllocator allocator = new SourceIdAllocator(new ArrayList<>());
|
||||
mockRace.getRaceDataSource().getParticipants().removeAll(mockRace.getBoatDataSource().getBoats().keySet());
|
||||
mockRace.getRaceDataSource().getParticipants().addAll(mockRace.getBoatDataSource().getBoats().keySet());
|
||||
|
||||
|
||||
try {
|
||||
int sourceID = allocator.allocateSourceID();
|
||||
int sourceID = sourceIdAllocator.allocateSourceID();
|
||||
|
||||
fail("Exception should have been thrown, but wasn't.");
|
||||
|
||||
@@ -73,6 +61,7 @@ public class SourceIdAllocatorTest {
|
||||
@Test
|
||||
public void allocationTest() throws Exception {
|
||||
|
||||
mockRace.setRaceStatusEnum(RaceStatusEnum.PRESTART);
|
||||
|
||||
int sourceID = sourceIdAllocator.allocateSourceID();
|
||||
|
||||
@@ -108,10 +97,7 @@ public class SourceIdAllocatorTest {
|
||||
@Test
|
||||
public void reallocationTest() throws Exception {
|
||||
|
||||
List<Integer> sourceIDList = new ArrayList<>();
|
||||
sourceIDList.add(123);
|
||||
|
||||
SourceIdAllocator sourceIdAllocator = new SourceIdAllocator(sourceIDList);
|
||||
mockRace.setRaceStatusEnum(RaceStatusEnum.PRESTART);
|
||||
|
||||
//Allocate.
|
||||
int sourceID = sourceIdAllocator.allocateSourceID();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package mock.model.commandFactory;
|
||||
|
||||
import mock.exceptions.CommandConstructionException;
|
||||
import mock.model.MockBoat;
|
||||
import mock.model.MockRace;
|
||||
import mock.model.MockRaceTest;
|
||||
import mock.exceptions.SourceIDAllocationException;
|
||||
import mock.model.*;
|
||||
import network.Messages.BoatAction;
|
||||
import network.Messages.Enums.BoatActionEnum;
|
||||
import network.Messages.Enums.RaceStatusEnum;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import shared.exceptions.InvalidBoatDataException;
|
||||
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock;
|
||||
*/
|
||||
public class WindCommandTest {
|
||||
private MockRace race;
|
||||
private SourceIdAllocator allocator;
|
||||
private MockBoat boat;
|
||||
private Command upwind;
|
||||
private Command downwind;
|
||||
@@ -29,12 +30,15 @@ public class WindCommandTest {
|
||||
private double offset = 3.0;
|
||||
|
||||
@Before
|
||||
public void setUp() throws CommandConstructionException, InvalidBoatDataException, InvalidRegattaDataException, InvalidRaceDataException {
|
||||
public void setUp() throws CommandConstructionException, InvalidBoatDataException, InvalidRegattaDataException, InvalidRaceDataException, SourceIDAllocationException {
|
||||
race = MockRaceTest.createMockRace();
|
||||
|
||||
allocator = new SourceIdAllocator(race);
|
||||
race.setRaceStatusEnum(RaceStatusEnum.PRESTART);
|
||||
allocator.allocateSourceID();
|
||||
boat = race.getBoats().get(0);
|
||||
|
||||
|
||||
|
||||
//when(race.getWindDirection()).thenReturn(Bearing.fromDegrees(0.0));
|
||||
boat.setBearing(Bearing.fromDegrees(45.0));
|
||||
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public class ConnectionToServerParticipantTest {
|
||||
incomingCommands.put(command);
|
||||
|
||||
//Need to wait for connection thread to execute commands.
|
||||
Thread.sleep(250);
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals(ConnectionToServerState.CONNECTED, connectionToServer.getConnectionState());
|
||||
assertTrue(connectionToServer.getJoinAcceptance() != null);
|
||||
|
||||
@@ -5,12 +5,6 @@
|
||||
<CreationTimeDate>2017-04-19T15:30:00+1200</CreationTimeDate>
|
||||
<RaceStartTime Postpone="false" Time="2017-04-19T15:33:00+1200"/>
|
||||
<Participants>
|
||||
<Yacht SourceID="121"/>
|
||||
<Yacht SourceID="122"/>
|
||||
<Yacht SourceID="123"/>
|
||||
<Yacht SourceID="124"/>
|
||||
<Yacht SourceID="125"/>
|
||||
<Yacht SourceID="126"/>
|
||||
</Participants>
|
||||
<CompoundMarkSequence>
|
||||
<Corner CompoundMarkID="1" SeqID="1"/>
|
||||
@@ -54,4 +48,4 @@
|
||||
<Limit Lat="32.297164" Lon="-64.856394" SeqID="10"/>
|
||||
<Limit Lat="32.296148" Lon="-64.849184" SeqID="11"/>
|
||||
</CourseLimit>
|
||||
</Race>
|
||||
</Race>
|
||||
|
||||
Reference in New Issue
Block a user