# Conflicts: # racevisionGame/src/main/java/mock/app/Event.java # racevisionGame/src/main/java/visualiser/Controllers/HostController.java # racevisionGame/src/main/java/visualiser/model/View3D.javamain
commit
4c2ab9cc9a
@ -0,0 +1,204 @@
|
||||
package mock.model;
|
||||
|
||||
import shared.model.Bearing;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* New Polars are the revampe of the old Polars class which interpolates the data after being parsed from the Polar Parser
|
||||
* There can only be one NewPolars instance stored statically however if a boat does happen to have a special case it can be assigned.
|
||||
*/
|
||||
public class NewPolars {
|
||||
|
||||
|
||||
//true wind speed, <true wind angle, best boat angle>
|
||||
private static Map<Double, TreeMap<Double, Double>> polars = new TreeMap<>();
|
||||
|
||||
public static NewPolars newPolars = null;
|
||||
|
||||
public NewPolars(){
|
||||
newPolars = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add polars from the polar table
|
||||
* @param trueWindSpeed True Wind Speed that the true wind angle and speed corresponds to
|
||||
* @param trueWindAngle True Wind Angle of the race
|
||||
* @param boatSpeed The speed the boat should be going at given the true wind angle
|
||||
*/
|
||||
public static void addPolars(double trueWindSpeed, Bearing trueWindAngle, double boatSpeed){
|
||||
double tws = trueWindSpeed;
|
||||
double bs = boatSpeed;
|
||||
double twa = trueWindAngle.degrees();
|
||||
if (!polars.containsKey(tws)){
|
||||
polars.put(tws, new TreeMap<>());
|
||||
}
|
||||
polars.get(tws).putIfAbsent(twa, bs);
|
||||
polars.get(tws).putIfAbsent(360d - twa, bs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linearly Interpolates this should only be called once per parsing of a polar table
|
||||
*/
|
||||
public static void linearInterpolatePolars(){
|
||||
TreeMap<Double, Double> prevTWS = null;
|
||||
TreeMap<Double, TreeMap<Double, Double>> iterablePolars = new TreeMap<>(polars);
|
||||
//this loop averages out the speed between tow angles
|
||||
//Example: Pair one: 0 degrees, 0 knots
|
||||
// Pair two: 3 degrees, 6 knots
|
||||
//This loop will add
|
||||
//Pair one: 0 degrees, 0 knots
|
||||
//Pair two: 1 degrees, 2 knots
|
||||
//Pair three: 2 degrees, 4 knots
|
||||
//Pair four: 3 degrees, 6 knots
|
||||
for (double windSpeed: iterablePolars.keySet()){
|
||||
TreeMap<Double, Double> tws = iterablePolars.get(windSpeed);
|
||||
|
||||
if (prevTWS == null){
|
||||
prevTWS = tws;
|
||||
continue;
|
||||
}
|
||||
|
||||
double previousTWA = -1;
|
||||
TreeMap<Double, Double> iterableTWS = new TreeMap<>(tws);
|
||||
|
||||
for (double twa: iterableTWS.keySet()){
|
||||
if (previousTWA == -1){
|
||||
previousTWA = twa;
|
||||
continue;
|
||||
}
|
||||
double twaDiff = twa - previousTWA;
|
||||
double speedDiff = iterableTWS.get(twa) - iterableTWS.get(previousTWA);
|
||||
double prevSpeed = iterableTWS.get(previousTWA);
|
||||
double diff = speedDiff/twaDiff;
|
||||
|
||||
for (double i = previousTWA; i < twa; i ++){
|
||||
double mult = i - previousTWA;
|
||||
double newSpeed = diff * mult + prevSpeed;
|
||||
tws.put(i, newSpeed);
|
||||
}
|
||||
previousTWA = twa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double getClosest(double value, Set<Double> set){
|
||||
double closestVal = 0;
|
||||
double smallestDiff = Double.MAX_VALUE;
|
||||
for (double d: set){
|
||||
double diff = Math.abs(value - d);
|
||||
if (diff < smallestDiff){
|
||||
closestVal = d;
|
||||
smallestDiff = diff;
|
||||
}
|
||||
}
|
||||
return closestVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which quadrant degrees are in
|
||||
* 0/360 Degrees
|
||||
* Quadrant 4 | Quadrant 1
|
||||
* -----------------------
|
||||
* Quadrant 3 | Quadrant 2
|
||||
* @param degrees
|
||||
* @return
|
||||
*/
|
||||
private static int getQuadrant(double degrees){
|
||||
return (int) modulateAngle(degrees) / 90 + 1;
|
||||
}
|
||||
|
||||
private static double getBestSpeedInQuadrant(int quad, Map<Double, Double> set){
|
||||
double min = (quad - 1)* 90;
|
||||
double max = quad * 90;
|
||||
double maxAngle = 0;
|
||||
double maxSpeed = 0;
|
||||
double dupAngle = 0;
|
||||
//DupAngle will average the angle between maxAngles that have the same speed
|
||||
//Example: if 150 degrees, 180 degrees, and 210 degrees all go at 10 knots
|
||||
//then the average will be taken as (150 + 210) / 2 and the angle will be returned on that.
|
||||
for (Double s: set.keySet()){
|
||||
if (s >= min && s < max){
|
||||
if (set.get(s) > maxSpeed){
|
||||
dupAngle = 0;
|
||||
maxAngle = s;
|
||||
maxSpeed = set.get(s);
|
||||
} else if (set.get(s) == maxSpeed){
|
||||
dupAngle = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dupAngle != 0 ){
|
||||
return getClosest((dupAngle + maxAngle) / 2, set.keySet());
|
||||
}
|
||||
return maxAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the best VMG that the boat can change to given it's current diagonal heading direction.
|
||||
* @param trueWindAngle True wind angle of the race
|
||||
* @param trueWindSpeed True wind speed of the race
|
||||
* @param boatAngle Angle that the boat is currently at
|
||||
* @return the best vmg that the boat can change to
|
||||
*/
|
||||
public static VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
|
||||
//System.out.println("VMG AUTO CALLED");
|
||||
//speed
|
||||
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
|
||||
|
||||
double angle = modulateAngle(boatAngle.degrees() - trueWindAngle.degrees());
|
||||
int quad = getQuadrant(angle);
|
||||
double bestAngle = getBestSpeedInQuadrant(quad, polars.get(closestSpeed));
|
||||
|
||||
double boatSpeed = polars.get(closestSpeed).get(bestAngle);
|
||||
|
||||
double newAngle = modulateAngle(bestAngle + trueWindAngle.degrees());
|
||||
|
||||
return new VMG(boatSpeed, Bearing.fromDegrees(newAngle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the speed that a certain angle should be doing
|
||||
* @param trueWindAngle TrueWind Angle of the race
|
||||
* @param trueWindSpeed True Wind Speed of the race
|
||||
* @param boatAngle Angle that the boat is current at
|
||||
* @return the speed that the boat should be traveling at.
|
||||
*/
|
||||
public static double calculateSpeed(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
|
||||
//speed
|
||||
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
|
||||
|
||||
double angleDiff = modulateAngle(boatAngle.degrees() - trueWindAngle.degrees());
|
||||
double closestAngle = getClosest(angleDiff, polars.get(closestSpeed).keySet());
|
||||
|
||||
double boatSpeed = polars.get(closestSpeed).get(closestAngle);
|
||||
|
||||
return boatSpeed;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static double modulateAngle(double angle){
|
||||
return (angle % 360 + 360) % 360;
|
||||
}
|
||||
|
||||
private Map<Double, TreeMap<Double, Double>> getPolars(){
|
||||
//this function is just for testing so therefore it is private
|
||||
return polars;
|
||||
}
|
||||
|
||||
private void printOutLinearInterpolated(){
|
||||
for (double tws: polars.keySet()){
|
||||
System.out.println("==================================================");
|
||||
System.out.println("Speed: " + tws);
|
||||
System.out.println("==================================================");
|
||||
for (double twa: polars.get(tws).keySet()){
|
||||
System.out.println("TWA: " + twa + ", Boat Speed: " + polars.get(tws).get(twa));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,11 +1,9 @@
|
||||
package mock.model;
|
||||
package mock.model.wind;
|
||||
|
||||
|
||||
import shared.model.Bearing;
|
||||
import shared.model.Wind;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* This class generates Wind objects for use in a MockRace.
|
||||
* Initialised with a baseline wind speed and direction, and keeps it constant.
|
||||
@ -1,4 +1,4 @@
|
||||
package mock.model;
|
||||
package mock.model.wind;
|
||||
|
||||
|
||||
import shared.model.Bearing;
|
||||
@ -0,0 +1,152 @@
|
||||
package mock.model.wind;
|
||||
|
||||
import shared.model.Bearing;
|
||||
import shared.model.Wind;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class ShiftingWindGenerator implements WindGenerator {
|
||||
private Bearing baselineBearing;
|
||||
private double baseLineSpeed;
|
||||
private double windSpeedVariance = 5;
|
||||
private double bearingVariance = 5; // In degrees
|
||||
private double oscillationVariance = 0.25;
|
||||
private double oscillationPeriod = 1e3 * 60 * 1; // In milliseconds
|
||||
private double shiftTime = 1e3 * 60;
|
||||
private double shiftedSoFar = 0;
|
||||
|
||||
private double timeOfLastOscillationReset = 0;
|
||||
private double timeOfLastChange = 0;
|
||||
private double timeOfLastShift = 0; // Back / veer
|
||||
|
||||
private boolean anticlockwise = false;
|
||||
private boolean shiftAnticlockwise = false;//true for Back, false for veer
|
||||
private boolean shiftThisRace = Math.random() > 0.5;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param baselineBearing baseline bearing for wind
|
||||
* @param baseLineSpeed base line speed for wind
|
||||
*/
|
||||
public ShiftingWindGenerator(Bearing baselineBearing, double baseLineSpeed) {
|
||||
this.baselineBearing = baselineBearing;
|
||||
this.baseLineSpeed = baseLineSpeed;
|
||||
initialiseOscillationDirection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind generateBaselineWind() {
|
||||
return new Wind(baselineBearing, baseLineSpeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind generateNextWind(Wind currentWind) {
|
||||
return changeWind(currentWind);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param wind the wind to change
|
||||
* @return the changed wind
|
||||
*/
|
||||
private Wind changeWind(Wind wind) {
|
||||
Wind newWind = new Wind(wind.getWindDirection(), wind.getWindSpeed());
|
||||
oscillateWind(newWind);
|
||||
if (shiftThisRace){shiftWind(newWind);}
|
||||
changeWindSpeed(newWind);
|
||||
timeOfLastChange = System.currentTimeMillis();
|
||||
return newWind;
|
||||
}
|
||||
|
||||
/**
|
||||
* moves the wind 5 degrees up and down
|
||||
* @param wind the wind to oscillate
|
||||
*/
|
||||
private void oscillateWind(Wind wind) {
|
||||
double timeSinceLastOscillationReset = System.currentTimeMillis() - timeOfLastOscillationReset;
|
||||
double timeSinceLastChange = System.currentTimeMillis() - timeOfLastChange;
|
||||
double newBearing = wind.getWindDirection().degrees();
|
||||
double degreeChange = timeSinceLastChange * 2 * bearingVariance / oscillationPeriod;
|
||||
degreeChange = (1 - oscillationVariance) * degreeChange + (2 * oscillationVariance) * degreeChange * Math.random();
|
||||
|
||||
if (timeSinceLastOscillationReset >= oscillationPeriod) {
|
||||
timeOfLastOscillationReset = System.currentTimeMillis();
|
||||
anticlockwise = !anticlockwise;
|
||||
}
|
||||
if (anticlockwise) {
|
||||
newBearing -= degreeChange;
|
||||
if (newBearing < baselineBearing.degrees() - bearingVariance) {
|
||||
anticlockwise = !anticlockwise;
|
||||
timeOfLastOscillationReset = System.currentTimeMillis();
|
||||
} else {
|
||||
wind.setWindDirection(Bearing.fromDegrees(newBearing % 360));
|
||||
}
|
||||
} else {
|
||||
newBearing += degreeChange;
|
||||
if (newBearing > baselineBearing.degrees() + bearingVariance) {
|
||||
anticlockwise = !anticlockwise;
|
||||
timeOfLastOscillationReset = System.currentTimeMillis();
|
||||
} else {
|
||||
wind.setWindDirection(Bearing.fromDegrees(newBearing % 360));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Slowly shifts the wind up to 180 degrees from where it started
|
||||
* @param wind the wind to change
|
||||
*/
|
||||
private void shiftWind(Wind wind) {
|
||||
double timeSinceLastShift = System.currentTimeMillis() - timeOfLastShift;
|
||||
double newBearing = wind.getWindDirection().degrees();
|
||||
double degreeChange = 7;
|
||||
|
||||
if (timeSinceLastShift >= shiftTime){
|
||||
shiftedSoFar += degreeChange;
|
||||
if (shiftedSoFar >= 180){
|
||||
shiftAnticlockwise = Math.random() > 0.5;
|
||||
shiftedSoFar = 0;
|
||||
// System.out.println("Swapping");
|
||||
}
|
||||
|
||||
timeOfLastShift = System.currentTimeMillis();
|
||||
if (shiftAnticlockwise){
|
||||
newBearing -= degreeChange;
|
||||
wind.setWindDirection(Bearing.fromDegrees(newBearing % 360));
|
||||
} else {
|
||||
newBearing += degreeChange;
|
||||
wind.setWindDirection(Bearing.fromDegrees(newBearing % 360));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the wind speed
|
||||
* @param wind the wind to change
|
||||
*/
|
||||
private void changeWindSpeed(Wind wind) {
|
||||
double offsetAngle = (wind.getWindDirection().radians() - baselineBearing.radians());
|
||||
double offset = Math.sin(offsetAngle) * windSpeedVariance;
|
||||
double newWindSpeed = baseLineSpeed + offset;
|
||||
wind.setWindSpeed(newWindSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* starts the wind oscillation direction
|
||||
*/
|
||||
private void initialiseOscillationDirection() {
|
||||
anticlockwise = new Random().nextBoolean();
|
||||
timeOfLastOscillationReset = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void setBearingVariance(double maxBearingVariance) {
|
||||
this.bearingVariance = maxBearingVariance;
|
||||
}
|
||||
|
||||
public void setWindSpeedVariance(double windSpeedVariance) {
|
||||
this.windSpeedVariance = windSpeedVariance;
|
||||
}
|
||||
|
||||
public void setOscillationPeriod(double oscillationPeriod) {
|
||||
this.oscillationPeriod = oscillationPeriod;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package mock.model;
|
||||
package mock.model.wind;
|
||||
|
||||
import shared.model.Wind;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -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>
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 9.2 KiB |
@ -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>
|
||||
@ -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>
|
||||
@ -0,0 +1,141 @@
|
||||
package mock.model;
|
||||
|
||||
import mock.dataInput.PolarParser;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import shared.model.Bearing;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Created by fwy13 on 5/09/17.
|
||||
*/
|
||||
public class NewPolarsTest {
|
||||
|
||||
@Before
|
||||
public void setUp(){
|
||||
PolarParser.parseNewPolars("mock/polars/acc_polars.csv");
|
||||
NewPolars.linearInterpolatePolars();
|
||||
|
||||
|
||||
// Uncomment if you want to read the linear interpolation in text
|
||||
// Method getPolars = null;
|
||||
// try {
|
||||
// getPolars = NewPolars.class.getDeclaredMethod("printOutLinearInterpolated");
|
||||
// } catch (NoSuchMethodException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// getPolars.setAccessible(true);
|
||||
// try {
|
||||
// getPolars.invoke(NewPolars.newPolars);
|
||||
// } catch (IllegalAccessException e) {
|
||||
// e.printStackTrace();
|
||||
// } catch (InvocationTargetException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuads() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
//reflection for private class
|
||||
Class[] parameterTypes = new Class[1];
|
||||
parameterTypes[0] = Double.TYPE;
|
||||
Method getQuads = NewPolars.class.getDeclaredMethod("getQuadrant", parameterTypes);
|
||||
getQuads.setAccessible(true);
|
||||
|
||||
//start invoking
|
||||
Object[] paras1 = new Object[1];
|
||||
paras1[0] = (new Double(0)).doubleValue();
|
||||
int q1 = (int) getQuads.invoke(NewPolars.newPolars, paras1);
|
||||
assertEquals(q1, 1);
|
||||
|
||||
//start invoking
|
||||
Object[] paras2 = new Object[1];
|
||||
paras2[0] = (new Double(90)).doubleValue();
|
||||
int q2 = (int) getQuads.invoke(NewPolars.newPolars, paras2);
|
||||
assertEquals(q2, 2);
|
||||
|
||||
//start invoking
|
||||
Object[] paras3 = new Object[1];
|
||||
paras3[0] = (new Double(180)).doubleValue();
|
||||
int q3 = (int) getQuads.invoke(NewPolars.newPolars, paras3);
|
||||
assertEquals(q3, 3);
|
||||
|
||||
//start invoking
|
||||
Object[] paras4 = new Object[1];
|
||||
paras4[0] = (new Double(270)).doubleValue();
|
||||
int q4 = (int) getQuads.invoke(NewPolars.newPolars, paras4);
|
||||
assertEquals(q4, 4);
|
||||
|
||||
//start invoking
|
||||
Object[] paras5 = new Object[1];
|
||||
paras5[0] = (new Double(360)).doubleValue();
|
||||
int q5 = (int) getQuads.invoke(NewPolars.newPolars, paras5);
|
||||
assertEquals(q5, 1);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEdgeSpeeds(){
|
||||
//just make sure that speeds at certain angles do not throw a null exception and are not negative
|
||||
double maxTWS = 30;
|
||||
|
||||
for (double tws = 0; tws < maxTWS; tws += 1){
|
||||
for (double j = 0; j < 360; j++){
|
||||
Bearing twa = Bearing.fromDegrees(j);
|
||||
for (double i = 0; i < 360; i++){
|
||||
Bearing boatBearing = Bearing.fromDegrees(i);
|
||||
double speed = NewPolars.calculateSpeed(twa, tws, boatBearing);
|
||||
assertTrue(speed >= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClosestSpeeds() throws NoSuchMethodException, NoSuchFieldException, InvocationTargetException, IllegalAccessException {
|
||||
//reflection for private class
|
||||
Method getClosest = NewPolars.class.getDeclaredMethod("getClosest", double.class, Set.class);
|
||||
getClosest.setAccessible(true);
|
||||
|
||||
Method getPolars = NewPolars.class.getDeclaredMethod("getPolars");
|
||||
getPolars.setAccessible(true);
|
||||
|
||||
double maxTWS = 30;
|
||||
|
||||
//only catches for nulls
|
||||
for (double tws = 0; tws < maxTWS; tws += 1){
|
||||
Map<Double, TreeMap<Double, Double>> polars = (Map<Double, TreeMap<Double, Double>>) getPolars.invoke(NewPolars.newPolars);
|
||||
double speed = (double) getClosest.invoke(NewPolars.newPolars, tws, polars.keySet());
|
||||
assertTrue(speed >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoVSCalculated(){
|
||||
//test that the auto chosen speed is the same speed that is calculated
|
||||
double maxTWS = 30;
|
||||
for (double tws = 0; tws < maxTWS; tws ++){
|
||||
for (double twa = 0; twa < 360; twa ++){
|
||||
Bearing TW = Bearing.fromDegrees(twa);
|
||||
for (double ba = 0; ba < 360; ba ++){
|
||||
Bearing boatBearing = Bearing.fromDegrees(ba);
|
||||
VMG autoVMG = NewPolars.setBestVMG(TW, tws, boatBearing);
|
||||
double speed = NewPolars.calculateSpeed(TW, tws, autoVMG.getBearing());
|
||||
assertTrue(autoVMG.getSpeed() == speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<java version="1.8.0_111" class="java.beans.XMLDecoder">
|
||||
<object class="java.util.HashMap">
|
||||
<void method="put">
|
||||
<string>SPACE</string>
|
||||
<object class="visualiser.gameController.Keys.VMGKey"/>
|
||||
</void>
|
||||
<void method="put">
|
||||
<string>SHIFT</string>
|
||||
<object class="visualiser.gameController.Keys.SailsToggleKey"/>
|
||||
</void>
|
||||
<void method="put">
|
||||
<string>DOWN</string>
|
||||
<object class="visualiser.gameController.Keys.DownWindKey"/>
|
||||
</void>
|
||||
<void method="put">
|
||||
<string>X</string>
|
||||
<object class="visualiser.gameController.Keys.ZoomOutKey"/>
|
||||
</void>
|
||||
<void method="put">
|
||||
<string>ENTER</string>
|
||||
<object class="visualiser.gameController.Keys.TackGybeKey"/>
|
||||
</void>
|
||||
<void method="put">
|
||||
<string>Z</string>
|
||||
<object class="visualiser.gameController.Keys.ZoomInKey"/>
|
||||
</void>
|
||||
<void method="put">
|
||||
<string>UP</string>
|
||||
<object class="visualiser.gameController.Keys.UpWindKey"/>
|
||||
</void>
|
||||
</object>
|
||||
</java>
|
||||
Loading…
Reference in new issue