From 091ee4735b5a4c25fe878c5394c12859facb8b19 Mon Sep 17 00:00:00 2001 From: fjc40 Date: Mon, 24 Apr 2017 20:19:39 +1200 Subject: [PATCH] Race.simulateRace() function now generates a BoatLocationMessage after updating the position of each boat. Currently we just print the message to stdout. Added functions to convert knots (as a double) to mm/sec (as an int) to BoatLocationMessage class. Added toString function to BoatLocationMessage class. Added a sequence number member to the BoatInRace class. Added Knots to meters per second conversion factor to Contants class. #story[788] --- mock/src/main/java/seng302/Constants.java | 3 + .../main/java/seng302/Model/BoatInRace.java | 17 +++ mock/src/main/java/seng302/Model/Race.java | 52 ++++++++- .../BoatLocationMessage.java | 110 ++++++++++++++++++ 4 files changed, 177 insertions(+), 5 deletions(-) diff --git a/mock/src/main/java/seng302/Constants.java b/mock/src/main/java/seng302/Constants.java index b4b3033f..a052b2b0 100644 --- a/mock/src/main/java/seng302/Constants.java +++ b/mock/src/main/java/seng302/Constants.java @@ -11,6 +11,9 @@ public class Constants { public static final int NMToMetersConversion = 1852; // 1 nautical mile = 1852 meters + //Knots x this = meters per second. + public static final double KnotsToMetersPerSecondConversionFactor = 0.514444; + public static final GPSCoordinate startLineMarker1 = new GPSCoordinate(32.296577, -64.854304); public static final GPSCoordinate startLineMarker2 = new GPSCoordinate(32.293771, -64.855242); public static final GPSCoordinate mark1 = new GPSCoordinate(32.293039, -64.843983); diff --git a/mock/src/main/java/seng302/Model/BoatInRace.java b/mock/src/main/java/seng302/Model/BoatInRace.java index 50ef24e9..2935d5c9 100644 --- a/mock/src/main/java/seng302/Model/BoatInRace.java +++ b/mock/src/main/java/seng302/Model/BoatInRace.java @@ -29,6 +29,9 @@ public class BoatInRace extends Boat { private StringProperty position; private double heading; + ///While generating BoatLocationMessages, each one needs a sequence number relating to each boat. + private long sequenceNumber = 0; + private boolean trackVisible = true; /** @@ -263,4 +266,18 @@ public class BoatInRace extends Boat { this.position.set(position); } + + /** + * Returns the current sequence number, and increments the internal value, such that that next call will return a value 1 larger than the current call. + * @return Current sequence number. + */ + public long getNextSequenceNumber(){ + //Make a copy of current value. + long oldNumber = this.sequenceNumber; + //Increment. + this.sequenceNumber += 1; + //Return the previous value. + return oldNumber; + } + } diff --git a/mock/src/main/java/seng302/Model/Race.java b/mock/src/main/java/seng302/Model/Race.java index 0de5c45f..3e7de7bc 100644 --- a/mock/src/main/java/seng302/Model/Race.java +++ b/mock/src/main/java/seng302/Model/Race.java @@ -11,6 +11,7 @@ import org.geotools.referencing.GeodeticCalculator; import seng302.Constants; import seng302.GPSCoordinate; import seng302.RaceDataSource; +import seng302.RaceEventMessages.BoatLocationMessage; import java.awt.geom.Point2D; @@ -158,20 +159,61 @@ public class Race implements Runnable { } new AnimationTimer() { - - long timeRaceStarted = System.currentTimeMillis(); //start time of loop + //Start time of loop. + long timeRaceStarted = System.currentTimeMillis(); @Override public void handle(long arg0) { if (boatsFinished < startingBoats.size()) { - totalTimeElapsed = System.currentTimeMillis() - timeRaceStarted; + //Get the current time. + long currentTime = System.currentTimeMillis(); + //Update the total elapsed time. + totalTimeElapsed = currentTime - timeRaceStarted; + //For each boat, we update it's position, and generate a BoatLocationMessage. for (BoatInRace boat : startingBoats) { if (boat != null && !boat.isFinished()) { + //Update position. updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS)); checkPosition(boat, totalTimeElapsed); + + + //Generate a boat location message for the updated boat. + BoatLocationMessage boatLocationMessage = new BoatLocationMessage(); + boatLocationMessage.setTime(currentTime); + boatLocationMessage.setSourceID(boat.getSourceID()); + boatLocationMessage.setSequenceNumber(boat.getNextSequenceNumber()); + boatLocationMessage.setDeviceType(BoatLocationMessage.RacingYacht); + + boatLocationMessage.setLatitude(BoatLocationMessage.convertCoordinateDoubleToInt(boat.getCurrentPosition().getLatitude())); + boatLocationMessage.setLongitude(BoatLocationMessage.convertCoordinateDoubleToInt(boat.getCurrentPosition().getLongitude())); + + boatLocationMessage.setAltitude(0);//Junk value. + boatLocationMessage.setHeading(BoatLocationMessage.convertHeadingDoubleToInt(boat.getHeading())); + + boatLocationMessage.setPitch((short)0);//Junk value. + boatLocationMessage.setRoll((short)0);//Junk value. + + boatLocationMessage.setBoatSpeed(BoatLocationMessage.convertBoatSpeedDoubleToInt(boat.getVelocity())); + boatLocationMessage.setBoatCOG(0);//Junk value. + boatLocationMessage.setBoatSOG(0);//Junk value. + + boatLocationMessage.setApparentWindSpeed(0);//Junk value. + boatLocationMessage.setApparentWindAngle((short)0);//Junk value. + boatLocationMessage.setTrueWindSpeed(0);//Junk value. + boatLocationMessage.setTrueWindAngle((short)0);//Junk value. + + boatLocationMessage.setCurrentDrift(0);//Junk value. + boatLocationMessage.setCurrentSet(0);//Junk value. + boatLocationMessage.setRudderAngle((short)0);//Junk value. + + //We have finished creating the message. + //TODO at this point, we need to send the event to the visualiser. + System.out.println(boatLocationMessage);//TEMP debug print + + } else { - System.out.println("Race is over"); + System.out.println("Race is over");//TEMP debug print //raceFinish = true; stop(); } @@ -194,7 +236,7 @@ public class Race implements Runnable { boat.setPosition("-"); } } - System.out.println("====="); + System.out.println("=====");//TEMP debug print } public void initialiseBoats() { diff --git a/mock/src/main/java/seng302/RaceEventMessages/BoatLocationMessage.java b/mock/src/main/java/seng302/RaceEventMessages/BoatLocationMessage.java index 9bacd840..425b86f0 100644 --- a/mock/src/main/java/seng302/RaceEventMessages/BoatLocationMessage.java +++ b/mock/src/main/java/seng302/RaceEventMessages/BoatLocationMessage.java @@ -4,6 +4,8 @@ package seng302.RaceEventMessages; * Created by f123 on 21-Apr-17. */ +import seng302.Constants; + /** * Represents the information in a boat location message (AC streaming spec: 4.9). */ @@ -442,4 +444,112 @@ public class BoatLocationMessage return angleShort; } + + /** + * Converts a double representing the speed of a boat in knots to an int in millimeters per second, as required by the streaming spec format. + * @param speed Speed in knots, stored as a double. + * @return Speed in millimeters per second, stored as an int (using only the two least significant bytes). + */ + public static int convertBoatSpeedDoubleToInt(double speed) + { + //Calculate meters per second. + double metersPerSecond = speed * Constants.KnotsToMetersPerSecondConversionFactor; + + //Calculate millimeters per second. + double millimetersPerSecond = metersPerSecond * 1000.0; + + //Convert to an int. + int millimetersPerSecondInt = (int)Math.round(millimetersPerSecond); + + return millimetersPerSecondInt; + } + + + /** + * Converts an int representing the speed of a boat in millimeters per second to a double in knots, as required by the streaming spec format. + * @param speed Speed in millimeters per second, stored as an int. + * @return Speed in knots, stored as a double. + */ + public static double convertBoatSpeedIntToDouble(int speed) + { + //Calculate meters per second. + double metersPerSecond = speed / 1000.0; + + //Calculate knots. + double knots = metersPerSecond / Constants.KnotsToMetersPerSecondConversionFactor; + + return knots; + } + + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + + builder.append("Message version number: "); + builder.append(this.getMessageVersionNumber()); + + builder.append("\nTime: "); + builder.append(this.getTime()); + + builder.append("\nSource ID: "); + builder.append(this.getSourceID()); + + builder.append("\nSequence number: "); + builder.append(this.getSequenceNumber()); + + builder.append("\nDevice type: "); + builder.append(this.getDeviceType()); + + builder.append("\nLatitude: "); + builder.append(this.getLatitude()); + + builder.append("\nLongitude: "); + builder.append(this.getLongitude()); + + builder.append("\nAltitude: "); + builder.append(this.getAltitude()); + + builder.append("\nHeading: "); + builder.append(this.getHeading()); + + builder.append("\nPitch: "); + builder.append(this.getPitch()); + + builder.append("\nRoll: "); + builder.append(this.getRoll()); + + builder.append("\nBoat speed (mm/sec): "); + builder.append(this.getBoatSpeed()); + + builder.append("\nBoat COG: "); + builder.append(this.getBoatCOG()); + + builder.append("\nBoat SOG: "); + builder.append(this.getBoatSOG()); + + builder.append("\nApparent wind speed: "); + builder.append(this.getApparentWindSpeed()); + + builder.append("\nApparent wind angle: "); + builder.append(this.getApparentWindAngle()); + + builder.append("\nTrue wind speed: "); + builder.append(this.getTrueWindSpeed()); + + builder.append("\nTrue wind angle: "); + builder.append(this.getTrueWindAngle()); + + builder.append("\nCurrent drift: "); + builder.append(this.getCurrentDrift()); + + builder.append("\nCurrent set: "); + builder.append(this.getCurrentSet()); + + builder.append("\nRudder angle: "); + builder.append(this.getRudderAngle()); + + return builder.toString(); + } }