Merge remote-tracking branch 'remotes/origin/master' into story77
# Conflicts: # racevisionGame/src/main/java/mock/app/Event.java # racevisionGame/src/main/java/mock/xml/RaceXMLCreator.java # racevisionGame/src/main/java/visualiser/Controllers/HostGameController.java # racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java # racevisionGame/src/main/java/visualiser/Controllers/TitleController.java # racevisionGame/src/main/java/visualiser/app/App.java # settings/keyBindings.xml
This commit is contained in:
@@ -183,3 +183,4 @@ local.properties
|
|||||||
# IntelliJDEA ignore
|
# IntelliJDEA ignore
|
||||||
*.iml
|
*.iml
|
||||||
dedicatedServer/.idea/
|
dedicatedServer/.idea/
|
||||||
|
settings/keyBindings.xml
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import shared.model.Constants;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
@@ -77,12 +78,10 @@ public class Event {
|
|||||||
/**
|
/**
|
||||||
* Constructs an event, using various XML files.
|
* Constructs an event, using various XML files.
|
||||||
* @param singlePlayer Whether or not to create a single player event.
|
* @param singlePlayer Whether or not to create a single player event.
|
||||||
|
* @param mapIndex Specifies which map to use.
|
||||||
* @throws EventConstructionException Thrown if we cannot create an Event for any reason.
|
* @throws EventConstructionException Thrown if we cannot create an Event for any reason.
|
||||||
*/
|
*/
|
||||||
public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException {
|
public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException {
|
||||||
|
|
||||||
// System.out.println(XMLUtilities.validateXML(this.getClass().getClassLoader().getResource("mock/mockXML/iMapLayout.xml").toString()
|
|
||||||
// , this.getClass().getClassLoader().getResource("mock/mockXML/schema/raceSchema.xsd")));
|
|
||||||
this.mapIndex = mapIndex;
|
this.mapIndex = mapIndex;
|
||||||
String raceXMLFile;
|
String raceXMLFile;
|
||||||
String boatsXMLFile = "mock/mockXML/boatTest.xml";
|
String boatsXMLFile = "mock/mockXML/boatTest.xml";
|
||||||
@@ -114,15 +113,18 @@ public class Event {
|
|||||||
//Read XML files.
|
//Read XML files.
|
||||||
try {
|
try {
|
||||||
//this.raceXML = RaceXMLCreator.alterRaceToWind(raceXMLFile, 90);
|
//this.raceXML = RaceXMLCreator.alterRaceToWind(raceXMLFile, 90);
|
||||||
this.raceXML = XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8);
|
|
||||||
this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8));
|
this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8));
|
||||||
if(mapIndex==4){
|
if(mapIndex==4){
|
||||||
this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8), 1000, 5000);
|
//this.raceXML = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString(raceXMLFile, StandardCharsets.UTF_8), 1000, 5000);
|
||||||
|
this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, -1, true);
|
||||||
|
} else {
|
||||||
|
this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, 300, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8);
|
this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8);
|
||||||
this.regattaXML = XMLReader.readXMLFileToString(regattaXMLFile, StandardCharsets.UTF_8);
|
this.regattaXML = XMLReader.readXMLFileToString(regattaXMLFile, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
} catch (XMLReaderException e) {
|
} catch (XMLReaderException | InvalidRaceDataException e) {
|
||||||
throw new EventConstructionException("Could not read XML files.", e);
|
throw new EventConstructionException("Could not read XML files.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,14 +154,23 @@ public class Event {
|
|||||||
Bearing.fromDegrees(225),
|
Bearing.fromDegrees(225),
|
||||||
12
|
12
|
||||||
);
|
);
|
||||||
RaceLogic newRace = new RaceLogic(
|
|
||||||
new MockRace(
|
MockRace mockRace = new MockRace(
|
||||||
boatDataSource,
|
boatDataSource,
|
||||||
raceDataSource,
|
raceDataSource,
|
||||||
regattaDataSource,
|
regattaDataSource,
|
||||||
this.boatPolars,
|
this.boatPolars,
|
||||||
Constants.RaceTimeScale,
|
Constants.RaceTimeScale,
|
||||||
windGenerator ),
|
windGenerator );
|
||||||
|
|
||||||
|
if(mapIndex==4){
|
||||||
|
mockRace.setRacePreStartTime(1000);
|
||||||
|
mockRace.setRacePreparatoryTime(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RaceLogic newRace = new RaceLogic(
|
||||||
|
mockRace,
|
||||||
this.latestMessages,
|
this.latestMessages,
|
||||||
this.compositeCommand);
|
this.compositeCommand);
|
||||||
|
|
||||||
@@ -194,7 +205,6 @@ public class Event {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//TODO remove this after demo on 18th august!
|
|
||||||
/**
|
/**
|
||||||
* Sets the xml description of the race to show the race was created now, and starts in 4 minutes
|
* Sets the xml description of the race to show the race was created now, and starts in 4 minutes
|
||||||
* @param raceXML The race.xml contents.
|
* @param raceXML The race.xml contents.
|
||||||
@@ -211,8 +221,6 @@ public class Event {
|
|||||||
|
|
||||||
|
|
||||||
long secondsToAdd = millisecondsToAdd / 1000;
|
long secondsToAdd = millisecondsToAdd / 1000;
|
||||||
//Scale the time using our time scalar.
|
|
||||||
secondsToAdd = secondsToAdd / Constants.RaceTimeScale;
|
|
||||||
|
|
||||||
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
|
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||||
ZonedDateTime creationTime = ZonedDateTime.now();
|
ZonedDateTime creationTime = ZonedDateTime.now();
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ public class MockBoat extends Boat {
|
|||||||
*/
|
*/
|
||||||
private boolean autoVMG = false;
|
private boolean autoVMG = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether boat velocity is determined by wind
|
||||||
|
*/
|
||||||
|
private boolean velocityDefault = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a boat object with a given sourceID, name, country/team abbreviation, and polars table.
|
* Constructs a boat object with a given sourceID, name, country/team abbreviation, and polars table.
|
||||||
@@ -300,4 +303,12 @@ public class MockBoat extends Boat {
|
|||||||
public void setAutoVMG(boolean autoVMG) {
|
public void setAutoVMG(boolean autoVMG) {
|
||||||
this.autoVMG = autoVMG;
|
this.autoVMG = autoVMG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isVelocityDefault() {
|
||||||
|
return velocityDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVelocityDefault(boolean velocityDefault) {
|
||||||
|
this.velocityDefault = velocityDefault;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
package mock.model;
|
package mock.model;
|
||||||
|
|
||||||
|
import mock.model.commandFactory.ActiveObserverCommand;
|
||||||
|
import mock.model.commandFactory.ObserverCommand;
|
||||||
import mock.model.wind.WindGenerator;
|
import mock.model.wind.WindGenerator;
|
||||||
import javafx.animation.AnimationTimer;
|
|
||||||
import mock.model.collider.ColliderRegistry;
|
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.BoatStatusEnum;
|
||||||
import network.Messages.Enums.RaceStatusEnum;
|
import network.Messages.Enums.RaceStatusEnum;
|
||||||
import shared.dataInput.BoatDataSource;
|
import shared.dataInput.BoatDataSource;
|
||||||
import shared.dataInput.RaceDataSource;
|
import shared.dataInput.RaceDataSource;
|
||||||
import shared.dataInput.RegattaDataSource;
|
import shared.dataInput.RegattaDataSource;
|
||||||
import shared.exceptions.BoatNotFoundException;
|
import shared.exceptions.BoatNotFoundException;
|
||||||
import shared.enums.RoundingType;
|
|
||||||
import shared.model.*;
|
import shared.model.*;
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
|
||||||
@@ -64,7 +61,11 @@ public class MockRace extends RaceState {
|
|||||||
*/
|
*/
|
||||||
private Polars polars;
|
private Polars polars;
|
||||||
|
|
||||||
|
private ActiveObserverCommand activeObserverCommand;
|
||||||
|
|
||||||
|
private long racePreStartTime = Constants.RacePreStartTime;
|
||||||
|
|
||||||
|
private long racePreparatoryTime = Constants.RacePreparatoryTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a race object with a given RaceDataSource, BoatDataSource, and RegattaDataSource and sends events to the given mockOutput.
|
* Constructs a race object with a given RaceDataSource, BoatDataSource, and RegattaDataSource and sends events to the given mockOutput.
|
||||||
@@ -81,6 +82,7 @@ public class MockRace extends RaceState {
|
|||||||
this.setRaceDataSource(raceDataSource);
|
this.setRaceDataSource(raceDataSource);
|
||||||
this.setRegattaDataSource(regattaDataSource);
|
this.setRegattaDataSource(regattaDataSource);
|
||||||
|
|
||||||
|
this.activeObserverCommand = new ActiveObserverCommand();
|
||||||
this.polars = polars;
|
this.polars = polars;
|
||||||
this.scaleFactor = timeScale;
|
this.scaleFactor = timeScale;
|
||||||
|
|
||||||
@@ -119,6 +121,7 @@ public class MockRace extends RaceState {
|
|||||||
//Construct a MockBoat using the Boat and Polars.
|
//Construct a MockBoat using the Boat and Polars.
|
||||||
MockBoat mockBoat = new MockBoat(boat, polars);
|
MockBoat mockBoat = new MockBoat(boat, polars);
|
||||||
mockBoat.setCurrentLeg(this.getLegs().get(0));
|
mockBoat.setCurrentLeg(this.getLegs().get(0));
|
||||||
|
mockBoat.setEstimatedTimeAtNextMark(this.getRaceClock().getCurrentTime());
|
||||||
|
|
||||||
//Update participant list.
|
//Update participant list.
|
||||||
getRaceDataSource().getParticipants().add(sourceID);
|
getRaceDataSource().getParticipants().add(sourceID);
|
||||||
@@ -163,15 +166,15 @@ public class MockRace extends RaceState {
|
|||||||
long timeToStart = - this.getRaceClock().getDurationMilli();
|
long timeToStart = - this.getRaceClock().getDurationMilli();
|
||||||
|
|
||||||
|
|
||||||
if (timeToStart > Constants.RacePreStartTime) {
|
if (timeToStart > racePreStartTime) {
|
||||||
//Time > 3 minutes is the prestart period.
|
//Time > 3 minutes is the prestart period.
|
||||||
this.setRaceStatusEnum(RaceStatusEnum.PRESTART);
|
this.setRaceStatusEnum(RaceStatusEnum.PRESTART);
|
||||||
|
|
||||||
} else if ((timeToStart <= Constants.RacePreStartTime) && (timeToStart >= Constants.RacePreparatoryTime)) {
|
} else if ((timeToStart <= racePreStartTime) && (timeToStart >= racePreparatoryTime)) {
|
||||||
//Time between [1, 3] minutes is the warning period.
|
//Time between [1, 3] minutes is the warning period.
|
||||||
this.setRaceStatusEnum(RaceStatusEnum.WARNING);
|
this.setRaceStatusEnum(RaceStatusEnum.WARNING);
|
||||||
|
|
||||||
} else if ((timeToStart <= Constants.RacePreparatoryTime) && (timeToStart > 0)) {
|
} else if ((timeToStart <= racePreparatoryTime) && (timeToStart > 0)) {
|
||||||
//Time between (0, 1] minutes is the preparatory period.
|
//Time between (0, 1] minutes is the preparatory period.
|
||||||
this.setRaceStatusEnum(RaceStatusEnum.PREPARATORY);
|
this.setRaceStatusEnum(RaceStatusEnum.PREPARATORY);
|
||||||
|
|
||||||
@@ -184,6 +187,13 @@ public class MockRace extends RaceState {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRacePreStartTime(long racePreStartTime) {
|
||||||
|
this.racePreStartTime = racePreStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRacePreparatoryTime(long racePreparatoryTime) {
|
||||||
|
this.racePreparatoryTime = racePreparatoryTime;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the status of all boats in the race to RACING.
|
* Sets the status of all boats in the race to RACING.
|
||||||
@@ -356,70 +366,24 @@ public class MockRace extends RaceState {
|
|||||||
//Checks if the current boat has finished the race or not.
|
//Checks if the current boat has finished the race or not.
|
||||||
boolean finish = this.isLastLeg(boat.getCurrentLeg());
|
boolean finish = this.isLastLeg(boat.getCurrentLeg());
|
||||||
|
|
||||||
if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds && boat.isSailsOut()) {
|
if (!finish && totalElapsedMilliseconds >= updatePeriodMilliseconds) {
|
||||||
|
|
||||||
checkPosition(boat, totalElapsedMilliseconds);
|
if(boat.isVelocityDefault()) setBoatSpeed(boat);
|
||||||
|
|
||||||
if (boat.getCurrentSpeed() == 0) {
|
|
||||||
newOptimalVMG(boat);
|
|
||||||
boat.setBearing(boat.calculateBearingToNextMarker());
|
|
||||||
}
|
|
||||||
|
|
||||||
setBoatSpeed(boat);
|
|
||||||
|
|
||||||
//Calculates the distance travelled, in meters, in the current timeslice.
|
//Calculates the distance travelled, in meters, in the current timeslice.
|
||||||
double distanceTravelledMeters = boat.calculateMetersTravelled(updatePeriodMilliseconds);
|
double distanceTravelledMeters = boat.calculateMetersTravelled(updatePeriodMilliseconds) * this.scaleFactor;
|
||||||
|
|
||||||
//Scale it.
|
|
||||||
distanceTravelledMeters = distanceTravelledMeters * this.scaleFactor;
|
|
||||||
|
|
||||||
|
|
||||||
|
checkPosition(boat, totalElapsedMilliseconds);
|
||||||
//Move the boat forwards that many meters, and advances its time counters by enough milliseconds.
|
//Move the boat forwards that many meters, and advances its time counters by enough milliseconds.
|
||||||
boat.moveForwards(distanceTravelledMeters);
|
boat.moveForwards(distanceTravelledMeters);
|
||||||
boat.setTimeSinceTackChange(boat.getTimeSinceTackChange() + updatePeriodMilliseconds);
|
boat.setTimeSinceTackChange(boat.getTimeSinceTackChange() + updatePeriodMilliseconds);
|
||||||
|
|
||||||
if (boat.getAutoVMG()) {
|
|
||||||
newOptimalVMG(boat);
|
|
||||||
boat.setAutoVMG(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
boat.setCurrentSpeed(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateEstimatedTime(boat);
|
this.updateEstimatedTime(boat);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void newOptimalVMG(MockBoat boat) {
|
|
||||||
long tackPeriod = 1000;
|
|
||||||
if (boat.getTimeSinceTackChange() > tackPeriod) {
|
|
||||||
//System.out.println("optim called");
|
|
||||||
//Calculate the new VMG.
|
|
||||||
// VMG newVMG = boat.getPolars().calculateVMG(
|
|
||||||
// this.getWindDirection(),
|
|
||||||
// this.getWindSpeed(),
|
|
||||||
// boat.calculateBearingToNextMarker(),
|
|
||||||
// Bearing.fromDegrees(0d),
|
|
||||||
// Bearing.fromDegrees(359.99999d));
|
|
||||||
|
|
||||||
VMG newVMG = NewPolars.setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
|
|
||||||
//System.out.println(newVMG);
|
|
||||||
//If the new vmg improves velocity, use it.
|
|
||||||
/*if (improvesVelocity(boat, newVMG)) {
|
|
||||||
}*/
|
|
||||||
boat.setVMG(newVMG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setBoatSpeed(MockBoat boat) {
|
private void setBoatSpeed(MockBoat boat) {
|
||||||
// VMG vmg = boat.getPolars().calculateVMG(
|
|
||||||
// this.getWindDirection(),
|
|
||||||
// this.getWindSpeed(),
|
|
||||||
// boat.getBearing(),
|
|
||||||
// Bearing.fromDegrees(boat.getBearing().degrees() - 1),
|
|
||||||
// Bearing.fromDegrees(boat.getBearing().degrees() + 1));
|
|
||||||
//VMG vmg = boat.getPolars().setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
|
|
||||||
VMG vmg = new VMG(NewPolars.calculateSpeed(
|
VMG vmg = new VMG(NewPolars.calculateSpeed(
|
||||||
this.getWindDirection(),
|
this.getWindDirection(),
|
||||||
this.getWindSpeed(),
|
this.getWindSpeed(),
|
||||||
@@ -515,22 +479,28 @@ public class MockRace extends RaceState {
|
|||||||
/**
|
/**
|
||||||
* Checks to be run on boats rounding marks on the port side
|
* Checks to be run on boats rounding marks on the port side
|
||||||
* @param boat the boat that is rounding a mark
|
* @param boat the boat that is rounding a mark
|
||||||
* @param roundingChecks the checks to run
|
* @param roundingData The data for the current leg's rounding.
|
||||||
* @param legBearing the direction of the leg
|
|
||||||
*/
|
*/
|
||||||
private void boatRoundingCheckPort(MockBoat boat, List<GPSCoordinate> roundingChecks, Bearing legBearing) {
|
private void boatRoundingCheckPort(MockBoat boat, MarkRoundingData roundingData) {
|
||||||
//boats must pass all checks in order to round a mark
|
//boats must pass all checks in order to round a mark
|
||||||
|
|
||||||
//boolean for if boat has to/needs to pass through a gate
|
//boolean for if boat has to/needs to pass through a gate
|
||||||
boolean gateCheck = boat.getCurrentLeg().getEndCompoundMark().getMark2() == null || boat.isBetweenGate(boat.getCurrentLeg().getEndCompoundMark());
|
boolean gateCheck = boat.getCurrentLeg().getEndCompoundMark().getMark2() == null || boat.isBetweenGate(boat.getCurrentLeg().getEndCompoundMark());
|
||||||
Mark roundingMark = boat.getCurrentLeg().getEndCompoundMark().getMarkForRounding(legBearing);
|
|
||||||
|
|
||||||
|
|
||||||
switch (boat.getRoundingStatus()) {
|
switch (boat.getRoundingStatus()) {
|
||||||
case 0://hasn't started rounding
|
case 0://hasn't started rounding
|
||||||
if (boat.isPortSide(roundingMark) &&
|
if (boat.isPortSide(roundingData.getMarkToRound()) &&
|
||||||
GPSCoordinate.passesLine(roundingMark.getPosition(),
|
GPSCoordinate.passesLine(
|
||||||
roundingChecks.get(0), boat.getPosition(), legBearing) &&
|
roundingData.getMarkToRound().getPosition(),
|
||||||
gateCheck && boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) {
|
roundingData.getRoundCheck1(),
|
||||||
|
boat.getPosition(),
|
||||||
|
roundingData.getLegBearing()) &&
|
||||||
|
gateCheck &&
|
||||||
|
boat.isBetweenGate(
|
||||||
|
roundingData.getMarkToRound(),
|
||||||
|
Mark.tempMark(roundingData.getRoundCheck1())) ) {
|
||||||
boat.increaseRoundingStatus();
|
boat.increaseRoundingStatus();
|
||||||
if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){
|
if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){
|
||||||
//boat has finished race
|
//boat has finished race
|
||||||
@@ -539,11 +509,18 @@ public class MockRace extends RaceState {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1://has been parallel to the mark;
|
case 1://has been parallel to the mark;
|
||||||
if (boat.isPortSide(roundingMark) &&
|
if (boat.isPortSide(roundingData.getMarkToRound()) &&
|
||||||
GPSCoordinate.passesLine(roundingMark.getPosition(),
|
GPSCoordinate.passesLine(
|
||||||
roundingChecks.get(1), boat.getPosition(),
|
roundingData.getMarkToRound().getPosition(),
|
||||||
Bearing.fromDegrees(legBearing.degrees() - 90)) &&//negative 90 from bearing because of port rounding
|
roundingData.getRoundCheck2(),
|
||||||
boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) {
|
boat.getPosition(),
|
||||||
|
Bearing.fromDegrees(
|
||||||
|
GPSCoordinate.calculateBearing(
|
||||||
|
roundingData.getMarkToRound().getPosition(),
|
||||||
|
roundingData.getRoundCheck2()).degrees() - 90)) &&//negative 90 from bearing because of port rounding
|
||||||
|
boat.isBetweenGate(
|
||||||
|
roundingData.getMarkToRound(),
|
||||||
|
Mark.tempMark(roundingData.getRoundCheck2()))) {
|
||||||
boat.increaseRoundingStatus();
|
boat.increaseRoundingStatus();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -559,23 +536,27 @@ public class MockRace extends RaceState {
|
|||||||
/**
|
/**
|
||||||
* Checks to be run on boats rounding marks on the starboard side
|
* Checks to be run on boats rounding marks on the starboard side
|
||||||
* @param boat the boat that is rounding a mark
|
* @param boat the boat that is rounding a mark
|
||||||
* @param roundingChecks the checks to run
|
* @param roundingData The data for the current leg's rounding.
|
||||||
* @param legBearing the direction of the leg
|
|
||||||
*/
|
*/
|
||||||
private void boatRoundingCheckStarboard(MockBoat boat, List<GPSCoordinate> roundingChecks, Bearing legBearing){
|
private void boatRoundingCheckStarboard(MockBoat boat, MarkRoundingData roundingData){
|
||||||
//boats must pass all checks in order to round a mark
|
//boats must pass all checks in order to round a mark
|
||||||
|
|
||||||
//boolean for if boat has to/needs to pass through a gate
|
//boolean for if boat has to/needs to pass through a gate
|
||||||
boolean gateCheck = boat.getCurrentLeg().getEndCompoundMark().getMark2() == null || boat.isBetweenGate(boat.getCurrentLeg().getEndCompoundMark());
|
boolean gateCheck = boat.getCurrentLeg().getEndCompoundMark().getMark2() == null || boat.isBetweenGate(boat.getCurrentLeg().getEndCompoundMark());
|
||||||
Mark roundingMark = boat.getCurrentLeg().getEndCompoundMark().getMarkForRounding(legBearing);
|
|
||||||
|
|
||||||
switch (boat.getRoundingStatus()) {
|
switch (boat.getRoundingStatus()) {
|
||||||
case 0://hasn't started rounding
|
case 0://hasn't started rounding
|
||||||
if (boat.isStarboardSide(roundingMark) &&
|
if (boat.isStarboardSide(roundingData.getMarkToRound()) &&
|
||||||
GPSCoordinate.passesLine(roundingMark.getPosition(),
|
GPSCoordinate.passesLine(
|
||||||
roundingChecks.get(0), boat.getPosition(), legBearing) &&
|
roundingData.getMarkToRound().getPosition(),
|
||||||
|
roundingData.getRoundCheck1(),
|
||||||
|
boat.getPosition(),
|
||||||
|
roundingData.getLegBearing()) &&
|
||||||
gateCheck &&
|
gateCheck &&
|
||||||
boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(0)))) {
|
boat.isBetweenGate(
|
||||||
|
roundingData.getMarkToRound(),
|
||||||
|
Mark.tempMark(roundingData.getRoundCheck1()))) {
|
||||||
boat.increaseRoundingStatus();
|
boat.increaseRoundingStatus();
|
||||||
if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){
|
if (boat.getCurrentLeg().getLegNumber() + 2 >= getLegs().size()){
|
||||||
//boat has finished race
|
//boat has finished race
|
||||||
@@ -584,10 +565,18 @@ public class MockRace extends RaceState {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1://has been parallel to the mark
|
case 1://has been parallel to the mark
|
||||||
if (boat.isStarboardSide(roundingMark) &&
|
if (boat.isStarboardSide(roundingData.getMarkToRound()) &&
|
||||||
GPSCoordinate.passesLine(roundingMark.getPosition(),
|
GPSCoordinate.passesLine(
|
||||||
roundingChecks.get(1), boat.getPosition(), Bearing.fromDegrees(legBearing.degrees() + 90)) && //positive 90 from bearing because of starboard rounding
|
roundingData.getMarkToRound().getPosition(),
|
||||||
boat.isBetweenGate(roundingMark, Mark.tempMark(roundingChecks.get(1)))) {
|
roundingData.getRoundCheck2(),
|
||||||
|
boat.getPosition(),
|
||||||
|
Bearing.fromDegrees(
|
||||||
|
GPSCoordinate.calculateBearing(
|
||||||
|
roundingData.getMarkToRound().getPosition(),
|
||||||
|
roundingData.getRoundCheck2() ).degrees() + 90)) && //positive 90 from bearing because of starboard rounding
|
||||||
|
boat.isBetweenGate(
|
||||||
|
roundingData.getMarkToRound(),
|
||||||
|
Mark.tempMark(roundingData.getRoundCheck2())) ) {
|
||||||
boat.increaseRoundingStatus();
|
boat.increaseRoundingStatus();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -606,55 +595,19 @@ public class MockRace extends RaceState {
|
|||||||
* @param timeElapsed The total time, in milliseconds, that has elapsed since the race started.
|
* @param timeElapsed The total time, in milliseconds, that has elapsed since the race started.
|
||||||
*/
|
*/
|
||||||
protected void checkPosition(MockBoat boat, long timeElapsed) {
|
protected void checkPosition(MockBoat boat, long timeElapsed) {
|
||||||
//The distance, in nautical miles, within which the boat needs to get in order to consider that it has reached the marker.
|
|
||||||
double epsilonNauticalMiles = boat.getCurrentLeg().getEndCompoundMark().getRoundingDistance(); //250 meters.
|
|
||||||
|
|
||||||
if (boat.calculateDistanceToNextMarker() < epsilonNauticalMiles) {
|
|
||||||
//Boat is within an acceptable distance from the mark.
|
|
||||||
|
|
||||||
GPSCoordinate startDirectionLinePoint = boat.getCurrentLeg().getStartCompoundMark().getMark1Position();
|
|
||||||
GPSCoordinate endDirectionLinePoint = boat.getCurrentLeg().getEndCompoundMark().getMark1Position();
|
|
||||||
Bearing bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, endDirectionLinePoint);
|
|
||||||
|
|
||||||
//use the direction line to create three invisible points that act as crossover lines a boat must cross
|
|
||||||
//to round a mark
|
|
||||||
|
|
||||||
double bearingToAdd;
|
|
||||||
if (boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.Port ||
|
|
||||||
boat.getCurrentLeg().getEndCompoundMark().getRoundingType() == RoundingType.SP){
|
|
||||||
bearingToAdd = 90;
|
|
||||||
}else{
|
|
||||||
bearingToAdd = -90;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPSCoordinate roundCheck1 = GPSCoordinate.calculateNewPosition(endDirectionLinePoint,
|
|
||||||
epsilonNauticalMiles, Azimuth.fromDegrees(bearingOfDirectionLine.degrees() + bearingToAdd));
|
|
||||||
|
|
||||||
GPSCoordinate roundCheck2;
|
|
||||||
try{
|
|
||||||
Leg nextLeg = getLegs().get(getLegs().indexOf(boat.getCurrentLeg()) + 1);
|
|
||||||
|
|
||||||
GPSCoordinate startNextDirectionLinePoint = nextLeg.getStartCompoundMark().getMark1Position();
|
|
||||||
GPSCoordinate endNextDirectionLinePoint = nextLeg.getEndCompoundMark().getMark1Position();
|
|
||||||
Bearing bearingOfNextDirectionLine = GPSCoordinate.calculateBearing(startNextDirectionLinePoint, endNextDirectionLinePoint);
|
|
||||||
|
|
||||||
roundCheck2 = GPSCoordinate.calculateNewPosition(endDirectionLinePoint,
|
|
||||||
epsilonNauticalMiles, Azimuth.fromDegrees(bearingOfNextDirectionLine.degrees() + bearingToAdd));
|
|
||||||
}catch(NullPointerException e){
|
|
||||||
//this is caused by the last leg not being having a leg after it
|
|
||||||
roundCheck2 = roundCheck1;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GPSCoordinate> roundingChecks = new ArrayList<GPSCoordinate>(Arrays.asList(roundCheck1, roundCheck2));
|
|
||||||
|
|
||||||
switch (boat.getCurrentLeg().getEndCompoundMark().getRoundingType()) {
|
switch (boat.getCurrentLeg().getEndCompoundMark().getRoundingType()) {
|
||||||
case SP://Not yet implemented so these gates will be rounded port side
|
case SP://Not yet implemented so these gates will be rounded port side
|
||||||
case Port:
|
case Port:
|
||||||
boatRoundingCheckPort(boat, roundingChecks, bearingOfDirectionLine);
|
boatRoundingCheckPort(
|
||||||
|
boat,
|
||||||
|
getMarkRoundingSequence().getRoundingData(boat.getCurrentLeg()) );
|
||||||
break;
|
break;
|
||||||
case PS://not yet implemented so these gates will be rounded starboard side
|
case PS://not yet implemented so these gates will be rounded starboard side
|
||||||
case Starboard:
|
case Starboard:
|
||||||
boatRoundingCheckStarboard(boat, roundingChecks, bearingOfDirectionLine);
|
boatRoundingCheckStarboard(
|
||||||
|
boat,
|
||||||
|
getMarkRoundingSequence().getRoundingData(boat.getCurrentLeg()) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,8 +623,6 @@ public class MockRace extends RaceState {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -755,4 +706,18 @@ public class MockRace extends RaceState {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Made public, so race logic can control it
|
||||||
|
*/
|
||||||
|
public void setChanged() {
|
||||||
|
super.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addVelocityCommand(ObserverCommand c) {
|
||||||
|
this.activeObserverCommand.changeVelocityCommand(this, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAngularCommand(ObserverCommand c) {
|
||||||
|
this.activeObserverCommand.changeAngularCommand(this, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,8 +145,6 @@ public class NewPolars {
|
|||||||
* @return the best vmg that the boat can change to
|
* @return the best vmg that the boat can change to
|
||||||
*/
|
*/
|
||||||
public static VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
|
public static VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
|
||||||
//System.out.println("VMG AUTO CALLED");
|
|
||||||
//speed
|
|
||||||
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
|
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
|
||||||
|
|
||||||
double angle = modulateAngle(boatAngle.degrees() - trueWindAngle.degrees());
|
double angle = modulateAngle(boatAngle.degrees() - trueWindAngle.degrees());
|
||||||
@@ -181,15 +179,29 @@ public class NewPolars {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the angle bound between 0 and 360 following modular arithmetic
|
||||||
|
* @param angle angle to modulate
|
||||||
|
* @return resultant angle after modulation.
|
||||||
|
*/
|
||||||
public static double modulateAngle(double angle){
|
public static double modulateAngle(double angle){
|
||||||
return (angle % 360 + 360) % 360;
|
return (angle % 360 + 360) % 360;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO NOT DELETE THIS FUNCTIONS THEY ARE USED FOR TESTING PURPOSES
|
||||||
|
* @return current polars map
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private Map<Double, TreeMap<Double, Double>> getPolars(){
|
private Map<Double, TreeMap<Double, Double>> getPolars(){
|
||||||
//this function is just for testing so therefore it is private
|
//this function is just for testing so therefore it is private
|
||||||
return polars;
|
return polars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO NOT DELETE THESE FUNCTIONS THEY ARE USED FOR TESTING PURPOSES
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private void printOutLinearInterpolated(){
|
private void printOutLinearInterpolated(){
|
||||||
for (double tws: polars.keySet()){
|
for (double tws: polars.keySet()){
|
||||||
System.out.println("==================================================");
|
System.out.println("==================================================");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mock.model;
|
|||||||
|
|
||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
import mock.model.collider.Collision;
|
import mock.model.collider.Collision;
|
||||||
|
import mock.model.commandFactory.CollisionCommand;
|
||||||
import mock.model.commandFactory.Command;
|
import mock.model.commandFactory.Command;
|
||||||
import mock.model.commandFactory.CompositeCommand;
|
import mock.model.commandFactory.CompositeCommand;
|
||||||
import mock.model.commandFactory.CommandFactory;
|
import mock.model.commandFactory.CommandFactory;
|
||||||
@@ -145,9 +146,13 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
|
|||||||
//Get the current time.
|
//Get the current time.
|
||||||
long currentTime = System.currentTimeMillis();
|
long currentTime = System.currentTimeMillis();
|
||||||
|
|
||||||
//Execute commands from clients.
|
// Execute commands from clients.
|
||||||
commands.execute();
|
commands.execute();
|
||||||
|
|
||||||
|
// Notify Observers
|
||||||
|
race.setChanged();
|
||||||
|
race.notifyObservers();
|
||||||
|
|
||||||
//Update race time.
|
//Update race time.
|
||||||
race.updateRaceTime(currentTime);
|
race.updateRaceTime(currentTime);
|
||||||
|
|
||||||
@@ -218,11 +223,9 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
Collision e = (Collision)arg;
|
if(arg instanceof Collision) {
|
||||||
|
Collision collision = (Collision)arg;
|
||||||
// if(e.getBearing().degrees() == 0) System.out.println("Ahead");
|
commands.addCommand(new CollisionCommand(race, (MockBoat)collision.getBoat()));
|
||||||
// else if(e.getBearing().degrees() < 90) System.out.println("Starboard");
|
}
|
||||||
// else if(e.getBearing().degrees() > 270) System.out.println("Port");
|
|
||||||
// else System.out.println("Behind");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class SourceIdAllocator {
|
|||||||
|
|
||||||
if (!((mockRace.getRaceStatusEnum() == RaceStatusEnum.PRESTART)
|
if (!((mockRace.getRaceStatusEnum() == RaceStatusEnum.PRESTART)
|
||||||
|| (mockRace.getRaceStatusEnum() == RaceStatusEnum.WARNING))) {
|
|| (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());
|
throw new SourceIDAllocationException("Could not allocate a source ID. Can only allocate during pre-start or warning period. It is currently: " + mockRace.getRaceStatusEnum());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Integer> allocatedIDs = mockRace.getRaceDataSource().getParticipants();
|
List<Integer> allocatedIDs = mockRace.getRaceDataSource().getParticipants();
|
||||||
|
|||||||
@@ -25,13 +25,9 @@ public abstract class Collider extends Observable implements Locatable {
|
|||||||
Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees());
|
Bearing relative = Bearing.fromDegrees(absolute.degrees() - boat.getBearing().degrees());
|
||||||
|
|
||||||
if(actualDistance <= distance) {
|
if(actualDistance <= distance) {
|
||||||
Collision collision = new Collision(relative, distance);
|
Collision collision = new Collision(boat, relative, distance);
|
||||||
// Notify object of collision
|
// Notify object of collision
|
||||||
onCollisionEnter(boat, collision);
|
onCollisionEnter(collision);
|
||||||
// Notify observers of collision
|
|
||||||
notifyObservers(collision);
|
|
||||||
this.setChanged();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else return false;
|
} else return false;
|
||||||
}
|
}
|
||||||
@@ -45,8 +41,7 @@ public abstract class Collider extends Observable implements Locatable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a collision event
|
* Handle a collision event
|
||||||
* @param collider Boat that is colliding
|
|
||||||
* @param e details of collision
|
* @param e details of collision
|
||||||
*/
|
*/
|
||||||
public abstract void onCollisionEnter(Boat collider, Collision e);
|
public abstract void onCollisionEnter(Collision e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package mock.model.collider;
|
package mock.model.collider;
|
||||||
|
|
||||||
|
import mock.model.MockBoat;
|
||||||
import shared.model.Boat;
|
import shared.model.Boat;
|
||||||
import shared.model.GPSCoordinate;
|
import shared.model.GPSCoordinate;
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ public class ColliderRegistry extends Collider implements Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCollisionEnter(Boat collider, Collision e) {}
|
public void onCollisionEnter(Collision e) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GPSCoordinate getPosition() {
|
public GPSCoordinate getPosition() {
|
||||||
@@ -60,7 +61,7 @@ public class ColliderRegistry extends Collider implements Observer {
|
|||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
Collision collision = (Collision)arg;
|
Collision collision = (Collision)arg;
|
||||||
|
|
||||||
notifyObservers(collision);
|
|
||||||
this.setChanged();
|
this.setChanged();
|
||||||
|
notifyObservers(collision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package mock.model.collider;
|
package mock.model.collider;
|
||||||
|
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
import shared.model.Boat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data structure for holding collision details for ray casting and event handling.
|
* Data structure for holding collision details for ray casting and event handling.
|
||||||
@@ -14,13 +15,19 @@ public class Collision {
|
|||||||
* Distance from boat centre to target centre
|
* Distance from boat centre to target centre
|
||||||
*/
|
*/
|
||||||
private double distance;
|
private double distance;
|
||||||
|
/**
|
||||||
|
* Boat involved in the collision
|
||||||
|
*/
|
||||||
|
private Boat boat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for Collision structure
|
* Constructor for Collision structure
|
||||||
|
* @param boat involved in collision
|
||||||
* @param bearing from boat heading to target
|
* @param bearing from boat heading to target
|
||||||
* @param distance from boat centre to target centre
|
* @param distance from boat centre to target centre
|
||||||
*/
|
*/
|
||||||
public Collision(Bearing bearing, double distance) {
|
public Collision(Boat boat, Bearing bearing, double distance) {
|
||||||
|
this.boat = boat;
|
||||||
this.bearing = bearing;
|
this.bearing = bearing;
|
||||||
this.distance = distance;
|
this.distance = distance;
|
||||||
}
|
}
|
||||||
@@ -32,4 +39,8 @@ public class Collision {
|
|||||||
public double getDistance() {
|
public double getDistance() {
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boat getBoat() {
|
||||||
|
return boat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package mock.model.commandFactory;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to track the current active observer command. This is to ensure two commands that do similar things do not overlap.
|
||||||
|
*/
|
||||||
|
public class ActiveObserverCommand {
|
||||||
|
private ObserverCommand currentVelocityCommand;
|
||||||
|
private ObserverCommand currentAngularCommand;
|
||||||
|
|
||||||
|
public ActiveObserverCommand() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeVelocityCommand(Observable o, ObserverCommand c) {
|
||||||
|
o.deleteObserver(currentVelocityCommand);
|
||||||
|
o.addObserver(c);
|
||||||
|
currentVelocityCommand = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeAngularCommand(Observable o, ObserverCommand c) {
|
||||||
|
o.deleteObserver(currentAngularCommand);
|
||||||
|
o.addObserver(c);
|
||||||
|
currentAngularCommand = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package mock.model.commandFactory;
|
||||||
|
|
||||||
|
import mock.model.MockBoat;
|
||||||
|
import mock.model.MockRace;
|
||||||
|
import shared.model.Azimuth;
|
||||||
|
import shared.model.GPSCoordinate;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command class for collisions
|
||||||
|
*/
|
||||||
|
public class CollisionCommand extends ObserverCommand {
|
||||||
|
private GPSCoordinate startingPosition;
|
||||||
|
private Azimuth azimuth;
|
||||||
|
private double distance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for class
|
||||||
|
* @param race race context
|
||||||
|
* @param boat boat controlled by command
|
||||||
|
*/
|
||||||
|
public CollisionCommand(MockRace race, MockBoat boat) {
|
||||||
|
super(race, boat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
this.azimuth = Azimuth.fromDegrees(boat.getBearing().degrees() - 180d);
|
||||||
|
this.startingPosition = boat.getPosition();
|
||||||
|
this.distance = 30;
|
||||||
|
boat.setVelocityDefault(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
if(GPSCoordinate.calculateDistanceMeters(boat.getPosition(), startingPosition) < distance) {
|
||||||
|
boat.setPosition(GPSCoordinate.calculateNewPosition(boat.getPosition(), 2, azimuth));
|
||||||
|
} else {
|
||||||
|
race.deleteObserver(this);
|
||||||
|
boat.setVelocityDefault(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package mock.model.commandFactory;
|
|||||||
import mock.model.MockBoat;
|
import mock.model.MockBoat;
|
||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
|
|
||||||
|
import java.util.Observer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows RaceLogic to control MockRace state according to the Command pattern
|
* Allows RaceLogic to control MockRace state according to the Command pattern
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package mock.model.commandFactory;
|
||||||
|
|
||||||
|
import mock.model.MockBoat;
|
||||||
|
import mock.model.MockRace;
|
||||||
|
|
||||||
|
import java.util.Observer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command that can observe the race
|
||||||
|
*/
|
||||||
|
public abstract class ObserverCommand implements Command, Observer {
|
||||||
|
MockRace race;
|
||||||
|
MockBoat boat;
|
||||||
|
|
||||||
|
public ObserverCommand(MockRace race, MockBoat boat) {
|
||||||
|
this.race = race;
|
||||||
|
this.boat = boat;
|
||||||
|
boat.setAutoVMG(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,20 +2,50 @@ package mock.model.commandFactory;
|
|||||||
|
|
||||||
import mock.model.MockBoat;
|
import mock.model.MockBoat;
|
||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
|
import mock.model.NewPolars;
|
||||||
|
import mock.model.VMG;
|
||||||
|
|
||||||
public class SailsCommand implements Command {
|
import java.util.Observable;
|
||||||
private MockRace race;
|
|
||||||
private MockBoat boat;
|
public class SailsCommand extends ObserverCommand {
|
||||||
private boolean sailsOut;
|
private boolean sailsOut;
|
||||||
|
private double goalVelocity;
|
||||||
|
|
||||||
public SailsCommand(MockRace race, MockBoat boat, Boolean sailsOut) {
|
public SailsCommand(MockRace race, MockBoat boat, boolean sailsOut) {
|
||||||
this.race = race;
|
super(race, boat);
|
||||||
this.boat = boat;
|
race.addVelocityCommand(this);
|
||||||
this.sailsOut = sailsOut;
|
this.sailsOut = sailsOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
this.boat.setSailsOut(this.sailsOut);
|
this.boat.setSailsOut(this.sailsOut);
|
||||||
|
boat.setVelocityDefault(false);
|
||||||
|
|
||||||
|
if(sailsOut) {
|
||||||
|
// Accelerate to VMG speed
|
||||||
|
double polarSpeed = NewPolars.calculateSpeed(race.getWindDirection(), race.getWindSpeed(), boat.getBearing());
|
||||||
|
VMG vmg = new VMG(polarSpeed, boat.getBearing());
|
||||||
|
goalVelocity = vmg.getSpeed();
|
||||||
|
} else {
|
||||||
|
// Decelerate to 0
|
||||||
|
goalVelocity = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
double acceleration = 0.5;
|
||||||
|
|
||||||
|
if(sailsOut && boat.getCurrentSpeed() < goalVelocity) {
|
||||||
|
boat.setCurrentSpeed(Math.min(goalVelocity, boat.getCurrentSpeed() + acceleration));
|
||||||
|
} else if (!sailsOut && boat.getCurrentSpeed() > goalVelocity) {
|
||||||
|
// Apply deceleration to strictly 0 speed
|
||||||
|
boat.setCurrentSpeed(Math.max(0, boat.getCurrentSpeed() - acceleration));
|
||||||
|
} else {
|
||||||
|
// Release boat from SailsCommand control
|
||||||
|
if(sailsOut) boat.setVelocityDefault(true);
|
||||||
|
race.deleteObserver(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ import mock.model.MockBoat;
|
|||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command class for tacking and gybing
|
* Command class for tacking and gybing
|
||||||
*/
|
*/
|
||||||
public class TackGybeCommand implements Command {
|
public class TackGybeCommand extends ObserverCommand {
|
||||||
private MockRace race;
|
private double goalRotation;
|
||||||
private MockBoat boat;
|
private double totalRotation = 0;
|
||||||
|
private int direction; // -1 for anticlockwise, 1 for clockwise
|
||||||
|
private double goalAngle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for class
|
* Constructor for class
|
||||||
@@ -17,24 +21,32 @@ public class TackGybeCommand implements Command {
|
|||||||
* @param boat mock boat to update
|
* @param boat mock boat to update
|
||||||
*/
|
*/
|
||||||
public TackGybeCommand(MockRace race, MockBoat boat) {
|
public TackGybeCommand(MockRace race, MockBoat boat) {
|
||||||
this.race = race;
|
super(race, boat);
|
||||||
this.boat = boat;
|
race.addAngularCommand(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
|
||||||
boat.setAutoVMG(false);
|
|
||||||
|
|
||||||
double boatAngle = boat.getBearing().degrees();
|
double boatAngle = boat.getBearing().degrees();
|
||||||
double windAngle =race.getWindDirection().degrees();
|
double windAngle = race.getWindDirection().degrees();
|
||||||
double differenceAngle = calcDistance(boatAngle, windAngle);
|
double differenceAngle = calcDistance(boatAngle, windAngle);
|
||||||
double angleA = windAngle + differenceAngle;
|
double angleA = windAngle + differenceAngle;
|
||||||
double angleB = windAngle - differenceAngle;
|
double angleB = windAngle - differenceAngle;
|
||||||
if(angleA % 360 == boatAngle){
|
if (angleA % 360 == boatAngle) {
|
||||||
boat.setBearing(Bearing.fromDegrees(angleB));
|
goalAngle = angleB % 360;
|
||||||
} else {
|
} else {
|
||||||
boat.setBearing(Bearing.fromDegrees(angleA));
|
goalAngle = angleA % 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
goalRotation = goalAngle - boatAngle;
|
||||||
|
if (goalRotation < 0) {
|
||||||
|
goalRotation += 360;
|
||||||
|
}
|
||||||
|
if (goalRotation > 180) {
|
||||||
|
goalRotation = 360 - goalRotation;
|
||||||
|
direction = -1;
|
||||||
|
} else {
|
||||||
|
direction = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,5 +61,16 @@ public class TackGybeCommand implements Command {
|
|||||||
return phi > 180 ? 360 - phi : phi;
|
return phi > 180 ? 360 - phi : phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
double offset = 3.0;
|
||||||
|
if (totalRotation < goalRotation) {
|
||||||
|
boat.setBearing(Bearing.fromDegrees(boat.getBearing().degrees() + offset * direction));
|
||||||
|
totalRotation += offset;
|
||||||
|
} else {
|
||||||
|
boat.setBearing(Bearing.fromDegrees(goalAngle));
|
||||||
|
race.deleteObserver(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,20 @@ package mock.model.commandFactory;
|
|||||||
|
|
||||||
import mock.model.MockBoat;
|
import mock.model.MockBoat;
|
||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
|
import mock.model.NewPolars;
|
||||||
|
import mock.model.VMG;
|
||||||
|
import shared.model.Bearing;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command class for autoVMG
|
* Command class for autoVMG
|
||||||
*/
|
*/
|
||||||
public class VMGCommand implements Command {
|
public class VMGCommand extends ObserverCommand {
|
||||||
private MockRace race;
|
private double goalAngle;
|
||||||
private MockBoat boat;
|
private double goalRotation;
|
||||||
|
private double totalRotation = 0;
|
||||||
|
private int direction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for class
|
* Constructor for class
|
||||||
@@ -16,8 +23,8 @@ public class VMGCommand implements Command {
|
|||||||
* @param boat mock boat to update
|
* @param boat mock boat to update
|
||||||
*/
|
*/
|
||||||
public VMGCommand(MockRace race, MockBoat boat) {
|
public VMGCommand(MockRace race, MockBoat boat) {
|
||||||
this.race = race;
|
super(race, boat);
|
||||||
this.boat = boat;
|
race.addAngularCommand(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -27,5 +34,37 @@ public class VMGCommand implements Command {
|
|||||||
} else {
|
} else {
|
||||||
boat.setAutoVMG(true);
|
boat.setAutoVMG(true);
|
||||||
}
|
}
|
||||||
|
newOptimalVMG(boat);
|
||||||
|
|
||||||
|
goalRotation = goalAngle - boat.getBearing().degrees();
|
||||||
|
if (goalRotation < 0) {
|
||||||
|
goalRotation += 360;
|
||||||
|
}
|
||||||
|
if (goalRotation > 180) {
|
||||||
|
goalRotation = 360 - goalRotation;
|
||||||
|
direction = -1;
|
||||||
|
} else {
|
||||||
|
direction = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newOptimalVMG(MockBoat boat) {
|
||||||
|
long tackPeriod = 1000;
|
||||||
|
if (boat.getTimeSinceTackChange() > tackPeriod) {
|
||||||
|
VMG newVMG = NewPolars.setBestVMG(race.getWindDirection(), race.getWindSpeed(), boat.getBearing());
|
||||||
|
goalAngle = newVMG.getBearing().degrees();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
double offset = 3.0;
|
||||||
|
if (totalRotation < goalRotation) {
|
||||||
|
boat.setBearing(Bearing.fromDegrees(boat.getBearing().degrees() + offset * direction));
|
||||||
|
totalRotation += offset;
|
||||||
|
} else {
|
||||||
|
boat.setBearing(Bearing.fromDegrees(goalAngle));
|
||||||
|
race.deleteObserver(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,23 @@ import mock.model.MockBoat;
|
|||||||
import mock.model.MockRace;
|
import mock.model.MockRace;
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by connortaylorbrown on 4/08/17.
|
* Command class for upwind and downwind controls
|
||||||
*/
|
*/
|
||||||
public class WindCommand implements Command {
|
public class WindCommand extends ObserverCommand {
|
||||||
private MockRace race;
|
|
||||||
private MockBoat boat;
|
|
||||||
private int direction;
|
private int direction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for class
|
||||||
|
* @param race race context
|
||||||
|
* @param boat boat controlled by command
|
||||||
|
* @param upwind if true, downwind if false
|
||||||
|
*/
|
||||||
public WindCommand(MockRace race, MockBoat boat, boolean upwind) {
|
public WindCommand(MockRace race, MockBoat boat, boolean upwind) {
|
||||||
this.race = race;
|
super(race, boat);
|
||||||
this.boat = boat;
|
race.addAngularCommand(this);
|
||||||
this.direction = upwind? -1 : 1;
|
this.direction = upwind? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,4 +40,9 @@ public class WindCommand implements Command {
|
|||||||
|
|
||||||
boat.setBearing(Bearing.fromDegrees(heading + offset));
|
boat.setBearing(Bearing.fromDegrees(heading + offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
race.deleteObserver(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ public class ShiftingWindGenerator implements WindGenerator {
|
|||||||
if (shiftedSoFar >= 180){
|
if (shiftedSoFar >= 180){
|
||||||
shiftAnticlockwise = Math.random() > 0.5;
|
shiftAnticlockwise = Math.random() > 0.5;
|
||||||
shiftedSoFar = 0;
|
shiftedSoFar = 0;
|
||||||
// System.out.println("Swapping");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timeOfLastShift = System.currentTimeMillis();
|
timeOfLastShift = System.currentTimeMillis();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import shared.xml.XMLUtilities;
|
|||||||
import javax.xml.bind.JAXBException;
|
import javax.xml.bind.JAXBException;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
@@ -52,21 +53,22 @@ public class RaceXMLCreator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotates the race in a specified direction.
|
* Rotates the race in a specified direction.
|
||||||
* @param s xml file name
|
* @param s xml file name or contents.
|
||||||
|
* @param fileType Whether s is a file name or contents.
|
||||||
* @param degrees degrees to rotate
|
* @param degrees degrees to rotate
|
||||||
|
* @param tutorial Whether we wish to run the tutorial - this changes the race start time.
|
||||||
* @return the new xml file as a string
|
* @return the new xml file as a string
|
||||||
* @throws XMLReaderException if the xml is not readable
|
* @throws XMLReaderException if the xml is not readable
|
||||||
* @throws InvalidRaceDataException if the race is invalid
|
* @throws InvalidRaceDataException if the race is invalid
|
||||||
* @throws JAXBException if the Race class cannot be parsed into a xml.
|
|
||||||
* @throws IOException if the schema file cannot be found
|
|
||||||
* @throws SAXException error in schema file
|
|
||||||
* @throws ParserConfigurationException error in parsing the schema file
|
|
||||||
*/
|
*/
|
||||||
public static String alterRaceToWind(String s, double degrees, boolean tutorial) throws XMLReaderException, InvalidRaceDataException, JAXBException, IOException, SAXException, ParserConfigurationException {
|
public static String alterRaceToWind(String s, XMLFileType fileType, double degrees, boolean tutorial) throws XMLReaderException, InvalidRaceDataException {
|
||||||
RaceXMLReader reader = new RaceXMLReader(s, XMLFileType.ResourcePath);
|
|
||||||
|
RaceXMLReader reader = new RaceXMLReader(s, fileType);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
XMLRace race = XMLUtilities.xmlToClass(
|
XMLRace race = XMLUtilities.xmlToClass(
|
||||||
RaceXMLCreator.class.getClassLoader().getResourceAsStream(s),
|
s,
|
||||||
RaceXMLCreator.class.getClassLoader().getResource("mock/mockXML/schema/raceSchema.xsd"),
|
RaceXMLCreator.class.getClassLoader().getResource("mock/mockXML/schema/raceSchema.xsd"),
|
||||||
XMLRace.class);
|
XMLRace.class);
|
||||||
|
|
||||||
@@ -76,13 +78,29 @@ public class RaceXMLCreator {
|
|||||||
setRaceXMLAtCurrentTimeToNow(race);
|
setRaceXMLAtCurrentTimeToNow(race);
|
||||||
}
|
}
|
||||||
|
|
||||||
double raceOriginalBearing = getLineAngle(getLeewardGate(reader).getMark1Position(), getWindwardGate(reader).getMark1Position());
|
|
||||||
|
CompoundMark leewardGate = getLeewardGate(reader);
|
||||||
|
CompoundMark windwardGate = getWindwardGate(reader);
|
||||||
|
|
||||||
|
double raceOriginalBearing = 0;
|
||||||
|
|
||||||
|
/*if (leewardGate != null && windwardGate != null) {
|
||||||
|
raceOriginalBearing = getLineAngle(
|
||||||
|
leewardGate.getMark1Position(),
|
||||||
|
windwardGate.getMark1Position() );
|
||||||
|
}*/
|
||||||
|
|
||||||
double degreesToRotate = degrees - raceOriginalBearing;
|
double degreesToRotate = degrees - raceOriginalBearing;
|
||||||
|
|
||||||
|
if (degrees >= 0) {
|
||||||
alterRaceRotation(race, degreesToRotate);
|
alterRaceRotation(race, degreesToRotate);
|
||||||
|
}
|
||||||
|
|
||||||
return XMLUtilities.classToXML(race);
|
return XMLUtilities.classToXML(race);
|
||||||
|
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException | JAXBException e) {
|
||||||
|
throw new InvalidRaceDataException("Could not parse or marshall race data file.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -179,8 +197,6 @@ public class RaceXMLCreator {
|
|||||||
//The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute.
|
//The start time is current time + 4 minutes. prestart is 3 minutes, and we add another minute.
|
||||||
long millisecondsToAdd = racePrestartTime + racePreparatoryTime;
|
long millisecondsToAdd = racePrestartTime + racePreparatoryTime;
|
||||||
long secondsToAdd = millisecondsToAdd / 1000;
|
long secondsToAdd = millisecondsToAdd / 1000;
|
||||||
//Scale the time using our time scalar.
|
|
||||||
secondsToAdd = secondsToAdd / Constants.RaceTimeScale;
|
|
||||||
|
|
||||||
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
|
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||||
ZonedDateTime creationTime = ZonedDateTime.now();
|
ZonedDateTime creationTime = ZonedDateTime.now();
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public class AC35DumpReader {
|
|||||||
messLen[1] = dump[pointer + 13];
|
messLen[1] = dump[pointer + 13];
|
||||||
messLen[0] = dump[pointer + 14];
|
messLen[0] = dump[pointer + 14];
|
||||||
int messageLength = ByteBuffer.wrap(messLen).getShort();
|
int messageLength = ByteBuffer.wrap(messLen).getShort();
|
||||||
//System.out.println(messageLength);
|
|
||||||
|
|
||||||
packets.add(new AC35Packet(Arrays.copyOfRange(dump, pointer, pointer + messageLength + 19)));
|
packets.add(new AC35Packet(Arrays.copyOfRange(dump, pointer, pointer + messageLength + 19)));
|
||||||
|
|
||||||
|
|||||||
@@ -403,10 +403,6 @@ public class Boat extends Collider {
|
|||||||
public boolean isSailsOut() {
|
public boolean isSailsOut() {
|
||||||
return sailsOut;
|
return sailsOut;
|
||||||
}
|
}
|
||||||
public void bounce(double repulsionRadius) {
|
|
||||||
Azimuth reverseAzimuth = Azimuth.fromDegrees(getBearing().degrees() - 180d);
|
|
||||||
setPosition(GPSCoordinate.calculateNewPosition(getPosition(), 2 * repulsionRadius, reverseAzimuth));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean rayCast(Boat boat) {
|
public boolean rayCast(Boat boat) {
|
||||||
@@ -416,9 +412,11 @@ public class Boat extends Collider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCollisionEnter(Boat collider, Collision e) {
|
public void onCollisionEnter(Collision e) {
|
||||||
if(e.getBearing().degrees() > 270 || e.getBearing().degrees() < 90) {
|
if(e.getBearing().degrees() > 270 || e.getBearing().degrees() < 90) {
|
||||||
collider.bounce(100);
|
// Notify observers of collision
|
||||||
|
this.setChanged();
|
||||||
|
notifyObservers(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ public class CompoundMark extends XMLCompoundMark{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//finds the mark furthest west and east
|
//finds the mark furthest west and east
|
||||||
if(this.getMark1Position().getLongitude() > this.getMark2Position().getLongitude()){
|
if(this.getMark1Position().getLongitude() < this.getMark2Position().getLongitude()){
|
||||||
westMostMark = this.mark1;
|
westMostMark = this.mark1;
|
||||||
eastMostMark = this.mark2;
|
eastMostMark = this.mark2;
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package shared.model;
|
|||||||
* Created by Erika on 19-Mar-17.
|
* Created by Erika on 19-Mar-17.
|
||||||
*/
|
*/
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiply by this factor to convert nautical miles to meters.
|
* Multiply by this factor to convert nautical miles to meters.
|
||||||
* <br>
|
* <br>
|
||||||
@@ -15,8 +14,6 @@ public class Constants {
|
|||||||
*/
|
*/
|
||||||
public static final int NMToMetersConversion = 1852;
|
public static final int NMToMetersConversion = 1852;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiply by this factor to convert Knots to millimeters per second.
|
* Multiply by this factor to convert Knots to millimeters per second.
|
||||||
* <br>
|
* <br>
|
||||||
@@ -26,33 +23,24 @@ public class Constants {
|
|||||||
*/
|
*/
|
||||||
public static final double KnotsToMMPerSecond = 514.444;
|
public static final double KnotsToMMPerSecond = 514.444;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The scale factor of the race.
|
* The scale factor of the race.
|
||||||
* Frame periods are multiplied by this to get the amount of time a single frame represents.
|
* 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.
|
* 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 = 2;//10;
|
public static final int RaceTimeScale = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The race pre-start time, in milliseconds. 3 minutes (30 seconds for development).
|
* The race pre-start time, in milliseconds. 30 seconds.
|
||||||
|
* Official time is 3 minutes.
|
||||||
*/
|
*/
|
||||||
// public static final long RacePreStartTime = 30 * 1000;
|
public static final long RacePreStartTime = 30 * 1000;
|
||||||
public static final long RacePreStartTime = 1000;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The race preparatory time, in milliseconds. 1 minute.
|
* The race preparatory time, in milliseconds. 10 seconds.
|
||||||
|
* Official time is 1 minute.
|
||||||
*/
|
*/
|
||||||
// public static final long RacePreparatoryTime = 60 * 1000;
|
public static final long RacePreparatoryTime = 10 * 1000;
|
||||||
public static final long RacePreparatoryTime = 1 * 60 * 1000;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of milliseconds in one hour.
|
* The number of milliseconds in one hour.
|
||||||
* <br>
|
* <br>
|
||||||
@@ -70,7 +58,4 @@ public class Constants {
|
|||||||
* Divide by this factor to convert hours to seconds.
|
* Divide by this factor to convert hours to seconds.
|
||||||
*/
|
*/
|
||||||
public static long OneHourSeconds = 1 * 60 * 60;
|
public static long OneHourSeconds = 1 * 60 * 60;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ public class Mark extends Collider{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCollisionEnter(Boat collider, Collision e) {
|
public void onCollisionEnter(Collision e) {
|
||||||
collider.bounce(repulsionRadius);
|
this.setChanged();
|
||||||
|
notifyObservers(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package shared.model;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains data related to mark rounding for a specific leg.
|
||||||
|
*/
|
||||||
|
public class MarkRoundingData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The leg this relates to.
|
||||||
|
*/
|
||||||
|
private Leg leg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mark that should be rounded.
|
||||||
|
*/
|
||||||
|
private Mark markToRound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bearing of the leg.
|
||||||
|
*/
|
||||||
|
private Bearing legBearing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bearing of the next leg.
|
||||||
|
*/
|
||||||
|
private Bearing nextLegBearing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of the first rounding check point.
|
||||||
|
*/
|
||||||
|
private GPSCoordinate roundCheck1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of the second rounding check point.
|
||||||
|
*/
|
||||||
|
private GPSCoordinate roundCheck2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A halfway point between mark to round and roundCheck1.
|
||||||
|
*/
|
||||||
|
private GPSCoordinate roundCheck1Halfway;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A halfway point between mark to round and roundCheck2.
|
||||||
|
*/
|
||||||
|
private GPSCoordinate roundCheck2Halfway;
|
||||||
|
|
||||||
|
|
||||||
|
public MarkRoundingData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Leg getLeg() {
|
||||||
|
return leg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLeg(Leg leg) {
|
||||||
|
this.leg = leg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mark getMarkToRound() {
|
||||||
|
return markToRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMarkToRound(Mark markToRound) {
|
||||||
|
this.markToRound = markToRound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bearing getLegBearing() {
|
||||||
|
return legBearing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLegBearing(Bearing legBearing) {
|
||||||
|
this.legBearing = legBearing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bearing getNextLegBearing() {
|
||||||
|
return nextLegBearing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNextLegBearing(Bearing nextLegBearing) {
|
||||||
|
this.nextLegBearing = nextLegBearing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPSCoordinate getRoundCheck1() {
|
||||||
|
return roundCheck1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoundCheck1(GPSCoordinate roundCheck1) {
|
||||||
|
this.roundCheck1 = roundCheck1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPSCoordinate getRoundCheck2() {
|
||||||
|
return roundCheck2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoundCheck2(GPSCoordinate roundCheck2) {
|
||||||
|
this.roundCheck2 = roundCheck2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPSCoordinate getRoundCheck1Halfway() {
|
||||||
|
return roundCheck1Halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoundCheck1Halfway(GPSCoordinate roundCheck1Halfway) {
|
||||||
|
this.roundCheck1Halfway = roundCheck1Halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GPSCoordinate getRoundCheck2Halfway() {
|
||||||
|
return roundCheck2Halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoundCheck2Halfway(GPSCoordinate roundCheck2Halfway) {
|
||||||
|
this.roundCheck2Halfway = roundCheck2Halfway;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
package shared.model;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static shared.enums.RoundingType.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class contains a sequence of points that describe the mark rounding order for a course.
|
||||||
|
*/
|
||||||
|
public class MarkRoundingSequence {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legs in the race.
|
||||||
|
*/
|
||||||
|
private List<Leg> legs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each leg, mark rounding information.
|
||||||
|
*/
|
||||||
|
private Map<Leg, MarkRoundingData> roundingPoints;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public MarkRoundingSequence(List<Leg> legs) {
|
||||||
|
this.legs = legs;
|
||||||
|
generateRoundingPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rounding points for a given leg.
|
||||||
|
* @param leg Leg to check.
|
||||||
|
* @return Rounding points for leg.
|
||||||
|
*/
|
||||||
|
public MarkRoundingData getRoundingData(Leg leg) {
|
||||||
|
return roundingPoints.get(leg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the rounding points for all legs in the race.
|
||||||
|
*/
|
||||||
|
private void generateRoundingPoints() {
|
||||||
|
this.roundingPoints = new HashMap<>(this.legs.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < this.legs.size(); i++) {
|
||||||
|
Leg currentLeg = this.legs.get(i);
|
||||||
|
|
||||||
|
Optional<Leg> nextLeg = Optional.empty();
|
||||||
|
if (i < legs.size() - 1) {
|
||||||
|
nextLeg = Optional.of(this.legs.get(i + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
generateRoundingPoint(currentLeg, nextLeg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the rounding points for a specific leg.
|
||||||
|
* @param currentLeg The leg to generate rounding points for.
|
||||||
|
* @param nextLeg The following leg, used to help generate rounding points. Final leg of race doesn't have a following leg.
|
||||||
|
*/
|
||||||
|
private void generateRoundingPoint(Leg currentLeg, Optional<Leg> nextLeg) {
|
||||||
|
|
||||||
|
Bearing bearingToAddFirstPoint = calculateBearingToAdd(currentLeg);
|
||||||
|
|
||||||
|
GPSCoordinate startCoord = currentLeg.getStartCompoundMark().getAverageGPSCoordinate();
|
||||||
|
GPSCoordinate endCoord = currentLeg.getEndCompoundMark().getAverageGPSCoordinate();
|
||||||
|
Bearing legBearing = GPSCoordinate.calculateBearing(startCoord, endCoord);
|
||||||
|
Bearing nextBearing = legBearing;
|
||||||
|
|
||||||
|
Mark markToRound = currentLeg.getEndCompoundMark().getMarkForRounding(legBearing);
|
||||||
|
|
||||||
|
GPSCoordinate roundCheck1;
|
||||||
|
if (currentLeg.getEndCompoundMark().getMark2() == null) {
|
||||||
|
//End is a single mark.
|
||||||
|
roundCheck1 = calculateRoundingCheckPoint(
|
||||||
|
currentLeg,
|
||||||
|
markToRound,
|
||||||
|
legBearing,
|
||||||
|
bearingToAddFirstPoint);
|
||||||
|
} else {
|
||||||
|
//End is a gate.
|
||||||
|
if (markToRound == currentLeg.getEndCompoundMark().getMark1()) {
|
||||||
|
roundCheck1 = currentLeg.getEndCompoundMark().getMark2().getPosition();
|
||||||
|
} else {
|
||||||
|
roundCheck1 = currentLeg.getEndCompoundMark().getMark1().getPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO the halfway points currently haven't been done properly.
|
||||||
|
|
||||||
|
GPSCoordinate roundCheck1Halfway = calculateRoundingCheckPoint(
|
||||||
|
currentLeg,
|
||||||
|
markToRound,
|
||||||
|
legBearing,
|
||||||
|
bearingToAddFirstPoint);
|
||||||
|
|
||||||
|
|
||||||
|
GPSCoordinate roundCheck2 = roundCheck1;
|
||||||
|
GPSCoordinate roundCheck2Halfway = roundCheck1Halfway;
|
||||||
|
if (nextLeg.isPresent()) {
|
||||||
|
|
||||||
|
Bearing bearingToAddSecondPoint = bearingToAddFirstPoint;//calculateBearingToAdd(nextLeg.get());
|
||||||
|
|
||||||
|
GPSCoordinate startCoord2 = nextLeg.get().getStartCompoundMark().getAverageGPSCoordinate();
|
||||||
|
GPSCoordinate endCoord2 = nextLeg.get().getEndCompoundMark().getAverageGPSCoordinate();
|
||||||
|
nextBearing = GPSCoordinate.calculateBearing(startCoord2, endCoord2);
|
||||||
|
|
||||||
|
roundCheck2 = calculateRoundingCheckPoint(
|
||||||
|
currentLeg,
|
||||||
|
markToRound,
|
||||||
|
nextBearing,
|
||||||
|
bearingToAddSecondPoint);
|
||||||
|
|
||||||
|
roundCheck2Halfway = calculateRoundingCheckPoint(
|
||||||
|
currentLeg,
|
||||||
|
markToRound,
|
||||||
|
nextBearing,
|
||||||
|
bearingToAddSecondPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MarkRoundingData roundingData = new MarkRoundingData();
|
||||||
|
roundingData.setLeg(currentLeg);
|
||||||
|
|
||||||
|
roundingData.setLegBearing(legBearing);
|
||||||
|
roundingData.setNextLegBearing(nextBearing);
|
||||||
|
|
||||||
|
roundingData.setMarkToRound(markToRound);
|
||||||
|
|
||||||
|
roundingData.setRoundCheck1(roundCheck1);
|
||||||
|
roundingData.setRoundCheck1Halfway(roundCheck1Halfway);
|
||||||
|
|
||||||
|
roundingData.setRoundCheck2(roundCheck2);
|
||||||
|
roundingData.setRoundCheck2Halfway(roundCheck2Halfway);
|
||||||
|
|
||||||
|
|
||||||
|
this.roundingPoints.put(currentLeg, roundingData);
|
||||||
|
|
||||||
|
|
||||||
|
//Rounding points:
|
||||||
|
|
||||||
|
//each mark/gate has a specific mark to round. Call this ROUNDINGMARK
|
||||||
|
// with a mark, it is the mark
|
||||||
|
// with a gate, it depends if it is a starboard or port gate.
|
||||||
|
// it is the mark that allows the boat to enter between both marks of the gate, whilst obeying the starboard/port requirement.
|
||||||
|
|
||||||
|
//let the bearing between start of leg and end of leg be called LEGBEARING
|
||||||
|
|
||||||
|
//the first rounding point is ROUNDINGDISTANCE units away from the ROUNDINGMARK, on an angle perpendicular to LEGBEARING.
|
||||||
|
// the angle means that the rounding mark is at the center of a gate, for gates.
|
||||||
|
|
||||||
|
//the second rounding point is the same as the first, except LEGBEARING is the bearing between end of current leg, and start of next leg.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the location of the rounding check point, which together with the mark to round, forms a line that the boat must cross to round the mark.
|
||||||
|
* @param leg Leg of race to check.
|
||||||
|
* @param markToRound Mark at end of leg to round.
|
||||||
|
* @param legBearing The bearing of the nearest leg. For the first rounding point this is the leg's bearing, for the second rounding point it is the next leg's bearing.
|
||||||
|
* @param bearingToAdd The bearing to add to the leg bearing to get a perpendicular bearing.
|
||||||
|
* @return The location of the rounding point, which together with the mark to round forms a line the boat must cross.
|
||||||
|
*/
|
||||||
|
private GPSCoordinate calculateRoundingCheckPoint(Leg leg, Mark markToRound, Bearing legBearing, Bearing bearingToAdd) {
|
||||||
|
|
||||||
|
|
||||||
|
double roundingDistanceMeters = leg.getEndCompoundMark().getRoundingDistance();
|
||||||
|
|
||||||
|
|
||||||
|
//We project from rounding mark to get the second point which forms the line the boat must cross.
|
||||||
|
/*
|
||||||
|
c2
|
||||||
|
|
|
||||||
|
|
|
||||||
|
r------c1
|
||||||
|
b
|
||||||
|
*/
|
||||||
|
GPSCoordinate roundCheck = GPSCoordinate.calculateNewPosition(
|
||||||
|
markToRound.getPosition(),
|
||||||
|
roundingDistanceMeters,
|
||||||
|
Azimuth.fromDegrees(legBearing.degrees() + bearingToAdd.degrees()) );
|
||||||
|
|
||||||
|
return roundCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the bearing that must be added to a leg's bearing to calculate a perpendicular bearing, used for finding rounding points.
|
||||||
|
* @param leg Leg to check.
|
||||||
|
* @return Bearing to add. Will be either +90 or -90.
|
||||||
|
*/
|
||||||
|
private Bearing calculateBearingToAdd(Leg leg) {
|
||||||
|
|
||||||
|
if (leg.getEndCompoundMark().getRoundingType() == Port ||
|
||||||
|
leg.getEndCompoundMark().getRoundingType() == SP) {
|
||||||
|
return Bearing.fromDegrees(90);
|
||||||
|
} else {
|
||||||
|
return Bearing.fromDegrees(-90);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import shared.dataInput.RegattaDataSource;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Observable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,7 +21,7 @@ import java.util.List;
|
|||||||
* This is a base class inherited by {@link mock.model.MockRace} and {@link visualiser.model.VisualiserRaceState}.
|
* This is a base class inherited by {@link mock.model.MockRace} and {@link visualiser.model.VisualiserRaceState}.
|
||||||
* Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}.
|
* 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 RaceState {
|
public abstract class RaceState extends Observable{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -46,6 +47,12 @@ public abstract class RaceState {
|
|||||||
private ObservableList<Leg> legs;
|
private ObservableList<Leg> legs;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sequence of rounding points for each leg/mark.
|
||||||
|
*/
|
||||||
|
private MarkRoundingSequence markRoundingSequence;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The clock which tracks the race's start time, current time, and elapsed duration.
|
* The clock which tracks the race's start time, current time, and elapsed duration.
|
||||||
@@ -102,10 +109,15 @@ public abstract class RaceState {
|
|||||||
*/
|
*/
|
||||||
protected void useLegsList(List<Leg> legs) {
|
protected void useLegsList(List<Leg> legs) {
|
||||||
this.legs.setAll(legs);
|
this.legs.setAll(legs);
|
||||||
|
|
||||||
|
//We create this before adding the extra finish leg, as it doesn't contain compound marks.
|
||||||
|
this.markRoundingSequence = new MarkRoundingSequence(getLegs());
|
||||||
|
|
||||||
//We add a "dummy" leg at the end of the race.
|
//We add a "dummy" leg at the end of the race.
|
||||||
if (getLegs().size() > 0) {
|
if (getLegs().size() > 0) {
|
||||||
getLegs().add(new Leg("Finish", getLegs().size()));
|
getLegs().add(new Leg("Finish", getLegs().size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -367,6 +379,11 @@ public abstract class RaceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rounding sequences for each leg.
|
||||||
|
* @return Rounding sequence for each leg.
|
||||||
|
*/
|
||||||
|
public MarkRoundingSequence getMarkRoundingSequence() {
|
||||||
|
return markRoundingSequence;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import javax.xml.bind.annotation.XmlType;
|
|||||||
})
|
})
|
||||||
public class XMLParticipants {
|
public class XMLParticipants {
|
||||||
|
|
||||||
@XmlElement(name = "Yacht", required = true)
|
@XmlElement(name = "Yacht", required = false)
|
||||||
protected List<XMLYacht> yacht;
|
protected List<XMLYacht> yacht;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class XMLUtilities {
|
|||||||
return xmlToClass(document, schemaURL, c);
|
return xmlToClass(document, schemaURL, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object xmlToClass(String xml, URL schemaURL, Class c) throws ParserConfigurationException, IOException, SAXException, JAXBException {
|
public static <T> T xmlToClass(String xml, URL schemaURL, Class<T> c) throws ParserConfigurationException, IOException, SAXException, JAXBException {
|
||||||
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
Document document = parser.parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8"))));
|
Document document = parser.parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8"))));
|
||||||
|
|
||||||
@@ -63,10 +63,10 @@ public class XMLUtilities {
|
|||||||
* @param c The XML class to convert to.
|
* @param c The XML class to convert to.
|
||||||
* @param <T> The XML class to convert to.
|
* @param <T> The XML class to convert to.
|
||||||
* @return The XML class object.
|
* @return The XML class object.
|
||||||
* @throws ParserConfigurationException
|
* @throws ParserConfigurationException Thrown if input cannot be converted to class.
|
||||||
* @throws IOException
|
* @throws IOException Thrown if input cannot be converted to class.
|
||||||
* @throws SAXException
|
* @throws SAXException Thrown if input cannot be converted to class.
|
||||||
* @throws JAXBException
|
* @throws JAXBException Thrown if input cannot be converted to class.
|
||||||
*/
|
*/
|
||||||
public static <T> T xmlToClass(InputStream i, URL schemaURL, Class<T> c) throws ParserConfigurationException, IOException, SAXException, JAXBException {
|
public static <T> T xmlToClass(InputStream i, URL schemaURL, Class<T> c) throws ParserConfigurationException, IOException, SAXException, JAXBException {
|
||||||
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ public class BoatConfig {
|
|||||||
* Objects of the following type(s) are allowed in the list
|
* Objects of the following type(s) are allowed in the list
|
||||||
* {@link BoatConfig.Boats.Boat }
|
* {@link BoatConfig.Boats.Boat }
|
||||||
*
|
*
|
||||||
*
|
* @return List of Boat entries.
|
||||||
*/
|
*/
|
||||||
public List<BoatConfig.Boats.Boat> getBoat() {
|
public List<BoatConfig.Boats.Boat> getBoat() {
|
||||||
if (boat == null) {
|
if (boat == null) {
|
||||||
@@ -327,7 +327,7 @@ public class BoatConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the sourceID property.
|
* Gets the value of the sourceID property.
|
||||||
*
|
* @return source id.
|
||||||
*/
|
*/
|
||||||
public int getSourceID() {
|
public int getSourceID() {
|
||||||
return sourceID;
|
return sourceID;
|
||||||
@@ -335,7 +335,7 @@ public class BoatConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the sourceID property.
|
* Sets the value of the sourceID property.
|
||||||
*
|
* @param value new source id.
|
||||||
*/
|
*/
|
||||||
public void setSourceID(int value) {
|
public void setSourceID(int value) {
|
||||||
this.sourceID = value;
|
this.sourceID = value;
|
||||||
@@ -494,7 +494,7 @@ public class BoatConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the y property.
|
* Gets the value of the y property.
|
||||||
*
|
* @return Y value.
|
||||||
*/
|
*/
|
||||||
public double getY() {
|
public double getY() {
|
||||||
return y;
|
return y;
|
||||||
@@ -502,7 +502,7 @@ public class BoatConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the y property.
|
* Sets the value of the y property.
|
||||||
*
|
* @param value new y value.
|
||||||
*/
|
*/
|
||||||
public void setY(double value) {
|
public void setY(double value) {
|
||||||
this.y = value;
|
this.y = value;
|
||||||
@@ -510,7 +510,7 @@ public class BoatConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the z property.
|
* Gets the value of the z property.
|
||||||
*
|
* @return z value.
|
||||||
*/
|
*/
|
||||||
public double getZ() {
|
public double getZ() {
|
||||||
return z;
|
return z;
|
||||||
@@ -518,7 +518,7 @@ public class BoatConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the z property.
|
* Sets the value of the z property.
|
||||||
*
|
* @param value new z value.
|
||||||
*/
|
*/
|
||||||
public void setZ(double value) {
|
public void setZ(double value) {
|
||||||
this.z = value;
|
this.z = value;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class ObjectFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link BoatConfig }
|
* Create an instance of {@link BoatConfig }
|
||||||
*
|
* @return BoatConfig.
|
||||||
*/
|
*/
|
||||||
public BoatConfig createBoatConfig() {
|
public BoatConfig createBoatConfig() {
|
||||||
return new BoatConfig();
|
return new BoatConfig();
|
||||||
@@ -46,7 +46,7 @@ public class ObjectFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link BoatConfig.Boats }
|
* Create an instance of {@link BoatConfig.Boats }
|
||||||
*
|
* @return Boats.
|
||||||
*/
|
*/
|
||||||
public BoatConfig.Boats createBoatConfigBoats() {
|
public BoatConfig.Boats createBoatConfigBoats() {
|
||||||
return new BoatConfig.Boats();
|
return new BoatConfig.Boats();
|
||||||
@@ -54,7 +54,7 @@ public class ObjectFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link BoatConfig.Boats.Boat }
|
* Create an instance of {@link BoatConfig.Boats.Boat }
|
||||||
*
|
* @return Boat.
|
||||||
*/
|
*/
|
||||||
public BoatConfig.Boats.Boat createBoatConfigBoatsBoat() {
|
public BoatConfig.Boats.Boat createBoatConfigBoatsBoat() {
|
||||||
return new BoatConfig.Boats.Boat();
|
return new BoatConfig.Boats.Boat();
|
||||||
@@ -62,7 +62,7 @@ public class ObjectFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link BoatConfig.Boats.Boat.GPSposition }
|
* Create an instance of {@link BoatConfig.Boats.Boat.GPSposition }
|
||||||
*
|
* @return GPSposition.
|
||||||
*/
|
*/
|
||||||
public BoatConfig.Boats.Boat.GPSposition createBoatConfigBoatsBoatGPSposition() {
|
public BoatConfig.Boats.Boat.GPSposition createBoatConfigBoatsBoatGPSposition() {
|
||||||
return new BoatConfig.Boats.Boat.GPSposition();
|
return new BoatConfig.Boats.Boat.GPSposition();
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class ObjectFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link RegattaConfig }
|
* Create an instance of {@link RegattaConfig }
|
||||||
*
|
* @return RegattaConfig.
|
||||||
*/
|
*/
|
||||||
public RegattaConfig createRegattaConfig() {
|
public RegattaConfig createRegattaConfig() {
|
||||||
return new RegattaConfig();
|
return new RegattaConfig();
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the regattaID property.
|
* Gets the value of the regattaID property.
|
||||||
*
|
* @return regatta id.
|
||||||
*/
|
*/
|
||||||
public int getRegattaID() {
|
public int getRegattaID() {
|
||||||
return regattaID;
|
return regattaID;
|
||||||
@@ -82,7 +82,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the regattaID property.
|
* Sets the value of the regattaID property.
|
||||||
*
|
* @param value new regatta id.
|
||||||
*/
|
*/
|
||||||
public void setRegattaID(int value) {
|
public void setRegattaID(int value) {
|
||||||
this.regattaID = value;
|
this.regattaID = value;
|
||||||
@@ -138,7 +138,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the centralLatitude property.
|
* Gets the value of the centralLatitude property.
|
||||||
*
|
* @return central latitude.
|
||||||
*/
|
*/
|
||||||
public double getCentralLatitude() {
|
public double getCentralLatitude() {
|
||||||
return centralLatitude;
|
return centralLatitude;
|
||||||
@@ -146,7 +146,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the centralLatitude property.
|
* Sets the value of the centralLatitude property.
|
||||||
*
|
* @param value new central latitude.
|
||||||
*/
|
*/
|
||||||
public void setCentralLatitude(double value) {
|
public void setCentralLatitude(double value) {
|
||||||
this.centralLatitude = value;
|
this.centralLatitude = value;
|
||||||
@@ -154,7 +154,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the centralLongitude property.
|
* Gets the value of the centralLongitude property.
|
||||||
*
|
* @return central longitude.
|
||||||
*/
|
*/
|
||||||
public double getCentralLongitude() {
|
public double getCentralLongitude() {
|
||||||
return centralLongitude;
|
return centralLongitude;
|
||||||
@@ -162,7 +162,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the centralLongitude property.
|
* Sets the value of the centralLongitude property.
|
||||||
*
|
* @param value new central longitude.
|
||||||
*/
|
*/
|
||||||
public void setCentralLongitude(double value) {
|
public void setCentralLongitude(double value) {
|
||||||
this.centralLongitude = value;
|
this.centralLongitude = value;
|
||||||
@@ -170,7 +170,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the centralAltitude property.
|
* Gets the value of the centralAltitude property.
|
||||||
*
|
* @return central altitude.
|
||||||
*/
|
*/
|
||||||
public double getCentralAltitude() {
|
public double getCentralAltitude() {
|
||||||
return centralAltitude;
|
return centralAltitude;
|
||||||
@@ -178,7 +178,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the centralAltitude property.
|
* Sets the value of the centralAltitude property.
|
||||||
*
|
* @param value new central altitude.
|
||||||
*/
|
*/
|
||||||
public void setCentralAltitude(double value) {
|
public void setCentralAltitude(double value) {
|
||||||
this.centralAltitude = value;
|
this.centralAltitude = value;
|
||||||
@@ -186,7 +186,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the utcOffset property.
|
* Gets the value of the utcOffset property.
|
||||||
*
|
* @return utc offset.
|
||||||
*/
|
*/
|
||||||
public double getUtcOffset() {
|
public double getUtcOffset() {
|
||||||
return utcOffset;
|
return utcOffset;
|
||||||
@@ -194,7 +194,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the utcOffset property.
|
* Sets the value of the utcOffset property.
|
||||||
*
|
* @param value new utc offset.
|
||||||
*/
|
*/
|
||||||
public void setUtcOffset(double value) {
|
public void setUtcOffset(double value) {
|
||||||
this.utcOffset = value;
|
this.utcOffset = value;
|
||||||
@@ -202,7 +202,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the magneticVariation property.
|
* Gets the value of the magneticVariation property.
|
||||||
*
|
* @return magnetic variation.
|
||||||
*/
|
*/
|
||||||
public double getMagneticVariation() {
|
public double getMagneticVariation() {
|
||||||
return magneticVariation;
|
return magneticVariation;
|
||||||
@@ -210,7 +210,7 @@ public class RegattaConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the magneticVariation property.
|
* Sets the value of the magneticVariation property.
|
||||||
*
|
* @param value new magnetic variation.
|
||||||
*/
|
*/
|
||||||
public void setMagneticVariation(double value) {
|
public void setMagneticVariation(double value) {
|
||||||
this.magneticVariation = value;
|
this.magneticVariation = value;
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import mock.exceptions.EventConstructionException;
|
|||||||
import visualiser.app.App;
|
import visualiser.app.App;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.DatagramSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for the opening title window.
|
* Controller for the opening title window.
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import javafx.stage.StageStyle;
|
|||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import mock.app.Event;
|
import mock.app.Event;
|
||||||
|
|
||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
private static Stage stage;
|
private static Stage stage;
|
||||||
public static Event game;
|
public static Event game;
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ public class InputChecker {
|
|||||||
ControlKey controlKey = keyFactory.getKey(codeString);
|
ControlKey controlKey = keyFactory.getKey(codeString);
|
||||||
if (controlKey != null) {
|
if (controlKey != null) {
|
||||||
controlKey.onAction();
|
controlKey.onAction();
|
||||||
// System.out.println(controlKey.toString() + " is Pressed.");
|
|
||||||
}
|
}
|
||||||
currentlyActiveKeys.put(codeString, true);
|
currentlyActiveKeys.put(codeString, true);
|
||||||
}
|
}
|
||||||
@@ -38,7 +37,6 @@ public class InputChecker {
|
|||||||
ControlKey controlKey = keyFactory.getKey(codeString);
|
ControlKey controlKey = keyFactory.getKey(codeString);
|
||||||
if (controlKey != null) {
|
if (controlKey != null) {
|
||||||
controlKey.onRelease();
|
controlKey.onRelease();
|
||||||
// System.out.println(controlKey.toString() + " is Released.");
|
|
||||||
}
|
}
|
||||||
currentlyActiveKeys.remove(event.getCode().toString());
|
currentlyActiveKeys.remove(event.getCode().toString());
|
||||||
});
|
});
|
||||||
@@ -50,15 +48,8 @@ public class InputChecker {
|
|||||||
ControlKey controlKey = keyFactory.getKey(key);
|
ControlKey controlKey = keyFactory.getKey(key);
|
||||||
if (controlKey != null){
|
if (controlKey != null){
|
||||||
controlKey.onHold();
|
controlKey.onHold();
|
||||||
// System.out.println(controlKey.toString() + " is Held.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// for (String key : InputKeys.stringKeysMap.keySet()){
|
|
||||||
// if (removeActiveKey(key)) {
|
|
||||||
// System.out.println(key);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,18 +325,6 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
//If the race hasn't started, we set the time since last mark to the current time, to ensure we don't start counting until the race actually starts.
|
|
||||||
if ((boat.getStatus() != BoatStatusEnum.RACING) && (boat.getStatus() == BoatStatusEnum.FINISHED)) {
|
|
||||||
boat.setTimeAtLastMark(visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -504,6 +492,52 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void drawRoundingLines() {
|
||||||
|
|
||||||
|
|
||||||
|
//ugly hack
|
||||||
|
//rounding lines
|
||||||
|
|
||||||
|
//Boat is within an acceptable distance from the mark.
|
||||||
|
VisualiserBoat boat = null;
|
||||||
|
for (VisualiserBoat visualiserBoat : new ArrayList<>(raceState.getBoats())) {
|
||||||
|
if (visualiserBoat.isClientBoat()) {
|
||||||
|
boat = visualiserBoat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (boat == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Leg currentLeg = boat.getCurrentLeg();
|
||||||
|
|
||||||
|
MarkRoundingData roundingData = raceState.getMarkRoundingSequence().getRoundingData(currentLeg);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//To screen coords.
|
||||||
|
GraphCoordinate legEnd = map.convertGPS(roundingData.getMarkToRound().getPosition());
|
||||||
|
GraphCoordinate round1 = map.convertGPS(roundingData.getRoundCheck1());
|
||||||
|
GraphCoordinate round2 = map.convertGPS(roundingData.getRoundCheck2());
|
||||||
|
|
||||||
|
|
||||||
|
gc.strokeLine(
|
||||||
|
legEnd.getX(),
|
||||||
|
legEnd.getY(),
|
||||||
|
round1.getX(),
|
||||||
|
round1.getY() );
|
||||||
|
|
||||||
|
gc.strokeLine(
|
||||||
|
legEnd.getX(),
|
||||||
|
legEnd.getY(),
|
||||||
|
round2.getX(),
|
||||||
|
round2.getY() );
|
||||||
|
|
||||||
|
drawCircle(round1, 12, Color.ORANGE);
|
||||||
|
drawCircle(round2, 12, Color.GREEN);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws all of the {@link Mark}s on the canvas.
|
* Draws all of the {@link Mark}s on the canvas.
|
||||||
@@ -513,6 +547,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
|||||||
for (Mark mark : new ArrayList<>(raceState.getMarks())) {
|
for (Mark mark : new ArrayList<>(raceState.getMarks())) {
|
||||||
drawMark(mark);
|
drawMark(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -621,6 +656,9 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
|||||||
//Marks.
|
//Marks.
|
||||||
drawMarks();
|
drawMarks();
|
||||||
|
|
||||||
|
//TEMP
|
||||||
|
drawRoundingLines();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -655,7 +693,7 @@ public class ResizableRaceCanvas extends ResizableCanvas {
|
|||||||
|
|
||||||
//finds the direction of the current leg as a bearing
|
//finds the direction of the current leg as a bearing
|
||||||
startDirectionLinePoint = legStartPoint;
|
startDirectionLinePoint = legStartPoint;
|
||||||
GPSCoordinate tempEndDirectionLinePoint = legs.get(index).getEndCompoundMark().getAverageGPSCoordinate();
|
GPSCoordinate tempEndDirectionLinePoint = legs.get(index).getEndCompoundMark().getMark1Position();
|
||||||
|
|
||||||
bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, tempEndDirectionLinePoint);
|
bearingOfDirectionLine = GPSCoordinate.calculateBearing(startDirectionLinePoint, tempEndDirectionLinePoint);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<xs:element name="Participants">
|
<xs:element name="Participants">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="Yacht" maxOccurs="unbounded">
|
<xs:element name="Yacht" maxOccurs="unbounded" minOccurs="0">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:attribute name="SourceID" type="xs:int" use="required"/>
|
<xs:attribute name="SourceID" type="xs:int" use="required"/>
|
||||||
<xs:attribute name="Entry" type="xs:string"/>
|
<xs:attribute name="Entry" type="xs:string"/>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package shared.dataInput;
|
package shared.dataInput;
|
||||||
|
|
||||||
|
import mock.app.Event;
|
||||||
import shared.enums.XMLFileType;
|
import shared.enums.XMLFileType;
|
||||||
import shared.exceptions.InvalidRaceDataException;
|
import shared.exceptions.InvalidRaceDataException;
|
||||||
import shared.exceptions.XMLReaderException;
|
import shared.exceptions.XMLReaderException;
|
||||||
@@ -16,7 +17,7 @@ public class RaceXMLReaderTest {
|
|||||||
String raceXMLString = null;
|
String raceXMLString = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
raceXMLString = XMLReader.readXMLFileToString("mock/mockXML/raceTest.xml", StandardCharsets.UTF_8);
|
raceXMLString = Event.setRaceXMLAtCurrentTimeToNow(XMLReader.readXMLFileToString("mock/mockXML/raceTest.xml", StandardCharsets.UTF_8));
|
||||||
|
|
||||||
} catch (XMLReaderException e) {
|
} catch (XMLReaderException e) {
|
||||||
throw new InvalidRaceDataException("Could not read race XML file into a string.", e);
|
throw new InvalidRaceDataException("Could not read race XML file into a string.", e);
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package shared.model;
|
|
||||||
|
|
||||||
public class BearingTest {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
@@ -2,17 +2,18 @@
|
|||||||
<Race>
|
<Race>
|
||||||
<RaceID>5326</RaceID>
|
<RaceID>5326</RaceID>
|
||||||
<RaceType>FLEET</RaceType>
|
<RaceType>FLEET</RaceType>
|
||||||
<CreationTimeDate>2017-04-19T15:30:00+1200</CreationTimeDate>
|
<CreationTimeDate>RACE_CREATION_TIME</CreationTimeDate>
|
||||||
<RaceStartTime Postpone="false" Time="2017-04-19T15:33:00+1200"/>
|
<RaceStartTime Postpone="false" Time="RACE_START_TIME"/>
|
||||||
<Participants>
|
<Participants>
|
||||||
|
|
||||||
</Participants>
|
</Participants>
|
||||||
<CompoundMarkSequence>
|
<CompoundMarkSequence>
|
||||||
<Corner CompoundMarkID="1" SeqID="1"/>
|
<Corner SeqID="1" CompoundMarkID="1" Rounding="SP" ZoneSize="3" />
|
||||||
<Corner CompoundMarkID="2" SeqID="2"/>
|
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3" />
|
||||||
<Corner CompoundMarkID="4" SeqID="3"/>
|
<Corner SeqID="3" CompoundMarkID="4" Rounding="Port" ZoneSize="3" />
|
||||||
<Corner CompoundMarkID="3" SeqID="4"/>
|
<Corner SeqID="4" CompoundMarkID="3" Rounding="Starboard" ZoneSize="3" />
|
||||||
<Corner CompoundMarkID="4" SeqID="5"/>
|
<Corner SeqID="5" CompoundMarkID="4" Rounding="Port" ZoneSize="3" />
|
||||||
<Corner CompoundMarkID="5" SeqID="6"/>
|
<Corner SeqID="6" CompoundMarkID="5" Rounding="SP" ZoneSize="3"/>
|
||||||
</CompoundMarkSequence>
|
</CompoundMarkSequence>
|
||||||
<Course>
|
<Course>
|
||||||
<CompoundMark CompoundMarkID="1" Name="Start Line">
|
<CompoundMark CompoundMarkID="1" Name="Start Line">
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<java version="1.8.0_121" 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>LEFT</string>
|
|
||||||
<object class="visualiser.gameController.Keys.UpWindKey"/>
|
|
||||||
</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>RIGHT</string>
|
|
||||||
<object class="visualiser.gameController.Keys.DownWindKey"/>
|
|
||||||
</void>
|
|
||||||
<void method="put">
|
|
||||||
<string>Z</string>
|
|
||||||
<object class="visualiser.gameController.Keys.ZoomInKey"/>
|
|
||||||
</void>
|
|
||||||
</object>
|
|
||||||
</java>
|
|
||||||
Reference in New Issue
Block a user